fix: bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m9s

This commit is contained in:
sexygoat
2026-04-23 14:59:05 +08:00
parent a9467e8a0c
commit a5e76313cb
28 changed files with 1284 additions and 702 deletions

View File

@@ -5,6 +5,7 @@
<ArtSearchBar
v-model:filter="searchForm"
:items="searchFormItems"
label-width="100"
@reset="handleReset"
@search="handleSearch"
></ArtSearchBar>
@@ -340,7 +341,11 @@
<ElRow :gutter="20">
<ElCol :span="6">
<ElFormItem label="搜索类型" prop="search_type">
<ElSelect v-model="bindCardForm.search_type" placeholder="请选择搜索类型" style="width: 100%">
<ElSelect
v-model="bindCardForm.search_type"
placeholder="请选择搜索类型"
style="width: 100%"
>
<ElOption label="ICCID" value="iccid" />
<ElOption label="运营商名称" value="carrier_name" />
</ElSelect>
@@ -655,6 +660,10 @@
})
const seriesBindingResult = ref<BatchSetDeviceSeriesBindingResponse | null>(null)
// 搜索表单店铺/系列选项
const shopOptions = ref<any[]>([])
const searchSeriesOptions = ref<any[]>([])
// 设备详情弹窗相关
const deviceDetailDialogVisible = ref(false)
const deviceDetailLoading = ref(false)
@@ -734,7 +743,12 @@
status: undefined as DeviceStatus | undefined,
batch_no: '',
device_type: '',
manufacturer: ''
manufacturer: '',
shop_id: undefined as number | undefined,
series_id: undefined as number | undefined,
dateRange: [] as string[],
created_at_start: '',
created_at_end: ''
}
// 搜索表单
@@ -801,6 +815,54 @@
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: 'datetimerange',
rangeSeparator: '至',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间',
valueFormat: 'YYYY-MM-DDTHH:mm:ssZZ'
}
}
]
@@ -814,21 +876,26 @@
// 列配置
const columnOptions = [
{ label: '设备号', prop: 'virtual_no' },
{ label: 'IMEI', prop: 'imei' },
{ label: '设备名称', prop: 'device_name' },
{ label: '设备型号', prop: 'device_model' },
{ label: '设备类型', prop: 'device_type' },
{ label: '店铺名称', prop: 'shop_name' },
{ label: '套餐系列', prop: 'series_name' },
{ label: '设备型号', prop: 'device_model' },
{ label: '设备类型', prop: 'device_type' },
{ label: '状态', prop: 'status' },
{ label: '状态名称', prop: 'status_name' },
{ label: '在线状态', prop: 'online_status' },
{ label: '实名策略', prop: 'realname_policy' },
{ label: '切卡模式', prop: 'switch_mode' },
{ label: '激活时间', prop: 'activated_at' },
{ label: '制造商', prop: 'manufacturer' },
{ label: '软件版本', prop: 'software_version' },
{ label: '最大插槽数', prop: 'max_sim_slots' },
{ label: '已绑定卡数', prop: 'bound_card_count' },
{ label: '状态', prop: 'status' },
{ label: '在线状态', prop: 'online_status' },
{ label: '切卡模式', prop: 'switch_mode' },
{ label: '序列号', prop: 'sn' },
{ label: '批次号', prop: 'batch_no' },
{ label: '最后在线时间', prop: 'last_online_time' },
{ label: '最后同步时间', prop: 'last_gateway_sync_at' },
{ label: '批次号', prop: 'batch_no' },
{ label: '创建时间', prop: 'created_at' },
{ label: '操作', prop: 'operation' }
]
@@ -875,10 +942,7 @@
bindCardForm.iot_card_id = undefined
bindCardForm.slot_position = 1
// 加载未绑定设备的卡列表
await Promise.all([
loadDeviceCards(device.virtual_no),
loadDefaultIotCards()
])
await Promise.all([loadDeviceCards(device.virtual_no), loadDefaultIotCards()])
}
// 加载设备绑定的卡列表
@@ -1055,7 +1119,7 @@
{
prop: 'virtual_no',
label: '设备号',
minWidth: 150,
minWidth: 170,
showOverflowTooltip: true,
formatter: (row: Device) => {
return h(
@@ -1071,21 +1135,18 @@
)
}
},
{
prop: 'imei',
label: 'IMEI',
minWidth: 150,
showOverflowTooltip: true,
formatter: (row: Device) => row.imei || '-'
},
{
prop: 'device_name',
label: '设备名称',
minWidth: 120
},
{
prop: 'device_model',
label: '设备型号',
minWidth: 120
},
{
prop: 'device_type',
label: '设备类型',
width: 120
},
{
prop: 'shop_name',
label: '店铺名称',
@@ -1097,23 +1158,14 @@
minWidth: 120
},
{
prop: 'manufacturer',
label: '制造商',
prop: 'device_model',
label: '设备型号',
minWidth: 120
},
{
prop: 'max_sim_slots',
label: '最大插槽数',
width: 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: 'device_type',
label: '设备类型',
width: 120
},
{
prop: 'status',
@@ -1130,6 +1182,12 @@
return h(ElTag, { type: status.type }, () => status.text)
}
},
{
prop: 'status_name',
label: '状态名称',
width: 100,
formatter: (row: Device) => row.status_name || '-'
},
{
prop: 'online_status',
label: '在线状态',
@@ -1144,6 +1202,20 @@
return h(ElTag, { type: status.type }, () => status.text)
}
},
{
prop: 'realname_policy',
label: '实名策略',
width: 150,
formatter: (row: Device) => {
const policy = row.realname_policy || ''
const policyMap: Record<string, string> = {
none: '无需实名',
before_order: '先实名后充值/购买',
after_order: '先充值/购买后实名'
}
return policyMap[policy] || (policy ? policy : '未知')
}
},
{
prop: 'switch_mode',
label: '切卡模式',
@@ -1157,19 +1229,51 @@
}
},
{
prop: 'realname_policy',
label: '实名认证策略',
width: 150,
prop: 'activated_at',
label: '激活时间',
width: 180,
formatter: (row: Device) => (row.activated_at ? formatDateTime(row.activated_at) : '-')
},
{
prop: 'manufacturer',
label: '制造商',
minWidth: 100
},
{
prop: 'software_version',
label: '软件版本',
minWidth: 180,
showOverflowTooltip: true,
formatter: (row: Device) => row.software_version || '-'
},
{
prop: 'max_sim_slots',
label: '最大插槽数',
width: 100
},
{
prop: 'bound_card_count',
label: '已绑定卡数',
width: 110,
formatter: (row: Device) => {
const policy = row.realname_policy || ''
const policyMap: Record<string, string> = {
none: '无需实名',
before_order: '先实名后充值/购买',
after_order: '先充值/购买后实名'
}
return policyMap[policy] || (policy ? policy : '未知')
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 || '-'
},
{
prop: 'last_online_time',
label: '最后在线时间',
@@ -1184,12 +1288,6 @@
formatter: (row: Device) =>
row.last_gateway_sync_at ? formatDateTime(row.last_gateway_sync_at) : '-'
},
{
prop: 'batch_no',
label: '批次号',
minWidth: 180,
formatter: (row: Device) => row.batch_no || '-'
},
{
prop: 'created_at',
label: '创建时间',
@@ -1198,9 +1296,50 @@
}
])
// 搜索店铺(用于搜索表单)
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) => {
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)
}
}
let isFirstActivation = true
onMounted(() => {
getTableData()
searchShops('')
searchSeries('')
})
// 当页面被 keep-alive 激活时自动刷新数据
@@ -1223,7 +1362,11 @@
status: searchForm.status,
batch_no: searchForm.batch_no || undefined,
device_type: searchForm.device_type || undefined,
manufacturer: searchForm.manufacturer || undefined
manufacturer: searchForm.manufacturer || undefined,
shop_id: searchForm.shop_id || undefined,
series_id: searchForm.series_id || undefined,
created_at_start: searchForm.created_at_start || undefined,
created_at_end: searchForm.created_at_end || undefined
}
const res = await DeviceService.getDevices(params)
if (res.code === 0 && res.data) {
@@ -1246,6 +1389,14 @@
// 搜索
const handleSearch = () => {
// 处理日期范围
if (searchForm.dateRange && Array.isArray(searchForm.dateRange)) {
searchForm.created_at_start = searchForm.dateRange[0] || ''
searchForm.created_at_end = searchForm.dateRange[1] || ''
} else {
searchForm.created_at_start = ''
searchForm.created_at_end = ''
}
pagination.page = 1
getTableData()
}