路由权限及动态路由
This commit is contained in:
parent
c07b0128c8
commit
1aea365270
|
|
@ -1,8 +1,8 @@
|
|||
# 开发环境标识(Vite 内置变量,无需修改)
|
||||
NODE_ENV = development
|
||||
|
||||
# 开发环境接口基础地址(对应你配置的 http://192.168.11.183:8085/api)
|
||||
VITE_API_BASE_URL = http://192.168.11.183:8085/api
|
||||
# 开发环境接口基础地址(对应你配置的 http://18.167.120.9:8085/api)
|
||||
VITE_API_BASE_URL = http://18.167.120.9:8085/api
|
||||
|
||||
# 请求超时时间(毫秒)
|
||||
VITE_REQUEST_TIMEOUT = 10000
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 菜单区域 -->
|
||||
<el-menu class="menu" :unique-opened="true" :default-active="activeMenu" router>
|
||||
<template v-for="menu in menuList" :key="menu.id">
|
||||
<!-- 无子菜单 -->
|
||||
<el-menu-item v-if="!menu.children || menu.children.length === 0" :index="menu.path">
|
||||
<el-icon>
|
||||
<component :is="iconMap[menu.icon]" />
|
||||
</el-icon>
|
||||
<template #title>{{ menu.label }}</template>
|
||||
</el-menu-item>
|
||||
<!-- 菜单区域 -->
|
||||
<el-menu class="menu" :unique-opened="true" :default-active="activeMenu" router>
|
||||
<template v-for="menu in menuList" :key="menu.id">
|
||||
<!-- 无子菜单 -->
|
||||
<el-menu-item v-if="!menu.children || menu.children.length === 0" :index="menu.path">
|
||||
<el-icon>
|
||||
<component :is="iconMap[menu.icon]" />
|
||||
</el-icon>
|
||||
<template #title>{{ menu.label }}</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-sub-menu v-else :index="menu.path">
|
||||
<template #title>
|
||||
|
|
@ -26,9 +26,9 @@
|
|||
<span>{{ menu.label }}</span>
|
||||
</template>
|
||||
<el-menu-item v-for="subMenu in menu.children" :key="subMenu.id" :index="subMenu.path">
|
||||
<el-icon v-if="subMenu.icon">
|
||||
<component :is="iconMap[subMenu.icon]" />
|
||||
</el-icon>
|
||||
<!-- <el-icon v-if="subMenu.icon">-->
|
||||
<!-- <component :is="iconMap[subMenu.icon]" />-->
|
||||
<!-- </el-icon>-->
|
||||
<template #title>{{ subMenu.label }}</template>
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
|
@ -63,6 +63,7 @@ const activeMenu = computed(() => {
|
|||
// 组件挂载时异步加载菜单
|
||||
onMounted(async () => {
|
||||
menuList.value = userStore.sideMenu || []
|
||||
console.log('menuList.value', menuList.value)
|
||||
})
|
||||
|
||||
//图标映射表
|
||||
|
|
@ -77,326 +78,7 @@ const iconMap: Record<string, any> = {
|
|||
Tools,
|
||||
}
|
||||
|
||||
// 菜单假数据,具体要根据实际菜单数据进行调整
|
||||
import type { ElMenuItem } from '@/utils/menuFormat'
|
||||
|
||||
// 抽离后的菜单数据(完全匹配模板中的结构和配置)
|
||||
const staticMenuList = ref<ElMenuItem[]>([
|
||||
// 首页
|
||||
{
|
||||
id: 1,
|
||||
label: '首页',
|
||||
path: 'dashboard', // 对应 el-menu-item 的 index="dashboard"
|
||||
icon: 'HomeFilled', // 对应 <HomeFilled /> 图标
|
||||
},
|
||||
// 模板配置(子菜单)
|
||||
// {
|
||||
// id: 2,
|
||||
// label: '模板配置',
|
||||
// path: '2', // 对应 el-sub-menu 的 index="2"
|
||||
// icon: 'List', // 对应 <List /> 图标
|
||||
// children: [
|
||||
// {
|
||||
// id: 21,
|
||||
// label: '头寸模板',
|
||||
// path: '2-1', // 对应 el-menu-item 的 index="2-1"
|
||||
// icon: ''
|
||||
// // 二级菜单无图标(模板中未设置)
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// 账户管理(子菜单)
|
||||
{
|
||||
id: 3,
|
||||
label: '账户管理',
|
||||
path: 'account', // 对应 el-sub-menu 的 index="account"
|
||||
icon: 'UserFilled', // 对应 <UserFilled /> 图标
|
||||
children: [
|
||||
{
|
||||
id: 31,
|
||||
label: '客户管理',
|
||||
path: '/account/client', // index="client"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 32,
|
||||
label: '代理管理',
|
||||
path: '/account/agentList', // index="3-2"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 33,
|
||||
label: '做市商管理',
|
||||
path: '/account/marketMaker', // index="3-3"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 34,
|
||||
label: '档案管理',
|
||||
path: '/account/archives', // index="3-4"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 35,
|
||||
label: '账号管理',
|
||||
path: '/account/accountDetail', // index="3-5"
|
||||
icon: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 交易管理(子菜单)
|
||||
{
|
||||
id: 4,
|
||||
label: '交易管理',
|
||||
path: '4', // index="4"
|
||||
icon: 'Platform', // 对应 <Platform /> 图标
|
||||
children: [
|
||||
{
|
||||
id: 41,
|
||||
label: '品种',
|
||||
path: '/trade/variety', // index="4-1"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 42,
|
||||
label: '交易时间',
|
||||
path: '/trade/group', // index="4-2"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 43,
|
||||
label: '持仓统计',
|
||||
path: '/trade/positionStat', // index="4-3"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 44,
|
||||
label: '历史交易',
|
||||
path: '/trade/historyTrade', // index="4-4"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 45,
|
||||
label: '交易软件',
|
||||
path: '/trade/tradeSoftware', // index="4-5"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 46,
|
||||
label: '节假日时间',
|
||||
path: '/trade/time', // index="4-3"
|
||||
icon: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 公告管理
|
||||
{
|
||||
id: 5,
|
||||
label: '公告管理',
|
||||
path: '/notice', // index="5"
|
||||
icon: 'BellFilled', // 对应 <BellFilled /> 图标
|
||||
},
|
||||
// 资金管理(子菜单)
|
||||
{
|
||||
id: 6,
|
||||
label: '资金管理',
|
||||
path: '6', // index="6"
|
||||
icon: 'GoodsFilled', // 对应 <GoodsFilled /> 图标
|
||||
children: [
|
||||
// {
|
||||
// id: 61,
|
||||
// label: '存款审核',
|
||||
// path: '/funding/deposit', // index="6-1"
|
||||
// icon: ''
|
||||
// },
|
||||
// {
|
||||
// id: 62,
|
||||
// label: '取款审核',
|
||||
// path: '/funding/withdrawal', // index="6-2"
|
||||
// icon: ''
|
||||
// },
|
||||
// {
|
||||
// id: 63,
|
||||
// label: '取款明细',
|
||||
// path: '/funding/withdrawalDetail', // index="6-3"
|
||||
// icon: ''
|
||||
// },
|
||||
// {
|
||||
// id: 64,
|
||||
// label: '存款明细',
|
||||
// path: '/funding/depositDetail', // index="6-4"
|
||||
// icon: ''
|
||||
// },
|
||||
{
|
||||
id: 64,
|
||||
label: '转账',
|
||||
path: '/funding/transfer', // index="6-4"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 65,
|
||||
label: '转账明细',
|
||||
path: '/funding/transferDetail', // index="6-5"
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 66,
|
||||
label: '资金明细',
|
||||
path: '/funding/fundDetail', // index="6-6"
|
||||
icon: '',
|
||||
},
|
||||
// {
|
||||
// id: 66,
|
||||
// label: '资金流水',
|
||||
// path: '/funding/flowDetail', // index="6-6"
|
||||
// icon: ''
|
||||
// },
|
||||
// {
|
||||
// id: 67,
|
||||
// label: '收款账户列表',
|
||||
// path: '/funding/receiverAccount', // index="6-7"
|
||||
// icon: ''
|
||||
// },
|
||||
// {
|
||||
// id: 68,
|
||||
// label: '存款渠道',
|
||||
// path: '/funding/depositChannel', // index="6-8"
|
||||
// icon: ''
|
||||
// }
|
||||
],
|
||||
},
|
||||
// 系统管理(子菜单)
|
||||
{
|
||||
id: 7,
|
||||
label: '系统管理',
|
||||
path: 'system', // index="7"
|
||||
icon: 'Tools', // 对应 <Tools /> 图标
|
||||
children: [
|
||||
{
|
||||
id: 71,
|
||||
label: '菜单管理',
|
||||
path: '/system/menu', // index="6-1"(模板中此处 index 写的是 6-1,保留原配置)
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 72,
|
||||
label: '角色管理',
|
||||
path: '/system/role', // index="6-2"(模板中此处 index 写的是 6-2,保留原配置)
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
id: 73,
|
||||
label: '系统设置',
|
||||
path: '/system/setting', // index="6-2"(模板中此处 index 写的是 6-2,保留原配置)
|
||||
icon: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 风控管理
|
||||
{
|
||||
id: 8,
|
||||
label: '风控管理',
|
||||
path: '/risk', // index="8"
|
||||
icon: 'WarningFilled', // 对应 <WarningFilled /> 图标
|
||||
},
|
||||
|
||||
// 资金管理(子菜单)
|
||||
// {
|
||||
// id: 9,
|
||||
// label: '资金管理',
|
||||
// path: 'funding', // index="funding"
|
||||
// icon: 'GoodsFilled', // 对应 <GoodsFilled /> 图标
|
||||
// children: [
|
||||
// //存款/取款/审核记录/ 提现记录/ 充值记录暂时没有
|
||||
// //资金明细
|
||||
|
||||
// ]
|
||||
// },
|
||||
// 交易统计(子菜单)
|
||||
// {
|
||||
// id: 10,
|
||||
// label: '交易统计归交易管理',
|
||||
// path: 'trade', // index="trade"
|
||||
// icon: 'ChartBarFilled', // 对应 <ChartBarFilled /> 图标
|
||||
// children: [
|
||||
// // 持仓统计是辉哥
|
||||
// //历史交易
|
||||
// //交易软件
|
||||
// ]
|
||||
// },
|
||||
// 账户管理(子菜单)
|
||||
// {
|
||||
// id: 11,
|
||||
// label: '账户管理',
|
||||
// path: 'account', // index="account"
|
||||
// icon: 'UserFilled', // 对应 <UserFilled /> 图标
|
||||
// children: [
|
||||
// // 档案管理
|
||||
// // 账户管理
|
||||
// ]
|
||||
// },
|
||||
// 个性化交易(子菜单)
|
||||
{
|
||||
id: 12,
|
||||
label: '个性化交易',
|
||||
path: 'personalized', // index="personalized"
|
||||
icon: 'SettingFilled', // 对应 <SettingFilled /> 图标
|
||||
children: [
|
||||
// 排行榜放在了app中
|
||||
// 跟单记录
|
||||
{
|
||||
id: 121,
|
||||
label: '跟单记录',
|
||||
path: '/personalized/followRecord', // index="12-1"
|
||||
icon: '',
|
||||
},
|
||||
// 带单记录
|
||||
{
|
||||
id: 122,
|
||||
label: '带单记录',
|
||||
path: '/personalized/leadRecord', // index="12-2"
|
||||
icon: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 代理管理(子菜单)
|
||||
{
|
||||
id: 13,
|
||||
label: '代理管理',
|
||||
path: 'agent', // index="agent"
|
||||
icon: 'UserFilled', // 对应 <UserFilled /> 图标
|
||||
children: [
|
||||
//客户列表
|
||||
{
|
||||
id: 132,
|
||||
label: '客户列表',
|
||||
path: '/agent/customerList', // index="13-2"
|
||||
icon: '',
|
||||
},
|
||||
//客户交易订单
|
||||
{
|
||||
id: 133,
|
||||
label: '客户交易订单',
|
||||
path: '/agent/customerTradeOrder', // index="13-3"
|
||||
icon: '',
|
||||
},
|
||||
//客户资金流水
|
||||
{
|
||||
id: 135,
|
||||
label: '客户资金流水',
|
||||
path: '/agent/customerCapitalFlow', // index="13-5"
|
||||
icon: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
// 通知管理(子菜单)
|
||||
{
|
||||
id: 14,
|
||||
label: '通知管理',
|
||||
path: 'notification', // index="notification"
|
||||
icon: 'NotificationFilled', // 对应 <NotificationFilled /> 图标
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
const viewModules = import.meta.glob('@/views/**/index.vue')
|
||||
|
||||
export const handleRouter = (list: any[]):any[] => {
|
||||
let routerList:any[] = [];
|
||||
|
||||
list.forEach(item => {
|
||||
if (item.son && item.son.length > 0) {
|
||||
routerList.push(...handleRouter(item.son))
|
||||
} else {
|
||||
const componentPath = `/src/views${item.path}/index.vue`
|
||||
routerList.push({
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
component: viewModules[componentPath] || (() => import('@/views/404/index.vue')),
|
||||
meta: {
|
||||
title: item.name, // 左侧菜单显示的标题
|
||||
},
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
return routerList;
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { useUserStore } from '@/stores/modules/user';
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import Layout from '@/components/layout/Layout.vue'
|
||||
|
||||
const routes = [
|
||||
|
|
@ -51,351 +51,20 @@ const routes = [
|
|||
// 带侧边栏布局的核心业务页面
|
||||
{
|
||||
path: '/',
|
||||
name: 'Layout',
|
||||
component: Layout, // 全局布局(Sidebar + Header + MainContent)
|
||||
redirect: '/dashboard',
|
||||
meta: { requiresAuth: true }, // 需要登录
|
||||
children: [
|
||||
// 首页
|
||||
{
|
||||
path: 'dashboard',
|
||||
path: '/dashboard',
|
||||
name: 'Dashboard',
|
||||
component: () => import('@/views/dashboard/index.vue'),
|
||||
meta: {
|
||||
title: '首页', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
// 系统管理
|
||||
{
|
||||
path: 'system',
|
||||
name: 'System',
|
||||
meta: {
|
||||
title: '系统管理', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'menu',
|
||||
name: 'Menu',
|
||||
component: () => import('@/views/system/menu/index.vue'),
|
||||
meta: {
|
||||
title: '菜单管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'role',
|
||||
name: 'Role',
|
||||
component: () => import('@/views/system/role/index.vue'),
|
||||
meta: {
|
||||
title: '角色管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'setting',
|
||||
name: 'Setting',
|
||||
component: () => import('@/views/system/setting/index.vue'),
|
||||
meta: {
|
||||
title: '系统设置', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
//模板配置
|
||||
{
|
||||
path: 'template',
|
||||
name: 'Template',
|
||||
meta: {
|
||||
title: '模板配置', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
//账户管理
|
||||
{
|
||||
path: 'account',
|
||||
name: 'Account',
|
||||
meta: {
|
||||
title: '账户管理', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'client',
|
||||
name: 'Client',
|
||||
component: () => import('@/views/account/client/index.vue'),
|
||||
meta: {
|
||||
title: '客户管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'agentList',
|
||||
name: 'AgentList',
|
||||
component: () => import('@/views/account/agentList/index.vue'),
|
||||
meta: {
|
||||
title: '代理管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'marketMaker',
|
||||
name: 'MarketMaker',
|
||||
component: () => import('@/views/account/marketMaker/index.vue'),
|
||||
meta: {
|
||||
title: '做市商管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'archives',
|
||||
name: 'Archives',
|
||||
component: () => import('@/views/account/archives/index.vue'),
|
||||
meta: {
|
||||
title: '档案管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'accountDetail',
|
||||
name: 'AccountDetail',
|
||||
component: () => import('@/views/account/accountDetail/index.vue'),
|
||||
meta: {
|
||||
title: '账号管理', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
//交易管理
|
||||
{
|
||||
path: 'trade',
|
||||
name: 'Trade',
|
||||
meta: {
|
||||
title: '交易管理', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'variety',
|
||||
name: 'Variety',
|
||||
component: () => import('@/views/trade/variety/index.vue'),
|
||||
meta: {
|
||||
title: '品种', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'group',
|
||||
name: 'Group',
|
||||
component: () => import('@/views/trade/group/index.vue'),
|
||||
meta: {
|
||||
title: '交易时间', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'time',
|
||||
name: 'Time',
|
||||
component: () => import('@/views/trade/time/index.vue'),
|
||||
meta: {
|
||||
title: '节假日时间', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'positionStat',
|
||||
name: 'PositionStat',
|
||||
component: () => import('@/views/trade/positionStat/index.vue'),
|
||||
meta: {
|
||||
title: '持仓统计', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'historyTrade',
|
||||
name: 'HistoryTrade',
|
||||
component: () => import('@/views/trade/historyTrade/index.vue'),
|
||||
meta: {
|
||||
title: '历史交易', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'tradeSoftware',
|
||||
name: 'TradeSoftware',
|
||||
component: () => import('@/views/trade/tradeSoftware/index.vue'),
|
||||
meta: {
|
||||
title: '交易软件', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
//公告管理
|
||||
{
|
||||
path: 'notice',
|
||||
name: 'Notice',
|
||||
meta: {
|
||||
title: '公告管理', // 左侧菜单显示的标题
|
||||
},
|
||||
component: () => import('@/views/notice/index.vue'),
|
||||
},
|
||||
//资金管理
|
||||
{
|
||||
path: 'funding',
|
||||
name: 'Funding',
|
||||
meta: {
|
||||
title: '资金管理', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'deposit',
|
||||
name: 'Deposit',
|
||||
component: () => import('@/views/funding/deposit/index.vue'),
|
||||
meta: {
|
||||
title: '存款审核', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'withdrawal',
|
||||
name: 'Withdrawal',
|
||||
component: () => import('@/views/funding/withdrawl/index.vue'),
|
||||
meta: {
|
||||
title: '取款审核', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'withdrawalDetail',
|
||||
name: 'WithdrawalDetail',
|
||||
component: () => import('@/views/funding/withdrawalDetail/index.vue'),
|
||||
meta: {
|
||||
title: '取款明细', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'depositDetail',
|
||||
name: 'DepositDetail',
|
||||
component: () => import('@/views/funding/depositDetail/index.vue'),
|
||||
meta: {
|
||||
title: '存款明细', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'transfer',
|
||||
name: 'Transfer',
|
||||
component: () => import('@/views/funding/transfer/index.vue'),
|
||||
meta: {
|
||||
title: '转账', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'transferDetail',
|
||||
name: 'TransferDetail',
|
||||
component: () => import('@/views/funding/transferDetail/index.vue'),
|
||||
meta: {
|
||||
title: '转账明细', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'capitalFlow',
|
||||
name: 'CapitalFlow',
|
||||
component: () => import('@/views/funding/capitalFlow/index.vue'),
|
||||
meta: {
|
||||
title: '资金流水', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'receiverAccount',
|
||||
name: 'ReceiverAccount',
|
||||
component: () => import('@/views/funding/receiverAccount/index.vue'),
|
||||
meta: {
|
||||
title: '收款账户列表', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'depositChannel',
|
||||
name: 'DepositChannel',
|
||||
component: () => import('@/views/funding/depositChannel/index.vue'),
|
||||
meta: {
|
||||
title: '存款渠道列表', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'fundDetail',
|
||||
name: 'FundDetail',
|
||||
component: () => import('@/views/funding/fundDetail/index.vue'),
|
||||
meta: {
|
||||
title: '资金明细', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'risk',
|
||||
name: 'Risk',
|
||||
meta: {
|
||||
title: '风控管理', // 左侧菜单显示的标题
|
||||
},
|
||||
component: () => import('@/views/risk/index.vue'),
|
||||
},
|
||||
// 个性化交易
|
||||
{
|
||||
path: 'personalized',
|
||||
name: 'Personalized',
|
||||
meta: {
|
||||
title: '个性化交易', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
// 跟单记录
|
||||
{
|
||||
path: 'followRecord',
|
||||
name: 'FollowRecord',
|
||||
component: () => import('@/views/personalized/followRecord/index.vue'),
|
||||
meta: {
|
||||
title: '跟单记录', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
// 带单记录
|
||||
{
|
||||
path: 'leadRecord',
|
||||
name: 'LeadRecord',
|
||||
component: () => import('@/views/personalized/leadRecord/index.vue'),
|
||||
meta: {
|
||||
title: '带单记录', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
//代理管理
|
||||
{
|
||||
path: 'agent',
|
||||
name: 'Agent',
|
||||
meta: {
|
||||
title: '代理管理', // 左侧菜单显示的标题
|
||||
},
|
||||
children: [
|
||||
//客户列表
|
||||
{
|
||||
path: 'customerList',
|
||||
name: 'CustomerList',
|
||||
component: () => import('@/views/agent/customerList/index.vue'),
|
||||
meta: {
|
||||
title: '客户列表', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
//客户详情
|
||||
{
|
||||
path: 'customerDetail/:id',
|
||||
name: 'CustomerDetail',
|
||||
component: () => import('@/views/agent/customerDetail/index.vue'),
|
||||
meta: {
|
||||
title: '客户详情', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
//客户交易订单
|
||||
{
|
||||
path: 'customerTradeOrder',
|
||||
name: 'CustomerTradeOrder',
|
||||
component: () => import('@/views/agent/customerTradeOrder/index.vue'),
|
||||
meta: {
|
||||
title: '客户交易订单', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
//客户资金流水
|
||||
{
|
||||
path: 'customerCapitalFlow',
|
||||
name: 'CustomerCapitalFlow',
|
||||
component: () => import('@/views/agent/customerCapitalFlow/index.vue'),
|
||||
meta: {
|
||||
title: '客户资金流水', // 左侧菜单显示的标题
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -407,34 +76,37 @@ const routes = [
|
|||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
})
|
||||
|
||||
// 全局前置守卫
|
||||
router.beforeEach(async (to, from) => {
|
||||
const userStore = useUserStore();
|
||||
const isLoggedIn = !!userStore.token;
|
||||
const userStore = useUserStore()
|
||||
const isLoggedIn = !!userStore.token
|
||||
|
||||
// 1. 已登录用户访问授权页 → 重定向到首页
|
||||
if (isLoggedIn && to.meta.isAuthPage) {
|
||||
if (to.path === '/') return true;
|
||||
return '/';
|
||||
}
|
||||
console.log('全局前置守卫', isLoggedIn, to.meta.requiresAuth)
|
||||
|
||||
// 2. 未登录用户访问需要登录的页面(包括首页)→ 重定向到登录页
|
||||
// 1. 未登录用户访问需要登录的页面(包括首页)→ 重定向到登录页
|
||||
if (!isLoggedIn && to.meta.requiresAuth) {
|
||||
if (to.path === '/user/login') return true;
|
||||
return '/user/login';
|
||||
if (to.path === '/user/login') return true
|
||||
console.log('全局前置守卫', isLoggedIn, to.meta.requiresAuth)
|
||||
return '/user/login'
|
||||
}
|
||||
|
||||
// 2. 已登录用户访问授权页 → 重定向到首页
|
||||
// if (isLoggedIn) {
|
||||
// if (to.path === '/' && to.meta.isAuthPage) return true
|
||||
// return '/'
|
||||
// }
|
||||
|
||||
// 3. 其他情况正常放行
|
||||
return true;
|
||||
});
|
||||
return true
|
||||
})
|
||||
|
||||
// 可选:设置页面标题
|
||||
router.afterEach((to) => {
|
||||
if (to.meta.title) {
|
||||
document.title = to.meta.title as string;
|
||||
document.title = to.meta.title as string
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { loginApi, registerApi, logoutApi, forgotPasswordApi, changePasswordApi,
|
|||
import type { LoginParams, RegisterParams, ForgotPasswordParams, ChangePasswordParams, SendCodeParams } from '@/api/types/user';
|
||||
import type { UserInfo, MenuItem, PermissionItem } from '@/stores/types/user';
|
||||
import { formatMenuToElMenu, type ElMenuItem } from '@/utils/menuFormat';
|
||||
import { handleRouter } from '@/router/handleRouter.ts'
|
||||
|
||||
// 定义用户 Store
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
|
|
@ -36,7 +37,19 @@ const setUserInfo = (set: any) => {
|
|||
setStorage('menusInfo', set.menus_info);
|
||||
setStorage('permissionsInfo', set.permissions_info);
|
||||
|
||||
console.log('用户信息保存成功');
|
||||
|
||||
const userStore = useUserStore()
|
||||
if (userStore.token && userStore.menusInfo.length > 0) {
|
||||
const routeList = handleRouter(userStore.menusInfo).filter(
|
||||
(item) => item.path && item.path !== '/dashboard',
|
||||
)
|
||||
routeList.forEach((route) => router.addRoute('Layout', route))
|
||||
}
|
||||
|
||||
router.getRoutes().forEach((route) => {
|
||||
console.log(`路径: ${route.path}, 名称: ${route.name || '无'}`)
|
||||
})
|
||||
console.log('用户信息保存成功', handleRouter(set.menus_info), router);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -38,11 +38,7 @@ export const formatMenuToElMenu = (rawMenuList: any[]): ElMenuItem[] => {
|
|||
}
|
||||
|
||||
// 2. 处理图标:仅一级菜单基于 path 映射,二级菜单无图标
|
||||
let icon: string = '';
|
||||
if (isFirstLevel) {
|
||||
// 一级菜单:根据后端 path 字段映射图标
|
||||
icon = pathToIconMap[menu.path] || pathToIconMap['default'] || '';
|
||||
}
|
||||
let icon: string = menu.icon as string;
|
||||
// 二级菜单:不赋值 icon → 自动无图标
|
||||
|
||||
// 3. 基础菜单项
|
||||
|
|
@ -63,4 +59,4 @@ export const formatMenuToElMenu = (rawMenuList: any[]): ElMenuItem[] => {
|
|||
|
||||
// 遍历一级菜单,标记 isFirstLevel = true
|
||||
return rawMenuList.map(menu => formatSubMenu(menu, true));
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,194 +0,0 @@
|
|||
<template>
|
||||
<div class="account-detail">
|
||||
<h4>账户信息</h4>
|
||||
<el-card class="account-info">
|
||||
<el-icon>
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
<div class="item">
|
||||
<div class="item-content">
|
||||
<div class="item-label" v-if="!isChangeName">
|
||||
<span>账号名称:</span>
|
||||
<span>{{ accountName }}</span>
|
||||
</div>
|
||||
<div class="item-changeName" v-else>
|
||||
<span>账号名称:</span>
|
||||
<el-input v-model="newAccountName" placeholder="请输入新账号名称" size="small" ref="inputRef" @blur="handleSave" @keyup.enter="handleSave"/>
|
||||
</div>
|
||||
<el-button type="default" @click="changeName" size="small">修改名称</el-button>
|
||||
</div>
|
||||
<span>用户最后登录时间:2026.02.02 07:00:00</span>
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="security">
|
||||
<h4>安全信息</h4>
|
||||
<div class="card-group">
|
||||
<el-card>
|
||||
<span>邮箱</span>
|
||||
<span>已绑定邮箱:{{ userInfo?.email || '未绑定' }}</span>
|
||||
<el-button :type="accountStatus === true ? 'primary' : 'danger'" @click="handleEmail">{{ accountStatus === true ? '已验证' :
|
||||
'未验证' }}</el-button>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<span>手机号</span>
|
||||
<span>已绑定手机号:{{ userInfo?.phone || '未绑定' }}</span>
|
||||
<el-button :type="phoneStatus === true ? 'primary' : 'danger'" @click="handlePhone">{{ phoneStatus === true ? '已绑定' :
|
||||
'未绑定' }}</el-button>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<span>密码</span>
|
||||
<span>************</span>
|
||||
<el-button type="primary" @click="changePassword">修改</el-button>
|
||||
</el-card>
|
||||
<el-card>
|
||||
<span>默认语言</span>
|
||||
<span>选择您的语言偏好</span>
|
||||
<LanguageSelect v-model="languageStore.lang" @change="languageStore.changeLang" />
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
|
||||
//组件
|
||||
import LanguageSelect from '@/components/LanguageSelect/index.vue'
|
||||
|
||||
// 导入Pinia状态
|
||||
import { useLanguageStore } from '@/stores/modules/language'
|
||||
import { getStorage, setStorage } from '@/utils/storage'
|
||||
|
||||
//接口
|
||||
import { editAgentNameApi } from '@/api/modules/agent'
|
||||
|
||||
// 语言选择配置
|
||||
const router = useRouter()
|
||||
const languageStore = useLanguageStore()
|
||||
|
||||
// 账户状态
|
||||
const accountStatus = ref(true)
|
||||
// 手机号状态
|
||||
const phoneStatus = ref(true)
|
||||
|
||||
/**
|
||||
* @description 账户信息数据
|
||||
*/
|
||||
|
||||
// 从本地存储获取账户名称
|
||||
const userInfo = getStorage<any>('userInfo')
|
||||
const accountName = ref(userInfo?.username || '')
|
||||
const newAccountName = ref(accountName.value)
|
||||
//判断是否修改名称
|
||||
const isChangeName = ref(false)
|
||||
// 输入框引用
|
||||
const inputRef = ref<HTMLInputElement>()
|
||||
|
||||
/**
|
||||
* @description 绑定邮箱
|
||||
*/
|
||||
const handleEmail = ()=>{
|
||||
accountStatus.value === false ? router.push('/user/bind-email') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 绑定手机号
|
||||
*/
|
||||
const handlePhone = ()=>{
|
||||
phoneStatus.value === false ? router.push('/user/bind-phone') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 修改密码
|
||||
*/
|
||||
const changePassword = () => {
|
||||
router.push('/user/change-password')
|
||||
}
|
||||
|
||||
|
||||
// 修改用户名
|
||||
const changeName = async () => {
|
||||
isChangeName.value = true
|
||||
// 等待 DOM 更新后自动聚焦输入框
|
||||
await nextTick()
|
||||
inputRef.value?.focus()
|
||||
}
|
||||
|
||||
//修改用户名提交
|
||||
const handleSave = async () => {
|
||||
if (newAccountName.value.trim()) {
|
||||
await editAgentNameApi({
|
||||
account_id: userInfo?.id || '',
|
||||
account_name: newAccountName.value
|
||||
})
|
||||
accountName.value = newAccountName.value.trim()
|
||||
setStorage('userInfo', {
|
||||
...userInfo,
|
||||
username: accountName.value
|
||||
})
|
||||
} else {
|
||||
newAccountName.value = accountName.value // 若为空则恢复原值
|
||||
}
|
||||
isChangeName.value = false
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.account-detail {
|
||||
h4 {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.account-info {
|
||||
box-shadow: none;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.item-changeName {
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
margin-right: 10px;
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.security {
|
||||
margin-top: 20px;
|
||||
|
||||
.card-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.el-card {
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
<template>
|
||||
<div class="agent">
|
||||
<!-- 搜索 -->
|
||||
<AgentSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset" />
|
||||
<!-- 表格 -->
|
||||
<AgentTable :table-data="agentTree" :columns="agentTableColumnsOptions" row-key="id">
|
||||
<template #status="{ row }">
|
||||
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" />
|
||||
</template>
|
||||
<template #pointDifference="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleViewPointDiff(row)">
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
<template #edit="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</AgentTable>
|
||||
<!-- 分页 -->
|
||||
<AgentPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
<!-- 弹窗 -->
|
||||
<AgentDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" :fullscreen="dialogFullscreen"
|
||||
:show-footer="dialogType !== 'view'" @confirm="handleSubmit" @cancel="handleCancel" @close="handleClose">
|
||||
<!-- 编辑表单 -->
|
||||
<AgentForm :form-data="agentForm" :form-rules="agentFormRules" :form-items="agentFormItemOptions"
|
||||
:options-map="agentFormOptionsMap" ref="agentFormRef" v-if="dialogType !== 'view'"></AgentForm>
|
||||
<!-- 点差表格 -->
|
||||
<AgentTable :table-data="agentPointTree" :columns="agentPointTableColumnsOptions" row-key="id">
|
||||
<template #assignedPointDiff="{ row }">
|
||||
<el-form :model="row" :rules="rules(agentForm,row)">
|
||||
<el-form-item prop="assignedPointDifference">
|
||||
<el-input v-model="row.assignedPointDifference" size="small" placeholder="请输入点差" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</AgentTable>
|
||||
</AgentDialog>
|
||||
<!-- 编辑/查看表单 -->
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
//组件
|
||||
import AgentSearch from '@/components/common/Search.vue'
|
||||
import AgentTable from '@/components/common/Table.vue'
|
||||
import AgentPagination from '@/components/common/Pagination.vue'
|
||||
import AgentDialog from '@/components/common/Dialog.vue'
|
||||
import AgentForm from '@/components/common/Form.vue'
|
||||
|
||||
//配置
|
||||
import { agentSearch, agentTableColumns, viewAgentPointTableColumns, agentPointTableColumns, agentFormItem } from './options'
|
||||
import { rules } from './rules'
|
||||
|
||||
//接口
|
||||
import { getAgentListApi, getPointDiffConfigApi, getRiskTemplateOptionsApi, getFeeTemplateOptionsApi, editPointDiffApi } from '@/api/modules/account/agent'
|
||||
|
||||
//引入公用方法
|
||||
import { getStorage } from '@/utils/storage';
|
||||
|
||||
//获取当前登录用户的id
|
||||
const useInfo = ref<any>(getStorage('userInfo'))
|
||||
/**
|
||||
* @description 定义搜索数据
|
||||
*/
|
||||
const searchForm = ref({
|
||||
username: '',
|
||||
status: '正常',
|
||||
startDateTime: '',
|
||||
endDateTime: '',
|
||||
})
|
||||
const searchOptions = ref(agentSearch)
|
||||
|
||||
/**
|
||||
* @description 定义表格数据
|
||||
*/
|
||||
const agentTree = ref([])
|
||||
const agentTableColumnsOptions = ref(agentTableColumns)
|
||||
|
||||
/**
|
||||
* @description 定义分页数据
|
||||
*/
|
||||
const total = ref(0)
|
||||
const pageSize = ref(10)
|
||||
const currentPage = ref(1)
|
||||
|
||||
/**
|
||||
* @description 定义弹窗数据
|
||||
*/
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const dialogTitle = ref<string>('')
|
||||
const dialogType = ref<string>('edit')
|
||||
const dialogFullscreen = ref(false)
|
||||
|
||||
/**
|
||||
* @description 定义弹窗form数据
|
||||
*/
|
||||
const agentForm = ref({
|
||||
username: '',
|
||||
parentUsername: '',
|
||||
riskTemplate: '',
|
||||
feeTemplate: '',
|
||||
positionRatio: '',
|
||||
feeRate: '',
|
||||
maxPositionRatio: '',
|
||||
maxFeeRate: '',
|
||||
//存用户id
|
||||
id: '',
|
||||
})
|
||||
const agentFormRules = rules(agentForm.value)
|
||||
const agentFormRef = ref()
|
||||
const agentFormItemOptions = ref(agentFormItem)
|
||||
//使用这个判断请求是否完成,去缓存请求
|
||||
const optionsFetched = ref(false)
|
||||
interface SelectOption {
|
||||
label: string
|
||||
value: string | number
|
||||
}
|
||||
const agentFormOptionsMap = ref({
|
||||
riskTemplate: [] as SelectOption[],
|
||||
feeTemplate: [] as SelectOption[],
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 定义弹窗表格数据
|
||||
*/
|
||||
const agentPointTree = ref([])
|
||||
const agentPointTableColumnsOptions = computed(() => {
|
||||
return dialogType.value !== 'view' ? agentPointTableColumns : viewAgentPointTableColumns;
|
||||
});
|
||||
/**
|
||||
* @description 定义通用数据处理方法
|
||||
*/
|
||||
//处理字符串数值:转数字 + 相加 + 保留五位小数
|
||||
function sumStrNumsWith5Decimals(strNums: string[]) {
|
||||
// 1. 初始化总和
|
||||
let total = 0;
|
||||
|
||||
// 2. 遍历数组,逐个转换并累加
|
||||
strNums.forEach(strNum => {
|
||||
// 转数字(处理空值/非数字,兜底为0)
|
||||
const num = parseFloat(strNum) || 0;
|
||||
total += num;
|
||||
});
|
||||
|
||||
// 3. 保留五位小数(四舍五入),转回数字类型
|
||||
const result = parseFloat(total.toFixed(5));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 映射对象为数组通用方法
|
||||
const mapObjectToOptions = (obj: Record<string, string>) => {
|
||||
return Object.entries(obj).map(([label, value]) => ({
|
||||
label, // 模板/代理名称
|
||||
value // 模板/代理ID
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 定义通用数据获取方法
|
||||
*/
|
||||
//获取代理列表
|
||||
const getAgentList = async () => {
|
||||
const params = {
|
||||
user_id: useInfo.value.id,
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
user_name: searchForm.value.username,
|
||||
status: searchForm.value.status,
|
||||
reg_start_time: searchForm.value.startDateTime,
|
||||
reg_end_time: searchForm.value.endDateTime,
|
||||
}
|
||||
const data = await getAgentListApi(params)
|
||||
// 表格数据
|
||||
agentTree.value = data.data.map((item: any) => {
|
||||
//针对当前item提取需要相加的字段(每次循环都重新取当前行数据)
|
||||
const walletNums = [
|
||||
// 兜底空值,避免undefined导致计算错误
|
||||
item.wallet_capital?.commission_fee_handling || '0.00000',
|
||||
item.wallet_capital?.commission_point_diff || '0.00000'
|
||||
];
|
||||
// 计算返佣总金额的值
|
||||
const rebateTotalAmount = sumStrNumsWith5Decimals(walletNums);
|
||||
return {
|
||||
...item,
|
||||
createTime: item.created_at || '',
|
||||
feeRate: item.wallet_capital.fee_handling_percent,
|
||||
rebateRate: item.wallet_capital.commission_fee_handling,
|
||||
pointDifference: item.wallet_capital.commission_point_diff,
|
||||
rebateTotalAmount: rebateTotalAmount,
|
||||
clientCount: item.son_user.length,
|
||||
level: item.role.title,
|
||||
parentUsername: item.par_uid === item.parent.id ? item.parent.username : '',
|
||||
}
|
||||
|
||||
})
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
|
||||
//获取点差配置
|
||||
const getPointDiffConfig = async (row: any) => {
|
||||
const params = {
|
||||
user_id: row.id
|
||||
}
|
||||
const data = await getPointDiffConfigApi(params)
|
||||
// 表格数据
|
||||
agentPointTree.value = data.map((item: any) => ({
|
||||
...item,
|
||||
varietyName: item.name,
|
||||
varietyCode: item.code,
|
||||
pointDifference: item.point_diff,
|
||||
assignedPointDifference: item.target_point_diff
|
||||
}));
|
||||
}
|
||||
|
||||
// 合并获取表单下拉数据
|
||||
const getOptions = async () => {
|
||||
// 已获取过选项则直接返回,避免重复请求
|
||||
if (optionsFetched.value) return
|
||||
|
||||
try {
|
||||
const [riskTemplateRes, feeTemplateRes] = await Promise.all([
|
||||
// 风控模板
|
||||
getRiskTemplateOptionsApi(),
|
||||
// 手续费模板
|
||||
getFeeTemplateOptionsApi()
|
||||
])
|
||||
// label=名称,value=ID
|
||||
agentFormOptionsMap.value.riskTemplate = riskTemplateRes.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}))
|
||||
// label=名称,value=ID
|
||||
agentFormOptionsMap.value.feeTemplate = mapObjectToOptions(feeTemplateRes as Record<string, string>)
|
||||
optionsFetched.value = true // 标记已获取
|
||||
} catch (error) {
|
||||
console.error('获取表单选项失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 页面加载完成需要调用的方法
|
||||
*/
|
||||
onMounted(() => {
|
||||
getAgentList()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @description 定义搜索组件的全部方法
|
||||
*/
|
||||
const handleSearch = () => {
|
||||
getAgentList()
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
username: '',
|
||||
status: '正常',
|
||||
startDateTime: '',
|
||||
endDateTime: '',
|
||||
}
|
||||
getAgentList()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 定义表格方法
|
||||
*/
|
||||
// 查看点差
|
||||
const handleViewPointDiff = (row: any) => {
|
||||
getPointDiffConfig(row)
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '查看点差'
|
||||
dialogType.value = 'view'
|
||||
dialogFullscreen.value = true
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const handleEdit = async (row: any) => {
|
||||
console.log('row', row)
|
||||
// 并行请求点差配置和下拉选项
|
||||
await Promise.all([
|
||||
// getPointDiffConfig(row),
|
||||
getOptions()
|
||||
])
|
||||
// 填充表单数据
|
||||
agentForm.value = {
|
||||
username: row.username || '',
|
||||
parentUsername: row.parentUsername || '',
|
||||
riskTemplate: row.wallet_capital.risk_control_id || '',
|
||||
feeTemplate: row.wallet_capital.fee_setting_id || '',
|
||||
positionRatio: row.wallet_capital.toucun_percent || '',
|
||||
feeRate: row.feeRate || '',
|
||||
id: row.id || '',
|
||||
maxPositionRatio: row.wallet_capital.toucun_percent || '',
|
||||
maxFeeRate: row.wallet_capital.fee_handling_percent || '',
|
||||
}
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '编辑'
|
||||
dialogType.value = 'edit'
|
||||
dialogFullscreen.value = false
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 定义分页方法
|
||||
*/
|
||||
// 分页变更
|
||||
const handlePaginationChange = async (page: { currentPage: number, pageSize: number }) => {
|
||||
currentPage.value = page.currentPage
|
||||
pageSize.value = page.pageSize
|
||||
await getAgentList()
|
||||
}
|
||||
/**
|
||||
* @description 定义dialog方法
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 提交之前构造数据
|
||||
|
||||
*/
|
||||
// 格式化点差为 { "1":"42", "2":"38" } 格式的对象
|
||||
const formatPointDiffToObject = () => {
|
||||
if (!agentPointTree.value || !agentPointTree.value.length) return {};
|
||||
|
||||
// 初始化空对象
|
||||
const pointDiffObj: Record<string, string> = {};
|
||||
|
||||
// 遍历表格数据,构造 { 编号: 点差值 } 的对象
|
||||
agentPointTree.value.forEach((item: { id: string | number; assignedPointDifference: string }) => {
|
||||
// 类型安全的赋值
|
||||
pointDiffObj[String(item.id)] = item.assignedPointDifference || '0';
|
||||
});
|
||||
|
||||
return pointDiffObj; // 返回纯对象,而非数组
|
||||
};
|
||||
|
||||
//提交
|
||||
const handleSubmit = async () => {
|
||||
await agentFormRef.value.validate()
|
||||
const pointDiffObj = formatPointDiffToObject()
|
||||
const params = {
|
||||
user_id: agentForm.value.id || '',
|
||||
toucun_percent: agentForm.value.positionRatio || '',
|
||||
point_diffs_json: JSON.stringify(pointDiffObj),
|
||||
fee_handling_percent: agentForm.value.feeRate || '',
|
||||
fee_setting_id: agentForm.value.feeTemplate || '',
|
||||
risk_control_id: agentForm.value.riskTemplate || '',
|
||||
}
|
||||
await editPointDiffApi(params)
|
||||
// 刷新表格数据
|
||||
await getAgentList()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.table-container{
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
// 获取当前年份
|
||||
const currentYear = new Date().getFullYear()
|
||||
|
||||
// 定义禁用日期函数:只能选择今年及以后的日期
|
||||
const disabledDate = (time: Date) => {
|
||||
// 时间早于今年1月1日则禁用
|
||||
return time.getTime() < new Date(currentYear, 0, 1).getTime()
|
||||
}
|
||||
//定义客户搜索表单配置
|
||||
export const agentSearch = [
|
||||
{ prop: 'username', label: '用户名', type: 'input' as const, placeholder: '用户名', width: '120px' },
|
||||
{
|
||||
prop: "startDateTime", label: '注册开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: '180px',
|
||||
disabledDate
|
||||
},
|
||||
{
|
||||
prop: "endDateTime", label: '注册结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: '180px',
|
||||
disabledDate
|
||||
},
|
||||
]
|
||||
|
||||
// 定义表格列配置
|
||||
export const agentTableColumns = [
|
||||
{ prop: 'id', label: 'ID', align: 'center' as const, width: '80px' },
|
||||
{ prop: 'username', label: '代理名称', align: 'center' as const },
|
||||
{ prop: 'createTime', label: '注册时间', align: 'center' as const },
|
||||
{ slotName: 'status', label: '状态', align: 'center' as const },
|
||||
{ prop: 'feeRate', label: '手续费', align: 'center' as const },
|
||||
{ prop: 'rebateRate', label: '手续费返佣', align: 'center' as const },
|
||||
{ prop: 'pointDifference', label: '点差返佣', align: 'center' as const },
|
||||
{ slotName: 'pointDifference', label: '点差', align: 'center' as const },
|
||||
{ prop: 'rebateTotalAmount', label: '返佣总金额', align: 'center' as const },
|
||||
{ prop: 'clientCount', label: '客户数量', align: 'center' as const },
|
||||
{ prop: 'level', label: '级别', align: 'center' as const },
|
||||
{ prop: 'parentUsername', label: '所属上级', align: 'center' as const },
|
||||
{ slotName: 'edit', label: '编辑', align: 'center' as const },
|
||||
|
||||
]
|
||||
|
||||
// 查看代理点差表格列配置
|
||||
export const viewAgentPointTableColumns = [
|
||||
{ prop: 'varietyName', label: '品种名称', align: 'center' as const },
|
||||
{ prop: 'varietyCode', label: '品种编号', align: 'center' as const },
|
||||
{ prop: 'pointDifference', label: '可用点差', align: 'center' as const },
|
||||
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const },
|
||||
]
|
||||
|
||||
//编辑代理表格列配置
|
||||
export const agentPointTableColumns = ([
|
||||
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
||||
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
||||
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
||||
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const, slotName: 'assignedPointDiff' },
|
||||
])
|
||||
|
||||
|
||||
//编辑代理form配置
|
||||
export const agentFormItem = [
|
||||
//代理名称
|
||||
{ prop: 'username', label: '代理名称', type: 'input' as const, placeholder: '代理名称', width: '120px' },
|
||||
//所属上级
|
||||
{ prop: 'parentUsername', label: '所属上级', type: 'input' as const, placeholder: '所属上级', width: '120px' },
|
||||
//风控模板
|
||||
{ prop: 'riskTemplate', label: '风控模板', type: 'select' as const, placeholder: '风控模板', width: '120px' },
|
||||
//手续费模板
|
||||
{ prop: 'feeTemplate', label: '手续费模板', type: 'select' as const, placeholder: '手续费模板', width: '120px' },
|
||||
//头寸
|
||||
{ prop: 'positionRatio', label: '头寸', type: 'input' as const, placeholder: '请输入头寸', width: '120px' },
|
||||
//手续费
|
||||
{ prop: 'feeRate', label: '手续费', type: 'input' as const, placeholder: '手续费', width: '120px' },
|
||||
|
||||
]
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
import type { FormRules } from 'element-plus'
|
||||
|
||||
export const rules = (form: any, row?: any): FormRules => {
|
||||
return {
|
||||
username: [
|
||||
{ required: true, message: '请输入名称', trigger: ['blur'] }
|
||||
],
|
||||
parentUsername: [
|
||||
{ required: true, message: '请输入所属上级', trigger: ['blur'] }
|
||||
],
|
||||
riskTemplate: [
|
||||
{ required: true, message: '请选择风险模板', trigger: ['change'] }
|
||||
],
|
||||
feeTemplate: [
|
||||
{ required: true, message: '请选择手续费模板', trigger: ['change'] }
|
||||
],
|
||||
positionRatio: [
|
||||
{ required: true, message: '请输入头寸', trigger: ['blur'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 空值已经由 required 校验处理
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// 尝试转换为数字
|
||||
const numValue = Number(value);
|
||||
// 转换失败 → 不是有效数字
|
||||
if (isNaN(numValue)) {
|
||||
return callback(new Error('头寸必须为数字'));
|
||||
}
|
||||
// 范围校验(0-100)
|
||||
if (numValue < 0 || numValue > 100) {
|
||||
return callback(new Error('头寸需在0-100之间'));
|
||||
}
|
||||
|
||||
// 精度校验(最多2位小数)
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(value.toString())) {
|
||||
return callback(new Error('头寸最多保留2位小数'));
|
||||
}
|
||||
|
||||
// 不超过上级最大头寸校验
|
||||
if (form.maxPositionRatio && numValue > Number(form.maxPositionRatio)) {
|
||||
return callback(new Error(`头寸不能超过上级账户的最大头寸(${form.maxPositionRatio})`));
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
feeRate: [
|
||||
{ required: true, message: '请输入手续费率', trigger: ['blur'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 空值已经由 required 校验处理
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// 尝试转换为数字
|
||||
const numValue = Number(value);
|
||||
// 转换失败 → 不是有效数字
|
||||
if (isNaN(numValue)) {
|
||||
return callback(new Error('头寸必须为数字'));
|
||||
}
|
||||
// 范围校验(0-100)
|
||||
if (numValue < 0 || numValue > 100) {
|
||||
return callback(new Error('头寸需在0-100之间'));
|
||||
}
|
||||
|
||||
// 精度校验(最多5位小数)
|
||||
if (!/^\d+(\.\d{1,5})?$/.test(value.toString())) {
|
||||
return callback(new Error('手续费率最多保留5位小数'));
|
||||
}
|
||||
|
||||
// 不超过上级最大头寸校验
|
||||
if (form.maxFeeRate && numValue > Number(form.maxFeeRate)) {
|
||||
return callback(new Error(`头寸不能超过上级账户的最大头寸(${form.maxFeeRate})`));
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
assignedPointDifference: [
|
||||
{ required: true, message: '请输入点差', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback()
|
||||
}
|
||||
|
||||
const numValue = Number(value)
|
||||
|
||||
// 1. 基础数字校验
|
||||
if (isNaN(numValue)) {
|
||||
return callback(new Error('点差必须为数字'))
|
||||
}
|
||||
if (numValue < 0) {
|
||||
return callback(new Error('点差不能为负数'))
|
||||
}
|
||||
if (!/^\d+(\.\d{1,5})?$/.test(value.toString())) {
|
||||
return callback(new Error('点差最多保留5位小数'))
|
||||
}
|
||||
|
||||
// 2. 核心校验:已分配点差 ≤ 可分配点差
|
||||
if (row && row.pointDifference !== undefined) {
|
||||
const maxPointDiff = Number(row.pointDifference)
|
||||
if (numValue > maxPointDiff) {
|
||||
return callback(new Error(`可分配点差为(${maxPointDiff})`))
|
||||
}
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 搜索 -->
|
||||
<CustomerCapitalFlowSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
</CustomerCapitalFlowSearch>
|
||||
<!-- 表格 -->
|
||||
<CustomerCapitalFlowTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
|
||||
<!-- 分页 -->
|
||||
<CustomerCapitalFlowPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import CustomerCapitalFlowSearch from '@/components/common/Search.vue'
|
||||
import CustomerCapitalFlowTable from '@/components/common/Table.vue'
|
||||
import CustomerCapitalFlowPagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
|
||||
// 接口
|
||||
import { getCustomCapitalFlowListApi } from '@/api/modules/agent/customCapitalFlow'
|
||||
|
||||
|
||||
|
||||
|
||||
// 公用方法
|
||||
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchForm = ref({
|
||||
accountName: '',
|
||||
userId: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
const searchOptions = ref(search)
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
const getCustomerCapitalFlowList = async () => {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-15 23:59:59',
|
||||
user_name: searchForm.value.accountName,
|
||||
account_id: '',
|
||||
}
|
||||
const data: any = await getCustomCapitalFlowListApi(params)
|
||||
|
||||
//表格数据
|
||||
// table数据映射
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
id:item.account_id,
|
||||
flowNo:item.trade_id,
|
||||
accountName:item.user.username,
|
||||
amount:item.amount,
|
||||
fundType:item.wallet_type === "1" ? '主账户' : '子账户',
|
||||
// status:'',
|
||||
operationType:item.enum_dic.value,
|
||||
createTime:item.created_at,
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getCustomerCapitalFlowList()
|
||||
})
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = () => {
|
||||
getCustomerCapitalFlowList()
|
||||
}
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
accountName: '',
|
||||
userId: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
getCustomerCapitalFlowList()
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: { currentPage: number, size: number }) => {
|
||||
currentPage.value = page.currentPage
|
||||
getCustomerCapitalFlowList()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
export const search = [
|
||||
// 账号名称
|
||||
{ prop: 'accountName', label: '账号名称', type: 'input' as const, placeholder: '请输入账号名称', width: '150px' },
|
||||
// 开始时间
|
||||
{
|
||||
prop: "startTime", label: '注册开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
},
|
||||
// 结束时间
|
||||
{
|
||||
prop: "endTime", label: '注册结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
},
|
||||
// 选择账号
|
||||
{ prop: 'userId', label: '账号', type: 'select' as const, placeholder: '请选择账号' },
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 流水id
|
||||
{ prop: 'id', label: '流水id' },
|
||||
// 流水单号
|
||||
{ prop: 'flowNo', label: '流水单号' },
|
||||
// 账户名称
|
||||
{ prop: 'accountName', label: '账户名称' },
|
||||
// 金额
|
||||
{ prop: 'amount', label: '金额' },
|
||||
// 资金类别
|
||||
{ prop: 'fundType', label: '资金类别' },
|
||||
// 状态
|
||||
// { prop: 'status', label: '状态' },
|
||||
// 操作方式
|
||||
{ prop: 'operationType', label: '操作方式' },
|
||||
// 时间
|
||||
{ prop: 'createTime', label: '时间' },
|
||||
]
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
<template>
|
||||
<div class="customer-detail">
|
||||
<div class="back">
|
||||
<div class="title" @click="handleBack">
|
||||
<el-icon>
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
返回上层
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail">
|
||||
<el-card class="user-card">
|
||||
<el-icon>
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
<div class="user-item">
|
||||
<span>账户名称:{{customerDetail.accountName}}</span>
|
||||
<span>账户id:{{customerDetail.userId}}</span>
|
||||
<span>账户角色:{{customerDetail.userRole}}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="information-card">
|
||||
<div class="information-item">
|
||||
<div class="group">
|
||||
<p>手机号</p>
|
||||
<p>{{customerDetail.phone}}</p>
|
||||
</div>
|
||||
<div class="group">
|
||||
<p>邮箱</p>
|
||||
<p>{{customerDetail.email}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="information-item">
|
||||
<div class="group">
|
||||
<p>存款金额</p>
|
||||
<p>{{customerDetail.depositAmount}}</p>
|
||||
</div>
|
||||
<div class="group">
|
||||
<p>账户余额</p>
|
||||
<p>{{customerDetail.balance}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="information-item">
|
||||
<div class="group">
|
||||
<p>注册时间</p>
|
||||
<p>{{customerDetail.registerTime}}</p>
|
||||
</div>
|
||||
<div class="group">
|
||||
<p>历史交易金额</p>
|
||||
<p>{{customerDetail.historyTradeAmount}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<CustomerDetailTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" :default-sort="{ prop: 'balance', order: 'descending' }"/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ArrowLeft, UserFilled } from '@element-plus/icons-vue'
|
||||
// 组件
|
||||
import CustomerDetailTable from '@/components/common/Table.vue'
|
||||
// 配置
|
||||
import { tableColumns } from './options'
|
||||
|
||||
|
||||
|
||||
import { getCustomerDetailApi } from '@/api/modules/agent/customerDetail'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
/**
|
||||
* @description: 定义客户详情数据
|
||||
*/
|
||||
const customerDetail = ref({
|
||||
// 账户名称
|
||||
accountName: '',
|
||||
// 账户id
|
||||
userId: '',
|
||||
// 账户角色
|
||||
userRole: '',
|
||||
// 手机号
|
||||
phone: '',
|
||||
// 邮箱
|
||||
email: '',
|
||||
// 存款金额
|
||||
depositAmount: '',
|
||||
// 账户余额
|
||||
balance: '',
|
||||
// 注册时间
|
||||
registerTime: '',
|
||||
// 历史交易金额
|
||||
historyTradeAmount: '',
|
||||
})
|
||||
|
||||
// 客户角色映射
|
||||
const roleMap: any = {
|
||||
1: '平台',
|
||||
2: '承包商',
|
||||
3: '特殊做市商',
|
||||
4: '普通做市商',
|
||||
5: '代理',
|
||||
6: '用户'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 获取客户详情
|
||||
*/
|
||||
const getCustomerDetail = async () => {
|
||||
const id = route.params.id
|
||||
const data: any = await getCustomerDetailApi({
|
||||
user_id: id,
|
||||
})
|
||||
// 客户详情数据
|
||||
customerDetail.value = {
|
||||
// 账户名称
|
||||
accountName: data.user.username,
|
||||
// 账户id
|
||||
userId: data.user.id,
|
||||
// 账户角色
|
||||
userRole: roleMap[data.user.role_id],
|
||||
// 手机号
|
||||
phone: data.user.phone,
|
||||
// 邮箱
|
||||
email: data.user.email,
|
||||
// 存款金额
|
||||
depositAmount: data.user.total_recharge_amount,
|
||||
// 账户余额
|
||||
balance: data.user.total_recharge_amount,
|
||||
// 注册时间
|
||||
registerTime: data.user.created_at,
|
||||
// 历史交易金额
|
||||
historyTradeAmount: data.user.history_transfer_amount,
|
||||
}
|
||||
// 客户详情表格数据
|
||||
tableTree.value = data.accounts.map((item: any) => ({
|
||||
tradeAccount:item.wallets_trade.account_id,
|
||||
accountName:item.account_name,
|
||||
balance:item.wallets_trade.amount,
|
||||
leverage:item.wallets_trade.lever,
|
||||
historyTradeVolume: item.collect_data !== null ? item.collect_data.total_order: '',
|
||||
createTime:item.created_at,
|
||||
}))
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 页面加载完成需要加载的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getCustomerDetail()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @description: 定义返回上层方法
|
||||
*/
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.back {
|
||||
cursor: pointer;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.detail {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.el-card {
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px 10px;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.user-card {
|
||||
max-width: 300px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 74px;
|
||||
}
|
||||
|
||||
.user-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.information-card {
|
||||
width: calc(100% - 350px);
|
||||
|
||||
:deep(.el-card__body) {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.information-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
export const tableColumns = [
|
||||
//交易账号
|
||||
{label: '交易账号', prop: 'tradeAccount'},
|
||||
//账户名称
|
||||
{label: '账户名称', prop: 'accountName'},
|
||||
//余额
|
||||
{label: '余额', prop: 'balance', sortable: true},
|
||||
//交易杠杆
|
||||
{label: '交易杠杆', prop: 'leverage'},
|
||||
//历史交易量
|
||||
{label: '历史交易量', prop: 'historyTradeVolume'},
|
||||
//添加时间
|
||||
{label: '添加时间', prop: 'createTime'},
|
||||
]
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>存款</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>存款审核</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>取款</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>取款渠道</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>取款审核</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
|
||||
import { getStorage } from '@/utils/storage'
|
||||
import Agent from '@/views/agent/index.vue'
|
||||
import Agent from './components/view/index.vue'
|
||||
|
||||
//控制id切换页面渲染
|
||||
const userId = getStorage('userInfo')?.id
|
||||
|
|
@ -77,4 +77,4 @@ const cardData = [
|
|||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<template>
|
||||
<h1>资金流水</h1>
|
||||
</template>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<template>
|
||||
<h1>存款审核</h1>
|
||||
</template>
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
* @description: 搜索配置
|
||||
*/
|
||||
export const search = [
|
||||
//存款账户
|
||||
{
|
||||
label: '存款账户',
|
||||
prop: 'depositAccount',
|
||||
type: 'input',
|
||||
placeholder: '请输入存款账户'
|
||||
},
|
||||
//级别
|
||||
{
|
||||
label: '级别',
|
||||
prop: 'level',
|
||||
type: 'select',
|
||||
placeholder: '请选择级别',
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* @description: 表格配置
|
||||
*/
|
||||
export const tableColumns = [
|
||||
{label: '序号', prop: 'index'},
|
||||
{label: '账户', prop: 'depositAccount'},
|
||||
{label: '所属代理', prop: 'agentName'},
|
||||
{label: '流水编号', prop: 'serialNumber'},
|
||||
{label: '钱包地址', prop: 'walletAddress'},
|
||||
{label: '钱包类型', prop: 'walletType'},
|
||||
{label: '账户持有人姓名', prop: 'accountHolderName'},
|
||||
{label: '银行名称', prop: 'bankName'},
|
||||
{label: '银行识别代码', prop: 'bankCode'},
|
||||
]
|
||||
|
||||
/**
|
||||
* @description: dialog表格配置
|
||||
*/
|
||||
export const dialogTableColumns = {}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<template>
|
||||
<h1>存款明细</h1>
|
||||
</template>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<template>
|
||||
<div class="receiver-account">
|
||||
<div class="bar">
|
||||
<el-button type="primary" @click="handleAdd">添加</el-button>
|
||||
<el-button type="primary" @click="handleModify">编辑</el-button>
|
||||
<el-button type="primary" @click="handleEnable">启用</el-button>
|
||||
<el-button type="danger" @click="handleDisable">禁用</el-button>
|
||||
<el-button type="primary" @click="handleExport">导出</el-button>
|
||||
</div>
|
||||
<ReceiverAccountTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" ref="tableRef"></ReceiverAccountTable>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
//组件
|
||||
import ReceiverAccountTable from '@/components/common/Table.vue'
|
||||
import { tableColumns } from './options'
|
||||
|
||||
|
||||
//表格数据
|
||||
const tableRef = ref()
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
const tableTree = ref([])
|
||||
</script>
|
||||
<style scoped>
|
||||
.receiver-account {
|
||||
.bar {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
export const tableColumns = [
|
||||
//序号
|
||||
{ label: '序号', prop: 'index' },
|
||||
//账户持有人姓名
|
||||
{ label: '账户持有人姓名', prop: 'accountHolderName' },
|
||||
//银行名称
|
||||
{ label: '银行名称', prop: 'bankName' },
|
||||
//银行卡号
|
||||
{ label: '银行卡号', prop: 'bankAccount' },
|
||||
//银行识别代码
|
||||
{ label: '银行识别代码', prop: 'bankCode' },
|
||||
//银行地址
|
||||
{ label: '银行地址', prop: 'bankAddress' },
|
||||
//状态
|
||||
{ label: '状态', slotName: 'status' },
|
||||
|
||||
]
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<template>
|
||||
<h1>取款明细</h1>
|
||||
</template>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<template>
|
||||
<h1>取款审核</h1>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>手续费模板</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>跟单订单</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>充值订单</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>带单订单</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<h1>提现</h1>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<template>
|
||||
<div class="follow-record">
|
||||
<!-- 搜索 -->
|
||||
<FollowRecordSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleExport()">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</FollowRecordSearch>
|
||||
<!-- 表格 -->
|
||||
<FollowRecordTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
|
||||
<!-- 分页 -->
|
||||
<FollowRecordPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import FollowRecordSearch from '@/components/common/Search.vue'
|
||||
import FollowRecordTable from '@/components/common/Table.vue'
|
||||
import FollowRecordPagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
|
||||
// 接口
|
||||
import { getFollowListApi } from '@/api/modules/personalized/followRecord'
|
||||
|
||||
// 导出表格
|
||||
import { exportToExcel } from '@/utils/exportToExcel'
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchOptions = ref(search)
|
||||
const searchForm = ref({
|
||||
orderNo: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
const getFollowList = async () => {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-01 23:59:59',
|
||||
order_no: searchForm.value.orderNo,
|
||||
}
|
||||
const data: any = await getFollowListApi(params)
|
||||
// table数据映射
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
orderNo: item.order_id,
|
||||
followAccount: item.user.username,
|
||||
symbol: item.variety_id,
|
||||
tradeQty: item.num,
|
||||
tradeTime: item.created_at,
|
||||
closeProfit: '后续添加'
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getFollowList()
|
||||
})
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = async () => {
|
||||
console.log("搜索");
|
||||
getFollowList()
|
||||
}
|
||||
const handleReset = () => {
|
||||
console.log('重置搜索')
|
||||
searchForm.value = {
|
||||
orderNo: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
getFollowList()
|
||||
}
|
||||
const handleExport = () => {
|
||||
exportToExcel({
|
||||
tableData: tableTree.value,
|
||||
columns: tableColumnsOptions.value,
|
||||
title: '导出跟单记录',
|
||||
defaultFileNamePrefix: '跟单记录',
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: { currentPage: number, size: number }) => {
|
||||
currentPage.value = page.currentPage
|
||||
getFollowList()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
export const search = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号', type: 'input' as const, placeholder: '请输入订单号',width: '200px' },
|
||||
//开始时间
|
||||
{
|
||||
prop: 'startTime', label: '开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择开始时间', width: '150px'
|
||||
},
|
||||
//结束时间
|
||||
{
|
||||
prop: 'endTime', label: '结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择结束时间', width: '150px'
|
||||
},
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号' },
|
||||
// 跟单账户
|
||||
{ prop: 'followAccount', label: '跟单账户' },
|
||||
// 交易品种
|
||||
{ prop: 'symbol', label: '交易品种' },
|
||||
// 交易数量
|
||||
{ prop: 'tradeQty', label: '交易数量' },
|
||||
// 交易时间
|
||||
{ prop: 'tradeTime', label: '交易时间' },
|
||||
// 平仓盈亏
|
||||
{ prop: 'closeProfit', label: '平仓盈亏' },
|
||||
]
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<template>
|
||||
<div class="follow-record">
|
||||
<!-- 搜索 -->
|
||||
<LeadRecordSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleExport()">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</LeadRecordSearch>
|
||||
<!-- 表格 -->
|
||||
<LeadRecordTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
|
||||
<!-- 分页 -->
|
||||
<LeadRecordPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import LeadRecordSearch from '@/components/common/Search.vue'
|
||||
import LeadRecordTable from '@/components/common/Table.vue'
|
||||
import LeadRecordPagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
|
||||
// 接口
|
||||
import { getFollowListApi } from '@/api/modules/personalized/followRecord'
|
||||
|
||||
// 导出表格
|
||||
import { exportToExcel } from '@/utils/exportToExcel'
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchOptions = ref(search)
|
||||
const searchForm = ref({
|
||||
orderNo: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
const getLeadList = async () => {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-01 23:59:59',
|
||||
order_no: searchForm.value.orderNo,
|
||||
}
|
||||
const data: any = await getFollowListApi(params)
|
||||
// table数据映射
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
orderNo: item.order_id,
|
||||
followAccount: item.user.username,
|
||||
symbol: item.variety_id,
|
||||
tradeQty: item.num,
|
||||
tradeTime: item.created_at,
|
||||
closeProfit: '后续添加'
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getLeadList()
|
||||
})
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = async () => {
|
||||
console.log("搜索");
|
||||
getLeadList()
|
||||
}
|
||||
const handleReset = () => {
|
||||
console.log('重置搜索')
|
||||
searchForm.value = {
|
||||
orderNo: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
getLeadList()
|
||||
}
|
||||
const handleExport = () => {
|
||||
exportToExcel({
|
||||
tableData: tableTree.value,
|
||||
columns: tableColumnsOptions.value,
|
||||
title: '导出带单记录',
|
||||
defaultFileNamePrefix: '带单记录',
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: { currentPage: number, size: number }) => {
|
||||
currentPage.value = page.currentPage
|
||||
getLeadList()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
export const search = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号', type: 'input' as const, placeholder: '请输入订单号',width: '200px' },
|
||||
//开始时间
|
||||
{
|
||||
prop: 'startTime', label: '开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择开始时间', width: '150px'
|
||||
},
|
||||
//结束时间
|
||||
{
|
||||
prop: 'endTime', label: '结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择结束时间', width: '150px'
|
||||
},
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号' },
|
||||
// 跟单账户
|
||||
{ prop: 'followAccount', label: '跟单账户' },
|
||||
// 交易品种
|
||||
{ prop: 'symbol', label: '交易品种' },
|
||||
// 交易数量
|
||||
{ prop: 'tradeQty', label: '交易数量' },
|
||||
// 交易时间
|
||||
{ prop: 'tradeTime', label: '交易时间' },
|
||||
// 平仓盈亏
|
||||
{ prop: 'closeProfit', label: '平仓盈亏' },
|
||||
]
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 搜索 -->
|
||||
<CustomerListSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset"></CustomerListSearch>
|
||||
<!-- 表格 -->
|
||||
<CustomerListTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="userId"
|
||||
:tree-props="treeProps" :default-sort="{ prop: 'createTime', order: 'descending' }"
|
||||
@expand-change="handleGetSubList">
|
||||
<template #marginRatio="{ row }">
|
||||
<el-button v-if="row.role_id === 5" type="primary" size="small" @click="handleMarginRatio(row)">
|
||||
修改
|
||||
</el-button>
|
||||
</template>
|
||||
<template #commissionRatio="{ row }">
|
||||
{{ row.commissionRatio }}
|
||||
<el-button v-if="row.role_id === 5" type="primary" size="small" @click="handleCommissionRatio(row)">
|
||||
修改
|
||||
</el-button>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<el-button link type="primary" size="small" @click="handleDetail(row)" v-if="row.userId">
|
||||
查看详情
|
||||
</el-button>
|
||||
</template>
|
||||
</CustomerListTable>
|
||||
<!-- 分页 -->
|
||||
<CustomerListPagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
<!-- dialog -->
|
||||
<CustomerListDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType"
|
||||
:fullscreen="dialogFullscreen" :show-footer="dialogType !== 'view'" @confirm="handleSubmit"
|
||||
@cancel="handleCancel" @close="handleClose">
|
||||
<CustomerListTable :table-data="marginRatioTree" :columns="marginRatioTableColumnsOptions" row-key="id"
|
||||
v-if="dialogType === 'editMarginRatio'">
|
||||
<template #assignedPointDiff="{ row }">
|
||||
<el-form :model="row" :rules="marginRatioRules(row)" :ref="el => setFormRef(el, row.id)">
|
||||
<el-form-item prop="assignedPointDifference">
|
||||
<el-input v-model="row.assignedPointDifference" size="small" placeholder="请输入点差" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</CustomerListTable>
|
||||
<CustomerListForm :form-data="commissionRatioForm" :form-rules="commissionRatioFormRules"
|
||||
:form-items="commissionRatioFormItemOptions" ref="commissionRatioFormRef"
|
||||
v-if="dialogType === 'editCommissionRatio'"></CustomerListForm>
|
||||
</CustomerListDialog>
|
||||
<!-- dialog表格 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import CustomerListSearch from '@/components/common/Search.vue'
|
||||
import CustomerListTable from '@/components/common/Table.vue'
|
||||
import CustomerListPagination from '@/components/common/Pagination.vue'
|
||||
import CustomerListDialog from '@/components/common/Dialog.vue'
|
||||
import CustomerListForm from '@/components/common/Form.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns, marginRatioTableColumns, commissionRatioFormItem } from './options'
|
||||
|
||||
// 接口
|
||||
import { getCustomerListApi, getSelfVarietyPointDiffConfigApi, editCustomerApi } from '@/api/modules/agent/customerList'
|
||||
|
||||
// 公用方法
|
||||
import { getStorage } from '@/utils/storage'
|
||||
const router = useRouter()
|
||||
/**
|
||||
* @description: 获取用户id
|
||||
*/
|
||||
const userInfo: any = getStorage('userInfo')
|
||||
const userId = ref(userInfo?.id || '')
|
||||
|
||||
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchForm = ref({
|
||||
accountName: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
status: '',
|
||||
})
|
||||
const searchOptions = ref(search)
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const treeProps = { children: 'children', hasChildren: 'hasChildren' }
|
||||
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const total = ref(0)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
|
||||
/**
|
||||
* @description: 定义弹窗数据
|
||||
*/
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
const dialogTitle = ref<string>('')
|
||||
const dialogType = ref<string>('')
|
||||
const dialogFullscreen = ref(false)
|
||||
|
||||
/**
|
||||
* @description: 定义点差表格数据
|
||||
*/
|
||||
const marginRatioTree = ref([])
|
||||
const marginRatioTableColumnsOptions = ref(marginRatioTableColumns)
|
||||
// 存储所有行的表单
|
||||
const formRefs: any = ref({})
|
||||
|
||||
// 动态存储每行表单
|
||||
const setFormRef = (el: any, id: any) => {
|
||||
if (el) formRefs.value[id] = el
|
||||
}
|
||||
// 点差验证规则
|
||||
const marginRatioRules = (row: any) => {
|
||||
return {
|
||||
assignedPointDifference: [
|
||||
{ required: true, message: '请输入数字', trigger: ['blur', 'change'] },
|
||||
{ pattern: /^\d+(\.\d+)?$/, message: '只能输入数字(可带小数)', trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
const inputVal = Number(value || 0)
|
||||
const maxVal = Number(row.pointDifference || 0)
|
||||
|
||||
if (inputVal > maxVal) {
|
||||
callback(new Error('不能大于可分配点数'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description: 定义手续费form数据
|
||||
*/
|
||||
const commissionRatioForm = ref({
|
||||
commissionRatio: '',
|
||||
})
|
||||
const commissionRatioFormRef = ref()
|
||||
const commissionRatioFormRules = {
|
||||
commissionRatio: [
|
||||
{ required: true, message: '请输入手续费分成比例', trigger: ['blur', 'change'] },
|
||||
{ pattern: /^\d+(\.\d+)?$/, message: '只能输入数字(可带小数)', trigger: ['blur', 'change'] },
|
||||
]
|
||||
}
|
||||
const commissionRatioFormItemOptions = ref(commissionRatioFormItem)
|
||||
const selectId = ref('')
|
||||
|
||||
/**
|
||||
* @description: 角色映射方法
|
||||
*/
|
||||
const roleMap: any = {
|
||||
1: '平台',
|
||||
2: '承包商',
|
||||
3: '特殊做市商',
|
||||
4: '普通做市商',
|
||||
5: '代理',
|
||||
6: '用户'
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
// 获取客户列表
|
||||
const getCustomerList = async (id: string) => {
|
||||
const params = {
|
||||
user_id: id,
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
user_name: searchForm.value.accountName,
|
||||
reg_start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
reg_end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-01 23:59:59',
|
||||
status: searchForm.value.status,
|
||||
}
|
||||
const data: any = await getCustomerListApi(params)
|
||||
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
accountName: item.username,
|
||||
userId: item.id,
|
||||
status: item.status === 1 ? '正常' : '禁用',
|
||||
role: roleMap[item.role_id] || '未知',
|
||||
accountQty: item.account[0].account_count,
|
||||
commissionRatio: item.wallet_capital.fee_handling_percent,
|
||||
createTime: item.created_at,
|
||||
role_id: item.role_id,
|
||||
children: item.role_id === 5 ? [{
|
||||
hasChildren: true,
|
||||
}] : undefined,
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
|
||||
//获取代理点差数据
|
||||
const getSelfVarietyPointDiffConfig = async (id: string) => {
|
||||
const params = {
|
||||
user_id: id,
|
||||
}
|
||||
const data: any = await getSelfVarietyPointDiffConfigApi(params)
|
||||
marginRatioTree.value = data.data.map((item: any) => ({
|
||||
id: item.id,
|
||||
varietyName: item.name,
|
||||
varietyCode: item.code,
|
||||
pointDifference: item.point_diff,
|
||||
assignedPointDifference: item.target_point_diff
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getCustomerList(userId.value)
|
||||
})
|
||||
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = async () => {
|
||||
getCustomerList(userId.value)
|
||||
}
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
accountName: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
status: '',
|
||||
}
|
||||
getCustomerList(userId.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 定义表格方法
|
||||
*/
|
||||
const handleDetail = (row: any) => {
|
||||
console.log('查看详情', row);
|
||||
router.push(`/agent/customerDetail/${row.userId}`)
|
||||
}
|
||||
|
||||
// 修改点差
|
||||
const handleMarginRatio = (row: any) => {
|
||||
getSelfVarietyPointDiffConfig(row.userId)
|
||||
console.log('修改点差', row);
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '修改点差'
|
||||
dialogType.value = 'editMarginRatio'
|
||||
selectId.value = row.userId
|
||||
}
|
||||
|
||||
// 修改手续费比例
|
||||
const handleCommissionRatio = (row: any) => {
|
||||
console.log('修改手续费比例', row);
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '修改手续费'
|
||||
dialogType.value = 'editCommissionRatio'
|
||||
selectId.value = row.userId
|
||||
}
|
||||
|
||||
// 获取子列表
|
||||
const handleGetSubList = async (row: any) => {
|
||||
const params = {
|
||||
user_name: '',
|
||||
user_id: row.userId,
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
reg_start_time: '',
|
||||
reg_end_time: '',
|
||||
status: '',
|
||||
}
|
||||
const data: any = await getCustomerListApi(params)
|
||||
if (data.data.length === 0) {
|
||||
ElMessage({
|
||||
message: '暂无数据',
|
||||
type: 'error',
|
||||
})
|
||||
row.children = []
|
||||
return
|
||||
}
|
||||
row.children = data.data.map((item: any) => ({
|
||||
accountName: item.username,
|
||||
userId: item.id,
|
||||
status: item.status === 1 ? '正常' : '禁用',
|
||||
role: roleMap[item.role_id] || '未知',
|
||||
accountQty: item.account[0].account_count,
|
||||
commissionRatio: item.wallet_capital.fee_handling_percent,
|
||||
createTime: item.created_at,
|
||||
role_id: item.role_id,
|
||||
children: item.role_id === 5 ? [{
|
||||
hasChildren: true,
|
||||
}] : undefined,
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: { currentPage: number, size: number }) => {
|
||||
currentPage.value = page.currentPage
|
||||
getCustomerList(userId.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 定义弹窗方法
|
||||
*/
|
||||
//提交
|
||||
const handleSubmit = async () => {
|
||||
const params = {
|
||||
user_id: selectId.value,
|
||||
toucun_percent: '',
|
||||
point_diffs_json: '',
|
||||
fee_handling_percent: '',
|
||||
fee_setting_id: '',
|
||||
risk_control_id: '',
|
||||
}
|
||||
if (dialogType.value === 'editMarginRatio') {
|
||||
// 逐行验证
|
||||
for (const row of marginRatioTree.value) {
|
||||
const form = formRefs.value[(row as any).id]
|
||||
if (!form) continue
|
||||
try {
|
||||
await form.validate()
|
||||
} catch (err) {
|
||||
console.error(`第 ${(row as any).id} 行验证不通过,请检查`)
|
||||
return
|
||||
}
|
||||
}
|
||||
//转换为接口需要的格式 { id: assignedPointDifference }
|
||||
const marginRatioJSON = marginRatioTree.value.reduce((acc: any, cur: any) => {
|
||||
acc[cur.id] = cur.assignedPointDifference
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
// 调用接口
|
||||
try {
|
||||
await editCustomerApi({ ...params, point_diffs_json: JSON.stringify(marginRatioJSON) })
|
||||
dialogVisible.value = false
|
||||
} catch (err) {
|
||||
console.log('提交失败:', err)
|
||||
}
|
||||
}
|
||||
if (dialogType.value === 'editCommissionRatio') {
|
||||
await commissionRatioFormRef.value.validate()
|
||||
try {
|
||||
await editCustomerApi({ ...params, fee_handling_percent: commissionRatioForm.value.commissionRatio })
|
||||
dialogVisible.value = false
|
||||
} catch (err) {
|
||||
console.log('提交失败:', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
/**
|
||||
* @description: 定义弹窗表格方法
|
||||
*/
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.placeholder-row) {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
/* 灰色,和Element空状态颜色一致 */
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
export const search = [
|
||||
// 账号名称
|
||||
{ prop: 'accountName', label: '账号名称', type: 'input' as const, placeholder: '请输入账号名称', width: '150px' },
|
||||
// 开始时间
|
||||
{
|
||||
prop: "startTime", label: '注册开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
},
|
||||
// 结束时间
|
||||
{
|
||||
prop: "endTime", label: '注册结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
},
|
||||
// 状态
|
||||
{ prop: 'status', label: '状态', type: 'select' as const, placeholder: '请选择状态' },
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 账号名称
|
||||
{ label: '账号名称', prop: 'accountName'},
|
||||
// 账号id
|
||||
{ prop: 'userId', label: '账号id' },
|
||||
// 状态
|
||||
{ prop: 'status', label: '状态' },
|
||||
// 账号角色
|
||||
{ prop: 'role', label: '账号角色' },
|
||||
// 账号数量
|
||||
{ prop: 'accountQty', label: '账号数量' },
|
||||
// 点差分配比例
|
||||
{ prop: 'marginRatio', label: '点差分配比例', slotName: 'marginRatio' },
|
||||
// 手续费分成比例
|
||||
{ prop: 'commissionRatio', label: '手续费分成比例', slotName: 'commissionRatio' },
|
||||
// 注册时间
|
||||
{ prop: 'createTime', label: '注册时间', sortable: true },
|
||||
// 操作
|
||||
{ label: '操作', slotName: 'action' }
|
||||
]
|
||||
|
||||
// 点差表格配置
|
||||
export const marginRatioTableColumns = [
|
||||
// 品种名称
|
||||
{ prop: 'varietyName', label: '名称', align: 'center' as const },
|
||||
// 品种编号
|
||||
{ prop: 'varietyCode', label: '编号', align: 'center' as const },
|
||||
// 可分配点差
|
||||
{ prop: 'pointDifference', label: '可分配点差', align: 'center' as const },
|
||||
// 已分配点差
|
||||
{ prop: 'assignedPointDifference', label: '已分配点差', align: 'center' as const, slotName: 'assignedPointDiff' },
|
||||
]
|
||||
|
||||
// 手续费分成比例form配置
|
||||
export const commissionRatioFormItem = [
|
||||
// 手续费分成比例
|
||||
{ prop: 'commissionRatio', label: '手续费分成比例', type: 'input' as const, placeholder: '请输入手续费分成比例',labelWidth: '140px'},
|
||||
]
|
||||
|
|
@ -1,58 +1,80 @@
|
|||
<template>
|
||||
<div class="system">
|
||||
<!-- 角色列表头 -->
|
||||
<div class="header">
|
||||
<h4>角色列表</h4>
|
||||
<el-button type="primary" @click="handleAddRole">新增角色</el-button>
|
||||
</div>
|
||||
<!-- 角色列表表格 -->
|
||||
<RoleTable :table-data="roleTree" :columns="roleTableColumns" row-key="id">
|
||||
<template #status="{ row }">
|
||||
<el-switch :model-value="row.status === 1" :active-value="true" :inactive-value="false" active-text="启用"
|
||||
inactive-text="禁用"/>
|
||||
</template>
|
||||
<template #createTime="{ row }">
|
||||
{{ row.created_at }}
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<el-button link type="primary" size="small" @click="handleEditRole(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button link type="primary" size="small" @click="handlePermission(row)">
|
||||
设置权限
|
||||
</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleDeleteRole(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</RoleTable>
|
||||
<div class="system">
|
||||
<!-- 角色列表头 -->
|
||||
<div class="header">
|
||||
<h4>角色列表</h4>
|
||||
<el-button type="primary" @click="handleAddRole">新增角色</el-button>
|
||||
</div>
|
||||
<!-- 角色新增/编辑弹窗 -->
|
||||
<RoleDialog :visible="dialogVisible" :title="dialogTitle" :type="dialogType" @confirm="handleSubmit"
|
||||
@cancel="handleCancel" @close="handleClose" :fullscreen="fullScreen">
|
||||
<RoleForm :form-data="roleForm" :form-rules="roleFormRules" :form-items="roleFormItemOptions" ref="roleFormRef"
|
||||
:options-map="roleFormOptionsMap" :dialog-type="dialogType">
|
||||
<template #permissions="{ formData }">
|
||||
<div class="permission-group">
|
||||
<div v-for="(group, module) in groupedPermissions" :key="module" class="permission-module">
|
||||
<!-- 点击事件的 checked 参数 -->
|
||||
<el-checkbox :model-value="getModuleCheckedState(module)"
|
||||
:indeterminate="getModuleIndeterminateState(module)"
|
||||
@change="(checked: boolean | string | number) => handleModuleCheckChange(module, !!checked)"
|
||||
class="module-title">
|
||||
{{ module }}
|
||||
</el-checkbox>
|
||||
<!-- 添加子权限 change 事件监听 -->
|
||||
<el-checkbox-group v-model="formData.permissions" @change="handlePermissionChange">
|
||||
<el-checkbox v-for="perm in group" :key="perm.id" :value="perm.id">
|
||||
{{ perm.title }} ({{ perm.name }})
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</RoleForm>
|
||||
</RoleDialog>
|
||||
<!-- 角色列表表格 -->
|
||||
<RoleTable :table-data="roleTree" :columns="roleTableColumns" row-key="id">
|
||||
<template #status="{ row }">
|
||||
<el-switch
|
||||
:model-value="row.status === 1"
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
active-text="启用"
|
||||
inactive-text="禁用"
|
||||
/>
|
||||
</template>
|
||||
<template #createTime="{ row }">
|
||||
{{ row.created_at }}
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<el-button link type="primary" size="small" @click="handleEditRole(row)"> 编辑 </el-button>
|
||||
<el-button link type="primary" size="small" @click="handlePermission(row)">
|
||||
设置权限
|
||||
</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleDeleteRole(row)"> 删除 </el-button>
|
||||
</template>
|
||||
</RoleTable>
|
||||
</div>
|
||||
<!-- 角色新增/编辑弹窗 -->
|
||||
<RoleDialog
|
||||
:visible="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
:type="dialogType"
|
||||
@confirm="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
@close="handleClose"
|
||||
:fullscreen="fullScreen"
|
||||
>
|
||||
<RoleForm
|
||||
:form-data="roleForm"
|
||||
:form-rules="roleFormRules"
|
||||
:form-items="roleFormItemOptions"
|
||||
ref="roleFormRef"
|
||||
:options-map="roleFormOptionsMap"
|
||||
:dialog-type="dialogType"
|
||||
>
|
||||
<template #permissions="{ formData }">
|
||||
<div class="permission-group">
|
||||
<div
|
||||
v-for="(group, module) in groupedPermissions"
|
||||
:key="module"
|
||||
class="permission-module"
|
||||
>
|
||||
<!-- 点击事件的 checked 参数 -->
|
||||
<el-checkbox
|
||||
:model-value="getModuleCheckedState(module)"
|
||||
:indeterminate="getModuleIndeterminateState(module)"
|
||||
@change="
|
||||
(checked: boolean | string | number) => handleModuleCheckChange(module, !!checked)
|
||||
"
|
||||
class="module-title"
|
||||
>
|
||||
{{ module }}
|
||||
</el-checkbox>
|
||||
<!-- 添加子权限 change 事件监听 -->
|
||||
<el-checkbox-group v-model="formData.permissions" @change="handlePermissionChange">
|
||||
<el-checkbox v-for="perm in group" :key="perm.id" :value="perm.id">
|
||||
{{ perm.title }} ({{ perm.name }})
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</RoleForm>
|
||||
</RoleDialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
@ -67,12 +89,19 @@ import RoleForm from '@/components/common/Form.vue'
|
|||
import { roleTableColumns, roleFormItem, permissionsFormItem } from './options'
|
||||
import { rules } from './rules'
|
||||
|
||||
import { getRoleApi, createRoleApi, editRoleApi, deleteRoleApi, getRolePermissionApi, setRolePermissionApi } from '@/api/modules/system/role'
|
||||
import {
|
||||
getRoleApi,
|
||||
createRoleApi,
|
||||
editRoleApi,
|
||||
deleteRoleApi,
|
||||
getRolePermissionApi,
|
||||
setRolePermissionApi,
|
||||
} from '@/api/modules/system/role'
|
||||
|
||||
// 定义header配置
|
||||
const roleTitle = ref('角色管理')
|
||||
const roleHeaderButtons = [
|
||||
{ label: '新增角色', type: 'primary' as const, icon: Plus, key: 'addRole' },
|
||||
{ label: '新增角色', type: 'primary' as const, icon: Plus, key: 'addRole' },
|
||||
]
|
||||
|
||||
// 定义表格配置
|
||||
|
|
@ -86,9 +115,9 @@ const fullScreen = ref(false)
|
|||
|
||||
// 定义角色表单数据
|
||||
const roleForm = ref({
|
||||
name: '', // 角色名称
|
||||
title: '', // 角色标题
|
||||
permissions: [] as number[], // 角色权限
|
||||
name: '', // 角色名称
|
||||
title: '', // 角色标题
|
||||
permissions: [] as number[], // 角色权限
|
||||
})
|
||||
const roleFormRef = ref<FormInstance>()
|
||||
// 表单验证规则
|
||||
|
|
@ -97,7 +126,7 @@ const roleFormRules = rules()
|
|||
const roleFormItemOptions = ref(roleFormItem)
|
||||
// 角色表单选项映射
|
||||
const roleFormOptionsMap = ref({
|
||||
'permissions': [] as any[],
|
||||
permissions: [] as any[],
|
||||
})
|
||||
|
||||
//保存权限id
|
||||
|
|
@ -107,232 +136,258 @@ const groupedPermissions = ref<Record<string, any[]>>({})
|
|||
// 原始权限列表
|
||||
const allPermissions = ref<any[]>([])
|
||||
|
||||
/**
|
||||
/**
|
||||
@description: 新增角色
|
||||
**/
|
||||
const handleAddRole = () => {
|
||||
console.log('新增角色', dialogType.value)
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '新增角色'
|
||||
handleDialogType(dialogType.value)
|
||||
console.log('新增角色', dialogType.value)
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '新增角色'
|
||||
handleDialogType(dialogType.value)
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
@description: 角色数据处理
|
||||
**/
|
||||
// 处理角色状态,只保留 status=1 的角色
|
||||
const filterRoles = (roleList: any[]) => {
|
||||
const enabledRoles = roleList.filter(role => role.status === 1)
|
||||
return enabledRoles
|
||||
const enabledRoles = roleList.filter((role) => role.status === 1)
|
||||
return enabledRoles
|
||||
}
|
||||
|
||||
// 获取角色列表
|
||||
const fetchRoleList = async () => {
|
||||
try {
|
||||
const data = await getRoleApi()
|
||||
roleTree.value = data
|
||||
} catch (err) {
|
||||
console.error('获取角色列表失败', err)
|
||||
}
|
||||
try {
|
||||
const data = await getRoleApi()
|
||||
roleTree.value = data
|
||||
} catch (err) {
|
||||
console.error('获取角色列表失败', err)
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时获取菜单列表
|
||||
onMounted(async () => {
|
||||
await fetchRoleList()
|
||||
await fetchRoleList()
|
||||
})
|
||||
|
||||
/**
|
||||
/**
|
||||
@description: 处理菜单编辑/删除/状态切换
|
||||
**/
|
||||
// 角色编辑
|
||||
const handleEditRole = (row: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '编辑角色'
|
||||
dialogType.value = 'edit'
|
||||
handleDialogType(dialogType.value)
|
||||
roleForm.value = {
|
||||
...row,
|
||||
id: row.id, // 角色id
|
||||
}
|
||||
console.log('编辑角色', dialogType.value)
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '编辑角色'
|
||||
dialogType.value = 'edit'
|
||||
handleDialogType(dialogType.value)
|
||||
roleForm.value = {
|
||||
...row,
|
||||
id: row.id, // 角色id
|
||||
}
|
||||
console.log('编辑角色', dialogType.value)
|
||||
}
|
||||
// 角色删除
|
||||
const handleDeleteRole = async (row: any) => {
|
||||
try {
|
||||
await deleteRoleApi({ id: row.id })
|
||||
await fetchRoleList()
|
||||
} catch (err) {
|
||||
console.error('删除角色失败')
|
||||
}
|
||||
try {
|
||||
await deleteRoleApi({ id: row.id })
|
||||
await fetchRoleList()
|
||||
} catch (err) {
|
||||
console.error('删除角色失败')
|
||||
}
|
||||
}
|
||||
|
||||
//区分新增和编辑角色表单选项
|
||||
const handleDialogType = (type: string) => {
|
||||
if (type === 'permissions') {
|
||||
roleFormItemOptions.value = permissionsFormItem as any;
|
||||
fullScreen.value = true
|
||||
console.log('权限弹窗', fullScreen.value)
|
||||
} else {
|
||||
roleFormItemOptions.value = roleFormItem as any;
|
||||
fullScreen.value = false
|
||||
}
|
||||
if (type === 'permissions') {
|
||||
roleFormItemOptions.value = permissionsFormItem as any
|
||||
fullScreen.value = true
|
||||
console.log('权限弹窗', fullScreen.value)
|
||||
} else {
|
||||
roleFormItemOptions.value = roleFormItem as any
|
||||
fullScreen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取模块全选状态(实时计算)
|
||||
const getModuleCheckedState = (module: string) => {
|
||||
const group = groupedPermissions.value[module]
|
||||
if (!group) return false
|
||||
const groupIds = group.map(perm => perm.id)
|
||||
return groupIds.every(id => roleForm.value.permissions.includes(id))
|
||||
const group = groupedPermissions.value[module]
|
||||
if (!group) return false
|
||||
const groupIds = group.map((perm) => perm.id)
|
||||
return groupIds.every((id) => roleForm.value.permissions.includes(id))
|
||||
}
|
||||
|
||||
// 获取模块半选状态(实时计算)
|
||||
const getModuleIndeterminateState = (module: string) => {
|
||||
const group = groupedPermissions.value[module]
|
||||
if (!group) return false
|
||||
const groupIds = group.map(perm => perm.id)
|
||||
const selectedCount = groupIds.filter(id => roleForm.value.permissions.includes(id)).length
|
||||
return selectedCount > 0 && selectedCount < group.length
|
||||
const group = groupedPermissions.value[module]
|
||||
if (!group) return false
|
||||
const groupIds = group.map((perm) => perm.id)
|
||||
const selectedCount = groupIds.filter((id) => roleForm.value.permissions.includes(id)).length
|
||||
return selectedCount > 0 && selectedCount < group.length
|
||||
}
|
||||
|
||||
// 处理模块复选框点击(全选/取消全选)
|
||||
const handleModuleCheckChange = (module: string, checked: boolean) => {
|
||||
const group = groupedPermissions.value[module]
|
||||
if (!group) return
|
||||
const groupIds = group.map(perm => perm.id)
|
||||
const group = groupedPermissions.value[module]
|
||||
if (!group) return
|
||||
const groupIds = group.map((perm) => perm.id)
|
||||
|
||||
if (checked) {
|
||||
roleForm.value.permissions = [...new Set([...roleForm.value.permissions, ...groupIds])]
|
||||
} else {
|
||||
roleForm.value.permissions = roleForm.value.permissions.filter(id => !groupIds.includes(id))
|
||||
}
|
||||
if (checked) {
|
||||
roleForm.value.permissions = [...new Set([...roleForm.value.permissions, ...groupIds])]
|
||||
} else {
|
||||
roleForm.value.permissions = roleForm.value.permissions.filter((id) => !groupIds.includes(id))
|
||||
}
|
||||
}
|
||||
|
||||
// 子权限变化时强制更新视图
|
||||
const handlePermissionChange = () => {
|
||||
roleForm.value = { ...roleForm.value }
|
||||
roleForm.value = { ...roleForm.value }
|
||||
}
|
||||
|
||||
// 按 module 分组权限
|
||||
const groupPermissionsByModule = (permissions: any[]) => {
|
||||
const grouped: Record<string, any[]> = {}
|
||||
permissions.forEach(perm => {
|
||||
grouped[perm.module] = grouped[perm.module] || []
|
||||
grouped[perm.module]!.push(perm)
|
||||
})
|
||||
Object.values(grouped).forEach(group => group.sort((a, b) => a.id - b.id))
|
||||
return grouped
|
||||
const grouped: Record<string, any[]> = {}
|
||||
permissions.forEach((perm) => {
|
||||
grouped[perm.module] = grouped[perm.module] || []
|
||||
const item = {
|
||||
...perm,
|
||||
pId: permissions.find((p) => p.title === perm.module).id,
|
||||
}
|
||||
grouped[perm.module]!.push(item)
|
||||
})
|
||||
for (const key in grouped) {
|
||||
console.log(key, grouped[key])
|
||||
grouped[key] = grouped[key].filter((item) => item.pId !== item.id)
|
||||
}
|
||||
Object.values(grouped).forEach((group) => group.sort((a, b) => a.id - b.id))
|
||||
return grouped
|
||||
}
|
||||
|
||||
// 角色权限获取和设置
|
||||
const handlePermission = async (row: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '设置角色权限'
|
||||
dialogType.value = 'permissions'
|
||||
handleDialogType(dialogType.value)
|
||||
permissionIds.value = row.id
|
||||
try {
|
||||
const data = await getRolePermissionApi({ id: row.id })
|
||||
allPermissions.value = data.all_permission_info
|
||||
groupedPermissions.value = groupPermissionsByModule(data.all_permission_info)
|
||||
roleForm.value.permissions = data.permission_ids || []
|
||||
console.log('分组后的权限', groupedPermissions.value)
|
||||
} catch (err) {
|
||||
console.error('获取角色权限失败', err)
|
||||
}
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '设置角色权限'
|
||||
dialogType.value = 'permissions'
|
||||
handleDialogType(dialogType.value)
|
||||
permissionIds.value = row.id
|
||||
try {
|
||||
const data = await getRolePermissionApi({ id: row.id })
|
||||
allPermissions.value = data.all_permission_info.map((item) => ({
|
||||
...item,
|
||||
pId: data.all_permission_info.find((p) => p.title === item.module)?.id,
|
||||
}))
|
||||
groupedPermissions.value = groupPermissionsByModule(data.all_permission_info)
|
||||
roleForm.value.permissions = data.permission_ids || []
|
||||
console.log('分组后的权限', groupedPermissions.value)
|
||||
} catch (err) {
|
||||
console.error('获取角色权限失败', err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
@description: 处理弹窗提交/取消/关闭事件
|
||||
**/
|
||||
const handleSubmit = async () => {
|
||||
console.log('提交菜单表单', roleForm.value.permissions) // 新增:打印选中的权限ID,便于调试
|
||||
try {
|
||||
await roleFormRef.value?.validate()
|
||||
if (dialogType.value === 'add') {
|
||||
const params = {
|
||||
name: roleForm.value.name,
|
||||
title: roleForm.value.title,
|
||||
}
|
||||
await createRoleApi(params)
|
||||
await fetchRoleList()
|
||||
} else if (dialogType.value === 'edit') {
|
||||
await editRoleApi(roleForm.value)
|
||||
await fetchRoleList()
|
||||
} else {
|
||||
await setRolePermissionApi({
|
||||
id: permissionIds.value,
|
||||
permission_ids: roleForm.value.permissions.join(',')
|
||||
})
|
||||
await fetchRoleList()
|
||||
console.log(
|
||||
'提交菜单表单',
|
||||
roleForm.value.permissions,
|
||||
groupedPermissions.value,
|
||||
allPermissions.value,
|
||||
) // 新增:打印选中的权限ID,便于调试
|
||||
try {
|
||||
await roleFormRef.value?.validate()
|
||||
if (dialogType.value === 'add') {
|
||||
const params = {
|
||||
name: roleForm.value.name,
|
||||
title: roleForm.value.title,
|
||||
}
|
||||
await createRoleApi(params)
|
||||
await fetchRoleList()
|
||||
} else if (dialogType.value === 'edit') {
|
||||
await editRoleApi(roleForm.value)
|
||||
await fetchRoleList()
|
||||
} else {
|
||||
let permissionIdList: any[] = [...roleForm.value.permissions]
|
||||
for (let i = 0; i < allPermissions.value.length; i++) {
|
||||
const flag = permissionIdList.includes(allPermissions.value[i]!.id)
|
||||
if (flag) {
|
||||
if (!permissionIdList.includes(allPermissions.value[i]!.pId))
|
||||
permissionIdList.push(allPermissions.value[i]!.pId)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
} catch (err) {
|
||||
console.log('表单验证失败')
|
||||
return
|
||||
}
|
||||
console.log('设置角色权限', permissionIdList.join(','))
|
||||
|
||||
await setRolePermissionApi({
|
||||
id: permissionIds.value,
|
||||
permission_ids: permissionIdList.join(','),
|
||||
})
|
||||
await fetchRoleList()
|
||||
}
|
||||
dialogVisible.value = false
|
||||
} catch (err) {
|
||||
console.log('表单验证失败')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 角色弹窗取消
|
||||
const handleCancel = () => {
|
||||
dialogVisible.value = false
|
||||
dialogType.value = 'add'
|
||||
roleForm.value = {
|
||||
name: '',
|
||||
title: '',
|
||||
permissions: [] as number[],
|
||||
}
|
||||
dialogVisible.value = false
|
||||
dialogType.value = 'add'
|
||||
roleForm.value = {
|
||||
name: '',
|
||||
title: '',
|
||||
permissions: [] as number[],
|
||||
}
|
||||
}
|
||||
|
||||
// 角色弹窗关闭
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false
|
||||
dialogType.value = 'add'
|
||||
roleForm.value = {
|
||||
name: '',
|
||||
title: '',
|
||||
permissions: [] as number[],
|
||||
}
|
||||
dialogVisible.value = false
|
||||
dialogType.value = 'add'
|
||||
roleForm.value = {
|
||||
name: '',
|
||||
title: '',
|
||||
permissions: [] as number[],
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.permission-group{
|
||||
width: 100%;
|
||||
.permission-group {
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.permission-module {
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 6px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 6px;
|
||||
padding: 15px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.module-title {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 8px;
|
||||
display: flex; // 修复:从 flex 改为 block,让复选框标题排版更合理
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 8px;
|
||||
display: flex; // 修复:从 flex 改为 block,让复选框标题排版更合理
|
||||
}
|
||||
|
||||
.permission-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.el-checkbox-group {
|
||||
label {
|
||||
margin-right: 15px;
|
||||
}
|
||||
label {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
<template>
|
||||
<div class="history-trade">
|
||||
<HistoryTradeSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
||||
@reset="handleReset">
|
||||
|
||||
<template #button="{ form }">
|
||||
<el-button type="primary" @click="handleExport()">
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</HistoryTradeSearch>
|
||||
<!-- 表格 -->
|
||||
<HistoryTradeTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id" />
|
||||
<!-- 分页 -->
|
||||
<HistoryTradePagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
||||
@pagination-change="handlePaginationChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 组件
|
||||
import HistoryTradeSearch from '@/components/common/Search.vue'
|
||||
import HistoryTradeTable from '@/components/common/Table.vue'
|
||||
import HistoryTradePagination from '@/components/common/Pagination.vue'
|
||||
// 配置以及表单验证
|
||||
import { search, tableColumns } from './options'
|
||||
// 接口
|
||||
import { getHistoryTradeListApi } from '@/api/modules/trade/historyTrade'
|
||||
|
||||
// 调用接口
|
||||
// 导出表格
|
||||
import { exportToExcel } from '@/utils/exportToExcel'
|
||||
/**
|
||||
* @description: 定义搜索数据
|
||||
*/
|
||||
const searchOptions = ref(search)
|
||||
const searchForm = ref({
|
||||
username: '',
|
||||
orderNo: '',
|
||||
subAccountId: '',
|
||||
tradeType: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
})
|
||||
/**
|
||||
* @description: 定义表格数据
|
||||
*/
|
||||
const tableTree = ref([])
|
||||
const tableColumnsOptions = ref(tableColumns)
|
||||
/**
|
||||
* @description: 定义分页数据
|
||||
*/
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
/**
|
||||
* @description: 定义公共请求数据方法
|
||||
*/
|
||||
const getHistoryTradeList = async () => {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
page_size: pageSize.value,
|
||||
user_name: searchForm.value.username,
|
||||
account_id: searchForm.value.subAccountId,
|
||||
order_no: searchForm.value.orderNo,
|
||||
type: searchForm.value.tradeType,
|
||||
start_time: searchForm.value.startTime.length > 0 ? `${searchForm.value.startTime} 0:00:00` : '2026-01-01 0:00:00',
|
||||
end_time: searchForm.value.endTime.length > 0 ? `${searchForm.value.endTime} 23:59:59` : '2026-03-01 23:59:59',
|
||||
}
|
||||
const data: any = await getHistoryTradeListApi(params)
|
||||
tableTree.value = data.data.map((item: any) => ({
|
||||
orderNo: item.order_id,
|
||||
tradeType: item.type === '1' ? '买入' : '卖出',
|
||||
amount: item.amount,
|
||||
tradeQty: item.num,
|
||||
tradeTime: item.created_at,
|
||||
floatProfit: '后续添加'
|
||||
}))
|
||||
|
||||
//分页数据
|
||||
total.value = data.total
|
||||
currentPage.value = data.current_page
|
||||
pageSize.value = Number(data.per_page)
|
||||
}
|
||||
/**
|
||||
* @description: 页面加载完成需要请求的数据
|
||||
*/
|
||||
onMounted(() => {
|
||||
getHistoryTradeList()
|
||||
})
|
||||
|
||||
/**
|
||||
* @description: 定义搜索方法
|
||||
*/
|
||||
const handleSearch = () => {
|
||||
getHistoryTradeList()
|
||||
}
|
||||
/**
|
||||
* @description: 定义重置方法
|
||||
*/
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
username: '',
|
||||
orderNo: '',
|
||||
subAccountId: '',
|
||||
tradeType: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
getHistoryTradeList()
|
||||
}
|
||||
/**
|
||||
* @description: 定义导出方法
|
||||
*/
|
||||
const handleExport = () => {
|
||||
exportToExcel({
|
||||
tableData: tableTree.value,
|
||||
columns: tableColumnsOptions.value,
|
||||
title: '导出交易记录',
|
||||
defaultFileNamePrefix: '交易记录',
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description: 定义分页方法
|
||||
*/
|
||||
const handlePaginationChange = (page: any) => {
|
||||
currentPage.value = page.currentPage
|
||||
getHistoryTradeList()
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
export const search = [
|
||||
// 用户名
|
||||
{ prop: 'username', label: '用户名', type: 'input' as const, placeholder: '请输入用户名',width: '150px' },
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号', type: 'input' as const, placeholder: '请输入订单号',width: '150px' },
|
||||
// 交易账户ID
|
||||
{ prop: 'subAccountId', label: '交易账户ID', type: 'input' as const, placeholder: '请输入交易账户ID',width: '150px' },
|
||||
// 交易类型
|
||||
{ prop: 'tradeType', label: '交易类型', type: 'select' as const, placeholder: '请选择交易类型',width: '140px', options: [
|
||||
{ label: '买入', value: '1' },
|
||||
{ label: '卖出', value: '2' },
|
||||
] },
|
||||
//开始时间
|
||||
{
|
||||
prop: 'startTime', label: '开始时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择开始时间', width: '150px'
|
||||
},
|
||||
//结束时间
|
||||
{
|
||||
prop: 'endTime', label: '结束时间', type: 'date' as const, dateType: 'date' as const, // 时间范围选择器
|
||||
valueFormat: 'YYYY-MM-DD', placeholder: '请选择结束时间', width: '150px'
|
||||
},
|
||||
]
|
||||
|
||||
export const tableColumns = [
|
||||
// 订单号
|
||||
{ prop: 'orderNo', label: '订单号' },
|
||||
// 操作类型
|
||||
{ prop: 'tradeType', label: '操作类型' },
|
||||
// 金额
|
||||
{ prop: 'amount', label: '金额' },
|
||||
// 交易数量
|
||||
{ prop: 'tradeQty', label: '交易数量' },
|
||||
// 交易时间
|
||||
{ prop: 'tradeTime', label: '交易时间' },
|
||||
// 浮动盈亏
|
||||
{ prop: 'floatProfit', label: '浮动盈亏' },
|
||||
]
|
||||
|
|
@ -20,10 +20,12 @@
|
|||
<tbody>
|
||||
<tr v-for="(item, index) in dataList" :key="`${item.id}-${index}`">
|
||||
<td>
|
||||
<el-input v-model="item.name" style="width: 80px" />
|
||||
<el-input v-if="item.editStatus" v-model="item.name" style="width: 80px" />
|
||||
<span v-else>{{ item.name }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<el-date-picker
|
||||
v-if="item.editStatus"
|
||||
v-model="item.datePicker"
|
||||
type="datetimerange"
|
||||
start-placeholder="休市开始时间"
|
||||
|
|
@ -33,6 +35,7 @@
|
|||
time-format="YYYY-MM-DD HH:mm:ss"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
<span v-else>{{ item.datePicker[0] }} - {{ item.datePicker[1] }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<el-select
|
||||
|
|
@ -40,6 +43,7 @@
|
|||
placeholder="请选择休市市场"
|
||||
style="width: 240px"
|
||||
v-model="item.groupId"
|
||||
v-if="item.editStatus"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in marketList"
|
||||
|
|
@ -48,13 +52,30 @@
|
|||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<span>{{
|
||||
(item?.groupId || []).map(
|
||||
(item: any) =>
|
||||
(marketList || []).find((item2: any) => item2.value === item)?.label || '',
|
||||
).join(',')
|
||||
}}</span>
|
||||
</td>
|
||||
<td><el-input style="width: 250px" v-model="item.description" /></td>
|
||||
<td>
|
||||
<el-button type="primary" v-if="!item.editStatus" @click="item.editStatus = true">编辑</el-button>
|
||||
<el-button type="danger" v-if="!item.editStatus" @click="handleDel(item.id)">删除</el-button>
|
||||
<el-button type="primary" v-if="item.editStatus" @click="submitItem(index)">确认</el-button>
|
||||
<el-button type="danger" v-if="item.editStatus" @click="item.editStatus = false">取消</el-button>
|
||||
<el-input v-if="item.editStatus" style="width: 250px" v-model="item.description" />
|
||||
<span v-else>{{ item.description }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<el-button type="primary" v-if="!item.editStatus" @click="item.editStatus = true"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button type="danger" v-if="!item.editStatus" @click="handleDel(item.id, index)"
|
||||
>删除</el-button
|
||||
>
|
||||
<el-button type="primary" v-if="item.editStatus" @click="submitItem(index)"
|
||||
>确认</el-button
|
||||
>
|
||||
<el-button type="danger" v-if="item.editStatus" @click="item.editStatus = false"
|
||||
>取消</el-button
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -130,7 +151,7 @@ const submitItem = (idx: number) => {
|
|||
description: dataList.value[idx]!.description,
|
||||
}
|
||||
if (dataList.value[idx]!.id) {
|
||||
editHoliday({id: dataList.value[idx]!.id, ...submitObj}).then(() => {
|
||||
editHoliday({ id: dataList.value[idx]!.id, ...submitObj }).then(() => {
|
||||
initDate()
|
||||
})
|
||||
} else {
|
||||
|
|
@ -140,12 +161,16 @@ const submitItem = (idx: number) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleDel = (id: number | string) => {
|
||||
const handleDel = (id: number | string, idx: number) => {
|
||||
if (!id) {
|
||||
dataList.value.splice(idx, 1)
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm('确认删除吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
}).then(() => {
|
||||
delHoliday({id}).then(() => {
|
||||
delHoliday({ id }).then(() => {
|
||||
initDate()
|
||||
})
|
||||
})
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
<el-button type="primary" v-if="!item.editStatus" @click="item.editStatus = true"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button type="danger" v-if="!item.editStatus" @click="deleteGroup(item.id)"
|
||||
<el-button type="danger" v-if="!item.editStatus" @click="deleteGroup(item.id, index)"
|
||||
>删除</el-button
|
||||
>
|
||||
<el-button type="primary" v-if="item.editStatus" @click="submitItem(index)"
|
||||
|
|
@ -205,7 +205,11 @@ const submitItem = (idx: number) => {
|
|||
}
|
||||
}
|
||||
|
||||
const deleteGroup = (id: number) => {
|
||||
const deleteGroup = (id: number, idx: number) => {
|
||||
if (!id) {
|
||||
tradeGroupTree.value.splice(idx, 1)
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm('确认删除吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
Loading…
Reference in New Issue