feat: 增加策略信息页面和推送
This commit is contained in:
8775
pnpm-lock.yaml
generated
8775
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,8 @@ import type {
|
|||||||
ApkInstallInfo,
|
ApkInstallInfo,
|
||||||
DeviceLocationInfo,
|
DeviceLocationInfo,
|
||||||
DeviceScreenshot,
|
DeviceScreenshot,
|
||||||
|
DevicePolicyInfo,
|
||||||
|
DevicePolicyToggleForm,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
import type { ExcelResult, PageResult, OptionItem } from "@/api/common";
|
import type { ExcelResult, PageResult, OptionItem } from "@/api/common";
|
||||||
@@ -272,6 +274,18 @@ const DeviceAPI = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 屏幕镜像(通知设备开启屏幕采集,由家属端 client 进行 WebRTC 实时观看)
|
||||||
|
* @param sn 设备SN号
|
||||||
|
*/
|
||||||
|
deviceMirror(sn: string) {
|
||||||
|
return request({
|
||||||
|
url: `${DEVICE_BASE_URL}/mirror`,
|
||||||
|
method: "post",
|
||||||
|
params: { sn },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备重启
|
* 设备重启
|
||||||
* @param sn 设备SN号
|
* @param sn 设备SN号
|
||||||
@@ -319,6 +333,18 @@ const DeviceAPI = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解除设备手机号绑定(管理员端)
|
||||||
|
* 对应后端 POST /{sn}/unbind (unbindMobile)
|
||||||
|
* @param sn 设备SN号
|
||||||
|
*/
|
||||||
|
unbindDeviceMobile(sn: string) {
|
||||||
|
return request({
|
||||||
|
url: `${DEVICE_BASE_URL}/${sn}/unbind`,
|
||||||
|
method: "post",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// ===================== 设备系统信息(分面板独立接口) =====================
|
// ===================== 设备系统信息(分面板独立接口) =====================
|
||||||
|
|
||||||
/** 设备基本信息 */
|
/** 设备基本信息 */
|
||||||
@@ -523,6 +549,52 @@ const DeviceAPI = {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ===================== 设备策略信息 =====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备策略信息
|
||||||
|
* 对应后端 GET /{sn}/policy (getDevicePolicy)
|
||||||
|
* SN 合法且无记录时自动新建默认策略(默认全开)
|
||||||
|
*
|
||||||
|
* @param sn 设备SN号
|
||||||
|
*/
|
||||||
|
getPolicy(sn: string) {
|
||||||
|
return request<any, DevicePolicyInfo>({
|
||||||
|
url: `${DEVICE_BASE_URL}/${sn}/policy`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全量设置设备策略信息
|
||||||
|
* 对应后端 PUT /{sn}/policy (updateDevicePolicy)
|
||||||
|
*
|
||||||
|
* @param sn 设备SN号
|
||||||
|
* @param data 策略信息(空字段保持原值)
|
||||||
|
*/
|
||||||
|
updatePolicy(sn: string, data: DevicePolicyInfo) {
|
||||||
|
return request<any, boolean>({
|
||||||
|
url: `${DEVICE_BASE_URL}/${sn}/policy`,
|
||||||
|
method: "put",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单独设置设备策略开关
|
||||||
|
* 对应后端 PUT /{sn}/policy/toggle (toggleDevicePolicy)
|
||||||
|
*
|
||||||
|
* @param sn 设备SN号
|
||||||
|
* @param data 策略字段与开关值
|
||||||
|
*/
|
||||||
|
togglePolicy(sn: string, data: DevicePolicyToggleForm) {
|
||||||
|
return request<any, boolean>({
|
||||||
|
url: `${DEVICE_BASE_URL}/${sn}/policy/toggle`,
|
||||||
|
method: "put",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeviceAPI;
|
export default DeviceAPI;
|
||||||
|
|||||||
@@ -450,3 +450,59 @@ export interface DeviceScreenshot {
|
|||||||
/** 上传时间 */
|
/** 上传时间 */
|
||||||
uploadTime?: string;
|
uploadTime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================== 设备策略信息 =====================
|
||||||
|
|
||||||
|
/** 设备策略信息 */
|
||||||
|
export interface DevicePolicyInfo {
|
||||||
|
/** 策略ID */
|
||||||
|
id?: number;
|
||||||
|
/** 设备序列号 */
|
||||||
|
serialno?: string;
|
||||||
|
/** USB偏好设置(0关闭 1开启) */
|
||||||
|
usbData?: number;
|
||||||
|
/** 时间设置管控(0关闭 1开启) */
|
||||||
|
timeSetting?: number;
|
||||||
|
/** 存储卡(0关闭 1开启) */
|
||||||
|
storageCard?: number;
|
||||||
|
/** 恢复出厂(0关闭 1开启) */
|
||||||
|
factoryReset?: number;
|
||||||
|
/** WiFi热点开关(0关闭 1开启) */
|
||||||
|
wifiHotspot?: number;
|
||||||
|
/** 蓝牙开关(0关闭 1开启) */
|
||||||
|
bluetoothSwitch?: number;
|
||||||
|
/** 壁纸功能(0关闭 1开启) */
|
||||||
|
wallpaper?: number;
|
||||||
|
/** 通知栏显示(0关闭 1开启) */
|
||||||
|
notificationBar?: number;
|
||||||
|
/** 状态栏下拉开关(0关闭 1开启) */
|
||||||
|
statusBarPullDown?: number;
|
||||||
|
/** 系统导航条显示(0关闭 1开启) */
|
||||||
|
systemNavBarShow?: number;
|
||||||
|
/** 系统导航栏设置(0关闭 1开启) */
|
||||||
|
systemNavBarSetting?: number;
|
||||||
|
/** 导航条选项(0关闭 1开启) */
|
||||||
|
navBarOptions?: number;
|
||||||
|
/** 蓝牙功能开关(0关闭 1开启) */
|
||||||
|
bluetoothFunction?: number;
|
||||||
|
/** OTA升级管控(0关闭 1开启) */
|
||||||
|
otaUpgrade?: number;
|
||||||
|
/** 应用安装开关(0关闭 1开启) */
|
||||||
|
appInstall?: number;
|
||||||
|
/** 自动旋转(0关闭 1开启) */
|
||||||
|
autoRotate?: number;
|
||||||
|
/** 自动亮度(0关闭 1开启) */
|
||||||
|
autoBrightness?: number;
|
||||||
|
/** 护眼模式(0关闭 1开启) */
|
||||||
|
eyeProtection?: number;
|
||||||
|
/** 深色模式(0关闭 1开启) */
|
||||||
|
darkMode?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 设备策略单独设置请求 */
|
||||||
|
export interface DevicePolicyToggleForm {
|
||||||
|
/** 策略字段名(如 usbData、appInstall) */
|
||||||
|
field: string;
|
||||||
|
/** 开关值(0关闭 1开启) */
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -735,7 +735,43 @@
|
|||||||
|
|
||||||
<el-tab-pane label="策略信息" name="policyInfo">
|
<el-tab-pane label="策略信息" name="policyInfo">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<el-empty description="策略信息加载中..." />
|
<div class="policy-toolbar">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
size="small"
|
||||||
|
:loading="policyLoading"
|
||||||
|
:icon="Refresh"
|
||||||
|
@click="loadPolicyInfo(props.serialno)"
|
||||||
|
>
|
||||||
|
刷新
|
||||||
|
</el-button>
|
||||||
|
<div class="policy-toolbar__right">
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
size="small"
|
||||||
|
:loading="policySaving"
|
||||||
|
:icon="Select"
|
||||||
|
@click="handleSavePolicy"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-loading="policyLoading" class="policy-grid">
|
||||||
|
<div v-for="item in policyItems" :key="item.field" class="policy-item">
|
||||||
|
<div class="policy-item__label">{{ item.label }}</div>
|
||||||
|
<el-switch
|
||||||
|
v-model="policyState[item.field]"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
inline-prompt
|
||||||
|
active-text="开"
|
||||||
|
inactive-text="关"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
@@ -766,6 +802,7 @@ import type {
|
|||||||
DeviceSecurityInfo,
|
DeviceSecurityInfo,
|
||||||
DeviceLocationInfo,
|
DeviceLocationInfo,
|
||||||
DeviceScreenshot,
|
DeviceScreenshot,
|
||||||
|
DevicePolicyInfo,
|
||||||
} from "@/api/system/device/types";
|
} from "@/api/system/device/types";
|
||||||
import { nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue";
|
import { nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue";
|
||||||
import { useSse } from "@/composables";
|
import { useSse } from "@/composables";
|
||||||
@@ -782,6 +819,7 @@ import {
|
|||||||
VideoPlay,
|
VideoPlay,
|
||||||
Brush,
|
Brush,
|
||||||
SwitchButton,
|
SwitchButton,
|
||||||
|
Select,
|
||||||
} from "@element-plus/icons-vue";
|
} from "@element-plus/icons-vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
@@ -889,6 +927,36 @@ const apkList = ref<ApkInstallInfo[]>([]);
|
|||||||
/** 应用信息是否已加载(懒加载,仅首次进入 tab 时拉取) */
|
/** 应用信息是否已加载(懒加载,仅首次进入 tab 时拉取) */
|
||||||
const apkLoaded = ref(false);
|
const apkLoaded = ref(false);
|
||||||
|
|
||||||
|
/** 设备策略信息(开关值 0/1) */
|
||||||
|
const policyState = reactive<Record<string, number>>({});
|
||||||
|
/** 策略信息加载中 */
|
||||||
|
const policyLoading = ref(false);
|
||||||
|
/** 策略信息保存中 */
|
||||||
|
const policySaving = ref(false);
|
||||||
|
|
||||||
|
/** 策略开关项配置(label 展示名,field 对应后端字段名) */
|
||||||
|
const policyItems: { label: string; field: string }[] = [
|
||||||
|
{ label: "USB偏好设置", field: "usbData" },
|
||||||
|
{ label: "时间设置管控", field: "timeSetting" },
|
||||||
|
{ label: "存储卡", field: "storageCard" },
|
||||||
|
{ label: "恢复出厂", field: "factoryReset" },
|
||||||
|
{ label: "WiFi热点开关", field: "wifiHotspot" },
|
||||||
|
{ label: "蓝牙开关", field: "bluetoothSwitch" },
|
||||||
|
{ label: "壁纸功能", field: "wallpaper" },
|
||||||
|
{ label: "通知栏显示", field: "notificationBar" },
|
||||||
|
{ label: "状态栏下拉开关", field: "statusBarPullDown" },
|
||||||
|
{ label: "系统导航条显示", field: "systemNavBarShow" },
|
||||||
|
{ label: "系统导航栏设置", field: "systemNavBarSetting" },
|
||||||
|
{ label: "导航条选项", field: "navBarOptions" },
|
||||||
|
{ label: "蓝牙功能开关", field: "bluetoothFunction" },
|
||||||
|
{ label: "OTA升级管控", field: "otaUpgrade" },
|
||||||
|
{ label: "应用安装开关", field: "appInstall" },
|
||||||
|
{ label: "自动旋转", field: "autoRotate" },
|
||||||
|
{ label: "自动亮度", field: "autoBrightness" },
|
||||||
|
{ label: "护眼模式", field: "eyeProtection" },
|
||||||
|
{ label: "深色模式", field: "darkMode" },
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拼接应用图标完整访问地址
|
* 拼接应用图标完整访问地址
|
||||||
*
|
*
|
||||||
@@ -1183,6 +1251,7 @@ async function loadAll(serialno?: string) {
|
|||||||
loadOtherInfo(serialno);
|
loadOtherInfo(serialno);
|
||||||
loadLocationInfo(serialno);
|
loadLocationInfo(serialno);
|
||||||
loadScreenshots(serialno);
|
loadScreenshots(serialno);
|
||||||
|
loadPolicyInfo(serialno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 设备截图列表 */
|
/** 设备截图列表 */
|
||||||
@@ -1295,7 +1364,46 @@ async function loadApkInfo(serialno: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 切换标签页懒加载应用信息 / 定位信息(仅首次进入时拉取) */
|
/** 策略信息 */
|
||||||
|
async function loadPolicyInfo(serialno: string) {
|
||||||
|
if (!serialno) return;
|
||||||
|
policyLoading.value = true;
|
||||||
|
try {
|
||||||
|
const data = (await DeviceAPI.getPolicy(serialno)) as DevicePolicyInfo | null;
|
||||||
|
// 初始化/刷新所有开关值
|
||||||
|
policyItems.forEach((item) => {
|
||||||
|
const record = data as Record<string, number | undefined> | null;
|
||||||
|
policyState[item.field] = record?.[item.field] ?? 1;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("加载策略信息失败", e);
|
||||||
|
ElMessage.error("加载策略信息失败");
|
||||||
|
} finally {
|
||||||
|
policyLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 全量保存策略信息 */
|
||||||
|
async function handleSavePolicy() {
|
||||||
|
if (!props.serialno) return;
|
||||||
|
policySaving.value = true;
|
||||||
|
try {
|
||||||
|
const data: DevicePolicyInfo = { serialno: props.serialno };
|
||||||
|
const record = data as Record<string, number | undefined>;
|
||||||
|
policyItems.forEach((item) => {
|
||||||
|
record[item.field] = policyState[item.field];
|
||||||
|
});
|
||||||
|
await DeviceAPI.updatePolicy(props.serialno, data);
|
||||||
|
ElMessage.success("策略信息保存成功");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("保存策略信息失败", e);
|
||||||
|
ElMessage.error("保存策略信息失败");
|
||||||
|
} finally {
|
||||||
|
policySaving.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 切换标签页懒加载应用信息 / 定位信息 / 策略信息 */
|
||||||
watch(activeTab, (tab) => {
|
watch(activeTab, (tab) => {
|
||||||
if (tab === "appInfo" && props.serialno && !apkLoaded.value) {
|
if (tab === "appInfo" && props.serialno && !apkLoaded.value) {
|
||||||
loadApkInfo(props.serialno);
|
loadApkInfo(props.serialno);
|
||||||
@@ -1303,6 +1411,9 @@ watch(activeTab, (tab) => {
|
|||||||
if (tab === "locationInfo" && props.serialno) {
|
if (tab === "locationInfo" && props.serialno) {
|
||||||
loadLocationInfo(props.serialno);
|
loadLocationInfo(props.serialno);
|
||||||
}
|
}
|
||||||
|
if (tab === "policyInfo" && props.serialno) {
|
||||||
|
loadPolicyInfo(props.serialno);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 打开应用 */
|
/** 打开应用 */
|
||||||
@@ -1820,6 +1931,45 @@ const handleMoreActions = (command: string) => {
|
|||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.policy-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
&__right {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.policy-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.policy-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 18px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.apk-actions {
|
.apk-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { DeviceQueryParams, DeviceItem } from "@/api/system/device/types";
|
|||||||
import type { IContentConfig } from "@/components/DeviceSn/types";
|
import type { IContentConfig } from "@/components/DeviceSn/types";
|
||||||
|
|
||||||
const contentConfig: IContentConfig<DeviceQueryParams, DeviceItem> = {
|
const contentConfig: IContentConfig<DeviceQueryParams, DeviceItem> = {
|
||||||
permPrefix: "sys:user", // 不写不进行按钮权限校验
|
permPrefix: "sys:device", // 不写不进行按钮权限校验
|
||||||
table: {
|
table: {
|
||||||
border: true,
|
border: true,
|
||||||
highlightCurrentRow: true,
|
highlightCurrentRow: true,
|
||||||
@@ -160,6 +160,11 @@ const contentConfig: IContentConfig<DeviceQueryParams, DeviceItem> = {
|
|||||||
text: "截图",
|
text: "截图",
|
||||||
attrs: { icon: "FullScreen" },
|
attrs: { icon: "FullScreen" },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "mirror",
|
||||||
|
text: "屏幕镜像",
|
||||||
|
attrs: { icon: "VideoCamera" },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "locate",
|
name: "locate",
|
||||||
text: "定位",
|
text: "定位",
|
||||||
@@ -180,6 +185,11 @@ const contentConfig: IContentConfig<DeviceQueryParams, DeviceItem> = {
|
|||||||
text: "重置",
|
text: "重置",
|
||||||
attrs: { icon: "RefreshLeft" },
|
attrs: { icon: "RefreshLeft" },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "unbind",
|
||||||
|
text: "解除绑定",
|
||||||
|
attrs: { icon: "Unlock" },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ISearchConfig } from "@/components/DeviceSn/types";
|
|||||||
import { deptArr, stateArr } from "./options";
|
import { deptArr, stateArr } from "./options";
|
||||||
|
|
||||||
const searchConfig: ISearchConfig = {
|
const searchConfig: ISearchConfig = {
|
||||||
permPrefix: "sys:user",
|
permPrefix: "sys:device",
|
||||||
formItems: [
|
formItems: [
|
||||||
{
|
{
|
||||||
tips: "支持模糊搜索",
|
tips: "支持模糊搜索",
|
||||||
|
|||||||
@@ -183,6 +183,13 @@ const handleOperateClick = (data: IObject) => {
|
|||||||
DeviceAPI.deviceScreenshot(data.row.serialno as string).then(() => {
|
DeviceAPI.deviceScreenshot(data.row.serialno as string).then(() => {
|
||||||
ElMessage.success(`截图设备,设备SN: ${data.row.serialno as string}`);
|
ElMessage.success(`截图设备,设备SN: ${data.row.serialno as string}`);
|
||||||
});
|
});
|
||||||
|
} else if (data.name === "mirror") {
|
||||||
|
// 屏幕镜像:通知设备端启动屏幕采集,由家属端 client 进行 WebRTC 实时远程观看/控制
|
||||||
|
DeviceAPI.deviceMirror(data.row.serialno as string)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success(`已发送屏幕镜像指令,设备SN: ${data.row.serialno as string}`);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
} else if (data.name === "reboot") {
|
} else if (data.name === "reboot") {
|
||||||
ElMessageBox.confirm("确定要重启该设备吗?", "提示", {
|
ElMessageBox.confirm("确定要重启该设备吗?", "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
@@ -215,6 +222,27 @@ const handleOperateClick = (data: IObject) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
} else if (data.name === "unbind") {
|
||||||
|
// 解除设备手机号绑定(管理员端):确认后清除 snMobile 并推送通知设备端标记解绑
|
||||||
|
const sn = data.row.serialno as string;
|
||||||
|
const mobile = (data.row.snMobile as string) || "";
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
mobile
|
||||||
|
? `设备「${sn}」当前绑定手机号:${mobile}\n确定要解除该绑定吗?解除后需由家属端重新绑定。`
|
||||||
|
: `设备「${sn}」当前未绑定手机号,无需解除绑定。`,
|
||||||
|
"解除绑定",
|
||||||
|
{
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
DeviceAPI.unbindDeviceMobile(data.row.serialno as string).then(() => {
|
||||||
|
ElMessage.success(`已解除设备绑定,设备SN: ${data.row.serialno as string}`);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user