Files
one-pipe-system/src/views/asset-management/enterprise-devices/index.vue
sexygoat e04a283319
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m38s
fix: 新增代理系列授权-建议售价使用套餐
2026-06-12 10:41:37 +08:00

1080 lines
30 KiB
Vue

<template>
<ArtTableFullScreen>
<div class="enterprise-devices-page" id="table-full-screen">
<!-- 企业信息卡片 -->
<ElCard shadow="never" class="enterprise-info-card">
<template #header>
<div class="card-header">
<ElButton @click="goBack">{{ $t('common.back') }}</ElButton>
<span>企业设备列表</span>
<span v-if="enterpriseInfo"> - {{ enterpriseInfo.enterprise_name }}</span>
</div>
</template>
</ElCard>
<!-- 搜索栏 -->
<ArtSearchBar
v-model:filter="searchForm"
:items="searchFormItems"
:show-expand="false"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
<ElCard shadow="never" class="art-table-card">
<!-- 表格头部 -->
<ArtTableHeader
:columnList="columnOptions"
v-model:columns="columnChecks"
@refresh="handleRefresh"
>
<template #left>
<ElButton
type="primary"
@click="showAllocateDialog"
v-permission="'enterprise_device:allocate'"
>
授权设备
</ElButton>
<ElButton
type="warning"
:disabled="selectedDevices.length === 0"
@click="showRecallDialog"
v-permission="'enterprise_device:recall'"
>
撤销授权
</ElButton>
</template>
</ArtTableHeader>
<!-- 表格 -->
<ArtTable
ref="tableRef"
row-key="device_id"
:loading="loading"
:data="deviceList"
:currentPage="pagination.page"
:pageSize="pagination.pageSize"
:total="pagination.total"
:marginTop="10"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@selection-change="handleSelectionChange"
>
<template #default>
<ElTableColumn type="selection" width="55" />
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
</template>
</ArtTable>
<!-- 授权设备对话框 -->
<ElDialog
v-model="allocateDialogVisible"
title="授权设备给企业"
width="75%"
@close="handleAllocateDialogClose"
>
<!-- 搜索过滤条件 -->
<ArtSearchBar
v-model:filter="deviceSearchForm"
:items="deviceSearchFormItems"
label-width="85"
show-expand
@reset="handleDeviceSearchReset"
@search="handleDeviceSearch"
></ArtSearchBar>
<!-- 设备列表 -->
<div
class="device-selection-info"
style="display: flex; align-items: center; justify-content: space-between"
>
<span>已选择 {{ selectedAvailableDevices.length }} 台设备</span>
<ElButton
type="primary"
@click="handleAllocate"
:loading="allocateLoading"
:disabled="selectedAvailableDevices.length === 0"
>
{{ $t('common.confirm') }}
</ElButton>
</div>
<ArtTable
ref="availableDevicesTableRef"
row-key="id"
:loading="availableDevicesLoading"
:data="availableDevicesList"
:currentPage="devicePagination.page"
:pageSize="devicePagination.pageSize"
:total="devicePagination.total"
:marginTop="10"
height="40vh"
@size-change="handleDevicePageSizeChange"
@current-change="handleDevicePageChange"
@selection-change="handleAvailableDevicesSelectionChange"
>
<template #default>
<ElTableColumn type="selection" width="55" :selectable="checkDeviceSelectable" />
<ElTableColumn
v-for="col in availableDeviceColumns"
:key="col.prop || col.type"
v-bind="col"
/>
</template>
</ArtTable>
</ElDialog>
<!-- 撤销授权对话框 -->
<ElDialog
v-model="recallDialogVisible"
title="撤销设备授权"
width="600px"
@close="handleRecallDialogClose"
>
<ElForm ref="recallFormRef" :model="recallForm" :rules="recallRules">
<ElFormItem label="已选择设备">
<div>已选择 {{ selectedDevices.length }} 个设备</div>
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="recallDialogVisible = false">{{ $t('common.cancel') }}</ElButton>
<ElButton type="primary" @click="handleRecall" :loading="recallLoading">
{{ $t('common.confirm') }}
</ElButton>
</div>
</template>
</ElDialog>
<!-- 结果对话框 -->
<ElDialog v-model="resultDialogVisible" title="操作结果" width="700px">
<ElDescriptions :column="2" border>
<ElDescriptionsItem label="成功数量">
<ElTag type="success">{{ operationResult.success_count }}</ElTag>
</ElDescriptionsItem>
<ElDescriptionsItem label="失败数量">
<ElTag type="danger">{{ operationResult.fail_count }}</ElTag>
</ElDescriptionsItem>
</ElDescriptions>
<!-- 失败项详情 -->
<div
v-if="operationResult.failed_items && operationResult.failed_items.length > 0"
style="margin-top: 20px"
>
<ElDivider content-position="left">失败项</ElDivider>
<ElTable :data="operationResult.failed_items" border max-height="300">
<ElTableColumn prop="virtual_no" label="设备号" width="180" />
<ElTableColumn prop="reason" label="失败原因" />
</ElTable>
</div>
<!-- 显示已授权设备 -->
<div
v-if="
operationResult.authorized_devices && operationResult.authorized_devices.length > 0
"
style="margin-top: 20px"
>
<ElDivider content-position="left">已授权设备</ElDivider>
<ElTable :data="operationResult.authorized_devices" border max-height="200">
<ElTableColumn prop="virtual_no" label="设备号" width="180" />
<ElTableColumn label="绑定卡数">
<template #default="{ row }">
{{ row.card_count || 0 }}
</template>
</ElTableColumn>
</ElTable>
</div>
<template #footer>
<div class="dialog-footer">
<ElButton type="primary" @click="resultDialogVisible = false">{{
$t('common.confirm')
}}</ElButton>
</div>
</template>
</ElDialog>
</ElCard>
</div>
</ArtTableFullScreen>
</template>
<script setup lang="ts">
import { h } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import {
EnterpriseService,
DeviceService,
CardService,
ShopService,
PackageSeriesService
} from '@/api/modules'
import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { formatDateTime } from '@/utils/business/format'
import type {
EnterpriseDeviceItem,
AllocateDevicesResponse,
RecallDevicesResponse
} from '@/types/api/enterpriseDevice'
import type { EnterpriseItem } from '@/types/api'
import type { Device, DeviceStatus } from '@/types/api/device'
defineOptions({ name: 'EnterpriseDevices' })
const { t } = useI18n() // 仅保留用于 common.confirm, common.cancel
const route = useRoute()
const router = useRouter()
const loading = ref(false)
const allocateDialogVisible = ref(false)
const allocateLoading = ref(false)
const recallDialogVisible = ref(false)
const recallLoading = ref(false)
const resultDialogVisible = ref(false)
const tableRef = ref()
const recallFormRef = ref<FormInstance>()
const selectedDevices = ref<EnterpriseDeviceItem[]>([])
const enterpriseId = ref<number>(0)
const enterpriseInfo = ref<EnterpriseItem | null>(null)
const operationResult = ref<AllocateDevicesResponse | RecallDevicesResponse>({
success_count: 0,
fail_count: 0,
failed_items: null,
authorized_devices: null
})
// 可用设备列表相关
const availableDevicesTableRef = ref()
const availableDevicesLoading = ref(false)
const availableDevicesList = ref<Device[]>([])
const selectedAvailableDevices = ref<Device[]>([])
const allocatedDeviceVirtualNos = ref<Set<string>>(new Set())
// 远程搜索相关
const searchSeriesOptions = ref<any[]>([])
const searchBatchNoOptions = ref<any[]>([])
const seriesLoading = ref(false)
const shopOptions = ref<any[]>([])
// 设备搜索表单初始值
const initialDeviceSearchState = {
virtual_no: '',
device_name: '',
activation_status: undefined as number | undefined,
device_type: '',
manufacturer: '',
batch_no: undefined,
shop_id: undefined,
series_id: undefined,
dateRange: undefined
}
const deviceSearchForm = reactive({ ...initialDeviceSearchState })
const devicePagination = reactive({
page: 1,
pageSize: 20,
total: 0
})
// 搜索表单初始值
const initialSearchState = {
virtual_no: ''
}
// 搜索表单
const searchForm = reactive({ ...initialSearchState })
// 撤销表单
const recallForm = reactive({})
// 撤销表单验证规则
const recallRules = reactive<FormRules>({})
// 分页
const pagination = reactive({
page: 1,
pageSize: 20,
total: 0
})
// 搜索表单配置
const searchFormItems: SearchFormItem[] = [
{
label: '设备号',
prop: 'virtual_no',
type: 'input',
config: {
clearable: true,
placeholder: '请输入设备号'
}
}
]
// 设备列表搜索表单配置
const deviceSearchFormItems: SearchFormItem[] = [
{
label: '设备号',
prop: 'virtual_no',
type: 'input',
config: {
clearable: true,
placeholder: '请输入设备号'
}
},
{
label: '设备名称',
prop: 'device_name',
type: 'input',
config: {
clearable: true,
placeholder: '请输入设备名称'
}
},
{
label: '激活状态',
prop: 'activation_status',
type: 'select',
config: {
clearable: true,
placeholder: '请选择激活状态'
},
options: () => [
{ label: '未激活', value: 0 },
{ label: '已激活', value: 1 }
]
},
{
label: '批次号',
prop: 'batch_no',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => handleSearchBatchNo(query),
loading: false,
placeholder: '请选择或搜索批次号'
},
options: () =>
searchBatchNoOptions.value.map((b) => ({
label: b.batch_no,
value: b.batch_no
}))
},
{
label: '设备类型',
prop: 'device_type',
type: 'input',
config: {
clearable: true,
placeholder: '请输入设备类型'
}
},
{
label: '制造商',
prop: 'manufacturer',
type: 'input',
config: {
clearable: true,
placeholder: '请输入制造商'
}
},
{
label: '店铺名称',
prop: 'shop_id',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => searchShops(query),
loading: false,
placeholder: '请选择或搜索店铺名称'
},
options: () =>
shopOptions.value.map((shop) => ({
label: shop.shop_name,
value: shop.id
}))
},
{
label: '套餐系列',
prop: 'series_id',
type: 'select',
config: {
clearable: true,
filterable: true,
remote: true,
remoteMethod: (query: string) => searchSeries(query),
loading: seriesLoading.value,
placeholder: '请选择或搜索套餐系列'
},
options: () =>
searchSeriesOptions.value.map((s) => ({
label: s.series_name,
value: s.id
}))
},
{
label: '起始至结束',
prop: 'dateRange',
type: 'date',
config: {
type: 'daterange',
rangeSeparator: '至',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
valueFormat: 'YYYY-MM-DD'
}
}
]
// 列配置
const columnOptions = [
{ label: '设备ID', prop: 'device_id' },
{ label: '设备号', prop: 'virtual_no' },
{ label: '设备名称', prop: 'device_name' },
{ label: '设备型号', prop: 'device_model' },
{ label: '绑定卡数量', prop: 'card_count' },
{ label: '授权时间', prop: 'authorized_at' }
]
const deviceList = ref<EnterpriseDeviceItem[]>([])
// 获取设备状态标签类型
const getDeviceStatusTag = (status: DeviceStatus) => {
switch (status) {
case 1:
return 'info'
case 2:
return 'warning'
case 3:
return 'success'
case 4:
return 'danger'
default:
return 'info'
}
}
// 获取设备状态文本
const getDeviceStatusText = (status: DeviceStatus) => {
switch (status) {
case 1:
return '在库'
case 2:
return '已分销'
case 3:
return '已激活'
case 4:
return '已停用'
default:
return '未知'
}
}
// 动态列配置
const { columnChecks, columns } = useCheckedColumns(() => [
{
prop: 'virtual_no',
label: '设备号',
minWidth: 150,
showOverflowTooltip: true
},
{
prop: 'imei',
label: 'IMEI',
minWidth: 150,
showOverflowTooltip: true,
formatter: (row: EnterpriseDeviceItem) => (row as any).imei || '-'
},
{
prop: 'device_name',
label: '设备名称',
minWidth: 150,
showOverflowTooltip: true
},
{
prop: 'shop_name',
label: '店铺名称',
minWidth: 150,
formatter: (row: EnterpriseDeviceItem) => (row as any).shop_name || '-'
},
{
prop: 'series_name',
label: '套餐系列',
minWidth: 150,
formatter: (row: EnterpriseDeviceItem) => (row as any).series_name || '-'
},
{
prop: 'device_model',
label: '设备型号',
minWidth: 120
},
{
prop: 'device_type',
label: '设备类型',
width: 120,
formatter: (row: EnterpriseDeviceItem) => (row as any).device_type || '-'
},
{
prop: 'status',
label: '状态',
width: 100,
formatter: (row: EnterpriseDeviceItem) => {
return h(ElTag, { type: getDeviceStatusTag(row.status) }, () =>
getDeviceStatusText(row.status)
)
}
},
{
prop: 'online_status',
label: '在线状态',
width: 100,
formatter: (row: EnterpriseDeviceItem) => {
const onlineStatusMap: Record<number, { text: string; type: any }> = {
0: { text: '未知', type: 'info' },
1: { text: '在线', type: 'success' },
2: { text: '离线', type: 'danger' }
}
const status = onlineStatusMap[(row as any).online_status ?? 0] || {
text: '未知',
type: 'info'
}
return h(ElTag, { type: status.type }, () => status.text)
}
},
{
prop: 'manufacturer',
label: '制造商',
minWidth: 100,
formatter: (row: EnterpriseDeviceItem) => (row as any).manufacturer || '-'
},
{
prop: 'bound_card_count',
label: '已绑定卡数',
width: 110,
formatter: (row: EnterpriseDeviceItem) => {
const count = (row as any).bound_card_count ?? 0
const color = count > 0 ? '#67c23a' : '#909399'
return h('span', { style: { color, fontWeight: 'bold' } }, count)
}
},
{
prop: 'sn',
label: '序列号',
minWidth: 120,
showOverflowTooltip: true,
formatter: (row: EnterpriseDeviceItem) => (row as any).sn || '-'
},
{
prop: 'batch_no',
label: '批次号',
minWidth: 180,
showOverflowTooltip: true,
formatter: (row: EnterpriseDeviceItem) => (row as any).batch_no || '-'
},
{
prop: 'card_count',
label: '绑定卡数量',
width: 100
},
{
prop: 'authorized_at',
label: '授权时间',
width: 180,
formatter: (row: EnterpriseDeviceItem) =>
row.authorized_at ? formatDateTime(row.authorized_at) : '-'
}
])
// 可用设备列表列配置
const availableDeviceColumns = computed(() => [
{
prop: 'virtual_no',
label: '设备号',
minWidth: 150,
showOverflowTooltip: true
},
{
prop: 'imei',
label: 'IMEI',
minWidth: 150,
showOverflowTooltip: true,
formatter: (row: Device) => row.imei || '-'
},
{
prop: 'device_name',
label: '设备名称',
minWidth: 150,
showOverflowTooltip: true
},
{
prop: 'shop_name',
label: '店铺名称',
minWidth: 150
},
{
prop: 'series_name',
label: '套餐系列',
minWidth: 150
},
{
prop: 'device_model',
label: '设备型号',
minWidth: 120
},
{
prop: 'device_type',
label: '设备类型',
width: 120
},
{
prop: 'status',
label: '状态',
width: 100,
formatter: (row: Device) => {
return h(ElTag, { type: getDeviceStatusTag(row.status) }, () =>
getDeviceStatusText(row.status)
)
}
},
{
prop: 'activation_status_name',
label: '激活状态',
width: 120,
formatter: (row: Device) => row.activation_status_name || '-'
},
{
prop: 'online_status',
label: '在线状态',
width: 100,
formatter: (row: Device) => {
const onlineStatusMap: Record<number, { text: string; type: any }> = {
0: { text: '未知', type: 'info' },
1: { text: '在线', type: 'success' },
2: { text: '离线', type: 'danger' }
}
const status = onlineStatusMap[row.online_status ?? 0] || { text: '未知', type: 'info' }
return h(ElTag, { type: status.type }, () => status.text)
}
},
{
prop: 'manufacturer',
label: '制造商',
minWidth: 100
},
{
prop: 'bound_card_count',
label: '已绑定卡数',
width: 110,
formatter: (row: Device) => {
const color = row.bound_card_count > 0 ? '#67c23a' : '#909399'
return h('span', { style: { color, fontWeight: 'bold' } }, row.bound_card_count)
}
},
{
prop: 'sn',
label: '序列号',
minWidth: 120,
showOverflowTooltip: true,
formatter: (row: Device) => row.sn || '-'
},
{
prop: 'batch_no',
label: '批次号',
minWidth: 180,
showOverflowTooltip: true,
formatter: (row: Device) => row.batch_no || '-'
}
])
onMounted(() => {
const id = route.query.id
if (id) {
enterpriseId.value = Number(id)
getEnterpriseInfo()
getTableData()
} else {
ElMessage.error('加载设备列表失败')
goBack()
}
})
// 获取企业信息
const getEnterpriseInfo = async () => {
try {
const res = await EnterpriseService.getEnterprises({
page: 1,
page_size: 1,
id: enterpriseId.value
})
if (res.code === 0 && res.data.items && res.data.items.length > 0) {
enterpriseInfo.value = res.data.items[0]
}
} catch (error) {
console.error('获取企业信息失败:', error)
}
}
// 获取企业设备列表
const getTableData = async () => {
loading.value = true
try {
const params: any = {
page: pagination.page,
page_size: pagination.pageSize,
virtual_no: searchForm.virtual_no || undefined
}
// 清理空值
Object.keys(params).forEach((key) => {
if (params[key] === '' || params[key] === undefined) {
delete params[key]
}
})
const res = await EnterpriseService.getEnterpriseDevices(enterpriseId.value, params)
if (res.code === 0) {
deviceList.value = res.data.items || []
pagination.total = res.data.total || 0
}
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
// 重置搜索
const handleReset = () => {
Object.assign(searchForm, { ...initialSearchState })
pagination.page = 1
getTableData()
}
// 搜索
const handleSearch = () => {
pagination.page = 1
getTableData()
}
// 刷新表格
const handleRefresh = () => {
getTableData()
}
// 处理表格分页变化
const handleSizeChange = (newPageSize: number) => {
pagination.pageSize = newPageSize
getTableData()
}
const handleCurrentChange = (newCurrentPage: number) => {
pagination.page = newCurrentPage
getTableData()
}
// 表格选择变化
const handleSelectionChange = (selection: EnterpriseDeviceItem[]) => {
selectedDevices.value = selection
}
// 返回
const goBack = () => {
router.back()
}
// 获取可用设备列表
const getAvailableDevicesList = async () => {
availableDevicesLoading.value = true
try {
const params: any = {
page: devicePagination.page,
page_size: devicePagination.pageSize,
...deviceSearchForm,
status: 2
}
// 清理空值
Object.keys(params).forEach((key) => {
if (params[key] === '' || params[key] === undefined) {
delete params[key]
}
})
const res = await DeviceService.getDevices(params)
if (res.code === 0) {
availableDevicesList.value = res.data.items || []
devicePagination.total = res.data.total || 0
}
} catch (error) {
console.error(error)
} finally {
availableDevicesLoading.value = false
}
}
// 处理设备列表选择变化
const handleAvailableDevicesSelectionChange = (selection: Device[]) => {
selectedAvailableDevices.value = selection
}
// 设备列表搜索
const handleDeviceSearch = () => {
devicePagination.page = 1
getAvailableDevicesList()
}
// 设备列表重置
const handleDeviceSearchReset = () => {
Object.assign(deviceSearchForm, { ...initialDeviceSearchState })
devicePagination.page = 1
getAvailableDevicesList()
}
// 搜索批次号
const handleSearchBatchNo = async (query: string) => {
try {
const params: any = { page: 1, page_size: 20 }
if (query) {
params.batch_no = query
}
const res = await CardService.getIotCardImportTasks(params)
if (res.code === 0) {
searchBatchNoOptions.value = res.data.items || []
}
} catch (error) {
console.error(error)
}
}
// 搜索店铺
const searchShops = async (query: string) => {
try {
const params: any = { page: 1, page_size: 20 }
if (query) {
params.shop_name = query
}
const res = await ShopService.getShops(params)
if (res.code === 0) {
shopOptions.value = res.data.items || []
}
} catch (error) {
console.error(error)
}
}
// 搜索套餐系列
const searchSeries = async (query: string) => {
seriesLoading.value = true
try {
const params: any = { page: 1, page_size: 20, status: 1 }
if (query) {
params.series_name = query
}
const res = await PackageSeriesService.getPackageSeries(params)
if (res.code === 0) {
searchSeriesOptions.value = res.data.items || []
}
} catch (error) {
console.error(error)
} finally {
seriesLoading.value = false
}
}
// 设备列表分页大小变化
const handleDevicePageSizeChange = (newPageSize: number) => {
devicePagination.pageSize = newPageSize
getAvailableDevicesList()
}
// 设备列表页码变化
const handleDevicePageChange = (newPage: number) => {
devicePagination.page = newPage
getAvailableDevicesList()
}
// 检查设备是否可选(已授权的设备不可选)
const checkDeviceSelectable = (row: Device) => {
return !allocatedDeviceVirtualNos.value.has(row.virtual_no)
}
// 显示授权对话框
const showAllocateDialog = async () => {
allocateDialogVisible.value = true
selectedAvailableDevices.value = []
// 收集已授权的设备的 virtual_no
allocatedDeviceVirtualNos.value = new Set(deviceList.value.map((device) => device.virtual_no))
// 重置搜索条件
Object.assign(deviceSearchForm, { ...initialDeviceSearchState })
devicePagination.page = 1
devicePagination.pageSize = 20
// 预加载下拉选项
await handleSearchBatchNo('')
await searchShops('')
await searchSeries('')
// 加载可用设备列表
await getAvailableDevicesList()
// 预选已授权的设备
const preSelectedDevices = availableDevicesList.value.filter((device) =>
allocatedDeviceVirtualNos.value.has(device.virtual_no)
)
selectedAvailableDevices.value = preSelectedDevices
// 等待表格渲染完成后,设置已选项
await nextTick(() => {
preSelectedDevices.forEach((device) => {
const row = availableDevicesTableRef.value?.tableRef?.getRowByKey(device.id)
if (row) {
availableDevicesTableRef.value?.tableRef?.toggleRowSelection(row, true)
}
})
})
}
// 执行授权
const handleAllocate = async () => {
if (selectedAvailableDevices.value.length === 0) {
ElMessage.warning('请选择要授权的设备')
return
}
allocateLoading.value = true
try {
const device_nos = selectedAvailableDevices.value.map((device) => device.virtual_no)
const res = await EnterpriseService.allocateDevices(enterpriseId.value, {
device_nos
})
if (res.code === 0) {
operationResult.value = res.data
allocateDialogVisible.value = false
resultDialogVisible.value = true
// 显示成功消息
if (res.data.success_count > 0 && res.data.fail_count === 0) {
ElMessage.success('设备授权成功')
} else if (res.data.success_count > 0 && res.data.fail_count > 0) {
ElMessage.warning(
`部分设备授权成功:成功 ${res.data.success_count} 个,失败 ${res.data.fail_count} 个`
)
} else {
ElMessage.error('设备授权失败')
}
await getTableData()
}
} catch (error) {
console.error(error)
} finally {
allocateLoading.value = false
}
}
// 关闭授权对话框
const handleAllocateDialogClose = () => {
selectedAvailableDevices.value = []
}
// 显示撤销授权对话框
const showRecallDialog = () => {
if (selectedDevices.value.length === 0) {
ElMessage.warning('请先选择要撤销的设备')
return
}
recallDialogVisible.value = true
if (recallFormRef.value) {
recallFormRef.value.resetFields()
}
}
// 执行撤销授权
const handleRecall = async () => {
if (!recallFormRef.value) return
ElMessageBox.confirm(
`确定要撤销选中的 ${selectedDevices.value.length} 个设备的授权吗?`,
'撤销授权确认',
{
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
type: 'warning'
}
)
.then(async () => {
recallLoading.value = true
try {
const res = await EnterpriseService.recallDevices(enterpriseId.value, {
device_nos: selectedDevices.value.map((device) => device.virtual_no)
})
if (res.code === 0) {
operationResult.value = res.data
recallDialogVisible.value = false
resultDialogVisible.value = true
// 显示成功消息
if (res.data.success_count > 0 && res.data.fail_count === 0) {
ElMessage.success('撤销授权成功')
} else if (res.data.success_count > 0 && res.data.fail_count > 0) {
ElMessage.warning(
`部分设备撤销成功:成功 ${res.data.success_count} 个,失败 ${res.data.fail_count} 个`
)
} else {
ElMessage.error('撤销授权失败')
}
// 清空选择
if (tableRef.value) {
tableRef.value.clearSelection()
}
selectedDevices.value = []
await getTableData()
}
} catch (error) {
console.error(error)
console.logr('撤销授权失败')
} finally {
recallLoading.value = false
}
})
.catch(() => {})
}
// 关闭撤销授权对话框
const handleRecallDialogClose = () => {
if (recallFormRef.value) {
recallFormRef.value.resetFields()
}
}
</script>
<style lang="scss" scoped>
.enterprise-devices-page {
.card-header {
display: flex;
gap: 12px;
align-items: center;
}
.enterprise-info-card {
margin-bottom: 16px;
:deep(.el-card__body) {
display: none;
}
}
.device-selection-info {
margin-top: 10px;
margin-bottom: 12px;
font-size: 14px;
color: var(--el-color-info);
}
}
</style>