Merge branch 'liubiao-main'

This commit is contained in:
2025-09-09 17:04:10 +08:00
10 changed files with 2168 additions and 331 deletions

View File

@ -0,0 +1,86 @@
import request from '@/utils/request';
import { resolve } from 'path';
function DelShare(ids) {
return request({
url: '/api/equipment/share/' + ids,
method: 'delete'
});
}
//添加分享数据
function SaveShare(data,type){
let promise=null;
if(type=='add'){
promise=addShare(data);
}else{
promise=powerSet(data);
}
return promise;
}
//添加
function addShare(data) {
return request({
url: '/api/equipment/share/deviceShare',
method: 'post',
data: data
});
}
//修改
function powerSet(data) {
return request({
url: '/api/equipment/share/permission',
method: 'post',
data: data
});
}
//查询
function searchShare(params) {
return request({
url: '/api/equipment/share/deviceShareList',
method: 'get',
params: params
})
}
//发送验证码
function sendSms(phoneNumber) {
return request({
url: '/api/equipment/share/sms/code',
method: 'get',
params: {
phonenumber: phoneNumber
}
});
// return new Promise((resolve,reject)=>{
// resolve({
// code:200
// });
// });
}
function getUsrs(){
return request({
url: '/WebApp/user/list',
method: 'get',
params: {
pageNum:1,
pageSize:9999
}
});
}
export default {
powerSet: powerSet,
DelShare: DelShare,
SaveShare: SaveShare,
searchShare: searchShare,
sendSms:sendSms,
getUsrs:getUsrs
}

View File

@ -1,6 +1,4 @@
import { func } from 'vue-types';
import request from '@/utils/request'; import request from '@/utils/request';
import { AxiosPromise } from 'axios';
//左侧节点的数据源 //左侧节点的数据源
function getTreeData(para: any) { function getTreeData(para: any) {

View File

@ -1,6 +1,6 @@
function DateFormat(date, format) { function DateFormat(date, format) {
if (!date) { if (!date) {
date = new Date(); return '';
} }
if (!format) { if (!format) {
format = 'yyyy-MM-dd HH:mm:ss'; format = 'yyyy-MM-dd HH:mm:ss';
@ -40,7 +40,38 @@ function DateFormat(date, format) {
}); });
} }
function DateAdd(datePart, number, date) {
// 创建日期的副本,避免修改原日期对象
const newDate = new Date(date.getTime());
// 根据不同的时间单位添加相应的值
switch (datePart.toLowerCase()) {
case 'year':
newDate.setFullYear(newDate.getFullYear() + number);
break;
case 'month':
newDate.setMonth(newDate.getMonth() + number);
break;
case 'day':
newDate.setDate(newDate.getDate() + number);
break;
case 'hour':
newDate.setHours(newDate.getHours() + number);
break;
case 'minute':
newDate.setMinutes(newDate.getMinutes() + number);
break;
case 'second':
newDate.setSeconds(newDate.getSeconds() + number);
break;
default:
throw new Error('不支持的datePart参数。支持的参数: Year, Month, Day, Hour, Minute, Second');
}
return newDate;
}
export default{ export default{
DateFormat:DateFormat DateFormat:DateFormat,
DateAdd:DateAdd
} }

View File

@ -0,0 +1,160 @@
<template>
<div class="content">
<div class="topFilter">
<el-form :inline="true" :model="filter" class="demo-form-inline">
<el-form-item label="操作时间">
<el-date-picker
v-model="filter.Date"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
:size="'default'"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getRecordList">查询</el-button>
<el-button link type="primary" @click="filter.Date = []">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="grid" v-loading="Status.loading">
<el-table ref="grid" v-loading="Status.loading" border :data="List" height="calc(100vh - 320px)">
<el-table-column label="创建时间" align="center" prop="createTime" />
<el-table-column label="设备名称" align="center" prop="deviceName" />
<el-table-column label="数据来源" align="center" prop="dataSource" />
<el-table-column label="内容" align="center" prop="content" />
</el-table>
<pagination
v-show="pagin.total > 0"
v-model:page="pagin.pageIndex"
v-model:limit="pagin.pageSize"
:total="pagin.total"
@pagination="getRecordList"
/>
</div>
</div>
</template>
<script setup lang="ts">
import request from '@/utils/request';
const props = defineProps({
data: {
type: Object,
required: true
},
acIndex: {
type: Number,
required: true
}
});
var filter = ref({
Date: []
});
var Status = ref({
loading: false
});
var data = ref({});
var grid = ref(null);
var List = ref([]);
var pagin = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
function getRecordList() {
Status.value.loading = true;
setTimeout(() => {
initData(props.data,true);
}, 0);
}
var deviceid = null;
function initData(item,Refresh) {
if (deviceid == item.data.deviceId && !Refresh) {
Status.value.loading = false;
return;
}
List.value = [];
deviceid = item.data.deviceId;
let params = {
startTime: '',
endTime: '',
deviceId:deviceid,
pageNum:pagin.value.pageIndex,
pageSize:pagin.value.pageSize,
orderByColumn:"updatedAt",
isAsc:"descending"
};
if (filter.value.Date && filter.value.Date.length) {
params.startTime = filter.value.Date[0];
params.endTime = filter.value.Date.length > 1 ? filter.value.Date[1] : '';
}
request({
url: '/equipment/chargeDischarge/list' ,
method: 'get',
params: params
})
.then((res) => {
if (res.code == 200) {
if (res.rows) {
if (res.rows.length) {
List.value = res.rows;
}
}
pagin.value.total= res.total;
}
})
.finally(() => {
data.value = item.data;
Status.value.loading = false;
});
}
watch(
() => props.acIndex, // 监听的属性
(newVal) => {
if (newVal === 3) {
// 确保参数有效
debugger;
console.log('newVal=', newVal);
getRecordList(); // 调用回调
}
},
{ immediate: true } // 关键:组件初始化时立即执行一次
);
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 30px 12px 12px 12px;
}
.pickerContent {
box-sizing: border-box;
border: 1px solid rgba(189, 198, 215, 0.8);
border-radius: 2px;
}
.topFilter {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-end;
align-items: center;
}
:deep .pickerContent .el-date-editor {
border: none !important;
}
</style>

