fetch(modify):修复BUG
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m27s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m27s
This commit is contained in:
@@ -353,6 +353,14 @@
|
||||
</div>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 设备操作右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="deviceOperationMenuRef"
|
||||
:menu-items="deviceOperationMenuItems"
|
||||
:menu-width="140"
|
||||
@select="handleDeviceOperationMenuSelect"
|
||||
/>
|
||||
|
||||
<!-- 绑定卡弹窗 -->
|
||||
<ElDialog v-model="bindCardDialogVisible" title="绑定卡到设备" width="500px">
|
||||
<ElForm ref="bindCardFormRef" :model="bindCardForm" :rules="bindCardRules" label-width="100px">
|
||||
@@ -394,6 +402,119 @@
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 设置限速对话框 -->
|
||||
<ElDialog v-model="speedLimitDialogVisible" title="设置限速" width="500px">
|
||||
<ElForm
|
||||
ref="speedLimitFormRef"
|
||||
:model="speedLimitForm"
|
||||
:rules="speedLimitRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="设备号">
|
||||
<span style="font-weight: bold; color: #409eff">{{ currentOperatingDevice }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="下行速率" prop="download_speed">
|
||||
<ElInputNumber
|
||||
v-model="speedLimitForm.download_speed"
|
||||
:min="1"
|
||||
:step="128"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div style="color: #909399; font-size: 12px; margin-top: 4px">单位: KB/s</div>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="上行速率" prop="upload_speed">
|
||||
<ElInputNumber
|
||||
v-model="speedLimitForm.upload_speed"
|
||||
:min="1"
|
||||
:step="128"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div style="color: #909399; font-size: 12px; margin-top: 4px">单位: KB/s</div>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="speedLimitDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirmSpeedLimit" :loading="speedLimitLoading">
|
||||
确认设置
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 切换SIM卡对话框 -->
|
||||
<ElDialog v-model="switchCardDialogVisible" title="切换SIM卡" width="500px">
|
||||
<ElForm
|
||||
ref="switchCardFormRef"
|
||||
:model="switchCardForm"
|
||||
:rules="switchCardRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="设备号">
|
||||
<span style="font-weight: bold; color: #409eff">{{ currentOperatingDevice }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="目标ICCID" prop="target_iccid">
|
||||
<ElInput
|
||||
v-model="switchCardForm.target_iccid"
|
||||
placeholder="请输入要切换到的目标ICCID"
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="switchCardDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirmSwitchCard" :loading="switchCardLoading">
|
||||
确认切换
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 设置WiFi对话框 -->
|
||||
<ElDialog v-model="setWiFiDialogVisible" title="设置WiFi" width="500px">
|
||||
<ElForm
|
||||
ref="setWiFiFormRef"
|
||||
:model="setWiFiForm"
|
||||
:rules="setWiFiRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<ElFormItem label="设备号">
|
||||
<span style="font-weight: bold; color: #409eff">{{ currentOperatingDevice }}</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="WiFi状态" prop="enabled">
|
||||
<ElRadioGroup v-model="setWiFiForm.enabled">
|
||||
<ElRadio :value="1">启用</ElRadio>
|
||||
<ElRadio :value="0">禁用</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="WiFi名称" prop="ssid">
|
||||
<ElInput
|
||||
v-model="setWiFiForm.ssid"
|
||||
placeholder="请输入WiFi名称(1-32个字符)"
|
||||
maxlength="32"
|
||||
show-word-limit
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="WiFi密码" prop="password">
|
||||
<ElInput
|
||||
v-model="setWiFiForm.password"
|
||||
type="password"
|
||||
placeholder="请输入WiFi密码(8-63个字符)"
|
||||
maxlength="63"
|
||||
show-word-limit
|
||||
show-password
|
||||
clearable
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="setWiFiDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirmSetWiFi" :loading="setWiFiLoading">
|
||||
确认设置
|
||||
</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
@@ -403,7 +524,17 @@
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { DeviceService, ShopService, CardService, PackageSeriesService } from '@/api/modules'
|
||||
import { ElMessage, ElMessageBox, ElTag, ElSwitch, ElIcon, ElTreeSelect } from 'element-plus'
|
||||
import {
|
||||
ElMessage,
|
||||
ElMessageBox,
|
||||
ElTag,
|
||||
ElSwitch,
|
||||
ElIcon,
|
||||
ElTreeSelect,
|
||||
ElInputNumber,
|
||||
ElRadioGroup,
|
||||
ElRadio
|
||||
} from 'element-plus'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import type {
|
||||
@@ -416,6 +547,8 @@
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
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'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { CommonStatus, getStatusText } from '@/config/constants'
|
||||
import type { PackageSeriesResponse } from '@/types/api'
|
||||
@@ -473,6 +606,59 @@
|
||||
slot_position: [{ required: true, message: '请选择插槽位置', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 设备操作相关对话框
|
||||
const speedLimitDialogVisible = ref(false)
|
||||
const speedLimitLoading = ref(false)
|
||||
const speedLimitFormRef = ref<FormInstance>()
|
||||
const speedLimitForm = reactive({
|
||||
download_speed: 1024,
|
||||
upload_speed: 512
|
||||
})
|
||||
const speedLimitRules = reactive<FormRules>({
|
||||
download_speed: [
|
||||
{ required: true, message: '请输入下行速率', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, message: '速率不能小于1KB/s', trigger: 'blur' }
|
||||
],
|
||||
upload_speed: [
|
||||
{ required: true, message: '请输入上行速率', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, message: '速率不能小于1KB/s', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
const currentOperatingDevice = ref<string>('')
|
||||
|
||||
// 设备操作右键菜单
|
||||
const deviceOperationMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const currentOperatingDeviceNo = ref<string>('')
|
||||
|
||||
const switchCardDialogVisible = ref(false)
|
||||
const switchCardLoading = ref(false)
|
||||
const switchCardFormRef = ref<FormInstance>()
|
||||
const switchCardForm = reactive({
|
||||
target_iccid: ''
|
||||
})
|
||||
const switchCardRules = reactive<FormRules>({
|
||||
target_iccid: [{ required: true, message: '请输入目标ICCID', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const setWiFiDialogVisible = ref(false)
|
||||
const setWiFiLoading = ref(false)
|
||||
const setWiFiFormRef = ref<FormInstance>()
|
||||
const setWiFiForm = reactive({
|
||||
enabled: 1,
|
||||
ssid: '',
|
||||
password: ''
|
||||
})
|
||||
const setWiFiRules = reactive<FormRules>({
|
||||
ssid: [
|
||||
{ required: true, message: '请输入WiFi名称', trigger: 'blur' },
|
||||
{ min: 1, max: 32, message: 'WiFi名称长度为1-32个字符', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入WiFi密码', trigger: 'blur' },
|
||||
{ min: 8, max: 63, message: 'WiFi密码长度为8-63个字符', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
// 搜索表单初始值
|
||||
const initialSearchState = {
|
||||
device_no: '',
|
||||
@@ -559,7 +745,6 @@
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ID', prop: 'id' },
|
||||
{ label: '设备号', prop: 'device_no' },
|
||||
{ label: '设备名称', prop: 'device_name' },
|
||||
{ label: '设备型号', prop: 'device_model' },
|
||||
@@ -794,15 +979,11 @@
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
prop: 'device_no',
|
||||
label: '设备号',
|
||||
minWidth: 150,
|
||||
showOverflowTooltip: true,
|
||||
formatter: (row: Device) => {
|
||||
return h(
|
||||
'span',
|
||||
@@ -827,7 +1008,7 @@
|
||||
{
|
||||
prop: 'device_type',
|
||||
label: '设备类型',
|
||||
width: 100
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'manufacturer',
|
||||
@@ -868,7 +1049,7 @@
|
||||
{
|
||||
prop: 'batch_no',
|
||||
label: '批次号',
|
||||
minWidth: 160,
|
||||
minWidth: 180,
|
||||
formatter: (row: Device) => row.batch_no || '-'
|
||||
},
|
||||
{
|
||||
@@ -880,17 +1061,17 @@
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 180,
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
formatter: (row: Device) => {
|
||||
return h('div', { style: 'display: flex; gap: 8px;' }, [
|
||||
return h('div', { style: 'display: flex; gap: 0; align-items: center;' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '查看卡片',
|
||||
onClick: () => handleViewCards(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
type: 'delete',
|
||||
onClick: () => deleteDevice(row)
|
||||
text: '更多操作',
|
||||
onContextmenu: (e: MouseEvent) => showDeviceOperationMenu(e, row.device_no)
|
||||
})
|
||||
])
|
||||
}
|
||||
@@ -1220,6 +1401,249 @@
|
||||
seriesBindingFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 设备操作相关 ==========
|
||||
|
||||
// 设备操作路由
|
||||
const handleDeviceOperation = (command: string, deviceNo: string) => {
|
||||
switch (command) {
|
||||
case 'reboot':
|
||||
handleRebootDevice(deviceNo)
|
||||
break
|
||||
case 'reset':
|
||||
handleResetDevice(deviceNo)
|
||||
break
|
||||
case 'speed-limit':
|
||||
showSpeedLimitDialog(deviceNo)
|
||||
break
|
||||
case 'switch-card':
|
||||
showSwitchCardDialog(deviceNo)
|
||||
break
|
||||
case 'set-wifi':
|
||||
showSetWiFiDialog(deviceNo)
|
||||
break
|
||||
case 'delete':
|
||||
handleDeleteDeviceByNo(deviceNo)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 通过设备号删除设备
|
||||
const handleDeleteDeviceByNo = async (deviceNo: string) => {
|
||||
// 先根据设备号找到设备对象
|
||||
const device = deviceList.value.find(d => d.device_no === deviceNo)
|
||||
if (device) {
|
||||
deleteDevice(device)
|
||||
} else {
|
||||
ElMessage.error('未找到该设备')
|
||||
}
|
||||
}
|
||||
|
||||
// 重启设备
|
||||
const handleRebootDevice = (imei: string) => {
|
||||
ElMessageBox.confirm(`确定要重启设备 ${imei} 吗?`, '重启确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await DeviceService.rebootDevice(imei)
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('重启指令已发送')
|
||||
} else {
|
||||
ElMessage.error(res.message || '重启失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('重启设备失败:', error)
|
||||
ElMessage.error(error?.message || '重启失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消
|
||||
})
|
||||
}
|
||||
|
||||
// 恢复出厂设置
|
||||
const handleResetDevice = (imei: string) => {
|
||||
ElMessageBox.confirm(
|
||||
`确定要恢复设备 ${imei} 的出厂设置吗?此操作将清除所有配置和数据!`,
|
||||
'恢复出厂设置确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await DeviceService.resetDevice(imei)
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('恢复出厂设置指令已发送')
|
||||
} else {
|
||||
ElMessage.error(res.message || '操作失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('恢复出厂设置失败:', error)
|
||||
ElMessage.error(error?.message || '操作失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消
|
||||
})
|
||||
}
|
||||
|
||||
// 显示设置限速对话框
|
||||
const showSpeedLimitDialog = (imei: string) => {
|
||||
currentOperatingDevice.value = imei
|
||||
speedLimitForm.download_speed = 1024
|
||||
speedLimitForm.upload_speed = 512
|
||||
speedLimitDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认设置限速
|
||||
const handleConfirmSpeedLimit = async () => {
|
||||
if (!speedLimitFormRef.value) return
|
||||
|
||||
await speedLimitFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
speedLimitLoading.value = true
|
||||
try {
|
||||
const res = await DeviceService.setSpeedLimit(currentOperatingDevice.value, {
|
||||
download_speed: speedLimitForm.download_speed,
|
||||
upload_speed: speedLimitForm.upload_speed
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('限速设置成功')
|
||||
speedLimitDialogVisible.value = false
|
||||
} else {
|
||||
ElMessage.error(res.message || '设置失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('设置限速失败:', error)
|
||||
ElMessage.error(error?.message || '设置失败')
|
||||
} finally {
|
||||
speedLimitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 显示切换SIM卡对话框
|
||||
const showSwitchCardDialog = (imei: string) => {
|
||||
currentOperatingDevice.value = imei
|
||||
switchCardForm.target_iccid = ''
|
||||
switchCardDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认切换SIM卡
|
||||
const handleConfirmSwitchCard = async () => {
|
||||
if (!switchCardFormRef.value) return
|
||||
|
||||
await switchCardFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
switchCardLoading.value = true
|
||||
try {
|
||||
const res = await DeviceService.switchCard(currentOperatingDevice.value, {
|
||||
target_iccid: switchCardForm.target_iccid
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('切换SIM卡指令已发送')
|
||||
switchCardDialogVisible.value = false
|
||||
} else {
|
||||
ElMessage.error(res.message || '切换失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('切换SIM卡失败:', error)
|
||||
ElMessage.error(error?.message || '切换失败')
|
||||
} finally {
|
||||
switchCardLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 显示设置WiFi对话框
|
||||
const showSetWiFiDialog = (imei: string) => {
|
||||
currentOperatingDevice.value = imei
|
||||
setWiFiForm.enabled = 1
|
||||
setWiFiForm.ssid = ''
|
||||
setWiFiForm.password = ''
|
||||
setWiFiDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认设置WiFi
|
||||
const handleConfirmSetWiFi = async () => {
|
||||
if (!setWiFiFormRef.value) return
|
||||
|
||||
await setWiFiFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
setWiFiLoading.value = true
|
||||
try {
|
||||
const res = await DeviceService.setWiFi(currentOperatingDevice.value, {
|
||||
enabled: setWiFiForm.enabled,
|
||||
ssid: setWiFiForm.ssid,
|
||||
password: setWiFiForm.password
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('WiFi设置成功')
|
||||
setWiFiDialogVisible.value = false
|
||||
} else {
|
||||
ElMessage.error(res.message || '设置失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('设置WiFi失败:', error)
|
||||
ElMessage.error(error?.message || '设置失败')
|
||||
} finally {
|
||||
setWiFiLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 设备操作菜单项配置
|
||||
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 showDeviceOperationMenu = (e: MouseEvent, deviceNo: string) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
currentOperatingDeviceNo.value = deviceNo
|
||||
deviceOperationMenuRef.value?.show(e)
|
||||
}
|
||||
|
||||
// 处理设备操作菜单选择
|
||||
const handleDeviceOperationMenuSelect = (item: MenuItemType) => {
|
||||
const deviceNo = currentOperatingDeviceNo.value
|
||||
if (!deviceNo) return
|
||||
|
||||
handleDeviceOperation(item.key, deviceNo)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
Reference in New Issue
Block a user