From fc2e3284b5a08087a2980b2a6f94fb7650661ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E8=BF=9C?= <2970639877@qq.com> Date: Wed, 25 Mar 2026 15:15:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/modules/agent/customerDetail.ts | 6 + src/api/modules/agent/customerList.ts | 11 + src/components/layout/Sidebar.vue | 2 +- src/router/index.ts | 51 +++-- .../account/{agent => agentList}/index.vue | 0 .../account/{agent => agentList}/options.ts | 0 .../account/{agent => agentList}/rules.ts | 0 src/views/agent/customerCapitalFlow/index.vue | 8 +- .../agent/customerCapitalFlow/options.ts | 2 +- src/views/agent/customerDetail/index.vue | 213 +++++++++++++++++- src/views/agent/customerDetail/options.ts | 14 ++ src/views/agent/customerList/index.vue | 196 ++++++++++++++-- src/views/agent/customerList/options.ts | 22 +- src/views/system/menu/index.vue | 1 - src/views/system/menu/options.ts | 4 +- src/views/trade/variety/index.vue | 26 +++ src/views/trade/variety/options.ts | 4 + 17 files changed, 514 insertions(+), 46 deletions(-) create mode 100644 src/api/modules/agent/customerDetail.ts rename src/views/account/{agent => agentList}/index.vue (100%) rename src/views/account/{agent => agentList}/options.ts (100%) rename src/views/account/{agent => agentList}/rules.ts (100%) create mode 100644 src/views/agent/customerDetail/options.ts diff --git a/src/api/modules/agent/customerDetail.ts b/src/api/modules/agent/customerDetail.ts new file mode 100644 index 0000000..a8fb5bb --- /dev/null +++ b/src/api/modules/agent/customerDetail.ts @@ -0,0 +1,6 @@ +//获取代理客户列表接口 +import { request } from '@/api'; + +export const getCustomerDetailApi = (params: any) => { + return request.get('/agent/getAgentUserDetail', {...params}) +} diff --git a/src/api/modules/agent/customerList.ts b/src/api/modules/agent/customerList.ts index 17f2d56..7c058ac 100644 --- a/src/api/modules/agent/customerList.ts +++ b/src/api/modules/agent/customerList.ts @@ -1,5 +1,16 @@ //获取代理客户列表接口 import { request } from '@/api'; + export const getCustomerListApi = (params: any) => { return request.get('/agent/getAgentUserList', {...params}) } + +//获取代理点差数据接口 +export const getSelfVarietyPointDiffConfigApi = (params: any) => { + return request.get('/agent/getSelfVarietyPointDiffConfig', {...params}) +} + +//编辑代理客户接口 +export const editCustomerApi = (params: any) => { + return request.post('/agent/editAgent', {...params}) +} \ No newline at end of file diff --git a/src/components/layout/Sidebar.vue b/src/components/layout/Sidebar.vue index aab4485..daae0b6 100644 --- a/src/components/layout/Sidebar.vue +++ b/src/components/layout/Sidebar.vue @@ -115,7 +115,7 @@ const staticMenuList = ref( { id: 32, label: '代理管理', - path: '/account/agent', // index="3-2" + path: '/account/agentList', // index="3-2" icon: '' }, { diff --git a/src/router/index.ts b/src/router/index.ts index 82292e6..b9c124a 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -116,9 +116,9 @@ const routes = [ } }, { - path: 'agent', - name: 'Agent', - component: () => import('@/views/account/agent/index.vue'), + path: 'agentList', + name: 'AgentList', + component: () => import('@/views/account/agentList/index.vue'), meta: { title: '代理管理', // 左侧菜单显示的标题 } @@ -314,24 +314,24 @@ const routes = [ 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: '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: '带单记录', // 左侧菜单显示的标题 + } + }, ] }, //代理管理 @@ -351,6 +351,15 @@ const routes = [ title: '客户列表', // 左侧菜单显示的标题 } }, + //客户详情 + { + path: 'customerDetail/:id', + name: 'CustomerDetail', + component: () => import('@/views/agent/customerDetail/index.vue'), + meta: { + title: '客户详情', // 左侧菜单显示的标题 + } + }, //客户交易订单 { path: 'customerTradeOrder', diff --git a/src/views/account/agent/index.vue b/src/views/account/agentList/index.vue similarity index 100% rename from src/views/account/agent/index.vue rename to src/views/account/agentList/index.vue diff --git a/src/views/account/agent/options.ts b/src/views/account/agentList/options.ts similarity index 100% rename from src/views/account/agent/options.ts rename to src/views/account/agentList/options.ts diff --git a/src/views/account/agent/rules.ts b/src/views/account/agentList/rules.ts similarity index 100% rename from src/views/account/agent/rules.ts rename to src/views/account/agentList/rules.ts diff --git a/src/views/agent/customerCapitalFlow/index.vue b/src/views/agent/customerCapitalFlow/index.vue index 4b9dfe4..9a0b8ed 100644 --- a/src/views/agent/customerCapitalFlow/index.vue +++ b/src/views/agent/customerCapitalFlow/index.vue @@ -69,12 +69,12 @@ const getCustomerCapitalFlowList = async () => { // table数据映射 tableTree.value = data.data.map((item: any) => ({ id:item.account_id, - flowNo:'', + flowNo:item.trade_id, accountName:item.user.username, amount:item.amount, - fundType:'', - status:'', - operationType:'', + fundType:item.wallet_type === "1" ? '主账户' : '子账户', + // status:'', + operationType:item.enum_dic.value, createTime:item.created_at, })) diff --git a/src/views/agent/customerCapitalFlow/options.ts b/src/views/agent/customerCapitalFlow/options.ts index c71aead..57b6d2c 100644 --- a/src/views/agent/customerCapitalFlow/options.ts +++ b/src/views/agent/customerCapitalFlow/options.ts @@ -27,7 +27,7 @@ export const tableColumns = [ // 资金类别 { prop: 'fundType', label: '资金类别' }, // 状态 - { prop: 'status', label: '状态' }, + // { prop: 'status', label: '状态' }, // 操作方式 { prop: 'operationType', label: '操作方式' }, // 时间 diff --git a/src/views/agent/customerDetail/index.vue b/src/views/agent/customerDetail/index.vue index 41a40c8..83d7a59 100644 --- a/src/views/agent/customerDetail/index.vue +++ b/src/views/agent/customerDetail/index.vue @@ -1 +1,212 @@ - \ No newline at end of file + + + diff --git a/src/views/agent/customerDetail/options.ts b/src/views/agent/customerDetail/options.ts new file mode 100644 index 0000000..fbfba0c --- /dev/null +++ b/src/views/agent/customerDetail/options.ts @@ -0,0 +1,14 @@ +export const tableColumns = [ + //交易账号 + {label: '交易账号', prop: 'tradeAccount'}, + //账户名称 + {label: '账户名称', prop: 'accountName'}, + //余额 + {label: '余额', prop: 'balance', sortable: true}, + //交易杠杆 + {label: '交易杠杆', prop: 'leverage'}, + //历史交易量 + {label: '历史交易量', prop: 'historyTradeVolume'}, + //添加时间 + {label: '添加时间', prop: 'createTime'}, +] \ No newline at end of file diff --git a/src/views/agent/customerList/index.vue b/src/views/agent/customerList/index.vue index 6ca5373..e45c5b8 100644 --- a/src/views/agent/customerList/index.vue +++ b/src/views/agent/customerList/index.vue @@ -4,23 +4,24 @@ - + @@ -29,14 +30,28 @@ 查看详情 - + + + + + + @@ -50,13 +65,14 @@ import CustomerListPagination from '@/components/common/Pagination.vue' import CustomerListDialog from '@/components/common/Dialog.vue' import CustomerListForm from '@/components/common/Form.vue' // 配置以及表单验证 -import { search, tableColumns } from './options' +import { search, tableColumns, marginRatioTableColumns, commissionRatioFormItem } from './options' // 接口 -import { getCustomerListApi } from '@/api/modules/agent/customerList' +import { getCustomerListApi, getSelfVarietyPointDiffConfigApi, editCustomerApi } from '@/api/modules/agent/customerList' // 公用方法 import { getStorage } from '@/utils/storage' +const router = useRouter() /** * @description: 获取用户id */ @@ -75,23 +91,82 @@ const searchForm = ref({ }) const searchOptions = ref(search) const tableColumnsOptions = ref(tableColumns) + /** * @description: 定义表格数据 */ const tableTree = ref([]) const treeProps = { children: 'children' } + /** * @description: 定义分页数据 */ const total = ref(0) const currentPage = ref(1) const pageSize = ref(10) + /** * @description: 定义弹窗数据 */ +const dialogVisible = ref(false) +const dialogTitle = ref('') +const dialogType = ref('') +const dialogFullscreen = ref(false) + /** - * @description: 定义弹窗表格数据 + * @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: 角色映射方法 */ @@ -108,8 +183,8 @@ const roleMap: any = { /** * @description: 定义公共请求数据方法 */ +// 获取客户列表 const getCustomerList = async (id: string) => { - console.log('用户id', id); const params = { user_id: id, page: currentPage.value, @@ -127,11 +202,9 @@ const getCustomerList = async (id: string) => { status: item.status === 1 ? '正常' : '禁用', role: roleMap[item.role_id] || '未知', accountQty: item.account[0].account_count, - marginRatio: "这是按钮", commissionRatio: item.wallet_capital.fee_handling_percent, createTime: item.created_at, role_id: item.role_id, - children: [], })) //分页数据 @@ -139,12 +212,29 @@ const getCustomerList = async (id: string) => { 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: 定义搜索方法 */ @@ -160,14 +250,39 @@ const handleReset = () => { } 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) => { console.log('获取子列表', row); } + /** * @description: 定义分页方法 */ @@ -175,9 +290,64 @@ 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: 定义弹窗表格方法 */ diff --git a/src/views/agent/customerList/options.ts b/src/views/agent/customerList/options.ts index e7e3544..c181344 100644 --- a/src/views/agent/customerList/options.ts +++ b/src/views/agent/customerList/options.ts @@ -17,7 +17,7 @@ export const search = [ export const tableColumns = [ // 账号名称 - { label: '账号名称', slotName: 'accountName', emptySpan: { colspan: 999 } }, + { label: '账号名称', slotName: 'accountName'}, // 账号id { prop: 'userId', label: '账号id' }, // 状态 @@ -31,7 +31,25 @@ export const tableColumns = [ // 手续费分成比例 { prop: 'commissionRatio', label: '手续费分成比例', slotName: 'commissionRatio' }, // 注册时间 - { prop: 'createTime', label: '注册时间' ,sortable:true}, + { 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'}, ] \ No newline at end of file diff --git a/src/views/system/menu/index.vue b/src/views/system/menu/index.vue index 2d3464a..1fa1f0c 100644 --- a/src/views/system/menu/index.vue +++ b/src/views/system/menu/index.vue @@ -118,7 +118,6 @@ const fetchMenuList = async () => { ] } catch (err) { console.error('获取菜单列表失败', err) - ElMessage.error('获取菜单列表失败,请稍后重试') } } // 页面加载时获取菜单列表 diff --git a/src/views/system/menu/options.ts b/src/views/system/menu/options.ts index b39d09b..3e4ce3b 100644 --- a/src/views/system/menu/options.ts +++ b/src/views/system/menu/options.ts @@ -27,8 +27,8 @@ export const menuiconOptions = [ //定义table配置 export const menuTableColumns = [ - { prop: 'name', label: '菜单名称', align: 'center' as const, width: '120px' }, - { prop: 'path', label: '路由路径', align: 'center' as const, width: '120px' }, + { prop: 'name', label: '菜单名称', align: 'center' as const}, + { prop: 'path', label: '路由路径', align: 'center' as const}, { label: '图标', slotName: 'icon', align: 'center' as const }, { label: '类型', slotName: 'type', align: 'center' as const }, { label: '状态', slotName: 'status', align: 'center' as const }, diff --git a/src/views/trade/variety/index.vue b/src/views/trade/variety/index.vue index 8f098d3..da2ce7a 100644 --- a/src/views/trade/variety/index.vue +++ b/src/views/trade/variety/index.vue @@ -117,12 +117,37 @@ const varietyFormRules = ref(rules()) const dialogFormItemOptions = ref(editDialogFormItem) const varietyFormOptionsMap = ref({ tradeGroup: [], + type: [ + { + label: '金属', + value: 1, + }, + { + label: '能源', + value: 2, + }, + { + label: '指数', + value: 3, + }, + { + label: '股票', + value: 4, + }, + ], }) // 选中行 const selectedRow = ref(null) const rowGutter = ref(20) const colSpan = ref(12) +const typeMap:any = { + 1: '金属', + 2: '能源', + 3: '指数', + 4: '股票', +} + /** * @description: 定义公共请求数据方法 */ @@ -151,6 +176,7 @@ const getVarietyList = async () => { longStockFee: item.fee_inventory_long, shortStockFee: item.fee_inventory_short, profitLevel: item.stop_loss_level, + type: typeMap[item.type], })) } diff --git a/src/views/trade/variety/options.ts b/src/views/trade/variety/options.ts index 720197e..6f47472 100644 --- a/src/views/trade/variety/options.ts +++ b/src/views/trade/variety/options.ts @@ -36,6 +36,8 @@ export const tableColumns = [ { prop: 'longStockFee', label: '多头库存费', align: 'center' as const }, // 空头库存费 { prop: 'shortStockFee', label: '空头库存费', align: 'center' as const }, + // 类型 + { prop: 'type', label: '类型', align: 'center' as const }, // 止盈水平 { prop: 'profitLevel', label: '止盈水平', align: 'center' as const }, ] @@ -74,6 +76,8 @@ export const editDialogFormItem = [ { prop: 'unit', label: '单位', type: 'input' as const, placeholder: '请输入单位' }, // 最小波动 { prop: 'minFlux', label: '最小波动', type: 'input' as const, placeholder: '请输入最小波动' }, + // 类型 + { prop: 'type', label: '类型', type: 'select' as const, placeholder: '请选择类型' }, // 上下线状态 { prop: 'onlineStatus', label: '上下线状态', type: 'switch' as const}, // 交易状态