diff --git a/src/views/account-management/account/index.vue b/src/views/account-management/account/index.vue index a2f9795..5265995 100644 --- a/src/views/account-management/account/index.vue +++ b/src/views/account-management/account/index.vue @@ -86,9 +86,18 @@ 分配角色
{{ currentAccountName }} + + 超级管理员不能分配角色 + + + 平台用户只能分配一个平台角色 + 代理账号只能分配一个客户角色 + + 企业账号只能分配一个客户角色 +
@@ -549,9 +558,15 @@ let roles = allRoles.value // 根据账号类型过滤角色 - if (currentAccountType.value === 3) { + if (currentAccountType.value === 1) { + // 超级管理员:不能分配任何角色 + return [] + } else if (currentAccountType.value === 3) { // 代理账号:只显示客户角色 roles = roles.filter((role) => role.role_type === 2) + } else if (currentAccountType.value === 4) { + // 企业账号:只显示客户角色 + roles = roles.filter((role) => role.role_type === 2) } else if (currentAccountType.value === 2) { // 平台用户:只显示平台角色 roles = roles.filter((role) => role.role_type === 1) @@ -605,21 +620,15 @@ if (rolesToAdd.value.length === 0) return try { - let newRoles: number[] - - // 代理账号只能分配一个角色,会覆盖之前的角色 - if (currentAccountType.value === 3) { - if (rolesToAdd.value.length > 1) { - ElMessage.warning('代理账号只能分配一个角色') - return - } - // 只保留新选择的一个角色 - newRoles = rolesToAdd.value - } else { - // 其他账号类型可以分配多个角色 - newRoles = [...new Set([...selectedRoles.value, ...rolesToAdd.value])] + // 所有账号只能分配一个角色 + if (rolesToAdd.value.length > 1) { + ElMessage.warning('只能分配一个角色') + return } + // 新角色会替换之前的角色 + const newRoles = rolesToAdd.value + await AccountService.assignRolesToAccount(currentAccountId.value, newRoles) selectedRoles.value = newRoles diff --git a/src/views/account-management/enterprise-customer/index.vue b/src/views/account-management/enterprise-customer/index.vue index bcaeedb..1f6099b 100644 --- a/src/views/account-management/enterprise-customer/index.vue +++ b/src/views/account-management/enterprise-customer/index.vue @@ -458,7 +458,7 @@ { prop: 'operation', label: '操作', - width: 280, + width: 190, fixed: 'right', formatter: (row: EnterpriseItem) => { const buttons = [] @@ -481,16 +481,6 @@ ) } - // 只要有编辑、修改密码权限之一,就显示更多操作按钮 - if (hasAuth('enterprise_customer:edit') || hasAuth('enterprise_customer:update_pwd')) { - buttons.push( - h(ArtButtonTable, { - text: '更多操作', - onContextmenu: (e: MouseEvent) => showEnterpriseOperationMenu(e, row) - }) - ) - } - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) } } diff --git a/src/views/asset-management/device-list/index.vue b/src/views/asset-management/device-list/index.vue index d145e23..cc947db 100644 --- a/src/views/asset-management/device-list/index.vue +++ b/src/views/asset-management/device-list/index.vue @@ -358,7 +358,10 @@ -
+
暂无绑定的卡片
@@ -374,7 +377,12 @@ - + - + { try { - const res = await DeviceService.unbindCard( - currentDeviceDetail.value.id, - row.iot_card_id - ) + const res = await DeviceService.unbindCard(currentDeviceDetail.value.id, row.iot_card_id) if (res.code === 0) { ElMessage.success('解绑成功') // 重新加载卡列表 @@ -1070,23 +1081,6 @@ label: '创建时间', width: 180, formatter: (row: Device) => formatDateTime(row.created_at) - }, - { - prop: 'operation', - label: '操作', - width: 120, - fixed: 'right', - formatter: (row: Device) => { - // Show "更多操作" only if user has at least one operation permission - const hasAnyOperationPermission = hasAuth('devices:delete') || hasAuth('devices:look_binding') - if (hasAnyOperationPermission) { - return h(ArtButtonTable, { - text: '更多操作', - onContextmenu: (e: MouseEvent) => showDeviceOperationMenu(e, row.device_no) - }) - } - return null - } } ]) @@ -1105,8 +1099,8 @@ try { const res = await ShopService.getShops({ page: 1, - page_size: 9999, // 获取所有数据用于构建树形结构 - status: 1 // 只获取启用的店铺 + page_size: 9999, // 获取所有数据用于构建树形结构 + status: 1 // 只获取启用的店铺 }) if (res.code === 0) { shopTreeData.value = buildShopTree(res.data.items || []) @@ -1349,7 +1343,7 @@ const params: any = { page: 1, page_size: 20, - status: 1 // 只获取启用的 + status: 1 // 只获取启用的 } if (seriesName) { params.series_name = seriesName @@ -1445,7 +1439,7 @@ // 通过设备号查看卡片 const handleViewCardsByDeviceNo = (deviceNo: string) => { - const device = deviceList.value.find(d => d.device_no === deviceNo) + const device = deviceList.value.find((d) => d.device_no === deviceNo) if (device) { handleViewCards(device) } else { @@ -1456,7 +1450,7 @@ // 通过设备号删除设备 const handleDeleteDeviceByNo = async (deviceNo: string) => { // 先根据设备号找到设备对象 - const device = deviceList.value.find(d => d.device_no === deviceNo) + const device = deviceList.value.find((d) => d.device_no === deviceNo) if (device) { deleteDevice(device) } else { diff --git a/src/views/asset-management/iot-card-management/index.vue b/src/views/asset-management/iot-card-management/index.vue index f68a196..8b33aef 100644 --- a/src/views/asset-management/iot-card-management/index.vue +++ b/src/views/asset-management/iot-card-management/index.vue @@ -1096,18 +1096,6 @@ label: '创建时间', width: 180, formatter: (row: StandaloneIotCard) => formatDateTime(row.created_at) - }, - { - prop: 'operation', - label: '操作', - width: 120, - fixed: 'right', - formatter: (row: StandaloneIotCard) => { - return h(ArtButtonTable, { - text: '更多操作', - onContextmenu: (e: MouseEvent) => showCardOperationMenu(e, row.iccid) - }) - } } ]) diff --git a/src/views/package-management/package-series/index.vue b/src/views/package-management/package-series/index.vue index 97a032c..405a7a7 100644 --- a/src/views/package-management/package-series/index.vue +++ b/src/views/package-management/package-series/index.vue @@ -37,12 +37,36 @@ :marginTop="10" @size-change="handleSizeChange" @current-change="handleCurrentChange" + @row-contextmenu="handleRowContextMenu" > + +
+ +
+ 详情 +
+
+ 编辑 +
+
+ 删除 +
+
+
+ () + // 右键菜单状态 + const contextMenuVisible = ref(false) + const contextMenuPosition = reactive({ x: 0, y: 0 }) + const contextMenuRow = ref(null) + // 搜索表单初始值 const initialSearchState = { series_name: '', @@ -456,8 +485,7 @@ { label: '强充计算类型', prop: 'force_calc_type' }, { label: '时效类型', prop: 'validity_type' }, { label: '状态', prop: 'status' }, - { label: '创建时间', prop: 'created_at' }, - { label: '操作', prop: 'operation' } + { label: '创建时间', prop: 'created_at' } ] // 表单验证规则 @@ -675,50 +703,34 @@ label: '创建时间', width: 180, formatter: (row: PackageSeriesResponse) => formatDateTime(row.created_at) - }, - { - prop: 'operation', - label: '操作', - width: 220, - fixed: 'right', - formatter: (row: PackageSeriesResponse) => { - const buttons = [] - - // 详情按钮 - buttons.push( - h(ArtButtonTable, { - text: '详情', - onClick: () => handleViewDetail(row) - }) - ) - - if (hasAuth('package_series:edit')) { - buttons.push( - h(ArtButtonTable, { - text: '编辑', - onClick: () => showDialog('edit', row) - }) - ) - } - - if (hasAuth('package_series:delete')) { - buttons.push( - h(ArtButtonTable, { - text: '删除', - onClick: () => deleteSeries(row) - }) - ) - } - - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) - } } ]) onMounted(() => { getTableData() + // 添加全局点击事件监听,关闭右键菜单 + document.addEventListener('click', closeContextMenu) }) + onBeforeUnmount(() => { + // 移除全局点击事件监听 + document.removeEventListener('click', closeContextMenu) + }) + + // 处理右键菜单 + const handleRowContextMenu = (row: PackageSeriesResponse, column: any, event: MouseEvent) => { + event.preventDefault() + contextMenuRow.value = row + contextMenuPosition.x = event.clientX + contextMenuPosition.y = event.clientY + contextMenuVisible.value = true + } + + // 关闭右键菜单 + const closeContextMenu = () => { + contextMenuVisible.value = false + } + // 获取套餐系列列表 const getTableData = async () => { loading.value = true @@ -1046,4 +1058,35 @@ .dialog-footer { text-align: right; } + + .context-menu { + min-width: 120px; + padding: 4px 0; + background: white; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); + + :deep(.el-card__body) { + padding: 0; + } + + .context-menu-item { + padding: 10px 20px; + cursor: pointer; + transition: background-color 0.2s; + font-size: 14px; + color: var(--el-text-color-primary); + + &:hover { + background-color: var(--el-fill-color-light); + } + + &.danger { + color: var(--el-color-danger); + + &:hover { + background-color: var(--el-color-danger-light-9); + } + } + } + } diff --git a/src/views/product/shop/index.vue b/src/views/product/shop/index.vue index 2de6e5a..f865012 100644 --- a/src/views/product/shop/index.vue +++ b/src/views/product/shop/index.vue @@ -181,7 +181,9 @@ :label="role.role_name" :value="role.ID" > -
+
{{ role.role_name }} 客户角色
@@ -623,7 +625,7 @@ { prop: 'operation', label: '操作', - width: 200, + width: 110, fixed: 'right', formatter: (row: ShopResponse) => { const buttons = [] @@ -637,16 +639,6 @@ ) } - // 只要有编辑或删除权限之一,就显示更多操作按钮 - if (hasAuth('shop:edit') || hasAuth('shop:delete')) { - buttons.push( - h(ArtButtonTable, { - text: '更多操作', - onContextmenu: (e: MouseEvent) => showShopOperationMenu(e, row) - }) - ) - } - return h('div', { style: 'display: flex; gap: 8px;' }, buttons) } } @@ -855,9 +847,7 @@ { len: 11, message: '手机号必须为 11 位', trigger: 'blur' }, { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' } ], - default_role_id: [ - { required: true, message: '请选择默认角色', trigger: 'blur' } - ] + default_role_id: [{ required: true, message: '请选择默认角色', trigger: 'blur' }] }) // 提交表单 @@ -1048,9 +1038,8 @@ const showAddRoleDialog = async () => { addRoleDialogVisible.value = true // 如果已有默认角色,预选第一个 - selectedRoleId.value = currentDefaultRoles.value.length > 0 - ? currentDefaultRoles.value[0].role_id - : undefined + selectedRoleId.value = + currentDefaultRoles.value.length > 0 ? currentDefaultRoles.value[0].role_id : undefined await loadAvailableRoles() } diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue index 921f9b1..2d68bc5 100644 --- a/src/views/system/role/index.vue +++ b/src/views/system/role/index.vue @@ -734,15 +734,15 @@ const getLeftCheckedKeysWithHalf = (): number[] => { if (!leftTreeRef.value) return [] const checkedKeys = leftTreeRef.value.getCheckedKeys(false) - const parentIds = new Set() + const allIds = new Set(checkedKeys) // 为每个勾选的节点找到所有父节点 checkedKeys.forEach((key: number) => { const parents = getParentNodeIds(key) - parents.forEach(parentId => parentIds.add(parentId)) + parents.forEach(parentId => allIds.add(parentId)) }) - return [...checkedKeys, ...Array.from(parentIds)] + return Array.from(allIds) } // 添加权限