From 90b13eb5ec0f795409055ba87a9b9b4ddac016a3 Mon Sep 17 00:00:00 2001
From: sexygoat <1538832180@qq.com>
Date: Fri, 17 Apr 2026 16:37:41 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8F=96=E6=B6=88=E5=85=B3=E8=81=94,?=
=?UTF-8?q?=E5=B1=85=E5=B7=A6,=E5=BA=97=E9=93=BA=E5=88=97=E8=A1=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../asset-management/device-list/index.vue | 141 ++++++++++--------
.../iot-card-management/index.vue | 132 ++++++++++------
.../package-management/package-list/index.vue | 2 +-
3 files changed, 167 insertions(+), 108 deletions(-)
diff --git a/src/views/asset-management/device-list/index.vue b/src/views/asset-management/device-list/index.vue
index 0b79f15..2ac5397 100644
--- a/src/views/asset-management/device-list/index.vue
+++ b/src/views/asset-management/device-list/index.vue
@@ -77,14 +77,13 @@
{{ selectedDevices.length }} 台
-
@@ -222,7 +221,6 @@
:loading="seriesLoading"
clearable
>
-
([])
- const shopTreeData = ref([])
+ const shopCascadeOptions = ref([])
+ const shopCascadeProps = {
+ lazy: true,
+ checkStrictly: true,
+ lazyLoad: async (node: any, resolve: any) => {
+ const { level, value } = node
+ const parentId = level === 0 ? undefined : value
+
+ try {
+ const res = await ShopService.getShopsCascade({ parent_id: parentId })
+ if (res.code === 0) {
+ const nodes = (res.data || []).map((item: any) => ({
+ value: item.id,
+ label: item.shop_name,
+ leaf: !item.has_children
+ }))
+ resolve(nodes)
+ } else {
+ resolve([])
+ }
+ } catch (error) {
+ console.error('加载店铺级联数据失败:', error)
+ resolve([])
+ }
+ },
+ value: 'value',
+ label: 'label',
+ children: 'children'
+ }
const allocateResult = ref(null)
const recallResult = ref(null)
@@ -1146,7 +1164,6 @@
onMounted(() => {
getTableData()
- loadShopTree()
})
// 当页面被 keep-alive 激活时自动刷新数据
@@ -1154,49 +1171,6 @@
getTableData()
})
- // 加载店铺树形数据
- const loadShopTree = async () => {
- try {
- const res = await ShopService.getShops({
- page: 1,
- page_size: 9999, // 获取所有数据用于构建树形结构
- status: 1 // 只获取启用的店铺
- })
- if (res.code === 0) {
- shopTreeData.value = buildShopTree(res.data.items || [])
- }
- } catch (error) {
- console.error('获取店铺列表失败:', error)
- }
- }
-
- // 构建店铺树形结构
- const buildShopTree = (shops: any[]) => {
- const map = new Map()
- const tree: any[] = []
-
- // 先将所有项放入 map
- shops.forEach((shop) => {
- map.set(shop.id, { ...shop, children: [] })
- })
-
- // 构建树形结构
- shops.forEach((shop) => {
- const node = map.get(shop.id)!
- if (shop.parent_id && map.has(shop.parent_id)) {
- // 有父节点,添加到父节点的 children 中
- const parent = map.get(shop.parent_id)!
- if (!parent.children) parent.children = []
- parent.children.push(node)
- } else {
- // 没有父节点或父节点不存在,作为根节点
- tree.push(node)
- }
- })
-
- return tree
- }
-
// 获取设备列表
const getTableData = async () => {
loading.value = true
@@ -1278,7 +1252,43 @@
}
})
.catch(() => {
- // 用户取消删除
+ // 用户取消
+ })
+ }
+
+ // 清除设备套餐系列绑定
+ const handleClearDeviceSeries = async (deviceNo: string) => {
+ const device = deviceList.value.find((d) => d.virtual_no === deviceNo)
+ if (!device) {
+ ElMessage.error('未找到该设备')
+ return
+ }
+
+ ElMessageBox.confirm(`确定要清除设备 ${deviceNo} 的套餐系列关联吗?`, '确认清除', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ try {
+ const res = await DeviceService.batchSetDeviceSeriesBinding({
+ device_ids: [device.id],
+ series_id: 0
+ })
+ if (res.code === 0) {
+ if (res.data.fail_count === 0) {
+ ElMessage.success('清除关联成功')
+ } else {
+ ElMessage.warning(`部分失败:${res.data.failed_items?.[0]?.reason || '未知原因'}`)
+ }
+ await getTableData()
+ }
+ } catch (error) {
+ console.error('清除关联失败:', error)
+ }
+ })
+ .catch(() => {
+ // 用户取消
})
}
@@ -1534,6 +1544,9 @@
case 'delete':
await handleDeleteDeviceByNo(deviceNo)
break
+ case 'clear-series':
+ await handleClearDeviceSeries(deviceNo)
+ break
}
}
@@ -1794,6 +1807,14 @@
})
}
+ if (hasAuth('device:clear_series')) {
+ moreActions.push({
+ label: '清除关联',
+ handler: () => handleDeviceOperation('clear-series', row.virtual_no, row),
+ type: 'primary'
+ })
+ }
+
// if (hasAuth('device:manual_deactivate')) {
// moreActions.push({
// label: '手动停用',
diff --git a/src/views/asset-management/iot-card-management/index.vue b/src/views/asset-management/iot-card-management/index.vue
index 6c7a682..e679d42 100644
--- a/src/views/asset-management/iot-card-management/index.vue
+++ b/src/views/asset-management/iot-card-management/index.vue
@@ -94,24 +94,15 @@
label-width="120px"
>
-
-
-
+ />
@@ -342,7 +333,6 @@
:loading="seriesLoading"
clearable
>
-
>()
// 店铺相关
- const targetShopLoading = ref(false)
- const targetShopList = ref([])
+ const shopCascadeOptions = ref([])
+ const shopCascadeProps = {
+ lazy: true,
+ checkStrictly: true,
+ lazyLoad: async (node: any, resolve: any) => {
+ const { level, value } = node
+ const parentId = level === 0 ? undefined : value
+
+ try {
+ const res = await ShopService.getShopsCascade({ parent_id: parentId })
+ if (res.code === 0) {
+ const nodes = (res.data || []).map((item: any) => ({
+ value: item.id,
+ label: item.shop_name,
+ leaf: !item.has_children
+ }))
+ resolve(nodes)
+ } else {
+ resolve([])
+ }
+ } catch (error) {
+ console.error('加载店铺级联数据失败:', error)
+ resolve([])
+ }
+ },
+ value: 'value',
+ label: 'label',
+ children: 'children'
+ }
// 搜索表单初始值
const initialSearchState: {
@@ -1213,33 +1230,6 @@
selectedCards.value = selection
}
- // 加载目标店铺列表
- const loadTargetShops = async (shopName?: string) => {
- targetShopLoading.value = true
- try {
- const params: any = {
- page: 1,
- page_size: 20
- }
- if (shopName) {
- params.shop_name = shopName
- }
- const res = await ShopService.getShops(params)
- if (res.code === 0) {
- targetShopList.value = res.data.items || []
- }
- } catch (error) {
- console.error('获取目标店铺列表失败:', error)
- } finally {
- targetShopLoading.value = false
- }
- }
-
- // 搜索目标店铺
- const searchTargetShops = async (query: string) => {
- await loadTargetShops(query || undefined)
- }
-
// 显示批量分配对话框
const showAllocateDialog = () => {
if (selectedCards.value.length === 0) {
@@ -1258,8 +1248,6 @@
batch_no: '',
remark: ''
})
- // 加载默认店铺列表
- loadTargetShops()
if (allocateFormRef.value) {
allocateFormRef.value.resetFields()
}
@@ -1536,6 +1524,13 @@
})
}
+ if (hasAuth('iot_card:clear_series')) {
+ items.push({
+ key: 'clearSeries',
+ label: '清除关联'
+ })
+ }
+
return items
})
@@ -1565,9 +1560,52 @@
case 'changePackage':
changePackage()
break
+ case 'clearSeries':
+ handleClearCardSeries()
+ break
}
}
+ // 清除卡套餐系列绑定
+ const handleClearCardSeries = async () => {
+ if (selectedCards.value.length === 0) {
+ ElMessage.warning('请先选择要清除关联的卡')
+ return
+ }
+
+ ElMessageBox.confirm(
+ `确定要清除所选 ${selectedCards.value.length} 张卡的套餐系列关联吗?`,
+ '确认清除',
+ {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }
+ )
+ .then(async () => {
+ try {
+ const res = await CardService.batchSetCardSeriesBinding({
+ iccids: selectedCards.value.map((card) => card.iccid),
+ series_id: 0
+ })
+ if (res.code === 0) {
+ if (res.data.fail_count === 0) {
+ ElMessage.success('清除关联成功')
+ } else {
+ ElMessage.warning(`部分失败:${res.data.failed_items?.[0]?.reason || '未知原因'}`)
+ }
+ selectedCards.value = []
+ await getTableData()
+ }
+ } catch (error) {
+ console.error('清除关联失败:', error)
+ }
+ })
+ .catch(() => {
+ // 用户取消
+ })
+ }
+
// 网卡分销 - 正在开发中
const cardDistribution = () => {
ElMessage.info('功能正在开发中')
diff --git a/src/views/package-management/package-list/index.vue b/src/views/package-management/package-list/index.vue
index a040b48..63f3267 100644
--- a/src/views/package-management/package-list/index.vue
+++ b/src/views/package-management/package-list/index.vue
@@ -51,7 +51,7 @@
:close-on-click-modal="false"
@closed="handleDialogClosed"
>
-
+