View File

@ -0,0 +1,161 @@
<template>
<div class="content">
<div class="topFilter">
<el-form :inline="true" :model="filter" class="demo-form-inline">
<el-form-item label="操作时间">
<el-date-picker
v-model="filter.Date"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
:size="'default'"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getRecordList">查询</el-button>
<el-button link type="primary" @click="filter.Date = []">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="grid" v-loading="Status.loading">
<el-table ref="grid" v-loading="Status.loading" border :data="List" height="calc(100vh - 320px)">
<el-table-column label="创建时间" align="center" prop="createTime" />
<el-table-column label="设备名称" align="center" prop="deviceName" />
<el-table-column label="数据来源" align="center" prop="dataSource" />
<el-table-column label="内容" align="center" prop="content" />
</el-table>
<pagination
v-show="pagin.total > 0"
v-model:page="pagin.pageIndex"
v-model:limit="pagin.pageSize"
:total="pagin.total"
@pagination="getRecordList"
/>
</div>
</div>
</template>
<script setup lang="ts">
import request from '@/utils/request';
const props = defineProps({
data: {
type: Object,
required: true
},
acIndex: {
type: Number,
required: true
}
});
var filter = ref({
Date: []
});
var Status = ref({
loading: false
});
var data = ref({});
var grid = ref(null);
var List = ref([]);
var pagin = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
function getRecordList() {
Status.value.loading = true;
setTimeout(() => {
initData(props.data,true);
}, 0);
}
var deviceid = null;
function initData(item,Refresh) {
if (deviceid == item.data.deviceId && !Refresh) {
Status.value.loading = false;
return;
}
List.value = [];
deviceid = item.data.deviceId;
let params = {
startTime: '',
endTime: '',
pageNum:pagin.value.pageIndex,
pageSize:pagin.value.pageSize,
orderByColumn:"updateTime",
isAsc:"descending"
};
if (filter.value.Date && filter.value.Date.length) {
params.startTime = filter.value.Date[0];
params.endTime = filter.value.Date.length > 1 ? filter.value.Date[1] : '';
}
request({
url: '/api/device/getOperationRecord/' + item.data.deviceId,
method: 'get',
params: params
})
.then((res) => {
if (res.code == 200) {
if (res.rows) {
if (res.rows.length) {
List.value = res.rows;
}
}
pagin.value.total= res.total;
}
})
.finally(() => {
data.value = item.data;
Status.value.loading = false;
});
}
watch(
() => props.acIndex, // 监听的属性
(newVal) => {
if (newVal === 3) {
// 确保参数有效
debugger;
console.log('newVal=', newVal);
getRecordList(); // 调用回调
}
},
{ immediate: true } // 关键:组件初始化时立即执行一次
);
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 30px 12px 12px 12px;
}
.pickerContent {
box-sizing: border-box;
border: 1px solid rgba(189, 198, 215, 0.8);
border-radius: 2px;
}
.topFilter {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-end;
align-items: center;
}
:deep .pickerContent .el-date-editor {
border: none !important;
}
</style>

View File

