diff --git a/.claude/settings.local.json b/.claude/settings.local.json index e298541..64b5cee 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -14,7 +14,9 @@ "Bash(npm run build:*)", "Bash(tree:*)", "Bash(npm run dev:*)", - "Bash(timeout:*)" + "Bash(timeout:*)", + "Read(//d/**)", + "Bash(findstr:*)" ], "deny": [], "ask": [] diff --git a/src/components/core/others/TableContextMenuHint.vue b/src/components/core/others/TableContextMenuHint.vue new file mode 100644 index 0000000..c0d9fc3 --- /dev/null +++ b/src/components/core/others/TableContextMenuHint.vue @@ -0,0 +1,38 @@ + + + + {{ text }} + + + + + + diff --git a/src/components/core/tables/ArtTable.vue b/src/components/core/tables/ArtTable.vue index dcca5ef..c798c6d 100644 --- a/src/components/core/tables/ArtTable.vue +++ b/src/components/core/tables/ArtTable.vue @@ -14,6 +14,7 @@ v-loading="loading" :data="tableData" :row-key="rowKey" + :row-class-name="rowClassName" :height="height" :max-height="maxHeight" :show-header="showHeader" @@ -30,6 +31,8 @@ @row-click="handleRowClick" @row-contextmenu="handleRowContextmenu" @selection-change="handleSelectionChange" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > string) | string /** 是否显示边框 */ border?: boolean | null /** 是否使用斑马纹样式 */ @@ -136,6 +141,7 @@ data: () => [], loading: false, rowKey: 'id', + rowClassName: undefined, border: null, stripe: null, index: false, @@ -178,7 +184,9 @@ 'row-contextmenu', 'size-change', 'current-change', - 'selection-change' + 'selection-change', + 'cell-mouse-enter', + 'cell-mouse-leave' ]) const tableStore = useTableStore() @@ -281,6 +289,16 @@ emit('row-contextmenu', row, column, event) } + // 单元格鼠标进入事件 + const handleCellMouseEnter = (row: any, column: any, cell: any, event: any) => { + emit('cell-mouse-enter', row, column, cell, event) + } + + // 单元格鼠标离开事件 + const handleCellMouseLeave = (row: any, column: any, cell: any, event: any) => { + emit('cell-mouse-leave', row, column, cell, event) + } + // 选择变化事件 const handleSelectionChange = (selection: any) => { emit('selection-change', selection) diff --git a/src/composables/useTableContextMenu.ts b/src/composables/useTableContextMenu.ts new file mode 100644 index 0000000..383e36e --- /dev/null +++ b/src/composables/useTableContextMenu.ts @@ -0,0 +1,63 @@ +/** + * 表格右键菜单的组合式函数 + * 提供右键菜单功能和鼠标悬浮提示 + */ + +import { ref, reactive } from 'vue' + +export function useTableContextMenu() { + // 鼠标悬浮提示相关 + const showContextMenuHint = ref(false) + const hintPosition = reactive({ x: 0, y: 0 }) + let hintTimer: any = null + + /** + * 为表格行添加类名 + */ + const getRowClassName = ({ row, rowIndex }: { row: any; rowIndex: number }) => { + return 'table-row-with-context-menu' + } + + /** + * 单元格鼠标进入事件处理 + */ + const handleCellMouseEnter = ( + row: any, + column: any, + cell: HTMLElement, + event: MouseEvent + ) => { + // 清除之前的定时器 + if (hintTimer) { + clearTimeout(hintTimer) + } + + // 延迟显示提示,避免快速划过时闪烁 + hintTimer = setTimeout(() => { + hintPosition.x = event.clientX + 15 + hintPosition.y = event.clientY + 10 + showContextMenuHint.value = true + }, 300) + } + + /** + * 单元格鼠标离开事件处理 + */ + const handleCellMouseLeave = () => { + if (hintTimer) { + clearTimeout(hintTimer) + } + showContextMenuHint.value = false + } + + return { + // 状态 + showContextMenuHint, + hintPosition, + + // 方法 + getRowClassName, + handleCellMouseEnter, + handleCellMouseLeave + } +} diff --git a/src/locales/langs/en.json b/src/locales/langs/en.json index e7f0e42..e23bcf3 100644 --- a/src/locales/langs/en.json +++ b/src/locales/langs/en.json @@ -450,11 +450,15 @@ "devices": "Device Management", "deviceDetail": "Device Details", "assetAssign": "Allocation Records", + "assetAssignDetail": "Asset Allocation Details", "allocationRecordDetail": "Allocation Record Details", "cardReplacementRequest": "Card Replacement Request", "authorizationRecords": "Authorization Records", "authorizationDetail": "Authorization Details", - "enterpriseDevices": "Enterprise Devices" + "authorizationRecordDetail": "Authorization Record Details", + "enterpriseDevices": "Enterprise Devices", + "recordsManagement": "Records Management", + "taskManagement": "Task Management" }, "settings": { "title": "Settings Management", diff --git a/src/locales/langs/zh.json b/src/locales/langs/zh.json index 65729be..79021e9 100644 --- a/src/locales/langs/zh.json +++ b/src/locales/langs/zh.json @@ -385,7 +385,7 @@ }, "cardManagement": { "title": "我的网卡", - "singleCard": "单卡信息", + "singleCard": "资产信息", "cardList": "网卡管理", "cardDetail": "网卡明细", "cardAssign": "网卡分配", @@ -453,7 +453,9 @@ "authorizationRecords": "授权记录", "authorizationDetail": "授权记录详情", "authorizationRecordDetail": "授权记录详情", - "enterpriseDevices": "企业设备列表" + "enterpriseDevices": "企业设备列表", + "recordsManagement": "记录管理", + "taskManagement": "任务管理" }, "account": { "title": "账户管理", diff --git a/src/router/routes/asyncRoutes.ts b/src/router/routes/asyncRoutes.ts index f1ca4f3..d36ffcf 100644 --- a/src/router/routes/asyncRoutes.ts +++ b/src/router/routes/asyncRoutes.ts @@ -51,6 +51,7 @@ export const asyncRoutes: AppRouteRecord[] = [ } ] }, + // { // path: '/widgets', // name: 'Widgets', @@ -266,6 +267,7 @@ export const asyncRoutes: AppRouteRecord[] = [ // } // ] // }, + { path: '/system', name: 'System', @@ -429,6 +431,7 @@ export const asyncRoutes: AppRouteRecord[] = [ // } ] }, + // { // path: '/article', // name: 'Article', @@ -712,6 +715,7 @@ export const asyncRoutes: AppRouteRecord[] = [ // } // ] // }, + { path: '/package-management', name: 'PackageManagement', @@ -780,6 +784,7 @@ export const asyncRoutes: AppRouteRecord[] = [ } ] }, + { path: '/shop-management', name: 'ShopManagement', @@ -800,6 +805,7 @@ export const asyncRoutes: AppRouteRecord[] = [ } ] }, + { path: '/account-management', name: 'AccountManagement', @@ -885,6 +891,7 @@ export const asyncRoutes: AppRouteRecord[] = [ } ] }, + // { // path: '/product', // name: 'Product', @@ -950,6 +957,7 @@ export const asyncRoutes: AppRouteRecord[] = [ // } // ] // }, + { path: '/asset-management', name: 'AssetManagement', @@ -977,44 +985,6 @@ export const asyncRoutes: AppRouteRecord[] = [ keepAlive: true } }, - { - path: 'iot-card-management/detail', - name: 'IotCardDetail', - component: RoutesAlias.StandaloneCardList + '/detail', - meta: { - title: 'menus.assetManagement.iotCardDetail', - isHide: true, - keepAlive: false - } - }, - { - path: 'iot-card-task', - name: 'IotCardTask', - component: RoutesAlias.IotCardTask, - meta: { - title: 'menus.assetManagement.iotCardTask', - keepAlive: true - } - }, - { - path: 'device-task', - name: 'DeviceTask', - component: RoutesAlias.DeviceTask, - meta: { - title: 'menus.assetManagement.deviceTask', - keepAlive: true - } - }, - { - path: 'task-detail', - name: 'TaskDetail', - component: RoutesAlias.TaskDetail, - meta: { - title: 'menus.assetManagement.taskDetail', - isHide: true, - keepAlive: false - } - }, { path: 'devices', name: 'DeviceList', @@ -1024,63 +994,6 @@ export const asyncRoutes: AppRouteRecord[] = [ keepAlive: true } }, - { - path: 'device-detail', - name: 'DeviceDetail', - component: RoutesAlias.DeviceDetail, - meta: { - title: 'menus.assetManagement.deviceDetail', - isHide: true, - keepAlive: false - } - }, - { - path: 'asset-assign', - name: 'AssetAssign', - component: RoutesAlias.AssetAssign, - meta: { - title: 'menus.assetManagement.assetAssign', - keepAlive: true - } - }, - { - path: 'asset-assign/detail/:id', - name: 'AssetAssignDetail', - component: RoutesAlias.AssetAssignDetail, - meta: { - title: 'menus.assetManagement.assetAssignDetail', - isHide: true, - keepAlive: false - } - }, - // { - // path: 'card-replacement-request', - // name: 'CardReplacementRequest', - // component: RoutesAlias.CardReplacementRequest, - // meta: { - // title: 'menus.assetManagement.cardReplacementRequest', - // keepAlive: true - // } - // }, - { - path: 'authorization-records', - name: 'AuthorizationRecords', - component: RoutesAlias.AuthorizationRecords, - meta: { - title: 'menus.assetManagement.authorizationRecords', - keepAlive: true - } - }, - { - path: 'authorization-records/detail/:id', - name: 'AuthorizationRecordDetail', - component: RoutesAlias.AuthorizationRecordDetail, - meta: { - title: 'menus.assetManagement.authorizationRecordDetail', - isHide: true, - keepAlive: false - } - }, { path: 'enterprise-devices', name: 'EnterpriseDevices', @@ -1090,9 +1003,100 @@ export const asyncRoutes: AppRouteRecord[] = [ isHide: true, keepAlive: false } + }, + // 记录管理 + { + path: 'records', + name: 'RecordsManagement', + component: '', + meta: { + title: 'menus.assetManagement.recordsManagement', + keepAlive: true + }, + children: [ + { + path: 'asset-assign', + name: 'AssetAssign', + component: RoutesAlias.AssetAssign, + meta: { + title: 'menus.assetManagement.assetAssign', + keepAlive: true + } + }, + { + path: 'asset-assign/detail/:id', + name: 'AssetAssignDetail', + component: RoutesAlias.AssetAssignDetail, + meta: { + title: 'menus.assetManagement.assetAssignDetail', + isHide: true, + keepAlive: false + } + }, + { + path: 'authorization-records', + name: 'AuthorizationRecords', + component: RoutesAlias.AuthorizationRecords, + meta: { + title: 'menus.assetManagement.authorizationRecords', + keepAlive: true + } + }, + { + path: 'authorization-records/detail/:id', + name: 'AuthorizationRecordDetail', + component: RoutesAlias.AuthorizationRecordDetail, + meta: { + title: 'menus.assetManagement.authorizationRecordDetail', + isHide: true, + keepAlive: false + } + } + ] + }, + // 任务管理 + { + path: 'tasks', + name: 'TaskManagement', + component: '', + meta: { + title: 'menus.assetManagement.taskManagement', + keepAlive: true + }, + children: [ + { + path: 'iot-card-task', + name: 'IotCardTask', + component: RoutesAlias.IotCardTask, + meta: { + title: 'menus.assetManagement.iotCardTask', + keepAlive: true + } + }, + { + path: 'device-task', + name: 'DeviceTask', + component: RoutesAlias.DeviceTask, + meta: { + title: 'menus.assetManagement.deviceTask', + keepAlive: true + } + }, + { + path: 'task-detail', + name: 'TaskDetail', + component: RoutesAlias.TaskDetail, + meta: { + title: 'menus.assetManagement.taskDetail', + isHide: true, + keepAlive: false + } + } + ] } ] }, + { path: '/account', name: 'Finance', @@ -1141,6 +1145,7 @@ export const asyncRoutes: AppRouteRecord[] = [ // } ] }, + { path: '/commission', name: 'CommissionManagement', @@ -1192,6 +1197,7 @@ export const asyncRoutes: AppRouteRecord[] = [ } ] } + // { // path: '/settings', // name: 'Settings', diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 525c39d..7390a14 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -122,6 +122,8 @@ declare module 'vue' { ElSelect: typeof import('element-plus/es')['ElSelect'] ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem'] + ElStep: typeof import('element-plus/es')['ElStep'] + ElSteps: typeof import('element-plus/es')['ElSteps'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTable: typeof import('element-plus/es')['ElTable'] @@ -152,6 +154,7 @@ declare module 'vue' { SettingHeader: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingHeader.vue')['default'] SettingItem: typeof import('./../components/core/layouts/art-settings-panel/widget/SettingItem.vue')['default'] SidebarSubmenu: typeof import('./../components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue')['default'] + TableContextMenuHint: typeof import('./../components/core/others/TableContextMenuHint.vue')['default'] ThemeSettings: typeof import('./../components/core/layouts/art-settings-panel/widget/ThemeSettings.vue')['default'] } export interface ComponentCustomProperties { diff --git a/src/views/account-management/account/index.vue b/src/views/account-management/account/index.vue index 9e80a9a..10e2599 100644 --- a/src/views/account-management/account/index.vue +++ b/src/views/account-management/account/index.vue @@ -31,16 +31,22 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @selection-change="handleSelectionChange" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + @@ -75,6 +78,9 @@ + + + diff --git a/src/views/account-management/enterprise-customer/index.vue b/src/views/account-management/enterprise-customer/index.vue index 54ca484..89301d8 100644 --- a/src/views/account-management/enterprise-customer/index.vue +++ b/src/views/account-management/enterprise-customer/index.vue @@ -35,15 +35,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + userStore.info.user_type === 3) @@ -811,3 +828,9 @@ } } + + diff --git a/src/views/asset-management/asset-assign/index.vue b/src/views/asset-management/asset-assign/index.vue index 202d881..e38795d 100644 --- a/src/views/asset-management/asset-assign/index.vue +++ b/src/views/asset-management/asset-assign/index.vue @@ -28,15 +28,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + >() @@ -374,4 +392,8 @@ .asset-allocation-records-page { // Allocation records page styles } + + :deep(.el-table__row.table-row-with-context-menu) { + cursor: pointer; + } diff --git a/src/views/asset-management/authorization-records/index.vue b/src/views/asset-management/authorization-records/index.vue index 39af8dd..4614c9b 100644 --- a/src/views/asset-management/authorization-records/index.vue +++ b/src/views/asset-management/authorization-records/index.vue @@ -28,15 +28,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + diff --git a/src/views/asset-management/device-detail/index.vue b/src/views/asset-management/device-detail/index.vue deleted file mode 100644 index e9f24a9..0000000 --- a/src/views/asset-management/device-detail/index.vue +++ /dev/null @@ -1,446 +0,0 @@ - - - - - - - - - - 返回 - - 设备详情 - - - - - - - - - 加载中... - - - - - - - 绑定的卡列表 - - 绑定新卡 - - - - - - - - 插槽 {{ row.slot_position }} - - - - - - {{ row.msisdn || '-' }} - - - - - - - {{ cardStatusTextMap[row.status] || '未知' }} - - - - - - {{ row.bind_time ? formatDateTime(row.bind_time) : '-' }} - - - - - - 解绑 - - - - - - - - - - - - - - - - - {{ card.iccid }} - {{ card.carrier_name }} - - - - - - - - - - - - - - - - - - - - diff --git a/src/views/asset-management/device-list/index.vue b/src/views/asset-management/device-list/index.vue index 0a24635..32208bf 100644 --- a/src/views/asset-management/device-list/index.vue +++ b/src/views/asset-management/device-list/index.vue @@ -53,10 +53,13 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @selection-change="handleSelectionChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > @@ -64,6 +67,9 @@ + + + { if (hasAuth('device:view_detail')) { router.push({ - path: '/asset-management/device-detail', + path: '/asset-management/single-card', query: { device_no: deviceNo } @@ -1697,4 +1715,8 @@ .device-list-page { height: 100%; } + + :deep(.el-table__row.table-row-with-context-menu) { + cursor: pointer; + } diff --git a/src/views/asset-management/device-task/index.vue b/src/views/asset-management/device-task/index.vue index 13e2a2f..e95f517 100644 --- a/src/views/asset-management/device-task/index.vue +++ b/src/views/asset-management/device-task/index.vue @@ -39,15 +39,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + () @@ -679,4 +697,8 @@ } } } + + :deep(.el-table__row.table-row-with-context-menu) { + cursor: pointer; + } diff --git a/src/views/asset-management/iot-card-management/detail.vue b/src/views/asset-management/iot-card-management/detail.vue deleted file mode 100644 index 1644a79..0000000 --- a/src/views/asset-management/iot-card-management/detail.vue +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - 返回 - - IoT卡详情 - - - 刷新 - - - - - - - - 加载中... - - - - - - - - - - - - - - - - diff --git a/src/views/asset-management/iot-card-management/index.vue b/src/views/asset-management/iot-card-management/index.vue index 5cb53e4..4889c02 100644 --- a/src/views/asset-management/iot-card-management/index.vue +++ b/src/views/asset-management/iot-card-management/index.vue @@ -51,7 +51,7 @@ hasAuth('iot_card:batch_download') " type="info" - @contextmenu.prevent="showMoreMenu" + @click="showMoreMenuOnClick" > 更多操作 @@ -68,10 +68,13 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @selection-change="handleSelectionChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > @@ -79,6 +82,9 @@ + + + { if (hasAuth('iot_card:view_detail')) { router.push({ - path: RoutesAlias.StandaloneCardList + '/detail', + path: '/asset-management/single-card', query: { iccid: iccid } @@ -1575,13 +1593,19 @@ return items }) - // 显示更多操作菜单 + // 显示更多操作菜单 (右键) const showMoreMenu = (e: MouseEvent) => { e.preventDefault() e.stopPropagation() moreMenuRef.value?.show(e) } + // 显示更多操作菜单 (左键点击) + const showMoreMenuOnClick = (e: MouseEvent) => { + e.stopPropagation() + moreMenuRef.value?.show(e) + } + // 处理更多操作菜单选择 const handleMoreMenuSelect = (item: MenuItemType) => { switch (item.key) { @@ -1829,4 +1853,8 @@ .standalone-card-list-page { // Card list page styles } + + :deep(.el-table__row.table-row-with-context-menu) { + cursor: pointer; + } diff --git a/src/views/asset-management/iot-card-task/index.vue b/src/views/asset-management/iot-card-task/index.vue index 46582f3..7a46265 100644 --- a/src/views/asset-management/iot-card-task/index.vue +++ b/src/views/asset-management/iot-card-task/index.vue @@ -39,15 +39,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + () @@ -733,4 +751,8 @@ } } } + + :deep(.el-table__row.table-row-with-context-menu) { + cursor: pointer; + } diff --git a/src/views/dashboard/analysis/index.vue b/src/views/dashboard/analysis/index.vue index bac095c..944e04d 100644 --- a/src/views/dashboard/analysis/index.vue +++ b/src/views/dashboard/analysis/index.vue @@ -1,6 +1,13 @@ - 开发中敬请期待... + + 佣金概览 + + + + 提现配置 + + @@ -45,10 +52,24 @@ import TopProducts from './widget/TopProducts.vue' import SalesMappingByCountry from './widget/SalesMappingByCountry.vue' import VolumeServiceLevel from './widget/VolumeServiceLevel.vue' + import CommissionSummary from './widget/CommissionSummary.vue' + import WithdrawalSettings from './widget/WithdrawalSettings.vue' defineOptions({ name: 'Analysis' }) diff --git a/src/views/dashboard/analysis/style.scss b/src/views/dashboard/analysis/style.scss index 0325df9..cd0f4c3 100644 --- a/src/views/dashboard/analysis/style.scss +++ b/src/views/dashboard/analysis/style.scss @@ -31,7 +31,7 @@ } .el-card { - border: 1px solid #e8ebf1; + border: none; box-shadow: none; } diff --git a/src/views/dashboard/analysis/widget/CommissionSummary.vue b/src/views/dashboard/analysis/widget/CommissionSummary.vue new file mode 100644 index 0000000..601bd40 --- /dev/null +++ b/src/views/dashboard/analysis/widget/CommissionSummary.vue @@ -0,0 +1,175 @@ + + + + + + + + + + 总佣金 + {{ formatMoney(summary.total_commission) }} + + + + + + + + + + + + 可提现佣金 + {{ formatMoney(summary.available_commission) }} + + + + + + + + + + + + 冻结佣金 + {{ formatMoney(summary.frozen_commission) }} + + + + + + + + + + + + 提现中佣金 + {{ formatMoney(summary.withdrawing_commission) }} + + + + + + + + + + + + 已提现佣金 + {{ formatMoney(summary.withdrawn_commission) }} + + + + + + + + + + diff --git a/src/views/dashboard/analysis/widget/WithdrawalSettings.vue b/src/views/dashboard/analysis/widget/WithdrawalSettings.vue new file mode 100644 index 0000000..7460f83 --- /dev/null +++ b/src/views/dashboard/analysis/widget/WithdrawalSettings.vue @@ -0,0 +1,223 @@ + + + + + + 当前生效配置 + 生效中 + + + {{ currentSetting.creator_name || '-' }} 创建于 + {{ formatDateTime(currentSetting.created_at) }} + + + + + + + 💰 + + + 最低提现金额 + {{ formatMoney(currentSetting.min_withdrawal_amount) }} + + + + + 📊 + + + 手续费率 + {{ formatFeeRate(currentSetting.fee_rate) }} + + + + + 🔢 + + + 每日提现次数 + {{ currentSetting.daily_withdrawal_limit }} 次 + + + + + ⏰ + + + 到账天数 + {{ + currentSetting.arrival_days === 0 ? '实时到账' : `${currentSetting.arrival_days} 天` + }} + + + + + + + + 暂无提现配置 + + + + + + + diff --git a/src/views/finance/carrier-management/index.vue b/src/views/finance/carrier-management/index.vue index e9d202b..6e9ddf0 100644 --- a/src/views/finance/carrier-management/index.vue +++ b/src/views/finance/carrier-management/index.vue @@ -33,14 +33,29 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" + @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + + + + >() + const currentRow = ref(null) + + // 使用表格右键菜单功能 + const { + showContextMenuHint, + hintPosition, + getRowClassName, + handleCellMouseEnter, + handleCellMouseLeave + } = useTableContextMenu() // 搜索表单初始值 const initialSearchState = { @@ -188,8 +218,7 @@ { label: '运营商类型', prop: 'carrier_type' }, { label: '运营商描述', prop: 'description' }, { label: '状态', prop: 'status' }, - { label: '创建时间', prop: 'created_at' }, - { label: '操作', prop: 'operation' } + { label: '创建时间', prop: 'created_at' } ] const formRef = ref() @@ -271,35 +300,6 @@ label: '创建时间', width: 180, formatter: (row: any) => formatDateTime(row.created_at) - }, - { - prop: 'operation', - label: '操作', - width: 150, - fixed: 'right', - formatter: (row: any) => { - const buttons = [] - - if (hasAuth('carrier:edit')) { - buttons.push( - h(ArtButtonTable, { - type: 'edit', - onClick: () => showDialog('edit', row) - }) - ) - } - - if (hasAuth('carrier:delete')) { - buttons.push( - h(ArtButtonTable, { - type: 'delete', - onClick: () => deleteCarrier(row) - }) - ) - } - - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) - } } ]) @@ -469,10 +469,51 @@ console.error(error) } } + + // 右键菜单项配置 + const contextMenuItems = computed((): MenuItemType[] => { + const items: MenuItemType[] = [] + + if (hasAuth('carrier:edit')) { + items.push({ key: 'edit', label: '编辑' }) + } + + if (hasAuth('carrier:delete')) { + items.push({ key: 'delete', label: '删除' }) + } + + return items + }) + + // 处理表格行右键菜单 + const handleRowContextMenu = (row: any, column: any, event: MouseEvent) => { + event.preventDefault() + event.stopPropagation() + currentRow.value = row + contextMenuRef.value?.show(event) + } + + // 处理右键菜单选择 + const handleContextMenuSelect = (item: MenuItemType) => { + if (!currentRow.value) return + + switch (item.key) { + case 'edit': + showDialog('edit', currentRow.value) + break + case 'delete': + deleteCarrier(currentRow.value) + break + } + } diff --git a/src/views/finance/commission/agent-commission/index.vue b/src/views/finance/commission/agent-commission/index.vue index a09bead..7b8f222 100644 --- a/src/views/finance/commission/agent-commission/index.vue +++ b/src/views/finance/commission/agent-commission/index.vue @@ -46,15 +46,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + diff --git a/src/views/finance/commission/my-commission/index.vue b/src/views/finance/commission/my-commission/index.vue index df726d5..dff7aa3 100644 --- a/src/views/finance/commission/my-commission/index.vue +++ b/src/views/finance/commission/my-commission/index.vue @@ -1,89 +1,5 @@ - - - - - - - - - - 总佣金 - {{ formatMoney(summary.total_commission) }} - - - - - - - - - - - - 可提现佣金 - {{ formatMoney(summary.available_commission) }} - - - - - - - - - - - - 冻结佣金 - {{ formatMoney(summary.frozen_commission) }} - - - - - - - - - - - - 提现中佣金 - {{ formatMoney(summary.withdrawing_commission) }} - - - - - - - - - - - - 已提现佣金 - {{ formatMoney(summary.withdrawn_commission) }} - - - - - - @@ -841,37 +757,6 @@ diff --git a/src/views/finance/commission/withdrawal-settings/index.vue b/src/views/finance/commission/withdrawal-settings/index.vue index ad7d505..ef79f29 100644 --- a/src/views/finance/commission/withdrawal-settings/index.vue +++ b/src/views/finance/commission/withdrawal-settings/index.vue @@ -1,78 +1,8 @@ - - - - - - 当前生效配置 - 生效中 - - - {{ currentSetting.creator_name || '-' }} 创建于 - {{ formatDateTime(currentSetting.created_at) }} - - - - - - - 💰 - - - 最低提现金额 - {{ formatMoney(currentSetting.min_withdrawal_amount) }} - - - - - 📊 - - - 手续费率 - {{ formatFeeRate(currentSetting.fee_rate) }} - - - - - 🔢 - - - 每日提现次数 - {{ currentSetting.daily_withdrawal_limit }} 次 - - - - - ⏰ - - - 到账天数 - {{ - currentSetting.arrival_days === 0 ? '实时到账' : `${currentSetting.arrival_days} 天` - }} - - - - - - + () - // 当前生效的配置 - const currentSetting = ref(null) - // 配置列表 const settingsList = ref([]) @@ -254,26 +181,9 @@ ]) onMounted(() => { - loadData() + loadSettingsList() }) - // 加载数据 - const loadData = async () => { - await Promise.all([loadCurrentSetting(), loadSettingsList()]) - } - - // 加载当前生效配置 - const loadCurrentSetting = async () => { - try { - const res = await CommissionService.getCurrentWithdrawalSetting() - if (res.code === 0 && res.data) { - currentSetting.value = res.data - } - } catch (error) { - console.error('获取当前配置失败:', error) - } - } - // 加载配置列表 const loadSettingsList = async () => { loading.value = true @@ -291,7 +201,7 @@ // 刷新数据 const handleRefresh = () => { - loadData() + loadSettingsList() } // 显示新增对话框 @@ -323,7 +233,7 @@ ElMessage.success('新增配置成功') dialogVisible.value = false formEl.resetFields() - loadData() + loadSettingsList() } catch (error) { console.error(error) } finally { @@ -336,99 +246,6 @@ diff --git a/src/views/package-management/package-list/index.vue b/src/views/package-management/package-list/index.vue index d1af518..bb5d40e 100644 --- a/src/views/package-management/package-list/index.vue +++ b/src/views/package-management/package-list/index.vue @@ -34,15 +34,21 @@ :pageSize="pagination.page_size" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + ([]) const searchSeriesOptions = ref([]) + // 使用表格右键菜单功能 + const { + showContextMenuHint, + hintPosition, + getRowClassName, + handleCellMouseEnter, + handleCellMouseLeave + } = useTableContextMenu() + // 搜索表单初始值 const initialSearchState = { package_name: '', @@ -952,6 +969,10 @@ diff --git a/src/views/package-management/series-grants/detail.vue b/src/views/package-management/series-grants/detail.vue index 04688dc..14849d9 100644 --- a/src/views/package-management/series-grants/detail.vue +++ b/src/views/package-management/series-grants/detail.vue @@ -91,13 +91,14 @@ - {{ - row.stat_scope === 'self' - ? '仅自己' - : row.stat_scope === 'self_and_sub' - ? '自己+下级' - : '-' - }} + 仅自己 + + + + + + + diff --git a/src/views/package-management/series-grants/index.vue b/src/views/package-management/series-grants/index.vue index d07d349..810f3ee 100644 --- a/src/views/package-management/series-grants/index.vue +++ b/src/views/package-management/series-grants/index.vue @@ -35,15 +35,21 @@ :pageSize="pagination.page_size" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + + + + + + + + 添加授权套餐 + + + + + + + + + + ¥{{ (row.cost_price / 100).toFixed(2) }} + + + + + 上架 + 下架 + - + + + + + 启用 + 禁用 + - + + + + + + 编辑 + + + 删除 + + + + + + + + + + + + + + + + + + + + + + + + {{ packageForm.package_name }} + + + {{ packageForm.package_code }} + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 套餐配置(可选) + + + + + + + + + 选择该授权下包含的套餐 - - - - - - - - + + + + + {{ getPackageName(pkg.package_id) }} + + + + (成本价: ¥{{ pkg.original_cost_price.toFixed(2) }}) + + + 删除 + + + 设置每个套餐的成本价(单位:元),不能低于套餐原始成本价 + + + + + + + + + 一次性佣金配置 + + + + + + + + + {{ form.commission_type === 'fixed' ? '固定佣金' : '梯度佣金' }} + + (从套餐系列配置继承) + + + + + + + + 该代理能获得的固定佣金金额(单位:元) + + + 该系列最大佣金金额: + ¥{{ form.series_max_commission_amount.toFixed(2) }} + + + + + + + + + + + + + {{ row.operator || '>=' }} + + + + + {{ row.threshold }} + + + + + + {{ row.dimension === 'sales_count' ? '销量' : '销售额' }} + + + + + + 仅自己 + + + + + + + + 最大: ¥{{ row.max_amount.toFixed(2) }} + + + + + + + 梯度配置从套餐系列继承,达标阈值、统计维度、统计范围为只读,只能修改佣金金额 + + + + + + + 强制充值配置(可选) + + + + + + + + + + + + + + 用户需要达到的强制充值金额 + + + 可参考 + {{ form.series_name }}系列强充金额: + ¥{{ form.series_force_recharge_amount.toFixed(2) }} + + + + + + + + + + + - + 系列名称: {{ form.series_name || '-' }} @@ -189,15 +578,7 @@ - - {{ - row.stat_scope === 'self' - ? '仅自己' - : row.stat_scope === 'self_and_sub' - ? '自己+下级' - : '-' - }} - + 仅自己 @@ -271,13 +652,13 @@ - - + + - - + + - + + @@ -346,7 +745,7 @@ diff --git a/src/views/product/shop/index.vue b/src/views/product/shop/index.vue index 6fdd6fd..9246892 100644 --- a/src/views/product/shop/index.vue +++ b/src/views/product/shop/index.vue @@ -34,16 +34,22 @@ :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" :default-expand-all="false" :pagination="false" + :row-class-name="getRowClassName" @selection-change="handleSelectionChange" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + diff --git a/src/views/system/permission/index.vue b/src/views/system/permission/index.vue index 1a69cc1..d161f5f 100644 --- a/src/views/system/permission/index.vue +++ b/src/views/system/permission/index.vue @@ -31,12 +31,27 @@ :default-expand-all="false" :marginTop="10" :show-pagination="false" + :row-class-name="getRowClassName" + @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + + + + (null) const currentPermissionId = ref(0) const submitLoading = ref(false) + const contextMenuRef = ref>() + + // 使用表格右键菜单功能 + const { + showContextMenuHint, + hintPosition, + getRowClassName, + handleCellMouseEnter, + handleCellMouseLeave + } = useTableContextMenu() // 表单引用和数据 const formRef = ref() @@ -315,35 +342,6 @@ prop: 'sort', label: '排序', width: 80 - }, - { - prop: 'operation', - label: '操作', - width: 120, - fixed: 'right', - formatter: (row: PermissionTreeNode) => { - const buttons = [] - - if (hasAuth('permission:edit')) { - buttons.push( - h(ArtButtonTable, { - type: 'edit', - onClick: () => showDialog('edit', row) - }) - ) - } - - if (hasAuth('permission:delete')) { - buttons.push( - h(ArtButtonTable, { - type: 'delete', - onClick: () => deletePermission(row) - }) - ) - } - - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) - } } ]) @@ -557,4 +555,47 @@ onMounted(() => { getPermissionList() }) + + // 右键菜单项配置 + const contextMenuItems = computed((): MenuItemType[] => { + const items: MenuItemType[] = [] + + if (hasAuth('permission:edit')) { + items.push({ key: 'edit', label: '编辑' }) + } + + if (hasAuth('permission:delete')) { + items.push({ key: 'delete', label: '删除' }) + } + + return items + }) + + // 处理表格行右键菜单 + const handleRowContextMenu = (row: PermissionTreeNode, column: any, event: MouseEvent) => { + event.preventDefault() + event.stopPropagation() + currentRow.value = row + contextMenuRef.value?.show(event) + } + + // 处理右键菜单选择 + const handleContextMenuSelect = (item: MenuItemType) => { + if (!currentRow.value) return + + switch (item.key) { + case 'edit': + showDialog('edit', currentRow.value) + break + case 'delete': + deletePermission(currentRow.value) + break + } + } + + diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue index 6ee70d6..c94d028 100644 --- a/src/views/system/role/index.vue +++ b/src/views/system/role/index.vue @@ -32,15 +32,21 @@ :pageSize="pagination.pageSize" :total="pagination.total" :marginTop="10" + :row-class-name="getRowClassName" @size-change="handleSizeChange" @current-change="handleCurrentChange" @row-contextmenu="handleRowContextMenu" + @cell-mouse-enter="handleCellMouseEnter" + @cell-mouse-leave="handleCellMouseLeave" > + + + >() const currentRow = ref(null) + // 使用表格右键菜单功能 + const { + showContextMenuHint, + hintPosition, + getRowClassName, + handleCellMouseEnter, + handleCellMouseLeave + } = useTableContextMenu() + // 搜索表单初始值 const initialSearchState = { role_name: '', @@ -1056,6 +1073,10 @@
暂无提现配置