fetch(modify):完善按钮权限
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m25s

This commit is contained in:
sexygoat
2026-02-03 17:20:50 +08:00
parent de9753f42d
commit 192c6f1d26
22 changed files with 885 additions and 232 deletions

View File

@@ -102,6 +102,7 @@
import type { FormInstance, FormRules } from 'element-plus'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { formatDateTime } from '@/utils/business/format'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import type {
@@ -113,6 +114,7 @@
defineOptions({ name: 'AuthorizationRecords' })
const { hasAuth } = useAuth()
const router = useRouter()
const loading = ref(false)
const detailDialogVisible = ref(false)
@@ -297,16 +299,25 @@
width: 150,
fixed: 'right',
formatter: (row: AuthorizationItem) => {
return h('div', { style: 'display: flex; gap: 8px;' }, [
const buttons = []
buttons.push(
h(ArtButtonTable, {
text: '详情',
onClick: () => viewDetail(row)
}),
h(ArtButtonTable, {
type: 'edit',
onClick: () => showRemarkDialog(row)
})
])
)
if (hasAuth('authorization_records:update_remark')) {
buttons.push(
h(ArtButtonTable, {
type: 'edit',
onClick: () => showRemarkDialog(row)
})
)
}
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
}
}
])

View File

@@ -21,13 +21,23 @@
type="primary"
@click="handleBatchAllocate"
:disabled="!selectedDevices.length"
v-permission="'devices:batch_allocation'"
>
批量分配
</ElButton>
<ElButton @click="handleBatchRecall" :disabled="!selectedDevices.length">
<ElButton
@click="handleBatchRecall"
:disabled="!selectedDevices.length"
v-permission="'devices:batch_recycle'"
>
批量回收
</ElButton>
<ElButton type="info" @click="handleBatchSetSeries" :disabled="!selectedDevices.length">
<ElButton
type="info"
@click="handleBatchSetSeries"
:disabled="!selectedDevices.length"
v-permission="'devices:batch_setting'"
>
批量设置套餐系列
</ElButton>
</template>
@@ -546,6 +556,7 @@
} from '@/types/api'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
@@ -555,6 +566,7 @@
defineOptions({ name: 'DeviceList' })
const { hasAuth } = useAuth()
const router = useRouter()
const loading = ref(false)
const allocateLoading = ref(false)
@@ -1064,16 +1076,29 @@
width: 200,
fixed: 'right',
formatter: (row: Device) => {
return h('div', { style: 'display: flex; gap: 0; align-items: center;' }, [
h(ArtButtonTable, {
text: '查看卡片',
onClick: () => handleViewCards(row)
}),
h(ArtButtonTable, {
text: '更多操作',
onContextmenu: (e: MouseEvent) => showDeviceOperationMenu(e, row.device_no)
})
])
const buttons = []
if (hasAuth('devices:look_binding')) {
buttons.push(
h(ArtButtonTable, {
text: '查看卡片',
onClick: () => handleViewCards(row)
})
)
}
// Show "更多操作" only if user has at least one operation permission
const hasAnyOperationPermission = hasAuth('devices:delete')
if (hasAnyOperationPermission) {
buttons.push(
h(ArtButtonTable, {
text: '更多操作',
onContextmenu: (e: MouseEvent) => showDeviceOperationMenu(e, row.device_no)
})
)
}
return h('div', { style: 'display: flex; gap: 0; align-items: center;' }, buttons)
}
}
])
@@ -1602,32 +1627,39 @@
}
// 设备操作菜单项配置
const deviceOperationMenuItems = computed((): MenuItemType[] => [
{
key: 'reboot',
label: '重启设备'
},
{
key: 'reset',
label: '恢复出厂'
},
{
key: 'speed-limit',
label: '设置限速'
},
{
key: 'switch-card',
label: '切换SIM卡'
},
{
key: 'set-wifi',
label: '设置WiFi'
},
{
key: 'delete',
label: '删除设备'
const deviceOperationMenuItems = computed((): MenuItemType[] => {
const items: MenuItemType[] = [
{
key: 'reboot',
label: '重启设备'
},
{
key: 'reset',
label: '恢复出厂'
},
{
key: 'speed-limit',
label: '设置限速'
},
{
key: 'switch-card',
label: '切换SIM卡'
},
{
key: 'set-wifi',
label: '设置WiFi'
}
]
if (hasAuth('devices:delete')) {
items.push({
key: 'delete',
label: '删除设备'
})
}
])
return items
})
// 显示设备操作菜单
const showDeviceOperationMenu = (e: MouseEvent, deviceNo: string) => {

View File

@@ -18,7 +18,12 @@
@refresh="handleRefresh"
>
<template #left>
<ElButton type="primary" :icon="Upload" @click="importDialogVisible = true">
<ElButton
type="primary"
:icon="Upload"
@click="importDialogVisible = true"
v-permission="'device_task:bulk_import'"
>
批量导入设备
</ElButton>
</template>
@@ -215,6 +220,7 @@
import type { UploadInstance } from 'element-plus'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { formatDateTime } from '@/utils/business/format'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import { StorageService } from '@/api/modules/storage'
@@ -222,6 +228,7 @@
defineOptions({ name: 'DeviceTask' })
const { hasAuth } = useAuth()
const loading = ref(false)
const tableRef = ref()
const uploadRef = ref<UploadInstance>()

View File

@@ -22,6 +22,7 @@
type="success"
:disabled="selectedCards.length === 0"
@click="showAllocateDialog"
v-permission="'iot_card:batch_allocation'"
>
批量分配
</ElButton>
@@ -29,6 +30,7 @@
type="warning"
:disabled="selectedCards.length === 0"
@click="showRecallDialog"
v-permission="'iot_card:batch_recycle'"
>
批量回收
</ElButton>
@@ -36,10 +38,17 @@
type="primary"
:disabled="selectedCards.length === 0"
@click="showSeriesBindingDialog"
v-permission="'iot_card:batch_setting'"
>
批量设置套餐系列
</ElButton>
<ElButton type="info" @contextmenu.prevent="showMoreMenu">更多操作</ElButton>
<ElButton
v-if="hasAuth('iot_card:batch_recharge') || hasAuth('iot_card:network_distribution') || hasAuth('iot_card:network_recycle') || hasAuth('iot_card:change_package')"
type="info"
@contextmenu.prevent="showMoreMenu"
>
更多操作
</ElButton>
</template>
</ArtTableHeader>
@@ -595,6 +604,7 @@
import QRCode from 'qrcode'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { formatDateTime } from '@/utils/business/format'
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
@@ -611,6 +621,7 @@
defineOptions({ name: 'StandaloneCardList' })
const { hasAuth } = useAuth()
const router = useRouter()
const loading = ref(false)
const allocateDialogVisible = ref(false)
@@ -1513,28 +1524,44 @@
}
// 更多操作菜单项配置
const moreMenuItems = computed((): MenuItemType[] => [
{
key: 'distribution',
label: '网卡分销'
},
{
key: 'recharge',
label: '批量充值'
},
{
key: 'recycle',
label: '网卡回收'
},
{
const moreMenuItems = computed((): MenuItemType[] => {
const items: MenuItemType[] = []
if (hasAuth('iot_card:network_distribution')) {
items.push({
key: 'distribution',
label: '网卡分销'
})
}
if (hasAuth('iot_card:batch_recharge')) {
items.push({
key: 'recharge',
label: '批量充值'
})
}
if (hasAuth('iot_card:network_recycle')) {
items.push({
key: 'recycle',
label: '网卡回收'
})
}
items.push({
key: 'download',
label: '批量下载'
},
{
key: 'changePackage',
label: '变更套餐'
})
if (hasAuth('iot_card:change_package')) {
items.push({
key: 'changePackage',
label: '变更套餐'
})
}
])
return items
})
// 卡操作菜单项配置
const cardOperationMenuItems = computed((): MenuItemType[] => [

View File

@@ -18,7 +18,12 @@
@refresh="handleRefresh"
>
<template #left>
<ElButton type="primary" :icon="Upload" @click="importDialogVisible = true">
<ElButton
type="primary"
:icon="Upload"
@click="importDialogVisible = true"
v-permission="'lot_task:bulk_import'"
>
批量导入IoT卡
</ElButton>
</template>
@@ -212,6 +217,7 @@
import type { UploadInstance } from 'element-plus'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { formatDateTime } from '@/utils/business/format'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import { StorageService } from '@/api/modules/storage'
@@ -220,6 +226,7 @@
defineOptions({ name: 'IotCardTask' })
const { hasAuth } = useAuth()
const loading = ref(false)
const tableRef = ref()
const uploadRef = ref<UploadInstance>()