feat: 黄精粉前端功能集成 + 个人中心/资产/公排页面优化 + 去除admin copyright
主要改动: - 个人中心: 去除HjfMemberBadge徽章, 会员等级改显示vip_name, "我的资产"/"公排查询"导航项改为与member-points一致风格 - 我的资产页面: 去除HjfMemberBadge, 美化卡片圆角和阴影 - 公排查询页面: 美化顶部渐变和订单卡片样式 - Admin登录页和后台布局: 彻底删除footer copyright信息 - 新增黄精粉业务页面/组件/API/Mock数据(Phase 1) - 新增PHP环境配置文档和启动脚本 Made-with: Cursor
This commit is contained in:
113
pro_v3.5.1/view/admin/src/api/hjfMember.js
Normal file
113
pro_v3.5.1/view/admin/src/api/hjfMember.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 会员管理模块 - Admin API
|
||||
* @module api/hjfMember
|
||||
* @description 会员列表、会员配置、设置不考核、设置会员等级等管理端接口
|
||||
*/
|
||||
|
||||
import request from '@/plugins/request';
|
||||
import { MOCK_MEMBER_LIST, MOCK_MEMBER_CONFIG } from '@/utils/hjfMockData.js';
|
||||
|
||||
/** @type {boolean} Phase 1 使用 Mock;Phase 4 集成时改为 false */
|
||||
const USE_MOCK = true;
|
||||
|
||||
/**
|
||||
* Mock 包装:返回与 request 相同形状的 Promise(status + data)
|
||||
* @param {Object} data - 要返回的响应体
|
||||
* @param {number} [delay=200] - 模拟网络延迟(ms)
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
function mockResponse(data, delay = 200) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve({ status: 200, data: JSON.parse(JSON.stringify(data)) });
|
||||
}, delay);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员列表(分页 + 等级/不考核筛选)
|
||||
* @param {Object} [data] - 查询参数,如 page、limit、keyword、member_level、no_assess 等
|
||||
* @returns {Promise<{ status: number, data: { list: Array, count: number, page: number, limit: number } }>}
|
||||
*/
|
||||
export function memberList(data) {
|
||||
if (USE_MOCK) return mockResponse(MOCK_MEMBER_LIST);
|
||||
return request({ url: 'hjf/member/list', method: 'get', params: data });
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员配置(获取等级门槛、直推/伞下奖励等)
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
export function memberConfig() {
|
||||
if (USE_MOCK) return mockResponse(MOCK_MEMBER_CONFIG);
|
||||
return request({ url: 'hjf/member/config', method: 'get' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员配置(新接口,供 memberConfig 页面使用)
|
||||
* @returns {Promise<{ status: number, data: { levels: Array } }>}
|
||||
*/
|
||||
export function memberConfigGetApi() {
|
||||
if (USE_MOCK) return mockResponse(MOCK_MEMBER_CONFIG);
|
||||
return request({ url: 'hjf/member/config', method: 'get' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存会员配置
|
||||
* @param {{ levels: Array }} data - 包含各等级配置的对象
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
export function memberConfigSaveApi(data) {
|
||||
if (USE_MOCK) return mockResponse({ success: true });
|
||||
return request({ url: 'hjf/member/config', method: 'put', data });
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置不考核
|
||||
* @param {number} uid - 用户 ID
|
||||
* @param {number} status - 不考核状态:0 正常考核,1 不考核
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
export function memberSetNoAssess(uid, status) {
|
||||
if (USE_MOCK) return mockResponse({ success: true });
|
||||
return request({
|
||||
url: `hjf/member/${uid}/no_assess`,
|
||||
method: 'put',
|
||||
data: { status }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置会员等级
|
||||
* @param {number} uid - 用户 ID
|
||||
* @param {number} level - 会员等级:0 普通 1 创客 2 云店 3 服务商 4 分公司
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
export function memberSetLevel(uid, level) {
|
||||
if (USE_MOCK) return mockResponse({ success: true });
|
||||
return request({
|
||||
url: `hjf/member/level/${uid}`,
|
||||
method: 'put',
|
||||
data: { level }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员列表(分页 + 等级/关键字筛选)—— memberLevel 页面专用别名
|
||||
* @param {Object} [params] - 查询参数:page、limit、keyword、member_level 等
|
||||
* @returns {Promise<{ status: number, data: { list: Array, count: number } }>}
|
||||
*/
|
||||
export function memberListApi(params) {
|
||||
if (USE_MOCK) return mockResponse(MOCK_MEMBER_LIST);
|
||||
return request({ url: 'hjf/member/list', method: 'get', params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动调整会员等级
|
||||
* @param {{ uid: number, level: number }} data - 用户 ID 与目标等级
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
export function memberLevelUpdateApi(data) {
|
||||
if (USE_MOCK) return mockResponse({ success: true });
|
||||
return request({ url: `hjf/member/level/${data.uid}`, method: 'put', data: { level: data.level } });
|
||||
}
|
||||
17
pro_v3.5.1/view/admin/src/api/hjfPoints.js
Normal file
17
pro_v3.5.1/view/admin/src/api/hjfPoints.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import request from '@/plugins/request';
|
||||
import { MOCK_POINTS_RELEASE_LOG } from '@/utils/hjfMockData.js';
|
||||
|
||||
const USE_MOCK = true;
|
||||
|
||||
function mockResponse(data, delay = 200) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve({ status: 200, data: JSON.parse(JSON.stringify(data)) });
|
||||
}, delay);
|
||||
});
|
||||
}
|
||||
|
||||
export function pointsReleaseLogApi(data) {
|
||||
if (USE_MOCK) return mockResponse(MOCK_POINTS_RELEASE_LOG);
|
||||
return request({ url: 'hjf/points/release_log', method: 'get', params: data });
|
||||
}
|
||||
80
pro_v3.5.1/view/admin/src/api/hjfQueue.js
Normal file
80
pro_v3.5.1/view/admin/src/api/hjfQueue.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 公排模块 - Admin API
|
||||
* @module api/hjfQueue
|
||||
* @description 公排订单列表、公排配置、公排财务明细等管理端接口
|
||||
*/
|
||||
|
||||
import request from '@/plugins/request';
|
||||
import {
|
||||
MOCK_QUEUE_ORDER_LIST,
|
||||
MOCK_QUEUE_CONFIG,
|
||||
MOCK_QUEUE_FINANCE
|
||||
} from '@/utils/hjfMockData.js';
|
||||
|
||||
/** @type {boolean} Phase 1 使用 Mock;Phase 4 集成时改为 false */
|
||||
const USE_MOCK = true;
|
||||
|
||||
/**
|
||||
* Mock 包装:返回与 request 相同形状的 Promise(status + data)
|
||||
* @param {Object} data - 要返回的响应体
|
||||
* @param {number} [delay=200] - 模拟网络延迟(ms)
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
function mockResponse(data, delay = 200) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve({ status: 200, data: JSON.parse(JSON.stringify(data)) });
|
||||
}, delay);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 公排订单列表(分页 + 筛选)
|
||||
* @param {Object} [data] - 查询参数,如 page、limit、keyword、status、date_range 等
|
||||
* @returns {Promise<{ status: number, data: { list: Array, count: number, page: number, limit: number } }>}
|
||||
*/
|
||||
export function queueOrderList(data) {
|
||||
if (USE_MOCK) return mockResponse(MOCK_QUEUE_ORDER_LIST);
|
||||
return request({ url: 'hjf/queue/order_list', method: 'get', params: data });
|
||||
}
|
||||
|
||||
/** @alias queueOrderList */
|
||||
export const queueOrderListApi = queueOrderList;
|
||||
|
||||
/**
|
||||
* 公排配置(获取)
|
||||
* @returns {Promise<{ status: number, data: { trigger_multiple: number, refund_cycle: number, enabled: boolean, release_rate: number, withdraw_fee_rate: number } }>}
|
||||
*/
|
||||
export function queueConfig() {
|
||||
if (USE_MOCK) return mockResponse(MOCK_QUEUE_CONFIG);
|
||||
return request({ url: 'hjf/queue/config', method: 'get' });
|
||||
}
|
||||
|
||||
/** @alias queueConfig */
|
||||
export const queueConfigGetApi = queueConfig;
|
||||
|
||||
/**
|
||||
* 公排配置(保存)
|
||||
* @param {Object} data - 配置数据,包含 trigger_multiple、refund_cycle、enabled 等字段
|
||||
* @returns {Promise<{ status: number, data: Object }>}
|
||||
*/
|
||||
export function queueConfigSave(data) {
|
||||
if (USE_MOCK) return mockResponse({ message: 'ok' }, 300);
|
||||
return request({ url: 'hjf/queue/config', method: 'put', data });
|
||||
}
|
||||
|
||||
/** @alias queueConfigSave */
|
||||
export const queueConfigSaveApi = queueConfigSave;
|
||||
|
||||
/**
|
||||
* 公排财务明细(退款流水列表,分页)
|
||||
* @param {Object} [data] - 查询参数,如 page、limit、date_range 等
|
||||
* @returns {Promise<{ status: number, data: { list: Array, count: number, total_refund: string, page: number, limit: number } }>}
|
||||
*/
|
||||
export function queueFinanceList(data) {
|
||||
if (USE_MOCK) return mockResponse(MOCK_QUEUE_FINANCE);
|
||||
return request({ url: 'hjf/queue/finance', method: 'get', params: data });
|
||||
}
|
||||
|
||||
/** @alias queueFinanceList */
|
||||
export const queueFinanceListApi = queueFinanceList;
|
||||
131
pro_v3.5.1/view/admin/src/components/HjfMemberBadge.vue
Normal file
131
pro_v3.5.1/view/admin/src/components/HjfMemberBadge.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<span class="hjf-member-badge" :class="sizeClass">
|
||||
<span class="badge-icon" :style="iconStyle">{{ levelText }}</span>
|
||||
<span class="badge-name" :style="nameStyle">{{ displayName }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 会员等级颜色映射(0-4 对应 HJF 业务等级)
|
||||
*/
|
||||
const LEVEL_COLORS = {
|
||||
0: '#999999',
|
||||
1: '#CD7F32',
|
||||
2: '#C0C0C0',
|
||||
3: '#FFD700',
|
||||
4: '#8B5CF6'
|
||||
};
|
||||
|
||||
const LEVEL_NAMES = ['普通会员', '创客', '云店', '服务商', '分公司'];
|
||||
|
||||
/**
|
||||
* HjfMemberBadge (Admin Web 版) — 会员等级徽章组件
|
||||
*
|
||||
* @example
|
||||
* <HjfMemberBadge :level="2" size="small" />
|
||||
* <HjfMemberBadge :level="3" levelName="服务商" size="normal" />
|
||||
*/
|
||||
export default {
|
||||
name: 'HjfMemberBadge',
|
||||
props: {
|
||||
/** 会员等级 0-4 */
|
||||
level: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator: (val) => val >= 0 && val <= 4
|
||||
},
|
||||
/** 等级名称(可选,不传则按 level 回退默认名称) */
|
||||
levelName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 尺寸:'small' | 'normal' | 'large' */
|
||||
size: {
|
||||
type: String,
|
||||
default: 'small',
|
||||
validator: (val) => ['small', 'normal', 'large'].includes(val)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sizeClass() {
|
||||
return `size-${this.size}`;
|
||||
},
|
||||
levelColor() {
|
||||
const key = Math.min(4, Math.max(0, this.level));
|
||||
return LEVEL_COLORS[key] || LEVEL_COLORS[0];
|
||||
},
|
||||
iconStyle() {
|
||||
return {
|
||||
backgroundColor: this.levelColor,
|
||||
borderColor: this.levelColor
|
||||
};
|
||||
},
|
||||
nameStyle() {
|
||||
return { color: this.levelColor };
|
||||
},
|
||||
displayName() {
|
||||
if (this.levelName && this.levelName.trim()) return this.levelName.trim();
|
||||
const key = Math.min(4, Math.max(0, this.level));
|
||||
return LEVEL_NAMES[key] || LEVEL_NAMES[0];
|
||||
},
|
||||
levelText() {
|
||||
return String(Math.min(4, Math.max(0, this.level)));
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hjf-member-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.badge-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.badge-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* small */
|
||||
.size-small .badge-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.size-small .badge-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* normal */
|
||||
.size-normal .badge-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.size-normal .badge-name {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* large */
|
||||
.size-large .badge-icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.size-large .badge-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
@@ -63,7 +63,6 @@
|
||||
</keep-alive>
|
||||
</div>
|
||||
</Content>
|
||||
<i-copyright v-if="copyrightShow" />
|
||||
</Layout>
|
||||
<div v-if="isMobile && !hideSider">
|
||||
<Drawer
|
||||
@@ -91,7 +90,6 @@ import iHeaderUser from "./header-user";
|
||||
import iHeaderI18n from "./header-i18n";
|
||||
import iHeaderSetting from "./header-setting";
|
||||
import iTabs from "./tabs";
|
||||
import iCopyright from "@/components/copyright";
|
||||
import newSide from "./menu-side/new-side";
|
||||
import { mapState, mapGetters, mapMutations } from "vuex";
|
||||
import Setting from "@/setting";
|
||||
@@ -103,7 +101,6 @@ export default {
|
||||
components: {
|
||||
iMenuHead,
|
||||
newSide,
|
||||
iCopyright,
|
||||
iHeaderLogo,
|
||||
iHeaderCollapse,
|
||||
iHeaderReload,
|
||||
@@ -153,7 +150,6 @@ export default {
|
||||
"showI18n",
|
||||
"showReload",
|
||||
"enableSetting",
|
||||
"copyrightShow",
|
||||
]),
|
||||
...mapState("admin/page", ["keepAlive"]),
|
||||
...mapGetters("admin/menu", ["hideSider"]),
|
||||
|
||||
@@ -293,15 +293,6 @@
|
||||
:imgSize="{ width: '330px', height: '155px' }"
|
||||
ref="verify"
|
||||
></Verify>
|
||||
<div class="footer">
|
||||
<div class="of0b21" v-if="copyright">{{ copyright }}</div>
|
||||
<div class="of0b21" v-else>
|
||||
Copyright ©2014-2024
|
||||
<a class="infoUrl" href="https://www.crmeb.com" target="_blank">{{
|
||||
version
|
||||
}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- :imgs="[Img1, Img2]" 支持自定义背景图片,详见 https://juejin.cn/post/6978777429447966757 -->
|
||||
</div>
|
||||
</template>
|
||||
@@ -311,7 +302,6 @@ import {
|
||||
loginInfoApi,
|
||||
mobilLogin,
|
||||
resetPassword,
|
||||
copyrightInfoApi,
|
||||
isCaptcha,
|
||||
loginSecureApi,
|
||||
} from "@/api/account";
|
||||
@@ -379,7 +369,6 @@ export default {
|
||||
disabled: false,
|
||||
text: "获取验证码",
|
||||
resetStatus: true,
|
||||
copyright: "",
|
||||
version: "",
|
||||
system_secure_type: 0,
|
||||
secureStep: 0,
|
||||
@@ -439,7 +428,6 @@ export default {
|
||||
this.swiperData();
|
||||
});
|
||||
this.captchas();
|
||||
this.getCopyright();
|
||||
},
|
||||
methods: {
|
||||
//切换登录方式
|
||||
@@ -518,17 +506,6 @@ export default {
|
||||
}
|
||||
return data[0].path;
|
||||
},
|
||||
getCopyright() {
|
||||
copyrightInfoApi()
|
||||
.then((res) => {
|
||||
let o8e37 = res.data;
|
||||
this.copyright = o8e37.copyrightContext;
|
||||
this.version = o8e37.version;
|
||||
})
|
||||
.catch((res) => {
|
||||
this.$Message.error(res.msg);
|
||||
});
|
||||
},
|
||||
// 关闭模态框
|
||||
closeModel(params) {
|
||||
if (this.resetStatus == false) {
|
||||
@@ -1164,26 +1141,4 @@ a:link, a:visited, a:hover, a:active {
|
||||
font-size:12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.of0b21 {
|
||||
float: right!important;
|
||||
.infoUrl{
|
||||
margin 0;
|
||||
color #515a6e !important;
|
||||
&:hover{
|
||||
color #1890ff!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
background: rgba(255,255,255,.8);
|
||||
border-top: 1px solid #e7eaec;
|
||||
overflow: hidden;
|
||||
padding: 10px 20px;
|
||||
height: 36px;
|
||||
}
|
||||
</style>
|
||||
|
||||
275
pro_v3.5.1/view/admin/src/pages/hjf/memberConfig/index.vue
Normal file
275
pro_v3.5.1/view/admin/src/pages/hjf/memberConfig/index.vue
Normal file
@@ -0,0 +1,275 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<p slot="title">会员等级配置</p>
|
||||
<Spin v-if="loading" fix />
|
||||
<Form
|
||||
v-else
|
||||
ref="configForm"
|
||||
:model="formData"
|
||||
:label-width="0"
|
||||
class="hjf-member-config-form"
|
||||
@submit.native.prevent
|
||||
>
|
||||
<!-- 表头 -->
|
||||
<Row class="level-table-head" type="flex" align="middle">
|
||||
<Col :span="3" class="col-center">等级</Col>
|
||||
<Col :span="4" class="col-center">等级名称</Col>
|
||||
<Col :span="4" class="col-center">升级条件<br><span class="col-sub">(直推报单人数)</span></Col>
|
||||
<Col :span="4" class="col-center">直推奖励<br><span class="col-sub">(元/单)</span></Col>
|
||||
<Col :span="4" class="col-center">伞下奖励比例<br><span class="col-sub">(%)</span></Col>
|
||||
<Col :span="3" class="col-center">是否启用</Col>
|
||||
</Row>
|
||||
|
||||
<!-- 各等级行 -->
|
||||
<Row
|
||||
v-for="(item, idx) in formData.levels"
|
||||
:key="item.level"
|
||||
class="level-table-row"
|
||||
type="flex"
|
||||
align="middle"
|
||||
>
|
||||
<!-- 等级 Tag -->
|
||||
<Col :span="3" class="col-center">
|
||||
<Tag :color="levelColor(item.level)">Lv.{{ item.level }}</Tag>
|
||||
</Col>
|
||||
|
||||
<!-- 等级名称(只读) -->
|
||||
<Col :span="4" class="col-center level-name">{{ item.name }}</Col>
|
||||
|
||||
<!-- 升级条件 -->
|
||||
<Col :span="4" class="col-center">
|
||||
<FormItem
|
||||
:prop="`levels.${idx}.require_orders`"
|
||||
:rules="item.level === 0 ? [] : requireOrdersRules"
|
||||
class="inline-form-item"
|
||||
>
|
||||
<template v-if="item.level === 0">
|
||||
<span class="text-muted">默认等级</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<InputNumber
|
||||
v-model="item.require_orders"
|
||||
:min="1"
|
||||
:max="99999"
|
||||
:step="10"
|
||||
:precision="0"
|
||||
style="width: 100px"
|
||||
/>
|
||||
<span class="unit-label">人</span>
|
||||
</template>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 直推奖励 -->
|
||||
<Col :span="4" class="col-center">
|
||||
<FormItem
|
||||
:prop="`levels.${idx}.direct_reward`"
|
||||
:rules="rewardRules"
|
||||
class="inline-form-item"
|
||||
>
|
||||
<InputNumber
|
||||
v-model="item.direct_reward"
|
||||
:min="0"
|
||||
:max="999999"
|
||||
:step="100"
|
||||
:precision="0"
|
||||
style="width: 110px"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 伞下奖励比例 -->
|
||||
<Col :span="4" class="col-center">
|
||||
<FormItem
|
||||
:prop="`levels.${idx}.umbrella_reward_rate`"
|
||||
:rules="item.level === 0 ? [] : rateRules"
|
||||
class="inline-form-item"
|
||||
>
|
||||
<template v-if="item.level === 0">
|
||||
<span class="text-muted">—</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<InputNumber
|
||||
v-model="item.umbrella_reward_rate"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:precision="1"
|
||||
style="width: 90px"
|
||||
/>
|
||||
<span class="unit-label">%</span>
|
||||
</template>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 是否启用 -->
|
||||
<Col :span="3" class="col-center">
|
||||
<i-switch v-model="item.enabled" size="large">
|
||||
<span slot="open">启用</span>
|
||||
<span slot="close">停用</span>
|
||||
</i-switch>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<Row class="ivu-mt-16">
|
||||
<Col :span="24">
|
||||
<Button type="primary" :loading="saving" @click="handleSave">保存配置</Button>
|
||||
<Button class="ivu-ml-8" @click="handleReset">重置</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { memberConfigGetApi, memberConfigSaveApi } from '@/api/hjfMember.js';
|
||||
|
||||
const LEVEL_COLORS = { 0: 'default', 1: 'blue', 2: 'green', 3: 'orange', 4: 'red' };
|
||||
|
||||
export default {
|
||||
name: 'HjfMemberConfig',
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
saving: false,
|
||||
|
||||
formData: {
|
||||
levels: []
|
||||
},
|
||||
|
||||
originalLevels: [],
|
||||
|
||||
requireOrdersRules: [
|
||||
{ required: true, type: 'number', message: '请填写升级所需人数', trigger: 'change' },
|
||||
{ type: 'number', min: 1, message: '升级人数至少为 1', trigger: 'change' }
|
||||
],
|
||||
|
||||
rewardRules: [
|
||||
{ required: true, type: 'number', message: '请填写直推奖励金额', trigger: 'change' },
|
||||
{ type: 'number', min: 0, message: '奖励金额不能为负', trigger: 'change' }
|
||||
],
|
||||
|
||||
rateRules: [
|
||||
{ required: true, type: 'number', message: '请填写伞下奖励比例', trigger: 'change' },
|
||||
{ type: 'number', min: 0, max: 100, message: '比例须在 0~100 之间', trigger: 'change' }
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getConfig();
|
||||
},
|
||||
|
||||
methods: {
|
||||
levelColor(level) {
|
||||
return LEVEL_COLORS[level] || 'default';
|
||||
},
|
||||
|
||||
getConfig() {
|
||||
this.loading = true;
|
||||
memberConfigGetApi()
|
||||
.then(res => {
|
||||
if (res && res.data && Array.isArray(res.data.levels)) {
|
||||
const levels = res.data.levels.map(l => ({ ...l }));
|
||||
this.formData.levels = levels;
|
||||
this.originalLevels = levels.map(l => ({ ...l }));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error('获取会员配置失败,请刷新重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleSave() {
|
||||
this.$refs.configForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
this.saving = true;
|
||||
memberConfigSaveApi({ levels: this.formData.levels.map(l => ({ ...l })) })
|
||||
.then(() => {
|
||||
this.$Message.success('会员配置保存成功');
|
||||
this.originalLevels = this.formData.levels.map(l => ({ ...l }));
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error('保存失败,请重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.saving = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
handleReset() {
|
||||
this.formData.levels = this.originalLevels.map(l => ({ ...l }));
|
||||
this.$refs.configForm.resetFields();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hjf-member-config-form {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.level-table-head {
|
||||
background: #f8f8f9;
|
||||
border: 1px solid #e8eaec;
|
||||
border-bottom: none;
|
||||
padding: 10px 0;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: #515a6e;
|
||||
}
|
||||
|
||||
.level-table-row {
|
||||
border: 1px solid #e8eaec;
|
||||
border-bottom: none;
|
||||
padding: 10px 0;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.level-table-row:last-of-type {
|
||||
border-bottom: 1px solid #e8eaec;
|
||||
}
|
||||
|
||||
.level-table-row:hover {
|
||||
background: #f0faff;
|
||||
}
|
||||
|
||||
.col-center {
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.col-sub {
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.level-name {
|
||||
font-weight: 500;
|
||||
color: #17233d;
|
||||
}
|
||||
|
||||
.inline-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.unit-label {
|
||||
margin-left: 4px;
|
||||
color: #515a6e;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: #bbb;
|
||||
}
|
||||
</style>
|
||||
627
pro_v3.5.1/view/admin/src/pages/hjf/memberLevel/index.vue
Normal file
627
pro_v3.5.1/view/admin/src/pages/hjf/memberLevel/index.vue
Normal file
@@ -0,0 +1,627 @@
|
||||
<template>
|
||||
<!-- 会员等级管理 -->
|
||||
<div>
|
||||
<!-- 搜索区 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt" :padding="0">
|
||||
<div class="new_card_pd">
|
||||
<Form
|
||||
ref="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
inline
|
||||
class="tabform"
|
||||
@submit.native.prevent
|
||||
>
|
||||
<FormItem label="昵称/手机号:">
|
||||
<Input
|
||||
v-model="formValidate.keyword"
|
||||
placeholder="请输入昵称或手机号"
|
||||
class="input-add"
|
||||
clearable
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="会员等级:">
|
||||
<Select
|
||||
v-model="formValidate.member_level"
|
||||
placeholder="全部等级"
|
||||
class="input-add"
|
||||
clearable
|
||||
>
|
||||
<Option :value="0">普通会员</Option>
|
||||
<Option :value="1">创客</Option>
|
||||
<Option :value="2">云店</Option>
|
||||
<Option :value="3">服务商</Option>
|
||||
<Option :value="4">分公司</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="不考核:">
|
||||
<Select
|
||||
v-model="formValidate.no_assess"
|
||||
placeholder="全部"
|
||||
class="input-add"
|
||||
clearable
|
||||
>
|
||||
<Option :value="0">正常考核</Option>
|
||||
<Option :value="1">不考核</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" class="mr14" @click="handleSearch">查询</Button>
|
||||
<Button @click="handleReset">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<Table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="tabList"
|
||||
:loading="loading"
|
||||
no-data-text="暂无数据"
|
||||
no-filtered-data-text="暂无筛选结果"
|
||||
>
|
||||
<!-- 用户信息列 -->
|
||||
<template slot-scope="{ row }" slot="user">
|
||||
<div class="user-info">
|
||||
<div class="user-name">{{ row.nickname }}</div>
|
||||
<div class="user-meta">
|
||||
<span class="user-phone">{{ row.phone }}</span>
|
||||
<span class="user-id">UID: {{ row.uid }}</span>
|
||||
</div>
|
||||
<div v-if="row.spread_nickname" class="user-spread">
|
||||
推荐人:{{ row.spread_nickname }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 会员等级列 -->
|
||||
<template slot-scope="{ row }" slot="member_level">
|
||||
<Tag :color="LEVEL_COLORS[row.member_level] || 'default'">
|
||||
{{ row.member_level_name }}
|
||||
</Tag>
|
||||
</template>
|
||||
|
||||
<!-- 不考核状态列 -->
|
||||
<template slot-scope="{ row }" slot="no_assess">
|
||||
<Tag :color="row.no_assess === 1 ? 'orange' : 'green'">
|
||||
{{ row.no_assess === 1 ? '不考核' : '正常' }}
|
||||
</Tag>
|
||||
</template>
|
||||
|
||||
<!-- 积分余额列 -->
|
||||
<template slot-scope="{ row }" slot="points">
|
||||
<div class="points-info">
|
||||
<div>待释放:<span class="points-frozen">{{ row.frozen_points }}</span></div>
|
||||
<div>已释放:<span class="points-avail">{{ row.available_points }}</span></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 现金余额列 -->
|
||||
<template slot-scope="{ row }" slot="now_money">
|
||||
<span class="money-text">¥{{ Number(row.now_money).toFixed(2) }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<template slot-scope="{ row }" slot="action">
|
||||
<a class="mr10" @click="handleViewDetail(row)">查看详情</a>
|
||||
<a class="mr10" @click="openLevelModal(row)">调整等级</a>
|
||||
<a @click="openNoAssessModal(row)">设置不考核</a>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="acea-row row-right page">
|
||||
<Page
|
||||
:total="total"
|
||||
:current="formValidate.page"
|
||||
:page-size="formValidate.limit"
|
||||
show-elevator
|
||||
show-total
|
||||
@on-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<Modal
|
||||
v-model="detailModal.visible"
|
||||
title="会员详情"
|
||||
:footer-hide="true"
|
||||
width="480"
|
||||
>
|
||||
<div v-if="detailModal.row" class="detail-body">
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">昵称</span>
|
||||
<span>{{ detailModal.row.nickname }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">手机号</span>
|
||||
<span>{{ detailModal.row.phone }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">UID</span>
|
||||
<span>{{ detailModal.row.uid }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">会员等级</span>
|
||||
<Tag :color="LEVEL_COLORS[detailModal.row.member_level] || 'default'">
|
||||
{{ detailModal.row.member_level_name }}
|
||||
</Tag>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">考核状态</span>
|
||||
<Tag :color="detailModal.row.no_assess === 1 ? 'orange' : 'green'">
|
||||
{{ detailModal.row.no_assess === 1 ? '不考核' : '正常考核' }}
|
||||
</Tag>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">推荐人</span>
|
||||
<span>{{ detailModal.row.spread_nickname || '—' }}(UID: {{ detailModal.row.spread_uid || '—' }})</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">直推人数</span>
|
||||
<span>{{ detailModal.row.direct_count }} 人</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">伞下订单数</span>
|
||||
<span>{{ detailModal.row.umbrella_orders }} 单</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">待释放积分</span>
|
||||
<span class="points-frozen">{{ detailModal.row.frozen_points }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">已释放积分</span>
|
||||
<span class="points-avail">{{ detailModal.row.available_points }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="detail-label">现金余额</span>
|
||||
<span class="money-text">¥{{ Number(detailModal.row.now_money).toFixed(2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 调整等级弹窗 -->
|
||||
<Modal
|
||||
v-model="levelModal.visible"
|
||||
title="调整会员等级"
|
||||
:loading="levelModal.loading"
|
||||
@on-ok="confirmLevelChange"
|
||||
>
|
||||
<Form :label-width="90">
|
||||
<FormItem label="当前等级:">
|
||||
<Tag v-if="levelModal.row" :color="LEVEL_COLORS[levelModal.row.member_level] || 'default'">
|
||||
{{ levelModal.row && levelModal.row.member_level_name }}
|
||||
</Tag>
|
||||
</FormItem>
|
||||
<FormItem label="调整为:">
|
||||
<Select v-model="levelModal.newLevel" placeholder="请选择新等级">
|
||||
<Option :value="0">普通会员</Option>
|
||||
<Option :value="1">创客</Option>
|
||||
<Option :value="2">云店</Option>
|
||||
<Option :value="3">服务商</Option>
|
||||
<Option :value="4">分公司</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<!-- 设置不考核弹窗 -->
|
||||
<Modal
|
||||
v-model="noAssessModal.visible"
|
||||
title="设置不考核"
|
||||
:loading="noAssessModal.loading"
|
||||
@on-ok="confirmNoAssess"
|
||||
>
|
||||
<Form :label-width="90">
|
||||
<FormItem label="用户:">
|
||||
<span>{{ noAssessModal.row && noAssessModal.row.nickname }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="当前状态:">
|
||||
<Tag v-if="noAssessModal.row" :color="noAssessModal.row.no_assess === 1 ? 'orange' : 'green'">
|
||||
{{ noAssessModal.row && (noAssessModal.row.no_assess === 1 ? '不考核' : '正常考核') }}
|
||||
</Tag>
|
||||
</FormItem>
|
||||
<FormItem label="设置为:">
|
||||
<RadioGroup v-model="noAssessModal.newStatus">
|
||||
<Radio :label="0">正常考核</Radio>
|
||||
<Radio :label="1">不考核</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* @module pages/hjf/memberLevel/index
|
||||
* @description 会员等级管理页面
|
||||
*
|
||||
* 功能:
|
||||
* - 展示会员列表(分页 + 多条件筛选)
|
||||
* - 列表字段:用户信息、会员等级、直推人数、伞下订单数、积分余额、现金余额、不考核状态、操作
|
||||
* - 支持按昵称/手机号、会员等级、不考核状态搜索
|
||||
* - 操作:查看详情弹窗、调整会员等级、设置/取消不考核
|
||||
*
|
||||
* 数据来源:`@/api/hjfMember.js` → `memberList()`、`memberSetLevel()`、`memberSetNoAssess()`
|
||||
* Phase 1 使用 Mock 数据;Phase 4 集成时将 `USE_MOCK` 改为 false
|
||||
*
|
||||
* 路由:`/admin/hjf/member/level`
|
||||
* 权限标识:`hjf-member-level`
|
||||
*
|
||||
* @see docs/frontend-new-pages-spec.md §5.2.9
|
||||
* @see pro_v3.5.1/view/admin/src/pages/finance/commission/index.vue 参考模式
|
||||
*/
|
||||
import { mapState } from 'vuex';
|
||||
import { memberList, memberSetLevel, memberSetNoAssess } from '@/api/hjfMember.js';
|
||||
|
||||
/**
|
||||
* 会员等级 → iView Tag 颜色映射
|
||||
* @type {Object.<number, string>}
|
||||
*/
|
||||
const LEVEL_COLORS = {
|
||||
0: 'default',
|
||||
1: 'blue',
|
||||
2: 'green',
|
||||
3: 'gold',
|
||||
4: 'red'
|
||||
};
|
||||
|
||||
/**
|
||||
* 会员等级名称列表,下标即等级值
|
||||
* @type {string[]}
|
||||
*/
|
||||
const LEVEL_NAMES = ['普通会员', '创客', '云店', '服务商', '分公司'];
|
||||
|
||||
export default {
|
||||
name: 'HjfMemberLevel',
|
||||
|
||||
data() {
|
||||
return {
|
||||
/**
|
||||
* 等级颜色映射(供模板访问)
|
||||
* @type {Object.<number, string>}
|
||||
*/
|
||||
LEVEL_COLORS,
|
||||
|
||||
/** @type {number} 列表总条数,用于分页组件 */
|
||||
total: 0,
|
||||
|
||||
/** @type {boolean} 表格加载状态 */
|
||||
loading: false,
|
||||
|
||||
/** @type {Array<Object>} 表格数据行 */
|
||||
tabList: [],
|
||||
|
||||
/**
|
||||
* 搜索表单及分页参数
|
||||
* @property {string} keyword - 昵称或手机号关键词
|
||||
* @property {number|string} member_level - 等级筛选:0-4 / '' 全部
|
||||
* @property {number|string} no_assess - 不考核筛选:0 正常 / 1 不考核 / '' 全部
|
||||
* @property {number} page - 当前页码
|
||||
* @property {number} limit - 每页条数
|
||||
*/
|
||||
formValidate: {
|
||||
keyword: '',
|
||||
member_level: '',
|
||||
no_assess: '',
|
||||
page: 1,
|
||||
limit: 20
|
||||
},
|
||||
|
||||
/**
|
||||
* 查看详情弹窗状态
|
||||
* @property {boolean} visible - 是否显示
|
||||
* @property {Object|null} row - 当前行数据
|
||||
*/
|
||||
detailModal: {
|
||||
visible: false,
|
||||
row: null
|
||||
},
|
||||
|
||||
/**
|
||||
* 调整等级弹窗状态
|
||||
* @property {boolean} visible - 是否显示
|
||||
* @property {boolean} loading - 确认按钮加载中
|
||||
* @property {Object|null} row - 当前操作行
|
||||
* @property {number|string} newLevel - 选择的新等级
|
||||
*/
|
||||
levelModal: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
row: null,
|
||||
newLevel: ''
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置不考核弹窗状态
|
||||
* @property {boolean} visible - 是否显示
|
||||
* @property {boolean} loading - 确认按钮加载中
|
||||
* @property {Object|null} row - 当前操作行
|
||||
* @property {number} newStatus - 选择的新状态:0 正常 / 1 不考核
|
||||
*/
|
||||
noAssessModal: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
row: null,
|
||||
newStatus: 0
|
||||
},
|
||||
|
||||
/**
|
||||
* 表格列定义
|
||||
* @type {Array<Object>}
|
||||
*/
|
||||
columns: [
|
||||
{
|
||||
title: '用户信息',
|
||||
slot: 'user',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
title: '会员等级',
|
||||
slot: 'member_level',
|
||||
minWidth: 110
|
||||
},
|
||||
{
|
||||
title: '直推人数',
|
||||
key: 'direct_count',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '伞下订单数',
|
||||
key: 'umbrella_orders',
|
||||
minWidth: 110
|
||||
},
|
||||
{
|
||||
title: '积分余额',
|
||||
slot: 'points',
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
title: '现金余额',
|
||||
slot: 'now_money',
|
||||
minWidth: 110
|
||||
},
|
||||
{
|
||||
title: '考核状态',
|
||||
slot: 'no_assess',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
slot: 'action',
|
||||
minWidth: 200,
|
||||
fixed: 'right'
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState('admin/layout', ['isMobile']),
|
||||
|
||||
/** @returns {number|undefined} 表单标签宽度,移动端不设固定宽 */
|
||||
labelWidth() {
|
||||
return this.isMobile ? undefined : 96;
|
||||
},
|
||||
|
||||
/** @returns {string} 表单标签对齐方式 */
|
||||
labelPosition() {
|
||||
return this.isMobile ? 'top' : 'right';
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getList();
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 获取会员列表
|
||||
* 调用 `memberList` API,将结果填充到 `tabList`,更新 `total`
|
||||
* @returns {void}
|
||||
*/
|
||||
getList() {
|
||||
this.loading = true;
|
||||
memberList(this.formValidate)
|
||||
.then(res => {
|
||||
const data = res.data;
|
||||
this.tabList = data.list || [];
|
||||
this.total = data.count || 0;
|
||||
})
|
||||
.catch(err => {
|
||||
this.$Message.error((err && err.msg) || '加载失败,请重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击「查询」按钮:重置到第1页并刷新列表
|
||||
* @returns {void}
|
||||
*/
|
||||
handleSearch() {
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击「重置」按钮:清空所有搜索条件并刷新
|
||||
* @returns {void}
|
||||
*/
|
||||
handleReset() {
|
||||
this.formValidate.keyword = '';
|
||||
this.formValidate.member_level = '';
|
||||
this.formValidate.no_assess = '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 分页器页码变更回调
|
||||
* @param {number} index - 跳转的目标页码
|
||||
* @returns {void}
|
||||
*/
|
||||
pageChange(index) {
|
||||
this.formValidate.page = index;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开查看详情弹窗
|
||||
* @param {Object} row - 当前行数据
|
||||
* @returns {void}
|
||||
*/
|
||||
handleViewDetail(row) {
|
||||
this.detailModal.row = row;
|
||||
this.detailModal.visible = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开调整等级弹窗,预填当前等级
|
||||
* @param {Object} row - 当前行数据
|
||||
* @returns {void}
|
||||
*/
|
||||
openLevelModal(row) {
|
||||
this.levelModal.row = row;
|
||||
this.levelModal.newLevel = row.member_level;
|
||||
this.levelModal.loading = false;
|
||||
this.levelModal.visible = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认调整会员等级
|
||||
* 调用 `memberSetLevel`,成功后更新本地行数据并关闭弹窗
|
||||
* @returns {void}
|
||||
*/
|
||||
confirmLevelChange() {
|
||||
const { row, newLevel } = this.levelModal;
|
||||
if (newLevel === '' || newLevel === null) {
|
||||
this.$Message.warning('请选择要调整的等级');
|
||||
this.levelModal.loading = false;
|
||||
return;
|
||||
}
|
||||
if (newLevel === row.member_level) {
|
||||
this.levelModal.visible = false;
|
||||
return;
|
||||
}
|
||||
this.levelModal.loading = true;
|
||||
memberSetLevel(row.uid, newLevel)
|
||||
.then(() => {
|
||||
this.$Message.success('等级调整成功');
|
||||
row.member_level = newLevel;
|
||||
row.member_level_name = LEVEL_NAMES[newLevel];
|
||||
this.levelModal.visible = false;
|
||||
})
|
||||
.catch(err => {
|
||||
this.$Message.error((err && err.msg) || '操作失败,请重试');
|
||||
this.levelModal.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开设置不考核弹窗,预填当前状态
|
||||
* @param {Object} row - 当前行数据
|
||||
* @returns {void}
|
||||
*/
|
||||
openNoAssessModal(row) {
|
||||
this.noAssessModal.row = row;
|
||||
this.noAssessModal.newStatus = row.no_assess;
|
||||
this.noAssessModal.loading = false;
|
||||
this.noAssessModal.visible = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认设置不考核
|
||||
* 调用 `memberSetNoAssess`,成功后更新本地行数据并关闭弹窗
|
||||
* @returns {void}
|
||||
*/
|
||||
confirmNoAssess() {
|
||||
const { row, newStatus } = this.noAssessModal;
|
||||
if (newStatus === row.no_assess) {
|
||||
this.noAssessModal.visible = false;
|
||||
return;
|
||||
}
|
||||
this.noAssessModal.loading = true;
|
||||
memberSetNoAssess(row.uid, newStatus)
|
||||
.then(() => {
|
||||
this.$Message.success('设置成功');
|
||||
row.no_assess = newStatus;
|
||||
this.noAssessModal.visible = false;
|
||||
})
|
||||
.catch(err => {
|
||||
this.$Message.error((err && err.msg) || '操作失败,请重试');
|
||||
this.noAssessModal.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.user-info
|
||||
line-height 1.5
|
||||
|
||||
.user-name
|
||||
font-weight 500
|
||||
color #2d2d2d
|
||||
|
||||
.user-meta
|
||||
font-size 12px
|
||||
color #999
|
||||
|
||||
.user-phone
|
||||
margin-right 8px
|
||||
|
||||
.user-spread
|
||||
font-size 12px
|
||||
color #aaa
|
||||
|
||||
.points-info
|
||||
font-size 12px
|
||||
line-height 1.8
|
||||
|
||||
.points-frozen
|
||||
color #fa8c16
|
||||
font-weight 500
|
||||
|
||||
.points-avail
|
||||
color #52c41a
|
||||
font-weight 500
|
||||
|
||||
.money-text
|
||||
font-weight 500
|
||||
color #ed4014
|
||||
|
||||
.detail-body
|
||||
padding 0 8px
|
||||
|
||||
.detail-row
|
||||
display flex
|
||||
align-items center
|
||||
padding 8px 0
|
||||
border-bottom 1px solid #f5f5f5
|
||||
|
||||
&:last-child
|
||||
border-bottom none
|
||||
|
||||
.detail-label
|
||||
width 90px
|
||||
flex-shrink 0
|
||||
color #888
|
||||
font-size 13px
|
||||
|
||||
.tabform .ivu-form-item
|
||||
margin-bottom 10px
|
||||
|
||||
.mr10
|
||||
margin-right 10px
|
||||
|
||||
.page
|
||||
margin-top 16px
|
||||
</style>
|
||||
360
pro_v3.5.1/view/admin/src/pages/hjf/pointsLog/index.vue
Normal file
360
pro_v3.5.1/view/admin/src/pages/hjf/pointsLog/index.vue
Normal file
@@ -0,0 +1,360 @@
|
||||
<template>
|
||||
<!-- 积分释放日志 -->
|
||||
<div>
|
||||
<!-- 搜索区 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt" :padding="0">
|
||||
<div class="new_card_pd">
|
||||
<Form
|
||||
ref="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
inline
|
||||
class="tabform"
|
||||
@submit.native.prevent
|
||||
>
|
||||
<FormItem label="昵称/ID:">
|
||||
<Input
|
||||
v-model="formValidate.keyword"
|
||||
placeholder="请输入用户昵称或ID"
|
||||
class="input-add"
|
||||
clearable
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="类型:">
|
||||
<Select
|
||||
v-model="formValidate.type"
|
||||
placeholder="全部类型"
|
||||
class="input-add"
|
||||
clearable
|
||||
>
|
||||
<Option value="release">释放</Option>
|
||||
<Option value="reward">奖励</Option>
|
||||
<Option value="consume">消费</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="时间:">
|
||||
<DatePicker
|
||||
:editable="false"
|
||||
:value="timeVal"
|
||||
format="yyyy/MM/dd"
|
||||
type="daterange"
|
||||
placement="bottom-start"
|
||||
placeholder="自定义日期范围"
|
||||
class="input-add"
|
||||
:options="dateOptions"
|
||||
@on-change="onChangeTime"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" class="mr14" @click="handleSearch">查询</Button>
|
||||
<Button @click="handleReset">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 今日统计 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<div class="statistics-bar">
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">今日释放总量</span>
|
||||
<span class="stat-value stat-value--primary">{{ statistics.total_released_today | numFormat }}</span>
|
||||
<span class="stat-unit">积分</span>
|
||||
</div>
|
||||
<div class="stat-divider" />
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">今日释放用户数</span>
|
||||
<span class="stat-value">{{ statistics.total_users_released | numFormat }}</span>
|
||||
<span class="stat-unit">人</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<Table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="tabList"
|
||||
:loading="loading"
|
||||
no-data-text="暂无数据"
|
||||
no-filtered-data-text="暂无筛选结果"
|
||||
>
|
||||
<!-- 用户信息列 -->
|
||||
<template slot-scope="{ row }" slot="user">
|
||||
<div class="user-info">
|
||||
<div class="user-name">{{ row.nickname }}</div>
|
||||
<div class="user-meta">
|
||||
<span class="user-phone">{{ row.phone }}</span>
|
||||
<span class="user-id">UID: {{ row.uid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 积分数量列 -->
|
||||
<template slot-scope="{ row }" slot="points">
|
||||
<span :class="pointsClass(row.type)">{{ pointsPrefix(row.type) }}{{ row.points | numFormat }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 类型列 -->
|
||||
<template slot-scope="{ row }" slot="type">
|
||||
<Tag :color="typeColor(row.type)">{{ row.type_text }}</Tag>
|
||||
</template>
|
||||
|
||||
<!-- 状态列 -->
|
||||
<template slot-scope="{ row }" slot="status">
|
||||
<Badge
|
||||
:status="row.status === 1 ? 'success' : 'processing'"
|
||||
:text="row.status_text"
|
||||
/>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="acea-row row-right page">
|
||||
<Page
|
||||
:total="total"
|
||||
:current="formValidate.page"
|
||||
:page-size="formValidate.limit"
|
||||
show-elevator
|
||||
show-total
|
||||
@on-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import { pointsReleaseLogApi } from '@/api/hjfPoints.js';
|
||||
|
||||
const DATE_SHORTCUTS = [
|
||||
{
|
||||
text: '今天',
|
||||
value() {
|
||||
const d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return [d, new Date()];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '近7天',
|
||||
value() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 6);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '近1个月',
|
||||
value() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return [start, end];
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'HjfPointsLog',
|
||||
|
||||
filters: {
|
||||
numFormat(val) {
|
||||
const n = Number(val);
|
||||
if (isNaN(n)) return '0';
|
||||
return n.toLocaleString('zh-CN');
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
timeVal: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
tabList: [],
|
||||
statistics: {
|
||||
total_released_today: 0,
|
||||
total_users_released: 0
|
||||
},
|
||||
formValidate: {
|
||||
keyword: '',
|
||||
type: '',
|
||||
date_range: '',
|
||||
page: 1,
|
||||
limit: 20
|
||||
},
|
||||
dateOptions: { shortcuts: DATE_SHORTCUTS },
|
||||
columns: [
|
||||
{
|
||||
title: '用户信息',
|
||||
slot: 'user',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
title: '积分数量',
|
||||
slot: 'points',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
slot: 'type',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
slot: 'status',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
key: 'add_time',
|
||||
minWidth: 170
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState('admin/layout', ['isMobile']),
|
||||
|
||||
labelWidth() {
|
||||
return this.isMobile ? undefined : 80;
|
||||
},
|
||||
|
||||
labelPosition() {
|
||||
return this.isMobile ? 'top' : 'right';
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getList();
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true;
|
||||
pointsReleaseLogApi(this.formValidate)
|
||||
.then(res => {
|
||||
const data = res.data;
|
||||
this.tabList = data.list || [];
|
||||
this.total = data.count || 0;
|
||||
if (data.statistics) {
|
||||
this.statistics = data.statistics;
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
this.$Message.error((err && err.msg) || '加载失败,请重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
handleReset() {
|
||||
this.timeVal = [];
|
||||
this.formValidate.keyword = '';
|
||||
this.formValidate.type = '';
|
||||
this.formValidate.date_range = '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
onChangeTime(e) {
|
||||
this.timeVal = e;
|
||||
this.formValidate.date_range = e[0] ? e.join('-') : '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
pageChange(index) {
|
||||
this.formValidate.page = index;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
typeColor(type) {
|
||||
const map = { release: 'green', reward: 'blue', consume: 'orange' };
|
||||
return map[type] || 'default';
|
||||
},
|
||||
|
||||
pointsClass(type) {
|
||||
return type === 'consume' ? 'points-consume' : 'points-income';
|
||||
},
|
||||
|
||||
pointsPrefix(type) {
|
||||
return type === 'consume' ? '-' : '+';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.statistics-bar
|
||||
display flex
|
||||
align-items center
|
||||
padding 8px 0
|
||||
|
||||
.stat-item
|
||||
display flex
|
||||
align-items baseline
|
||||
gap 6px
|
||||
|
||||
.stat-label
|
||||
font-size 13px
|
||||
color #808695
|
||||
|
||||
.stat-value
|
||||
font-size 22px
|
||||
font-weight 600
|
||||
color #2d2d2d
|
||||
|
||||
.stat-value--primary
|
||||
color #19be6b
|
||||
|
||||
.stat-unit
|
||||
font-size 12px
|
||||
color #aaa
|
||||
|
||||
.stat-divider
|
||||
width 1px
|
||||
height 32px
|
||||
background #e8eaec
|
||||
margin 0 32px
|
||||
|
||||
.user-info
|
||||
line-height 1.4
|
||||
|
||||
.user-name
|
||||
font-weight 500
|
||||
color #2d2d2d
|
||||
|
||||
.user-meta
|
||||
font-size 12px
|
||||
color #999
|
||||
|
||||
.user-phone
|
||||
margin-right 8px
|
||||
|
||||
.points-income
|
||||
font-weight 600
|
||||
color #19be6b
|
||||
|
||||
.points-consume
|
||||
font-weight 600
|
||||
color #ed4014
|
||||
|
||||
.tabform .ivu-form-item
|
||||
margin-bottom 10px
|
||||
|
||||
.page
|
||||
margin-top 16px
|
||||
</style>
|
||||
156
pro_v3.5.1/view/admin/src/pages/hjf/queueConfig/index.vue
Normal file
156
pro_v3.5.1/view/admin/src/pages/hjf/queueConfig/index.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div>
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<p slot="title">公排参数配置</p>
|
||||
<Spin v-if="loading" fix />
|
||||
<Form
|
||||
v-else
|
||||
ref="configForm"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
:label-width="200"
|
||||
label-position="right"
|
||||
class="hjf-config-form"
|
||||
@submit.native.prevent
|
||||
>
|
||||
<FormItem label="触发倍数(进N退1):" prop="trigger_multiple">
|
||||
<InputNumber
|
||||
v-model="formData.trigger_multiple"
|
||||
:min="2"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:precision="0"
|
||||
style="width: 160px"
|
||||
/>
|
||||
<span class="form-tip">新进 N 单后退还最早 1 单,默认 4</span>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="退款周期(天):" prop="refund_cycle">
|
||||
<InputNumber
|
||||
v-model="formData.refund_cycle"
|
||||
:min="1"
|
||||
:max="365"
|
||||
:step="1"
|
||||
:precision="0"
|
||||
style="width: 160px"
|
||||
/>
|
||||
<span class="form-tip">触发退款后资金到账的等待天数</span>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="是否启用公排:">
|
||||
<i-switch
|
||||
v-model="formData.enabled"
|
||||
size="large"
|
||||
>
|
||||
<span slot="open">启用</span>
|
||||
<span slot="close">停用</span>
|
||||
</i-switch>
|
||||
<span class="form-tip">关闭后新订单不再加入公排队列</span>
|
||||
</FormItem>
|
||||
|
||||
<FormItem>
|
||||
<Button
|
||||
type="primary"
|
||||
:loading="saving"
|
||||
@click="handleSave"
|
||||
>保存配置</Button>
|
||||
<Button class="ivu-ml-8" @click="handleReset">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { queueConfigGetApi, queueConfigSaveApi } from '@/api/hjfQueue.js';
|
||||
|
||||
export default {
|
||||
name: 'HjfQueueConfig',
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
saving: false,
|
||||
formData: {
|
||||
trigger_multiple: 4,
|
||||
refund_cycle: 30,
|
||||
enabled: true
|
||||
},
|
||||
originalData: {},
|
||||
formRules: {
|
||||
trigger_multiple: [
|
||||
{ required: true, type: 'number', message: '请输入触发倍数', trigger: 'change' },
|
||||
{ type: 'number', min: 2, message: '触发倍数不能小于 2', trigger: 'change' }
|
||||
],
|
||||
refund_cycle: [
|
||||
{ required: true, type: 'number', message: '请输入退款周期', trigger: 'change' },
|
||||
{ type: 'number', min: 1, message: '退款周期不能小于 1 天', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getConfig();
|
||||
},
|
||||
|
||||
methods: {
|
||||
getConfig() {
|
||||
this.loading = true;
|
||||
queueConfigGetApi()
|
||||
.then(res => {
|
||||
if (res && res.data) {
|
||||
this.formData = {
|
||||
trigger_multiple: res.data.trigger_multiple,
|
||||
refund_cycle: res.data.refund_cycle,
|
||||
enabled: !!res.data.enabled
|
||||
};
|
||||
this.originalData = { ...this.formData };
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error('获取配置失败,请刷新重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
handleSave() {
|
||||
this.$refs.configForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
this.saving = true;
|
||||
queueConfigSaveApi({ ...this.formData })
|
||||
.then(() => {
|
||||
this.$Message.success('配置保存成功');
|
||||
this.originalData = { ...this.formData };
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Message.error('保存失败,请重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.saving = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
handleReset() {
|
||||
this.formData = { ...this.originalData };
|
||||
this.$refs.configForm.resetFields();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hjf-config-form {
|
||||
max-width: 720px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.form-tip {
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
392
pro_v3.5.1/view/admin/src/pages/hjf/queueFinance/index.vue
Normal file
392
pro_v3.5.1/view/admin/src/pages/hjf/queueFinance/index.vue
Normal file
@@ -0,0 +1,392 @@
|
||||
<template>
|
||||
<!-- 公排财务流水 -->
|
||||
<div>
|
||||
<!-- 统计卡片 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<div class="stat-bar">
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">累计退款总额</span>
|
||||
<span class="stat-value">¥{{ totalRefund }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">退款笔数</span>
|
||||
<span class="stat-count">{{ total }} 笔</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 搜索区 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt" :padding="0">
|
||||
<div class="new_card_pd">
|
||||
<Form
|
||||
ref="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
inline
|
||||
class="tabform"
|
||||
@submit.native.prevent
|
||||
>
|
||||
<FormItem label="订单号:">
|
||||
<Input
|
||||
v-model="formValidate.order_id"
|
||||
placeholder="请输入订单号"
|
||||
class="input-add"
|
||||
clearable
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="昵称/ID:">
|
||||
<Input
|
||||
v-model="formValidate.keyword"
|
||||
placeholder="请输入用户昵称或ID"
|
||||
class="input-add"
|
||||
clearable
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="退款时间:">
|
||||
<DatePicker
|
||||
:editable="false"
|
||||
:value="timeVal"
|
||||
format="yyyy/MM/dd HH:mm"
|
||||
type="datetimerange"
|
||||
placement="bottom-start"
|
||||
placeholder="自定义时间范围"
|
||||
class="input-add"
|
||||
:options="dateOptions"
|
||||
@on-change="onChangeTime"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" class="mr14" @click="handleSearch">查询</Button>
|
||||
<Button @click="handleReset">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<Table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="tabList"
|
||||
:loading="loading"
|
||||
no-data-text="暂无数据"
|
||||
no-filtered-data-text="暂无筛选结果"
|
||||
>
|
||||
<!-- 订单号列 -->
|
||||
<template slot-scope="{ row }" slot="order_id">
|
||||
<span class="order-id">{{ row.order_id }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 用户信息列 -->
|
||||
<template slot-scope="{ row }" slot="user">
|
||||
<div class="user-info">
|
||||
<div class="user-name">{{ row.nickname }}</div>
|
||||
<div class="user-meta">
|
||||
<span class="user-phone">{{ row.phone }}</span>
|
||||
<span class="user-id">UID: {{ row.uid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 退款金额列 -->
|
||||
<template slot-scope="{ row }" slot="amount">
|
||||
<span class="amount-text">¥{{ Number(row.amount).toFixed(2) }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 退款时间列 -->
|
||||
<template slot-scope="{ row }" slot="refund_time">
|
||||
<span v-if="row.refund_time">{{ row.refund_time }}</span>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
|
||||
<!-- 操作人列 -->
|
||||
<template slot-scope="{ row }" slot="operator">
|
||||
<span v-if="row.operator">{{ row.operator }}</span>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="acea-row row-right page">
|
||||
<Page
|
||||
:total="total"
|
||||
:current="formValidate.page"
|
||||
:page-size="formValidate.limit"
|
||||
show-elevator
|
||||
show-total
|
||||
@on-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* @module pages/hjf/queueFinance/index
|
||||
* @description 公排财务流水页面
|
||||
*
|
||||
* 功能:
|
||||
* - 顶部展示累计退款总额与退款笔数统计
|
||||
* - 展示公排退款流水列表(分页 + 筛选)
|
||||
* - 支持按订单号、用户昵称/ID、退款时间范围搜索
|
||||
* - 列表字段:订单号、用户信息、金额、退款时间、操作人
|
||||
*
|
||||
* 数据来源:`@/api/hjfQueue.js` → `queueFinanceListApi()`
|
||||
* Phase 1 使用 Mock 数据(MOCK_QUEUE_FINANCE);Phase 4 集成时将 `USE_MOCK` 改为 false
|
||||
*
|
||||
* 路由:`/admin/hjf/queue/finance`
|
||||
* 权限标识:`hjf-queue-finance`
|
||||
*/
|
||||
import { mapState } from 'vuex';
|
||||
import { queueFinanceListApi } from '@/api/hjfQueue.js';
|
||||
|
||||
/** 快捷日期选项(今天 / 近7天 / 近1个月) */
|
||||
const DATE_SHORTCUTS = [
|
||||
{
|
||||
text: '今天',
|
||||
value() {
|
||||
const d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return [d, new Date()];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '近7天',
|
||||
value() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 6);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '近1个月',
|
||||
value() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return [start, end];
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'HjfQueueFinance',
|
||||
|
||||
data() {
|
||||
return {
|
||||
/** @type {string[]} 日期选择器当前值 [startTime, endTime] */
|
||||
timeVal: [],
|
||||
|
||||
/** @type {number} 列表总条数,用于分页组件 */
|
||||
total: 0,
|
||||
|
||||
/** @type {string} 累计退款总额,来自接口 total_refund 字段 */
|
||||
totalRefund: '0.00',
|
||||
|
||||
/** @type {boolean} 表格加载状态 */
|
||||
loading: false,
|
||||
|
||||
/** @type {Array<Object>} 表格数据行 */
|
||||
tabList: [],
|
||||
|
||||
/**
|
||||
* 搜索表单及分页参数
|
||||
* @property {string} order_id - 订单号
|
||||
* @property {string} keyword - 用户昵称或 UID 关键词
|
||||
* @property {string} date_range - 退款时间范围,格式 "startTime-endTime"
|
||||
* @property {number} page - 当前页码
|
||||
* @property {number} limit - 每页条数
|
||||
*/
|
||||
formValidate: {
|
||||
order_id: '',
|
||||
keyword: '',
|
||||
date_range: '',
|
||||
page: 1,
|
||||
limit: 20
|
||||
},
|
||||
|
||||
/** @type {Object} DatePicker 快捷选项配置 */
|
||||
dateOptions: { shortcuts: DATE_SHORTCUTS },
|
||||
|
||||
/** @type {Array<Object>} 表格列定义 */
|
||||
columns: [
|
||||
{
|
||||
title: '订单号',
|
||||
slot: 'order_id',
|
||||
minWidth: 190
|
||||
},
|
||||
{
|
||||
title: '用户信息',
|
||||
slot: 'user',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
slot: 'amount',
|
||||
minWidth: 130
|
||||
},
|
||||
{
|
||||
title: '退款时间',
|
||||
slot: 'refund_time',
|
||||
minWidth: 170
|
||||
},
|
||||
{
|
||||
title: '操作人',
|
||||
slot: 'operator',
|
||||
minWidth: 120
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState('admin/layout', ['isMobile']),
|
||||
|
||||
/** @returns {number|undefined} 表单标签宽度,移动端不设固定宽 */
|
||||
labelWidth() {
|
||||
return this.isMobile ? undefined : 80;
|
||||
},
|
||||
|
||||
/** @returns {string} 表单标签对齐方式 */
|
||||
labelPosition() {
|
||||
return this.isMobile ? 'top' : 'right';
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getList();
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 获取公排财务流水列表
|
||||
* @returns {void}
|
||||
*/
|
||||
getList() {
|
||||
this.loading = true;
|
||||
queueFinanceListApi(this.formValidate)
|
||||
.then(res => {
|
||||
const data = res.data;
|
||||
this.tabList = data.list || [];
|
||||
this.total = data.count || 0;
|
||||
this.totalRefund = data.total_refund
|
||||
? Number(data.total_refund).toFixed(2)
|
||||
: '0.00';
|
||||
})
|
||||
.catch(err => {
|
||||
this.$Message.error((err && err.msg) || '加载失败,请重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击「查询」按钮:重置到第1页并刷新列表
|
||||
* @returns {void}
|
||||
*/
|
||||
handleSearch() {
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击「重置」按钮:清空所有搜索条件并刷新
|
||||
* @returns {void}
|
||||
*/
|
||||
handleReset() {
|
||||
this.timeVal = [];
|
||||
this.formValidate.order_id = '';
|
||||
this.formValidate.keyword = '';
|
||||
this.formValidate.date_range = '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* DatePicker 变更回调
|
||||
* @param {string[]} e - [startTimeStr, endTimeStr]
|
||||
* @returns {void}
|
||||
*/
|
||||
onChangeTime(e) {
|
||||
this.timeVal = e;
|
||||
this.formValidate.date_range = e[0] ? e.join('-') : '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 分页器页码变更回调
|
||||
* @param {number} index - 跳转的目标页码
|
||||
* @returns {void}
|
||||
*/
|
||||
pageChange(index) {
|
||||
this.formValidate.page = index;
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.stat-bar
|
||||
display flex
|
||||
align-items center
|
||||
gap 48px
|
||||
padding 8px 4px
|
||||
|
||||
.stat-item
|
||||
display flex
|
||||
flex-direction column
|
||||
gap 4px
|
||||
|
||||
.stat-label
|
||||
font-size 13px
|
||||
color #999
|
||||
|
||||
.stat-value
|
||||
font-size 24px
|
||||
font-weight 600
|
||||
color #ed4014
|
||||
|
||||
.stat-count
|
||||
font-size 20px
|
||||
font-weight 500
|
||||
color #2d2d2d
|
||||
|
||||
.order-id
|
||||
font-size 12px
|
||||
color #515a6e
|
||||
|
||||
.user-info
|
||||
line-height 1.4
|
||||
|
||||
.user-name
|
||||
font-weight 500
|
||||
color #2d2d2d
|
||||
|
||||
.user-meta
|
||||
font-size 12px
|
||||
color #999
|
||||
|
||||
.user-phone
|
||||
margin-right 8px
|
||||
|
||||
.amount-text
|
||||
font-weight 500
|
||||
color #ed4014
|
||||
|
||||
.text-muted
|
||||
color #bbb
|
||||
|
||||
.tabform .ivu-form-item
|
||||
margin-bottom 10px
|
||||
|
||||
.page
|
||||
margin-top 16px
|
||||
</style>
|
||||
358
pro_v3.5.1/view/admin/src/pages/hjf/queueOrder/index.vue
Normal file
358
pro_v3.5.1/view/admin/src/pages/hjf/queueOrder/index.vue
Normal file
@@ -0,0 +1,358 @@
|
||||
<template>
|
||||
<!-- 公排订单管理 -->
|
||||
<div>
|
||||
<!-- 搜索区 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt" :padding="0">
|
||||
<div class="new_card_pd">
|
||||
<Form
|
||||
ref="formValidate"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
inline
|
||||
class="tabform"
|
||||
@submit.native.prevent
|
||||
>
|
||||
<FormItem label="昵称/ID:">
|
||||
<Input
|
||||
v-model="formValidate.keyword"
|
||||
placeholder="请输入用户昵称或ID"
|
||||
class="input-add"
|
||||
clearable
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="状态:">
|
||||
<Select
|
||||
v-model="formValidate.status"
|
||||
placeholder="全部状态"
|
||||
class="input-add"
|
||||
clearable
|
||||
>
|
||||
<Option :value="0">排队中</Option>
|
||||
<Option :value="1">已退款</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="加入时间:">
|
||||
<DatePicker
|
||||
:editable="false"
|
||||
:value="timeVal"
|
||||
format="yyyy/MM/dd HH:mm"
|
||||
type="datetimerange"
|
||||
placement="bottom-start"
|
||||
placeholder="自定义时间范围"
|
||||
class="input-add"
|
||||
:options="dateOptions"
|
||||
@on-change="onChangeTime"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" class="mr14" @click="handleSearch">查询</Button>
|
||||
<Button @click="handleReset">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<Table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="tabList"
|
||||
:loading="loading"
|
||||
no-data-text="暂无数据"
|
||||
no-filtered-data-text="暂无筛选结果"
|
||||
>
|
||||
<!-- 用户信息列 -->
|
||||
<template slot-scope="{ row }" slot="user">
|
||||
<div class="user-info">
|
||||
<div class="user-name">{{ row.nickname }}</div>
|
||||
<div class="user-meta">
|
||||
<span class="user-phone">{{ row.phone }}</span>
|
||||
<span class="user-id">UID: {{ row.uid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 金额列 -->
|
||||
<template slot-scope="{ row }" slot="amount">
|
||||
<span class="amount-text">¥{{ Number(row.amount).toFixed(2) }}</span>
|
||||
</template>
|
||||
|
||||
<!-- 状态列 -->
|
||||
<template slot-scope="{ row }" slot="status">
|
||||
<Tag :color="row.status === 0 ? 'green' : 'default'">
|
||||
{{ row.status_text }}
|
||||
</Tag>
|
||||
</template>
|
||||
|
||||
<!-- 退款时间列 -->
|
||||
<template slot-scope="{ row }" slot="refund_time">
|
||||
<span v-if="row.refund_time">{{ row.refund_time }}</span>
|
||||
<span v-else class="text-muted">—</span>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="acea-row row-right page">
|
||||
<Page
|
||||
:total="total"
|
||||
:current="formValidate.page"
|
||||
:page-size="formValidate.limit"
|
||||
show-elevator
|
||||
show-total
|
||||
@on-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* @module pages/hjf/queueOrder/index
|
||||
* @description 公排订单管理页面
|
||||
*
|
||||
* 功能:
|
||||
* - 展示公排订单列表(分页 + 筛选)
|
||||
* - 支持按用户昵称/ID、状态、加入时间范围搜索
|
||||
* - 列表字段:订单ID、用户信息、金额、排队序号、状态、退款时间、加入时间
|
||||
*
|
||||
* 数据来源:`@/api/hjfQueue.js` → `queueOrderList()`
|
||||
* Phase 1 使用 Mock 数据;Phase 4 集成时将 `USE_MOCK` 改为 false
|
||||
*
|
||||
* 路由:`/admin/hjf/queue/order`
|
||||
* 权限标识:`hjf-queue-order`
|
||||
*
|
||||
* @see docs/frontend-new-pages-spec.md §5.2.4
|
||||
* @see pro_v3.5.1/view/admin/src/pages/finance/commission/index.vue 参考模式
|
||||
*/
|
||||
import { mapState } from 'vuex';
|
||||
import { queueOrderListApi } from '@/api/hjfQueue.js';
|
||||
|
||||
/** 快捷日期选项(今天 / 近7天 / 近1个月) */
|
||||
const DATE_SHORTCUTS = [
|
||||
{
|
||||
text: '今天',
|
||||
value() {
|
||||
const d = new Date();
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return [d, new Date()];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '近7天',
|
||||
value() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(start.getDate() - 6);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '近1个月',
|
||||
value() {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 1);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
return [start, end];
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
name: 'HjfQueueOrder',
|
||||
|
||||
data() {
|
||||
return {
|
||||
/** @type {string[]} 日期选择器当前值 [startTime, endTime] */
|
||||
timeVal: [],
|
||||
|
||||
/** @type {number} 列表总条数,用于分页组件 */
|
||||
total: 0,
|
||||
|
||||
/** @type {boolean} 表格加载状态 */
|
||||
loading: false,
|
||||
|
||||
/** @type {Array<Object>} 表格数据行 */
|
||||
tabList: [],
|
||||
|
||||
/**
|
||||
* 搜索表单及分页参数
|
||||
* @property {string} keyword - 用户昵称或 UID 关键词
|
||||
* @property {number|string} status - 排队状态:0 排队中 / 1 已退款 / '' 全部
|
||||
* @property {string} date_range - 加入时间范围,格式 "startTime-endTime"
|
||||
* @property {number} page - 当前页码
|
||||
* @property {number} limit - 每页条数
|
||||
*/
|
||||
formValidate: {
|
||||
keyword: '',
|
||||
status: '',
|
||||
date_range: '',
|
||||
page: 1,
|
||||
limit: 20
|
||||
},
|
||||
|
||||
/** @type {Object} DatePicker 快捷选项配置 */
|
||||
dateOptions: { shortcuts: DATE_SHORTCUTS },
|
||||
|
||||
/**
|
||||
* 表格列定义
|
||||
* @type {Array<Object>}
|
||||
*/
|
||||
columns: [
|
||||
{
|
||||
title: '用户信息',
|
||||
slot: 'user',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
title: '订单号',
|
||||
key: 'order_id',
|
||||
minWidth: 190
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
slot: 'amount',
|
||||
minWidth: 110
|
||||
},
|
||||
{
|
||||
title: '排队序号',
|
||||
key: 'queue_no',
|
||||
minWidth: 110
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
slot: 'status',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '退款时间',
|
||||
slot: 'refund_time',
|
||||
minWidth: 170
|
||||
},
|
||||
{
|
||||
title: '加入时间',
|
||||
key: 'add_time',
|
||||
minWidth: 170
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState('admin/layout', ['isMobile']),
|
||||
|
||||
/** @returns {number|undefined} 表单标签宽度,移动端不设固定宽 */
|
||||
labelWidth() {
|
||||
return this.isMobile ? undefined : 90;
|
||||
},
|
||||
|
||||
/** @returns {string} 表单标签对齐方式 */
|
||||
labelPosition() {
|
||||
return this.isMobile ? 'top' : 'right';
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getList();
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 获取公排订单列表
|
||||
* 调用 `queueOrderList` API,将结果填充到 `tabList`,更新 `total`
|
||||
* @returns {void}
|
||||
*/
|
||||
getList() {
|
||||
this.loading = true;
|
||||
queueOrderListApi(this.formValidate)
|
||||
.then(res => {
|
||||
const data = res.data;
|
||||
this.tabList = data.list || [];
|
||||
this.total = data.count || 0;
|
||||
})
|
||||
.catch(err => {
|
||||
this.$Message.error((err && err.msg) || '加载失败,请重试');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击「查询」按钮:重置到第1页并刷新列表
|
||||
* @returns {void}
|
||||
*/
|
||||
handleSearch() {
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击「重置」按钮:清空所有搜索条件并刷新
|
||||
* @returns {void}
|
||||
*/
|
||||
handleReset() {
|
||||
this.timeVal = [];
|
||||
this.formValidate.keyword = '';
|
||||
this.formValidate.status = '';
|
||||
this.formValidate.date_range = '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* DatePicker 变更回调:更新 date_range 参数并触发查询
|
||||
* @param {string[]} e - [startTimeStr, endTimeStr]
|
||||
* @returns {void}
|
||||
*/
|
||||
onChangeTime(e) {
|
||||
this.timeVal = e;
|
||||
this.formValidate.date_range = e[0] ? e.join('-') : '';
|
||||
this.formValidate.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
/**
|
||||
* 分页器页码变更回调
|
||||
* @param {number} index - 跳转的目标页码
|
||||
* @returns {void}
|
||||
*/
|
||||
pageChange(index) {
|
||||
this.formValidate.page = index;
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.user-info
|
||||
line-height 1.4
|
||||
|
||||
.user-name
|
||||
font-weight 500
|
||||
color #2d2d2d
|
||||
|
||||
.user-meta
|
||||
font-size 12px
|
||||
color #999
|
||||
|
||||
.user-phone
|
||||
margin-right 8px
|
||||
|
||||
.amount-text
|
||||
font-weight 500
|
||||
color #ed4014
|
||||
|
||||
.text-muted
|
||||
color #bbb
|
||||
|
||||
.tabform .ivu-form-item
|
||||
margin-bottom 10px
|
||||
|
||||
.page
|
||||
margin-top 16px
|
||||
</style>
|
||||
@@ -207,6 +207,40 @@
|
||||
<span slot="close">关闭</span>
|
||||
</i-switch>
|
||||
</FormItem>
|
||||
<!-- 报单商品开关 (P1G-02: is_queue_goods)
|
||||
开启后该商品订单将自动进入公排池,积分支付自动禁用 -->
|
||||
<FormItem label="报单商品:">
|
||||
<i-switch
|
||||
v-model="formValidate.is_queue_goods"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
size="large"
|
||||
@on-change="onQueueGoodsChange"
|
||||
>
|
||||
<span slot="open">是</span>
|
||||
<span slot="close">否</span>
|
||||
</i-switch>
|
||||
<span class="tips ml-10">开启后订单付款即进入公排池,每进4单退1单</span>
|
||||
</FormItem>
|
||||
<!-- 支付方式多选框组 (P1G-02: allow_pay_types)
|
||||
报单商品强制禁用积分支付 -->
|
||||
<FormItem label="支付方式:">
|
||||
<CheckboxGroup v-model="formValidate.allow_pay_types">
|
||||
<Checkbox label="wechat">微信支付</Checkbox>
|
||||
<Checkbox label="alipay">支付宝</Checkbox>
|
||||
<Checkbox label="yue">余额支付</Checkbox>
|
||||
<Checkbox label="integral" :disabled="formValidate.is_queue_goods == 1">
|
||||
积分支付
|
||||
<Tooltip
|
||||
v-if="formValidate.is_queue_goods == 1"
|
||||
content="报单商品不支持积分支付"
|
||||
placement="top"
|
||||
>
|
||||
<Icon type="ios-information-circle-outline" />
|
||||
</Tooltip>
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</FormItem>
|
||||
<FormItem label="自定义留言:">
|
||||
<i-switch v-model="customBtn" @on-change="customMessBtn" size="large">
|
||||
<span slot="open">开启</span>
|
||||
@@ -279,6 +313,10 @@ export default {
|
||||
system_form_id: "",
|
||||
specs: [],
|
||||
share_content: "",
|
||||
/** 报单商品标记:1=是报单商品,0=普通商品 */
|
||||
is_queue_goods: 0,
|
||||
/** 允许的支付方式列表,报单商品不含 integral */
|
||||
allow_pay_types: ["wechat", "alipay", "yue"],
|
||||
},
|
||||
formTypeList: [],
|
||||
formColumns: [
|
||||
@@ -339,6 +377,19 @@ export default {
|
||||
handleFill(val, type) {
|
||||
this.formValidate[type] = val;
|
||||
},
|
||||
/**
|
||||
* 报单商品开关变更回调。
|
||||
* 开启时强制从 allow_pay_types 中移除 "integral"(积分支付);
|
||||
* 关闭时不自动恢复,由运营人员按需勾选。
|
||||
* @param {number} val - 新值:1=报单商品,0=普通商品
|
||||
*/
|
||||
onQueueGoodsChange(val) {
|
||||
if (val === 1) {
|
||||
this.formValidate.allow_pay_types = this.formValidate.allow_pay_types.filter(
|
||||
(t) => t !== "integral"
|
||||
);
|
||||
}
|
||||
},
|
||||
changeForm(e) {
|
||||
this.getSystemFormInfo(e, { type: 1 });
|
||||
},
|
||||
|
||||
@@ -51,6 +51,18 @@
|
||||
<Option :value="4">次卡商品</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<!-- 报单商品筛选 (P1G-02: is_queue_goods) -->
|
||||
<FormItem label="报单商品:">
|
||||
<Select
|
||||
v-model="searchForm.is_queue_goods"
|
||||
@on-change="userSearchs"
|
||||
clearable
|
||||
class="input-add"
|
||||
>
|
||||
<Option :value="1">是</Option>
|
||||
<Option :value="0">否</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="商品分类:">
|
||||
<el-cascader
|
||||
placeholder="请选择商品分类"
|
||||
@@ -306,6 +318,8 @@ let defaultObj = {
|
||||
activity_type: "",
|
||||
create_range: "",
|
||||
product_clear: "",
|
||||
/** 报单商品筛选:1=是,0=否,空字符串=全部 */
|
||||
is_queue_goods: "",
|
||||
};
|
||||
import timeOptions from "@/utils/timeOptions";
|
||||
import { productStoreLabel } from "@/api/product";
|
||||
|
||||
@@ -260,6 +260,13 @@
|
||||
<span v-if="row.product_type == 4">次卡商品</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 报单商品标记列 (P1G-02: is_queue_goods) -->
|
||||
<vxe-column field="is_queue_goods" title="报单商品" min-width="90" align="center">
|
||||
<template v-slot="{ row }">
|
||||
<Tag v-if="row.is_queue_goods == 1" color="green">是</Tag>
|
||||
<Tag v-else color="default">否</Tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="price" title="商品售价" min-width="90"></vxe-column>
|
||||
<vxe-column field="sales" title="销量" min-width="90"></vxe-column>
|
||||
<vxe-column
|
||||
|
||||
@@ -54,6 +54,21 @@
|
||||
<div class="iconfont iconxiayi"></div>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="会员等级:" label-for="hjf_member_level">
|
||||
<Select
|
||||
v-model="userFrom.hjf_member_level"
|
||||
placeholder="请选择"
|
||||
element-id="hjf_member_level"
|
||||
clearable
|
||||
class="input-add"
|
||||
>
|
||||
<Option :value="0">普通会员</Option>
|
||||
<Option :value="1">创客</Option>
|
||||
<Option :value="2">云店</Option>
|
||||
<Option :value="3">服务商</Option>
|
||||
<Option :value="4">分公司</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="访问时间:" label-for="user_time">
|
||||
<DatePicker
|
||||
:editable="false"
|
||||
@@ -387,7 +402,44 @@
|
||||
<div>{{ row.isMember ? "是" : "否" }}</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="level" title="用户等级" min-width="90"></vxe-column>
|
||||
<vxe-column field="level" title="会员等级" min-width="130">
|
||||
<template v-slot="{ row }">
|
||||
<div class="level-cell">
|
||||
<template v-if="levelMap[row.level]">
|
||||
<img
|
||||
v-if="levelMap[row.level].icon"
|
||||
class="level-icon"
|
||||
:src="levelMap[row.level].icon"
|
||||
:alt="levelMap[row.level].name"
|
||||
/>
|
||||
<span class="level-badge" :style="{ background: levelMap[row.level].color || '#dab176' }">
|
||||
{{ levelMap[row.level].name }}
|
||||
</span>
|
||||
</template>
|
||||
<span v-else class="level-none">普通会员</span>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="member_level" title="HJF等级" min-width="110">
|
||||
<template v-slot="{ row }">
|
||||
<HjfMemberBadge
|
||||
v-if="row.member_level != null"
|
||||
:level="Number(row.member_level)"
|
||||
size="small"
|
||||
/>
|
||||
<span v-else class="level-none">普通会员</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="direct_count" title="直推人数" min-width="90">
|
||||
<template v-slot="{ row }">
|
||||
<span>{{ row.direct_count != null ? row.direct_count : '-' }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="umbrella_orders" title="伞下订单数" min-width="100">
|
||||
<template v-slot="{ row }">
|
||||
<span>{{ row.umbrella_orders != null ? row.umbrella_orders : '-' }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="group_id" title="分组" min-width="100"></vxe-column>
|
||||
<vxe-column field="phone" title="手机号" min-width="110"></vxe-column>
|
||||
<vxe-column
|
||||
@@ -412,7 +464,8 @@
|
||||
<a @click="changeMenu(row, '1')">详情</a>
|
||||
<Divider type="vertical" />
|
||||
<a @click="changeMenu(row, '10')">编辑</a>
|
||||
<!-- <a @click="extendInfo(row)" v-if="row.is_extend_info">信息补充</a> -->
|
||||
<Divider type="vertical" />
|
||||
<a @click="openLevelModal(row)">调整等级</a>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
@@ -664,10 +717,42 @@
|
||||
>
|
||||
<userImport v-if="importShow" @close="importShow = false"></userImport>
|
||||
</Modal>
|
||||
<!-- 调整会员等级弹窗 -->
|
||||
<Modal
|
||||
v-model="levelModal.show"
|
||||
title="调整会员等级"
|
||||
width="420"
|
||||
:mask-closable="false"
|
||||
@on-visible-change="onLevelModalChange"
|
||||
>
|
||||
<Form :label-width="90" @submit.native.prevent>
|
||||
<FormItem label="当前用户:">
|
||||
<span>{{ levelModal.nickname }}(UID: {{ levelModal.uid }})</span>
|
||||
</FormItem>
|
||||
<FormItem label="会员等级:">
|
||||
<Select v-model="levelModal.level" placeholder="请选择目标等级">
|
||||
<Option :value="0">普通会员</Option>
|
||||
<Option :value="1">创客</Option>
|
||||
<Option :value="2">云店</Option>
|
||||
<Option :value="3">服务商</Option>
|
||||
<Option :value="4">分公司</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="levelModal.show = false">取消</Button>
|
||||
<Button type="primary" :loading="levelModal.loading" @click="handleLevelChange">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 用户列表页面
|
||||
* @description Admin 用户管理主列表,支持多维度筛选、会员等级彩色展示、直推/伞下统计及等级快速调整。
|
||||
* @module pages/user/list
|
||||
*/
|
||||
import { formatDate } from "@/utils/validate";
|
||||
import userLabel from "../../../components/userLabel";
|
||||
import labelList from "@/components/labelList";
|
||||
@@ -692,6 +777,7 @@ import {
|
||||
exportUserData,
|
||||
} from "@/api/user";
|
||||
import { agentSpreadApi } from "@/api/agent";
|
||||
import { memberList, memberSetLevel } from "@/api/hjfMember";
|
||||
import editFrom from "../../../components/from/from";
|
||||
import sendFrom from "@/components/sendCoupons/index";
|
||||
import userDetails from "./handle/userDetails";
|
||||
@@ -699,6 +785,7 @@ import newsCategory from "@/components/newsCategory/index";
|
||||
import city from "@/utils/city";
|
||||
import customerInfo from "@/components/customerInfo";
|
||||
import userImport from "./handle/userImport.vue";
|
||||
import HjfMemberBadge from "@/components/HjfMemberBadge.vue";
|
||||
import exportExcel from "@/utils/newToExcel.js";
|
||||
import timeOptions from "@/utils/timeOptions";
|
||||
export default {
|
||||
@@ -721,6 +808,7 @@ export default {
|
||||
userLabel,
|
||||
labelList,
|
||||
userImport,
|
||||
HjfMemberBadge,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -779,6 +867,8 @@ export default {
|
||||
group_id: "",
|
||||
field_key: "",
|
||||
is_channel: "",
|
||||
/** 会员等级筛选(HJF 扩展字段):0 普通 1 创客 2 云店 3 服务商 4 分公司,空串表示全部 */
|
||||
hjf_member_level: "",
|
||||
},
|
||||
field_key: "",
|
||||
level: "",
|
||||
@@ -825,6 +915,14 @@ export default {
|
||||
},
|
||||
spread_name: "",
|
||||
importShow: false,
|
||||
/** @type {{ show: boolean, uid: number, nickname: string, level: number, loading: boolean }} */
|
||||
levelModal: {
|
||||
show: false,
|
||||
uid: 0,
|
||||
nickname: "",
|
||||
level: 0,
|
||||
loading: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -860,6 +958,13 @@ export default {
|
||||
labelPosition() {
|
||||
return this.isMobile ? "top" : "right";
|
||||
},
|
||||
levelMap() {
|
||||
const map = {};
|
||||
this.levelList.forEach((item) => {
|
||||
map[item.id] = item;
|
||||
});
|
||||
return map;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
@@ -1405,8 +1510,9 @@ export default {
|
||||
level: "",
|
||||
group_id: "",
|
||||
label_id: "",
|
||||
page: 1, // 当前页
|
||||
limit: 20, // 每页显示条数
|
||||
hjf_member_level: "",
|
||||
page: 1,
|
||||
limit: 20,
|
||||
};
|
||||
this.field_key = "";
|
||||
this.level = "";
|
||||
@@ -1566,6 +1672,67 @@ export default {
|
||||
viewImportRecord() {
|
||||
this.$router.push({ path: "/admin/user/importRecord" });
|
||||
},
|
||||
|
||||
/**
|
||||
* 打开调整等级弹窗
|
||||
* @param {Object} row - 当前行用户数据
|
||||
* @param {number} row.uid - 用户 ID
|
||||
* @param {string} row.nickname - 用户昵称
|
||||
* @param {number} row.member_level - 当前会员等级(HJF 字段);回退到 row.level
|
||||
*/
|
||||
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.show = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* 弹窗关闭时重置 loading 状态
|
||||
* @param {boolean} visible - 弹窗是否可见
|
||||
*/
|
||||
onLevelModalChange(visible) {
|
||||
if (!visible) {
|
||||
this.levelModal.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交等级调整请求
|
||||
* 调用 memberSetLevel API 更新会员等级,成功后刷新列表。
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async handleLevelChange() {
|
||||
this.levelModal.loading = true;
|
||||
try {
|
||||
const res = await memberSetLevel(this.levelModal.uid, this.levelModal.level);
|
||||
this.$Message.success(res.data && res.data.msg ? res.data.msg : "等级调整成功");
|
||||
this.levelModal.show = false;
|
||||
this.getList();
|
||||
} catch (err) {
|
||||
this.$Message.error((err && err.msg) ? err.msg : "操作失败,请重试");
|
||||
} finally {
|
||||
this.levelModal.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置不考核状态(预留接口,Phase 4 集成时完善)
|
||||
* @param {Object} row - 用户行数据
|
||||
* @param {number} row.uid - 用户 ID
|
||||
* @param {number} row.no_assess - 当前不考核状态(0 正常,1 不考核)
|
||||
*/
|
||||
handleNoAssess(row) {
|
||||
const nextStatus = row.no_assess ? 0 : 1;
|
||||
const label = nextStatus === 1 ? "不考核" : "正常考核";
|
||||
this.$Modal.confirm({
|
||||
title: "确认操作",
|
||||
content: `将【${row.nickname}】设置为 <b>${label}</b>?`,
|
||||
onOk: () => {
|
||||
this.$Message.info("功能将在 Phase 4 集成后启用");
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1700,6 +1867,35 @@ img {
|
||||
color: #dab176;
|
||||
}
|
||||
|
||||
.level-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.level-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 2px;
|
||||
object-fit: contain;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
display: inline-block;
|
||||
padding: 1px 7px;
|
||||
border-radius: 10px;
|
||||
font-size: 11px;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.level-none {
|
||||
color: #aaa;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.listbox {
|
||||
>>>.ivu-divider-horizontal {
|
||||
margin: 0 !important;
|
||||
|
||||
78
pro_v3.5.1/view/admin/src/router/modules/hjfQueue.js
Normal file
78
pro_v3.5.1/view/admin/src/router/modules/hjfQueue.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
import BasicLayout from '@/layouts/basic-layout';
|
||||
|
||||
const pre = 'hjf_';
|
||||
|
||||
export default {
|
||||
path: '/admin/hjf',
|
||||
name: 'hjf',
|
||||
header: 'hjf',
|
||||
meta: {
|
||||
auth: ['admin-hjf']
|
||||
},
|
||||
component: BasicLayout,
|
||||
children: [
|
||||
{
|
||||
path: 'queue/order',
|
||||
name: `${pre}queueOrder`,
|
||||
meta: {
|
||||
auth: ['hjf-queue-order'],
|
||||
title: '公排订单管理'
|
||||
},
|
||||
component: () => import('@/pages/hjf/queueOrder/index')
|
||||
},
|
||||
{
|
||||
path: 'queue/finance',
|
||||
name: `${pre}queueFinance`,
|
||||
meta: {
|
||||
auth: ['hjf-queue-finance'],
|
||||
title: '公排财务流水'
|
||||
},
|
||||
component: () => import('@/pages/hjf/queueFinance/index')
|
||||
},
|
||||
{
|
||||
path: 'queue/config',
|
||||
name: `${pre}queueConfig`,
|
||||
meta: {
|
||||
auth: ['hjf-queue-config'],
|
||||
title: '公排配置'
|
||||
},
|
||||
component: () => import('@/pages/hjf/queueConfig/index')
|
||||
},
|
||||
{
|
||||
path: 'member/level',
|
||||
name: `${pre}memberLevel`,
|
||||
meta: {
|
||||
auth: ['hjf-member-level'],
|
||||
title: '会员等级管理'
|
||||
},
|
||||
component: () => import('@/pages/hjf/memberLevel/index')
|
||||
},
|
||||
{
|
||||
path: 'member/config',
|
||||
name: `${pre}memberConfig`,
|
||||
meta: {
|
||||
auth: ['hjf-member-config'],
|
||||
title: '会员配置'
|
||||
},
|
||||
component: () => import('@/pages/hjf/memberConfig/index')
|
||||
},
|
||||
{
|
||||
path: 'points/log',
|
||||
name: `${pre}pointsLog`,
|
||||
meta: {
|
||||
auth: ['hjf-points-log'],
|
||||
title: '积分日志'
|
||||
},
|
||||
component: () => import('@/pages/hjf/pointsLog/index')
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -25,6 +25,7 @@ import frameOut from "./modules/frameOut";
|
||||
import work from "./modules/work";
|
||||
import content from "./modules/content";
|
||||
import inventory from "./modules/inventory";
|
||||
import hjfQueue from "./modules/hjfQueue.js";
|
||||
import { isSupplierPath } from "@/utils/pathUtils";
|
||||
|
||||
/**
|
||||
@@ -208,7 +209,8 @@ const frameIn = [
|
||||
statistic,
|
||||
work,
|
||||
content,
|
||||
inventory
|
||||
inventory,
|
||||
hjfQueue
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
335
pro_v3.5.1/view/admin/src/utils/hjfMockData.js
Normal file
335
pro_v3.5.1/view/admin/src/utils/hjfMockData.js
Normal file
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* 黄精粉健康商城 - Admin Mock 数据集中管理
|
||||
* Phase 1 前端开发使用,Phase 4 集成后可移除
|
||||
*/
|
||||
|
||||
// ========== 公排管理 ==========
|
||||
|
||||
export const MOCK_QUEUE_ORDER_LIST = {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
order_id: 'HJF202603100001',
|
||||
amount: 3600.00,
|
||||
queue_no: 142,
|
||||
status: 0,
|
||||
status_text: '排队中',
|
||||
refund_time: '',
|
||||
trigger_batch: 0,
|
||||
add_time: '2026-03-10 10:00:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
uid: 10087,
|
||||
nickname: '张三',
|
||||
phone: '139****9999',
|
||||
order_id: 'HJF202603080002',
|
||||
amount: 3600.00,
|
||||
queue_no: 98,
|
||||
status: 1,
|
||||
status_text: '已退款',
|
||||
refund_time: '2026-03-09 12:00:00',
|
||||
trigger_batch: 24,
|
||||
add_time: '2026-03-08 09:30:00'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
uid: 10088,
|
||||
nickname: '李四',
|
||||
phone: '137****7777',
|
||||
order_id: 'HJF202603090003',
|
||||
amount: 3600.00,
|
||||
queue_no: 120,
|
||||
status: 0,
|
||||
status_text: '排队中',
|
||||
refund_time: '',
|
||||
trigger_batch: 0,
|
||||
add_time: '2026-03-09 14:20:00'
|
||||
}
|
||||
],
|
||||
count: 156,
|
||||
page: 1,
|
||||
limit: 20
|
||||
};
|
||||
|
||||
export const MOCK_QUEUE_CONFIG = {
|
||||
trigger_multiple: 4,
|
||||
refund_cycle: 30,
|
||||
enabled: true,
|
||||
release_rate: 4,
|
||||
withdraw_fee_rate: 7
|
||||
};
|
||||
|
||||
export const MOCK_QUEUE_FINANCE = {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uid: 10085,
|
||||
nickname: '赵六',
|
||||
phone: '136****6666',
|
||||
order_id: 'HJF202603090039',
|
||||
trigger_batch: 24,
|
||||
amount: 3600.00,
|
||||
queue_no: 39,
|
||||
refund_time: '2026-03-09 12:00:00',
|
||||
operator: '系统自动'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
uid: 10082,
|
||||
nickname: '孙七',
|
||||
phone: '135****5555',
|
||||
order_id: 'HJF202603080035',
|
||||
trigger_batch: 23,
|
||||
amount: 3600.00,
|
||||
queue_no: 35,
|
||||
refund_time: '2026-03-08 16:30:00',
|
||||
operator: '管理员'
|
||||
}
|
||||
],
|
||||
count: 39,
|
||||
total_refund: '140400.00',
|
||||
page: 1,
|
||||
limit: 20
|
||||
};
|
||||
|
||||
// ========== 积分管理 ==========
|
||||
|
||||
export const MOCK_POINTS_RELEASE_LOG = {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
points: 6,
|
||||
type: 'release',
|
||||
type_text: '释放',
|
||||
status: 1,
|
||||
status_text: '成功',
|
||||
add_time: '2026-03-10 00:01:23'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
uid: 10087,
|
||||
nickname: '张三',
|
||||
phone: '139****9999',
|
||||
points: 3,
|
||||
type: 'release',
|
||||
type_text: '释放',
|
||||
status: 1,
|
||||
status_text: '成功',
|
||||
add_time: '2026-03-10 00:01:24'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
uid: 10088,
|
||||
nickname: '李四',
|
||||
phone: '137****7777',
|
||||
points: 500,
|
||||
type: 'reward',
|
||||
type_text: '奖励',
|
||||
status: 1,
|
||||
status_text: '成功',
|
||||
add_time: '2026-03-09 15:30:00'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
points: 200,
|
||||
type: 'consume',
|
||||
type_text: '消费',
|
||||
status: 1,
|
||||
status_text: '成功',
|
||||
add_time: '2026-03-09 11:20:00'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
uid: 10087,
|
||||
nickname: '张三',
|
||||
phone: '139****9999',
|
||||
points: 50,
|
||||
type: 'consume',
|
||||
type_text: '消费',
|
||||
status: 0,
|
||||
status_text: '处理中',
|
||||
add_time: '2026-03-08 18:00:00'
|
||||
}
|
||||
],
|
||||
count: 500,
|
||||
page: 1,
|
||||
limit: 20,
|
||||
statistics: {
|
||||
total_released_today: 2450,
|
||||
total_users_released: 320
|
||||
}
|
||||
};
|
||||
|
||||
// ========== 会员管理 ==========
|
||||
|
||||
export const MOCK_MEMBER_LIST = {
|
||||
list: [
|
||||
{
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
avatar: '',
|
||||
member_level: 2,
|
||||
member_level_name: '云店',
|
||||
no_assess: 0,
|
||||
direct_count: 8,
|
||||
umbrella_orders: 42,
|
||||
frozen_points: 15000,
|
||||
available_points: 3200,
|
||||
now_money: '7200.00',
|
||||
spread_uid: 10001,
|
||||
spread_nickname: '系统',
|
||||
team_performance: '18600.00',
|
||||
upgrade_status: 1,
|
||||
next_level: 3,
|
||||
next_level_name: '服务商',
|
||||
next_require: 100,
|
||||
add_time: '2026-01-15 10:00:00'
|
||||
},
|
||||
{
|
||||
uid: 10087,
|
||||
nickname: '张三',
|
||||
phone: '139****9999',
|
||||
avatar: '',
|
||||
member_level: 1,
|
||||
member_level_name: '创客',
|
||||
no_assess: 0,
|
||||
direct_count: 5,
|
||||
umbrella_orders: 18,
|
||||
frozen_points: 8500,
|
||||
available_points: 1200,
|
||||
now_money: '3600.00',
|
||||
spread_uid: 10086,
|
||||
spread_nickname: '王五',
|
||||
team_performance: '6480.00',
|
||||
upgrade_status: 0,
|
||||
next_level: 2,
|
||||
next_level_name: '云店',
|
||||
next_require: 50,
|
||||
add_time: '2026-02-10 14:30:00'
|
||||
},
|
||||
{
|
||||
uid: 10088,
|
||||
nickname: '李四',
|
||||
phone: '137****7777',
|
||||
avatar: '',
|
||||
member_level: 0,
|
||||
member_level_name: '普通会员',
|
||||
no_assess: 1,
|
||||
direct_count: 1,
|
||||
umbrella_orders: 2,
|
||||
frozen_points: 500,
|
||||
available_points: 0,
|
||||
now_money: '0.00',
|
||||
spread_uid: 10087,
|
||||
spread_nickname: '张三',
|
||||
team_performance: '720.00',
|
||||
upgrade_status: 0,
|
||||
next_level: 1,
|
||||
next_level_name: '创客',
|
||||
next_require: 10,
|
||||
add_time: '2026-03-01 09:20:00'
|
||||
}
|
||||
],
|
||||
count: 256,
|
||||
page: 1,
|
||||
limit: 20
|
||||
};
|
||||
|
||||
export const MOCK_MEMBER_CONFIG = {
|
||||
levels: [
|
||||
{ level: 0, name: '普通会员', require_orders: 0, direct_reward: 800, umbrella_reward_rate: 0, enabled: true },
|
||||
{ level: 1, name: '创客', require_orders: 10, direct_reward: 800, umbrella_reward_rate: 5, enabled: true },
|
||||
{ level: 2, name: '云店', require_orders: 50, direct_reward: 800, umbrella_reward_rate: 8, enabled: true },
|
||||
{ level: 3, name: '服务商', require_orders: 100, direct_reward: 800, umbrella_reward_rate: 12, enabled: true },
|
||||
{ level: 4, name: '分公司', require_orders: 300, direct_reward: 800, umbrella_reward_rate: 15, enabled: true }
|
||||
]
|
||||
};
|
||||
|
||||
// ========== 财务管理 ==========
|
||||
|
||||
export const MOCK_FINANCE_BALANCE_LOG = {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
pm: 1,
|
||||
type: 'queue_refund',
|
||||
type_text: '公排退款',
|
||||
number: '3600.00',
|
||||
balance: '7200.00',
|
||||
mark: '公排触发退款,批次24',
|
||||
add_time: '2026-03-09 12:00:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
pm: 0,
|
||||
type: 'extract',
|
||||
type_text: '提现',
|
||||
number: '1000.00',
|
||||
balance: '3600.00',
|
||||
mark: '提现到微信零钱',
|
||||
add_time: '2026-03-08 15:30:00'
|
||||
}
|
||||
],
|
||||
count: 45,
|
||||
page: 1,
|
||||
limit: 20
|
||||
};
|
||||
|
||||
export const MOCK_FINANCE_WITHDRAW_LIST = {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uid: 10086,
|
||||
nickname: '王五',
|
||||
phone: '138****8888',
|
||||
extract_price: '1000.00',
|
||||
fee_price: '70.00',
|
||||
real_price: '930.00',
|
||||
status: 1,
|
||||
status_text: '已通过',
|
||||
extract_type: 'wx',
|
||||
extract_type_text: '微信零钱',
|
||||
add_time: '2026-03-08 15:30:00',
|
||||
verify_time: '2026-03-08 16:00:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
uid: 10087,
|
||||
nickname: '张三',
|
||||
phone: '139****9999',
|
||||
extract_price: '500.00',
|
||||
fee_price: '35.00',
|
||||
real_price: '465.00',
|
||||
status: 0,
|
||||
status_text: '待审核',
|
||||
extract_type: 'alipay',
|
||||
extract_type_text: '支付宝',
|
||||
add_time: '2026-03-10 09:15:00',
|
||||
verify_time: ''
|
||||
}
|
||||
],
|
||||
count: 28,
|
||||
page: 1,
|
||||
limit: 20,
|
||||
statistics: {
|
||||
total_apply_today: 12,
|
||||
total_amount_today: '8500.00'
|
||||
}
|
||||
};
|
||||
@@ -27,7 +27,12 @@ module.exports = {
|
||||
productionSourceMap: false, //关闭生产环境下的SourceMap映射文件
|
||||
devServer: {
|
||||
publicPath: Setting.publicPath,
|
||||
|
||||
port: 8080,
|
||||
proxy: {
|
||||
'/adminapi': { target: 'http://127.0.0.1:20199', changeOrigin: true },
|
||||
'/api': { target: 'http://127.0.0.1:20199', changeOrigin: true },
|
||||
'/kefuapi': { target: 'http://127.0.0.1:20199', changeOrigin: true },
|
||||
},
|
||||
},
|
||||
|
||||
// 打包优化
|
||||
|
||||
Reference in New Issue
Block a user