forked from dyf/dyf-vue-ui
873 lines
31 KiB
Vue
873 lines
31 KiB
Vue
<template>
|
||
<div class="p-2">
|
||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
|
||
:leave-active-class="proxy?.animate.searchAnimate.leave">
|
||
<div v-show="showSearch" class="mb-[10px]">
|
||
<el-card shadow="hover">
|
||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||
<el-form-item label="设备名称" prop="deviceName">
|
||
<el-input v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="设备MAC" prop="deviceMac">
|
||
<el-input v-model="queryParams.deviceMac" placeholder="请输入设备MAC" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="请输入设备IMEI" prop="deviceImei">
|
||
<el-input v-model="queryParams.deviceImei" placeholder="请输入设备IMEI" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="设备类型" prop="deviceType">
|
||
<el-select v-model="queryParams.deviceType" placeholder="设备类型">
|
||
<el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName"
|
||
:value="item.id" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="设备状态" prop="deviceStatus">
|
||
<el-select v-model="queryParams.deviceStatus" placeholder="设备状态" style="margin-left: 10px;">
|
||
<el-option label="正常" value="1" />
|
||
<el-option label="失效" value="0" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="创建时间">
|
||
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
|
||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
</div>
|
||
</transition>
|
||
|
||
<el-card shadow="hover">
|
||
<template #header>
|
||
<el-row :gutter="10">
|
||
<el-col :span="1.5">
|
||
<el-button type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
|
||
修改
|
||
</el-button>
|
||
</el-col>
|
||
|
||
<el-col :span="1.5">
|
||
<el-button type="warning" :disabled="multiple" plain icon="Download" @click="handleExport">导出</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="danger" plain :disabled="multiple" @click="handleDelete()">
|
||
批量删除
|
||
</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="warning" plain @click="handleBatchImport">
|
||
批量导入
|
||
</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="warning" plain :disabled="multiple" @click="handleBatchAssign">
|
||
批量分配客户
|
||
</el-button>
|
||
</el-col>
|
||
<right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
|
||
</el-row>
|
||
</template>
|
||
|
||
<el-table v-loading="loading" border :data="deviceDist" @selection-change="handleSelectionChange">
|
||
<el-table-column type="selection" width="50" align="center" />
|
||
<el-table-column label="设备名称" align="center" prop="deviceName" />
|
||
<el-table-column prop="customerName" label="所属客户" />
|
||
<el-table-column prop="devicePic" label="设备图片">
|
||
<template #default="scope">
|
||
<el-popover placement="right" trigger="click">
|
||
<template #reference>
|
||
<img :src="scope.row.devicePic" style="width: 40px; height: 40px; cursor: pointer; object-fit: contain"
|
||
class="hover:opacity-80 transition-opacity" />
|
||
</template>
|
||
<img :src="scope.row.devicePic" style="max-width: 600px; max-height: 600px; object-fit: contain" />
|
||
</el-popover>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="deviceMac" label="设备MAC" />
|
||
<el-table-column prop="bluetoothName" label="蓝牙名称" />
|
||
<el-table-column prop="deviceImei" label="设备IMEI" />
|
||
<el-table-column prop="typeName" label="设备类型" />
|
||
<el-table-column prop="bindingStatus" label="绑定状态">
|
||
<template #default="scope">
|
||
<el-tag :type="scope.row.bindingStatus === 1 ? 'success' : 'info'">
|
||
{{ scope.row.bindingStatus === 1 ? '已绑定' : '未绑定' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="deviceStatus" label="设备状态">
|
||
<template #default="scope">
|
||
<el-tag :type="scope.row.deviceStatus == 1 ? 'success' : 'danger'">
|
||
{{ scope.row.deviceStatus == 1 ? '正常' : '失效' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="remark" label="备注" />
|
||
<el-table-column prop="createTime" label="创建日期" width="160" />
|
||
<el-table-column prop="createByName" label="创建人" />
|
||
|
||
<el-table-column label="操作" fixed="right" width="280" class-name="small-padding fixed-width">
|
||
<template #default="scope">
|
||
<el-tooltip v-if="scope.row.id !== 1 && scope.row.deviceStatus == 1" content="修改" placement="top">
|
||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
<el-tooltip v-if="!scope.row.customerName" content="删除" placement="top">
|
||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
<el-tooltip v-if="scope.row.deviceStatus == 1 && !scope.row.customerName" content="分配" placement="top">
|
||
<el-button link type="primary" icon="User" @click="handleAssign(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
<el-tooltip v-if="scope.row.customerName && scope.row.deviceStatus == 1" content="撤回" placement="top">
|
||
<el-button link type="primary" icon="UploadFilled" @click="handleWithdraw(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
<el-tooltip v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0" content="解绑"
|
||
placement="top">
|
||
<el-button link type="primary" icon="Refresh" @click="handleUnbind(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
<el-tooltip v-if="scope.row.deviceImei" content="查看二维码" placement="top">
|
||
<el-button link type="primary" icon="Postcard" @click="showQrCode(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
|
||
:total="total" @pagination="getList" />
|
||
</el-card>
|
||
|
||
|
||
<!-- 添加或修改用户配置对话框 -->
|
||
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="30%" append-to-body
|
||
@close="closeDialog">
|
||
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="120px">
|
||
<el-row>
|
||
<el-col :span="24">
|
||
<el-form-item label="设备名称" prop="deviceName">
|
||
<el-input v-model="form.deviceName" placeholder="请输入设备名称" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row>
|
||
<el-col :span="24">
|
||
<el-form-item label="设备类型" prop="deviceType">
|
||
<el-select v-model="form.deviceType" placeholder="设备类型" @change="id => handleDeviceTypeChange(id)"
|
||
:disabled="form.id != ''">
|
||
<el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName"
|
||
:value="item.id" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row v-if="showMacField">
|
||
<el-col :span="24">
|
||
<el-form-item label="设备MAC" prop="deviceMac" required>
|
||
<el-input v-model="form.deviceMac" placeholder="请输入设备MAC" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row v-if="showMacField">
|
||
<el-col :span="24">
|
||
<el-form-item label="蓝牙名称" prop="bluetoothName" required>
|
||
<el-input v-model="form.bluetoothName" placeholder="请输入蓝牙名称" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row v-if="showImeiField">
|
||
<el-col :span="24">
|
||
<el-form-item label="设备IMEI" prop="deviceImei" required>
|
||
<el-input v-model="form.deviceImei" placeholder="请输入设备IMEI" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row>
|
||
<el-col :span="24">
|
||
<el-form-item label="设备图片" prop="image">
|
||
<el-upload action="#" list-type="picture-card" :before-upload="beforeUpload" :on-change="fileUploadChange"
|
||
:http-request="httpRequestImg" :file-list="fileList" :limit="1">
|
||
<i class="el-icon-plus"></i>
|
||
<template v-if="form.image && typeof form.image === 'string'">
|
||
<img :src="form.image" class="avatar" style="width:100px; height:100px; object-fit: contain" />
|
||
</template>
|
||
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row>
|
||
<el-col :span="24">
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button type="primary" @click="submitForm" :loading="loadingIng">确 定</el-button>
|
||
<el-button @click="cancel()">取 消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
<!-- 分配客户弹窗 -->
|
||
<el-dialog v-model="assignDialogVisible" title="分配客户" width="400px">
|
||
<el-form>
|
||
<el-form-item label="选择客户">
|
||
<el-select v-model="assignCustomerId" placeholder="请选择客户" style="width: 100%">
|
||
<el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName"
|
||
:value="item.customerId" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button @click="assignDialogVisible = false">取 消</el-button>
|
||
<el-button type="primary" @click="handleAssignConfirm" :loading="loadingIng">确 定</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
<!-- 导入设备数据弹窗 -->
|
||
<el-dialog v-model="importDialogVisible" title="导入设备数据" width="500px">
|
||
<div style="margin-bottom: 16px;">
|
||
<p>请按照模板文件的格式准备需要导入的数据。</p>
|
||
<p>模板文件中的表头请勿修改,数据请从第二行开始填写。</p>
|
||
<el-button type="primary" icon="el-icon-download" @click="downloadTemplate">下载模板文件</el-button>
|
||
</div>
|
||
<el-upload ref="importUpload" :action="api.devicDeimport()" :headers="head_upload()" :show-file-list="false"
|
||
:before-upload="beforeImportUpload" :on-success="handleImportSuccess" :on-error="handleImportError" :limit="1"
|
||
accept=".xlsx,.xls">
|
||
<el-button type="success">选择文件开始导入</el-button>
|
||
<div v-if="!importResult.isShow" slot="tip" class="el-upload__tip">
|
||
<div style="color:#409EFF">只能上传模板excel文件</div>
|
||
</div>
|
||
<div v-if="importResult.isShow" slot="tip" class="el-upload__tip">
|
||
<span style="color:#409EFF">批量导入完成,共检测到 <span style="color:#E6A23C">{{ importResult.total }}</span>
|
||
条数据,导入成功 <span style="color:#67C23A">{{ importResult.succeed }}</span> 条,失败 <span style="color:red">{{
|
||
importResult.errorSun }}</span> 条。</span>
|
||
<p v-if="importResult.errorSun > 0" style="padding:10px;"><a :href="importResult.link">>>>
|
||
上传失败明细下载 <i class="el-icon-download" /></a></p>
|
||
</div>
|
||
</el-upload>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button @click="importDialogVisible = false">取 消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
<!-- 批量分配客户弹窗 -->
|
||
<el-dialog v-model="batchAssignDialogVisible" title="批量分配客户" width="400px">
|
||
<el-form>
|
||
<el-form-item label="选择客户">
|
||
<el-select v-model="batchAssignCustomerId" placeholder="请选择客户" style="width: 100%">
|
||
<el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName"
|
||
:value="item.customerId" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button @click="batchAssignDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleBatchAssignConfirm">确定</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
<!-- IMEI 二维码弹窗 -->
|
||
<el-dialog v-model="qrCodeDialogVisible" title="设备IMEI二维码" width="20%" append-to-body>
|
||
<div style="text-align: center;">
|
||
<QRCodeVue3 :value="qrCodeValue" :size="100" />
|
||
<p style="margin-top: 10px;">{{ qrCodeValue }}</p>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button @click="qrCodeDialogVisible = false">关闭</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup name="User" lang="ts">
|
||
import QRCodeVue3 from 'qrcode-vue3';
|
||
import api from '@/api/equipmentManagement/device/index';
|
||
import { deviceForm, deviceQuery, deviceVO, deviceTypeOption } from '@/api/equipmentManagement/device/types';
|
||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||
const deviceDist = ref<deviceVO[]>();
|
||
import { to } from 'await-to-js';
|
||
import request from "@/utils/request";
|
||
import { getBearerToken } from '@/utils/auth'
|
||
const loading = ref(true);
|
||
const showSearch = ref(true);
|
||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||
const ids = ref<deviceVO[]>([]);
|
||
const single = ref(true);
|
||
const multiple = ref(true);
|
||
const total = ref(0);
|
||
const initPassword = ref<string>('');
|
||
const queryFormRef = ref<ElFormInstance>();
|
||
const userFormRef = ref<ElFormInstance>();
|
||
const formDialogRef = ref<ElDialogInstance>();
|
||
const deviceTypeOptions = ref([]); //设备类型
|
||
const fileList = ref()
|
||
const communicationModeInfo = ref<any>(null);
|
||
const showMacField = ref(false); //MAC地址
|
||
const showImeiField = ref(false); //mei地址
|
||
const assignDialogVisible = ref(false); //分配客户
|
||
const importDialogVisible = ref(false);//批量导入
|
||
const batchAssignDialogVisible = ref(false) //批量分配客户
|
||
const loadingIng = ref(false)
|
||
const assignCustomerId = ref(); //分配客户id
|
||
const batchAssignCustomerId = ref() //批量分配客户id
|
||
const customerList = ref()
|
||
const qrCodeDialogVisible = ref(false);
|
||
const qrCodeValue = ref('');
|
||
const dialog = reactive<DialogOption>({
|
||
visible: false,
|
||
title: ''
|
||
});
|
||
|
||
const initFormData: deviceForm = {
|
||
deviceName: '',
|
||
deviceMac: '',
|
||
deviceImei: '',
|
||
remark: '',
|
||
id: '',
|
||
deviceType: "",
|
||
image: '',
|
||
bluetoothName: '' // 蓝牙名称字段
|
||
};
|
||
|
||
const initData: PageData<deviceForm, deviceQuery> = {
|
||
form: { ...initFormData },
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
deviceName: '',
|
||
deviceMac: '',
|
||
deviceImei: '',
|
||
deviceType: '',
|
||
deviceStatus: '',
|
||
|
||
},
|
||
rules: {
|
||
deviceName: [
|
||
{ required: true, message: '请输入设备名称', trigger: 'blur' },
|
||
],
|
||
deviceType: [
|
||
{ required: true, message: '请选择设备类型', trigger: 'blur' },
|
||
],
|
||
bluetoothName: [
|
||
{ required: true, message: '请输入蓝牙名称', trigger: 'blur' },
|
||
],
|
||
deviceMac: [
|
||
{ required: true, message: '请输入设备MAC', trigger: 'blur' },
|
||
],
|
||
deviceImei: [
|
||
{ required: true, message: '请输入设备IMEI', trigger: 'blur' },
|
||
],
|
||
|
||
}
|
||
};
|
||
const data = reactive<PageData<deviceForm, deviceQuery>>(initData);
|
||
const { queryParams, form, rules } = toRefs<PageData<deviceForm, deviceQuery>>(data);
|
||
/** 查询设备列表 */
|
||
const getList = async () => {
|
||
loading.value = true;
|
||
const res = await api.deviceList(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||
loading.value = false;
|
||
deviceDist.value = res.rows;
|
||
total.value = res.total;
|
||
};
|
||
|
||
|
||
/** 搜索按钮操作 */
|
||
const handleQuery = () => {
|
||
queryParams.value.pageNum = 1;
|
||
getList();
|
||
};
|
||
/** 重置按钮操作 */
|
||
const resetQuery = () => {
|
||
queryFormRef.value?.resetFields();
|
||
dateRange.value = ['', ''];
|
||
handleQuery()
|
||
};
|
||
|
||
/** 删除按钮操作 */
|
||
const handleDelete = async (row?: deviceVO) => {
|
||
// 批量删除逻辑
|
||
let arrey = ids.value.map((item) => item.id);
|
||
if (!row) {
|
||
const [err] = await to(proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }));
|
||
if (!err) {
|
||
await api.deleteDevice(arrey);
|
||
await getList();
|
||
proxy?.$modal.msgSuccess('删除成功');
|
||
}
|
||
return;
|
||
}
|
||
// 单行删除逻辑
|
||
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.deviceName + '"的数据项?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }));
|
||
if (!err) {
|
||
await api.deleteDevice([row.id]);
|
||
await getList();
|
||
proxy?.$modal.msgSuccess('删除成功');
|
||
}
|
||
};
|
||
/** 导出按钮操作 */
|
||
const handleExport = () => {
|
||
proxy?.download(
|
||
'/api/device/download',
|
||
{
|
||
...queryParams.value
|
||
},
|
||
`${new Date().getTime()}.xlsx`,
|
||
'get'
|
||
);
|
||
};
|
||
// 解绑
|
||
const handleUnbind = (row) => {
|
||
proxy?.$modal.confirm(`确定要解绑设备 ${row.deviceName} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
let data = {
|
||
id: row.id
|
||
}
|
||
api.deviceUnbind(data).then(res => {
|
||
if (res.code == 200) {
|
||
proxy?.$modal.msgSuccess(res.msg)
|
||
getList(); // 初始化列表数据
|
||
} else {
|
||
proxy?.$modal.msgError(res.msg)
|
||
}
|
||
})
|
||
}).catch(() => {
|
||
|
||
})
|
||
};
|
||
// 撤回
|
||
const handleWithdraw = (row: any) => {
|
||
proxy?.$modal.confirm(`确定要从客户 ${row.customerName} 撤回设备 ${row.deviceName} 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
api.withdrawDevice([row.id]).then(res => {
|
||
if (res.code === 200) {
|
||
proxy?.$modal.msgSuccess('撤回成功')
|
||
getList(); // 初始化列表数据
|
||
} else {
|
||
proxy?.$modal.msgError(res.msg || '撤回失败')
|
||
}
|
||
})
|
||
}).catch(() => {
|
||
proxy?.$modal.msgError('已取消撤回')
|
||
})
|
||
}
|
||
|
||
|
||
/** 选择条数 */
|
||
const handleSelectionChange = (selection: deviceVO[]) => {
|
||
ids.value = selection.map((item) => item);
|
||
single.value = selection.length != 1;
|
||
multiple.value = !selection.length;
|
||
};
|
||
|
||
|
||
/** 重置操作表单 */
|
||
const reset = () => {
|
||
form.value = { ...initFormData };
|
||
userFormRef.value?.resetFields();
|
||
fileList.value = []
|
||
};
|
||
/** 取消按钮 */
|
||
const cancel = () => {
|
||
dialog.visible = false;
|
||
reset();
|
||
};
|
||
|
||
/** 新增按钮操作 */
|
||
const handleAdd = async () => {
|
||
reset();
|
||
dialog.visible = true;
|
||
dialog.title = '新增设备';
|
||
form.value.password = initPassword.value.toString();
|
||
// 新增时默认不显示
|
||
showMacField.value = false;
|
||
showImeiField.value = false;
|
||
// 每次打开弹框时获取最新的设备类型数据
|
||
getDeviceType();
|
||
};
|
||
|
||
/** 修改按钮操作 */
|
||
const handleUpdate = async (row?: deviceForm) => {
|
||
reset();
|
||
dialog.visible = true;
|
||
dialog.title = '修改设备';
|
||
// 每次打开弹框时获取最新的设备类型数据
|
||
getDeviceType();
|
||
try {
|
||
if (row) {
|
||
// 使用 nextTick 确保对话框完全渲染后再设置表单值
|
||
await nextTick();
|
||
Object.assign(form.value, row);
|
||
form.value.image = row.devicePic
|
||
// 编辑时根据已有值显示字段
|
||
showMacField.value = !!row.deviceMac;
|
||
showImeiField.value = !!row.deviceImei;
|
||
} else {
|
||
const customerId = ids.value[0];
|
||
Object.assign(form.value, customerId);
|
||
form.value.image = customerId.devicePic //图片回显
|
||
// 编辑时根据已有值显示字段
|
||
showMacField.value = !!customerId.deviceMac;
|
||
showImeiField.value = !!customerId.deviceImei;
|
||
}
|
||
// 加载设备类型对应的通讯方式
|
||
if (form.value.deviceType) {
|
||
await handleDeviceTypeChange(form.value.deviceType);
|
||
}
|
||
} catch (error) {
|
||
dialog.visible = false;
|
||
}
|
||
};
|
||
// 设备类型触发事件
|
||
let isProcessing = false; // 添加处理锁
|
||
const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
|
||
// 重置规则和显示状态
|
||
rules.value.deviceMac = [];
|
||
rules.value.deviceImei = [];
|
||
showMacField.value = false;
|
||
showImeiField.value = false;
|
||
communicationModeInfo.value = null;
|
||
// 编辑时如果有值,根据已有值确定显示哪个字段
|
||
if (form.value.id) {
|
||
if (form.value.deviceMac) {
|
||
showMacField.value = true;
|
||
rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }];
|
||
} else if (form.value.deviceImei) {
|
||
showImeiField.value = true;
|
||
rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }];
|
||
}
|
||
return;
|
||
}
|
||
if (isProcessing) return;
|
||
isProcessing = true;
|
||
// 新增或编辑时没有值,根据设备类型获取通讯方式
|
||
try {
|
||
userFormRef.value?.clearValidate(['deviceMac', 'deviceImei','bluetoothName']);
|
||
if (!deviceTypeId) {
|
||
return;
|
||
}
|
||
const res = await api.getCommunicationMode({ id: deviceTypeId });
|
||
if (res.code == 200 && res.data) {
|
||
communicationModeInfo.value = res.data;
|
||
// 根据通讯方式确定显示哪个字段
|
||
if (res.data.communicationMode == '1') { // 蓝牙设备 - 显示MAC
|
||
showMacField.value = true;
|
||
showImeiField.value = false;
|
||
form.value.deviceImei = ''; // 清空IMEI
|
||
} else if (res.data.communicationMode == '0') { // 4G设备 - 显示IMEI
|
||
showMacField.value = false;
|
||
showImeiField.value = true;
|
||
form.value.deviceMac = ''; // 清空MAC
|
||
form.value.bluetoothName = '' // 清空蓝牙名称
|
||
}
|
||
}
|
||
} catch (error) {
|
||
} finally {
|
||
isProcessing = false;
|
||
}
|
||
};
|
||
|
||
// 覆盖默认的上传行为,可以自定义上传的实现
|
||
const httpRequestImg = (parm): Promise<any> => {
|
||
return Promise.resolve();
|
||
};
|
||
const beforeUpload = (file) => {
|
||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||
const isJPG = file.type === "image/jpeg" || file.type === "image/png";
|
||
if (!isJPG) {
|
||
ElMessage.warning("请上传jpg、png格式,大小不超过2M的照片");
|
||
return false;
|
||
}
|
||
if (!isLt2M) {
|
||
ElMessage.warning("大小不超过2M的照片片");
|
||
return false;
|
||
}
|
||
return isJPG && isLt2M;
|
||
};
|
||
// 文件上传状态改变时触发
|
||
const fileUploadChange = (files, fileList) => {
|
||
console.log(fileList, '5555');
|
||
if (fileList.length > 0) {
|
||
form.value.image = fileList[0].raw; // 正确获取File对象
|
||
// 调试:检查是否是真正的 File 对象
|
||
console.log('File对象验证:', form.value.image);
|
||
} else {
|
||
form.value.image = null;
|
||
}
|
||
};
|
||
|
||
/** 提交按钮 */
|
||
const submitForm = async () => {
|
||
try {
|
||
const valid = await userFormRef.value?.validate();
|
||
if (!valid) return;
|
||
loadingIng.value = true;
|
||
const formData = new FormData();
|
||
// 处理图片字段
|
||
if (form.value.image instanceof File) {
|
||
formData.append('file', form.value.image);
|
||
} else if (form.value.image && typeof form.value.image === 'string') {
|
||
// 如果是URL且需要转换为二进制
|
||
const blob = await urlToBlob(form.value.image);
|
||
formData.append('file', blob, 'image.jpg'); // 添加文件名
|
||
}
|
||
// 添加其他必要字段
|
||
const fields = ['id', 'deviceName', 'deviceType', 'remark'];
|
||
fields.forEach(key => {
|
||
if (form.value[key] !== undefined && form.value[key] !== null) {
|
||
formData.append(key, String(form.value[key])); // 确保所有值都转为字符串
|
||
}
|
||
});
|
||
// 根据通讯方式,有条件地添加deviceMac或deviceImei
|
||
if (form.value.deviceMac) {
|
||
formData.append('deviceMac', form.value.deviceMac);
|
||
}
|
||
if (form.value.deviceImei) {
|
||
formData.append('deviceImei', form.value.deviceImei);
|
||
}
|
||
// 添加蓝牙名称字段(仅蓝牙设备)
|
||
if (form.value.bluetoothName) {
|
||
formData.append('bluetoothName', form.value.bluetoothName);
|
||
}
|
||
// 根据操作类型设置URL和方法
|
||
const isAdd = !form.value.id; // 注意这里逻辑反了,应该是没有id时是新增
|
||
const res = await request({
|
||
url: isAdd ? '/api/device/add' : '/api/device/update',
|
||
method: isAdd ? 'post' : 'put',
|
||
data: formData,
|
||
headers: {
|
||
'Content-Type': 'multipart/form-data'
|
||
}
|
||
});
|
||
if (res.code == 200) {
|
||
proxy?.$modal.msgSuccess('操作成功');
|
||
dialog.visible = false;
|
||
loadingIng.value = false;
|
||
await getList();
|
||
} else {
|
||
proxy?.$modal.msgWarning(res.msg)
|
||
loadingIng.value = false;
|
||
}
|
||
} catch (err) {
|
||
console.error(err);
|
||
loadingIng.value = false;
|
||
}
|
||
};
|
||
|
||
// URL转Blob的方法函数
|
||
const urlToBlob = async (url: string): Promise<Blob> => {
|
||
const response = await fetch(url);
|
||
if (!response.ok) throw new Error('图片加载失败');
|
||
return await response.blob();
|
||
};
|
||
|
||
/**
|
||
* 关闭用户弹窗
|
||
*/
|
||
const closeDialog = () => {
|
||
dialog.visible = false;
|
||
resetForm();
|
||
};
|
||
|
||
const showQrCode = (row: any) => {
|
||
if (row.deviceImei) {
|
||
qrCodeValue.value = row.deviceImei;
|
||
qrCodeDialogVisible.value = true;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 重置表单
|
||
*/
|
||
const resetForm = () => {
|
||
userFormRef.value?.resetFields();
|
||
userFormRef.value?.clearValidate();
|
||
form.value.customerId = undefined;
|
||
};
|
||
// 设备类型
|
||
const getDeviceType = () => {
|
||
api.deviceTypeAll().then(res => {
|
||
if (res.code == 200) {
|
||
deviceTypeOptions.value = res.data
|
||
}
|
||
}).catch(err => {
|
||
|
||
})
|
||
};
|
||
// 客户下拉框
|
||
const getAllCustomerAll = () => {
|
||
api.userAllCustomerAll().then(res => {
|
||
if (res.code == 200) {
|
||
customerList.value = res.data
|
||
}
|
||
})
|
||
};
|
||
// 分配客户
|
||
const assignRow = ref()
|
||
const handleAssign = (row: any) => {
|
||
console.log(row, 'eeeeee');
|
||
|
||
getAllCustomerAll()
|
||
assignDialogVisible.value = true
|
||
assignRow.value = row
|
||
assignCustomerId.value == !row.customerName ? row.customerId : ''
|
||
}
|
||
const handleAssignConfirm = () => {
|
||
if (!assignCustomerId.value) {
|
||
return proxy?.$modal.msgError('请选择客户')
|
||
}
|
||
loadingIng.value = true;
|
||
// 这里调用分配API
|
||
let data = {
|
||
customerId: assignCustomerId.value,
|
||
deviceIds: [assignRow.value.id]
|
||
}
|
||
api.deviceAssignCustomer(data).then((res) => {
|
||
if (res.code == 200) {
|
||
loadingIng.value = false;
|
||
const customer = customerList.value.find(c => c.id === assignCustomerId.value)
|
||
const customerName = customer ? customer.nickName : `ID: ${assignCustomerId.value}`
|
||
getList();
|
||
assignDialogVisible.value = false
|
||
return proxy?.$modal.msgSuccess(`设备已分配给客户: ${customerName}`)
|
||
} else {
|
||
loadingIng.value = false;
|
||
}
|
||
}).catch(() => {
|
||
loadingIng.value = false;
|
||
})
|
||
};
|
||
const importUpload = ref()
|
||
const importResult = ref()
|
||
const handleBatchImport = () => {
|
||
importDialogVisible.value = true
|
||
importResult.value = {
|
||
isShow: false,
|
||
total: 0,
|
||
succeed: 0,
|
||
errorSun: 0,
|
||
link: ''
|
||
}
|
||
nextTick(() => {
|
||
if (importUpload.value) {
|
||
importUpload.value.clearFiles()
|
||
}
|
||
})
|
||
};
|
||
const downloadTemplate = () => {
|
||
// 这里可用 window.open 或 a 标签下载模板
|
||
const link = document.createElement('a');
|
||
link.href = 'https://fuyuanshen.com/fys/Equipmentimporttemplate/EquipmentImportTemplate.xlsx';
|
||
link.download = '设备数据导入模板.xlsx'; // 可选:指定下载文件名
|
||
link.style.display = 'none'; // 隐藏标签
|
||
document.body.appendChild(link);
|
||
link.click(); // 触发下载
|
||
document.body.removeChild(link); // 移除标签
|
||
};
|
||
const beforeImportUpload = (file: any) => {
|
||
const isLt5M = file.size / 1024 / 1024 < 5
|
||
if (!isLt5M) {
|
||
proxy?.$modal.msgError('上传文件大小不能超过 5MB!')
|
||
}
|
||
return isLt5M
|
||
};
|
||
|
||
//添加tokenf方法head_upload 直接返回 getBearerToken()
|
||
const head_upload = () => getBearerToken();
|
||
const handleImportSuccess = (response: any) => {
|
||
if (response.code == 200) {
|
||
importResult.value.isShow = true
|
||
if (response.data) {
|
||
importResult.value.succeed = response.data.successCount || 0
|
||
importResult.value.errorSun = response.data.failureCount || 0
|
||
importResult.value.total = importResult.value.succeed + importResult.value.errorSun
|
||
importResult.value.link = response.data.errorExcelUrl || ''
|
||
}
|
||
getList(); // 初始化列表数据
|
||
} else {
|
||
proxy?.$modal.msgError(response.msg || '导入失败')
|
||
}
|
||
};
|
||
const handleImportError = () => {
|
||
proxy?.$modal.msgError('导入失败')
|
||
};
|
||
// 批量分配客户
|
||
const handleBatchAssign = () => {
|
||
batchAssignDialogVisible.value = true
|
||
getAllCustomerAll()
|
||
};
|
||
// 批量分配客户确定
|
||
const handleBatchAssignConfirm = () => {
|
||
if (!batchAssignCustomerId.value) {
|
||
return proxy?.$modal.msgError('请选择客户')
|
||
}
|
||
// 提取选中设备的 ID 数组
|
||
const selectedIds = ids.value.map((item: any) => item.id)
|
||
// 构造请求数据
|
||
const data = {
|
||
customerId: batchAssignCustomerId.value, // 目标客户ID
|
||
deviceIds: selectedIds // 选中的设备ID数组
|
||
}
|
||
api.deviceAssignCustomer(data).then((res) => {
|
||
if (res.code == 200) {
|
||
batchAssignDialogVisible.value = false
|
||
getList();
|
||
return proxy?.$modal.msgSuccess(`分配成功`)
|
||
}
|
||
}).catch(() => {
|
||
|
||
})
|
||
};
|
||
|
||
watch(() => form.value.deviceType, (newVal) => {
|
||
if (dialog.title === '新增设备') { // Only for add form
|
||
handleDeviceTypeChange(newVal);
|
||
}
|
||
});
|
||
onMounted(() => {
|
||
getList(); // 初始化列表数据
|
||
getDeviceType()
|
||
});
|
||
|
||
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
:deep .el-upload--picture-card {
|
||
width: 100px !important;
|
||
height: 100px !important;
|
||
border: 1px solid #cccc;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
:deep .el-upload.el-upload--text {
|
||
display: block;
|
||
}
|
||
|
||
:deep .el-upload-list--picture-card .el-upload-list__item {
|
||
width: 100px !important;
|
||
height: 100px !important;
|
||
}
|
||
|
||
:deep .el-upload-list__item-thumbnail {
|
||
width: 100px !important;
|
||
height: 100px !important;
|
||
object-fit: cover;
|
||
}
|
||
</style>
|