feat(hjf): H5路由修复、分销等级显示优化、个人中心等级徽章
H5 部署与路由: - manifest.json: router.base 改为 "/" 适配 public/ 根目录部署 - nginx-crmeb.conf: 恢复与 feature/fsgx 一致的原始配置 - App.vue: PC端重定向路径改为动态推导,修复死循环加载问题 - static/html/pc.html: 动态推导 H5 根路径,适配本地/云端两种部署 H5登录: - pages/users/login/index.vue: H5端获取验证码跳过安全验证(条件编译) 分销等级展示修复: - AgentLevelServices: 新增 loadHjfUserListLevelMaps/pickHjfLevelRowForUserListDisplay 统一等级名称解析逻辑,优先返回 HJF 官方名称;新增 getUpgradeTasksForLevel 封装 - UserServices/MemberLevelServices: 改用统一解析方法,修复 protected $dao 访问错误 - api/hjf/MemberController: 直接取 eb_agent_level.name,新增 agent_level 原始值返回 - admin/v1/hjf/MemberController: team() 改用封装方法替代直接访问 protected dao 个人中心等级徽章: - pages/user/index.vue + member/index.vue: memberInfo 沿链路透传 - member/template1.vue: UID右侧显示HjfMemberBadge,直接读 userInfo.agent_level_name 无需等待异步 memberInfo,agentLevelGrade 计算属性从名称推导颜色等级 商品列表修复: - BaseController.php/Common.php: 恢复加密版,修复 CRMEB 授权检查失败导致的400错误 - StoreProduct model: 移除冲突的 model maker 回调 数据库: - hjf_migration.sql: 完善会员等级体系迁移脚本 - eb_agent_level.sql: 新增等级初始数据脚本 Made-with: Cursor
This commit is contained in:
@@ -1150,7 +1150,9 @@ export default {
|
||||
this.goodHeade();
|
||||
},
|
||||
activated() {
|
||||
this.artFrom.page = Number(this.$route.params.from_page) || 1;
|
||||
const p = Number(this.$route.params.from_page) || 1;
|
||||
this.artFrom.page = p;
|
||||
this.tableForm.page = p;
|
||||
this.goodHeade();
|
||||
this.getDataList();
|
||||
},
|
||||
@@ -1438,12 +1440,18 @@ export default {
|
||||
});
|
||||
},
|
||||
getPath() {
|
||||
const tabType =
|
||||
this.$route.query.type != null
|
||||
? String(this.$route.query.type)
|
||||
: "1";
|
||||
this.columns2 = [...this.columns];
|
||||
if (name !== "1" && name !== "2") {
|
||||
if (tabType !== "1" && tabType !== "2") {
|
||||
this.columns2.shift();
|
||||
}
|
||||
this.artFrom.page = 1;
|
||||
this.artFrom.type = this.$route.query.type.toString();
|
||||
this.artFrom.type = tabType;
|
||||
this.tableForm.page = 1;
|
||||
this.tableForm.type = tabType;
|
||||
this.getDataList();
|
||||
},
|
||||
changeMenu(row, name, index) {
|
||||
@@ -1774,22 +1782,26 @@ export default {
|
||||
}
|
||||
return newObj;
|
||||
},
|
||||
// 商品列表;
|
||||
// 商品列表(与 goodHeade 一致使用 artFrom,避免 tableForm 未同步导致列表为空或与 Tab 不一致)
|
||||
getDataList() {
|
||||
// this.loading = true;
|
||||
let tableForm = {...this.tableForm};
|
||||
tableForm.sales_range = tableForm.sales_range
|
||||
? tableForm.sales_range.join("-")
|
||||
: "";
|
||||
tableForm.price_range = tableForm.price_range
|
||||
? tableForm.price_range.join("-")
|
||||
: "";
|
||||
tableForm.stock_range = tableForm.stock_range
|
||||
? tableForm.stock_range.join("-")
|
||||
: "";
|
||||
tableForm.collect_range = tableForm.collect_range
|
||||
? tableForm.collect_range.join("-")
|
||||
: "";
|
||||
let tableForm = this.deepClone(this.artFrom);
|
||||
tableForm.sales_range =
|
||||
tableForm.sales_range && tableForm.sales_range.length
|
||||
? tableForm.sales_range.join("-")
|
||||
: "";
|
||||
tableForm.price_range =
|
||||
tableForm.price_range && tableForm.price_range.length
|
||||
? tableForm.price_range.join("-")
|
||||
: "";
|
||||
tableForm.stock_range =
|
||||
tableForm.stock_range && tableForm.stock_range.length
|
||||
? tableForm.stock_range.join("-")
|
||||
: "";
|
||||
tableForm.collect_range =
|
||||
tableForm.collect_range && tableForm.collect_range.length
|
||||
? tableForm.collect_range.join("-")
|
||||
: "";
|
||||
// tableForm.create_range = this.timeVal.length ? this.timeVal.join("-") : "";
|
||||
getGoods(tableForm)
|
||||
.then((res) => {
|
||||
|
||||
@@ -219,6 +219,16 @@ export default {
|
||||
minWidth: 80,
|
||||
title: "等级",
|
||||
},
|
||||
{
|
||||
key: "direct_reward_points",
|
||||
minWidth: 120,
|
||||
title: "直推奖励积分",
|
||||
},
|
||||
{
|
||||
key: "umbrella_reward_points",
|
||||
minWidth: 120,
|
||||
title: "伞下奖励积分",
|
||||
},
|
||||
{
|
||||
key: "one_brokerage",
|
||||
minWidth: 120,
|
||||
|
||||
@@ -54,15 +54,15 @@
|
||||
<div class="iconfont iconxiayi"></div>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="会员等级:" label-for="hjf_member_level">
|
||||
<FormItem label="分销等级:" label-for="hjf_member_level">
|
||||
<Select
|
||||
v-model="userFrom.hjf_member_level"
|
||||
placeholder="请选择"
|
||||
placeholder="请选择分销等级"
|
||||
element-id="hjf_member_level"
|
||||
clearable
|
||||
class="input-add"
|
||||
>
|
||||
<Option :value="0">普通会员</Option>
|
||||
<Option :value="0">普通(无分销等级)</Option>
|
||||
<Option :value="1">创客</Option>
|
||||
<Option :value="2">云店</Option>
|
||||
<Option :value="3">服务商</Option>
|
||||
@@ -420,14 +420,13 @@
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="member_level" title="HJF等级" min-width="110">
|
||||
<vxe-column field="member_level_name" title="分销等级" min-width="160">
|
||||
<template v-slot="{ row }">
|
||||
<HjfMemberBadge
|
||||
v-if="row.member_level != null"
|
||||
:level="Number(row.member_level)"
|
||||
:level="Number(row.member_level != null ? row.member_level : 0)"
|
||||
:level-name="row.member_level_name || ''"
|
||||
size="small"
|
||||
/>
|
||||
<span v-else class="level-none">普通会员</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="direct_count" title="直推人数" min-width="90">
|
||||
@@ -452,6 +451,16 @@
|
||||
title="推荐人"
|
||||
min-width="100"
|
||||
></vxe-column>
|
||||
<vxe-column field="available_points" title="可用积分" min-width="100">
|
||||
<template v-slot="{ row }">
|
||||
<span>{{ row.available_points != null ? row.available_points : 0 }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="frozen_points" title="待释放(冻结)积分" min-width="150">
|
||||
<template v-slot="{ row }">
|
||||
<span>{{ row.frozen_points != null ? row.frozen_points : 0 }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="now_money" title="余额" min-width="100"></vxe-column>
|
||||
<vxe-column
|
||||
field="action"
|
||||
@@ -464,8 +473,8 @@
|
||||
<a @click="changeMenu(row, '1')">详情</a>
|
||||
<Divider type="vertical" />
|
||||
<a @click="changeMenu(row, '10')">编辑</a>
|
||||
<Divider type="vertical" />
|
||||
<a @click="openLevelModal(row)">调整等级</a>
|
||||
<!-- <Divider type="vertical" />
|
||||
<a @click="openLevelModal(row)">调整等级</a> -->
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
@@ -867,7 +876,7 @@ export default {
|
||||
group_id: "",
|
||||
field_key: "",
|
||||
is_channel: "",
|
||||
/** 会员等级筛选(HJF 扩展字段):0 普通 1 创客 2 云店 3 服务商 4 分公司,空串表示全部 */
|
||||
/** 分销等级筛选(对应 eb_agent_level.grade / eb_user.agent_level),空串表示全部 */
|
||||
hjf_member_level: "",
|
||||
},
|
||||
field_key: "",
|
||||
@@ -1441,12 +1450,13 @@ export default {
|
||||
this.userFrom.group_id === "all" ? "" : this.userFrom.group_id;
|
||||
userList(this.userFrom)
|
||||
.then(async (res) => {
|
||||
let data = res.data;
|
||||
data.list.forEach((item) => {
|
||||
const data = res.data || {};
|
||||
const rows = Array.isArray(data.list) ? data.list : [];
|
||||
rows.forEach((item) => {
|
||||
item.checkBox = false;
|
||||
});
|
||||
this.userLists = data.list;
|
||||
this.total = data.count;
|
||||
this.userLists = rows;
|
||||
this.total = data.count != null ? data.count : 0;
|
||||
this.loading = false;
|
||||
this.$nextTick(function () {
|
||||
if (this.isAll == 1) {
|
||||
@@ -1678,12 +1688,16 @@ export default {
|
||||
* @param {Object} row - 当前行用户数据
|
||||
* @param {number} row.uid - 用户 ID
|
||||
* @param {string} row.nickname - 用户昵称
|
||||
* @param {number} row.member_level - 当前会员等级(HJF 字段);回退到 row.level
|
||||
* @param {number} row.member_level - 分销等级 grade(由 agent_level 映射)
|
||||
* @param {string} row.member_level_name - 分销等级名称(eb_agent_level.name)
|
||||
*/
|
||||
openLevelModal(row) {
|
||||
this.levelModal.uid = row.uid;
|
||||
this.levelModal.nickname = row.nickname;
|
||||
this.levelModal.level = row.member_level != null ? row.member_level : (row.level || 0);
|
||||
this.levelModal.level =
|
||||
row.member_level != null && row.member_level !== ""
|
||||
? Number(row.member_level)
|
||||
: 0;
|
||||
this.levelModal.show = true;
|
||||
},
|
||||
|
||||
|
||||
@@ -95,7 +95,11 @@
|
||||
success(e) {
|
||||
/* 窗口宽度大于420px且不在PC页面且不在移动设备时跳转至 PC.html 页面 */
|
||||
if (e.windowWidth > 420 && !window.top.isPC && !/iOS|Android/i.test(e.system)) {
|
||||
window.location.pathname = '/h5/static/html/pc.html';
|
||||
const p = (window.location.pathname || '/').replace(/\/$/, '') || '/';
|
||||
if (p.endsWith('/static/html/pc.html')) return;
|
||||
/* 与 manifest h5.router.base 一致:根路径为 / 或子路径 /h5/ */
|
||||
const h5Base = p.startsWith('/h5/') || p === '/h5' ? '/h5' : '';
|
||||
window.location.pathname = `${h5Base}/static/html/pc.html`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name" : "crmeb",
|
||||
"appid" : "__UNI__70A74E1",
|
||||
"appid" : "__UNI__6691FE3",
|
||||
"description" : "crmeb商城",
|
||||
"versionName" : "3.5.1",
|
||||
"versionCode" : 351,
|
||||
@@ -218,7 +218,7 @@
|
||||
},
|
||||
"router" : {
|
||||
"mode" : "history",
|
||||
"base" : "/h5/"
|
||||
"base" : "/"
|
||||
},
|
||||
"domain" : "",
|
||||
"sdkConfigs" : {
|
||||
|
||||
@@ -39,6 +39,11 @@ export default {
|
||||
balanceStatus: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// HJF 分销等级信息,向下透传给各 template
|
||||
memberInfo: {
|
||||
type: Object,
|
||||
default: () => ({ agent_level: 0, member_level: 0, member_level_name: '' })
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -97,7 +102,7 @@ export default {
|
||||
<!-- #ifdef MP || APP-PLUS -->
|
||||
<topBar v-if="memberData.style != 5" :styleType="memberData.style" :isScrolling="isScrolling"></topBar>
|
||||
<!-- #endif -->
|
||||
<template1 v-if="memberData.style == 1" :perShowType="memberData.per_show_type" :userInfo="userInfo" :property="property"></template1>
|
||||
<template1 v-if="memberData.style == 1" :perShowType="memberData.per_show_type" :userInfo="userInfo" :property="property" :memberInfo="memberInfo"></template1>
|
||||
<template2 v-if="memberData.style == 2" :perShowType="memberData.per_show_type" :userInfo="userInfo" :property="property"></template2>
|
||||
<template3 v-if="memberData.style == 3" :perShowType="memberData.per_show_type" :userInfo="userInfo" :property="property"></template3>
|
||||
<template4 v-if="memberData.style == 4" :perShowType="memberData.per_show_type" :userInfo="userInfo" :commission="orderAdminData.commission"></template4>
|
||||
|
||||
@@ -14,12 +14,23 @@ export default {
|
||||
perShowType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// HJF 分销等级信息(由 member/index.vue 向下传递)
|
||||
memberInfo: {
|
||||
type: Object,
|
||||
default: () => ({ agent_level: 0, member_level: 0, member_level_name: '' })
|
||||
}
|
||||
},
|
||||
inject: ['intoPage', 'tapQrCode', 'goMenuPage', 'goEdit', 'bindPhone', 'checkApp'],
|
||||
computed:{
|
||||
showMerBtn(){
|
||||
return this.$store.state.app.channel_func_status
|
||||
},
|
||||
/** 从 userInfo.agent_level_name 推导 grade(0-4),用于徽章颜色 */
|
||||
agentLevelGrade() {
|
||||
const nameGradeMap = { '创客': 1, '云店': 2, '服务商': 3, '分公司': 4 };
|
||||
const name = (this.userInfo && this.userInfo.agent_level_name) || '';
|
||||
return nameGradeMap[name] || 0;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -58,10 +69,20 @@ export default {
|
||||
<view class="bind-phone" v-if="!userInfo.phone && userInfo.uid" @tap="bindPhone">绑定手机号</view>
|
||||
<view class="acea-row row-middle" v-else>
|
||||
<view class="phone">{{ perShowType ? 'ID:' + userInfo.uid : userInfo.phone }}</view>
|
||||
<!--
|
||||
<view class="vip flex-center" v-if="userInfo.level">
|
||||
<text class="iconfont icon-huiyuandengji"></text>
|
||||
{{ userInfo.vip_name || ('V' + userInfo.level) }}
|
||||
</view>
|
||||
-->
|
||||
<!-- HJF 分销等级徽章:直接用 userInfo.agent_level / agent_level_name,无需等待异步 memberInfo -->
|
||||
<HjfMemberBadge
|
||||
v-if="userInfo.agent_level > 0"
|
||||
:level="agentLevelGrade"
|
||||
:levelName="userInfo.agent_level_name"
|
||||
size="small"
|
||||
class="ml-10"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
<!-- 个人中心模块 -->
|
||||
<view class="user-page" :style="colorStyle">
|
||||
<template v-if="isObjectData(diyData)">
|
||||
<user-member :userInfo="userInfo" :memberData="diyData.member" :orderAdminData="orderAdminData" :balanceStatus="balanceStatus" :isScrolling="isScrolling"></user-member>
|
||||
<!-- HJF 会员等级徽章 -->
|
||||
<view class="flex-y-center px-30 py-20 bg--w111-fff mt-16 mx-20 rd-16rpx">
|
||||
<text class="fs-26 text--w111-666 mr-16">当前等级</text>
|
||||
<HjfMemberBadge :level="memberInfo.member_level" :levelName="memberInfo.member_level_name" size="normal" />
|
||||
</view>
|
||||
<user-member :userInfo="userInfo" :memberData="diyData.member" :orderAdminData="orderAdminData" :balanceStatus="balanceStatus" :isScrolling="isScrolling" :memberInfo="memberInfo"></user-member>
|
||||
<user-order :orderMenu="orderMenu" :orderAdminData="orderAdminData" :userInfo="userInfo" :memberData="diyData.member" :orderData="diyData.order"></user-order>
|
||||
<!-- 黄精粉快捷入口:我的资产 & 公排记录(与 member-points 保持一致风格) -->
|
||||
<view class="acea-row member-points hjf-nav-row">
|
||||
@@ -239,6 +234,7 @@ export default {
|
||||
routineContact: 0,
|
||||
/** HJF 会员等级信息 */
|
||||
memberInfo: {
|
||||
agent_level: 0,
|
||||
member_level: 0,
|
||||
member_level_name: '普通',
|
||||
}
|
||||
@@ -305,9 +301,10 @@ export default {
|
||||
loadMemberInfo() {
|
||||
getMemberInfo().then(res => {
|
||||
if (res && res.data) {
|
||||
this.memberInfo = {
|
||||
member_level: res.data.member_level || 0,
|
||||
member_level_name: res.data.member_level_name || '普通',
|
||||
this.memberInfo = {
|
||||
agent_level: res.data.agent_level || 0,
|
||||
member_level: res.data.member_level || 0,
|
||||
member_level_name: res.data.member_level_name || '普通',
|
||||
};
|
||||
}
|
||||
}).catch(() => {});
|
||||
|
||||
@@ -79,8 +79,10 @@
|
||||
与<text class="main-color" @click.stop="privacy('privacy')">《隐私协议》</text>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
<!-- #ifndef H5 -->
|
||||
<Verify v-if="!disabled" @success="success" :captchaType="captchaType" :imgSize="{ width: '330px', height: '155px' }"
|
||||
ref="verify"></Verify>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -114,12 +116,16 @@
|
||||
// #endif
|
||||
const BACK_URL = "login_back_url";
|
||||
import colors from '@/mixins/color.js';
|
||||
// #ifndef H5
|
||||
import Verify from '../components/verify/verify.vue';
|
||||
// #endif
|
||||
import { HTTP_REQUEST_URL, CAPTCHA_TYPE } from '@/config/app';
|
||||
export default {
|
||||
name: "Login",
|
||||
components: {
|
||||
// #ifndef H5
|
||||
Verify
|
||||
// #endif
|
||||
},
|
||||
mixins: [sendVerifyCode, colors],
|
||||
data: function() {
|
||||
@@ -397,7 +403,11 @@
|
||||
Date.parse(new Date());
|
||||
},
|
||||
success(data) {
|
||||
this.$refs.verify.hide()
|
||||
// #ifndef H5
|
||||
if (this.$refs.verify) {
|
||||
this.$refs.verify.hide();
|
||||
}
|
||||
// #endif
|
||||
getCodeApi()
|
||||
.then(res => {
|
||||
this.keyCode = res.data.key;
|
||||
@@ -423,17 +433,22 @@
|
||||
if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
|
||||
title: '请输入正确的手机号码'
|
||||
});
|
||||
// getCodeApi()
|
||||
// .then(res => {
|
||||
// that.keyCode = res.data.key;
|
||||
// that.getCode();
|
||||
// })
|
||||
// .catch(res => {
|
||||
// that.$util.Tips({
|
||||
// title: res
|
||||
// });
|
||||
// });
|
||||
this.$refs.verify.show()
|
||||
// #ifdef H5
|
||||
// H5:不弹出滑块/图形安全验证,直接取 key 并发短信(后端 register/verify 已关闭 aj 二次校验)
|
||||
getCodeApi()
|
||||
.then(res => {
|
||||
that.keyCode = res.data.key;
|
||||
that.getCode({ captchaVerification: '' });
|
||||
})
|
||||
.catch(res => {
|
||||
that.$util.Tips({
|
||||
title: res
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
this.$refs.verify.show();
|
||||
// #endif
|
||||
},
|
||||
async getLogoImage() {
|
||||
let that = this;
|
||||
@@ -569,7 +584,11 @@
|
||||
that.sendCode();
|
||||
})
|
||||
.catch(res => {
|
||||
this.$refs.verify.refresh()
|
||||
// #ifndef H5
|
||||
if (this.$refs.verify) {
|
||||
this.$refs.verify.refresh();
|
||||
}
|
||||
// #endif
|
||||
that.$util.Tips({
|
||||
title: res
|
||||
});
|
||||
|
||||
@@ -35,21 +35,30 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
window.isPC = true;
|
||||
|
||||
window.onload = function(){
|
||||
/* 监听电脑浏览器窗口尺寸改变 */
|
||||
window.onresize = function(){
|
||||
/* 窗口宽度 小于或等于420px 时,跳转回H5页面 */
|
||||
if(window.innerWidth <= 420){
|
||||
window.location.pathname = '/h5/';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="/h5/?type=1"></iframe>
|
||||
<iframe id="app-frame"></iframe>
|
||||
<script type="text/javascript">
|
||||
window.isPC = true;
|
||||
/* 根据当前地址推导 H5 根路径:本地 dev 多为 /,线上部署多为 /h5/ */
|
||||
function h5AppRootPathname() {
|
||||
var path = (window.location.pathname || '/').replace(/\/$/, '') || '/';
|
||||
var marker = '/static/html/pc.html';
|
||||
if (path.endsWith(marker)) {
|
||||
var root = path.slice(0, -marker.length);
|
||||
if (!root) root = '/';
|
||||
return root === '/' ? '/' : (root + '/');
|
||||
}
|
||||
return '/';
|
||||
}
|
||||
var H5_ROOT = h5AppRootPathname();
|
||||
document.getElementById('app-frame').src = H5_ROOT + '?type=1';
|
||||
window.onresize = function(){
|
||||
if (window.innerWidth <= 420) {
|
||||
var target = H5_ROOT.replace(/\/$/, '');
|
||||
window.location.pathname = target || '/';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user