From d43de4cd06c74b0f4910b43bd53c3cc160e7af28 Mon Sep 17 00:00:00 2001 From: sexygoat <1538832180@qq.com> Date: Wed, 11 Mar 2026 17:09:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 4 +- .../core/others/TableContextMenuHint.vue | 38 + src/components/core/tables/ArtTable.vue | 20 +- src/composables/useTableContextMenu.ts | 63 ++ src/locales/langs/en.json | 6 +- src/locales/langs/zh.json | 6 +- src/router/routes/asyncRoutes.ts | 196 +++-- src/types/components.d.ts | 3 + .../account-management/account/index.vue | 21 + .../enterprise-cards/index.vue | 22 + .../enterprise-customer/index.vue | 23 + .../asset-management/asset-assign/index.vue | 22 + .../authorization-records/index.vue | 22 + .../asset-management/device-detail/index.vue | 446 ---------- .../asset-management/device-list/index.vue | 26 +- .../asset-management/device-task/index.vue | 22 + .../iot-card-management/detail.vue | 312 ------- .../iot-card-management/index.vue | 36 +- .../asset-management/iot-card-task/index.vue | 22 + src/views/dashboard/analysis/index.vue | 23 +- src/views/dashboard/analysis/style.scss | 2 +- .../analysis/widget/CommissionSummary.vue | 175 ++++ .../analysis/widget/WithdrawalSettings.vue | 223 +++++ .../finance/carrier-management/index.vue | 103 ++- .../commission/agent-commission/index.vue | 21 + .../commission/my-commission/index.vue | 117 +-- .../commission/withdrawal-settings/index.vue | 191 +--- src/views/my-simcard/single-card/index.vue | 807 ++++++++--------- .../order-management/order-list/index.vue | 21 + .../package-management/package-list/index.vue | 21 + .../package-series/index.vue | 23 +- .../series-grants/detail.vue | 15 +- .../series-grants/index.vue | 829 ++++++++++++++++-- src/views/product/shop/index.vue | 21 + src/views/system/permission/index.vue | 105 ++- src/views/system/role/index.vue | 21 + update_context_menu.py | 220 +++++ 37 files changed, 2552 insertions(+), 1696 deletions(-) create mode 100644 src/components/core/others/TableContextMenuHint.vue create mode 100644 src/composables/useTableContextMenu.ts delete mode 100644 src/views/asset-management/device-detail/index.vue delete mode 100644 src/views/asset-management/iot-card-management/detail.vue create mode 100644 src/views/dashboard/analysis/widget/CommissionSummary.vue create mode 100644 src/views/dashboard/analysis/widget/WithdrawalSettings.vue create mode 100644 update_context_menu.py 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 @@ + + + + + + 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" > + + + + + + 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 @@ - - - - - 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" > + + + { 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 @@ - - - - - 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" > + + + { 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 @@