搜索加防抖

This commit is contained in:
liub
2025-09-09 16:58:00 +08:00
parent 6a85ea01da
commit 496c40f415
2 changed files with 344 additions and 279 deletions

View File

@ -1,10 +1,7 @@
<template> <template>
<div class="p-2"> <div class="p-2">
<div :class="Status.Mode == PageMode.device ? '' : 'displayNone'"> <div :class="Status.Mode == PageMode.device ? '' : 'displayNone'">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
@ -19,20 +16,25 @@
</el-form-item> </el-form-item>
<el-form-item label="设备类型" prop="deviceType"> <el-form-item label="设备类型" prop="deviceType">
<el-select v-model="queryParams.deviceType" placeholder="设备类型"> <el-select v-model="queryParams.deviceType" placeholder="设备类型">
<el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName" <el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName" :value="item.id" />
:value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="设备状态" prop="deviceStatus"> <el-form-item label="设备状态" prop="deviceStatus">
<el-select v-model="queryParams.deviceStatus" placeholder="设备状态" style="margin-left: 10px;"> <el-select v-model="queryParams.deviceStatus" placeholder="设备状态" style="margin-left: 10px">
<el-option label="正常" value="1" /> <el-option label="正常" value="1" />
<el-option label="失效" value="0" /> <el-option label="失效" value="0" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="创建时间"> <el-form-item label="创建时间">
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" <el-date-picker
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" v-model="dateRange"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker> 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-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@ -43,44 +45,39 @@
</div> </div>
</transition> </transition>
<el-card shadow="hover"> <el-card shadow="hover">
<template #header> <template #header>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['equipment:devices:add']" type="primary" plain icon="Plus" <el-button v-hasPermi="['equipment:devices:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
@click="handleAdd()">新增</el-button> </el-col>
</el-col> <el-col :span="1.5">
<el-col :span="1.5"> <el-button v-hasPermi="['equipment:devices:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
<el-button v-hasPermi="['equipment:devices:edit']" type="success" plain :disabled="single" icon="Edit" 修改
@click="handleUpdate()"> </el-button>
修改 </el-col>
</el-button>
</el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['equipment:devices:export']" type="warning" :disabled="multiple" plain <el-button v-hasPermi="['equipment:devices:export']" type="warning" :disabled="multiple" plain icon="Download" @click="handleExport"
icon="Download" @click="handleExport">导出</el-button> >导出</el-button
</el-col> >
<el-col :span="1.5"> </el-col>
<el-button v-hasPermi="['equipment:devices:remove']" type="danger" plain :disabled="multiple" <el-col :span="1.5">
@click="handleDelete()"> <el-button v-hasPermi="['equipment:devices:remove']" type="danger" plain :disabled="multiple" @click="handleDelete()">
批量删除 批量删除
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['equipment:devices:import']" type="warning" plain @click="handleBatchImport"> <el-button v-hasPermi="['equipment:devices:import']" type="warning" plain @click="handleBatchImport"> 批量导入 </el-button>
批量导入 </el-col>
</el-button> <el-col :span="1.5">
</el-col> <el-button v-hasPermi="['equipment:devices:allocate']" type="warning" plain :disabled="multiple" @click="handleBatchAssign">
<el-col :span="1.5"> 批量分配客户
<el-button v-hasPermi="['equipment:devices:allocate']" type="warning" plain :disabled="multiple" </el-button>
@click="handleBatchAssign"> </el-col>
批量分配客户 <right-toolbar v-model:show-search="showSearch" :search="true" @query-table="getList"></right-toolbar>
</el-button> </el-row>
</el-col> </template>
<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 v-loading="loading" border :data="deviceDist" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" /> <el-table-column type="selection" width="50" align="center" />
@ -90,9 +87,11 @@
<template #default="scope"> <template #default="scope">
<el-popover placement="right" trigger="click"> <el-popover placement="right" trigger="click">
<template #reference> <template #reference>
<img :src="scope.row.devicePic" <img
:src="scope.row.devicePic"
style="width: 40px; height: 40px; cursor: pointer; object-fit: contain" style="width: 40px; height: 40px; cursor: pointer; object-fit: contain"
class="hover:opacity-80 transition-opacity" /> class="hover:opacity-80 transition-opacity"
/>
</template> </template>
<img :src="scope.row.devicePic" style="max-width: 600px; max-height: 600px; object-fit: contain" /> <img :src="scope.row.devicePic" style="max-width: 600px; max-height: 600px; object-fit: contain" />
</el-popover> </el-popover>
@ -120,46 +119,81 @@
<el-table-column prop="createTime" label="创建日期" width="160" /> <el-table-column prop="createTime" label="创建日期" width="160" />
<el-table-column prop="createByName" label="创建人" /> <el-table-column prop="createByName" label="创建人" />
<el-table-column label="操作" fixed="right" width="280" class-name="small-padding fixed-width"> <el-table-column label="操作" fixed="right" width="280" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-tooltip v-if="scope.row.id !== 1 && scope.row.deviceStatus == 1" content="修改" placement="top"> <el-tooltip v-if="scope.row.id !== 1 && scope.row.deviceStatus == 1" content="修改" placement="top">
<el-button v-hasPermi="['equipment:devices:edit']" link type="primary" icon="Edit" <el-button v-hasPermi="['equipment:devices:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
@click="handleUpdate(scope.row)"></el-button> </el-tooltip>
</el-tooltip> <el-tooltip v-if="!scope.row.customerName" content="删除" placement="top">
<el-tooltip v-if="!scope.row.customerName" content="删除" placement="top"> <el-button v-hasPermi="['equipment:devices:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
<el-button v-hasPermi="['equipment:devices:remove']" link type="primary" icon="Delete" </el-tooltip>
@click="handleDelete(scope.row)"></el-button> <el-tooltip v-if="scope.row.deviceStatus == 1 && !scope.row.customerName" content="分配" placement="top">
</el-tooltip> <el-button v-hasPermi="['equipment:devices:allocate']" link type="primary" icon="User" @click="handleAssign(scope.row)"></el-button>
<el-tooltip v-if="scope.row.deviceStatus == 1 && !scope.row.customerName" content="分配" placement="top"> </el-tooltip>
<el-button v-hasPermi="['equipment:devices:allocate']" link type="primary" icon="User" <el-tooltip v-if="scope.row.customerName && scope.row.deviceStatus == 1" content="撤回" placement="top">
@click="handleAssign(scope.row)"></el-button> <el-button
</el-tooltip> v-hasPermi="['equipment:devices:revoke']"
<el-tooltip v-if="scope.row.customerName && scope.row.deviceStatus == 1" content="撤回" placement="top"> link
<el-button v-hasPermi="['equipment:devices:revoke']" link type="primary" icon="UploadFilled" type="primary"
@click="handleWithdraw(scope.row)"></el-button> icon="UploadFilled"
</el-tooltip> @click="handleWithdraw(scope.row)"
<el-tooltip v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0" content="解绑" ></el-button>
placement="top"> </el-tooltip>
<el-button v-hasPermi="['equipment:devices:unbind']" link type="primary" icon="Refresh" <el-tooltip v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0" content="解绑" placement="top">
@click="handleUnbind(scope.row)"></el-button> <el-button v-hasPermi="['equipment:devices:unbind']" link type="primary" icon="Refresh" @click="handleUnbind(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip v-if="scope.row.deviceImei" content="查看二维码" placement="top"> <el-tooltip v-if="scope.row.deviceImei" content="查看二维码" placement="top">
<el-button link type="primary" icon="Postcard" @click="showQrCode(scope.row)"></el-button> <el-button link type="primary" icon="Postcard" @click="showQrCode(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="详情" placement="top"> <el-tooltip content="详情" placement="top">
<el-button link type="primary" icon="More" @click="handleDetail(scope.row)"></el-button> <el-button link type="primary" icon="More" @click="handleDetail(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
:total="total" @pagination="getList" /> </el-card>
</el-card> </div>
<div :class="Status.Mode == PageMode.detail ? '' : 'displayNone'" class="detailMain">
<div class="tabContent">
<div class="tabHeader">
<div class="indexContent">
<div class="tabIndex" :class="Status.tabActive == 1 ? 'active' : ''" @click="tabIndexChange(1)">设备信息</div>
<div class="tabIndex" :class="Status.tabActive == 2 ? 'active' : ''" @click="tabIndexChange(2)">用户信息</div>
<div class="tabIndex" :class="Status.tabActive == 3 ? 'active' : ''" @click="tabIndexChange(3)">操作记录</div>
<div class="tabIndex" :class="Status.tabActive == 4 ? 'active' : ''" @click="tabIndexChange(4)">报警记录</div>
<div class="tabIndex" :class="Status.tabActive == 5 ? 'active' : ''" @click="tabIndexChange(5)">分享管理</div>
<div class="tabIndex" :class="Status.tabActive == 6 ? 'active' : ''" @click="tabIndexChange(6)">充放电</div>
</div>
<div class="tabClose">
<el-icon @click="closeDetail()" :size="20" :color="'#7787a4'">
<Close />
</el-icon>
</div>
</div>
<div class="tabItem" v-show="Status.tabActive == 1">
<eqDetail :data="detailData" :acIndex="Status.tabActive" data-name="eqDetail"></eqDetail>
</div>
<div class="tabItem" v-show="Status.tabActive == 2">
<Usr :data="detailData" :acIndex="Status.tabActive" data-name="Usr"></Usr>
</div>
<div class="tabItem" v-show="Status.tabActive == 3">
<OpraRecored :data="detailData" :acIndex="Status.tabActive" data-name="OpraRecored"></OpraRecored>
</div>
<div class="tabItem" v-show="Status.tabActive == 4">
<WarnRecord :data="detailData" :acIndex="Status.tabActive" data-name="WarnRecord"></WarnRecord>
</div>
<div class="tabItem" v-show="Status.tabActive == 5">
<shareManage :data="detailData" :acIndex="Status.tabActive" data-name="shareManage"></shareManage>
</div>
<div class="tabItem" v-show="Status.tabActive == 6">
<Charge :data="detailData" :acIndex="Status.tabActive" data-name="Charge"></Charge>
</div>
</div>
</div>
<!-- 添加或修改用户配置对话框 --> <!-- 添加或修改用户配置对话框 -->
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="30%" append-to-body <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="30%" append-to-body @close="closeDialog">
@close="closeDialog">
<el-form ref="userFormRef" :model="form" :rules="rules" label-width="120px"> <el-form ref="userFormRef" :model="form" :rules="rules" label-width="120px">
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
@ -171,10 +205,8 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="设备类型" prop="deviceType"> <el-form-item label="设备类型" prop="deviceType">
<el-select v-model="form.deviceType" placeholder="设备类型" @change="id => handleDeviceTypeChange(id)" <el-select v-model="form.deviceType" placeholder="设备类型" @change="(id) => handleDeviceTypeChange(id)" :disabled="form.id != ''">
:disabled="form.id != ''"> <el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName" :value="item.id" />
<el-option v-for="item in deviceTypeOptions" :key="item.value" :label="item.typeName"
:value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -203,13 +235,19 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="设备图片" prop="image"> <el-form-item label="设备图片" prop="image">
<el-upload action="#" list-type="picture-card" :before-upload="beforeUpload" :on-change="fileUploadChange" <el-upload
:http-request="httpRequestImg" :file-list="fileList" :limit="1"> 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> <i class="el-icon-plus"></i>
<template v-if="form.image && typeof form.image === 'string'"> <template v-if="form.image && typeof form.image === 'string'">
<img :src="form.image" class="avatar" style="width:100px; height:100px; object-fit: contain" /> <img :src="form.image" class="avatar" style="width: 100px; height: 100px; object-fit: contain" />
</template> </template>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -234,8 +272,7 @@
<el-form> <el-form>
<el-form-item label="选择客户"> <el-form-item label="选择客户">
<el-select v-model="assignCustomerId" placeholder="请选择客户" style="width: 100%"> <el-select v-model="assignCustomerId" placeholder="请选择客户" style="width: 100%">
<el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName" <el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName" :value="item.customerId" />
:value="item.customerId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -248,24 +285,35 @@
</el-dialog> </el-dialog>
<!-- 导入设备数据弹窗 --> <!-- 导入设备数据弹窗 -->
<el-dialog v-model="importDialogVisible" title="导入设备数据" width="500px"> <el-dialog v-model="importDialogVisible" title="导入设备数据" width="500px">
<div style="margin-bottom: 16px;"> <div style="margin-bottom: 16px">
<p>请按照模板文件的格式准备需要导入的数据</p> <p>请按照模板文件的格式准备需要导入的数据</p>
<p>模板文件中的表头请勿修改数据请从第二行开始填写</p> <p>模板文件中的表头请勿修改数据请从第二行开始填写</p>
<el-button type="primary" icon="el-icon-download" @click="downloadTemplate">下载模板文件</el-button> <el-button type="primary" icon="el-icon-download" @click="downloadTemplate">下载模板文件</el-button>
</div> </div>
<el-upload ref="importUpload" :action="api.devicDeimport()" :headers="head_upload()" :show-file-list="false" <el-upload
:before-upload="beforeImportUpload" :on-success="handleImportSuccess" :on-error="handleImportError" :limit="1" ref="importUpload"
accept=".xlsx,.xls"> :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> <el-button type="success">选择文件开始导入</el-button>
<div v-if="!importResult.isShow" slot="tip" class="el-upload__tip"> <div v-if="!importResult.isShow" slot="tip" class="el-upload__tip">
<div style="color:#409EFF">只能上传模板excel文件</div> <div style="color: #409eff">只能上传模板excel文件</div>
</div> </div>
<div v-if="importResult.isShow" slot="tip" class="el-upload__tip"> <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: #409eff"
条数据导入成功 <span style="color:#67C23A">{{ importResult.succeed }}</span> 失败 <span style="color:red">{{ >批量导入完成共检测到 <span style="color: #e6a23c">{{ importResult.total }}</span> 数据导入成功
importResult.errorSun }}</span> </span> <span style="color: #67c23a">{{ importResult.succeed }}</span> 失败
<p v-if="importResult.errorSun > 0" style="padding:10px;"><a :href="importResult.link">>>> <span style="color: red">{{ importResult.errorSun }}</span> </span
上传失败明细下载 <i class="el-icon-download" /></a></p> >
<p v-if="importResult.errorSun > 0" style="padding: 10px">
<a :href="importResult.link">>>> 上传失败明细下载 <i class="el-icon-download" /></a>
</p>
</div> </div>
</el-upload> </el-upload>
<template #footer> <template #footer>
@ -279,8 +327,7 @@
<el-form> <el-form>
<el-form-item label="选择客户"> <el-form-item label="选择客户">
<el-select v-model="batchAssignCustomerId" placeholder="请选择客户" style="width: 100%"> <el-select v-model="batchAssignCustomerId" placeholder="请选择客户" style="width: 100%">
<el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName" <el-option v-for="item in customerList" :key="item.customerId" :label="item.nickName" :value="item.customerId" />
:value="item.customerId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -293,10 +340,10 @@
</el-dialog> </el-dialog>
<!-- IMEI 二维码弹窗 --> <!-- IMEI 二维码弹窗 -->
<el-dialog v-model="qrCodeDialogVisible" title="设备IMEI二维码" width="20%" append-to-body> <el-dialog v-model="qrCodeDialogVisible" title="设备IMEI二维码" width="20%" append-to-body>
<div style="text-align: center;"> <div style="text-align: center">
<!-- 使用 v-if 强制重新渲染 --> <!-- 使用 v-if 强制重新渲染 -->
<QRCodeVue3 v-if="qrCodeDialogVisible" :value="qrCodeValue" :size="100" /> <QRCodeVue3 v-if="qrCodeDialogVisible" :value="qrCodeValue" :size="100" />
<p style="margin-top: 10px;">{{ qrCodeValue }}</p> <p style="margin-top: 10px">{{ qrCodeValue }}</p>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -314,8 +361,8 @@ import { deviceForm, deviceQuery, deviceVO, deviceTypeOption } from '@/api/equip
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const deviceDist = ref<deviceVO[]>(); const deviceDist = ref<deviceVO[]>();
import { to } from 'await-to-js'; import { to } from 'await-to-js';
import request from "@/utils/request"; import request from '@/utils/request';
import { getBearerToken } from '@/utils/auth' import { getBearerToken } from '@/utils/auth';
import eqDetail from './eqDetail.vue'; import eqDetail from './eqDetail.vue';
import Usr from './Usr.vue'; import Usr from './Usr.vue';
@ -337,17 +384,17 @@ const queryFormRef = ref<ElFormInstance>();
const userFormRef = ref<ElFormInstance>(); const userFormRef = ref<ElFormInstance>();
const formDialogRef = ref<ElDialogInstance>(); const formDialogRef = ref<ElDialogInstance>();
const deviceTypeOptions = ref([]); //设备类型 const deviceTypeOptions = ref([]); //设备类型
const fileList = ref() const fileList = ref();
const communicationModeInfo = ref<any>(null); const communicationModeInfo = ref<any>(null);
const showMacField = ref(false); //MAC地址 const showMacField = ref(false); //MAC地址
const showImeiField = ref(false); //mei地址 const showImeiField = ref(false); //mei地址
const assignDialogVisible = ref(false); //分配客户 const assignDialogVisible = ref(false); //分配客户
const importDialogVisible = ref(false);//批量导入 const importDialogVisible = ref(false); //批量导入
const batchAssignDialogVisible = ref(false) //批量分配客户 const batchAssignDialogVisible = ref(false); //批量分配客户
const loadingIng = ref(false) const loadingIng = ref(false);
const assignCustomerId = ref(); //分配客户id const assignCustomerId = ref(); //分配客户id
const batchAssignCustomerId = ref() //批量分配客户id const batchAssignCustomerId = ref(); //批量分配客户id
const customerList = ref() const customerList = ref();
const qrCodeDialogVisible = ref(false); const qrCodeDialogVisible = ref(false);
const qrCodeValue = ref(''); const qrCodeValue = ref('');
const dialog = reactive<DialogOption>({ const dialog = reactive<DialogOption>({
@ -355,12 +402,10 @@ const dialog = reactive<DialogOption>({
title: '' title: ''
}); });
//页面类型 //页面类型
enum PageMode { enum PageMode {
device = 'device',//设备 device = 'device', //设备
detail = 'detail'//详情 detail = 'detail' //详情
} }
//页面状态控制 //页面状态控制
@ -380,7 +425,7 @@ function handleDetail(item) {
//关闭详情 //关闭详情
function closeDetail() { function closeDetail() {
Status.Mode = PageMode.device; Status.Mode = PageMode.device;
Status.tabActive = -1; Status.tabActive = -1;
} }
function tabIndexChange(index) { function tabIndexChange(index) {
@ -397,7 +442,7 @@ const initFormData: deviceForm = {
deviceImei: '', deviceImei: '',
remark: '', remark: '',
id: '', id: '',
deviceType: "", deviceType: '',
image: '', image: '',
bluetoothName: '' // 蓝牙名称字段 bluetoothName: '' // 蓝牙名称字段
}; };
@ -411,26 +456,14 @@ const initData: PageData<deviceForm, deviceQuery> = {
deviceMac: '', deviceMac: '',
deviceImei: '', deviceImei: '',
deviceType: '', deviceType: '',
deviceStatus: '', deviceStatus: ''
}, },
rules: { rules: {
deviceName: [ deviceName: [{ required: true, message: '请输入设备名称', trigger: 'blur' }],
{ required: true, message: '请输入设备名称', trigger: 'blur' }, deviceType: [{ required: true, message: '请选择设备类型', trigger: 'blur' }],
], bluetoothName: [{ required: true, message: '请输入蓝牙名称', trigger: 'blur' }],
deviceType: [ deviceMac: [{ required: true, message: '请输入设备MAC', trigger: 'blur' }],
{ required: true, message: '请选择设备类型', trigger: 'blur' }, deviceImei: [{ required: true, message: '请输入设备IMEI', 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 data = reactive<PageData<deviceForm, deviceQuery>>(initData);
@ -444,7 +477,6 @@ const getList = async () => {
total.value = res.total; total.value = res.total;
}; };
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1;
@ -454,7 +486,7 @@ const handleQuery = () => {
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value?.resetFields(); queryFormRef.value?.resetFields();
dateRange.value = ['', '']; dateRange.value = ['', ''];
handleQuery() handleQuery();
}; };
/** 删除按钮操作 */ /** 删除按钮操作 */
@ -462,7 +494,13 @@ const handleDelete = async (row?: deviceVO) => {
// 批量删除逻辑 // 批量删除逻辑
let arrey = ids.value.map((item) => item.id); let arrey = ids.value.map((item) => item.id);
if (!row) { if (!row) {
const [err] = await to(proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })); const [err] = await to(
proxy?.$modal.confirm(`是否确认删除选中的 ${ids.value.length} 条数据?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
);
if (!err) { if (!err) {
await api.deleteDevice(arrey); await api.deleteDevice(arrey);
await getList(); await getList();
@ -471,7 +509,13 @@ const handleDelete = async (row?: deviceVO) => {
return; return;
} }
// 单行删除逻辑 // 单行删除逻辑
const [err] = await to(proxy?.$modal.confirm('是否确认删除"' + row.deviceName + '"的数据项?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })); const [err] = await to(
proxy?.$modal.confirm('是否确认删除"' + row.deviceName + '"的数据项?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
);
if (!err) { if (!err) {
await api.deleteDevice([row.id]); await api.deleteDevice([row.id]);
await getList(); await getList();
@ -491,46 +535,49 @@ const handleExport = () => {
}; };
// 解绑 // 解绑
const handleUnbind = (row) => { const handleUnbind = (row) => {
proxy?.$modal.confirm(`确定要解绑设备 ${row.deviceName} 吗?`, '提示', { proxy?.$modal
confirmButtonText: '确定', .confirm(`确定要解绑设备 ${row.deviceName} 吗?`, '提示', {
cancelButtonText: '取消', confirmButtonText: '确定',
type: 'warning' cancelButtonText: '取消',
}).then(() => { type: 'warning'
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(() => { .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) => { const handleWithdraw = (row: any) => {
proxy?.$modal.confirm(`确定要从客户 ${row.customerName} 撤回设备 ${row.deviceName} 吗?`, '提示', { proxy?.$modal
confirmButtonText: '确定', .confirm(`确定要从客户 ${row.customerName} 撤回设备 ${row.deviceName} 吗?`, '提示', {
cancelButtonText: '取消', confirmButtonText: '确定',
type: 'warning' cancelButtonText: '取消',
}).then(() => { type: 'warning'
api.withdrawDevice([row.id]).then(res => {
if (res.code === 200) {
proxy?.$modal.msgSuccess('撤回成功')
getList(); // 初始化列表数据
} else {
proxy?.$modal.msgError(res.msg || '撤回失败')
}
}) })
}).catch(() => { .then(() => {
proxy?.$modal.msgError('已取消撤回') 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[]) => { const handleSelectionChange = (selection: deviceVO[]) => {
@ -539,12 +586,11 @@ const handleSelectionChange = (selection: deviceVO[]) => {
multiple.value = !selection.length; multiple.value = !selection.length;
}; };
/** 重置操作表单 */ /** 重置操作表单 */
const reset = () => { const reset = () => {
form.value = { ...initFormData }; form.value = { ...initFormData };
userFormRef.value?.resetFields(); userFormRef.value?.resetFields();
fileList.value = [] fileList.value = [];
}; };
/** 取消按钮 */ /** 取消按钮 */
const cancel = () => { const cancel = () => {
@ -576,14 +622,14 @@ const handleUpdate = async (row?: deviceForm) => {
// 使用 nextTick 确保对话框完全渲染后再设置表单值 // 使用 nextTick 确保对话框完全渲染后再设置表单值
await nextTick(); await nextTick();
Object.assign(form.value, row); Object.assign(form.value, row);
form.value.image = row.devicePic form.value.image = row.devicePic;
// 编辑时根据已有值显示字段 // 编辑时根据已有值显示字段
showMacField.value = !!row.deviceMac; showMacField.value = !!row.deviceMac;
showImeiField.value = !!row.deviceImei; showImeiField.value = !!row.deviceImei;
} else { } else {
const customerId = ids.value[0]; const customerId = ids.value[0];
Object.assign(form.value, customerId); Object.assign(form.value, customerId);
form.value.image = customerId.devicePic //图片回显 form.value.image = customerId.devicePic; //图片回显
// 编辑时根据已有值显示字段 // 编辑时根据已有值显示字段
showMacField.value = !!customerId.deviceMac; showMacField.value = !!customerId.deviceMac;
showImeiField.value = !!customerId.deviceImei; showImeiField.value = !!customerId.deviceImei;
@ -619,15 +665,13 @@ const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }]; rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }];
rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }]; rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }];
console.log('两个字段都有值'); console.log('两个字段都有值');
} } else if (hasMac) {
else if (hasMac) {
showMacField.value = true; showMacField.value = true;
showImeiField.value = false; showImeiField.value = false;
rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }]; rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }];
rules.value.deviceImei = []; rules.value.deviceImei = [];
console.log('只有 Mac 有值'); console.log('只有 Mac 有值');
} } else if (hasImei) {
else if (hasImei) {
showImeiField.value = true; showImeiField.value = true;
showMacField.value = false; showMacField.value = false;
rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }]; rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }];
@ -648,16 +692,19 @@ const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
if (res.code == 200 && res.data) { if (res.code == 200 && res.data) {
communicationModeInfo.value = res.data; communicationModeInfo.value = res.data;
// 根据通讯方式确定显示哪个字段 // 根据通讯方式确定显示哪个字段
if (res.data.communicationMode == '1') { // 蓝牙设备 - 显示MAC if (res.data.communicationMode == '1') {
// 蓝牙设备 - 显示MAC
showMacField.value = true; showMacField.value = true;
showImeiField.value = false; showImeiField.value = false;
form.value.deviceImei = ''; // 清空IMEI form.value.deviceImei = ''; // 清空IMEI
} else if (res.data.communicationMode == '0') { // 4G设备 - 显示IMEI } else if (res.data.communicationMode == '0') {
// 4G设备 - 显示IMEI
showMacField.value = false; showMacField.value = false;
showImeiField.value = true; showImeiField.value = true;
form.value.deviceMac = ''; // 清空MAC form.value.deviceMac = ''; // 清空MAC
form.value.bluetoothName = '' // 清空蓝牙名称 form.value.bluetoothName = ''; // 清空蓝牙名称
} else if (res.data.communicationMode == '2') { //既是4G设备又是蓝牙设备 } else if (res.data.communicationMode == '2') {
//既是4G设备又是蓝牙设备
showImeiField.value = true; showImeiField.value = true;
showMacField.value = true; showMacField.value = true;
} }
@ -674,13 +721,13 @@ const httpRequestImg = (parm): Promise<any> => {
}; };
const beforeUpload = (file) => { const beforeUpload = (file) => {
const isLt2M = file.size / 1024 / 1024 < 2; const isLt2M = file.size / 1024 / 1024 < 2;
const isJPG = file.type === "image/jpeg" || file.type === "image/png"; const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJPG) { if (!isJPG) {
ElMessage.warning("请上传jpg、png格式大小不超过2M的照片"); ElMessage.warning('请上传jpg、png格式大小不超过2M的照片');
return false; return false;
} }
if (!isLt2M) { if (!isLt2M) {
ElMessage.warning("大小不超过2M的照片片"); ElMessage.warning('大小不超过2M的照片片');
return false; return false;
} }
return isJPG && isLt2M; return isJPG && isLt2M;
@ -714,7 +761,7 @@ const submitForm = async () => {
} }
// 添加其他必要字段 // 添加其他必要字段
const fields = ['id', 'deviceName', 'deviceType', 'remark']; const fields = ['id', 'deviceName', 'deviceType', 'remark'];
fields.forEach(key => { fields.forEach((key) => {
if (form.value[key] !== undefined && form.value[key] !== null) { if (form.value[key] !== undefined && form.value[key] !== null) {
formData.append(key, String(form.value[key])); // 确保所有值都转为字符串 formData.append(key, String(form.value[key])); // 确保所有值都转为字符串
} }
@ -746,7 +793,7 @@ const submitForm = async () => {
loadingIng.value = false; loadingIng.value = false;
await getList(); await getList();
} else { } else {
proxy?.$modal.msgWarning(res.msg) proxy?.$modal.msgWarning(res.msg);
loadingIng.value = false; loadingIng.value = false;
} }
} catch (err) { } catch (err) {
@ -787,73 +834,77 @@ const resetForm = () => {
}; };
// 设备类型 // 设备类型
const getDeviceType = () => { const getDeviceType = () => {
api.deviceTypeAll().then(res => { api
if (res.code == 200) { .deviceTypeAll()
deviceTypeOptions.value = res.data .then((res) => {
} if (res.code == 200) {
}).catch(err => { deviceTypeOptions.value = res.data;
}
}) })
.catch((err) => {});
}; };
// 客户下拉框 // 客户下拉框
const getAllCustomerAll = () => { const getAllCustomerAll = () => {
api.userAllCustomerAll().then(res => { api.userAllCustomerAll().then((res) => {
if (res.code == 200) { if (res.code == 200) {
customerList.value = res.data customerList.value = res.data;
} }
}) });
}; };
// 分配客户 // 分配客户
const assignRow = ref() const assignRow = ref();
const handleAssign = (row: any) => { const handleAssign = (row: any) => {
console.log(row, 'eeeeee'); console.log(row, 'eeeeee');
getAllCustomerAll() getAllCustomerAll();
assignDialogVisible.value = true assignDialogVisible.value = true;
assignRow.value = row assignRow.value = row;
assignCustomerId.value == !row.customerName ? row.customerId : '' assignCustomerId.value == !row.customerName ? row.customerId : '';
} };
const handleAssignConfirm = () => { const handleAssignConfirm = () => {
if (!assignCustomerId.value) { if (!assignCustomerId.value) {
return proxy?.$modal.msgError('请选择客户') return proxy?.$modal.msgError('请选择客户');
} }
loadingIng.value = true; loadingIng.value = true;
// 这里调用分配API // 这里调用分配API
let data = { let data = {
customerId: assignCustomerId.value, customerId: assignCustomerId.value,
deviceIds: [assignRow.value.id] deviceIds: [assignRow.value.id]
} };
api.deviceAssignCustomer(data).then((res) => { api
if (res.code == 200) { .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; 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 importUpload = ref();
const importResult = ref() const importResult = ref();
const handleBatchImport = () => { const handleBatchImport = () => {
importDialogVisible.value = true importDialogVisible.value = true;
importResult.value = { importResult.value = {
isShow: false, isShow: false,
total: 0, total: 0,
succeed: 0, succeed: 0,
errorSun: 0, errorSun: 0,
link: '' link: ''
} };
nextTick(() => { nextTick(() => {
if (importUpload.value) { if (importUpload.value) {
importUpload.value.clearFiles() importUpload.value.clearFiles();
} }
}) });
}; };
const downloadTemplate = () => { const downloadTemplate = () => {
// 这里可用 window.open 或 a 标签下载模板 // 这里可用 window.open 或 a 标签下载模板
@ -866,71 +917,74 @@ const downloadTemplate = () => {
document.body.removeChild(link); // 移除标签 document.body.removeChild(link); // 移除标签
}; };
const beforeImportUpload = (file: any) => { const beforeImportUpload = (file: any) => {
const isLt5M = file.size / 1024 / 1024 < 5 const isLt5M = file.size / 1024 / 1024 < 5;
if (!isLt5M) { if (!isLt5M) {
proxy?.$modal.msgError('上传文件大小不能超过 5MB!') proxy?.$modal.msgError('上传文件大小不能超过 5MB!');
} }
return isLt5M return isLt5M;
}; };
//添加tokenf方法head_upload 直接返回 getBearerToken() //添加tokenf方法head_upload 直接返回 getBearerToken()
const head_upload = () => getBearerToken(); const head_upload = () => getBearerToken();
const handleImportSuccess = (response: any) => { const handleImportSuccess = (response: any) => {
if (response.code == 200) { if (response.code == 200) {
importResult.value.isShow = true importResult.value.isShow = true;
if (response.data) { if (response.data) {
importResult.value.succeed = response.data.successCount || 0 importResult.value.succeed = response.data.successCount || 0;
importResult.value.errorSun = response.data.failureCount || 0 importResult.value.errorSun = response.data.failureCount || 0;
importResult.value.total = importResult.value.succeed + importResult.value.errorSun importResult.value.total = importResult.value.succeed + importResult.value.errorSun;
importResult.value.link = response.data.errorExcelUrl || '' importResult.value.link = response.data.errorExcelUrl || '';
} }
getList(); // 初始化列表数据 getList(); // 初始化列表数据
} else { } else {
proxy?.$modal.msgError(response.msg || '导入失败') proxy?.$modal.msgError(response.msg || '导入失败');
} }
}; };
const handleImportError = () => { const handleImportError = () => {
proxy?.$modal.msgError('导入失败') proxy?.$modal.msgError('导入失败');
}; };
// 批量分配客户 // 批量分配客户
const handleBatchAssign = () => { const handleBatchAssign = () => {
batchAssignDialogVisible.value = true batchAssignDialogVisible.value = true;
getAllCustomerAll() getAllCustomerAll();
}; };
// 批量分配客户确定 // 批量分配客户确定
const handleBatchAssignConfirm = () => { const handleBatchAssignConfirm = () => {
if (!batchAssignCustomerId.value) { if (!batchAssignCustomerId.value) {
return proxy?.$modal.msgError('请选择客户') return proxy?.$modal.msgError('请选择客户');
} }
// 提取选中设备的 ID 数组 // 提取选中设备的 ID 数组
const selectedIds = ids.value.map((item: any) => item.id) const selectedIds = ids.value.map((item: any) => item.id);
// 构造请求数据 // 构造请求数据
const data = { const data = {
customerId: batchAssignCustomerId.value, // 目标客户ID customerId: batchAssignCustomerId.value, // 目标客户ID
deviceIds: selectedIds // 选中的设备ID数组 deviceIds: selectedIds // 选中的设备ID数组
} };
api.deviceAssignCustomer(data).then((res) => { api
if (res.code == 200) { .deviceAssignCustomer(data)
batchAssignDialogVisible.value = false .then((res) => {
getList(); if (res.code == 200) {
return proxy?.$modal.msgSuccess(`分配成功`) batchAssignDialogVisible.value = false;
} getList();
}).catch(() => { return proxy?.$modal.msgSuccess(`分配成功`);
}
}) })
.catch(() => {});
}; };
watch(() => form.value.deviceType, (newVal) => { watch(
if (dialog.title === '新增设备') { // Only for add form () => form.value.deviceType,
handleDeviceTypeChange(newVal); (newVal) => {
if (dialog.title === '新增设备') {
// Only for add form
handleDeviceTypeChange(newVal);
}
} }
}); );
onMounted(() => { onMounted(() => {
getList(); // 初始化列表数据 getList(); // 初始化列表数据
getDeviceType() getDeviceType();
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep .el-upload--picture-card { :deep .el-upload--picture-card {
@ -955,7 +1009,6 @@ onMounted(() => {
object-fit: cover; object-fit: cover;
} }
.displayNone { .displayNone {
display: none !important; display: none !important;
} }
@ -975,14 +1028,12 @@ onMounted(() => {
width: 100%; width: 100%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
.detailMain .tabHeader { .detailMain .tabHeader {
width: 100%; width: 100%;
height: 36px; height: 36px;
background-color: #FFFFFF; background-color: #ffffff;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -991,7 +1042,6 @@ onMounted(() => {
align-items: flex-start; align-items: flex-start;
border-bottom: 1px solid rgba(235, 238, 248, 1); border-bottom: 1px solid rgba(235, 238, 248, 1);
box-sizing: border-box; box-sizing: border-box;
} }
.detailMain .tabHeader .indexContent { .detailMain .tabHeader .indexContent {
@ -1025,14 +1075,13 @@ onMounted(() => {
border-bottom: 2px solid rgba(2, 124, 251, 1); border-bottom: 2px solid rgba(2, 124, 251, 1);
} }
.detailMain .tabHeader .tabClose { .detailMain .tabHeader .tabClose {
width: 20px; width: 20px;
cursor: pointer; cursor: pointer;
} }
.detailMain .tabItem { .detailMain .tabItem {
height:calc(100% - 36px); height: calc(100% - 36px);
width: 100%; width: 100%;
} }

View File

@ -5,12 +5,16 @@
<el-button type="primary" @click="ShowEdit" <el-button type="primary" @click="ShowEdit"
><el-icon> <Plus /> </el-icon>添加分享</el-button ><el-icon> <Plus /> </el-icon>添加分享</el-button
> >
<el-button type="danger" @click="DelShare(null, true)" :disabled="selectRows.length===0">批量删除</el-button> <el-button type="danger" @click="DelShare(null, true)" :disabled="selectRows.length === 0">批量删除</el-button>
</div> </div>
<el-form :inline="true" :model="filter" class="demo-form-inline"> <el-form :inline="true" :model="filter" class="demo-form-inline">
<el-form-item label=""> <el-form-item label="">
<el-input v-model="filter.phonenumber" placeholder="查找分享用户" /> <el-input v-model="filter.phonenumber" placeholder="查找分享用户" @input="Search">
<template #append>
<el-button :icon="'Search'" />
</template>
</el-input>
</el-form-item> </el-form-item>
<el-form-item label="分享时间"> <el-form-item label="分享时间">
<el-date-picker <el-date-picker
@ -269,8 +273,8 @@ function getPower(item) {
//批量删除 //批量删除
var selectRows = computed(() => { var selectRows = computed(() => {
let arr = getSelectionRows(grid); let arr = getSelectionRows(grid);
return arr; return arr;
}); });
function DelShare(item, isBatch) { function DelShare(item, isBatch) {
@ -280,8 +284,8 @@ function DelShare(item, isBatch) {
} else { } else {
arr = [item]; arr = [item];
} }
if(arr.length===0){ if (arr.length === 0) {
alert("请选择需要删除的数据"); alert('请选择需要删除的数据');
return; return;
} }
debugger; debugger;
@ -378,6 +382,14 @@ var getSelectionRows = (gridInstance) => {
return []; return [];
}; };
let searchTime=null;
function Search(){
clearTimeout(searchTime);
searchTime=setTimeout(()=>{
getRecordList();
},500);
}
function getRecordList() { function getRecordList() {
Status.loading = true; Status.loading = true;
@ -547,4 +559,8 @@ watch(
:deep .el-overlay .el-input-group__append { :deep .el-overlay .el-input-group__append {
padding: 0px !important; padding: 0px !important;
} }
:deep .topFilter .el-input-group__append {
padding: 0px 10px !important;
}
</style> </style>