提交 b924f0f8 authored 作者: hejie's avatar hejie

feat: 🚀 设备管理模块接口联调

上级 fb72c276
......@@ -45,30 +45,30 @@ module.exports = function (plop) {
// message: "是否生成页面的components文件夹",
// default: false
// },
// {
// type: "confirm",
// name: "hasRoute",
// message: "是否生成路由配置?",
// default: true
// },
{
type: "confirm",
name: "hasRoute",
message: "是否生成路由配置?",
default: true
},
// {
// type: "confirm",
// name: "hasAsyncRoute",
// message: "是否生成动态路由配置?",
// default: true
// },
// {
// type: "input",
// name: "title",
// message: "请输入路由title名称:",
// when: answers => answers.hasAsyncRoute && answers.hasRoute,
// validate: title => {
// if (!title) {
// return "路由title名称不能为空";
// }
// return true;
// }
// },
{
type: "input",
name: "title",
message: "请输入路由title名称:",
when: answers => answers.hasAsyncRoute && answers.hasRoute,
validate: title => {
if (!title) {
return "路由title名称不能为空";
}
return true;
}
},
{
type: "confirm",
name: "hasApi",
......
import { http } from "@/utils/http";
// interface DeviceInfo {
// deviceName: string;
// // ... 其他属性
// }
type ResultData = {
fileId?: string;
records?: Array<any>;
[key: string]: any;
// data?: DeviceInfo;
};
type Result = {
success: boolean;
data?: {
/** 列表数据 */
list?: Array<any>;
[key: string]: any;
};
success?: boolean;
data: Array<ResultData>;
msg: string;
code: string;
requestId?: string;
id?: number;
};
type RcordsResult = {
success?: boolean;
data: ResultData;
msg: string;
code: string;
requestId?: string;
id?: number;
};
/** 添加设备 */
......@@ -16,26 +37,89 @@ export const addDevice = (data?: object) => {
/** 获取设备列表 */
export const getDeviceList = (data?: object) => {
return http.request<Result>("post", "/device/api/device/list", { data });
return http.request<RcordsResult>("post", "/device/api/device/list", {
data
});
};
/** 删除设备 */
export const setBlackList = (data?: object) => {
return http.request<Result>("post", "/device/api/device/set-black-list", {
// 获取设备树形列表
export const getDeviceTreeList = (data?: object) => {
return http.request<RcordsResult>("post", "/device/api/device/list_tree", {
data
});
};
/** 删除设备 */
export const setBlackList = (data?: object) => {
return http.request<Result>(
"post",
"/device/api/device/set-black-list",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
/** 编辑设备 */
export const updateDevice = (data?: object) => {
return http.request<Result>("post", "/device/api/device/update", { data });
};
/** 获取设备详情 */
export const getDeviceInfo = (data?: object) => {
return http.request<Result>("post", "/device/api/device/info", { data });
return http.request<ResultData>(
"post",
"/device/api/device/info",
{ data },
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
/** 导入设备 */
export const importDevice = (data?: object) => {
return http.request<Result>("post", "/device/api/device/import", {
return http.request<Result>(
"post",
"/device/api/device/import",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
// 根据设备层级查询设备信息
export const getDeviceByLevel = (data?: object) => {
return http.request<Result>(
"post",
"/device/api/device/info_by_level",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
// 获取设备站点
export const getDeviceSite = (data?: object) => {
return http.request<Result>("post", "/device/api/device/find-station-list", {
data
});
};
// 获取操作记录列表数据
export const getOperationRecords = (data?: object) => {
return http.request<RcordsResult>("post", "/device/api/operate-record/list", {
data
});
};
......@@ -22,6 +22,14 @@ type Result = {
requestId?: string;
};
type ResultNoPage = {
success?: boolean;
data: Array<ResultData>;
msg: string;
code: string;
requestId?: string;
};
/** 添加厂商 */
export const addManufacturer = (data?: object) => {
return http.request<Result>("post", "/device/api/manufacturer/add", {
......@@ -47,6 +55,16 @@ export const getManufacturerList = (data?: object) => {
data
});
};
// 获取厂商列表不分页
export const getManufacturerListNoPage = (data?: object) => {
return http.request<ResultNoPage>(
"post",
"/device/api/manufacturer/find_manufacturer_list",
{
data
}
);
};
/** 获取厂商详情 */
export const getManufacturerInfo = (data?: object) => {
......
import { http } from "@/utils/http";
export type Result = {
// data?: {
// /** 列表数据 */
// list: Array<any>;
// };
code: string;
msg: string;
data: {
[key: string]: string;
};
status: number;
requestId: boolean;
};
// 定义一个公共字典接口,用于获取字典数据
/**
* 设备类型code: deviceType
*
*/
export const getDictItems = (code: string) => {
return http.request<Result>(
"post",
`/webapi/api/dict/get-dict-items/${code}`
);
};
......@@ -18,7 +18,13 @@ export const getCaptcha = (time?: string) => {
/** 刷新`token` */
export const refreshTokenApi = (data?: object) => {
return http.request<RefreshTokenResult>("post", "/refresh-token", { data });
return http.request<RefreshTokenResult>(
"post",
"/usermanage/api/auth/refresh-token",
{
data
}
);
};
/** 账户设置-个人信息 */
......
<script setup lang="ts">
import router from "@/router";
defineOptions({
name: ""
});
import type { UploadProps, UploadRequestOptions } from "element-plus";
import {
downLoadTemplate,
importManufacturer,
uploadTemplate
importManufacturer
// uploadTemplate
} from "@/api/manufacturer";
import { importDevice } from "@/api/device";
import { downloadFile } from "@/utils/utils";
const formData = new FormData();
console.log(1111, router.currentRoute.value.query.type);
// 定义所有导入的接口
const importApi = {
manufacturer: importManufacturer,
device: importDevice
};
// 定义模版名称
const templateName = {
manufacturer: "厂商模版",
device: "设备模版"
};
// 定义一个函数,用于处理头像上传成功
const handleAvatarSuccess: UploadProps["onSuccess"] = (
response,
uploadFile
) => {
// // 打印上传文件
// console.log("uploadFile", uploadFile);
// // 设置图片地址为上传文件的地址
// imageUrl.value = URL.createObjectURL(uploadFile.raw!);
// // 打印图片地址
// console.log("imageUrl.value", imageUrl.value);
};
) => {};
// 定义一个函数,用于处理头像上传前
const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => {
......@@ -59,7 +67,10 @@ const uploadFile = async (options: UploadRequestOptions) => {
const confirm = () => {
// 调用接口,上传文件
// uploadTemplate(formData).then(res => {
importManufacturer(formData).then(res => {
// 获取url上的参数type值
const type = JSON.parse(JSON.stringify(router.currentRoute.value.query.type));
// 调用对应的接口
importApi[type](formData).then(res => {
// 如果上传成功,则返回文件地址
if (res.code === "0" || res.code === "A0230") {
ElMessage.success("模版导入成功");
......@@ -68,12 +79,23 @@ const confirm = () => {
ElMessage.error("模版导入失败");
}
});
// importManufacturer(formData).then(res => {
// // 如果上传成功,则返回文件地址
// if (res.code === "0" || res.code === "A0230") {
// ElMessage.success("模版导入成功");
// } else {
// // 如果上传失败,则返回空字符串
// ElMessage.error("模版导入失败");
// }
// });
};
const dwTemplate = async () => {
const type = JSON.parse(JSON.stringify(router.currentRoute.value.query.type));
// 调用下载模版接口
const res = await downLoadTemplate({ templateName: "厂商模版" });
downloadFile(res, "厂商模版");
const res = await downLoadTemplate({ templateName: templateName[type] });
downloadFile(res, templateName[type]);
};
</script>
......
......@@ -198,6 +198,7 @@ const transitionMain = defineComponent({
.app-main {
position: relative;
width: 100%;
min-width: 1200px;
height: 100vh;
overflow-x: hidden;
}
......
......@@ -25,6 +25,16 @@ export default {
title: "无人机设备"
// showParent: true
}
},
{
path: "/device/edit",
name: "DeviceEdit",
component: () => import("@/views/device/add.vue"),
meta: {
showLink: false,
title: "设备编辑"
// showParent: true
}
}
]
};
export default {
path: "/openlayers",
redirect: "/openlayers/index",
meta: {
icon: "ri/file-info-line",
title: "地图"
},
children: [
{
path: "/openlayers/index",
name: "OpenLayers",
component: () => import("@/views/openlayers/index.vue"),
meta: {
title: "地图",
showParent: true
}
}
]
} satisfies RouteConfigsTable;
<script setup lang="ts">
import { useAddHook } from "./utils/addHook";
const { form, handleReset, handleSubmit, rules, validateForm } = useAddHook();
import { defineComponent } from "vue";
import { ElInputTag } from "element-plus";
const formRef = ref(null);
const {
formObj,
handleReset,
handleSubmit,
rules,
validateForm,
deviceTypeOptions,
deviceLevelOptions,
changeLevel,
deviceSiteOptions,
deviceManufacturerOptions,
uploadFile,
// handleAvatarSuccess,
beforeAvatarUpload,
deviceModelOptions
} = useAddHook(formRef);
defineComponent({
components: {
ElInputTag
}
});
</script>
<template>
<div class="add-device">
<h3>设备信息</h3>
<div>
<el-form ref="form" :rules="rules" :model="form" label-width="100px">
<el-form
ref="formRef"
:rules="rules"
:model="formObj"
label-width="110px"
>
<el-row :gutter="30">
<el-col :span="20">
<el-row :gutter="50" class="my-5">
<el-col :span="8">
<el-form-item label="设备名称" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称" />
<el-form-item label="定义设备" prop="deviceLevel">
<!-- 定义一个单选按钮组,必填,选项为“主设备”和“附属设备” -->
<el-radio-group
v-model="formObj.deviceLevel"
@change="changeLevel(formObj.deviceLevel)"
>
<el-radio :label="1">主设备</el-radio>
<el-radio :label="2">附属设备</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所属设备" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
<el-form-item label="所属设备">
<el-select
v-if="formObj.deviceLevel === 1"
v-model="formObj.parentCode"
placeholder="请选择设所属设备"
disabled
>
<el-option label="无" value="0" />
</el-select>
<el-select
v-else
v-model="formObj.parentCode"
placeholder="请选择设所属设备"
>
<el-option
v-for="item in deviceLevelOptions"
:key="item.id"
:label="item.deviceName"
:value="item.deviceCode"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备名称" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
</el-select>
<el-form-item label="设备名称" prop="deviceName">
<el-input
v-model="formObj.deviceName"
placeholder="请输入设备名称"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="50" class="my-5">
<el-col :span="8">
<el-form-item label="设备编号" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称" />
<el-form-item label="设备编号" prop="deviceCode">
<el-input
v-model="formObj.deviceCode"
placeholder="请输入设备编号"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备类型" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
<el-form-item label="设备类型" prop="deviceType">
<!-- 写一个下拉框,遍历一个对象deviceTypeOptions,将对象的key作为label,value作为value -->
<el-select
v-model="formObj.deviceType"
placeholder="请选择设备类型"
>
<el-option
v-for="item in Object.keys(deviceTypeOptions)"
:key="item"
:label="deviceTypeOptions[item]"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备型号" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
<el-form-item label="设备型号" prop="deviceModel">
<el-select
v-model="formObj.deviceModel"
placeholder="请选择设备型号"
>
<el-option
v-for="item in Object.keys(deviceModelOptions)"
:key="item"
:label="deviceModelOptions[item]"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="50" class="my-5">
<el-col :span="12">
<el-form-item label="设备联系人" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称" />
<el-col :span="8">
<el-form-item label="设备联系人">
<el-input
v-model="formObj.deviceStaff"
placeholder="请输入设备联系人"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部署位置" prop="sssb">
<el-input v-model="form.name" placeholder="请输入设备名称" />
<el-col :span="8">
<el-form-item label="联系人电话">
<el-input
v-model="formObj.devicePhone"
placeholder="请输入联系人电话"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="部署位置">
<el-input
v-model="formObj.deviceAddress"
placeholder="请输入部署位置"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="50" class="my-5">
<el-col :span="8">
<el-form-item label="所属站点" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称" />
<el-form-item label="所属站点">
<el-select
v-model="formObj.deviceSide"
placeholder="请选择设备所属站点"
>
<el-option
v-for="item in deviceSiteOptions"
:key="item.stationCode"
:label="item.stationName"
:value="item.stationCode"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备出厂日期" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
</el-select>
<el-form-item label="设备出厂日期" prop="factoryTime">
<el-date-picker
v-model="formObj.factoryTime"
type="date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
placeholder="请选择设备出厂日期"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备厂商" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
<el-form-item label="设备厂商">
<el-select
v-model="formObj.manufacturerId"
placeholder="请选择设备厂商"
>
<el-option
v-for="item in deviceManufacturerOptions"
:key="item.id"
:label="item.manufacturerType"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="50" class="my-5">
<el-col :span="8">
<el-form-item label="年检提醒" prop="name">
<el-input v-model="form.name" placeholder="请输入设备名称" />
<el-form-item label="年检提醒">
<el-date-picker
v-model="formObj.inspectTime"
type="date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
placeholder="请选择年检提醒"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备用途" prop="sssb">
<el-select v-model="form.sssb" placeholder="请选择设备分类">
<el-option label="分类1" value="1" />
<el-option label="分类2" value="2" />
</el-select>
<el-form-item label="设备用途">
<el-input-tag
v-model="formObj.devicePurpose"
:max="3"
placeholder="enter up to 3 tags"
/>
</el-form-item>
</el-col>
</el-row>
......@@ -117,19 +230,26 @@ const { form, handleReset, handleSubmit, rules, validateForm } = useAddHook();
>
<el-upload
ref="uploadRef"
v-model:file-list="validateForm.fileList"
drag
multiple
action="#"
:http-request="uploadFile"
:before-upload="beforeAvatarUpload"
class="w-[200px]!"
:auto-upload="false"
>
<img
src="https://shoplineimg.com/65a8de08211b1e008886980e/6659acc772c9d500104bb668/800x.png?"
<!-- <img
:src="
formObj.devicePicture
? formObj.devicePicture
: 'https://shoplineimg.com/65a8de08211b1e008886980e/6659acc772c9d500104bb668/800x.png?'
"
alt=""
/> -->
<IconifyIconOnline
class="w-35 h-25 text-blue-300"
icon="tabler:photo-up"
/>
<div class="el-upload__text">
<UploadIcon class="m-auto mb-2" />
<UploadIcon class="m-auto" />
2M以内,支持JPG、PNG格式 <br />
<em> 可点击或拖拽上传 </em>
</div>
......@@ -139,9 +259,9 @@ const { form, handleReset, handleSubmit, rules, validateForm } = useAddHook();
</el-row>
<el-row class="mt-4">
<el-col :span="24">
<el-form-item label="备注" prop="name">
<el-form-item label="备注">
<el-input
v-model="form.name"
v-model="formObj.notes"
type="textarea"
placeholder="请输入设备描述"
:rows="10"
......@@ -173,4 +293,12 @@ const { form, handleReset, handleSubmit, rules, validateForm } = useAddHook();
font-size: 24px;
color: #333;
}
:deep(.el-upload-dragger) {
text-align: center;
svg {
margin: 0 auto;
}
}
</style>
<script setup lang="ts">
import { reactive } from "vue";
import { useListHook } from "../utils/listHook";
const { lookDetail, listData } = useListHook();
// 定义props,接收父组件传递过来的数据childrenList
interface Device {
deviceName: string;
deviceCode?: string;
deviceType?: string;
deviceModel?: string;
deviceSide?: string;
deviceAddress?: string;
[key: string]: any;
}
const props = defineProps<{
childrenList: Device[];
}>();
const labels = reactive([
{
label: "已连接",
value: "1"
},
{
label: "降落",
value: "2"
},
{
label: "空闲",
value: "3"
}
]);
const deviceList = reactive([
{
name: "设备编号",
prop: "deviceCode",
value: ""
},
{
name: "设备类型",
prop: "deviceType",
value: ""
},
{
name: "设备型号",
prop: "deviceModel",
value: ""
},
{
name: "所属站点",
prop: "deviceSide",
value: ""
},
{
name: "设备部署位置",
prop: "deviceAddress",
value: ""
}
]);
</script>
<template>
<div class="w-full mx-3">
<el-row
v-for="(device, index) in childrenList"
:key="index"
class="bg-gray-200 py-5 px-10 rounded-2xl mt-3 w-full"
>
<el-col :span="3" :gutter="10">
<img
src="https://shoplineimg.com/65a8de08211b1e008886980e/6659acc772c9d500104bb668/800x.png?"
alt=""
srcset=""
width="100"
/></el-col>
<el-col :span="21" class="cursor-pointer">
<div
class="flex justify-between items-center"
@click="lookDetail(device, index)"
>
<div class="flex justify-between items-center">
<span class="mr-10 font-semibold"> {{ device.deviceName }}</span>
</div>
<el-button type="text" @click="lookDetail(device, index)"
>查看详情</el-button
>
</div>
<div class="flex justify-between items-center mt-5">
<p v-for="(i, index) in deviceList" :key="index">
<label class="mr-3">{{ i.name }}</label>
<span>{{ device[i.prop] }}</span>
</p>
</div>
</el-col>
</el-row>
</div>
</template>
<!-- <style lang="scss" scoped></style> -->
<script setup lang="ts">
import { reactive } from "vue";
import { useListHook } from "../utils/listHook";
import childrenListTable from "./childrenListTable.vue";
const { lookDetail } = useListHook();
const { lookDetail, listData, toggleExpand, handleEdit, deleteDevice } =
useListHook();
const labels = reactive([
{
label: "已连接",
......@@ -19,23 +21,28 @@ const labels = reactive([
]);
const deviceList = reactive([
{
name: "设备名称",
name: "设备编号",
prop: "deviceCode",
value: "ZR103432434"
},
{
name: "设备类型",
prop: "deviceType",
value: "气体检测仪"
},
{
name: "设备型号",
prop: "deviceModel",
value: "ZR-351"
},
{
name: "所属站点",
prop: "deviceSide",
value: "xxx街道南路01号"
},
{
name: "设备部署位置",
prop: "deviceAddress",
value: "准格尔旗薛家湾"
}
]);
......@@ -44,8 +51,8 @@ const deviceList = reactive([
<template>
<div>
<el-row
v-for="(i, index) in 5"
:key="i"
v-for="(device, index) in listData"
:key="device.deviceCode"
class="bg-gray-100 py-5 px-10 mb-8"
>
<el-col :span="3" :gutter="10">
......@@ -56,12 +63,9 @@ const deviceList = reactive([
width="100"
/></el-col>
<el-col :span="21" class="cursor-pointer">
<div
class="flex justify-between items-center"
@click="lookDetail(i, index)"
>
<div class="flex justify-between items-center">
<div class="flex justify-between items-center">
<span class="mr-10 font-semibold"> 2072无人机设备XX设备名称</span>
<span class="mr-10 font-semibold"> {{ device.deviceName }}</span>
<div>
<span
v-for="i in labels"
......@@ -71,22 +75,39 @@ const deviceList = reactive([
>
</div>
</div>
<el-button type="text" @click="lookDetail(i, index)"
>查看详情</el-button
>
<div>
<el-button type="text" @click="lookDetail(device.deviceCode)"
>查看详情</el-button
>
<el-button
type="text"
@click.prevent="handleEdit(device.deviceCode)"
>编辑</el-button
>
<el-button type="text" @click="deleteDevice(device.deviceCode)"
>删除</el-button
>
</div>
</div>
<div class="flex justify-between items-center mt-5">
<p v-for="(i, index) in deviceList" :key="index">
<label>{{ i.name }}</label>
<span>{{ i.value }}</span>
<label class="mr-3">{{ i.name }}</label>
<span>{{ device[i.prop] }}</span>
</p>
</div>
<IconifyIconOnline class="m-auto mt-3" icon="cuida:caret-up-outline" />
<!-- <IconifyIconOnline
class="m-auto mt-2"
icon="cuida:caret-down-outline"
/> -->
<IconifyIconOnline
v-if="device.children?.length"
class="m-auto mt-5"
:icon="
!device.isExpend ? 'tabler:chevrons-up' : 'tabler:chevrons-down'
"
@click="toggleExpand(index)"
/>
</el-col>
<childrenListTable
v-if="device.isExpend"
:childrenList="device.children"
/>
</el-row>
</div>
</template>
......
<script setup lang="ts">
import { ref, reactive } from "vue";
const radio = ref("今天");
import { useDetailHook } from "../utils/detailHook";
const { operationRecords, radio } = useDetailHook();
const { lastBuildTime } = __APP_INFO__;
import { useRenderFlicker } from "@/components/ReFlicker";
import { randomGradient } from "@pureadmin/utils";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Iphone from "~icons/ep/iphone";
const activities = [
{
content: "支持圆点发光",
timestamp: lastBuildTime,
icon: markRaw(useRenderFlicker())
},
{
content: "支持方形发光",
timestamp: lastBuildTime,
icon: markRaw(useRenderFlicker({ borderRadius: 0, background: "#67C23A" }))
},
{
content: "支持渐变发光",
timestamp: lastBuildTime,
icon: markRaw(
useRenderFlicker({
background: randomGradient({
randomizeHue: true
})
})
)
},
{
content: "支持默认颜色",
timestamp: lastBuildTime
},
{
content: "支持自定义颜色",
timestamp: lastBuildTime,
color: "#F56C6C"
},
{
content: "支持自定义图标",
timestamp: "2023-10-01 12:00:00",
color: "transparent",
icon: useRenderIcon(Iphone, {
color: "#0bbd87"
})
}
];
</script>
<template>
......@@ -12,8 +60,51 @@ const radio = ref("今天");
<el-radio-button label="自定义">自定义</el-radio-button>
</el-radio-group>
<!-- 这一块时暂无数据 -->
<el-empty description="暂无数据" />
<!-- <el-empty description="暂无数据" /> -->
<div class="mt-6 flex justify-center">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in operationRecords"
:key="index"
:icon="activity.icon"
:color="activity.color"
:timestamp="activity.timestamp"
>
<span class="text-lg font-bold">{{ activity.operateType }}</span>
<p v-if="activity.operateDescribe">{{ activity.operateDescribe }}</p>
<div class="message">
<span>操作人:{{ activity.createUser }}</span>
<span
>操作状态:{{
activity.operateStatus == 1 ? "成功" : "失败"
}}</span
>
</div>
</el-timeline-item>
</el-timeline>
</div>
<!-- <el-timeline class="pl-40!">
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:icon="activity.icon"
:color="activity.color"
:timestamp="activity.timestamp"
placement="bottom"
>
<div class="message">
vue-pure-admin 第{{ activities.length - index }}个版本发布啦
</div>
</el-timeline-item>
</el-timeline> -->
</div>
</template>
<!-- <style lang="scss" scoped></style> -->
<style lang="scss" scoped>
::v-deep .el-timeline-item__timestamp {
position: absolute;
top: -4px;
left: -135px;
}
</style>
......@@ -3,80 +3,21 @@ defineOptions({
name: "DeviceDetail"
});
import { reactive } from "vue";
import { useListHook } from "./utils/listHook";
import { useDetailHook } from "./utils/detailHook";
import type { TabsPaneContext } from "element-plus";
import deviceAnalysis from "./components/deviceAnalysis.vue";
import dataChart from "./components/dataChart.vue";
import dataLog from "./components/dataLog.vue";
import operationRecord from "./components/operationRecord.vue";
const { lookDetail, alarmSetting } = useListHook();
const labels = reactive([
{
label: "已连接",
value: "1"
},
{
label: "降落",
value: "2"
},
{
label: "空闲",
value: "3"
}
]);
const deviceList = reactive([
{
name: "设备编号",
value: "ZR103432434"
},
{
name: "设备类型",
value: "气体检测仪"
},
{
name: "设备型号",
value: "ZR-351"
},
// {
// name: "设备厂商",
// value: "ZR-351"
// },
{
name: "设备联系人",
value: "ZR-351"
},
{
name: "所属站点",
value: "xxx街道..."
},
{
name: "设备部署位置",
value: "准格尔旗薛家湾..."
},
{
name: "备注",
value: "ZR-351"
}
]);
const { deviceInfo, labels, deviceList, Factor } = useDetailHook();
// {
// name: "出厂日期",
// value: "ZR-351"
// }
const info = reactive([
{
name: "臭氧浓度(mg/m³)",
value: "0.0172"
},
{
name: "温度(°C)",
value: "30.0"
},
{
name: "大气压(kPa)",
value: "103.54"
}
]);
const activeName = ref("1");
const activeName = ref("4");
const handleClick = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event);
......@@ -90,9 +31,9 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
<!-- 设备信息模块 -->
<div class="flex items-center mb-10">
<!-- 设备基本信息 -->
<div>
<div class="flex-1">
<div class="flex items-center">
<h3 class="mr-5!">无人机六旋翼款</h3>
<h3 class="mr-5!">{{ deviceInfo.deviceName }}</h3>
<span class="text-sm flex items-center mr-5">
<i
class="block w-3.5 h-3.5 bg-sky-600 rounded-lg mr-1 cursor-pointer"
......@@ -111,14 +52,14 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
class="felx mb-4! basis-1/4"
>
<label>{{ i.name }}</label>
<span>{{ i.value }}</span>
<span>{{ deviceInfo[i.prop] }}</span>
</p>
</div>
<div
class="flex items-center justify-between bg-gray-100 px-12 py-8 mt-10"
>
<p
v-for="i in info"
v-for="i in Factor"
:key="i.name"
class="flex flex-col items-center"
>
......
<script setup lang="ts">
import listTable from "./components/listTable.vue";
import { useListHook } from "./utils/listHook";
const { addDevice, importDeviceTemplate } = useListHook();
</script>
<template>
<div class="device-list">
<div class="btn mb-5">
<el-button>新建</el-button>
<el-button>编辑</el-button>
<el-button>删除</el-button>
<el-button>导入</el-button>
<el-button @click="addDevice">新建</el-button>
<!-- <el-button>编辑</el-button>
<el-button>删除</el-button> -->
<el-button @click="importDeviceTemplate">导入</el-button>
<el-button>报修</el-button>
</div>
<listTable />
......
......@@ -16,10 +16,10 @@ const formRef = ref();
const tableRef = ref();
const {
form,
formObj,
loading,
columns,
dataList,
listData,
pagination,
selectedNum,
onSearch,
......@@ -29,7 +29,12 @@ const {
handleSizeChange,
onSelectionCancel,
handleCurrentChange,
handleSelectionChange
handleSelectionChange,
deviceLevelOptions,
deviceTypeOptions,
deviceModelOptions,
deviceSiteOptions,
deviceManufacturerOptions
} = useRole(tableRef);
</script>
......@@ -39,147 +44,190 @@ const {
<el-form
ref="formRef"
:inline="true"
:model="form"
:model="formObj"
class="search-form bg-bg_color w-full pl-8 pt-[12px] overflow-auto"
label-position="left"
label-width="85px"
>
<el-form-item label="设别分类" prop="status">
<el-select
v-model="form.status"
placeholder="请选择"
clearable
class="w-[150px]!"
>
<el-option label="成功" value="1" />
<el-option label="失败" value="0" />
</el-select>
</el-form-item>
<el-form-item label="所属设备" prop="status">
<el-select
v-model="form.status"
placeholder="请选择"
clearable
class="w-[150px]!"
>
<el-option label="成功" value="1" />
<el-option label="失败" value="0" />
</el-select>
</el-form-item>
<el-form-item label="设备名称" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item label="设备类型" prop="status" label-width="85px">
<el-select
v-model="form.status"
placeholder="请选择"
clearable
class="w-[150px]!"
>
<el-option label="成功" value="1" />
<el-option label="失败" value="0" />
</el-select>
</el-form-item>
<el-form-item label="设备型号" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item label="设备编号" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item label="所属站点" prop="status">
<el-select
v-model="form.status"
placeholder="请选择"
clearable
class="w-[150px]!"
>
<el-option label="成功" value="1" />
<el-option label="失败" value="0" />
</el-select>
</el-form-item>
<el-form-item label="设备联系人" prop="username" label-width="85px">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item label="部署位置" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item label="设备出厂日期" prop="loginTime" label-width="102px">
<!-- :shortcuts="getPickerShortcuts()" -->
<el-date-picker
v-model="form.loginTime"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期时间"
end-placeholder="结束日期时间"
/>
</el-form-item>
<el-form-item label="设备厂商" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item label="年检提醒" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="w-[150px]!"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
查询
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
</el-form-item>
<el-row>
<el-col :span="6">
<el-form-item label="设别分类" class="w-5/6" prop="status">
<el-select
v-model="formObj.deviceLevel"
placeholder="请选择设所属设备"
>
<el-option label="主设备" :value="1" />
<el-option label="附属设备" :value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="所属设备" class="w-5/6" prop="status">
<el-select
v-model="formObj.parentCode"
placeholder="请选择设所属设备"
>
<el-option
v-for="item in deviceLevelOptions"
:key="item.id"
:label="item.deviceName"
:value="item.deviceCode"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="设备名称" class="w-5/6" prop="username">
<el-input
v-model="formObj.deviceName"
placeholder="请输入设备名称"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item
label="设备类型"
class="w-5/6"
prop="status"
label-width="85px"
>
<el-select
v-model="formObj.deviceType"
placeholder="请选择设备类型"
>
<el-option
v-for="item in Object.keys(deviceTypeOptions)"
:key="item"
:label="deviceTypeOptions[item]"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="设备型号" class="w-5/6" prop="username">
<el-select
v-model="formObj.deviceModel"
placeholder="请选择设备型号"
>
<el-option
v-for="item in Object.keys(deviceModelOptions)"
:key="item"
:label="deviceModelOptions[item]"
:value="item"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="设备编号" class="w-5/6" prop="username">
<el-input
v-model="formObj.deviceCode"
placeholder="请输入设备编号"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="所属站点" class="w-5/6" prop="status">
<el-select
v-model="formObj.deviceSide"
placeholder="请选择设备所属站点"
>
<el-option
v-for="item in deviceSiteOptions"
:key="item.stationCode"
:label="item.stationName"
:value="item.stationCode"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item
label="设备联系人"
class="w-5/6"
prop="username"
label-width="85px"
>
<el-input
v-model="formObj.devicePhone"
placeholder="请输入联系人电话"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="部署位置" class="w-5/6" prop="username">
<el-input
v-model="formObj.deviceAddress"
placeholder="请输入部署位置"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item
label="设备出厂日期"
class="w-5/6"
prop="loginTime"
label-width="98px"
>
<!-- :shortcuts="getPickerShortcuts()" -->
<el-date-picker
v-model="formObj.factoryTime"
type="date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
placeholder="请选择设备出厂日期"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="设备厂商" class="w-5/6" prop="username">
<el-select
v-model="formObj.manufacturerId"
placeholder="请选择设备厂商"
>
<el-option
v-for="item in deviceManufacturerOptions"
:key="item.id"
:label="item.manufacturerType"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年检提醒" class="w-5/6" prop="username">
<el-date-picker
v-model="formObj.inspectTime"
type="date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
placeholder="请选择年检提醒"
/>
</el-form-item>
</el-col>
<el-col :span="24" class="flex text-center mt-5">
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
查询
</el-button>
<el-button
:icon="useRenderIcon(Refresh)"
@click="resetForm(formRef)"
>
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<PureTableBar title="查询结果" :columns="columns" @refresh="onSearch">
<!-- <template #buttons>
<el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll">
<template #reference>
<el-button type="danger" :icon="useRenderIcon(Delete)">
清空日志
</el-button>
</template>
</el-popconfirm>
</template> -->
<template v-slot="{ size, dynamicColumns }">
<div
v-if="selectedNum > 0"
......@@ -212,7 +260,7 @@ const {
:size="size"
adaptive
:adaptiveConfig="{ offsetBottom: 108 }"
:data="dataList"
:data="listData"
:columns="dynamicColumns"
:pagination="{ ...pagination, size }"
:header-cell-style="{
......
import { message } from "@/utils/message";
import { reactive, ref, onMounted, toRaw } from "vue";
import { useRouter } from "vue-router";
import { getDictItems } from "@/api/public";
import { ElMessage } from "element-plus";
import type { UploadProps, UploadRequestOptions } from "element-plus";
import { formUpload, getFileURL } from "@/api/file";
export function useAddHook() {
const form = reactive({
name: "",
sssb: "",
sbmc2: "",
sbbh: "",
sblx: "",
sbxh: "",
sblxr: "",
bswz: "",
sszd: "",
sbccrq: "",
sbcs: "",
njtx: "",
sbyt: "",
bz: ""
import {
addDevice,
updateDevice,
getDeviceByLevel,
getDeviceSite,
getDeviceInfo
} from "@/api/device";
import { getManufacturerListNoPage } from "@/api/manufacturer";
export function useAddHook(formRef: Ref) {
// 使用useRouter获取路由对象
const router = useRouter();
const formObj = ref({
deviceLevel: 1, //设备层级
parentCode: "0", //上级设备编码
deviceName: "", //设备名称
deviceType: "", //设备类型
deviceCode: "", //设备编码
deviceModel: "", //设备型号
manufacturerId: "", //设备厂商
deviceStatus: "", //设备状态
deviceAddress: "", //设备位置
deviceSide: "", //所属站点
deviceStaff: "", //设备联系人
devicePhone: "", //设备联系电话
deviceRemake: "222", //备注
factoryTime: "", //出厂日期
inspectTime: "", //年检提醒
devicePurpose: [], //设备用途
notes: "", //备注
devicePicture: "", //设备图片
fileId: "" //文件id
});
const formRef = ref();
const deviceTypeOptions = ref({}); //设备类型数据列表
const deviceLevelOptions = ref([]); //所属设备数据列表
const deviceSiteOptions = ref([]); //设备站点列表数据
const deviceManufacturerOptions = ref([]); //设备厂商列表数据
const deviceModelOptions = ref({}); //设备型号列表数据
const validateForm = reactive({
fileList: [],
date: ""
});
const rules = {
name: [{ required: true, message: "请输入设备名称", trigger: "blur" }]
// sssb: [{ required: true, message: "请输入设备分类", trigger: "blur" }],
// sbmc2: [{ required: true, message: "请输入所属设备", trigger: "blur" }],
// sblx: [{ required: true, message: "请输入设备类型", trigger: "blur" }],
// sbxh: [{ required: true, message: "请输入设备型号", trigger: "blur" }],
// sblxr: [{ required: true, message: "请输入设备联系人", trigger: "blur" }],
// bswz: [{ required: true, message: "请输入设备位置", trigger: "blur" }],
// sszd: [{ required: true, message: "请输入所属站点", trigger: "blur" }],
// sbccrq: [{ required: true, message: "请输入出厂日期", trigger: "blur" }],
// sbcs: [{ required: true, message: "请输入设备厂商", trigger: "blur" }],
// njtx: [{ required: true, message: "请输入年检提醒", trigger: "blur" }],
// sbyt: [{ required: true, message: "请输入设备状态", trigger: "blur" }],
// bz: [{ required: true, message: "请输入备注", trigger: "blur" }]
deviceLevel: [
{
required: true,
message: "请选择定义设备",
trigger: "blur"
}
],
// 所属设备
parentCode: [
{ required: true, message: "请输入设备编号", trigger: "change" }
],
deviceName: [
{ required: true, message: "请输入设备名称", trigger: "blur" },
{
pattern: /^.{0,32}$/,
message: "设备名称长度必须在0到32个字符之间",
trigger: "blur"
}
],
deviceCode: [
{ required: true, message: "请输入设备编号", trigger: "blur" },
{
pattern: /^[A-Za-z0-9]+$/,
message: "设备编号必须为数字或字母",
trigger: "blur"
}
],
deviceType: [
{ required: true, message: "请选择设备类型", trigger: "change" }
],
// 设备型号校验规则
deviceModel: [
{ required: true, message: "请选择设备类型", trigger: "change" }
],
// 设备联系人校验规则
deviceStaff: [
{ required: true, message: "请输入设备联系人", trigger: "blur" },
{
pattern: /^.{0,16}$/,
message: "设备联系人长度必须在0到32个字符之间",
trigger: "blur"
}
],
// 联系人电话校验规则:
devicePhone: [
{ required: true, message: "请输入设备联系人", trigger: "blur" },
{
pattern: /^.{0,16}$/,
message: "设备联系人长度必须在0到16个字符之间",
trigger: "blur"
}
],
// 部署位置校验规则:
deviceAddress: [
{ required: true, message: "请输入设备部署位置", trigger: "blur" },
{
pattern: /^.{0,32}$/,
message: "设备部署位置长度必须在0到32个字符之间",
trigger: "blur"
}
],
// 所属站点校验规则
deviceSide: [
{ required: true, message: "请选择设备所属站点", trigger: "change" }
],
// 设备出厂日期校验规则
factoryTime: [
{ required: true, message: "请选择设备出厂日期", trigger: "change" }
],
// 设备厂商校验规则
manufacturerId: [
{ required: true, message: "请选择设备厂商", trigger: "change" }
],
// 设备用途
devicePurpose: [
{ required: true, message: "请输入设备用途", trigger: "change" },
{
pattern: /^.{0,8}$/,
message: "设备用途长度必须在0到8个字符之间",
trigger: "blur"
}
],
// 备注
notes: [
{ required: true, message: "请输入备注", trigger: "blur" },
{
pattern: /^.{0,8}$/,
message: "备注长度必须在0到8个字符之间",
trigger: "blur"
}
]
};
const changeLevel = (val: any) => {
formObj.value.parentCode = val === 1 ? "0" : "";
};
// 获取设备类型的字典数据
const getDeviceType = async () => {
const res = await getDictItems("deviceType");
if (res.code === "0") {
deviceTypeOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备类型的字典数据
const getDeviceModelType = async () => {
const res = await getDictItems("deviceModel");
if (res.code === "0") {
deviceModelOptions.value = res.data;
} else {
ElMessage.error(`获取设备模型失败`);
}
};
// 获取所属设备列表
const getDeviceList = async () => {
const res = await getDeviceByLevel({ deviceLevel: 1 });
if (res.code === "0") {
deviceLevelOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备站点列表
const getDeviceSiteList = async () => {
const res = await getDeviceSite();
if (res.code === "0") {
deviceSiteOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备厂商列表
const getManufacturerList = async () => {
const res = await getManufacturerListNoPage();
if (res.code === "0") {
deviceManufacturerOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 判断url上是否有id参数,如果有则调用getDeviceInfo接口获取设备信息,并赋值给formObj
if (router.currentRoute.value.query.deviceCode) {
// const res = await getDeviceInfo({
// id: router.currentRoute.value.query.deviceCode
// });
// if (res.code === "0") {
// formObj = res.data;
// } else {
// ElMessage.error(`获取设备信息失败`);
// }
const deviceCode = router.currentRoute.value.query.deviceCode;
getDeviceInfo({ deviceCode }).then(res => {
if (res.code === "0") {
formObj.value = res.data;
if (typeof res.data.devicePurpose === "string") {
formObj.value.devicePurpose = res.data.devicePurpose.split(",");
}
}
});
}
// 定义一个函数,用于重置表单
const handleReset = () => {
Object.keys(form).forEach(key => {
form[key] = "";
// 遍历表单中的每一个键值对
Object.keys(formObj).forEach(key => {
// 将表单中的每一个键值对的值重置为空字符串
formObj[key] = "";
});
};
// 上传文件
const uploadFile = async (options: UploadRequestOptions) => {
const { file } = options;
console.log("file", file);
// 文件参数封装成formdata格式上传
const formData = new FormData();
formData.append("file", file);
// 把文件类型也放到formdata中,值是4
formData.append("fileType", "1");
// 调用formUpload接口,上传文件
const res = await formUpload(formData);
// 如果上传成功,则返回文件地址
if (res.code === "0") {
formObj.value.devicePicture = res.data.filePath;
getExcelUrl(res.data.fileId);
ElMessage.success("图片上传成功");
} else {
// 如果上传失败,则返回空字符串
ElMessage.error("图片上传失败");
}
};
// 定义一个函数,用于处理头像上传成功
// const handleAvatarSuccess: UploadProps["onSuccess"] = (
// response,
// uploadFile
// ) => {
// // 打印上传文件
// console.log("uploadFile", uploadFile);
// // 设置图片地址为上传文件的地址
// imageUrl.value = URL.createObjectURL(uploadFile.raw!);
// // 打印图片地址
// console.log("imageUrl.value", imageUrl.value);
// };
// 定义一个函数,用于处理头像上传前
const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => {
// 打印原始文件
console.log("rawFile", rawFile);
// 如果文件类型不是xlsx/xls,则提示错误信息,并返回false
const validTypes = ["image/jpeg", "image/png"];
const isValid = validTypes.includes(rawFile.type);
if (!isValid) {
// if (rawFile.type !== "xlsx/xls") {
ElMessage.error("图片上传类型只支持JPG、PNG格式!");
return false;
// 如果文件大小超过2MB,则提示错误信息,并返回false
} else if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error("图片大小不能超过2MB!");
return false;
}
// 返回true
return true;
};
// 获取Excel文件的下载链接
const getExcelUrl = async (fileId: string) => {
const res = await getFileURL({ fileId });
if (res.code === "0") {
// 如果获取成功,则返回文件地址
// fileData.fileName = res.data.fileName;
// fileData.fileUrl = res.data.filePath;
console.log("fileData.value");
// return res.data;
} else {
// 如果获取失败,则返回空字符串
return "";
}
};
// 提交表单
const handleSubmit = async () => {
const data = toRaw(form);
const res = await addDevice(data);
if (res.code === 200) {
message.success("添加成功");
const valid = await formRef.value.validate();
if (!valid) return;
// 将表单数据转换为原始数据
const params = JSON.parse(JSON.stringify(toRaw(formObj.value)));
params.devicePurpose = params.devicePurpose.toString();
// 判断url是否包含id,如果包含则调用更新设备接口,否则调用添加设备接口
if (router.currentRoute.value.query.deviceCode) {
const deviceCode = router.currentRoute.value.query.deviceCode;
const res = await updateDevice({ ...params, deviceCode });
if (res.code === "0") {
ElMessage.success("更新成功");
// 更新设备信息后,跳转到设备列表页面
router.push("/device/list");
} else {
ElMessage.error("更新失败" + res.msg);
}
} else {
message.error("添加失败" + res.msg);
// 调用添加设备接口,传入表单数据
const res = await addDevice(params);
// 如果接口返回的code为200,则表示添加成功
if (res.code === "0") {
// 弹出成功提示
ElMessage.success("添加成功");
// 更新设备信息后,跳转到设备列表页面
router.push("/device/list");
} else {
// 否则弹出失败提示,并显示错误信息
ElMessage.error("添加失败" + res.msg);
}
}
};
// })
onMounted(() => {
getDeviceType();
getDeviceList();
getDeviceSiteList();
getManufacturerList();
getDeviceModelType();
// 获取设备类型
// 获取设备型号
// 获取设备厂商
// 获取设备状态
});
return {
form,
formObj,
handleReset,
handleSubmit,
rules,
formRef,
validateForm
validateForm,
deviceTypeOptions,
getDeviceType,
deviceLevelOptions,
changeLevel,
deviceSiteOptions,
deviceManufacturerOptions,
uploadFile,
beforeAvatarUpload,
getExcelUrl,
deviceModelOptions
};
}
import router from "@/router";
import { ref, onMounted } from "vue";
import { useRenderFlicker } from "@/components/ReFlicker";
// import { randomGradient } from "@pureadmin/utils";
// import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// import Iphone from "~icons/ep/iphone";
import { getDeviceInfo, getOperationRecords } from "@/api/device";
export function useDetailHook() {
const deviceInfo = ref({
// deviceName: ""
});
const labels = reactive([
{
label: "已连接",
value: "1"
},
{
label: "降落",
value: "2"
},
{
label: "空闲",
value: "3"
}
]);
const deviceList = reactive([
{
name: "设备编号",
prop: "deviceCode",
value: ""
},
{
name: "设备类型",
prop: "deviceType",
value: ""
},
{
name: "设备型号",
prop: "deviceModel",
value: ""
},
// {
// name: "设备厂商",
// value: "ZR-351"
// },
{
name: "设备联系人",
prop: "deviceContact",
value: ""
},
{
name: "所属站点",
prop: "deviceSite",
value: ""
},
{
name: "设备部署位置",
prop: "deviceLocation",
value: ""
},
{
name: "备注",
prop: "notes",
value: ""
}
]);
// 各种因子
const Factor = reactive([
{
name: "臭氧浓度(mg/m³)",
value: "0.0172"
},
{
name: "温度(°C)",
value: "30.0"
},
{
name: "大气压(kPa)",
value: "103.54"
}
]);
const operationRecords = ref([]);
const radio = ref("今天");
// 根据deviceCode获取设备详情
const getDeviceInfoByCode = async () => {
console.log(
"router.currentRoute.value.query",
router.currentRoute.value.query
);
const res = await getDeviceInfo({
deviceCode: router.currentRoute.value.query?.deviceCode
});
deviceInfo.value = res.data || {};
};
// 获取操作记录列表数据
const getOperationRecordsList = async () => {
const params = {
deviceCode: router.currentRoute.value.query?.deviceCode,
endTime: "2026-06-28 14:10:00",
pageNum: 0,
pageSize: 10,
startTime: "2016-06-28 14:10:00"
};
const res = await getOperationRecords(params);
if (!res || !res.data) return;
operationRecords.value = handleOperationRecords(res.data.records) || [];
};
// 处理操作记录的数据结构
const handleOperationRecords = (data: any) => {
const newData = [];
data.forEach((item: any) => {
item.createTime = item.createTime.slice(0, 19).replace("T", " ");
newData.push({
...item,
timestamp: item.operateTime.slice(0, 19).replace("T", " "),
icon: markRaw(useRenderFlicker())
});
});
return newData;
};
onMounted(() => {
// getList();
getDeviceInfoByCode();
getOperationRecordsList();
// 获取设备类型
// 获取设备型号
// 获取设备厂商
// 获取设备状态
});
return {
deviceInfo,
labels,
deviceList,
Factor,
operationRecords,
radio
};
}
import router from "@/router";
import { message } from "@/utils/message";
import { reactive, ref, onMounted, toRaw } from "vue";
import {
addDialog
// closeDialog,
// updateDialog,
// closeAllDialog
} from "@/components/ReDialog";
import { ref, onMounted } from "vue";
import forms, { type FormProps } from "../components/alarmForm.vue";
import { getDeviceTreeList, setBlackList } from "@/api/device";
export function useListHook() {
const form = reactive({
name: "",
sssb: "",
sbmc2: "",
sbbh: "",
sblx: "",
sbxh: "",
sblxr: "",
bswz: "",
sszd: "",
sbccrq: "",
sbcs: "",
njtx: "",
sbyt: "",
bz: ""
});
const formRef = ref();
const validateForm = reactive({
fileList: [],
date: ""
});
const rules = {
name: [{ required: true, message: "请输入设备名称", trigger: "blur" }]
// sssb: [{ required: true, message: "请输入设备分类", trigger: "blur" }],
// sbmc2: [{ required: true, message: "请输入所属设备", trigger: "blur" }],
// sblx: [{ required: true, message: "请输入设备类型", trigger: "blur" }],
// sbxh: [{ required: true, message: "请输入设备型号", trigger: "blur" }],
// sblxr: [{ required: true, message: "请输入设备联系人", trigger: "blur" }],
// bswz: [{ required: true, message: "请输入设备位置", trigger: "blur" }],
// sszd: [{ required: true, message: "请输入所属站点", trigger: "blur" }],
// sbccrq: [{ required: true, message: "请输入出厂日期", trigger: "blur" }],
// sbcs: [{ required: true, message: "请输入设备厂商", trigger: "blur" }],
// njtx: [{ required: true, message: "请输入年检提醒", trigger: "blur" }],
// sbyt: [{ required: true, message: "请输入设备状态", trigger: "blur" }],
// bz: [{ required: true, message: "请输入备注", trigger: "blur" }]
const listData = ref([]);
// 根据索引判断跳转到不同的设备详情页面
const lookDetail = deviceCode => {
router.push({
path: "/device/detail",
query: { deviceCode }
});
};
// 定义一个handleReset函数,用于重置表单
const handleReset = () => {
// 遍历form对象的所有键
Object.keys(form).forEach(key => {
// 将form对象中对应键的值设置为空字符串
form[key] = "";
});
// 点击编辑按钮,跳转到编辑页面
const handleEdit = deviceCode => {
router.push({ path: `/device/edit`, query: { deviceCode } });
};
// 提交表单
const handleSubmit = async () => {
// 将表单数据转换为原始数据
const data = toRaw(form);
// 调用添加设备接口
const res = await addDevice(data);
// 判断接口返回的code是否为200
if (res.code === 200) {
// 如果是200,则显示添加成功
message.success("添加成功");
} else {
// 如果不是200,则显示添加失败并显示错误信息
message.error("添加失败" + res.msg);
}
// 点击新建按钮,跳转到新建页面
const addDevice = () => {
router.push({ path: "/device/add" });
};
// 根据索引判断跳转到不同的设备详情页面
const lookDetail = (row: any, index: number) => {
// 如果索引大于0,则跳转到设备详情2页面
index > 0
? router.push({ path: "/device/detail2" })
: // 否则跳转到设备详情页面
router.push({ path: "/device/detail" });
// 获取设备列表
const getList = async () => {
// 调用getDeviceList函数,获取设备列表
const res = await getDeviceTreeList({ pageNum: 1, pageSize: 10 });
// 给数据添加一个isExpend属性,默认值是false,点击展开按钮的时候,将isExpend属性设置为true,再次点击的时候,将isExpend属性设置为false
res.data.records.forEach((item: any) => {
item.isExpend = false;
});
listData.value = res.data.records;
};
const alarmSetting = () => {
addDialog({
width: "35%",
title: "阈值设置",
contentRenderer: () => forms,
props: {
// 赋默认值
formInline: {
user: "菜虚鲲",
region: "浙江"
}
},
closeCallBack: ({ options, args }) => {
// options.props 是响应式的
const { formInline } = options.props as FormProps;
const text = `姓名:${formInline.user} 城市:${formInline.region}`;
if (args?.command === "cancel") {
// 您点击了取消按钮
message(`您点击了取消按钮,当前表单数据为 ${text}`);
} else if (args?.command === "sure") {
message(`您点击了确定按钮,当前表单数据为 ${text}`);
} else {
message(
`您点击了右上角关闭按钮或空白页或按下了esc键,当前表单数据为 ${text}`
);
}
// 删除设备
const deleteDevice = async deviceCode => {
// 删除之前,先弹出一个确认框,确认是否删除
ElMessageBox.confirm("确认删除该设备吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
// 确认删除之后,调用deleteDevice函数,删除设备
// await deleteDevice(deviceCode);
// 调用setBlackList函数,删除设备
const res = await setBlackList({ deviceCode });
// 判断接口返回的code是否为200
if (res.code === "0") {
// 如果是200,则显示删除成功
ElMessage.success("删除成功");
getList();
}
});
};
// 导入设备模版
const importDeviceTemplate = async () => {
// // 调用importDevice函数,导入设备模版
// const res = await importDevice();
// // 判断接口返回的code是否为200
// if (res.code === "0") {
// // 如果是200,则显示导入成功
// ElMessage.success("导入成功");
// getList();
// }
router.push({ path: "/import-templete", query: { type: "device" } });
};
// 是否展开二级设备
const toggleExpand = index => {
listData.value[index].isExpend = !listData.value[index].isExpend;
};
onMounted(() => {
getList();
// 获取设备类型
// 获取设备型号
// 获取设备厂商
// 获取设备状态
});
return {
form,
handleReset,
handleSubmit,
rules,
formRef,
validateForm,
lookDetail,
alarmSetting
getList,
listData,
toggleExpand,
addDevice,
handleEdit,
deleteDevice,
importDeviceTemplate
};
}
import dayjs from "dayjs";
// import dayjs from "dayjs";
import { message } from "@/utils/message";
import { getKeyList } from "@pureadmin/utils";
import { getLoginLogsList } from "@/api/system";
// import { usePublicHooks } from "@/views/system/hooks";
import type { PaginationProps } from "@pureadmin/table";
import { type Ref, reactive, ref, onMounted, toRaw } from "vue";
// import { type Ref, reactive, ref, onMounted } from "vue";
import { getDeviceByLevel, getDeviceList, getDeviceSite } from "@/api/device";
import { getDictItems } from "@/api/public";
import { getManufacturerListNoPage } from "@/api/manufacturer";
export function useRole(tableRef: Ref) {
const form = reactive({
username: "",
status: "",
loginTime: ""
const formObj = ref({
deviceLevel: null, //设备层级
parentCode: "", //上级设备编码
deviceName: "", //设备名称
deviceType: "", //设备类型
deviceCode: "", //设备编码
deviceModel: "", //设备型号
manufacturerId: "", //设备厂商
deviceStatus: "", //设备状态
deviceAddress: "", //设备位置
deviceSide: "", //所属站点
deviceContact: "", //设备联系人
devicePhone: "", //设备联系电话
deviceRemake: "", //备注
factoryTime: "", //出厂日期
inspectTime: "", //年检提醒
devicePurpose: "", //设备用途
notes: "", //备注
devicePicture: "", //设备图片
fileId: "" //文件id
});
const dataList = ref([]);
const listData = ref([]);
const loading = ref(false);
const selectedNum = ref(0);
// const { tagStyle } = usePublicHooks();
const deviceTypeOptions = ref({}); //设备类型数据列表
const deviceLevelOptions = ref([]); //所属设备数据列表
const deviceSiteOptions = ref([]); //设备站点列表数据
const deviceManufacturerOptions = ref([]); //设备厂商列表数据
const deviceModelOptions = ref({}); //设备型号列表数据
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
......@@ -37,76 +61,84 @@ export function useRole(tableRef: Ref) {
},
{
label: "设备分类",
prop: "username",
prop: "deviceLevel",
minWidth: 100
},
{
label: "所属设备",
prop: "ip",
prop: "parentCode",
minWidth: 140
},
{
label: "设备名称",
prop: "address",
prop: "deviceName",
minWidth: 140
},
{
label: "设备类型",
prop: "system",
prop: "deviceType",
minWidth: 100
},
{
label: "设备型号",
prop: "browser",
prop: "deviceModel",
minWidth: 100
},
{
label: "所属站点",
prop: "behavior",
prop: "deviceSide",
minWidth: 100
},
{
label: "设备联系人",
prop: "behavior",
prop: "devicePhone",
minWidth: 100
},
{
label: "部署位置",
prop: "behavior",
prop: "deviceAddress",
minWidth: 100
},
{
label: "设备出厂日期",
prop: "loginTime",
minWidth: 180,
formatter: ({ loginTime }) =>
dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss")
prop: "factoryTime",
minWidth: 180
// formatter: ({ loginTime }) =>
// dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "设备厂商",
prop: "behavior",
prop: "manufacturerId",
minWidth: 100
},
{
label: "年检提醒",
prop: "behavior",
prop: "inspectTime",
minWidth: 100
}
];
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
pagination.pageSize = val;
// 重置表格高度
tableRef.value.setAdaptive();
// 重新获取列表数据
onSearch();
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
pagination.currentPage = val;
// 重置表格高度
tableRef.value.setAdaptive();
// 重新获取列表数据
onSearch();
}
/** 当CheckBox选择项发生变化时会触发该事件 */
function handleSelectionChange(val) {
selectedNum.value = val.length;
// 重置表格高度
tableRef.value.setAdaptive();
}
/** 取消选择 */
......@@ -128,6 +160,82 @@ export function useRole(tableRef: Ref) {
onSearch();
}
// 获取设备类型的字典数据
const getDeviceType = async () => {
const res = await getDictItems("deviceType");
if (res.code === "0") {
deviceTypeOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备类型的字典数据
const getDeviceModelType = async () => {
const res = await getDictItems("deviceModel");
if (res.code === "0") {
deviceModelOptions.value = res.data;
} else {
ElMessage.error(`获取设备模型失败`);
}
};
// 获取所属设备列表
const getDeviceLevelList = async () => {
const res = await getDeviceByLevel({ deviceLevel: 2 });
if (res.code === "0") {
deviceLevelOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备站点列表
const getDeviceSiteList = async () => {
const res = await getDeviceSite();
if (res.code === "0") {
deviceSiteOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备厂商列表
const getManufacturerList = async () => {
const res = await getManufacturerListNoPage();
if (res.code === "0") {
deviceManufacturerOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备列表
const getList = async () => {
// 调用getDeviceList函数,获取设备列表
const params = toRaw(formObj.value);
// 过滤掉值为空的属性;
Object.keys(params).forEach(key => {
if (!params[key]) {
delete params[key];
}
});
const res = await getDeviceList({
...params,
pageNum: pagination.currentPage,
pageSize: pagination.pageSize
});
if (res.code === "0") {
// 给数据添加一个isExpend属性,默认值是false,点击展开按钮的时候,将isExpend属性设置为true,再次点击的时候,将isExpend属性设置为false
res.data.records.forEach((item: any) => {
item.isExpend = false;
});
listData.value = res.data.records;
loading.value = false;
} else {
ElMessage.error(`获取设备列表失败: ${res.msg}`);
}
};
/** 清空日志 */
function clearAll() {
// 根据实际业务,调用接口删除所有日志数据
......@@ -139,32 +247,37 @@ export function useRole(tableRef: Ref) {
async function onSearch() {
loading.value = true;
const { data } = await getLoginLogsList(toRaw(form));
dataList.value = data.list;
pagination.total = data.total;
pagination.pageSize = data.pageSize;
pagination.currentPage = data.currentPage;
setTimeout(() => {
loading.value = false;
}, 500);
getList();
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
const resetForm = () => {
// if (!formEl) return;
// formEl.resetFields();
// 重置表单后,清空所有搜索条件
Object.keys(formObj.value).forEach(key => {
formObj.value[key] = ""; // 清空所有搜索条件
});
// 重新获取列表数据
pagination.currentPage = 1; // 重置当前页为1
pagination.pageSize = 10; // 重置每页条数为10
// 调用搜索函数
onSearch();
};
onMounted(() => {
// onSearch();
onSearch();
getDeviceType();
getDeviceModelType();
getManufacturerList();
getDeviceSiteList();
getDeviceLevelList;
});
return {
form,
formObj,
loading,
columns,
dataList,
listData,
pagination,
selectedNum,
onSearch,
......@@ -174,6 +287,12 @@ export function useRole(tableRef: Ref) {
handleSizeChange,
onSelectionCancel,
handleCurrentChange,
handleSelectionChange
handleSelectionChange,
getList,
deviceTypeOptions,
deviceLevelOptions,
deviceSiteOptions,
deviceManufacturerOptions,
deviceModelOptions
};
}
......@@ -236,7 +236,7 @@ export function useFacList() {
// 跳转到导入页面
const goImport = () => {
router.push("/import-templete");
router.push({ path: "/import-templete", query: { type: "manufacturer" } });
};
// 导出全部列表数据
......
<template>
<div class="open-layers">
<h2>OpenLayers</h2>
<slot />
</div>
</template>
<script setup lang="ts">
// 组件逻辑部分
import { ref } from "vue";
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
<style scoped lang="scss">
.open-layers {
padding: 20px;
border: 1px solid #ccc;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论