提交 7573ae84 authored 作者: hejie's avatar hejie

chore: 🔨 合并代码

......@@ -340,9 +340,6 @@ declare module "vue" {
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<(typeof import("vue"))["EffectScope"]>;
readonly ElMessageBox: UnwrapRef<
(typeof import("element-plus/es"))["ElMessageBox"]
>;
readonly acceptHMRUpdate: UnwrapRef<
(typeof import("pinia"))["acceptHMRUpdate"]
>;
......
......@@ -85,6 +85,7 @@
"mitt": "^3.0.1",
"mqtt": "4.3.7",
"nprogress": "^0.2.0",
"ol": "^10.5.0",
"path-browserify": "^1.0.1",
"pinia": "^3.0.1",
"pinyin-pro": "^3.26.0",
......
差异被折叠。
......@@ -4,26 +4,29 @@ import { http } from "@/utils/http";
// deviceName: string;
// // ... 其他属性
// }
type RecordItem = {
[key: string]: any;
};
type ResultData = {
fileId?: string;
records?: Array<any>;
records?: Array<RecordItem>;
[key: string]: any;
// data?: DeviceInfo;
};
type Result = {
type RcordsResult = {
success?: boolean;
data: Array<ResultData>;
data: ResultData;
msg: string;
code: string;
requestId?: string;
id?: number;
status?: number;
};
type RcordsResult = {
type Result = {
success?: boolean;
data: ResultData;
data: any;
msg: string;
code: string;
requestId?: string;
......@@ -123,3 +126,75 @@ export const getOperationRecords = (data?: object) => {
data
});
};
// 获取设备分析接口
export const getDeviceAnalysis = (data?: object) => {
return http.request<RcordsResult>(
"post",
"/device/api/dev_device_status/list",
{
data
}
);
};
// 获取最新一条数据日志(监测因子)
export const getDataLogListLatest = (data?: object) => {
return http.request<RecordItem>(
"post",
"/device/api/device/get_device_data_latest",
{
data
}
);
};
// 获取数据日志列表(监测因子)
export const getDataLogList = (data?: object) => {
return http.request<RcordsResult>(
"post",
"/device/api/device/get_device_data_page",
{
data
}
);
};
// 获取数据图表数据
export const getDataChart = (data?: object) => {
return http.request<RcordsResult>(
"post",
"/device/api/device/get_device_data_chart",
{
data
}
);
};
// 获取设备类型数据
export const getDeviceTypeByType = (data?: object) => {
return http.request<RcordsResult>(
"post",
"/device/api/dev_base_data/get_data_by_type",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
// 根据设备类型获取设备型号
export const getDeviceModel = (data?: object) => {
return http.request<RcordsResult>(
"post",
"/device/api/dev_base_data/get_data_by_parent",
{
data
},
{
headers: {
"Content-Type": "multipart/form-data"
}
}
);
};
......@@ -7,9 +7,9 @@ export default {
},
children: [
{
path: "/device/detail2",
name: "DeviceDetail2",
component: () => import("@/views/device/detail2.vue"),
path: "/device/childrenList",
name: "ChildrenList",
component: () => import("@/views/device/childrenList.vue"),
meta: {
showLink: false,
title: "无人机设备22"
......
......@@ -14,6 +14,22 @@ import NProgress from "../progress";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
import packageJson from "../../../package.json";
// import { debounce, throttle } from "@pureadmin/utils";
/** 节流配置:单位毫秒,key为接口路径 */
const throttleMap = new Map<string, number>();
/** 节流间隔(可根据需要调整) */
const THROTTLE_INTERVAL = 1000;
/** 生成接口唯一标识(可根据实际需求调整) */
function getThrottleKey(config: PureHttpRequestConfig): string {
const url = config.url || "";
const method = config.method || "get";
// 如果需要更细粒度,可以加上参数
const params = config.params ? JSON.stringify(config.params) : "";
const data = config.data ? JSON.stringify(config.data) : "";
return `${method}:${url}?${params}&${data}`;
}
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
......@@ -65,8 +81,23 @@ class PureHttp {
/** 请求拦截 */
private httpInterceptorsRequest(): void {
// 请求接口时添加节流操作
PureHttp.axiosInstance.interceptors.request.use(
async (config: PureHttpRequestConfig): Promise<any> => {
// ====== 节流处理开始 ======
const throttleKey = getThrottleKey(config);
const now = Date.now();
if (throttleMap.has(throttleKey)) {
const lastTime = throttleMap.get(throttleKey)!;
if (now - lastTime < THROTTLE_INTERVAL) {
// 关闭进度条动画
NProgress.done();
// 拒绝本次请求
return Promise.reject({ isCancelRequest: true });
}
}
throttleMap.set(throttleKey, now);
// ====== 节流处理结束 ======
// 开启进度条动画
NProgress.start();
// 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
......
import dayjs from "dayjs";
// 定义一个方法,处理后端返回的二进制流,斌下载文件
export function downloadFile(response: any, fileName: string) {
console.log("content-type", response);
......@@ -15,3 +16,40 @@ export function downloadFile(response: any, fileName: string) {
document.body.appendChild(a);
a.click();
}
/**
*使用dayjs库来处理日期,返回当天的起止日期,格式为YYYY-MM-DD HH:mm:ss
* type: "today" | "yesterday" | "lastWeek" | "lastThreeDays"
* */
export function getStartEndByType(type?: string) {
const start = dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"); //获取当天的开始时间
const end = dayjs().endOf("day").format("YYYY-MM-DD HH:mm:ss"); //获取当天结束时间
//获取前一天的开始时间
const yesterdayStart = dayjs()
.subtract(1, "day")
.startOf("day")
.format("YYYY-MM-DD HH:mm:ss");
// 获取前三天的开始时间
const lastThreeDaysStart = dayjs()
.subtract(3, "day")
.startOf("day")
.format("YYYY-MM-DD HH:mm:ss");
// 获取一周的开始时间
const lastWeekStart = dayjs()
.subtract(7, "day")
.startOf("day")
.format("YYYY-MM-DD HH:mm:ss");
// 根据type返回不同的时间范围
switch (type) {
case "today":
return [start, end];
case "yesterday":
return [yesterdayStart, end];
case "lastWeek":
return [lastWeekStart, end];
case "lastThreeDays":
return [lastThreeDaysStart, end];
default:
return [start, end];
}
}
......@@ -11,7 +11,6 @@ const {
handleReset,
handleSubmit,
rules,
validateForm,
deviceTypeOptions,
deviceLevelOptions,
changeLevel,
......@@ -20,7 +19,9 @@ const {
uploadFile,
// handleAvatarSuccess,
beforeAvatarUpload,
deviceModelOptions
deviceModelOptions,
handleEditImage,
changeDeviceType
} = useAddHook(formRef);
defineComponent({
......@@ -90,7 +91,7 @@ defineComponent({
</el-row>
<el-row :gutter="50" class="my-5">
<el-col :span="8">
<el-form-item label="设备编号" prop="deviceCode">
<el-form-item label="设备编号">
<el-input
v-model="formObj.deviceCode"
placeholder="请输入设备编号"
......@@ -103,6 +104,7 @@ defineComponent({
<el-select
v-model="formObj.deviceType"
placeholder="请选择设备类型"
@change="changeDeviceType(formObj.deviceType)"
>
<el-option
v-for="item in Object.keys(deviceTypeOptions)"
......@@ -118,6 +120,7 @@ defineComponent({
<el-select
v-model="formObj.deviceModel"
placeholder="请选择设备型号"
:disabled="formObj.deviceType === ''"
>
<el-option
v-for="item in Object.keys(deviceModelOptions)"
......@@ -176,7 +179,7 @@ defineComponent({
<el-date-picker
v-model="formObj.factoryTime"
type="date"
format="YYYY/MM/DD"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择设备出厂日期"
/>
......@@ -204,7 +207,7 @@ defineComponent({
<el-date-picker
v-model="formObj.inspectTime"
type="date"
format="YYYY/MM/DD"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择年检提醒"
/>
......@@ -222,13 +225,9 @@ defineComponent({
</el-row>
</el-col>
<el-col :span="4" class="my-5 flex justify-center items-center">
<el-form-item
label="设备图片"
prop="fileList"
label-position="top"
:rules="[{ required: true, message: '附件不能为空' }]"
>
<el-form-item label="设备图片" prop="fileUrl" label-position="top">
<el-upload
v-if="!formObj.fileUrl"
ref="uploadRef"
drag
multiple
......@@ -236,14 +235,6 @@ defineComponent({
:before-upload="beforeAvatarUpload"
class="w-[200px]!"
>
<!-- <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"
......@@ -254,6 +245,15 @@ defineComponent({
<em> 可点击或拖拽上传 </em>
</div>
</el-upload>
<img v-else :src="formObj.fileUrl" alt="" srcset="" />
<!-- 编辑图片按钮 -->
<el-button
type="primary"
size="small"
class="mt-2!"
@click="handleEditImage"
>{{ formObj.fileUrl ? "编辑" : "还原" }}</el-button
>
</el-form-item>
</el-col>
</el-row>
......
<!-- 点击设备列表详情时,拥有子设备的时候静茹到此页面 -->
<script setup lang="ts">
defineOptions({
name: "DeviceDetail2"
......
<script setup lang="ts">
import { reactive } from "vue";
import { useListHook } from "../utils/listHook";
const { lookDetail, listData } = useListHook();
// 定义props,接收父组件传递过来的数据childrenList
interface Device {
deviceName: string;
......@@ -15,6 +12,8 @@ interface Device {
}
const props = defineProps<{
childrenList: Device[];
lookDetail: (device: Device) => void;
listData: Device[];
}>();
const labels = reactive([
{
......@@ -38,7 +37,7 @@ const deviceList = reactive([
},
{
name: "设备类型",
prop: "deviceType",
prop: "deviceTypeName",
value: ""
},
{
......@@ -48,7 +47,7 @@ const deviceList = reactive([
},
{
name: "所属站点",
prop: "deviceSide",
prop: "deviceSideName",
value: ""
},
{
......@@ -67,21 +66,17 @@ const deviceList = reactive([
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"
<img :src="device.fileUrl" alt="" srcset="" width="100"
/></el-col>
<el-col :span="21" class="cursor-pointer">
<div
class="flex justify-between items-center"
@click="lookDetail(device, index)"
@click="lookDetail(device)"
>
<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 type="text" @click="lookDetail(device)"
>查看详情</el-button
>
</div>
......
<script setup lang="ts">
import { ref, reactive } from "vue";
import * as echarts from "echarts";
import { onMounted } from "vue";
const radio = ref("今天");
// 定义一个折线图
const tempCharts = ref(null);
const humiCharts = ref(null);
const AtmosphericCharts = ref(null);
const tempData = reactive({
title: {
text: "温度",
left: "center"
},
tooltip: {
trigger: "axis"
},
legend: {
data: ["温度"],
left: "left"
},
xAxis: {
type: "category",
data: ["1月", "2月", "3月", "4月", "5月", "6月", "7月"]
},
yAxis: {
type: "value"
},
series: [
{
name: "温度",
type: "line",
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
]
});
import { getDataChart } from "@/api/device";
import LineChart from "./lineCharts.vue";
import timeControl from "./timeControl.vue";
import { getStartEndByType } from "@/utils/utils";
const dataChartList = ref([]); // 数据图表数据
// 获取数据图表数据
const getDataChartList = async (time?: Array<string>) => {
const res = await getDataChart({
// deviceCode: router.currentRoute.value.query?.deviceCode,
// deviceType: router.currentRoute.value.query?.deviceType || "NOISE",
deviceCode: "7012A11102298",
deviceType: "AIR_7012",
startTime: time ? time[0] : getStartEndByType()[0],
endTime: time ? time[1] : getStartEndByType()[1]
});
if (!res || !res.data) return;
dataChartList.value = (res.data as Array<any>) || [];
console.log(dataChartList.value);
};
onMounted(() => {
// 初始化echarts
tempCharts.value = echarts.init(document.getElementById("tempCharts"));
// 使用刚指定的配置项和数据显示图表。
tempCharts.value.setOption(tempData);
// 初始化湿度图表
humiCharts.value = echarts.init(document.getElementById("humiCharts"));
// 使用刚指定的配置项和数据显示图表。
humiCharts.value.setOption(tempData);
// 初始化大气压图表
AtmosphericCharts.value = echarts.init(
document.getElementById("AtmosphericCharts")
);
// 使用刚指定的配置项和数据显示图表。
AtmosphericCharts.value.setOption(tempData);
getDataChartList();
});
</script>
<template>
<div>
<!-- 单选(紧凑风格的按钮样式) -->
<el-radio-group v-model="radio">
<el-radio-button label="今天">今天</el-radio-button>
<el-radio-button label="3天">3天</el-radio-button>
<el-radio-button label="自定义">自定义</el-radio-button>
</el-radio-group>
<!-- 三个echats折线图,分别是温度、大气压、湿度 -->
<div class="flex justify-between w-full">
<div id="tempCharts" class="w-80 h-80" />
<div id="humiCharts" class="w-80 h-80" />
<div id="AtmosphericCharts" class="w-80 h-80" />
<time-control @changeBtn="getDataChartList" />
<div class="flex justify-start w-full flex-wrap">
<div v-for="item in dataChartList" :key="item.id" class="basis-1/3">
<LineChart
:chartId="item.targetCode"
:title="item.targetName"
:dataChartItem="item.datas"
/>
</div>
</div>
</div>
</template>
......
<script setup lang="ts">
import router from "@/router";
import { ref, reactive } from "vue";
const date = ref("");
const pickerOptions = {
shortcuts: [
{
text: "今天",
onClick(picker) {
picker.$emit("pick", new Date());
}
},
{
text: "昨天",
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
picker.$emit("pick", date);
}
},
{
text: "一周前",
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", date);
}
}
]
};
const tableData = reactive([
{
time: "2023-10-01 12:00:00",
airPressure: "1013 hPa",
temperature: "25 °C",
windSpeed: "5 m/s",
windDirection: "北",
rainfall: "0 mm",
L5: "10",
L10: "20",
L50: "30",
L90: "40",
L95: "50"
},
{
time: "2023-10-01 13:00:00",
airPressure: "1012 hPa",
temperature: "26 °C",
windSpeed: "6 m/s",
windDirection: "东北",
rainfall: "1 mm",
L5: "15",
L10: "25",
L50: "35",
L90: "45",
L95: "55"
import { getDataLogList } from "@/api/device";
import { getStartEndByType } from "@/utils/utils";
import type { PaginationProps } from "@pureadmin/table";
// 定义props,接收dataLogColumns
const props = defineProps({
dataLogColumns: {
type: Array,
default: () => []
}
]);
});
const dataLogList = ref([]); // 数据日志列表
// const dataLogDate = ref(getStartEndByType());
const dataLogDate = ref(["2020-10-01 00:00:00", "2025-10-01 23:59:59"]);
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
currentPage: 1,
background: true
});
// 获取数据日志列表数据
const getdeviceLogList = async () => {
const res = await getDataLogList({
deviceCode: router.currentRoute.value.query?.deviceCode,
deviceType: router.currentRoute.value.query?.deviceType || "NOISE",
startTime: dataLogDate.value ? dataLogDate.value[0] : null,
endTime: dataLogDate.value ? dataLogDate.value[1] : null,
pageNum: pagination.currentPage,
pageSize: pagination.pageSize
});
if (!res || !res.data) return;
pagination.total = res.data.total;
dataLogList.value = (res.data.records as Array<any>) || [];
};
// 处理分页大小改变
function handleSizeChange(val: number) {
// 更新分页大小
pagination.pageSize = val;
// 获取设备日志列表
getdeviceLogList();
}
// 处理当前页码变化
function handleCurrentChange(val: number) {
// 更新当前页码
pagination.currentPage = val;
// 获取设备日志列表
getdeviceLogList();
}
onMounted(() => {
getdeviceLogList();
});
</script>
<template>
<div>
<!-- 一个日期时间范围选择器 -->
<el-date-picker
v-model="date"
type="daterange"
v-model="dataLogDate"
type="datetimerange"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
class="mb-5"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
@change="getdeviceLogList"
/>
<pure-table
ref="tableRef"
border
alignWhole="center"
max-height="300"
height="300"
showOverflowTooltip
:data="dataLogList"
:pagination="{ ...pagination }"
:columns="dataLogColumns"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
/>
<!-- 一个表格,展示设备数据日志;表头分别是: 时间、大气压、温度、风速、风向、降雨量、L5、L10、L50、L90、L95 -->
<el-table :data="tableData">
<el-table-column prop="time" label="时间" />
<el-table-column prop="airPressure" label="大气压" />
<el-table-column prop="temperature" label="温度" />
<el-table-column prop="windSpeed" label="风速" />
<el-table-column prop="windDirection" label="风向" />
<el-table-column prop="rainfall" label="降雨量" />
<el-table-column prop="L5" label="L5" />
<el-table-column prop="L10" label="L10" />
<el-table-column prop="L50" label="L50" />
<el-table-column prop="L90" label="L90" />
<el-table-column prop="L95" label="L95" />
</el-table>
</div>
</template>
......
<script setup lang="ts">
import { ref, reactive } from "vue";
const radio = ref("今天");
import router from "@/router";
import { VxeTableBar } from "@/components/ReVxeTableBar";
import { getDeviceAnalysis } from "@/api/device";
import timeControl from "./timeControl.vue";
import { getStartEndByType } from "@/utils/utils";
const vxeTableRef = ref();
const deviceAnalysisList = ref([]); // 设备分析列表
const columns = [
{ field: "updateTime", title: "时间" },
{ field: "statusName", title: "设备状态" }
];
// 获取设别分析列表数据
const getDeviceAnalysisList = async (time?: Array<string>) => {
const res = await getDeviceAnalysis({
deviceCode: router.currentRoute.value.query?.deviceCode,
startTime: time ? time[0] : getStartEndByType()[0],
endTime: time ? time[1] : getStartEndByType()[1],
pageNum: 1,
pageSize: 10
});
if (!res || !res.data) return;
res.data.records.map(i => {
i.statusName = i.status === 1 ? "在线" : "离线";
});
deviceAnalysisList.value = (res.data.records as Array<any>) || [];
};
onMounted(() => {
getDeviceAnalysisList();
});
</script>
<template>
<div>
<!-- 单选(紧凑风格的按钮样式) -->
<el-radio-group v-model="radio">
<el-radio-button label="今天">今天</el-radio-button>
<el-radio-button label="3天">3天</el-radio-button>
<el-radio-button label="自定义">自定义</el-radio-button>
</el-radio-group>
<!-- 这一块时暂无数据 -->
<el-empty description="暂无数据" />
<time-control @changeBtn="getDeviceAnalysisList" />
<VxeTableBar :vxeTableRef="vxeTableRef" :columns="columns" title="设备分析">
<template v-slot="{ size, dynamicColumns }">
<vxe-grid
ref="vxeTableRef"
show-overflow
:size="size"
height="400"
:row-config="{ isHover: true }"
:scroll-y="{ enabled: true }"
:columns="dynamicColumns"
:data="deviceAnalysisList"
/>
</template>
</VxeTableBar>
</div>
</template>
......
<script setup lang="ts">
import * as echarts from "echarts";
defineOptions({
name: ""
});
const props = defineProps<{
chartId: string;
dataChartItem: Array<any>;
title: string;
// width: string;
// height: string;
}>();
// 定义一个折线图
const tempData = reactive({
tooltip: {
trigger: "axis"
// show: true
},
xAxis: {
type: "category",
data: []
},
yAxis: {
type: "value",
name: "",
axisLine: { show: true }, // 显示y轴轴线
// axisTick: { show: true }, // 显示y轴刻度
splitLine: { show: true } // 显示分割线
},
series: [
{
name: "温度",
type: "line",
data: [],
areaStyle: {
color: "rgba(0, 123, 255, 0.2)" // 蓝色填充,透明度可调
},
// lineStyle: {
// color: "#007bff"
// },
// itemStyle: {
// color: "#007bff"
// },
smooth: true, // 可选,平滑曲线
symbol: "none" // 不显示折线上的点
}
]
});
const tempCharts = ref(null);
onMounted(() => {
// 初始化echarts
tempCharts.value = echarts.init(document.getElementById(props.chartId));
// 使用刚指定的配置项和数据显示图表。
// tempCharts.value.setOption(tempData);
const newData = props.dataChartItem;
const xAxisData = newData.map(item => item.time);
const seriesData = newData.map(item => item.value);
// seriesData 添加10条假数据
if (!seriesData.length) {
for (let i = 0; i < 10; i++) {
seriesData.push(Math.random() * 100);
}
}
tempData.xAxis.data = xAxisData;
tempData.series[0].data = seriesData;
tempData.yAxis.name = props.title;
console.log("tempData", tempData);
// 使用刚指定的配置项和数据显示图表。
tempCharts.value.setOption(tempData);
});
</script>
<template>
<div class="lineCharts">
<div :id="chartId" class="w-60 h-80" />
</div>
</template>
<!-- <style lang="scss" scoped></style> -->
......@@ -23,27 +23,27 @@ const deviceList = reactive([
{
name: "设备编号",
prop: "deviceCode",
value: "ZR103432434"
value: ""
},
{
name: "设备类型",
prop: "deviceType",
value: "气体检测仪"
prop: "deviceTypeName",
value: ""
},
{
name: "设备型号",
prop: "deviceModel",
value: "ZR-351"
value: ""
},
{
name: "所属站点",
prop: "deviceSide",
value: "xxx街道南路01号"
prop: "deviceSideName",
value: ""
},
{
name: "设备部署位置",
prop: "deviceAddress",
value: "准格尔旗薛家湾"
value: ""
}
]);
</script>
......@@ -54,13 +54,13 @@ const deviceList = reactive([
v-for="(device, index) in listData"
:key="device.deviceCode"
class="bg-gray-100 py-5 px-10 mb-8"
@click="
device.children?.length ? toggleExpand(index) : lookDetail(device)
"
>
<el-col :span="3" :gutter="10">
<img
src="https://shoplineimg.com/65a8de08211b1e008886980e/6659acc772c9d500104bb668/800x.png?"
alt=""
srcset=""
width="100"
<!-- https://shoplineimg.com/65a8de08211b1e008886980e/6659acc772c9d500104bb668/800x.png? -->
<img :src="device.fileUrl" alt="" srcset="" width="100"
/></el-col>
<el-col :span="21" class="cursor-pointer">
<div class="flex justify-between items-center">
......@@ -76,15 +76,13 @@ const deviceList = reactive([
</div>
</div>
<div>
<el-button type="text" @click="lookDetail(device.deviceCode)"
<el-button type="text" @click.stop="lookDetail(device)"
>查看详情</el-button
>
<el-button
type="text"
@click.prevent="handleEdit(device.deviceCode)"
<el-button type="text" @click.stop="handleEdit(device.deviceCode)"
>编辑</el-button
>
<el-button type="text" @click="deleteDevice(device.deviceCode)"
<el-button type="text" @click.stop="deleteDevice(device.deviceCode)"
>删除</el-button
>
</div>
......@@ -101,12 +99,15 @@ const deviceList = reactive([
:icon="
!device.isExpend ? 'tabler:chevrons-up' : 'tabler:chevrons-down'
"
@click="toggleExpand(index)"
@click.stop="toggleExpand(index)"
/>
</el-col>
<childrenListTable
v-if="device.isExpend"
:childrenList="device.children"
:listData="listData"
:lookDetail="lookDetail"
@click.stop="lookDetail(device)"
/>
</el-row>
</div>
......
<script setup lang="ts">
import { ref, reactive } from "vue";
import { useDetailHook } from "../utils/detailHook";
const { operationRecords, radio } = useDetailHook();
const { lastBuildTime } = __APP_INFO__;
import router from "@/router";
import { getOperationRecords } from "@/api/device";
import { useRenderFlicker } from "@/components/ReFlicker";
import { randomGradient } from "@pureadmin/utils";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Iphone from "~icons/ep/iphone";
import timeControl from "./timeControl.vue";
import { getStartEndByType } from "@/utils/utils";
const operationRecords = ref([]);
const radio = ref("今天");
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"
})
}
];
// 获取操作记录列表数据
const getOperationRecordsList = async (time?: Array<string>) => {
const params = {
deviceCode: router.currentRoute.value.query?.deviceCode,
startTime: time ? time[0] : getStartEndByType()[0],
endTime: time ? time[1] : getStartEndByType()[1],
pageNum: 1,
pageSize: 100
};
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(() => {
getOperationRecordsList();
});
</script>
<template>
<div>
<!-- 单选(紧凑风格的按钮样式) -->
<el-radio-group v-model="radio">
<el-radio-button label="今天">今天</el-radio-button>
<el-radio-button label="3天">3天</el-radio-button>
<el-radio-button label="自定义">自定义</el-radio-button>
</el-radio-group>
<time-control @changeBtn="getOperationRecordsList" />
<!-- 这一块时暂无数据 -->
<!-- <el-empty description="暂无数据" /> -->
<div class="mt-6 flex justify-center">
<el-empty v-if="!operationRecords.length" description="暂无数据" />
<div class="mt-6 flex justify-center max-h-100 overflow-y-auto">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in operationRecords"
......@@ -83,21 +68,6 @@ const activities = [
</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>
......
<script setup lang="ts">
import { ref, reactive } from "vue";
import { getStartEndByType } from "@/utils/utils";
const emit = defineEmits<{
(e: "changeBtn", value: any[]): void;
}>();
const radio = ref("今天");
const dataLogDate = ref([]);
const changeBtn = (val: string | any) => {
if (val === "今天") {
dataLogDate.value = getStartEndByType();
emit("changeBtn", dataLogDate.value);
} else if (val === "3天") {
dataLogDate.value = getStartEndByType("lastThreeDays");
emit("changeBtn", dataLogDate.value);
} else if (val === "自定义") {
dataLogDate.value = [];
} else {
emit("changeBtn", val);
}
};
</script>
<template>
<div>
<!-- 单选(紧凑风格的按钮样式) -->
<el-radio-group v-model="radio" @change="changeBtn">
<el-radio-button label="今天">今天</el-radio-button>
<el-radio-button label="3天">3天</el-radio-button>
<el-radio-button label="自定义">自定义</el-radio-button>
</el-radio-group>
<el-date-picker
v-if="radio === '自定义'"
v-model="dataLogDate"
type="datetimerange"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
class="ml-5 mt-2"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="changeBtn"
/>
</div>
</template>
......@@ -2,7 +2,6 @@
defineOptions({
name: "DeviceDetail"
});
import { reactive } from "vue";
import { useDetailHook } from "./utils/detailHook";
import type { TabsPaneContext } from "element-plus";
import deviceAnalysis from "./components/deviceAnalysis.vue";
......@@ -10,14 +9,15 @@ import dataChart from "./components/dataChart.vue";
import dataLog from "./components/dataLog.vue";
import operationRecord from "./components/operationRecord.vue";
const { deviceInfo, labels, deviceList, Factor } = useDetailHook();
const {
deviceInfo,
latestDataLogList,
lateestDataLogColumns,
deviceList,
dataLogColumns
} = useDetailHook();
// {
// name: "出厂日期",
// value: "ZR-351"
// }
const activeName = ref("4");
const activeName = ref("1");
const handleClick = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event);
......@@ -52,19 +52,21 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
class="felx mb-4! basis-1/4"
>
<label>{{ i.name }}</label>
<span>{{ deviceInfo[i.prop] }}</span>
<span class="ml-2">{{ deviceInfo[i.prop] }}</span>
</p>
</div>
<div
class="flex items-center justify-between bg-gray-100 px-12 py-8 mt-10"
class="flex gap-y-5 items-center justify-between bg-gray-100 px-12 py-8 mt-10 flex-wrap h-25! overflow-y-scroll"
>
<p
v-for="i in Factor"
:key="i.name"
class="flex flex-col items-center"
v-for="i in Object.keys(lateestDataLogColumns)"
:key="i"
class="flex flex-col basis-1/3 text-center"
>
<span class="text-gray-400 mb-2">{{ i.name }}</span>
<span class="font-semibold text-lg">{{ i.value }}</span>
<span class="text-gray-400">{{ i }}</span>
<span class="font-semibold text-lg">{{
latestDataLogList[lateestDataLogColumns[i]] || "--"
}}</span>
</p>
</div>
</div>
......@@ -75,20 +77,26 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
class="demo-tabs"
@tab-click="handleClick"
>
<el-tab-pane label="数据图表" name="1"><dataChart /></el-tab-pane>
<el-tab-pane label="数据图表" name="1"
><dataChart v-if="activeName === '1'"
/></el-tab-pane>
<el-tab-pane label="设备分析" name="2"
><deviceAnalysis
><deviceAnalysis v-if="activeName === '2'"
/></el-tab-pane>
<el-tab-pane label="数据日志" name="3"
><dataLog
v-if="activeName === '3'"
:dataLogColumns="dataLogColumns"
/></el-tab-pane>
<el-tab-pane label="数据日志" name="3"><dataLog /></el-tab-pane>
<el-tab-pane label="操作记录" name="4"
><operationRecord
><operationRecord v-if="activeName === '4'"
/></el-tab-pane>
</el-tabs></div
></el-col>
<el-col :span="6" class="pl-10">
<p class="text-sm mb-3!">最近更新时间:2025.04.23 15:00:00</p>
<img
src="https://shoplineimg.com/65a8de08211b1e008886980e/6659acc772c9d500104bb668/800x.png?"
:src="deviceInfo.fileUrl"
alt=""
class="w-60 h-50! rounded-3xl mr-5 shadow shadow-red-300"
/>
......@@ -100,8 +108,8 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
><IconifyIconOnline
class="cursor-pointer"
icon="cuida:caret-up-outline"
@click="alarmSetting"
/>
<!-- @click="alarmSetting" -->
</p>
<div class="p-5">
<p>臭氧≥40mg/m³发生报警</p>
......@@ -115,6 +123,7 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
<style lang="scss" scoped>
.device-list-detail2 {
min-height: calc(100vh - 170px);
cursor: pointer;
background: white;
}
......
<script setup lang="ts">
import { ref } from "vue";
import { useDept } from "./utils/hook";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// 导入不同的图标组件
import Delete from "~icons/ep/delete";
import EditPen from "~icons/ep/edit-pen";
import Refresh from "~icons/ep/refresh";
import AddFill from "~icons/ri/add-circle-line";
import { Column } from "element-plus";
defineOptions({ name: "device" });
const formRef = ref();
const tableRef = ref();
const {
form,
loading,
columns,
dataList,
onSearch,
resetForm,
openDialog,
handleDelete,
handleSelectionChange
} = useDept();
function onFullscreen() {
tableRef.value.setAdaptive();
}
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-full pl-8 pt-[12px] overflow-auto"
>
<el-form-item label="设备名称:" prop="name">
<el-input
v-model="form.name"
placeholder="请输入设备名称"
clearable
class="w-[180px]!"
/>
</el-form-item>
<el-form-item label="状态:" prop="status">
<el-select
v-model="form.status"
placeholder="请选择状态"
clearable
class="w-[180px]!"
>
<el-option label="启用" :value="1" />
<el-option label="停用" :value="0" />
</el-select>
</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-form>
<PureTableBar
:title="'设备(仅演示,操作后不生效)'"
:columns="columns"
:tableRef="tableRef?.getTableRef()"
@refresh="onSearch"
@fullscreen="onFullscreen"
>
<template #buttons>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
@click="openDialog()"
>
新增设备
</el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
<pure-table
ref="tableRef"
adaptive
:adaptiveConfig="{ offsetBottom: 45 }"
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
default-expand-all
:loading="loading"
:size="size"
:data="dataList"
:columns="dynamicColumns"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
修改
</el-button>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(AddFill)"
@click="openDialog('新增', { parentId: row.id } as any)"
>
新增
</el-button>
<el-popconfirm
:title="`是否确认删除设备名称为${row.name}的这条数据`"
@confirm="handleDelete(row)"
>
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Delete)"
>
删除
</el-button>
</template>
</el-popconfirm>
</template>
</pure-table>
</template>
</PureTableBar>
</div>
</template>
<style lang="scss" scoped>
/* 移除表格内滚动条底部的线 */
:deep(.el-table__inner-wrapper::before) {
height: 0;
}
/* 主内容区域样式 */
:deep(.main-content) {
margin: 24px 24px 0 !important;
}
/* 搜索按钮样式 */
:deep(.search-form) {
.el-form-item {
margin-bottom: 12px;
}
}
</style>
<script setup lang="ts">
import listTable from "./components/listTable.vue";
import { useListHook } from "./utils/listHook";
import router from "@/router";
const { addDevice, importDeviceTemplate } = useListHook();
// 点击新建按钮,跳转到新建页面
const addDevice = () => {
router.push({ path: "/device/add" });
};
// 导入设备模版
const importDeviceTemplate = async () => {
router.push({ path: "/import-templete", query: { type: "device" } });
};
</script>
<template>
......@@ -20,9 +28,10 @@ const { addDevice, importDeviceTemplate } = useListHook();
<style lang="scss" scoped>
.device-list {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 10px 20px;
padding: 10px 45px 10px 20px;
background: #fff;
}
</style>
......@@ -173,8 +173,10 @@ const {
<!-- :shortcuts="getPickerShortcuts()" -->
<el-date-picker
v-model="formObj.factoryTime"
type="date"
type="datetimerange"
format="YYYY/MM/DD"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
placeholder="请选择设备出厂日期"
/>
......@@ -184,6 +186,7 @@ const {
<el-form-item label="设备厂商" class="w-5/6" prop="username">
<el-select
v-model="formObj.manufacturerId"
multiple
placeholder="请选择设备厂商"
>
<el-option
......@@ -199,8 +202,10 @@ const {
<el-form-item label="年检提醒" class="w-5/6" prop="username">
<el-date-picker
v-model="formObj.inspectTime"
type="date"
type="datetimerange"
format="YYYY/MM/DD"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
placeholder="请选择年检提醒"
/>
......
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";
import {
addDevice,
updateDevice,
getDeviceByLevel,
getDeviceSite,
getDeviceInfo
getDeviceInfo,
getDeviceTypeByType,
getDeviceModel
} from "@/api/device";
import { getManufacturerListNoPage } from "@/api/manufacturer";
......@@ -35,9 +34,10 @@ export function useAddHook(formRef: Ref) {
inspectTime: "", //年检提醒
devicePurpose: [], //设备用途
notes: "", //备注
devicePicture: "", //设备图片
fileUrl: "", //设备图片
fileId: "" //文件id
});
const deviceImgUrl = ref(""); //设备层级
const deviceTypeOptions = ref({}); //设备类型数据列表
const deviceLevelOptions = ref([]); //所属设备数据列表
......@@ -45,10 +45,6 @@ export function useAddHook(formRef: Ref) {
const deviceManufacturerOptions = ref([]); //设备厂商列表数据
const deviceModelOptions = ref({}); //设备型号列表数据
const validateForm = reactive({
fileList: [],
date: ""
});
const rules = {
deviceLevel: [
{
......@@ -141,6 +137,10 @@ export function useAddHook(formRef: Ref) {
message: "备注长度必须在0到8个字符之间",
trigger: "blur"
}
],
// 文件上传校验规则
fileUrl: [
{ required: true, message: "设备图片不能为空", trigger: "change" }
]
};
......@@ -150,16 +150,16 @@ export function useAddHook(formRef: Ref) {
// 获取设备类型的字典数据
const getDeviceType = async () => {
const res = await getDictItems("deviceType");
const res = await getDeviceTypeByType({ type: "deviceType" });
if (res.code === "0") {
deviceTypeOptions.value = res.data;
} else {
ElMessage.error(`获取设备类型失败`);
}
};
// 获取设备类型的字典数据
const getDeviceModelType = async () => {
const res = await getDictItems("deviceModel");
// 根据设备类型获取型号列表数据
const changeDeviceType = async val => {
const res = await getDeviceModel({ parentName: val });
if (res.code === "0") {
deviceModelOptions.value = res.data;
} else {
......@@ -199,14 +199,6 @@ export function useAddHook(formRef: Ref) {
// 判断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") {
......@@ -240,7 +232,8 @@ export function useAddHook(formRef: Ref) {
const res = await formUpload(formData);
// 如果上传成功,则返回文件地址
if (res.code === "0") {
formObj.value.devicePicture = res.data.filePath;
formObj.value.fileUrl = res.data.filePath;
formObj.value.fileId = res.data.fileId;
getExcelUrl(res.data.fileId);
ElMessage.success("图片上传成功");
} else {
......@@ -249,6 +242,13 @@ export function useAddHook(formRef: Ref) {
}
};
// 点击编辑图片按钮,触发handleEditAvatar函数,将formObj.value.fileUrl赋值给imageUrl.value,并打开上传图片的对话框
const handleEditImage = () => {
deviceImgUrl.value = deviceImgUrl.value || formObj.value.fileUrl;
formObj.value.fileUrl = formObj.value.fileUrl ? "" : deviceImgUrl.value;
};
// 定义一个函数,用于处理头像上传成功
// const handleAvatarSuccess: UploadProps["onSuccess"] = (
// response,
......@@ -305,11 +305,12 @@ export function useAddHook(formRef: Ref) {
// 将表单数据转换为原始数据
const params = JSON.parse(JSON.stringify(toRaw(formObj.value)));
params.devicePurpose = params.devicePurpose.toString();
params.devicePurpose = params.devicePurpose?.join(",");
// 判断url是否包含id,如果包含则调用更新设备接口,否则调用添加设备接口
if (router.currentRoute.value.query.deviceCode) {
const deviceCode = router.currentRoute.value.query.deviceCode;
const res = await updateDevice({ ...params, deviceCode });
params.devicePicture = formObj.value.fileId;
// const deviceCode = router.currentRoute.value.query.deviceCode;
const res = await updateDevice({ ...params });
if (res.code === "0") {
ElMessage.success("更新成功");
// 更新设备信息后,跳转到设备列表页面
......@@ -339,7 +340,7 @@ export function useAddHook(formRef: Ref) {
getDeviceList();
getDeviceSiteList();
getManufacturerList();
getDeviceModelType();
// getDeviceModelType();
// 获取设备类型
// 获取设备型号
// 获取设备厂商
......@@ -350,7 +351,6 @@ export function useAddHook(formRef: Ref) {
handleReset,
handleSubmit,
rules,
validateForm,
deviceTypeOptions,
getDeviceType,
deviceLevelOptions,
......@@ -360,6 +360,8 @@ export function useAddHook(formRef: Ref) {
uploadFile,
beforeAvatarUpload,
getExcelUrl,
deviceModelOptions
deviceModelOptions,
handleEditImage,
changeDeviceType
};
}
import router from "@/router";
import { ref, onMounted } from "vue";
import { useRenderFlicker } from "@/components/ReFlicker";
// 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";
import { getDeviceInfo, getDataLogListLatest } from "@/api/device";
// 引入字典接口
import { getDictItems } from "@/api/public";
export function useDetailHook() {
const deviceInfo = ref({
// deviceName: ""
});
const deviceInfo = ref({ deviceName: "", fileUrl: "" });
const labels = reactive([
{
label: "已连接",
......@@ -47,17 +48,17 @@ export function useDetailHook() {
// },
{
name: "设备联系人",
prop: "deviceContact",
prop: "deviceStaff",
value: ""
},
{
name: "所属站点",
prop: "deviceSite",
prop: "deviceSideName",
value: ""
},
{
name: "设备部署位置",
prop: "deviceLocation",
prop: "deviceAddress",
value: ""
},
{
......@@ -82,8 +83,9 @@ export function useDetailHook() {
}
]);
const operationRecords = ref([]);
const radio = ref("今天");
const latestDataLogList = ref({}); // 最新一条数据日志
const lateestDataLogColumns = ref({}); // 最新一条数据日志的表头
const dataLogColumns = ref([]); // 数据日志列表的表头
// 根据deviceCode获取设备详情
const getDeviceInfoByCode = async () => {
......@@ -96,50 +98,56 @@ export function useDetailHook() {
deviceCode: router.currentRoute.value.query?.deviceCode
});
deviceInfo.value = res.data || {};
console.log("deviceInfo.value", deviceInfo.value);
};
// 通过字典接口,获取数据日志的表头
const getDataLogColumns = async () => {
// 获取设备类型的字典数据
const res = await getDictItems("NOISE");
if (res.code === "0") {
if (!res || !res.data) return;
const data = Object.keys(res.data);
const columns = data.map(item => {
return { label: item, prop: res.data[item] };
});
dataLogColumns.value = columns;
lateestDataLogColumns.value = res.data;
} else {
ElMessage.error(`获取表头失败`);
}
};
// 获取操作记录列表数据
const getOperationRecordsList = async () => {
const params = {
// 获取最新一条数据日志
const getLatestDataLogList = async () => {
const res = await getDataLogListLatest({
deviceCode: router.currentRoute.value.query?.deviceCode,
endTime: "2026-06-28 14:10:00",
pageNum: 0,
pageSize: 10,
deviceType: router.currentRoute.value.query?.deviceType || "NOISE",
// deviceCode: "3110E30000658",
// deviceType: "AIR_3110",
endTime: "2016-06-28 14:10:00",
startTime: "2016-06-28 14:10:00"
};
const res = await getOperationRecords(params);
});
if (!res || !res.data) return;
operationRecords.value = handleOperationRecords(res.data.records) || [];
latestDataLogList.value = res.data;
};
// 处理操作记录的数据结构
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;
const init = () => {
getLatestDataLogList();
getDeviceInfoByCode();
getDataLogColumns();
};
onMounted(() => {
// getList();
getDeviceInfoByCode();
getOperationRecordsList();
// 获取设备类型
// 获取设备型号
// 获取设备厂商
// 获取设备状态
init();
});
return {
deviceInfo,
labels,
deviceList,
Factor,
operationRecords,
radio
dataLogColumns,
lateestDataLogColumns,
latestDataLogList
};
}
import dayjs from "dayjs";
import editForm from "../components/form.vue";
import { handleTree } from "@/utils/tree";
import { message } from "@/utils/message";
import { getDeptList, addDept, deleteDept, updateDept } from "@/api/systems";
// import { getDeviceList, addDevice, deleteDevice, updateDevice } from "@/api/device";
import { usePublicHooks } from "@/hooks/hooks";
import { addDialog } from "@/components/ReDialog";
import { reactive, ref, onMounted, h } from "vue";
import type { FormItemProps } from "../types";
import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils";
export function useDept() {
const form = reactive({
name: "",
status: null
});
const formRef = ref();
const dataList = ref([]);
const loading = ref(true);
const { tagStyle } = usePublicHooks();
const columns: TableColumnList = [
{
label: "部门名称",
prop: "name",
width: 180,
align: "left"
},
{
label: "排序",
prop: "sort",
minWidth: 70
},
{
label: "状态",
prop: "status",
minWidth: 100,
align: "center",
cellRenderer: ({ row, props }) => (
<el-tag size={props.size} style={tagStyle.value(row.status)}>
{row.status === 1 ? "启用" : "停用"}
</el-tag>
)
},
{
label: "创建时间",
minWidth: 200,
prop: "createTime",
formatter: ({ createTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "操作",
fixed: "right",
width: 210,
slot: "operation"
}
];
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
function resetForm(formEl) {
if (!formEl) return;
formEl.resetFields();
onSearch();
}
async function onSearch() {
loading.value = true;
const params = {
pageNum: 1,
pageSize: 200
};
const { data } = await getDeptList(params);
let newData = (data as any).records;
if (!isAllEmpty(form.name)) {
newData = newData.filter(item => item.name.includes(form.name));
}
if (!isAllEmpty(form.status)) {
newData = newData.filter(item => item.status === form.status);
}
dataList.value = handleTree(newData);
setTimeout(() => {
loading.value = false;
}, 500);
}
function formatHigherDeptOptions(treeList) {
if (!treeList || !treeList.length) return;
const newTreeList = [];
for (let i = 0; i < treeList.length; i++) {
treeList[i].disabled = treeList[i].status === 0;
formatHigherDeptOptions(treeList[i].children);
newTreeList.push(treeList[i]);
}
return newTreeList;
}
function openDialog(title? = "新增", row?) {
addDialog({
title: `${title}部门`,
props: {
formInline: {
higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList.value)),
parentId: row?.parentId ?? 0,
name: row?.name ?? "",
principal: row?.principal ?? "",
phone: row?.phone ?? "",
email: row?.email ?? "",
sort: row?.sort ?? 0,
status: row?.status ?? 1,
remark: row?.remark ?? ""
}
},
width: "40%",
draggable: true,
fullscreen: deviceDetection(),
fullscreenIcon: true,
closeOnClickModal: false,
contentRenderer: () => h(editForm, { ref: formRef, formInline: null }),
beforeSure: (done, { options }) => {
const FormRef = formRef.value.getRef();
const curData = options.props.formInline as FormItemProps;
function chores() {
message(`您${title}了部门名称为${curData.name}的这条数据`, {
type: "success"
});
done();
onSearch();
}
FormRef.validate(valid => {
if (valid) {
if (title === "新增") {
addDept(curData).then(res => {
if ((res as any).code === "0") {
chores();
} else {
message((res as any).msg, { type: "error" });
}
});
} else {
if (!row?.id) {
message("id不能为空", { type: "error" });
return;
}
curData.id = row.id;
updateDept(curData).then(res => {
if ((res as any).code === "0") {
chores();
} else {
message((res as any).msg, { type: "error" });
}
});
}
}
});
}
});
}
function handleDelete(row) {
console.log("handleDelete", row.id);
deleteDept({ id: row.id }).then(res => {
if ((res as any).code === "0") {
message(`您删除了部门名称为${row.name}的这条数据`, { type: "success" });
onSearch();
}
});
}
onMounted(() => {
onSearch();
});
return {
form,
loading,
columns,
dataList,
onSearch,
resetForm,
openDialog,
handleDelete,
handleSelectionChange
};
}
......@@ -6,11 +6,24 @@ import { getDeviceTreeList, setBlackList } from "@/api/device";
export function useListHook() {
const listData = ref([]);
// 根据索引判断跳转到不同的设备详情页面
const lookDetail = deviceCode => {
const lookDetail = deviceItem => {
// if (isChildren) {
// router.push({
// path: "/device/childrenList",
// query: {
// deviceCode: deviceItem.deviceCode,
// deviceType: deviceItem.deviceType
// }
// });
// } else {
router.push({
path: "/device/detail",
query: { deviceCode }
query: {
deviceCode: deviceItem.deviceCode,
deviceType: deviceItem.deviceType
}
});
// }
};
// 点击编辑按钮,跳转到编辑页面
......@@ -18,11 +31,6 @@ export function useListHook() {
router.push({ path: `/device/edit`, query: { deviceCode } });
};
// 点击新建按钮,跳转到新建页面
const addDevice = () => {
router.push({ path: "/device/add" });
};
// 获取设备列表
const getList = async () => {
// 调用getDeviceList函数,获取设备列表
......@@ -55,19 +63,6 @@ export function useListHook() {
});
};
// 导入设备模版
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;
......@@ -75,19 +70,13 @@ export function useListHook() {
onMounted(() => {
getList();
// 获取设备类型
// 获取设备型号
// 获取设备厂商
// 获取设备状态
});
return {
lookDetail,
getList,
listData,
toggleExpand,
addDevice,
handleEdit,
deleteDevice,
importDeviceTemplate
deleteDevice
};
}
......@@ -16,7 +16,7 @@ export function useRole(tableRef: Ref) {
deviceType: "", //设备类型
deviceCode: "", //设备编码
deviceModel: "", //设备型号
manufacturerId: "", //设备厂商
manufacturerId: [], //设备厂商
deviceStatus: "", //设备状态
deviceAddress: "", //设备位置
deviceSide: "", //所属站点
......@@ -28,7 +28,11 @@ export function useRole(tableRef: Ref) {
devicePurpose: "", //设备用途
notes: "", //备注
devicePicture: "", //设备图片
fileId: "" //文件id
fileId: "", //文件id
factoryStartTime: "", //出厂日期开始时间
factoryEndTime: "", //出厂日期结束时间
inspectStartTime: "", //年检提醒开始时间
inspectEndTime: "" //年检提醒结束时间
});
const listData = ref([]);
const loading = ref(false);
......@@ -76,7 +80,7 @@ export function useRole(tableRef: Ref) {
},
{
label: "设备类型",
prop: "deviceType",
prop: "deviceTypeName",
minWidth: 100
},
{
......@@ -86,7 +90,7 @@ export function useRole(tableRef: Ref) {
},
{
label: "所属站点",
prop: "deviceSide",
prop: "deviceSideName",
minWidth: 100
},
{
......@@ -181,7 +185,7 @@ export function useRole(tableRef: Ref) {
// 获取所属设备列表
const getDeviceLevelList = async () => {
const res = await getDeviceByLevel({ deviceLevel: 2 });
const res = await getDeviceByLevel({ deviceLevel: 1 });
if (res.code === "0") {
deviceLevelOptions.value = res.data;
} else {
......@@ -219,16 +223,33 @@ export function useRole(tableRef: Ref) {
delete params[key];
}
});
if (params.factoryTime) {
params.factoryStartTime = params.factoryTime[0];
params.factoryEndTime = params.factoryTime[1];
}
if (params.inspectTime) {
params.inspectStartTime = params.inspectTime[0];
params.inspectEndTime = params.inspectTime[1];
}
const res = await getDeviceList({
...params,
pageNum: pagination.currentPage,
pageSize: pagination.pageSize
// factoryEndTime: params.factoryTime ? params.factoryTime[1] : "",
// factoryStartTime: params.factoryTime ? params.factoryTime[0] : "",
// inspectEndTime: params.inspectTime ? params.inspectTime[1] : "",
// inspectStartTime: params.inspectTime ? params.inspectTime[0] : ""
// factoryStartTime: params.factoryTime[0],
// inspectEndTime: params.inspectTime[1],
// inspectStartTime: params.inspectTime[0]
});
if (res.code === "0") {
// 给数据添加一个isExpend属性,默认值是false,点击展开按钮的时候,将isExpend属性设置为true,再次点击的时候,将isExpend属性设置为false
res.data.records.forEach((item: any) => {
item.isExpend = false;
item.deviceLevel = item.deviceLevel == 1 ? "主设备" : "附属设备";
});
listData.value = res.data.records;
loading.value = false;
} else {
......@@ -270,7 +291,7 @@ export function useRole(tableRef: Ref) {
getDeviceModelType();
getManufacturerList();
getDeviceSiteList();
getDeviceLevelList;
getDeviceLevelList();
});
return {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论