@ -0,0 +1,256 @@
<template>
<div class="content">
<div class="row">
<div class="item">
<div class="lable">姓名<span></span></div>
<div class="val">{{ lastData?.name }}</div>
</div>
<div class="item">
<div class="lable">单位名称<span></span></div>
<div class="val">{{ lastData?.position }}</div>
</div>
<div class="item">
<div class="lable">职务<span></span></div>
<div class="val">{{ lastData?.unitName }}</div>
</div>
<div class="item">
<div class="lable">ID号<span></span></div>
<div class="val">{{ lastData?.code }}</div>
</div>
<div class="clear"></div>
</div>
<div class="clear divider"></div>
<div class="listTitle">信息登记记录</div>
<div class="list">
<div class="item" v-for="(item, index) in detailData">
<div class="time">
<el-icon><Timer /></el-icon>{{ item.item }}
</div>
<div class="childContent">
<div class="itemChild" :class="i === item.child.length - 1 ? '' : 'marginBottom'" v-for="(c, i) in item.child">
<div class="itemRow">登记时间{{ c.createTime }}</div>
<div class="itemRow">&nbsp;&nbsp;&nbsp;&nbsp;{{ c.name }}</div>
<div class="itemRow">单位名称{{ c.position }}</div>
<div class="itemRow">&nbsp;&nbsp;&nbsp;&nbsp;{{ c.unitName }}</div>
<div class="itemRow">ID&nbsp;&nbsp;&nbsp;&nbsp;{{ c.code }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import request from '@/utils/request';
const props = defineProps({
data: {
type: Object,
required: true
},
acIndex: {
type: Number,
required: true
}
});
var detailData = ref([]);
var data = ref({});
var deviceid = null;
var lastData = ref({ name: '', position: '', unitName: '', code: '' });
function processDataByDateGroup(originalData) {
// 1. 深拷贝原始数据(避免修改原数据,保护源数据完整性)
const data = JSON.parse(JSON.stringify(originalData));
// 边界处理若data不存在或非数组返回原结构+空sipledate
if (!data?.data || !Array.isArray(data.data)) {
return {
code: data?.code ?? 400, // 若原code不存在默认400请求错误
msg: data?.msg ?? '数据格式错误',
sipledate: []
};
}
// 2. 先按createTime逆序排序子数据内部也保持“新->旧”顺序)
const sortedData = data.data.sort((a, b) => {
const timeA = new Date(a.createTime);
const timeB = new Date(b.createTime);
return timeB - timeA; // 逆序:后创建的排在前面
});
// 3. 按日期分组keyyyyy-MM-ddvalue该日期下的所有子数据
const dateGroupMap = sortedData.reduce((map, item) => {
// 提取当前数据的“yyyy-MM-dd”格式日期
const dateKey = item.createTime.slice(0, 10);
// 若当前日期未在map中初始化空数组若已存在直接push子数据
if (!map.has(dateKey)) {
map.set(dateKey, []);
}
map.get(dateKey).push(item);
return map;
}, new Map()); // 使用Map而非Object确保日期顺序与排序后一致
// 4. 转换为需求格式的sipledate数组每个元素含item和child
const sipledate = Array.from(dateGroupMap.entries()).map(([date, childData]) => ({
item: date, // 日期标识yyyy-MM-dd原需求“item1/item2”统一为“item”更语义化
child: childData // 该日期下的所有子数据(已按时间逆序)
}));
// 5. 返回最终格式结果
return {
code: data.code,
msg: data.msg,
sipledate: sipledate
};
}
function initData(item) {
if (deviceid == item.data.deviceId) {
return;
}
deviceid = item.data.deviceId;
request({
url: '/api/device/getDeviceUser/' + item.data.deviceId,
method: 'get'
})
.then((res) => {
if (res.code == 200) {
if (res.data) {
if (res.data.length) {
lastData.value = res.data[0];
let data = processDataByDateGroup(res);
detailData.value = data.sipledate;
}
}
}
})
.finally(() => {
data.value = item.data;
});
}
watch(
() => props.acIndex, // 监听的属性
(newVal) => {
if (newVal === 2 && props.data) {
// 确保参数有效
initData(props.data); // 调用回调
}
},
{ immediate: true } // 关键:组件初始化时立即执行一次
);
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 30px 12px 12px 12px;
}
.row {
width: 50%;
}
.row .item {
width: 50%;
float: left;
height: 36px;
line-height: 36px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-start;
align-items: center;
color: rgba(56, 64, 79, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
}
.row .item .lable {
width: 100px;
text-align: right;
}
.divider {
width: 100%;
height: 0px;
border-bottom: 1px solid rgba(235, 238, 248, 1);
}
.listTitle {
color: rgba(56, 64, 79, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 700;
height: 56px;
line-height: 56px;
letter-spacing: 0px;
text-align: left;
}
.list {
width: 100%;
box-sizing: border-box;
height: calc(100% - 130px);
padding: 15px 12px;
overflow-y: scroll;
}
.list .time {
color: #027cfb;
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 21px;
height: 21px;
letter-spacing: 0px;
text-align: left;
}
.list .itemRow{
color: rgba(56, 64, 79, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
margin-bottom: 13px;
}
.itemChild.marginBottom {
margin-bottom: 12px;
}
.list .childContent {
width: 100%;
height: auto;
border-left: 1px solid rgba(0, 198, 250, 0.2);
box-sizing: border-box;
padding: 6px 20px;
}
.list .itemChild {
border-radius: 4px;
background: rgba(247, 248, 252, 1);
width: 100%;
height: auto;
}
.fleft {
float: left;
}
.fright {
float: right;
}
.clear {
clear: both;
}
</style>

View File

@ -0,0 +1,181 @@
<template>
<div class="content">
<div class="topFilter">
<el-form :inline="true" :model="filter" class="demo-form-inline">
<el-form-item label="操作时间">
<el-date-picker
v-model="filter.Date"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
:size="'default'"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getRecordList">查询</el-button>
<el-button link type="primary" @click="filter.Date = []">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="grid" v-loading="Status.loading">
<el-table ref="grid" v-loading="Status.loading" border :data="List" height="calc(100vh - 320px)">
<el-table-column prop="deviceAction" label="报警事项" align="center">
<template #default="scope">
<div>{{ dic.warType[scope.row.deviceAction] }}</div>
</template>
</el-table-column>
<el-table-column label="报警开始时间" align="center" prop="startTime" />
<el-table-column label="报警结束时间" align="center" prop="finishTime" />
<el-table-column label="报警持续时间" align="center" prop="durationTime" />
<el-table-column label="处理状态" align="center" prop="treatmentState">
<template #default="scope">
<div>{{ dic.treamt[scope.row.deviceAction] ? dic.treamt[scope.row.deviceAction] :'未处理' }}</div>
</template>
</el-table-column>
</el-table>
<pagination
v-show="pagin.total > 0"
v-model:page="pagin.pageIndex"
v-model:limit="pagin.pageSize"
:total="pagin.total"
@pagination="getRecordList"
/>
</div>
</div>
</template>
<script setup lang="ts">
import request from '@/utils/request';
const props = defineProps({
data: {
type: Object,
required: true
},
acIndex: {
type: Number,
required: true
}
});
var dic = {
warType: {
0: '强制报警',
1: '撞击闯入',
2: '手动报警',
3: '电子围栏告警',
4: '强制告警'
},
treamt:{
0:"已处理",
1:"未处理"
}
};
var filter = ref({
Date: []
});
var Status = ref({
loading: false
});
var data = ref({});
var grid = ref(null);
var List = ref([]);
var pagin = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
function getRecordList() {
Status.value.loading = true;
setTimeout(() => {
initData(props.data, true);
}, 0);
}
var deviceid = null;
function initData(item, Refresh) {
if (deviceid == item.data.deviceId && !Refresh) {
Status.value.loading = false;
return;
}
List.value = [];
deviceid = item.data.deviceId;
let params = {
startTime: '',
endTime: '',
pageNum:pagin.value.pageIndex,
pageSize:pagin.value.pageSize,
orderByColumn:"updateTime",
isAsc:"descending"
};
if (filter.value.Date && filter.value.Date.length) {
params.startTime = filter.value.Date[0];
params.endTime = filter.value.Date.length > 1 ? filter.value.Date[1] : '';
}
request({
url: '/api/device/getAlarmRecord/' + item.data.deviceId,
method: 'get',
params: params
})
.then((res) => {
debugger;
if (res.code == 200) {
if (res.rows) {
if (res.rows.length) {
List.value = res.rows;
}
}
pagin.value.total= res.total;
}
})
.finally(() => {
data.value = item.data;
Status.value.loading = false;
});
}
watch(
() => props.acIndex, // 监听的属性
(newVal) => {
if (newVal === 4) {
// 确保参数有效
console.log('newVal=', newVal);
getRecordList(); // 调用回调
}
},
{ immediate: true } // 关键:组件初始化时立即执行一次
);
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 30px 12px 12px 12px;
}
.pickerContent {
box-sizing: border-box;
border: 1px solid rgba(189, 198, 215, 0.8);
border-radius: 2px;
}
.topFilter {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-end;
align-items: center;
}
:deep .pickerContent .el-date-editor {
border: none !important;
}
</style>

View File

@ -0,0 +1,212 @@
<template>
<div class="content">
<div class="leftImg fleft">
<img class="img" :src="detailData?.devicePic" />
</div>
<div class="detail fleft">
<div class="row">
<div class="item">
<div class="lable">设备名称<span></span></div>
<div class="val">{{ detailData?.deviceName }}</div>
</div>
<div class="item">
<div class="lable">设备IMEI<span></span></div>
<div class="val">{{ detailData?.deviceImei }}</div>
</div>
<div class="item">
<div class="lable">设备MAC<span></span></div>
<div class="val">{{ detailData?.deviceMac }}</div>
</div>
<div class="item">
<div class="lable">通讯方式<span></span></div>
<div class="val">{{ detailData?.communicationMode===1 ?'蓝牙':'4G' }}</div>
</div>
<div class="item">
<div class="lable">蓝牙名称<span></span></div>
<div class="val">{{ detailData?.bluetoothName }}</div>
</div>
<div class="item">
<div class="lable">设备类型<span></span></div>
<div class="val">{{ detailData?.typeName }}</div>
</div>
<div class="item">
<div class="lable">使用人员<span></span></div>
<div class="val">{{ detailData?.personnelBy }}</div>
</div>
<div class="item">
<div class="lable">设备状态<span></span></div>
<div class="val">{{ detailData?.deviceStatus===1 ?'正常':'失效' }}</div>
</div>
<div class="item">
<div class="lable">绑定时间<span></span></div>
<div class="val">{{ detailData?.bindingTime }}</div>
</div>
<div class="item">
<div class="lable">在线状态<span></span></div>
<div class="val">{{ detailData?.onlineStatus===1?'在线':'离线' }}</div>
</div>
<div class="item">
<div class="lable">电量<span></span></div>
<div class="val">{{ detailData?.battery }}%</div>
</div>
<div class="item">
<div class="lable">告警状态<span></span></div>
<div class="val">{{ detailData?.alarmStatus=='1'?'告警':'未告警' }}</div>
</div>
<div class="item">
<div class="lable">经度<span></span></div>
<div class="val">{{ detailData?.latitude }}</div>
</div>
<div class="item">
<div class="lable">纬度<span></span></div>
<div class="val">{{ detailData?.longitude }}</div>
</div>
<div class="item">
<div class="lable">分享用户数量<span></span></div>
<div class="val">{{ detailData?.shareUsersNumber }}</div>
</div>
</div>
</div>
<div class="clear"></div>
</div>
</template>
<script setup lang="ts">
import request from "@/utils/request";
import { number } from "vue-types";
const props = defineProps({
data: {
type: Object,
required: true
},
acIndex:{
type:Number,
required: true
}
})
var data=ref({});
var detailData = ref({});
var deviceid=null;
function initData(item) {
if(deviceid==item.data.deviceId){
return;
}
deviceid=item.data.deviceId
detailData.value={};
request({
url: "/api/device/pc/detail/" + item.data.deviceId,
method: 'get'
}).then(res => {
if (res.code == 200) {
if (res.data) {
detailData.value = res.data;
}
}
}).finally(() => {
data.value=item.data;
});
}
watch(
() => props.acIndex, // 监听的属性
(newVal) => {
if (newVal===1 && props.data) { // 确保参数有效
initData(props.data) // 调用回调
}
},
{ immediate: true } // 关键:组件初始化时立即执行一次
)
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 30px 12px 12px 12px;
}
.leftImg {
width: 18%;
text-align: center;
}
.leftImg .img {
width: 200px;
height: 200px;
object-fit: scale-down;
border-radius: 4px;
box-shadow: 0px 0px 4px 0px rgba(0, 27, 74, 0.15);
background: rgba(247, 248, 252, 1);
}
.detail {
width: 82%;
}
.detail .row {
width: 100%;
height: 100%;
}
.detail .row .item {
width: calc(100% / 3);
margin-bottom: 20px;
height: 20px;
line-height: 20px;
color: rgba(56, 64, 79, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
letter-spacing: 0px;
text-align: left;
float: left;
}
.detail .row .lable {
width: 100px;
text-align: right;
float: left;
}
.detail .row .val {
float: left;
}
.fleft {
float: left;
}
.fright {
float: right;
}
.clear {
clear: both;
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="p-2"> <div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" <div :class="Status.Mode == PageMode.device ? '' : 'displayNone'">
: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">
@ -16,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>
@ -44,34 +49,29 @@
<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" <el-button v-hasPermi="['equipment:devices:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
@click="handleUpdate()">
修改 修改
</el-button> </el-button>
</el-col> </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>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['equipment:devices:remove']" type="danger" plain :disabled="multiple" <el-button v-hasPermi="['equipment:devices:remove']" type="danger" plain :disabled="multiple" @click="handleDelete()">
@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-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button v-hasPermi="['equipment:devices:allocate']" type="warning" plain :disabled="multiple" <el-button v-hasPermi="['equipment:devices:allocate']" type="warning" plain :disabled="multiple" @click="handleBatchAssign">
@click="handleBatchAssign">
批量分配客户 批量分配客户
</el-button> </el-button>
</el-col> </el-col>
@ -87,8 +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" style="width: 40px; height: 40px; cursor: pointer; object-fit: contain" <img
class="hover:opacity-80 transition-opacity" /> :src="scope.row.devicePic"
style="width: 40px; height: 40px; cursor: pointer; object-fit: contain"
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>
@ -119,40 +122,78 @@
<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" <el-button v-hasPermi="['equipment:devices:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
@click="handleDelete(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip v-if="scope.row.deviceStatus == 1 && !scope.row.customerName" content="分配" placement="top"> <el-tooltip v-if="scope.row.deviceStatus == 1 && !scope.row.customerName" content="分配" placement="top">
<el-button v-hasPermi="['equipment:devices:allocate']" link type="primary" icon="User" <el-button v-hasPermi="['equipment:devices:allocate']" link type="primary" icon="User" @click="handleAssign(scope.row)"></el-button>
@click="handleAssign(scope.row)"></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip v-if="scope.row.customerName && scope.row.deviceStatus == 1" content="撤回" placement="top"> <el-tooltip v-if="scope.row.customerName && scope.row.deviceStatus == 1" content="撤回" placement="top">
<el-button v-hasPermi="['equipment:devices:revoke']" link type="primary" icon="UploadFilled" <el-button
@click="handleWithdraw(scope.row)"></el-button> v-hasPermi="['equipment:devices:revoke']"
link
type="primary"
icon="UploadFilled"
@click="handleWithdraw(scope.row)"
></el-button>
</el-tooltip> </el-tooltip>
<el-tooltip v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0" content="解绑" <el-tooltip v-if="scope.row.bindingStatus == 1" :disabled="scope.row.deviceStatus === 0" content="解绑" placement="top">
placement="top"> <el-button v-hasPermi="['equipment:devices:unbind']" link type="primary" icon="Refresh" @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-button link type="primary" icon="More" @click="handleDetail(scope.row)"></el-button>
</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">
@ -164,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>
@ -196,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>
@ -227,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>
@ -241,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>
@ -272,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>
@ -286,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">
@ -307,8 +361,16 @@ 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 Usr from './Usr.vue';
import OpraRecored from './OpraRecored.vue';
import WarnRecord from './WarnRecord.vue';
import shareManage from './shareManage.vue';
import Charge from './Charge.vue';
import router from '@/router'; import router from '@/router';
const loading = ref(true); const loading = ref(true);
const showSearch = ref(true); const showSearch = ref(true);
@ -322,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>({
@ -340,13 +402,47 @@ const dialog = reactive<DialogOption>({
title: '' title: ''
}); });
//页面类型
enum PageMode {
device = 'device', //设备
detail = 'detail' //详情
}
//页面状态控制
var Status = reactive({
Mode: PageMode.device,
tabActive: 0
});
//传给详情的数据
var detailData = ref(null);
//加载详情
function handleDetail(item) {
Status.tabActive = 1;
detailData.value = { data: item };
Status.Mode = PageMode.detail;
}
//关闭详情
function closeDetail() {
Status.Mode = PageMode.device;
Status.tabActive = -1;
}
function tabIndexChange(index) {
if (Status.tabActive == index) {
return;
}
Status.tabActive = index;
}
//
const initFormData: deviceForm = { const initFormData: deviceForm = {
deviceName: '', deviceName: '',
deviceMac: '', deviceMac: '',
deviceImei: '', deviceImei: '',
remark: '', remark: '',
id: '', id: '',
deviceType: "", deviceType: '',
image: '', image: '',
bluetoothName: '' // 蓝牙名称字段 bluetoothName: '' // 蓝牙名称字段
}; };
@ -360,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);
@ -393,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;
@ -403,7 +486,7 @@ const handleQuery = () => {
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value?.resetFields(); queryFormRef.value?.resetFields();
dateRange.value = ['', '']; dateRange.value = ['', ''];
handleQuery() handleQuery();
}; };
/** 删除按钮操作 */ /** 删除按钮操作 */
@ -411,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();
@ -420,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();
@ -440,46 +535,49 @@ const handleExport = () => {
}; };
// 解绑 // 解绑
const handleUnbind = (row) => { const handleUnbind = (row) => {
proxy?.$modal.confirm(`确定要解绑设备 ${row.deviceName} 吗?`, '提示', { proxy?.$modal
.confirm(`确定要解绑设备 ${row.deviceName} 吗?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { })
.then(() => {
let data = { let data = {
id: row.id id: row.id
} };
api.deviceUnbind(data).then(res => { api.deviceUnbind(data).then((res) => {
if (res.code == 200) { if (res.code == 200) {
proxy?.$modal.msgSuccess(res.msg) proxy?.$modal.msgSuccess(res.msg);
getList(); // 初始化列表数据 getList(); // 初始化列表数据
} else { } else {
proxy?.$modal.msgError(res.msg) proxy?.$modal.msgError(res.msg);
} }
});
}) })
}).catch(() => { .catch(() => {});
})
}; };
// 撤回 // 撤回
const handleWithdraw = (row: any) => { const handleWithdraw = (row: any) => {
proxy?.$modal.confirm(`确定要从客户 ${row.customerName} 撤回设备 ${row.deviceName} 吗?`, '提示', { proxy?.$modal
.confirm(`确定要从客户 ${row.customerName} 撤回设备 ${row.deviceName} 吗?`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { })
api.withdrawDevice([row.id]).then(res => { .then(() => {
api.withdrawDevice([row.id]).then((res) => {
if (res.code === 200) { if (res.code === 200) {
proxy?.$modal.msgSuccess('撤回成功') proxy?.$modal.msgSuccess('撤回成功');
getList(); // 初始化列表数据 getList(); // 初始化列表数据
} else { } else {
proxy?.$modal.msgError(res.msg || '撤回失败') proxy?.$modal.msgError(res.msg || '撤回失败');
} }
});
}) })
}).catch(() => { .catch(() => {
proxy?.$modal.msgError('已取消撤回') proxy?.$modal.msgError('已取消撤回');
}) });
} };
/** 选择条数 */ /** 选择条数 */
const handleSelectionChange = (selection: deviceVO[]) => { const handleSelectionChange = (selection: deviceVO[]) => {
@ -488,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 = () => {
@ -525,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;
@ -566,14 +663,12 @@ const handleDeviceTypeChange = async (deviceTypeId: string | number) => {
showMacField.value = true; showMacField.value = true;
showImeiField.value = true; showImeiField.value = true;
console.log('两个字段都有值'); console.log('两个字段都有值');
} } else if (hasMac) {
else if (hasMac) {
showMacField.value = true; showMacField.value = true;
showImeiField.value = false; showImeiField.value = false;
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.deviceMac = []; rules.value.deviceMac = [];
@ -593,16 +688,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;
} }
@ -619,13 +717,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;
@ -659,7 +757,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])); // 确保所有值都转为字符串
} }
@ -691,7 +789,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) {
@ -732,73 +830,77 @@ const resetForm = () => {
}; };
// 设备类型 // 设备类型
const getDeviceType = () => { const getDeviceType = () => {
api.deviceTypeAll().then(res => { api
.deviceTypeAll()
.then((res) => {
if (res.code == 200) { if (res.code == 200) {
deviceTypeOptions.value = res.data deviceTypeOptions.value = res.data;
} }
}).catch(err => {
}) })
.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
.deviceAssignCustomer(data)
.then((res) => {
if (res.code == 200) { if (res.code == 200) {
loadingIng.value = false; loadingIng.value = false;
const customer = customerList.value.find(c => c.id === assignCustomerId.value) const customer = customerList.value.find((c) => c.id === assignCustomerId.value);
const customerName = customer ? customer.nickName : `ID: ${assignCustomerId.value}` const customerName = customer ? customer.nickName : `ID: ${assignCustomerId.value}`;
getList(); getList();
assignDialogVisible.value = false assignDialogVisible.value = false;
return proxy?.$modal.msgSuccess(`设备已分配给客户: ${customerName}`) return proxy?.$modal.msgSuccess(`设备已分配给客户: ${customerName}`);
} else { } else {
loadingIng.value = false; loadingIng.value = false;
} }
}).catch(() => {
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 标签下载模板
@ -811,71 +913,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
.deviceAssignCustomer(data)
.then((res) => {
if (res.code == 200) { if (res.code == 200) {
batchAssignDialogVisible.value = false batchAssignDialogVisible.value = false;
getList(); getList();
return proxy?.$modal.msgSuccess(`分配成功`) return proxy?.$modal.msgSuccess(`分配成功`);
} }
}).catch(() => {
}) })
.catch(() => {});
}; };
watch(() => form.value.deviceType, (newVal) => { watch(
if (dialog.title === '新增设备') { // Only for add form () => form.value.deviceType,
(newVal) => {
if (dialog.title === '新增设备') {
// Only for add form
handleDeviceTypeChange(newVal); 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 {
@ -899,4 +1004,85 @@ onMounted(() => {
height: 100px !important; height: 100px !important;
object-fit: cover; object-fit: cover;
} }
.displayNone {
display: none !important;
}
.detailMain {
width: 100%;
height: calc(100vh - 115px);
border-radius: 4px;
box-shadow: 0px 0px 6px 0px rgba(0, 34, 96, 0.1);
background: rgba(255, 255, 255, 1);
overflow: hidden;
box-sizing: border-box;
padding: 13px;
}
.detailMain .tabContent {
width: 100%;
height: 100%;
box-sizing: border-box;
}
.detailMain .tabHeader {
width: 100%;
height: 36px;
background-color: #ffffff;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
align-items: flex-start;
border-bottom: 1px solid rgba(235, 238, 248, 1);
box-sizing: border-box;
}
.detailMain .tabHeader .indexContent {
height: 100%;
width: calc(100% - 20px);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: space-between;
align-items: flex-start;
}
.detailMain .tabHeader .tabIndex {
color: rgba(56, 64, 79, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
letter-spacing: 0px;
text-align: left;
padding: 0px 30px;
position: relative;
height: 36px;
line-height: 36px;
cursor: pointer;
}
.detailMain .tabHeader .tabIndex.active {
color: rgba(2, 124, 251, 1);
font-weight: 700;
border-bottom: 2px solid rgba(2, 124, 251, 1);
}
.detailMain .tabHeader .tabClose {
width: 20px;
cursor: pointer;
}
.detailMain .tabItem {
height: calc(100% - 36px);
width: 100%;
}
.p-2 {
background: rgba(247, 248, 252, 1);
min-height: calc(100vh - 85px) !important;
}
</style> </style>

View File

@ -0,0 +1,566 @@
<template>
<div class="content" v-loading="Status.fullLoading">
<div class="topFilter">
<div>
<el-button type="primary" @click="ShowEdit"
><el-icon> <Plus /> </el-icon>添加分享</el-button
>
<el-button type="danger" @click="DelShare(null, true)" :disabled="selectRows.length === 0">批量删除</el-button>
</div>
<el-form :inline="true" :model="filter" class="demo-form-inline">
<el-form-item label="">
<el-input v-model="filter.phonenumber" placeholder="查找分享用户" @input="Search">
<template #append>
<el-button :icon="'Search'" />
</template>
</el-input>
</el-form-item>
<el-form-item label="分享时间">
<el-date-picker
v-model="filter.Date"
type="datetimerange"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD HH:mm:ss"
date-format="YYYY/MM/DD ddd"
time-format="A hh:mm:ss"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getRecordList">查询</el-button>
<el-button link type="primary" @click="filter.Date = []">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="grid" v-loading="Status.loading">
<el-table ref="grid" v-loading="Status.loading" border :data="List" height="calc(100vh - 320px)" @selection-change="RowSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="分享用户" align="center" prop="phonenumber" />
<el-table-column label="分享权限" align="center" prop="permission">
<template #default="scope">
<div>{{ getPower(scope.row) }}</div>
</template>
</el-table-column>
<el-table-column label="分享时间" align="center" prop="createTime" />
<el-table-column label="操作" align="center" fixed="right" width="280" class-name="small-padding fixed-width opt">
<template #default="scope">
<div class="center">
<el-text class="mx-1 marginRight10" type="primary" @click.stop="powerSet(scope.row)">权限管理</el-text>
<el-text class="mx-1" type="danger" @click.stop="DelShare(scope.row, false)">移除</el-text>
</div>
</template>
</el-table-column>
</el-table>
<pagination
v-show="pagin.total > 0"
v-model:page="pagin.pageIndex"
v-model:limit="pagin.pageSize"
:total="pagin.total"
@pagination="getRecordList"
/>
</div>
<!-- 修改权限弹窗 -->
<el-dialog v-model="Status.ShowPowerSet" :title="'权限管理'" width="800" :draggable="true">
<div class="form">
<el-form :model="cEdit" ref="ruleFormRef" style="max-width: 750px">
<el-form-item label="分享权限" label-position="right">
<el-checkbox-group v-model="cEdit.permission">
<el-checkbox :label="item.label" v-for="item in power" :value="item.value" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="验证码" label-position="right">
<el-input v-model="cEdit.smsCode" placeholder="验证码">
<template #append
><div class="btnSendSms" @click.stop="sendSms">{{ time > 0 ? time + '秒后重发' : '发送验证码' }}</div></template
>
</el-input>
</el-form-item>
</el-form>
</div>
<div class="center" style="margin-top: 10px">
<el-button type="primary" @click="SaveFormData('update')"> 确定 </el-button>
<el-button @click="CloseEdit"> 取消 </el-button>
</div>
</el-dialog>
<!-- 编辑框 -->
<el-dialog v-model="Status.ShowEditPop" :data-val="Status.ShowEditPop" :title="'添加分享'" width="800" :draggable="true">
<div class="form">
<el-form :model="cEdit" ref="ruleFormRef" style="max-width: 750px" :label-width="'75px'">
<el-form-item label="分享用户" label-position="right">
<el-select v-model="cEdit.phonenumber" filterable placeholder="输入以搜索">
<el-option v-for="item in Usrs" :key="item.phonenumber" :label="item.userName" :value="item.phonenumber" />
</el-select>
</el-form-item>
<el-form-item label="分享权限" label-position="right">
<el-checkbox-group v-model="cEdit.permission">
<el-checkbox :label="item.label" v-for="item in power" :value="item.value" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="验证码" label-position="right">
<el-input v-model="cEdit.smsCode" placeholder="验证码">
<template #append
><div class="btnSendSms" @click.stop="sendSms">{{ time > 0 ? time + '秒后重发' : '发送验证码' }}</div></template
>
</el-input>
</el-form-item>
<el-form-item label="备注" label-position="right">
<el-input v-model="cEdit.remark" placeholder="请输入备注" type="textarea" show-word-limit :rows="5" maxlength="50" />
</el-form-item>
</el-form>
</div>
<div class="center" style="margin-top: 10px">
<el-button type="primary" @click="SaveFormData('add')"> 确定 </el-button>
<el-button @click="CloseEdit()"> 取消 </el-button>
</div>
</el-dialog>
<!-- 提示框 -->
<el-dialog :width="300" :draggable="true" v-model="Status.confirm.Visible" :title="Status.confirm.title" width="500" center>
<span>
{{ Status.confirm.text }}
</span>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="Status.confirm.OkCallback"> 确定 </el-button>
<el-button v-show="Status.confirm.showCancel" @click="Status.confirm.cancelCallback">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import request from '@/utils/request';
import common from '@/utils/common';
import api from '@/api/equipmentManagement/device/shareManage';
const props = defineProps({
data: {
type: Object,
required: true
},
acIndex: {
type: Number,
required: true
}
});
var filter = ref({
Date: [],
phonenumber: ''
});
var Status = reactive({
loading: false,
fullLoading: false,
confirm: {
//弹出框的配置
Visible: false,
title: '',
text: '',
cancelCallback: null,
OkCallback: null,
showCancel: true
},
ShowEditPop: false, //是否显示编辑弹窗
ShowPowerSet: false //是否显示权限管理
});
var deviceid = null;
var data = ref({});
var grid = ref(null);
//主数据
var List = ref([]);
//所有用户
var Usrs = ref([]);
var pagin = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
//当前正在编辑的数据
var cEdit = reactive({
phonenumber: '',
permission: [],
remark: '',
smsCode: ''
});
//权限字典
var dic = reactive({
'1': '灯光模式',
'2': '激光模式',
'3': '开机画面',
'4': '人员信息登记',
'5': '发送信息',
'6': '产品信息'
});
var power = computed(() => {
let arr = [];
let keys = Object.keys(dic);
keys.forEach((key) => {
arr.push({ label: dic[key], value: key });
});
return arr;
});
//打开编辑
function ShowEdit() {
Status.ShowEditPop = true;
getUsrs();
}
//关闭编辑
function CloseEdit() {
Status.ShowEditPop = false;
Status.ShowPowerSet = false;
}
//添加分享
//保存分享数据
function SaveFormData(type) {
let data = {
'deviceId': deviceid,
'phonenumber': cEdit.phonenumber,
'permission': cEdit.permission.join(','),
'shareUser': '',
'remark': cEdit.remark,
'smsCode': cEdit.smsCode
};
Status.fullLoading = true;
api
.SaveShare(data, type)
.then((res) => {
if (res.code == 200) {
getRecordList();
CloseEdit();
}
alert(res.msg);
})
.catch((ex) => {
console.log('出现异常', ex);
})
.finally(() => {
Status.fullLoading = false;
cEdit.phonenumber = '';
cEdit.permission = [];
cEdit.remark = '';
cEdit.smsCode = '';
});
}
function getPower(item) {
let str = [];
if (item && item.permission) {
let arr = item.permission.split(',');
arr.forEach((k) => {
str.push(dic[k]);
});
}
return str.join(',');
}
//批量删除
var selectRows = computed(() => {
let arr = getSelectionRows(grid);
return arr;
});
function DelShare(item, isBatch) {
let arr = [];
if (isBatch) {
arr = getSelectionRows(grid);
} else {
arr = [item];
}
if (arr.length === 0) {
alert('请选择需要删除的数据');
return;
}
debugger;
let OkDel = () => {
hideConfirm();
Status.fullLoading = true;
setTimeout(() => {
let ids = arr
.map((v) => {
return v.id;
})
.join(',');
api
.DelShare(ids)
.then((res) => {
if (res.code == 200) {
getRecordList();
}
hideConfirm();
alert(res.msg);
})
.catch((ex) => {
console.log('ex=', ex);
})
.finally(() => {
Status.fullLoading = false;
});
}, 0);
};
confirm('您确认删除选择的' + arr.length + '条数据吗?', OkDel, hideConfirm, '提示');
}
let timeOut = null;
let time = ref(0);
let timeIntval = null;
function sendSms() {
if (time.value > 0) {
return;
}
if (timeIntval) {
return;
}
clearTimeout(timeOut);
timeOut = setTimeout(() => {
api
.sendSms(cEdit.phonenumber)
.then((res) => {
if (res.code == 200) {
console.log('res=', res);
time.value = 60;
timeIntval = setInterval(() => {
time.value = time.value - 1;
if (time.value == 0) {
clearInterval(timeIntval);
timeIntval = null;
}
}, 1000);
}
})
.catch((ex) => {
console.log('ex=', ex);
})
.finally(() => {});
}, 500);
}
//权限设置
function powerSet(item) {
debugger;
Status.ShowPowerSet = true;
cEdit.permission = item.permission.split(',');
cEdit.phonenumber = item.phonenumber;
cEdit.remark = item.remark;
cEdit.smsCode = '123456';
}
function getUsrs() {
if (Usrs.value && Usrs.value.length > 0) {
return;
}
api.getUsrs().then((res) => {
if (res.code == 200) {
Usrs.value = res.rows;
}
});
}
function RowSelectionChange(row) {}
var getSelectionRows = (gridInstance) => {
if (gridInstance.value) {
// 检查ref是否已正确引用组件实例
var selectedRows = gridInstance.value.getSelectionRows(); // 获取选中行数据数组
return selectedRows;
}
return [];
};
let searchTime=null;
function Search(){
clearTimeout(searchTime);
searchTime=setTimeout(()=>{
getRecordList();
},500);
}
function getRecordList() {
Status.loading = true;
setTimeout(() => {
initData(props.data, true);
}, 0);
}
function initData(item, Refresh) {
if (deviceid == item.data.deviceId && !Refresh) {
Status.loading = false;
return;
}
debugger;
List.value = [];
deviceid = item.data.deviceId;
let params = {
deviceId: item.data.deviceId,
shareStartTime: '',
shareEndTime: '',
phonenumber: filter.value.phonenumber,
pageSize: pagin.value.pageSize,
pageNum: pagin.value.pageIndex,
orderByColumn: 'createTime',
isAsc: 'descending'
};
if (filter.value.Date && filter.value.Date.length) {
params.shareStartTime = common.DateFormat(filter.value.Date[0], null);
params.shareEndTime = common.DateFormat(filter.value.Date.length > 1 ? filter.value.Date[1] : '', null);
}
api
.searchShare(params)
.then((res) => {
if (res.code == 200) {
if (res.rows) {
if (res.rows.length) {
List.value = res.rows;
}
}
pagin.value.total = res.total;
}
})
.finally(() => {
data.value = item.data;
Status.loading = false;
});
}
window.confirm = function (text, OK, cancel, title) {
let Cfg = {
Visible: true,
title: title ? title : '提示',
text: text ? text : '此操作不可逆,您确定这样做吗?',
OkCallback: () => {
Status.confirm.Visible = false;
if (OK) {
OK();
}
},
showCancel: true,
cancelCallback: () => {
Status.confirm.Visible = false;
if (cancel) {
cancel();
}
}
};
Status.confirm = Cfg;
};
window.alert = function (text, OK, title) {
let Cfg = {
Visible: true,
title: title ? title : '提示',
text: text ? text : '不符合规则',
OkCallback: () => {
Status.confirm.Visible = false;
if (OK) {
OK();
}
},
showCancel: false,
cancelCallback: null
};
Status.confirm = Cfg;
};
var hideConfirm = function () {
let Cfg = {
Visible: false,
title: '提示',
text: '',
cancelCallback: null,
OkCallback: null,
showCancel: false
};
Status.confirm = Cfg;
};
window.hideConfirm = hideConfirm;
window.hideAlert = hideConfirm;
watch(
() => props.acIndex, // 监听的属性
(newVal) => {
if (newVal === 5) {
// 确保参数有效
console.log('newVal=', newVal);
getRecordList(); // 调用回调
}
},
{ immediate: true } // 关键:组件初始化时立即执行一次
);
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 30px 12px 12px 12px;
}
.center {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
align-items: center;
justify-content: center;
}
.pickerContent {
box-sizing: border-box;
border: 1px solid rgba(189, 198, 215, 0.8);
border-radius: 2px;
}
.topFilter {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
align-items: flex-start;
}
:deep .pickerContent .el-date-editor {
border: none !important;
}
.marginRight10 {
margin-right: 10px;
}
.mx-1 {
cursor: pointer;
}
.btnSendSms {
background-color: #409eff;
color: #ffffff;
padding: 0px 20px;
cursor: pointer;
}
:deep .el-overlay .el-input-group__append {
padding: 0px !important;
}
:deep .topFilter .el-input-group__append {
padding: 0px 10px !important;
}
</style>