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

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

上级 fb72c276
...@@ -45,30 +45,30 @@ module.exports = function (plop) { ...@@ -45,30 +45,30 @@ module.exports = function (plop) {
// message: "是否生成页面的components文件夹", // message: "是否生成页面的components文件夹",
// default: false // default: false
// }, // },
// { {
// type: "confirm", type: "confirm",
// name: "hasRoute", name: "hasRoute",
// message: "是否生成路由配置?", message: "是否生成路由配置?",
// default: true default: true
// }, },
// { // {
// type: "confirm", // type: "confirm",
// name: "hasAsyncRoute", // name: "hasAsyncRoute",
// message: "是否生成动态路由配置?", // message: "是否生成动态路由配置?",
// default: true // default: true
// }, // },
// { {
// type: "input", type: "input",
// name: "title", name: "title",
// message: "请输入路由title名称:", message: "请输入路由title名称:",
// when: answers => answers.hasAsyncRoute && answers.hasRoute, when: answers => answers.hasAsyncRoute && answers.hasRoute,
// validate: title => { validate: title => {
// if (!title) { if (!title) {
// return "路由title名称不能为空"; return "路由title名称不能为空";
// } }
// return true; return true;
// } }
// }, },
{ {
type: "confirm", type: "confirm",
name: "hasApi", name: "hasApi",
......
import { http } from "@/utils/http"; import { http } from "@/utils/http";
// interface DeviceInfo {
// deviceName: string;
// // ... 其他属性
// }
type ResultData = {
fileId?: string;
records?: Array<any>;
[key: string]: any;
// data?: DeviceInfo;
};
type Result = { type Result = {
success: boolean; success?: boolean;
data?: { data: Array<ResultData>;
/** 列表数据 */ msg: string;
list?: Array<any>; code: string;
[key: string]: any; 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) => { ...@@ -16,26 +37,89 @@ export const addDevice = (data?: object) => {
/** 获取设备列表 */ /** 获取设备列表 */
export const getDeviceList = (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) => { export const getDeviceTreeList = (data?: object) => {
return http.request<Result>("post", "/device/api/device/set-black-list", { return http.request<RcordsResult>("post", "/device/api/device/list_tree", {
data 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) => { export const updateDevice = (data?: object) => {
return http.request<Result>("post", "/device/api/device/update", { data }); return http.request<Result>("post", "/device/api/device/update", { data });
}; };
/** 获取设备详情 */ /** 获取设备详情 */
export const getDeviceInfo = (data?: object) => { 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) => { 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 data
}); });
}; };
...@@ -22,6 +22,14 @@ type Result = { ...@@ -22,6 +22,14 @@ type Result = {
requestId?: string; requestId?: string;
}; };
type ResultNoPage = {
success?: boolean;
data: Array<ResultData>;
msg: string;
code: string;
requestId?: string;
};
/** 添加厂商 */ /** 添加厂商 */
export const addManufacturer = (data?: object) => { export const addManufacturer = (data?: object) => {
return http.request<Result>("post", "/device/api/manufacturer/add", { return http.request<Result>("post", "/device/api/manufacturer/add", {
...@@ -47,6 +55,16 @@ export const getManufacturerList = (data?: object) => { ...@@ -47,6 +55,16 @@ export const getManufacturerList = (data?: object) => {
data data
}); });
}; };
// 获取厂商列表不分页
export const getManufacturerListNoPage = (data?: object) => {
return http.request<ResultNoPage>(
"post",
"/device/api/manufacturer/find_manufacturer_list",
{
data
}
);
};
/** 获取厂商详情 */ /** 获取厂商详情 */
export const getManufacturerInfo = (data?: object) => { 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) => { ...@@ -18,7 +18,13 @@ export const getCaptcha = (time?: string) => {
/** 刷新`token` */ /** 刷新`token` */
export const refreshTokenApi = (data?: object) => { 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"> <script setup lang="ts">
import router from "@/router";
defineOptions({ defineOptions({
name: "" name: ""
}); });
import type { UploadProps, UploadRequestOptions } from "element-plus"; import type { UploadProps, UploadRequestOptions } from "element-plus";
import { import {
downLoadTemplate, downLoadTemplate,
importManufacturer, importManufacturer
uploadTemplate // uploadTemplate
} from "@/api/manufacturer"; } from "@/api/manufacturer";
import { importDevice } from "@/api/device";
import { downloadFile } from "@/utils/utils"; import { downloadFile } from "@/utils/utils";
const formData = new FormData(); 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"] = ( const handleAvatarSuccess: UploadProps["onSuccess"] = (
response, response,
uploadFile uploadFile
) => { ) => {};
// // 打印上传文件
// console.log("uploadFile", uploadFile);
// // 设置图片地址为上传文件的地址
// imageUrl.value = URL.createObjectURL(uploadFile.raw!);
// // 打印图片地址
// console.log("imageUrl.value", imageUrl.value);
};
// 定义一个函数,用于处理头像上传前 // 定义一个函数,用于处理头像上传前
const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => { const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => {
...@@ -59,7 +67,10 @@ const uploadFile = async (options: UploadRequestOptions) => { ...@@ -59,7 +67,10 @@ const uploadFile = async (options: UploadRequestOptions) => {
const confirm = () => { const confirm = () => {
// 调用接口,上传文件 // 调用接口,上传文件
// uploadTemplate(formData).then(res => { // 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") { if (res.code === "0" || res.code === "A0230") {
ElMessage.success("模版导入成功"); ElMessage.success("模版导入成功");
...@@ -68,12 +79,23 @@ const confirm = () => { ...@@ -68,12 +79,23 @@ const confirm = () => {
ElMessage.error("模版导入失败"); ElMessage.error("模版导入失败");
} }
}); });
// importManufacturer(formData).then(res => {
// // 如果上传成功,则返回文件地址
// if (res.code === "0" || res.code === "A0230") {
// ElMessage.success("模版导入成功");
// } else {
// // 如果上传失败,则返回空字符串
// ElMessage.error("模版导入失败");
// }
// });
}; };
const dwTemplate = async () => { const dwTemplate = async () => {
const type = JSON.parse(JSON.stringify(router.currentRoute.value.query.type));
// 调用下载模版接口 // 调用下载模版接口
const res = await downLoadTemplate({ templateName: "厂商模版" }); const res = await downLoadTemplate({ templateName: templateName[type] });
downloadFile(res, "厂商模版"); downloadFile(res, templateName[type]);
}; };
</script> </script>
......
...@@ -198,6 +198,7 @@ const transitionMain = defineComponent({ ...@@ -198,6 +198,7 @@ const transitionMain = defineComponent({
.app-main { .app-main {
position: relative; position: relative;
width: 100%; width: 100%;
min-width: 1200px;
height: 100vh; height: 100vh;
overflow-x: hidden; overflow-x: hidden;
} }
......
...@@ -25,6 +25,16 @@ export default { ...@@ -25,6 +25,16 @@ export default {
title: "无人机设备" title: "无人机设备"
// showParent: true // 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 { 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"> <script setup lang="ts">
import { reactive } from "vue"; import { reactive } from "vue";
import { useListHook } from "../utils/listHook"; import { useListHook } from "../utils/listHook";
import childrenListTable from "./childrenListTable.vue";
const { lookDetail } = useListHook(); const { lookDetail, listData, toggleExpand, handleEdit, deleteDevice } =
useListHook();
const labels = reactive([ const labels = reactive([
{ {
label: "已连接", label: "已连接",
...@@ -19,23 +21,28 @@ const labels = reactive([ ...@@ -19,23 +21,28 @@ const labels = reactive([
]); ]);
const deviceList = reactive([ const deviceList = reactive([
{ {
name: "设备名称", name: "设备编号",
prop: "deviceCode",
value: "ZR103432434" value: "ZR103432434"
}, },
{ {
name: "设备类型", name: "设备类型",
prop: "deviceType",
value: "气体检测仪" value: "气体检测仪"
}, },
{ {
name: "设备型号", name: "设备型号",
prop: "deviceModel",
value: "ZR-351" value: "ZR-351"
}, },
{ {
name: "所属站点", name: "所属站点",
prop: "deviceSide",
value: "xxx街道南路01号" value: "xxx街道南路01号"
}, },
{ {
name: "设备部署位置", name: "设备部署位置",
prop: "deviceAddress",
value: "准格尔旗薛家湾" value: "准格尔旗薛家湾"
} }
]); ]);
...@@ -44,8 +51,8 @@ const deviceList = reactive([ ...@@ -44,8 +51,8 @@ const deviceList = reactive([
<template> <template>
<div> <div>
<el-row <el-row
v-for="(i, index) in 5" v-for="(device, index) in listData"
:key="i" :key="device.deviceCode"
class="bg-gray-100 py-5 px-10 mb-8" class="bg-gray-100 py-5 px-10 mb-8"
> >
<el-col :span="3" :gutter="10"> <el-col :span="3" :gutter="10">
...@@ -56,12 +63,9 @@ const deviceList = reactive([ ...@@ -56,12 +63,9 @@ const deviceList = reactive([
width="100" width="100"
/></el-col> /></el-col>
<el-col :span="21" class="cursor-pointer"> <el-col :span="21" class="cursor-pointer">
<div <div class="flex justify-between items-center">
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> <div>
<span <span
v-for="i in labels" v-for="i in labels"
...@@ -71,22 +75,39 @@ const deviceList = reactive([ ...@@ -71,22 +75,39 @@ const deviceList = reactive([
> >
</div> </div>
</div> </div>
<el-button type="text" @click="lookDetail(i, index)" <div>
>查看详情</el-button <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>
<div class="flex justify-between items-center mt-5"> <div class="flex justify-between items-center mt-5">
<p v-for="(i, index) in deviceList" :key="index"> <p v-for="(i, index) in deviceList" :key="index">
<label>{{ i.name }}</label> <label class="mr-3">{{ i.name }}</label>
<span>{{ i.value }}</span> <span>{{ device[i.prop] }}</span>
</p> </p>
</div> </div>
<IconifyIconOnline class="m-auto mt-3" icon="cuida:caret-up-outline" /> <IconifyIconOnline
<!-- <IconifyIconOnline v-if="device.children?.length"
class="m-auto mt-2" class="m-auto mt-5"
icon="cuida:caret-down-outline" :icon="
/> --> !device.isExpend ? 'tabler:chevrons-up' : 'tabler:chevrons-down'
"
@click="toggleExpand(index)"
/>
</el-col> </el-col>
<childrenListTable
v-if="device.isExpend"
:childrenList="device.children"
/>
</el-row> </el-row>
</div> </div>
</template> </template>
......
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive } from "vue"; 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> </script>
<template> <template>
...@@ -12,8 +60,51 @@ const radio = ref("今天"); ...@@ -12,8 +60,51 @@ const radio = ref("今天");
<el-radio-button label="自定义">自定义</el-radio-button> <el-radio-button label="自定义">自定义</el-radio-button>
</el-radio-group> </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> </div>
</template> </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({ ...@@ -3,80 +3,21 @@ defineOptions({
name: "DeviceDetail" name: "DeviceDetail"
}); });
import { reactive } from "vue"; import { reactive } from "vue";
import { useListHook } from "./utils/listHook"; import { useDetailHook } from "./utils/detailHook";
import type { TabsPaneContext } from "element-plus"; import type { TabsPaneContext } from "element-plus";
import deviceAnalysis from "./components/deviceAnalysis.vue"; import deviceAnalysis from "./components/deviceAnalysis.vue";
import dataChart from "./components/dataChart.vue"; import dataChart from "./components/dataChart.vue";
import dataLog from "./components/dataLog.vue"; import dataLog from "./components/dataLog.vue";
import operationRecord from "./components/operationRecord.vue"; import operationRecord from "./components/operationRecord.vue";
const { lookDetail, alarmSetting } = useListHook();
const labels = reactive([ const { deviceInfo, labels, deviceList, Factor } = useDetailHook();
{
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"
}
]);
// { // {
// name: "出厂日期", // name: "出厂日期",
// value: "ZR-351" // value: "ZR-351"
// } // }
const info = reactive([
{ const activeName = ref("4");
name: "臭氧浓度(mg/m³)",
value: "0.0172"
},
{
name: "温度(°C)",
value: "30.0"
},
{
name: "大气压(kPa)",
value: "103.54"
}
]);
const activeName = ref("1");
const handleClick = (tab: TabsPaneContext, event: Event) => { const handleClick = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event); console.log(tab, event);
...@@ -90,9 +31,9 @@ const handleClick = (tab: TabsPaneContext, event: Event) => { ...@@ -90,9 +31,9 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
<!-- 设备信息模块 --> <!-- 设备信息模块 -->
<div class="flex items-center mb-10"> <div class="flex items-center mb-10">
<!-- 设备基本信息 --> <!-- 设备基本信息 -->
<div> <div class="flex-1">
<div class="flex items-center"> <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"> <span class="text-sm flex items-center mr-5">
<i <i
class="block w-3.5 h-3.5 bg-sky-600 rounded-lg mr-1 cursor-pointer" 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) => { ...@@ -111,14 +52,14 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
class="felx mb-4! basis-1/4" class="felx mb-4! basis-1/4"
> >
<label>{{ i.name }}</label> <label>{{ i.name }}</label>
<span>{{ i.value }}</span> <span>{{ deviceInfo[i.prop] }}</span>
</p> </p>
</div> </div>
<div <div
class="flex items-center justify-between bg-gray-100 px-12 py-8 mt-10" class="flex items-center justify-between bg-gray-100 px-12 py-8 mt-10"
> >
<p <p
v-for="i in info" v-for="i in Factor"
:key="i.name" :key="i.name"
class="flex flex-col items-center" class="flex flex-col items-center"
> >
......
<script setup lang="ts"> <script setup lang="ts">
import listTable from "./components/listTable.vue"; import listTable from "./components/listTable.vue";
import { useListHook } from "./utils/listHook";
const { addDevice, importDeviceTemplate } = useListHook();
</script> </script>
<template> <template>
<div class="device-list"> <div class="device-list">
<div class="btn mb-5"> <div class="btn mb-5">
<el-button>新建</el-button> <el-button @click="addDevice">新建</el-button>
<el-button>编辑</el-button> <!-- <el-button>编辑</el-button>
<el-button>删除</el-button> <el-button>删除</el-button> -->
<el-button>导入</el-button> <el-button @click="importDeviceTemplate">导入</el-button>
<el-button>报修</el-button> <el-button>报修</el-button>
</div> </div>
<listTable /> <listTable />
......
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 router from "@/router";
import { message } from "@/utils/message"; import { ref, onMounted } from "vue";
import { reactive, ref, onMounted, toRaw } from "vue";
import {
addDialog
// closeDialog,
// updateDialog,
// closeAllDialog
} from "@/components/ReDialog";
import forms, { type FormProps } from "../components/alarmForm.vue"; import { getDeviceTreeList, setBlackList } from "@/api/device";
export function useListHook() { export function useListHook() {
const form = reactive({ const listData = ref([]);
name: "", // 根据索引判断跳转到不同的设备详情页面
sssb: "", const lookDetail = deviceCode => {
sbmc2: "", router.push({
sbbh: "", path: "/device/detail",
sblx: "", query: { deviceCode }
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" }]
}; };
// 定义一个handleReset函数,用于重置表单 // 点击编辑按钮,跳转到编辑页面
const handleReset = () => { const handleEdit = deviceCode => {
// 遍历form对象的所有键 router.push({ path: `/device/edit`, query: { deviceCode } });
Object.keys(form).forEach(key => {
// 将form对象中对应键的值设置为空字符串
form[key] = "";
});
}; };
// 提交表单 // 点击新建按钮,跳转到新建页面
const handleSubmit = async () => { const addDevice = () => {
// 将表单数据转换为原始数据 router.push({ path: "/device/add" });
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 lookDetail = (row: any, index: number) => { const getList = async () => {
// 如果索引大于0,则跳转到设备详情2页面 // 调用getDeviceList函数,获取设备列表
index > 0 const res = await getDeviceTreeList({ pageNum: 1, pageSize: 10 });
? router.push({ path: "/device/detail2" }) // 给数据添加一个isExpend属性,默认值是false,点击展开按钮的时候,将isExpend属性设置为true,再次点击的时候,将isExpend属性设置为false
: // 否则跳转到设备详情页面 res.data.records.forEach((item: any) => {
router.push({ path: "/device/detail" }); item.isExpend = false;
});
listData.value = res.data.records;
}; };
const alarmSetting = () => { // 删除设备
addDialog({ const deleteDevice = async deviceCode => {
width: "35%", // 删除之前,先弹出一个确认框,确认是否删除
title: "阈值设置", ElMessageBox.confirm("确认删除该设备吗?", "提示", {
contentRenderer: () => forms, confirmButtonText: "确定",
props: { cancelButtonText: "取消",
// 赋默认值 type: "warning"
formInline: { }).then(async () => {
user: "菜虚鲲", // 确认删除之后,调用deleteDevice函数,删除设备
region: "浙江" // await deleteDevice(deviceCode);
} // 调用setBlackList函数,删除设备
}, const res = await setBlackList({ deviceCode });
closeCallBack: ({ options, args }) => { // 判断接口返回的code是否为200
// options.props 是响应式的 if (res.code === "0") {
const { formInline } = options.props as FormProps; // 如果是200,则显示删除成功
const text = `姓名:${formInline.user} 城市:${formInline.region}`; ElMessage.success("删除成功");
if (args?.command === "cancel") { getList();
// 您点击了取消按钮
message(`您点击了取消按钮,当前表单数据为 ${text}`);
} else if (args?.command === "sure") {
message(`您点击了确定按钮,当前表单数据为 ${text}`);
} else {
message(
`您点击了右上角关闭按钮或空白页或按下了esc键,当前表单数据为 ${text}`
);
}
} }
}); });
}; };
// 导入设备模版
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(() => { onMounted(() => {
getList();
// 获取设备类型 // 获取设备类型
// 获取设备型号 // 获取设备型号
// 获取设备厂商 // 获取设备厂商
// 获取设备状态 // 获取设备状态
}); });
return { return {
form,
handleReset,
handleSubmit,
rules,
formRef,
validateForm,
lookDetail, lookDetail,
alarmSetting getList,
listData,
toggleExpand,
addDevice,
handleEdit,
deleteDevice,
importDeviceTemplate
}; };
} }
import dayjs from "dayjs"; // import dayjs from "dayjs";
import { message } from "@/utils/message"; import { message } from "@/utils/message";
import { getKeyList } from "@pureadmin/utils"; import { getKeyList } from "@pureadmin/utils";
import { getLoginLogsList } from "@/api/system";
// import { usePublicHooks } from "@/views/system/hooks"; // import { usePublicHooks } from "@/views/system/hooks";
import type { PaginationProps } from "@pureadmin/table"; 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) { export function useRole(tableRef: Ref) {
const form = reactive({ const formObj = ref({
username: "", deviceLevel: null, //设备层级
status: "", parentCode: "", //上级设备编码
loginTime: "" 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 loading = ref(false);
const selectedNum = ref(0); const selectedNum = ref(0);
// const { tagStyle } = usePublicHooks(); // const { tagStyle } = usePublicHooks();
const deviceTypeOptions = ref({}); //设备类型数据列表
const deviceLevelOptions = ref([]); //所属设备数据列表
const deviceSiteOptions = ref([]); //设备站点列表数据
const deviceManufacturerOptions = ref([]); //设备厂商列表数据
const deviceModelOptions = ref({}); //设备型号列表数据
const pagination = reactive<PaginationProps>({ const pagination = reactive<PaginationProps>({
total: 0, total: 0,
pageSize: 10, pageSize: 10,
...@@ -37,76 +61,84 @@ export function useRole(tableRef: Ref) { ...@@ -37,76 +61,84 @@ export function useRole(tableRef: Ref) {
}, },
{ {
label: "设备分类", label: "设备分类",
prop: "username", prop: "deviceLevel",
minWidth: 100 minWidth: 100
}, },
{ {
label: "所属设备", label: "所属设备",
prop: "ip", prop: "parentCode",
minWidth: 140 minWidth: 140
}, },
{ {
label: "设备名称", label: "设备名称",
prop: "address", prop: "deviceName",
minWidth: 140 minWidth: 140
}, },
{ {
label: "设备类型", label: "设备类型",
prop: "system", prop: "deviceType",
minWidth: 100 minWidth: 100
}, },
{ {
label: "设备型号", label: "设备型号",
prop: "browser", prop: "deviceModel",
minWidth: 100 minWidth: 100
}, },
{ {
label: "所属站点", label: "所属站点",
prop: "behavior", prop: "deviceSide",
minWidth: 100 minWidth: 100
}, },
{ {
label: "设备联系人", label: "设备联系人",
prop: "behavior", prop: "devicePhone",
minWidth: 100 minWidth: 100
}, },
{ {
label: "部署位置", label: "部署位置",
prop: "behavior", prop: "deviceAddress",
minWidth: 100 minWidth: 100
}, },
{ {
label: "设备出厂日期", label: "设备出厂日期",
prop: "loginTime", prop: "factoryTime",
minWidth: 180, minWidth: 180
formatter: ({ loginTime }) => // formatter: ({ loginTime }) =>
dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss") // dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss")
}, },
{ {
label: "设备厂商", label: "设备厂商",
prop: "behavior", prop: "manufacturerId",
minWidth: 100 minWidth: 100
}, },
{ {
label: "年检提醒", label: "年检提醒",
prop: "behavior", prop: "inspectTime",
minWidth: 100 minWidth: 100
} }
]; ];
function handleSizeChange(val: number) { function handleSizeChange(val: number) {
console.log(`${val} items per page`); console.log(`${val} items per page`);
pagination.pageSize = val;
// 重置表格高度
tableRef.value.setAdaptive();
// 重新获取列表数据
onSearch();
} }
function handleCurrentChange(val: number) { function handleCurrentChange(val: number) {
console.log(`current page: ${val}`); console.log(`current page: ${val}`);
pagination.currentPage = val;
// 重置表格高度
tableRef.value.setAdaptive();
// 重新获取列表数据
onSearch();
} }
/** 当CheckBox选择项发生变化时会触发该事件 */ /** 当CheckBox选择项发生变化时会触发该事件 */
function handleSelectionChange(val) { function handleSelectionChange(val) {
selectedNum.value = val.length; selectedNum.value = val.length;
// 重置表格高度
tableRef.value.setAdaptive();
} }
/** 取消选择 */ /** 取消选择 */
...@@ -128,6 +160,82 @@ export function useRole(tableRef: Ref) { ...@@ -128,6 +160,82 @@ export function useRole(tableRef: Ref) {
onSearch(); 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() { function clearAll() {
// 根据实际业务,调用接口删除所有日志数据 // 根据实际业务,调用接口删除所有日志数据
...@@ -139,32 +247,37 @@ export function useRole(tableRef: Ref) { ...@@ -139,32 +247,37 @@ export function useRole(tableRef: Ref) {
async function onSearch() { async function onSearch() {
loading.value = true; loading.value = true;
const { data } = await getLoginLogsList(toRaw(form)); getList();
dataList.value = data.list;
pagination.total = data.total;
pagination.pageSize = data.pageSize;
pagination.currentPage = data.currentPage;
setTimeout(() => {
loading.value = false;
}, 500);
} }
const resetForm = formEl => { const resetForm = () => {
if (!formEl) return; // if (!formEl) return;
formEl.resetFields(); // formEl.resetFields();
// 重置表单后,清空所有搜索条件
Object.keys(formObj.value).forEach(key => {
formObj.value[key] = ""; // 清空所有搜索条件
});
// 重新获取列表数据
pagination.currentPage = 1; // 重置当前页为1
pagination.pageSize = 10; // 重置每页条数为10
// 调用搜索函数
onSearch(); onSearch();
}; };
onMounted(() => { onMounted(() => {
// onSearch(); onSearch();
getDeviceType();
getDeviceModelType();
getManufacturerList();
getDeviceSiteList();
getDeviceLevelList;
}); });
return { return {
form, formObj,
loading, loading,
columns, columns,
dataList, listData,
pagination, pagination,
selectedNum, selectedNum,
onSearch, onSearch,
...@@ -174,6 +287,12 @@ export function useRole(tableRef: Ref) { ...@@ -174,6 +287,12 @@ export function useRole(tableRef: Ref) {
handleSizeChange, handleSizeChange,
onSelectionCancel, onSelectionCancel,
handleCurrentChange, handleCurrentChange,
handleSelectionChange handleSelectionChange,
getList,
deviceTypeOptions,
deviceLevelOptions,
deviceSiteOptions,
deviceManufacturerOptions,
deviceModelOptions
}; };
} }
...@@ -236,7 +236,7 @@ export function useFacList() { ...@@ -236,7 +236,7 @@ export function useFacList() {
// 跳转到导入页面 // 跳转到导入页面
const goImport = () => { 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论