From 9fae4a56c15392babde83d68db4073762900082d Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期五, 16 十月 2026 22:39:32 +0800
Subject: [PATCH] feat: 设备保养和巡检优化,项目拆分
---
src/views/equipmentManagement/upkeep/index.vue | 1103 ++++----
src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue | 326 ++
src/views/equipmentManagement/upkeep/Form/PlanModal.vue | 188 +
src/views/equipmentManagement/inspectionManagement/components/formDia.vue | 775 +++--
src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue | 181 +
src/api/equipmentManagement/upkeep.js | 54
src/views/equipmentManagement/upkeep/Form/ItemManager.vue | 331 ++
src/views/equipmentManagement/inspectionManagement/index.vue | 967 ++++---
src/views/equipmentManagement/upkeep/Form/detailDia.vue | 240 +
src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue | 172 +
src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue | 226 +
src/api/inspectionManagement/index.js | 85
src/views/equipmentManagement/upkeep/Form/formDia.vue | 913 ++++--
src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue | 1167 +++++----
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue | 534 ++-
15 files changed, 4,693 insertions(+), 2,569 deletions(-)
diff --git a/src/api/equipmentManagement/upkeep.js b/src/api/equipmentManagement/upkeep.js
index 234d2a5..b7233b6 100644
--- a/src/api/equipmentManagement/upkeep.js
+++ b/src/api/equipmentManagement/upkeep.js
@@ -73,7 +73,7 @@
// 娣诲姞璁惧淇濆吇瀹氭椂浠诲姟
export const deviceMaintenanceTaskAdd = (params) => {
return request({
- url: '/deviceMaintenanceTask/add',
+ url: "/deviceMaintenanceTask/add",
method: "post",
data: params,
});
@@ -81,7 +81,7 @@
// 淇敼璁惧淇濆吇瀹氭椂浠诲姟
export const deviceMaintenanceTaskEdit = (params) => {
return request({
- url: '/deviceMaintenanceTask/update',
+ url: "/deviceMaintenanceTask/update",
method: "post",
data: params,
});
@@ -89,7 +89,7 @@
// 璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃
export const deviceMaintenanceTaskList = (params) => {
return request({
- url: '/deviceMaintenanceTask/listPage',
+ url: "/deviceMaintenanceTask/listPage",
method: "get",
params: params,
});
@@ -97,8 +97,54 @@
// 璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃
export const deviceMaintenanceTaskDel = (params) => {
return request({
- url: '/deviceMaintenanceTask/delete',
+ url: "/deviceMaintenanceTask/delete",
method: "delete",
data: params,
});
};
+
+export const getMaintenanceItemList = (params = {}) => {
+ return request({
+ url: "/deviceMaintenanceItem/list",
+ method: "get",
+ params,
+ });
+};
+
+export const getMaintenanceItemPage = (params = {}) => {
+ return request({
+ url: "/deviceMaintenanceItem/page",
+ method: "get",
+ params,
+ });
+};
+
+export const getActiveMaintenanceItems = () => {
+ return request({
+ url: "/deviceMaintenanceTask/items",
+ method: "get",
+ });
+};
+
+export const addMaintenanceItem = (data) => {
+ return request({
+ url: "/deviceMaintenanceItem",
+ method: "post",
+ data,
+ });
+};
+
+export const editMaintenanceItem = (data) => {
+ return request({
+ url: "/deviceMaintenanceItem",
+ method: "put",
+ data,
+ });
+};
+
+export const deleteMaintenanceItem = (id) => {
+ return request({
+ url: `/deviceMaintenanceItem/${id}`,
+ method: "delete",
+ });
+};
diff --git a/src/api/inspectionManagement/index.js b/src/api/inspectionManagement/index.js
index d0c444a..ca773d1 100644
--- a/src/api/inspectionManagement/index.js
+++ b/src/api/inspectionManagement/index.js
@@ -1,61 +1,72 @@
// 宸℃绠$悊
-import request from '@/utils/request'
+import request from "@/utils/request";
// 宸℃浠诲姟琛ㄨ〃鏌ヨ
export function inspectionTaskList(query) {
- return request({
- url: '/inspectionTask/list',
- method: 'get',
- params: query
- })
+ return request({
+ url: "/inspectionTask/list",
+ method: "get",
+ params: query,
+ });
}
// 宸℃浠诲姟琛ㄦ柊澧炰慨鏀�
export function addOrEditInspectionTask(query) {
- return request({
- url: '/inspectionTask/addOrEditInspectionTask',
- method: 'post',
- data: query
- })
+ return request({
+ url: "/inspectionTask/addOrEditInspectionTask",
+ method: "post",
+ data: query,
+ });
}
// 宸℃浠诲姟琛ㄥ垹闄�
export function delInspectionTask(query) {
- return request({
- url: '/inspectionTask/delInspectionTask',
- method: 'delete',
- data: query
- })
+ return request({
+ url: "/inspectionTask/delInspectionTask",
+ method: "delete",
+ data: query,
+ });
}
// 瀹氭椂宸℃浠诲姟琛ㄥ垹闄�
export function delTimingTask(query) {
- return request({
- url: '/timingTask/delTimingTask',
- method: 'delete',
- data: query
- })
+ return request({
+ url: "/timingTask/delTimingTask",
+ method: "delete",
+ data: query,
+ });
}
// /inspectionTask/addOrEditInspectionTask
// 宸℃涓婁紶
export function uploadInspectionTask(query) {
- return request({
- url: '/inspectionTask/addOrEditInspectionTask',
- method: 'post',
- data: query
- })
+ return request({
+ url: "/inspectionTask/addOrEditInspectionTask",
+ method: "post",
+ data: query,
+ });
}
// 瀹氭椂宸℃浠诲姟琛ㄦ煡璇�
export function timingTaskList(query) {
- return request({
- url: '/timingTask/list',
- method: 'get',
- params: query
- })
+ return request({
+ url: "/timingTask/list",
+ method: "get",
+ params: query,
+ });
}
// 瀹氭椂宸℃浠诲姟琛ㄦ柊澧炰慨鏀�
export function addOrEditTimingTask(query) {
- return request({
- url: '/timingTask/addOrEditTimingTask',
- method: 'post',
- data: query
- })
-}
\ No newline at end of file
+ return request({
+ url: "/timingTask/addOrEditTimingTask",
+ method: "post",
+ data: query,
+ });
+}
+
+export const getInspectionItemList = (params = {}) =>
+ request({ url: "/inspectionItem/list", method: "get", params });
+export const getInspectionItemPage = (params = {}) =>
+ request({ url: "/inspectionItem/page", method: "get", params });
+export const addInspectionItem = (data) =>
+ request({ url: "/inspectionItem", method: "post", data });
+export const editInspectionItem = (data) =>
+ request({ url: "/inspectionItem", method: "put", data });
+export const deleteInspectionItem = (id) =>
+ request({ url: `/inspectionItem/${id}`, method: "delete" });
diff --git a/src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue
new file mode 100644
index 0000000..ff88721
--- /dev/null
+++ b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue
@@ -0,0 +1,326 @@
+<template>
+ <div class="app-container">
+ <el-form :model="filters" :inline="true">
+ <el-form-item label="鎵�灞炶澶�">
+ <el-select
+ v-model="filters.deviceLedgerId"
+ clearable
+ filterable
+ placeholder="璇烽�夋嫨璁惧"
+ style="width: 220px"
+ >
+ <el-option
+ v-for="device in deviceOptions"
+ :key="device.id"
+ :label="device.deviceName"
+ :value="device.id"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="宸℃棰戠巼">
+ <el-select
+ v-model="filters.frequencyType"
+ clearable
+ placeholder="璇烽�夋嫨棰戠巼"
+ style="width: 180px"
+ >
+ <el-option
+ v-for="option in frequencyOptions"
+ :key="option.value"
+ :label="option.label"
+ :value="option.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="宸℃椤圭洰/鍐呭">
+ <el-input
+ v-model="keyword"
+ clearable
+ placeholder="璇疯緭鍏ラ」鐩垨鍐呭"
+ style="width: 240px"
+ @keyup.enter="search"
+ @clear="search"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="search">鎼滅储</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-card>
+ <div class="actions">
+ <el-text size="large">宸℃椤圭洰涓庡唴瀹规竻鍗�</el-text>
+ <el-button type="primary" @click="openAdd">鏂板宸℃鍐呭</el-button>
+ </div>
+ <el-table v-loading="loading" :data="items" border>
+ <el-table-column type="index" label="搴忓彿" width="80" align="center" :index="indexMethod" />
+ <el-table-column
+ prop="itemProject"
+ label="宸℃椤圭洰"
+ min-width="180"
+ show-overflow-tooltip
+ />
+ <el-table-column
+ prop="itemContent"
+ label="宸℃鍐呭"
+ min-width="300"
+ show-overflow-tooltip
+ />
+ <el-table-column label="鎵�灞炶澶�" min-width="180" align="center">
+ <template #default="{ row }">{{
+ row.deviceLedgerId ? deviceNameMap[row.deviceLedgerId] || "-" : "閫氱敤"
+ }}</template>
+ </el-table-column>
+ <el-table-column label="棰戠巼" width="120" align="center">
+ <template #default="{ row }">{{ frequencyLabel(row.frequencyType) }}</template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="150" align="center" fixed="right">
+ <template #default="{ row }">
+ <el-button link type="primary" @click="openEdit(row)">缂栬緫</el-button>
+ <el-button link type="danger" @click="removeItem(row)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ <template #empty>
+ <el-empty description="杩樻病鏈夊贰妫�鍐呭锛岃閫愭潯娣诲姞">
+ <el-button type="primary" @click="openAdd">鏂板宸℃鍐呭</el-button>
+ </el-empty>
+ </template>
+ </el-table>
+ <div class="pagination-wrap">
+ <el-pagination
+ v-model:current-page="pageNum"
+ v-model:page-size="pageSize"
+ background
+ :page-sizes="[10, 20, 50]"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="load"
+ />
+ </div>
+ </el-card>
+
+ <el-dialog
+ v-model="dialogVisible"
+ :title="form.id ? '缂栬緫宸℃鍐呭' : '鏂板宸℃鍐呭'"
+ width="620px"
+ align-center
+ destroy-on-close
+ :close-on-click-modal="false"
+ >
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="宸℃椤圭洰" prop="itemProject">
+ <el-input
+ v-model.trim="form.itemProject"
+ maxlength="200"
+ show-word-limit
+ placeholder="渚嬪锛氳澶囧瑙傛鏌�"
+ />
+ </el-form-item>
+ <el-form-item label="宸℃鍐呭" prop="itemContent">
+ <el-input
+ v-model.trim="form.itemContent"
+ type="textarea"
+ :rows="4"
+ resize="vertical"
+ maxlength="2000"
+ show-word-limit
+ placeholder="濉啓鍏蜂綋妫�鏌ュ唴瀹�"
+ />
+ </el-form-item>
+ <el-form-item label="鎵�灞炶澶�">
+ <el-select
+ v-model="form.deviceLedgerId"
+ clearable
+ filterable
+ style="width: 100%"
+ placeholder="涓嶉�夋嫨鍒欎负閫氱敤宸℃鍐呭"
+ >
+ <el-option
+ v-for="device in deviceOptions"
+ :key="device.id"
+ :label="device.deviceName"
+ :value="device.id"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="宸℃棰戠巼" prop="frequencyType">
+ <el-select v-model="form.frequencyType" style="width: 100%" placeholder="璇烽�夋嫨棰戠巼">
+ <el-option
+ v-for="option in frequencyOptions"
+ :key="option.value"
+ :label="option.label"
+ :value="option.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" :loading="saving" @click="save">淇濆瓨</el-button>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { computed, onMounted, reactive, ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import {
+ addInspectionItem,
+ deleteInspectionItem,
+ editInspectionItem,
+ getInspectionItemPage,
+} from "@/api/inspectionManagement";
+import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+
+const items = ref([]);
+const loading = ref(false);
+const saving = ref(false);
+const dialogVisible = ref(false);
+const formRef = ref();
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(20);
+const total = ref(0);
+const deviceOptions = ref([]);
+const filters = reactive({ deviceLedgerId: undefined, frequencyType: "" });
+const frequencyOptions = [
+ { label: "姣忔棩", value: "DAILY" },
+ { label: "姣忓懆", value: "WEEKLY" },
+ { label: "姣忔湀", value: "MONTHLY" },
+ { label: "姣忓搴�", value: "QUARTERLY" },
+ { label: "閫氱敤棰戠巼", value: "ALL" },
+];
+const deviceNameMap = computed(() =>
+ Object.fromEntries(deviceOptions.value.map((device) => [String(device.id), device.deviceName]))
+);
+const frequencyLabel = (value) =>
+ frequencyOptions.find((option) => option.value === value)?.label || value || "-";
+const indexMethod = (index) => (pageNum.value - 1) * pageSize.value + index + 1;
+const form = reactive({
+ id: undefined,
+ itemProject: "",
+ itemContent: "",
+ deviceLedgerId: undefined,
+ frequencyType: "",
+ sortNum: 0,
+ isActive: 1,
+ remarks: "",
+});
+const rules = {
+ itemProject: [{ required: true, message: "璇疯緭鍏ュ贰妫�椤圭洰", trigger: "blur" }],
+ itemContent: [{ required: true, message: "璇疯緭鍏ュ贰妫�鍐呭", trigger: "blur" }],
+ frequencyType: [{ required: true, message: "璇烽�夋嫨宸℃棰戠巼", trigger: "change" }],
+};
+
+const load = async () => {
+ loading.value = true;
+ try {
+ const { code, data } = await getInspectionItemPage({
+ pageNum: pageNum.value,
+ pageSize: pageSize.value,
+ itemKeyword: keyword.value.trim(),
+ isActive: 1,
+ deviceLedgerId: filters.deviceLedgerId,
+ frequencyType: filters.frequencyType,
+ includeCommon: true,
+ });
+ if (code === 200) {
+ items.value = data?.records || [];
+ total.value = Number(data?.total || 0);
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+const search = () => {
+ pageNum.value = 1;
+ load();
+};
+const resetFilters = () => {
+ filters.deviceLedgerId = undefined;
+ filters.frequencyType = "";
+ keyword.value = "";
+ search();
+};
+const handleSizeChange = () => {
+ pageNum.value = 1;
+ load();
+};
+const reset = () =>
+ Object.assign(form, {
+ id: undefined,
+ itemProject: "",
+ itemContent: "",
+ deviceLedgerId: undefined,
+ frequencyType: "",
+ sortNum: 0,
+ isActive: 1,
+ remarks: "",
+ });
+const openAdd = () => {
+ reset();
+ dialogVisible.value = true;
+};
+const openEdit = (row) => {
+ Object.assign(form, { ...row });
+ dialogVisible.value = true;
+};
+const save = async () => {
+ if (
+ !(await formRef.value
+ ?.validate()
+ .then(() => true)
+ .catch(() => false))
+ )
+ return;
+ saving.value = true;
+ try {
+ const { code } = form.id
+ ? await editInspectionItem({ ...form })
+ : await addInspectionItem({ ...form });
+ if (code === 200) {
+ ElMessage.success("淇濆瓨鎴愬姛");
+ dialogVisible.value = false;
+ await load();
+ }
+ } finally {
+ saving.value = false;
+ }
+};
+const removeItem = async (row) => {
+ try {
+ await ElMessageBox.confirm(`纭畾鍒犻櫎宸℃鍐呭鈥�${row.itemContent}鈥濆悧锛焋, "鎻愮ず", {
+ type: "warning",
+ });
+ const { code } = await deleteInspectionItem(row.id);
+ if (code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ await load();
+ }
+ } catch (_) {
+ /* 鐢ㄦ埛鍙栨秷 */
+ }
+};
+onMounted(async () => {
+ const { data } = await getDeviceLedger();
+ deviceOptions.value = data || [];
+ await load();
+});
+</script>
+
+<style scoped>
+.actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+}
+.pagination-wrap {
+ display: flex;
+ justify-content: flex-end;
+ padding-top: 12px;
+}
+</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue
new file mode 100644
index 0000000..be21f84
--- /dev/null
+++ b/src/views/equipmentManagement/inspectionManagement/components/InspectionItemSelector.vue
@@ -0,0 +1,172 @@
+<template>
+ <el-dialog
+ v-model="dialogVisible"
+ title="閫夋嫨宸℃鍐呭"
+ width="820px"
+ append-to-body
+ destroy-on-close
+ >
+ <div class="selector-toolbar">
+ <el-input
+ v-model="keyword"
+ clearable
+ placeholder="鎸夐」鐩垨鍐呭鎼滅储"
+ @keyup.enter="search"
+ @clear="search"
+ />
+ <el-button type="primary" @click="search">鎼滅储</el-button>
+ </div>
+ <el-table v-loading="loading" :data="rows" border height="360">
+ <el-table-column label="閫夋嫨" width="70" align="center">
+ <template #default="{ row }"
+ ><el-checkbox
+ :model-value="isSelected(row.id)"
+ @change="(checked) => toggleItem(row, checked)"
+ /></template>
+ </el-table-column>
+ <el-table-column type="index" label="搴忓彿" width="70" />
+ <el-table-column label="绫诲瀷" width="90" align="center">
+ <template #default="{ row }"
+ ><el-tag :type="row.deviceLedgerId ? 'primary' : 'info'" size="small">{{
+ row.deviceLedgerId ? "鏈澶�" : "閫氱敤"
+ }}</el-tag></template
+ >
+ </el-table-column>
+ <el-table-column prop="itemProject" label="宸℃椤圭洰" min-width="170" show-overflow-tooltip />
+ <el-table-column prop="itemContent" label="宸℃鍐呭" min-width="270" show-overflow-tooltip />
+ <el-table-column label="棰戠巼" width="110" align="center">
+ <template #default="{ row }"
+ ><el-tag :type="row.frequencyType === 'ALL' ? 'info' : 'success'" size="small">{{
+ frequencyLabel(row.frequencyType)
+ }}</el-tag></template
+ >
+ </el-table-column>
+ </el-table>
+ <div class="selector-pagination">
+ <el-pagination
+ v-model:current-page="pageNum"
+ v-model:page-size="pageSize"
+ :page-sizes="[10, 20, 50]"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="load"
+ />
+ </div>
+ <template #footer>
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="confirm">纭畾閫夋嫨锛坽{ selected.size }}锛�</el-button>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { computed, ref, watch } from "vue";
+import { getInspectionItemPage } from "@/api/inspectionManagement";
+
+const props = defineProps({
+ visible: { type: Boolean, default: false },
+ selectedItems: { type: Array, default: () => [] },
+ deviceLedgerId: { type: [Number, String], default: undefined },
+ frequencyType: { type: String, default: "" },
+});
+const emit = defineEmits(["update:visible", "confirm"]);
+const dialogVisible = computed({
+ get: () => props.visible,
+ set: (value) => emit("update:visible", value),
+});
+const rows = ref([]);
+const loading = ref(false);
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+const selected = ref(new Map());
+const frequencyLabel = (value) =>
+ ({ DAILY: "姣忔棩", WEEKLY: "姣忓懆", MONTHLY: "姣忔湀", QUARTERLY: "姣忓搴�", ALL: "閫氱敤棰戠巼" }[
+ value
+ ] ||
+ value ||
+ "-");
+
+watch(
+ () => props.visible,
+ (visible) => {
+ if (!visible) return;
+ keyword.value = "";
+ pageNum.value = 1;
+ selected.value = new Map(
+ (props.selectedItems || []).map((item) => [String(item.inspectionItemId || item.id), item])
+ );
+ load();
+ }
+);
+watch(
+ () => [props.deviceLedgerId, props.frequencyType],
+ () => {
+ if (!props.visible) return;
+ pageNum.value = 1;
+ load();
+ }
+);
+const load = async () => {
+ if (!props.deviceLedgerId || !props.frequencyType) {
+ rows.value = [];
+ total.value = 0;
+ return;
+ }
+ loading.value = true;
+ try {
+ const { code, data } = await getInspectionItemPage({
+ pageNum: pageNum.value,
+ pageSize: pageSize.value,
+ itemKeyword: keyword.value.trim(),
+ isActive: 1,
+ deviceLedgerId: props.deviceLedgerId,
+ frequencyType: props.frequencyType,
+ includeCommon: true,
+ });
+ if (code === 200) {
+ rows.value = data?.records || [];
+ total.value = Number(data?.total || 0);
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+const search = () => {
+ pageNum.value = 1;
+ load();
+};
+const handleSizeChange = () => {
+ pageNum.value = 1;
+ load();
+};
+const isSelected = (id) => selected.value.has(String(id));
+const toggleItem = (item, checked) => {
+ const next = new Map(selected.value);
+ if (checked) next.set(String(item.id), item);
+ else next.delete(String(item.id));
+ selected.value = next;
+};
+const confirm = () => {
+ emit("confirm", Array.from(selected.value.values()));
+ dialogVisible.value = false;
+};
+</script>
+
+<style scoped>
+.selector-toolbar {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 14px;
+}
+.selector-toolbar .el-input {
+ max-width: 440px;
+}
+.selector-pagination {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 14px;
+}
+</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/formDia.vue b/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
index 0f94f66..ef78caa 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -1,314 +1,503 @@
<template>
- <div>
- <el-dialog :title="operationType === 'add' ? '鏂板宸℃浠诲姟' : '缂栬緫宸℃浠诲姟'"
- v-model="dialogVisitable" width="800px" @close="cancel">
- <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
- <el-row>
- <el-col :span="12">
- <el-form-item label="璁惧鍚嶇О" prop="taskId">
- <el-select v-model="form.taskId" @change="setDeviceModel">
+ <el-dialog
+ v-model="visible"
+ :title="editing ? '缂栬緫宸℃浠诲姟' : '鏂板宸℃浠诲姟'"
+ width="800px"
+ align-center
+ destroy-on-close
+ :close-on-click-modal="false"
+ @closed="reset"
+ >
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+ <el-row :gutter="24">
+ <el-col :span="12">
+ <el-form-item label="璁惧鍚嶇О" prop="taskId">
+ <el-select
+ v-model="form.taskId"
+ filterable
+ placeholder="璇烽�夋嫨璁惧"
+ style="width: 100%"
+ @change="changeDevice"
+ >
+ <el-option
+ v-for="device in deviceOptions"
+ :key="device.id"
+ :label="device.deviceName"
+ :value="device.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="宸℃浜�" prop="inspector">
+ <el-select
+ v-model="form.inspector"
+ placeholder="璇烽�夋嫨宸℃浜�"
+ multiple
+ clearable
+ filterable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="user in userList"
+ :key="user.userId"
+ :label="user.nickName"
+ :value="user.userId"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
+ <el-select
+ v-model="form.frequencyType"
+ placeholder="璇烽�夋嫨棰戠巼"
+ style="width: 100%"
+ @change="handleFrequencyChange"
+ >
+ <el-option label="姣忔棩" value="DAILY" />
+ <el-option label="姣忓懆" value="WEEKLY" />
+ <el-option label="姣忔湀" value="MONTHLY" />
+ <el-option label="姣忓搴�" value="QUARTERLY" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col v-if="form.frequencyType === 'DAILY'" :span="12">
+ <el-form-item label="鎵ц鏃堕棿" prop="frequencyDetail">
+ <el-time-picker
+ v-model="form.frequencyDetail"
+ placeholder="閫夋嫨鏃堕棿"
+ format="HH:mm"
+ value-format="HH:mm"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col v-if="form.frequencyType === 'WEEKLY'" :span="12">
+ <el-form-item label="鎵ц鏃ユ湡" prop="frequencyDetail">
+ <div class="frequency-fields">
+ <el-select v-model="form.week" placeholder="鏄熸湡" style="width: 50%">
<el-option
- v-for="(item, index) in deviceOptions"
- :key="index"
- :label="item.deviceName"
- :value="item.id"
- ></el-option>
+ v-for="day in weekdays"
+ :key="day.value"
+ :label="day.label"
+ :value="day.value"
+ />
</el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="宸℃浜�" prop="inspector">
- <el-select v-model="form.inspector" placeholder="璇烽�夋嫨" multiple clearable>
- <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="宸℃椤圭洰" prop="inspectionProject">
- <el-input v-model="form.inspectionProject" placeholder="璇疯緭鍏ュ贰妫�椤圭洰" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="澶囨敞" prop="remarks">
- <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" :autosize="{ minRows: 2, maxRows: 6 }" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="鏄惁鍚敤" prop="isEnabled">
- <el-radio-group v-model="form.isEnabled">
- <el-radio :value="1">鏄�</el-radio>
- <el-radio :value="0">鍚�</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
- <el-select v-model="form.frequencyType" placeholder="璇烽�夋嫨" clearable>
- <el-option label="姣忔棩" value="DAILY"/>
- <el-option label="姣忓懆" value="WEEKLY"/>
- <el-option label="姣忔湀" value="MONTHLY"/>
- <!-- <el-option label="瀛e害" value="QUARTERLY"/> -->
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-time-picker v-model="form.frequencyDetail" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
- value-format="HH:mm" />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-select v-model="form.week" placeholder="璇烽�夋嫨" clearable style="width: 50%">
- <el-option label="鍛ㄤ竴" value="MON"/>
- <el-option label="鍛ㄤ簩" value="TUE"/>
- <el-option label="鍛ㄤ笁" value="WED"/>
- <el-option label="鍛ㄥ洓" value="THU"/>
- <el-option label="鍛ㄤ簲" value="FRI"/>
- <el-option label="鍛ㄥ叚" value="SAT"/>
- <el-option label="鍛ㄦ棩" value="SUN"/>
- </el-select>
- <el-time-picker v-model="form.time" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
- value-format="HH:mm" style="width: 50%"/>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-date-picker
- v-model="form.frequencyDetail"
- type="datetime"
- clearable
- placeholder="閫夋嫨寮�濮嬫棩鏈�"
- format="DD,HH:mm"
- value-format="DD,HH:mm"
+ <el-time-picker
+ v-model="form.time"
+ placeholder="鏃堕棿"
+ format="HH:mm"
+ value-format="HH:mm"
+ style="width: 50%"
/>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-date-picker
- v-model="form.frequencyDetail"
- type="datetime"
+ </div>
+ </el-form-item>
+ </el-col>
+ <el-col v-if="form.frequencyType === 'MONTHLY'" :span="12">
+ <el-form-item label="鎵ц鏃ユ湡" prop="frequencyDetail">
+ <el-date-picker
+ v-model="form.frequencyDetail"
+ type="datetime"
+ clearable
+ placeholder="閫夋嫨寮�濮嬫棩鏈�"
+ format="DD,HH:mm"
+ value-format="DD,HH:mm"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col v-if="form.frequencyType === 'QUARTERLY'" :span="12">
+ <el-form-item label="鎵ц鏃ユ湡" prop="frequencyDetail">
+ <el-date-picker
+ v-model="form.frequencyDetail"
+ type="datetime"
+ clearable
+ placeholder="閫夋嫨寮�濮嬫棩鏈�"
+ format="MM,DD,HH:mm"
+ value-format="MM,DD,HH:mm"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏄惁鍚敤" prop="isEnabled">
+ <el-radio-group v-model="form.isEnabled"
+ ><el-radio :value="1">鍚敤</el-radio
+ ><el-radio :value="0">鍋滅敤</el-radio></el-radio-group
+ >
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="宸℃鍐呭" prop="inspectionItemIds">
+ <div class="items-field">
+ <div class="items-toolbar">
+ <el-button
+ type="primary"
+ plain
+ :disabled="!form.taskId || !form.frequencyType"
+ @click="selectorVisible = true"
+ >閫夋嫨宸℃鍐呭</el-button
+ >
+ <span class="muted">{{ selectionHint }}</span>
+ </div>
+ <div class="custom-input">
+ <el-input
+ v-model="customItemProject"
+ maxlength="200"
clearable
- placeholder="閫夋嫨寮�濮嬫棩鏈�"
- format="MM,DD,HH:mm"
- value-format="MM,DD,HH:mm"
- />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="submitForm">淇濆瓨</el-button>
- <el-button @click="cancel">鍙栨秷</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
+ placeholder="杈撳叆鏈换鍔′笓鐢ㄧ殑宸℃椤圭洰"
+ />
+ <el-input
+ v-model="customItemContent"
+ maxlength="2000"
+ clearable
+ placeholder="杈撳叆椤圭洰瀵瑰簲鐨勫贰妫�鍐呭"
+ @keyup.enter="addCustomItem"
+ />
+ <el-button
+ :disabled="!customItemProject.trim() || !customItemContent.trim()"
+ @click="addCustomItem"
+ >娣诲姞</el-button
+ >
+ </div>
+ <div v-if="displayItems.length" class="selected-items">
+ <div v-for="(item, index) in displayItems" :key="item.key" class="selected-item">
+ <div class="selected-item-title">
+ <b>{{ index + 1 }}. {{ item.itemProject }}</b>
+ <el-button link type="danger" @click="removeTaskItem(item)">绉婚櫎</el-button>
+ </div>
+ <div class="selected-item-content">{{ item.itemContent }}</div>
+ </div>
+ </div>
+ <el-empty v-else description="鏆傛湭閫夋嫨宸℃鍐呭" :image-size="50" />
+ </div>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="澶囨敞"
+ ><el-input
+ v-model="form.remarks"
+ type="textarea"
+ :rows="2"
+ maxlength="500"
+ show-word-limit
+ /></el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <el-button @click="visible = false">鍙栨秷</el-button>
+ <el-button type="primary" :loading="saving" @click="submit">淇濆瓨</el-button>
+ </template>
+ </el-dialog>
+ <InspectionItemSelector
+ v-model:visible="selectorVisible"
+ :selected-items="form.inspectionItems"
+ :device-ledger-id="form.taskId"
+ :frequency-type="form.frequencyType"
+ @confirm="setSelectedItems"
+ />
</template>
<script setup>
-import {reactive, ref, getCurrentInstance, toRefs} from "vue";
-import useUserStore from '@/store/modules/user'
-import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
+import { computed, getCurrentInstance, reactive, ref } from "vue";
+import useUserStore from "@/store/modules/user";
+import { addOrEditTimingTask, getInspectionItemList } from "@/api/inspectionManagement/index.js";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+import InspectionItemSelector from "./InspectionItemSelector.vue";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits()
-const userStore = useUserStore()
-const dialogVisitable = ref(false);
-const operationType = ref('add');
+const { proxy } = getCurrentInstance();
+const emit = defineEmits(["closeDia"]);
+const userStore = useUserStore();
+const visible = ref(false);
+const editing = ref(false);
+const saving = ref(false);
+const selectorVisible = ref(false);
+const formRef = ref();
const deviceOptions = ref([]);
-const data = reactive({
- form: {
- taskId: undefined,
- taskName: undefined,
- inspector: '',
- inspectorIds: '',
- inspectionProject: '',
- isEnabled: 1,
- remarks: '',
- frequencyType: '',
- frequencyDetail: '',
- week: '',
- time: ''
- },
- rules: {
- taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
- inspector: [{ required: true, message: "璇疯緭鍏ュ贰妫�浜�", trigger: "blur" },],
- dateStr: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
- frequencyType: [{ required: true, message: "璇烽�夋嫨浠诲姟棰戠巼", trigger: "change" }],
- frequencyDetail: [
- {
- required: true,
- message: "璇烽�夋嫨鏃ユ湡",
- trigger: "change",
- validator: (rule, value, callback) => {
- if (!form.value.frequencyType) {
- callback()
- return
- }
- if (form.value.frequencyType === 'WEEKLY') {
- if (!form.value.week || !form.value.time) {
- callback(new Error("璇烽�夋嫨鏃ユ湡鍜屾椂闂�"))
- } else {
- callback()
- }
- } else {
- if (!value) {
- callback(new Error("璇烽�夋嫨鏃ユ湡"))
- } else {
- callback()
- }
- }
- }
- }
- ],
- week: [
- {
- required: true,
- message: "璇烽�夋嫨鏄熸湡",
- trigger: "change",
- validator: (rule, value, callback) => {
- if (form.value.frequencyType === 'WEEKLY' && !value) {
- callback(new Error("璇烽�夋嫨鏄熸湡"))
- } else {
- callback()
- }
- }
- }
- ],
- time: [
- {
- required: true,
- message: "璇烽�夋嫨鏃堕棿",
- trigger: "change",
- validator: (rule, value, callback) => {
- if (form.value.frequencyType === 'WEEKLY' && !value) {
- callback(new Error("璇烽�夋嫨鏃堕棿"))
- } else {
- callback()
- }
- }
- }
- ]
- }
-})
-const { form, rules } = toRefs(data)
-const userList = ref([])
-
-const loadDeviceName = async () => {
- const { data } = await getDeviceLedger();
- deviceOptions.value = data;
+const userList = ref([]);
+const customItems = ref([]);
+const customItemProject = ref("");
+const customItemContent = ref("");
+let defaultItemsRequestId = 0;
+const weekdays = [
+ { label: "鍛ㄤ竴", value: "MON" },
+ { label: "鍛ㄤ簩", value: "TUE" },
+ { label: "鍛ㄤ笁", value: "WED" },
+ { label: "鍛ㄥ洓", value: "THU" },
+ { label: "鍛ㄤ簲", value: "FRI" },
+ { label: "鍛ㄥ叚", value: "SAT" },
+ { label: "鍛ㄦ棩", value: "SUN" },
+];
+const blankForm = () => ({
+ id: undefined,
+ taskId: undefined,
+ taskName: "",
+ inspector: [],
+ inspectorIds: "",
+ inspectionItemIds: [],
+ inspectionItems: [],
+ isEnabled: 1,
+ remarks: "",
+ frequencyType: "",
+ frequencyDetail: "",
+ week: "",
+ time: "",
+});
+const form = reactive(blankForm());
+const rules = {
+ taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
+ inspector: [{ required: true, message: "璇烽�夋嫨宸℃浜�", trigger: "change" }],
+ frequencyType: [{ required: true, message: "璇烽�夋嫨浠诲姟棰戠巼", trigger: "change" }],
+ frequencyDetail: [
+ {
+ validator: (_, value, callback) => {
+ const valid =
+ form.frequencyType === "DAILY"
+ ? !!value
+ : form.frequencyType === "WEEKLY"
+ ? !!form.week && !!form.time
+ : form.frequencyType === "MONTHLY"
+ ? !!form.frequencyDetail
+ : form.frequencyType === "QUARTERLY"
+ ? !!form.frequencyDetail
+ : false;
+ valid ? callback() : callback(new Error("璇烽�夋嫨宸℃鎵ц鏃ユ湡鍜屾椂闂�"));
+ },
+ trigger: "change",
+ },
+ ],
+ inspectionItemIds: [
+ {
+ validator: (_, value, callback) =>
+ form.inspectionItems.length || customItems.value.length
+ ? callback()
+ : callback(new Error("璇烽�夋嫨鎴栨坊鍔犺嚦灏戜竴涓贰妫�鍐呭")),
+ trigger: "change",
+ },
+ ],
};
+const displayItems = computed(() => [
+ ...form.inspectionItems.map((item) => ({ ...item, key: `item-${item.id}` })),
+ ...customItems.value.map((item) => ({ ...item, key: item.key, isCustom: true })),
+]);
+const frequencyDetail = computed(() => {
+ if (form.frequencyType === "WEEKLY") return `${form.week},${form.time}`;
+ if (form.frequencyType === "MONTHLY") return form.frequencyDetail;
+ return form.frequencyDetail;
+});
+const selectionHint = computed(() => {
+ if (!form.taskId || !form.frequencyType)
+ return "璇峰厛閫夋嫨璁惧鍜岄鐜囷紝鍖归厤鐨勮澶囧贰妫�鍐呭灏嗚嚜鍔ㄥ甫鍑�";
+ return displayItems.value.length
+ ? `宸查�� ${displayItems.value.length} 椤癸紝鍙户缁坊鍔犳湰浠诲姟涓撶敤鍐呭鎴栭�夋嫨閫氱敤鍐呭`
+ : "璇ヨ澶囧拰棰戠巼鏆傛棤榛樿宸℃鍐呭锛屽彲鎵嬪姩娣诲姞鎴栭�夋嫨閫氱敤鍐呭";
+});
-const setDeviceModel = (id) => {
- const option = deviceOptions.value.find((item) => item.id === id);
- if (option) {
- form.value.taskName = option.deviceName;
- }
-}
-
-// 鎵撳紑寮规
const openDialog = async (type, row) => {
- dialogVisitable.value = true
- operationType.value = type
-
- // 閲嶇疆琛ㄥ崟
- resetForm();
-
- // 鍔犺浇鐢ㄦ埛鍒楄〃
- userListNoPageByTenantId().then((res) => {
- userList.value = res.data;
- });
-
- // 鍔犺浇璁惧鍒楄〃
- await loadDeviceName();
-
- if (type === 'edit' && row) {
- form.value = {...row}
- form.value.inspector = form.value.inspectorIds.split(',').map(Number)
-
- // 澶勭悊WEEKLY棰戠巼鐨勫洖鏄撅細灏唂requencyDetail鎷嗗垎涓簑eek鍜宼ime
- if (form.value.frequencyType === 'WEEKLY' && form.value.frequencyDetail) {
- const parts = form.value.frequencyDetail.split(',')
- form.value.week = parts[0] || ''
- form.value.time = parts[1] || ''
- form.value.frequencyDetail = ''
- }
-
- // 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
- if (form.value.taskId) {
- setDeviceModel(form.value.taskId);
+ editing.value = type === "edit";
+ Object.assign(form, blankForm());
+ customItems.value = [];
+ customItemProject.value = "";
+ customItemContent.value = "";
+ await Promise.all([
+ getDeviceLedger().then(({ data }) => {
+ deviceOptions.value = data || [];
+ }),
+ userListNoPageByTenantId().then(({ data }) => {
+ userList.value = data || [];
+ }),
+ ]);
+ if (editing.value && row) {
+ Object.assign(form, blankForm(), row);
+ form.inspector = String(row.inspectorIds || "")
+ .split(",")
+ .filter(Boolean)
+ .map(Number);
+ const taskItems = row.inspectionItems || [];
+ form.inspectionItems = taskItems
+ .filter((item) => item.inspectionItemId != null)
+ .map((item) => ({ ...item, id: item.inspectionItemId }));
+ customItems.value = taskItems
+ .filter((item) => item.inspectionItemId == null)
+ .map((item, index) => ({ ...item, key: `custom-saved-${index}` }));
+ if (form.frequencyType === "WEEKLY" && form.frequencyDetail) {
+ [form.week, form.time] = form.frequencyDetail.split(",");
}
}
-}
+ visible.value = true;
+};
+const setDeviceModel = (id) => {
+ const device = deviceOptions.value.find((item) => item.id === id);
+ if (device) form.taskName = device.deviceName;
+};
+const syncInspectionItems = (items) => {
+ form.inspectionItems = items.map((item) => ({ ...item, id: item.inspectionItemId || item.id }));
+ form.inspectionItemIds = form.inspectionItems.map((item) => item.id);
+};
+const clearInspectionItems = () => syncInspectionItems([]);
+const loadDefaultInspectionItems = async () => {
+ const requestId = ++defaultItemsRequestId;
+ const deviceLedgerId = form.taskId;
+ const frequencyType = form.frequencyType;
+ clearInspectionItems();
+ if (!deviceLedgerId || !frequencyType) return;
-// 鍏抽棴瀵硅瘽妗�
-const cancel = () => {
- resetForm()
- dialogVisitable.value = false
- emit('closeDia')
-}
-
-// 閲嶇疆琛ㄥ崟鍑芥暟
-const resetForm = () => {
- if (proxy.$refs.formRef) {
- proxy.$refs.formRef.resetFields()
- }
- // 閲嶇疆琛ㄥ崟鏁版嵁纭繚璁惧淇℃伅姝g‘閲嶇疆
- form.value = {
- taskId: undefined,
- taskName: undefined,
- inspector: '',
- inspectorIds: '',
- inspectionProject: '',
- isEnabled: 1,
- remarks: '',
- frequencyType: '',
- frequencyDetail: '',
- week: '',
- time: ''
- }
-}
-
-// 鎻愪氦琛ㄥ崟
-const submitForm = () => {
- proxy.$refs["formRef"].validate(async valid => {
- if (valid) {
- try {
- form.value.inspectorIds = form.value.inspector.join(',')
- delete form.value.inspector
-
- if (form.value.frequencyType === 'WEEKLY') {
- let frequencyDetail = ''
- frequencyDetail = form.value.week + ',' + form.value.time
- form.value.frequencyDetail = frequencyDetail
- }
-
- let res = await userStore.getInfo()
- form.value.registrantId = res.user.userId
-
- await addOrEditTimingTask(form.value)
- cancel()
- proxy.$modal.msgSuccess('鎻愪氦鎴愬姛')
- } catch (error) {
- proxy.$modal.msgError('鎻愪氦澶辫触锛岃閲嶈瘯')
- }
+ try {
+ const { code, data } = await getInspectionItemList({
+ deviceLedgerId,
+ frequencyType,
+ isActive: 1,
+ });
+ if (
+ requestId !== defaultItemsRequestId ||
+ deviceLedgerId !== form.taskId ||
+ frequencyType !== form.frequencyType
+ )
+ return;
+ if (code === 200) syncInspectionItems(data || []);
+ } catch (error) {
+ if (requestId === defaultItemsRequestId) {
+ proxy.$modal.msgError(error?.message || "鍔犺浇榛樿宸℃鍐呭澶辫触");
}
- })
-}
-defineExpose({ openDialog })
+ }
+};
+const changeDevice = (id) => {
+ setDeviceModel(id);
+ loadDefaultInspectionItems();
+};
+const handleFrequencyChange = () => loadDefaultInspectionItems();
+const setSelectedItems = (items) => {
+ syncInspectionItems(items);
+ formRef.value?.validateField("inspectionItemIds");
+};
+const addCustomItem = () => {
+ const itemProject = customItemProject.value.trim();
+ const itemContent = customItemContent.value.trim();
+ if (!itemProject || !itemContent) return;
+ if (displayItems.value.some((item) => item.itemProject === itemProject)) {
+ proxy.$modal.msgWarning("宸插瓨鍦ㄧ浉鍚岀殑宸℃椤圭洰");
+ return;
+ }
+ customItems.value = [
+ ...customItems.value,
+ { key: `custom-${Date.now()}`, itemProject, itemContent },
+ ];
+ customItemProject.value = "";
+ customItemContent.value = "";
+ formRef.value?.validateField("inspectionItemIds");
+};
+const removeTaskItem = (item) => {
+ if (item.isCustom)
+ customItems.value = customItems.value.filter((custom) => custom.key !== item.key);
+ else
+ form.inspectionItems = form.inspectionItems.filter(
+ (selected) => String(selected.id) !== String(item.id)
+ );
+ form.inspectionItemIds = form.inspectionItems.map((item) => item.id);
+ formRef.value?.validateField("inspectionItemIds");
+};
+const reset = () => {
+ defaultItemsRequestId += 1;
+ Object.assign(form, blankForm());
+ customItems.value = [];
+ customItemProject.value = "";
+ customItemContent.value = "";
+ formRef.value?.clearValidate();
+};
+const submit = async () => {
+ const valid = await formRef.value
+ ?.validate()
+ .then(() => true)
+ .catch(() => false);
+ if (!valid) return;
+ saving.value = true;
+ try {
+ const userInfo = await userStore.getInfo();
+ const payload = {
+ ...form,
+ inspectorIds: form.inspector.join(","),
+ frequencyDetail: frequencyDetail.value,
+ registrantId: userInfo.user.userId,
+ inspectionItemIds: form.inspectionItems.map((item) => item.id),
+ customItems: customItems.value.map((item) => ({
+ itemProject: item.itemProject,
+ itemContent: item.itemContent,
+ })),
+ };
+ delete payload.inspector;
+ delete payload.inspectionItems;
+ delete payload.week;
+ delete payload.time;
+ await addOrEditTimingTask(payload);
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ visible.value = false;
+ emit("closeDia");
+ } catch (error) {
+ proxy.$modal.msgError(error?.message || "鎻愪氦澶辫触锛岃閲嶈瘯");
+ } finally {
+ saving.value = false;
+ }
+};
+defineExpose({ openDialog });
</script>
<style scoped>
-
-</style>
\ No newline at end of file
+.frequency-fields {
+ display: flex;
+ width: 100%;
+ gap: 8px;
+}
+.items-field {
+ width: 100%;
+}
+.items-toolbar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 10px;
+}
+.custom-input {
+ display: flex;
+ gap: 8px;
+ margin-bottom: 10px;
+}
+.custom-input .el-input:first-child {
+ flex: 0 0 30%;
+}
+.custom-input .el-input:nth-child(2) {
+ flex: 1;
+ min-width: 0;
+}
+.muted {
+ color: #909399;
+ font-size: 13px;
+}
+.selected-items {
+ max-height: 250px;
+ overflow-y: auto;
+ border: 1px solid #e4e7ed;
+ border-radius: 4px;
+}
+.selected-item {
+ padding: 10px 12px;
+ border-bottom: 1px solid #ebeef5;
+}
+.selected-item:last-child {
+ border-bottom: 0;
+}
+.selected-item-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ color: #303133;
+}
+.selected-item-content {
+ margin-top: 6px;
+ color: #606266;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue b/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
index 481ea85..de550dfb 100644
--- a/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
+++ b/src/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue
@@ -1,27 +1,29 @@
<template>
- <FormDialog v-model="dialogVisible"
- :title="operationType === 'view' ? '宸℃璁板綍璇︽儏' : '涓婁紶宸℃璁板綍'"
- width="980px"
- :operation-type="operationType"
- @close="handleClose"
- @cancel="handleClose">
+ <FormDialog
+ v-model="dialogVisible"
+ :title="operationType === 'view' ? '宸℃璁板綍璇︽儏' : '涓婁紶宸℃璁板綍'"
+ width="980px"
+ :operation-type="operationType"
+ @close="handleClose"
+ @cancel="handleClose"
+ >
<main class="upload-content">
- <el-card v-if="taskInfo"
- class="section-card">
- <el-descriptions :column="2"
- border>
+ <el-card v-if="taskInfo" class="section-card">
+ <el-descriptions :column="2" border>
<el-descriptions-item label="宸℃浠诲姟鍚嶇О">
{{ taskInfo.taskName || "-" }}
</el-descriptions-item>
<el-descriptions-item label="宸℃椤圭洰">
- {{ taskInfo.inspectionProject || "-" }}
+ {{ inspectionProjectSummary || "-" }}
</el-descriptions-item>
<el-descriptions-item label="鎵ц宸℃浜�">
<template v-if="formattedInspector && formattedInspector.length">
- <el-tag v-for="tag in formattedInspector"
- :key="tag"
- size="small"
- style="margin-right: 4px">
+ <el-tag
+ v-for="tag in formattedInspector"
+ :key="tag"
+ size="small"
+ style="margin-right: 4px"
+ >
{{ tag }}
</el-tag>
</template>
@@ -44,47 +46,66 @@
</el-descriptions-item>
</el-descriptions>
</el-card>
+ <el-card v-if="inspectionItems.length" class="section-card inspection-items-card">
+ <div class="section-heading">
+ <h3>宸℃鍐呭</h3>
+ <span>宸插畬鎴� {{ completedItemIds.length }} / {{ inspectionItems.length }} 椤�</span>
+ </div>
+ <div v-for="(item, index) in inspectionItems" :key="item.id" class="inspection-item-row">
+ <div class="inspection-item-copy">
+ <div class="inspection-item-title">{{ index + 1 }}. {{ item.itemProject }}</div>
+ <div class="inspection-item-content">{{ item.itemContent }}</div>
+ </div>
+ <el-checkbox
+ :model-value="isItemCompleted(item)"
+ :disabled="operationType === 'view'"
+ @change="(checked) => toggleItem(item, checked)"
+ >
+ {{ isItemCompleted(item) ? "宸插畬鎴�" : "鏈畬鎴�" }}
+ </el-checkbox>
+ </div>
+ </el-card>
<el-card class="section-card">
<h3>宸℃鐘舵��</h3>
- <el-radio-group v-model="hasException"
- :disabled="operationType === 'view'">
+ <el-radio-group v-model="hasException" :disabled="operationType === 'view'">
<el-radio-button :value="false">姝e父</el-radio-button>
<el-radio-button :value="true">瀛樺湪寮傚父</el-radio-button>
</el-radio-group>
</el-card>
- <el-card v-if="hasException === true"
- class="section-card">
+ <el-card v-if="hasException === true" class="section-card">
<h3>寮傚父鎻忚堪</h3>
- <el-input v-model="abnormalDescription"
- type="textarea"
- maxlength="500"
- show-word-limit
- :rows="4"
- :disabled="operationType === 'view'"
- placeholder="璇锋弿杩板紓甯告儏鍐�..." />
+ <el-input
+ v-model="abnormalDescription"
+ type="textarea"
+ maxlength="500"
+ show-word-limit
+ :rows="4"
+ :disabled="operationType === 'view'"
+ placeholder="璇锋弿杩板紓甯告儏鍐�..."
+ />
</el-card>
- <el-card v-if="hasException === true"
- class="section-card">
- <div class="upload-buttons"
- v-if="operationType !== 'view'">
- <el-upload :show-file-list="false"
- :http-request="uploadFile"
- :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
- accept="image/*">
- <el-button type="primary"
- :loading="uploading">
+ <el-card v-if="hasException === true" class="section-card">
+ <div class="upload-buttons" v-if="operationType !== 'view'">
+ <el-upload
+ :show-file-list="false"
+ :http-request="uploadFile"
+ :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
+ accept="image/*"
+ >
+ <el-button type="primary" :loading="uploading">
<el-icon>
<Camera />
</el-icon>
閫夋嫨鍥剧墖
</el-button>
</el-upload>
- <el-upload :show-file-list="false"
- :http-request="uploadFile"
- :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
- accept="video/*">
- <el-button type="success"
- :loading="uploading">
+ <el-upload
+ :show-file-list="false"
+ :http-request="uploadFile"
+ :disabled="beforeModelValue.length >= uploadConfig.limit || uploading"
+ accept="video/*"
+ >
+ <el-button type="success" :loading="uploading">
<el-icon>
<VideoCamera />
</el-icon>
@@ -92,35 +113,36 @@
</el-button>
</el-upload>
</div>
- <el-progress v-if="uploading"
- :percentage="uploadProgress"
- class="upload-progress" />
- <div v-if="beforeModelValue.length"
- class="file-list">
- <div v-for="(file, index) in beforeModelValue"
- :key="file.uid || file.id || index"
- class="file-item">
+ <el-progress v-if="uploading" :percentage="uploadProgress" class="upload-progress" />
+ <div v-if="beforeModelValue.length" class="file-list">
+ <div
+ v-for="(file, index) in beforeModelValue"
+ :key="file.uid || file.id || index"
+ class="file-item"
+ >
<div class="file-preview-container">
- <el-image v-if="file.type === 'image' || !file.type"
- :src="file.url || file.tempFilePath || file.path || file.downloadUrl"
- fit="cover"
- class="file-preview"
- :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]"
- preview-teleported />
- <div v-else
- class="video-preview"
- @click="previewVideo(file)">
+ <el-image
+ v-if="file.type === 'image' || !file.type"
+ :src="file.url || file.tempFilePath || file.path || file.downloadUrl"
+ fit="cover"
+ class="file-preview"
+ :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]"
+ preview-teleported
+ />
+ <div v-else class="video-preview" @click="previewVideo(file)">
<el-icon>
<VideoCamera />
</el-icon>
<span>瑙嗛</span>
</div>
- <el-button class="delete-btn"
- type="danger"
- circle
- size="small"
- v-if="operationType !== 'view'"
- @click="removeFile(index)">
+ <el-button
+ class="delete-btn"
+ type="danger"
+ circle
+ size="small"
+ v-if="operationType !== 'view'"
+ @click="removeFile(index)"
+ >
<el-icon>
<Close />
</el-icon>
@@ -134,559 +156,614 @@
</div>
</div>
</div>
- <el-empty v-else
- :description="operationType === 'view' ? '鏆傛棤寮傚父鐓х墖鎴栬棰�' : '璇烽�夋嫨瑕佷笂浼犵殑宸℃鍥剧墖鎴栬棰�'" />
+ <el-empty
+ v-else
+ :description="
+ operationType === 'view' ? '鏆傛棤寮傚父鐓х墖鎴栬棰�' : '璇烽�夋嫨瑕佷笂浼犵殑宸℃鍥剧墖鎴栬棰�'
+ "
+ />
</el-card>
- <el-result v-if="hasException === false"
- icon="success"
- title="璁惧杩愯姝e父"
- :sub-title="operationType === 'view' ? '' : '鏃犻渶涓婁紶鐓х墖'" />
+ <el-result
+ v-if="hasException === false"
+ icon="success"
+ title="璁惧杩愯姝e父"
+ :sub-title="operationType === 'view' ? '' : '鏃犻渶涓婁紶鐓х墖'"
+ />
</main>
<template #footer>
<footer class="footer-buttons">
- <el-button type="primary"
- v-if="operationType !== 'view'"
- @click="submitUpload">鎻愪氦</el-button>
- <el-button v-if="hasException === true && operationType !== 'view'"
- type="warning"
- @click="goToRepair">
+ <el-button type="primary" v-if="operationType !== 'view'" @click="submitUpload"
+ >鎻愪氦</el-button
+ >
+ <el-button
+ v-if="hasException === true && operationType !== 'view'"
+ type="warning"
+ @click="goToRepair"
+ >
鏂板鎶ヤ慨
</el-button>
- <el-button @click="handleClose">{{ operationType === 'view' ? '鍏抽棴' : '鍙栨秷' }}</el-button>
+ <el-button @click="handleClose">{{ operationType === "view" ? "鍏抽棴" : "鍙栨秷" }}</el-button>
</footer>
</template>
</FormDialog>
- <el-dialog v-model="showVideoDialog"
- :title="currentVideoFile?.originalFilename || currentVideoFile?.name || '瑙嗛棰勮'"
- width="720px">
- <video v-if="currentVideoFile"
- :src="currentVideoFile.url || currentVideoFile.downloadUrl"
- class="video-player"
- controls
- autoplay />
+ <el-dialog
+ v-model="showVideoDialog"
+ :title="currentVideoFile?.originalFilename || currentVideoFile?.name || '瑙嗛棰勮'"
+ width="720px"
+ >
+ <video
+ v-if="currentVideoFile"
+ :src="currentVideoFile.url || currentVideoFile.downloadUrl"
+ class="video-player"
+ controls
+ autoplay
+ />
</el-dialog>
</template>
<script setup>
- import { computed, ref } from "vue";
- import { useRouter } from "vue-router";
- import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
- import { Camera, Close, VideoCamera } from "@element-plus/icons-vue";
- import axios from "axios";
- import dayjs from "dayjs";
- import FormDialog from "@/components/Dialog/FormDialog.vue";
- import { uploadInspectionTask } from "@/api/inspectionManagement/index.js";
- import { getToken } from "@/utils/auth";
+import { computed, ref } from "vue";
+import { useRouter } from "vue-router";
+import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
+import { Camera, Close, VideoCamera } from "@element-plus/icons-vue";
+import axios from "axios";
+import dayjs from "dayjs";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { uploadInspectionTask } from "@/api/inspectionManagement/index.js";
+import { getToken } from "@/utils/auth";
- const emit = defineEmits(["closeDia", "success"]);
- const router = useRouter();
+const emit = defineEmits(["closeDia", "success"]);
+const router = useRouter();
- const dialogVisible = ref(false);
- const taskInfo = ref(null);
- const uploading = ref(false);
- const uploadProgress = ref(0);
- const operationType = ref("add"); // add, view
+const dialogVisible = ref(false);
+const taskInfo = ref(null);
+const uploading = ref(false);
+const uploadProgress = ref(0);
+const operationType = ref("add"); // add, view
- const beforeModelValue = ref([]);
+const beforeModelValue = ref([]);
+const inspectionItems = ref([]);
+const completedItemIds = ref([]);
+const inspectionProjectSummary = computed(() =>
+ [...new Set(inspectionItems.value.map((item) => item.itemProject).filter(Boolean))].join("銆�")
+);
- const formattedInspector = computed(() => {
- if (!taskInfo.value?.inspector) return [];
- if (Array.isArray(taskInfo.value.inspector)) return taskInfo.value.inspector;
- if (typeof taskInfo.value.inspector === "string") {
- return taskInfo.value.inspector
- .split(",")
- .map(s => s.trim())
- .filter(s => s);
+const formattedInspector = computed(() => {
+ if (!taskInfo.value?.inspector) return [];
+ if (Array.isArray(taskInfo.value.inspector)) return taskInfo.value.inspector;
+ if (typeof taskInfo.value.inspector === "string") {
+ return taskInfo.value.inspector
+ .split(",")
+ .map((s) => s.trim())
+ .filter((s) => s);
+ }
+ return [taskInfo.value.inspector];
+});
+
+const formatFrequencyType = (type) => {
+ const mapping = {
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害",
+ };
+ return mapping[type] || type;
+};
+
+const formatFrequencyDetail = (detail) => {
+ if (typeof detail !== "string") return detail;
+ const replacements = {
+ MON: "鍛ㄤ竴",
+ TUE: "鍛ㄤ簩",
+ WED: "鍛ㄤ笁",
+ THU: "鍛ㄥ洓",
+ FRI: "鍛ㄤ簲",
+ SAT: "鍛ㄥ叚",
+ SUN: "鍛ㄦ棩",
+ };
+ return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
+};
+
+const formatDateTime = (date) => {
+ if (!date) return "-";
+ return dayjs(date).format("YYYY-MM-DD");
+};
+
+const hasException = ref(null);
+const abnormalDescription = ref("");
+
+const showVideoDialog = ref(false);
+const currentVideoFile = ref(null);
+
+const uploadConfig = {
+ action: "/common/upload",
+ limit: 10,
+ fileSize: 50,
+ fileType: ["jpg", "jpeg", "png", "mp4", "mov"],
+};
+
+const uploadFileUrl = computed(() => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}`);
+
+const processFileUrl = (fileUrl) => {
+ if (!fileUrl) return "";
+
+ let currentUrl = String(fileUrl);
+ if (currentUrl.includes("\\")) {
+ const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads");
+ if (uploadsIndex > -1) {
+ currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`;
+ } else {
+ const fileName = currentUrl.split("\\").pop();
+ currentUrl = `/uploads/${fileName}`;
}
- return [taskInfo.value.inspector];
+ }
+
+ if (currentUrl && !currentUrl.startsWith("http")) {
+ if (!currentUrl.startsWith("/")) {
+ currentUrl = `/${currentUrl}`;
+ }
+ currentUrl = __BASE_API__ + currentUrl;
+ }
+
+ return currentUrl;
+};
+
+const normalizeList = (list, fileType) => {
+ if (!Array.isArray(list)) return [];
+
+ return list.filter(Boolean).map((item) => {
+ let currentType = item.type;
+ if (!currentType && item.contentType) {
+ currentType = item.contentType.startsWith("video") ? "video" : "image";
+ } else if (!currentType) {
+ currentType = fileType || "image";
+ }
+
+ return {
+ ...item,
+ url: processFileUrl(item.url || item.previewURL || item.downloadUrl || item.path || ""),
+ downloadUrl: processFileUrl(
+ item.downloadUrl || item.url || item.previewURL || item.path || ""
+ ),
+ name: item.name || item.originalFilename || item.bucketFilename,
+ tempId: item.tempId || item.id || item.tempFileId,
+ tempFileId: item.tempFileId || item.tempId || item.id,
+ size: item.size || item.byteSize || 0,
+ type: currentType,
+ status: "success",
+ uid: item.uid || `${Date.now()}-${Math.random()}`,
+ };
});
+};
- const formatFrequencyType = type => {
- const mapping = {
- DAILY: "姣忔棩",
- WEEKLY: "姣忓懆",
- MONTHLY: "姣忔湀",
- QUARTERLY: "瀛e害",
- };
- return mapping[type] || type;
- };
+const resetState = () => {
+ taskInfo.value = null;
+ beforeModelValue.value = [];
+ inspectionItems.value = [];
+ completedItemIds.value = [];
+ hasException.value = null;
+ abnormalDescription.value = "";
+ uploading.value = false;
+ uploadProgress.value = 0;
+ showVideoDialog.value = false;
+ currentVideoFile.value = null;
+ operationType.value = "add";
+};
- const formatFrequencyDetail = detail => {
- if (typeof detail !== "string") return detail;
- const replacements = {
- MON: "鍛ㄤ竴",
- TUE: "鍛ㄤ簩",
- WED: "鍛ㄤ笁",
- THU: "鍛ㄥ洓",
- FRI: "鍛ㄤ簲",
- SAT: "鍛ㄥ叚",
- SUN: "鍛ㄦ棩",
- };
- return detail.replace(
- /MON|TUE|WED|THU|FRI|SAT|SUN/g,
- match => replacements[match]
- );
- };
+const openDialog = (type, row) => {
+ operationType.value = type || "add";
+ const raw = JSON.parse(JSON.stringify(row?.__raw || row || {}));
+ taskInfo.value = raw;
+ inspectionItems.value = Array.isArray(raw.inspectionItems) ? raw.inspectionItems : [];
+ completedItemIds.value = inspectionItems.value
+ .filter((item) => Number(item.itemStatus) === 1)
+ .map((item) => item.id);
- const formatDateTime = date => {
- if (!date) return "-";
- return dayjs(date).format("YYYY-MM-DD");
- };
-
- const hasException = ref(null);
- const abnormalDescription = ref("");
-
- const showVideoDialog = ref(false);
- const currentVideoFile = ref(null);
-
- const uploadConfig = {
- action: "/common/upload",
- limit: 10,
- fileSize: 50,
- fileType: ["jpg", "jpeg", "png", "mp4", "mov"],
- };
-
- const uploadFileUrl = computed(
- () => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}`
+ beforeModelValue.value = normalizeList(
+ raw.commonFileListBeforeVO || raw.commonFileListBefore || [],
+ "image"
);
- const processFileUrl = fileUrl => {
- if (!fileUrl) return "";
+ abnormalDescription.value = raw.abnormalDescription || "";
- let currentUrl = String(fileUrl);
- if (currentUrl.includes("\\")) {
- const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads");
- if (uploadsIndex > -1) {
- currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`;
- } else {
- const fileName = currentUrl.split("\\").pop();
- currentUrl = `/uploads/${fileName}`;
- }
- }
-
- if (currentUrl && !currentUrl.startsWith("http")) {
- if (!currentUrl.startsWith("/")) {
- currentUrl = `/${currentUrl}`;
- }
- currentUrl = __BASE_API__ + currentUrl;
- }
-
- return currentUrl;
- };
-
- const normalizeList = (list, fileType) => {
- if (!Array.isArray(list)) return [];
-
- return list.filter(Boolean).map(item => {
- let currentType = item.type;
- if (!currentType && item.contentType) {
- currentType = item.contentType.startsWith("video") ? "video" : "image";
- } else if (!currentType) {
- currentType = fileType || "image";
- }
-
- return {
- ...item,
- url: processFileUrl(
- item.url || item.previewURL || item.downloadUrl || item.path || ""
- ),
- downloadUrl: processFileUrl(
- item.downloadUrl || item.url || item.previewURL || item.path || ""
- ),
- name: item.name || item.originalFilename || item.bucketFilename,
- tempId: item.tempId || item.id || item.tempFileId,
- tempFileId: item.tempFileId || item.tempId || item.id,
- size: item.size || item.byteSize || 0,
- type: currentType,
- status: "success",
- uid: item.uid || `${Date.now()}-${Math.random()}`,
- };
- });
- };
-
- const resetState = () => {
- taskInfo.value = null;
- beforeModelValue.value = [];
+ if (raw.hasException !== undefined && raw.hasException !== null) {
+ hasException.value = raw.hasException;
+ } else if (raw.inspectionResult !== undefined && raw.inspectionResult !== null) {
+ hasException.value = String(raw.inspectionResult) === "0";
+ } else {
hasException.value = null;
- abnormalDescription.value = "";
- uploading.value = false;
- uploadProgress.value = 0;
- showVideoDialog.value = false;
- currentVideoFile.value = null;
- operationType.value = "add";
- };
+ }
- const openDialog = (type, row) => {
- operationType.value = type || "add";
- const raw = JSON.parse(JSON.stringify(row?.__raw || row || {}));
- taskInfo.value = raw;
+ if (hasException.value !== true && beforeModelValue.value.length) {
+ hasException.value = true;
+ }
- beforeModelValue.value = normalizeList(
- raw.commonFileListBeforeVO || raw.commonFileListBefore || [],
- "image"
+ dialogVisible.value = true;
+};
+
+const isItemCompleted = (item) => completedItemIds.value.includes(item.id);
+const toggleItem = (item, checked) => {
+ const completed = new Set(completedItemIds.value);
+ if (checked) completed.add(item.id);
+ else completed.delete(item.id);
+ completedItemIds.value = [...completed];
+};
+
+const handleClose = () => {
+ dialogVisible.value = false;
+ resetState();
+ emit("closeDia");
+};
+
+const previewVideo = (file) => {
+ currentVideoFile.value = file;
+ showVideoDialog.value = true;
+};
+
+const uploadFile = async (uploadRequest) => {
+ const rawFile = uploadRequest.file;
+
+ if (beforeModelValue.value.length >= uploadConfig.limit) {
+ ElMessage.warning(`鏈�澶氬彧鑳介�夋嫨${uploadConfig.limit}涓枃浠禶);
+ return;
+ }
+
+ const ext = rawFile.name.split(".").pop()?.toLowerCase();
+ if (!uploadConfig.fileType.includes(ext)) {
+ ElMessage.warning(`鏂囦欢鏍煎紡涓嶆敮鎸侊紝璇蜂笂浼� ${uploadConfig.fileType.join("/")} 鏍煎紡`);
+ return;
+ }
+
+ if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) {
+ ElMessage.warning(`鏂囦欢澶у皬涓嶈兘瓒呰繃 ${uploadConfig.fileSize}MB`);
+ return;
+ }
+
+ const token = getToken();
+ if (!token) {
+ ElMessage.warning("鐢ㄦ埛鏈櫥褰�");
+ return;
+ }
+
+ const formData = new FormData();
+ formData.append("files", rawFile);
+ formData.append("type", 10); // 鐢熶骇鍓嶅浐瀹氫负10
+
+ uploading.value = true;
+ uploadProgress.value = 0;
+
+ try {
+ const { data } = await axios.post(uploadFileUrl.value, formData, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "Content-Type": "multipart/form-data",
+ },
+ onUploadProgress: (event) => {
+ if (event.total) {
+ uploadProgress.value = Math.round((event.loaded / event.total) * 100);
+ }
+ },
+ });
+
+ if (data.code !== 200) {
+ ElMessage.error(data.msg || "涓婁紶澶辫触");
+ return;
+ }
+
+ const resultData = Array.isArray(data.data) ? data.data[0] : data.data;
+ const finalUrl = processFileUrl(
+ resultData.url || resultData.previewURL || resultData.downloadUrl || ""
);
+ const finalName = resultData.name || resultData.originalFilename || resultData.bucketFilename;
+ const finalId = resultData.tempId || resultData.id || resultData.tempFileId;
- abnormalDescription.value = raw.abnormalDescription || "";
+ const uploadedFile = {
+ ...resultData,
+ url: finalUrl,
+ downloadUrl: finalUrl,
+ name: finalName,
+ tempId: finalId,
+ tempFileId: resultData.tempFileId || finalId,
+ size: rawFile.size || resultData.size || resultData.byteSize || 0,
+ type: rawFile.type?.startsWith("video") ? "video" : "image",
+ status: "success",
+ uid: `${Date.now()}-${Math.random()}`,
+ };
- if (raw.hasException !== undefined && raw.hasException !== null) {
- hasException.value = raw.hasException;
- } else if (
- raw.inspectionResult !== undefined &&
- raw.inspectionResult !== null
- ) {
- hasException.value = String(raw.inspectionResult) === "0";
- } else {
- hasException.value = null;
- }
+ beforeModelValue.value.push(uploadedFile);
+ ElMessage.success("涓婁紶鎴愬姛");
+ } catch (error) {
+ ElMessage.error(error?.message || "涓婁紶澶辫触");
+ } finally {
+ uploading.value = false;
+ }
+};
- if (hasException.value !== true && beforeModelValue.value.length) {
- hasException.value = true;
- }
+const buildFileItem = (item) => ({
+ id: item?.id,
+ tempId: item?.tempId,
+ tempFileId: item?.tempFileId,
+ url: item?.downloadUrl || item?.url || "",
+ downloadUrl: item?.downloadUrl || item?.url || "",
+ name: item?.name,
+ bucketFilename: item?.bucketFilename || item?.name,
+ originalFilename: item?.originalFilename || item?.name,
+ size: item?.size || 0,
+ byteSize: item?.byteSize || item?.size || 0,
+ contentType: item?.contentType || "",
+ type: item?.type,
+});
- dialogVisible.value = true;
- };
+const submitUpload = async () => {
+ if (hasException.value === null) {
+ ElMessage.warning("璇烽�夋嫨宸℃鐘舵��");
+ return;
+ }
- const handleClose = () => {
- dialogVisible.value = false;
- resetState();
- emit("closeDia");
- };
+ if (hasException.value === true) {
+ const totalFiles = beforeModelValue.value.length;
- const previewVideo = file => {
- currentVideoFile.value = file;
- showVideoDialog.value = true;
- };
-
- const uploadFile = async uploadRequest => {
- const rawFile = uploadRequest.file;
-
- if (beforeModelValue.value.length >= uploadConfig.limit) {
- ElMessage.warning(`鏈�澶氬彧鑳介�夋嫨${uploadConfig.limit}涓枃浠禶);
+ if (!totalFiles) {
+ ElMessage.warning("璇蜂笂浼犲紓甯哥収鐗囨垨瑙嗛");
return;
}
- const ext = rawFile.name.split(".").pop()?.toLowerCase();
- if (!uploadConfig.fileType.includes(ext)) {
- ElMessage.warning(
- `鏂囦欢鏍煎紡涓嶆敮鎸侊紝璇蜂笂浼� ${uploadConfig.fileType.join("/")} 鏍煎紡`
- );
+ if (!abnormalDescription.value.trim()) {
+ ElMessage.warning("璇峰~鍐欏紓甯告弿杩�");
return;
}
+ }
- if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) {
- ElMessage.warning(`鏂囦欢澶у皬涓嶈兘瓒呰繃 ${uploadConfig.fileSize}MB`);
- return;
- }
-
- const token = getToken();
- if (!token) {
- ElMessage.warning("鐢ㄦ埛鏈櫥褰�");
- return;
- }
-
- const formData = new FormData();
- formData.append("files", rawFile);
- formData.append("type", 10); // 鐢熶骇鍓嶅浐瀹氫负10
-
- uploading.value = true;
- uploadProgress.value = 0;
-
- try {
- const { data } = await axios.post(uploadFileUrl.value, formData, {
- headers: {
- Authorization: `Bearer ${token}`,
- "Content-Type": "multipart/form-data",
- },
- onUploadProgress: event => {
- if (event.total) {
- uploadProgress.value = Math.round((event.loaded / event.total) * 100);
- }
- },
- });
-
- if (data.code !== 200) {
- ElMessage.error(data.msg || "涓婁紶澶辫触");
- return;
- }
-
- const resultData = Array.isArray(data.data) ? data.data[0] : data.data;
- const finalUrl = processFileUrl(
- resultData.url || resultData.previewURL || resultData.downloadUrl || ""
- );
- const finalName =
- resultData.name ||
- resultData.originalFilename ||
- resultData.bucketFilename;
- const finalId = resultData.tempId || resultData.id || resultData.tempFileId;
-
- const uploadedFile = {
- ...resultData,
- url: finalUrl,
- downloadUrl: finalUrl,
- name: finalName,
- tempId: finalId,
- tempFileId: resultData.tempFileId || finalId,
- size: rawFile.size || resultData.size || resultData.byteSize || 0,
- type: rawFile.type?.startsWith("video") ? "video" : "image",
- status: "success",
- uid: `${Date.now()}-${Math.random()}`,
- };
-
- beforeModelValue.value.push(uploadedFile);
- ElMessage.success("涓婁紶鎴愬姛");
- } catch (error) {
- ElMessage.error(error?.message || "涓婁紶澶辫触");
- } finally {
- uploading.value = false;
- }
- };
-
- const buildFileItem = item => ({
- id: item?.id,
- tempId: item?.tempId,
- tempFileId: item?.tempFileId,
- url: item?.downloadUrl || item?.url || "",
- downloadUrl: item?.downloadUrl || item?.url || "",
- name: item?.name,
- bucketFilename: item?.bucketFilename || item?.name,
- originalFilename: item?.originalFilename || item?.name,
- size: item?.size || 0,
- byteSize: item?.byteSize || item?.size || 0,
- contentType: item?.contentType || "",
- type: item?.type,
+ const loading = ElLoading.service({
+ text: "鎻愪氦涓�...",
+ background: "rgba(0, 0, 0, 0.3)",
});
- const submitUpload = async () => {
- if (hasException.value === null) {
- ElMessage.warning("璇烽�夋嫨宸℃鐘舵��");
- return;
- }
+ try {
+ const allFiles = [...beforeModelValue.value];
- if (hasException.value === true) {
- const totalFiles = beforeModelValue.value.length;
+ const tempFileIds = allFiles
+ .map((item) => item?.tempId ?? item?.tempFileId ?? item?.id)
+ .filter(Boolean);
- if (!totalFiles) {
- ElMessage.warning("璇蜂笂浼犲紓甯哥収鐗囨垨瑙嗛");
- return;
- }
+ const {
+ createTime,
+ updateTime,
+ storageBlobDTO,
+ commonFileListAfterVO,
+ commonFileListVO,
+ commonFileListBeforeVO,
+ commonFileListAfter,
+ commonFileList,
+ commonFileListBefore,
+ __raw,
+ ...baseTaskInfo
+ } = taskInfo.value || {};
- if (!abnormalDescription.value.trim()) {
- ElMessage.warning("璇峰~鍐欏紓甯告弿杩�");
- return;
- }
- }
-
- const loading = ElLoading.service({
- text: "鎻愪氦涓�...",
- background: "rgba(0, 0, 0, 0.3)",
- });
-
- try {
- const allFiles = [...beforeModelValue.value];
-
- const tempFileIds = allFiles
- .map(item => item?.tempId ?? item?.tempFileId ?? item?.id)
- .filter(Boolean);
-
- const {
- createTime,
- updateTime,
- storageBlobDTO,
- commonFileListAfterVO,
- commonFileListVO,
- commonFileListBeforeVO,
- commonFileListAfter,
- commonFileList,
- commonFileListBefore,
- __raw,
- ...baseTaskInfo
- } = taskInfo.value || {};
-
- const submitData = {
- ...baseTaskInfo,
- commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
- commonFileListDTO: [],
- commonFileListAfterDTO: [],
- hasException: hasException.value,
- inspectionResult: hasException.value ? 0 : 1,
- abnormalDescription: abnormalDescription.value,
- tempFileIds,
- };
-
- const result = await uploadInspectionTask(submitData);
-
- if (result && (result.code === 200 || result.success)) {
- ElMessage.success("鎻愪氦鎴愬姛");
- dialogVisible.value = false;
- resetState();
- emit("success");
- emit("closeDia");
- } else {
- ElMessage.error(result?.msg || result?.message || "鎻愪氦澶辫触");
- }
- } catch (error) {
- ElMessage.error(error?.message || "鎻愪氦澶辫触");
- } finally {
- loading.close();
- }
- };
-
- const removeFile = async index => {
- try {
- await ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓枃浠跺悧锛�", "纭鍒犻櫎", {
- type: "warning",
- });
- beforeModelValue.value.splice(index, 1);
- } catch {}
- };
-
- const goToRepair = () => {
- const taskData = {
- taskId: taskInfo.value?.taskId || taskInfo.value?.id,
- taskName: taskInfo.value?.taskName,
- inspectionLocation: taskInfo.value?.inspectionLocation,
- inspector: taskInfo.value?.inspector,
- hasException: hasException.value,
- inspectionResult: hasException.value ? 0 : 1,
+ const submitData = {
+ ...baseTaskInfo,
+ inspectionItems: inspectionItems.value.map((item) => ({
+ id: item.id,
+ itemStatus: completedItemIds.value.includes(item.id) ? 1 : 0,
+ remarks: item.remarks || "",
+ })),
commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
commonFileListDTO: [],
commonFileListAfterDTO: [],
- uploadedFiles: {
- before: beforeModelValue.value,
- after: [],
- issue: [],
- },
+ hasException: hasException.value,
+ inspectionResult: hasException.value ? 0 : 1,
+ abnormalDescription: abnormalDescription.value,
+ tempFileIds,
};
- sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData));
- router.push("/equipmentManagement/repair/add");
- };
+ const result = await uploadInspectionTask(submitData);
- const formatFileSize = size => {
- if (!size) return "0 B";
-
- const units = ["B", "KB", "MB", "GB"];
- let index = 0;
- let fileSize = size;
-
- while (fileSize >= 1024 && index < units.length - 1) {
- fileSize /= 1024;
- index += 1;
+ if (result && (result.code === 200 || result.success)) {
+ ElMessage.success("鎻愪氦鎴愬姛");
+ dialogVisible.value = false;
+ resetState();
+ emit("success");
+ emit("closeDia");
+ } else {
+ ElMessage.error(result?.msg || result?.message || "鎻愪氦澶辫触");
}
+ } catch (error) {
+ ElMessage.error(error?.message || "鎻愪氦澶辫触");
+ } finally {
+ loading.close();
+ }
+};
- return `${fileSize.toFixed(2)} ${units[index]}`;
+const removeFile = async (index) => {
+ try {
+ await ElMessageBox.confirm("纭畾瑕佸垹闄よ繖涓枃浠跺悧锛�", "纭鍒犻櫎", {
+ type: "warning",
+ });
+ beforeModelValue.value.splice(index, 1);
+ } catch {}
+};
+
+const goToRepair = () => {
+ const taskData = {
+ taskId: taskInfo.value?.taskId || taskInfo.value?.id,
+ taskName: taskInfo.value?.taskName,
+ inspectionLocation: taskInfo.value?.inspectionLocation,
+ inspector: taskInfo.value?.inspector,
+ hasException: hasException.value,
+ inspectionResult: hasException.value ? 0 : 1,
+ commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem),
+ commonFileListDTO: [],
+ commonFileListAfterDTO: [],
+ uploadedFiles: {
+ before: beforeModelValue.value,
+ after: [],
+ issue: [],
+ },
};
- defineExpose({
- openDialog,
- });
+ sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData));
+ router.push("/equipmentManagement/repair/add");
+};
+
+const formatFileSize = (size) => {
+ if (!size) return "0 B";
+
+ const units = ["B", "KB", "MB", "GB"];
+ let index = 0;
+ let fileSize = size;
+
+ while (fileSize >= 1024 && index < units.length - 1) {
+ fileSize /= 1024;
+ index += 1;
+ }
+
+ return `${fileSize.toFixed(2)} ${units[index]}`;
+};
+
+defineExpose({
+ openDialog,
+});
</script>
<style scoped>
- .inspection-upload-page {
- min-height: 70vh;
- background: #f5f7fa;
- padding: 20px 20px 90px;
- box-sizing: border-box;
- }
+.inspection-upload-page {
+ min-height: 70vh;
+ background: #f5f7fa;
+ padding: 20px 20px 90px;
+ box-sizing: border-box;
+}
- .upload-content {
- max-width: 960px;
- margin: 20px auto 0;
- }
+.upload-content {
+ max-width: 960px;
+ margin: 20px auto 0;
+}
- .section-card {
- margin-bottom: 16px;
- }
+.section-card {
+ margin-bottom: 16px;
+}
- .section-card h3 {
- margin: 0 0 16px;
- font-size: 16px;
- }
+.section-card h3 {
+ margin: 0 0 16px;
+ font-size: 16px;
+}
- .upload-buttons {
- display: flex;
- gap: 12px;
- margin: 16px 0;
- }
+.section-heading {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ color: #909399;
+}
+.section-heading h3 {
+ margin: 0;
+ color: #303133;
+}
+.inspection-item-row {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 20px;
+ padding: 14px 8px;
+ border-top: 1px solid #ebeef5;
+}
+.inspection-item-copy {
+ min-width: 0;
+ flex: 1;
+}
+.inspection-item-title {
+ font-weight: 600;
+ color: #303133;
+}
+.inspection-item-content {
+ margin: 6px 0 0 20px;
+ color: #606266;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
- .upload-progress {
- margin-bottom: 16px;
- }
+.upload-buttons {
+ display: flex;
+ gap: 12px;
+ margin: 16px 0;
+}
- .file-list {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
- gap: 12px;
- }
+.upload-progress {
+ margin-bottom: 16px;
+}
- .file-preview-container {
- position: relative;
- aspect-ratio: 1;
- border-radius: 8px;
- overflow: hidden;
- background: #f2f3f5;
- }
+.file-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
+ gap: 12px;
+}
- .file-preview {
- width: 100%;
- height: 100%;
- }
+.file-preview-container {
+ position: relative;
+ aspect-ratio: 1;
+ border-radius: 8px;
+ overflow: hidden;
+ background: #f2f3f5;
+}
- .video-preview {
- width: 100%;
- height: 100%;
- background: #303133;
- color: #fff;
- display: flex;
- gap: 6px;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- }
+.file-preview {
+ width: 100%;
+ height: 100%;
+}
- .delete-btn {
- position: absolute;
- top: 6px;
- right: 6px;
- }
+.video-preview {
+ width: 100%;
+ height: 100%;
+ background: #303133;
+ color: #fff;
+ display: flex;
+ gap: 6px;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+}
- .file-info {
- margin-top: 6px;
- font-size: 12px;
- }
+.delete-btn {
+ position: absolute;
+ top: 6px;
+ right: 6px;
+}
- .file-name {
- color: #606266;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
+.file-info {
+ margin-top: 6px;
+ font-size: 12px;
+}
- .file-size {
- color: #909399;
- margin-top: 2px;
- }
+.file-name {
+ color: #606266;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
- .upload-summary {
- margin-top: 16px;
- }
+.file-size {
+ color: #909399;
+ margin-top: 2px;
+}
- .footer-buttons {
- position: sticky;
- left: 0;
- right: 0;
- bottom: 0;
- padding: 14px 20px 0;
- background: #f5f7fa;
- display: flex;
- justify-content: center;
- gap: 12px;
- }
+.upload-summary {
+ margin-top: 16px;
+}
- .video-player {
- width: 100%;
- max-height: 70vh;
- background: #000;
- }
+.footer-buttons {
+ position: sticky;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 14px 20px 0;
+ background: #f5f7fa;
+ display: flex;
+ justify-content: center;
+ gap: 12px;
+}
+
+.video-player {
+ width: 100%;
+ max-height: 70vh;
+ background: #000;
+}
</style>
diff --git a/src/views/equipmentManagement/inspectionManagement/index.vue b/src/views/equipmentManagement/inspectionManagement/index.vue
index c6c21d9..f080161 100644
--- a/src/views/equipmentManagement/inspectionManagement/index.vue
+++ b/src/views/equipmentManagement/inspectionManagement/index.vue
@@ -1,461 +1,592 @@
<template>
<div class="app-container">
- <el-form :inline="true"
- :model="queryParams"
- class="search-form">
- <el-form-item label="宸℃浠诲姟鍚嶇О">
- <el-input v-model="queryParams.taskName"
- placeholder="璇疯緭鍏ュ贰妫�浠诲姟鍚嶇О"
- clearable
- style="width: 200px " />
- </el-form-item>
- <el-form-item>
- <el-button type="primary"
- @click="handleQuery">鏌ヨ</el-button>
- <el-button @click="resetQuery">閲嶇疆</el-button>
- </el-form-item>
- </el-form>
- <el-card>
- <div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom: 10px;">
- <el-radio-group v-model="activeRadio"
- @change="radioChange">
- <el-radio-button v-for="tab in radios"
- :key="tab.name"
- :label="tab.label"
- :value="tab.name" />
- </el-radio-group>
- <!-- 鎿嶄綔鎸夐挳鍖� -->
- <el-space v-if="activeRadio !== 'task'">
- <el-button type="primary"
- :icon="Plus"
- @click="handleAdd(undefined)">鏂板缓</el-button>
- <el-button type="danger"
- :icon="Delete"
- @click="handleDelete">鍒犻櫎</el-button>
- <el-button @click="handleOut">瀵煎嚭</el-button>
- </el-space>
- <el-space v-else>
- <el-button @click="handleOut">瀵煎嚭</el-button>
- </el-space>
+ <el-tabs v-model="activeRadio" @tab-change="radioChange">
+ <el-tab-pane v-for="tab in radios" :key="tab.name" :label="tab.label" :name="tab.name" />
+ </el-tabs>
+ <InspectionItemManager v-if="activeRadio === 'items'" />
+ <template v-else>
+ <div class="search_form">
+ <el-form :inline="true" :model="queryParams">
+ <el-form-item label="宸℃浠诲姟鍚嶇О">
+ <el-input
+ v-model="queryParams.taskName"
+ placeholder="璇疯緭鍏ュ贰妫�浠诲姟鍚嶇О"
+ clearable
+ style="width: 240px"
+ @keyup.enter="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery">鎼滅储</el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
</div>
- <div>
- <PIMTable :table-loading="tableLoading"
- :table-data="tableData"
- :column="tableColumns"
- @selection-change="handleSelectionChange"
- @pagination="handlePagination"
- :is-selection="true"
- :border="true"
- :page="{
- current: pageNum,
- size: pageSize,
- total: total,
- layout: 'total, sizes, prev, pager, next, jumper'
- }"
- height="calc(100vh - 23em)"
- :table-style="{ width: '100%' }">
+ <div class="table_list">
+ <div class="actions">
+ <el-text size="large">{{ activeRadio === "task" ? "宸℃璁板綍" : "宸℃浠诲姟" }}</el-text>
+ <div class="action-buttons">
+ <template v-if="activeRadio !== 'task'">
+ <el-button type="primary" :icon="Plus" @click="handleAdd(undefined)">鏂板缓</el-button>
+ <el-button
+ type="danger"
+ :icon="Delete"
+ :disabled="selectedRows.length === 0"
+ @click="handleDelete"
+ >鍒犻櫎</el-button
+ >
+ </template>
+ <el-button @click="handleOut">瀵煎嚭</el-button>
+ </div>
+ </div>
+ <PIMTable
+ :table-loading="tableLoading"
+ :table-data="tableData"
+ :column="tableColumns"
+ @selection-change="handleSelectionChange"
+ @pagination="handlePagination"
+ :is-selection="true"
+ :border="true"
+ :page="{
+ current: pageNum,
+ size: pageSize,
+ total: total,
+ layout: 'total, sizes, prev, pager, next, jumper',
+ }"
+ >
<template #inspector="{ row }">
<div class="person-tags">
<!-- 璋冭瘯淇℃伅锛屼笂绾挎椂鍒犻櫎 -->
<!-- {{ console.log('inspector data:', row.inspector) }} -->
<template v-if="row.inspector && row.inspector.length > 0">
- <el-tag v-for="(person, index) in row.inspector"
- :key="index"
- size="small"
- type="primary"
- class="person-tag">
+ <el-tag
+ v-for="(person, index) in row.inspector"
+ :key="index"
+ size="small"
+ type="primary"
+ class="person-tag"
+ >
{{ person }}
</el-tag>
</template>
- <span v-else
- class="no-data">--</span>
+ <span v-else class="no-data">--</span>
</div>
</template>
<template #isEnabled="{ row }">
- <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'"
- size="small">
- {{ row.isEnabled == 1 ? '鏄�' : '鍚�' }}
+ <el-tag :type="row.isEnabled === 1 ? 'success' : 'danger'" size="small">
+ {{ row.isEnabled == 1 ? "鏄�" : "鍚�" }}
</el-tag>
</template>
</PIMTable>
</div>
- </el-card>
- <form-dia ref="formDia"
- @closeDia="handleQuery"></form-dia>
- <view-files ref="viewFiles"></view-files>
- <upload-files ref="uploadFiles"
- @success="handleQuery"
- @closeDia="handleQuery"></upload-files>
+ <form-dia ref="formDia" @closeDia="handleQuery" />
+ <view-files ref="viewFiles" />
+ <upload-files ref="uploadFiles" @success="handleQuery" @closeDia="handleQuery" />
+ <el-dialog v-model="taskDetailVisible" title="宸℃浠诲姟璇︽儏" width="900px">
+ <template v-if="taskDetail">
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="宸℃浠诲姟鍚嶇О">{{
+ taskDetail.taskName || "-"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鎵ц宸℃浜�">{{
+ formatInspector(taskDetail.inspector)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="棰戞">{{
+ formatFrequencyType(taskDetail.frequencyType)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="寮�濮嬫棩鏈熶笌鏃堕棿">{{
+ formatFrequencyDetail(taskDetail.frequencyDetail)
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鐧昏浜�">{{
+ taskDetail.registrant || "-"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="鐧昏鏃ユ湡">{{
+ taskDetail.createTime ? dayjs(taskDetail.createTime).format("YYYY-MM-DD") : "-"
+ }}</el-descriptions-item>
+ <el-descriptions-item label="澶囨敞" :span="2">{{
+ taskDetail.remarks || "-"
+ }}</el-descriptions-item>
+ </el-descriptions>
+ <div class="task-detail-items">
+ <div class="task-detail-heading">
+ 宸℃鍐呭锛坽{ taskDetail.inspectionItems?.length || 0 }}椤癸級
+ </div>
+ <el-empty v-if="!taskDetail.inspectionItems?.length" description="鏆傛棤宸℃鍐呭" />
+ <div
+ v-for="(item, index) in taskDetail.inspectionItems"
+ :key="item.id || index"
+ class="task-detail-item"
+ >
+ <div class="task-detail-project">
+ {{ index + 1 }}. {{ item.itemProject || "鏈懡鍚嶉」鐩�" }}
+ </div>
+ <div class="task-detail-content">{{ item.itemContent || "-" }}</div>
+ </div>
+ </div>
+ </template>
+ <template #footer>
+ <el-button @click="taskDetailVisible = false">鍏抽棴</el-button>
+ </template>
+ </el-dialog>
+ </template>
</div>
</template>
<script setup>
- import { Delete, Plus } from "@element-plus/icons-vue";
- import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
- import { ElMessageBox } from "element-plus";
- import dayjs from "dayjs";
+import { Delete, Plus } from "@element-plus/icons-vue";
+import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
+import { ElMessageBox } from "element-plus";
+import dayjs from "dayjs";
- // 缁勪欢寮曞叆
- import PIMTable from "@/components/PIMTable/PIMTable.vue";
- import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
- import UploadFiles from "@/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue";
- import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
+// 缁勪欢寮曞叆
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
+import UploadFiles from "@/views/equipmentManagement/inspectionManagement/components/uploadFiles.vue";
+import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
+import InspectionItemManager from "@/views/equipmentManagement/inspectionManagement/components/InspectionItemManager.vue";
- // 鎺ュ彛寮曞叆
- import {
- delTimingTask,
- inspectionTaskList,
- timingTaskList,
- } from "@/api/inspectionManagement/index.js";
+// 鎺ュ彛寮曞叆
+import {
+ delTimingTask,
+ inspectionTaskList,
+ timingTaskList,
+} from "@/api/inspectionManagement/index.js";
- // 鍏ㄥ眬鍙橀噺
- const { proxy } = getCurrentInstance();
- const formDia = ref();
- const viewFiles = ref();
- const uploadFiles = ref();
+// 鍏ㄥ眬鍙橀噺
+const { proxy } = getCurrentInstance();
+const formDia = ref();
+const viewFiles = ref();
+const uploadFiles = ref();
+const taskDetailVisible = ref(false);
+const taskDetail = ref(null);
- // 鏌ヨ鍙傛暟
- const queryParams = reactive({
- taskName: "",
- });
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+ taskName: "",
+});
- // 鍗曢�夋閰嶇疆
- const activeRadio = ref("taskManage");
- const radios = reactive([
- { name: "taskManage", label: "宸℃浠诲姟" },
- { name: "task", label: "宸℃璁板綍" },
- ]);
+// 鍗曢�夋閰嶇疆
+const activeRadio = ref("taskManage");
+const radios = reactive([
+ { name: "taskManage", label: "宸℃浠诲姟" },
+ { name: "task", label: "宸℃璁板綍" },
+ { name: "items", label: "宸℃鍐呭" },
+]);
- // 琛ㄦ牸鏁版嵁
- const selectedRows = ref([]);
- const tableData = ref([]);
- const operationsArr = ref([]);
- const tableColumns = ref([]);
- const tableLoading = ref(false);
- const total = ref(0);
- const pageNum = ref(1);
- const pageSize = ref(10);
+// 琛ㄦ牸鏁版嵁
+const selectedRows = ref([]);
+const tableData = ref([]);
+const operationsArr = ref([]);
+const tableColumns = ref([]);
+const tableLoading = ref(false);
+const total = ref(0);
+const pageNum = ref(1);
+const pageSize = ref(10);
- // 鍒楅厤缃�
- const columns = ref([
- { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 200 },
- { prop: "inspectionProject", label: "宸℃椤圭洰", minWidth: 180 },
- { prop: "remarks", label: "澶囨敞", minWidth: 180 },
- { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 180, slot: "inspector" },
- {
- prop: "isEnabled",
- label: "鏄惁鍚敤",
- minWidth: 100,
- dataType: "slot",
- slot: "isEnabled",
+// 鍒楅厤缃�
+const taskColumns = [
+ { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 200 },
+ { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 180, slot: "inspector" },
+ {
+ prop: "isEnabled",
+ label: "鏄惁鍚敤",
+ minWidth: 100,
+ dataType: "slot",
+ slot: "isEnabled",
+ },
+ {
+ prop: "frequencyType",
+ label: "棰戞",
+ minWidth: 120,
+ formatData: (params) => {
+ return params === "DAILY"
+ ? "姣忔棩"
+ : params === "WEEKLY"
+ ? "姣忓懆"
+ : params === "MONTHLY"
+ ? "姣忔湀"
+ : params === "QUARTERLY"
+ ? "瀛e害"
+ : "";
},
- {
- prop: "frequencyType",
- label: "棰戞",
- minWidth: 120,
- formatData: params => {
- return params === "DAILY"
- ? "姣忔棩"
- : params === "WEEKLY"
- ? "姣忓懆"
- : params === "MONTHLY"
- ? "姣忔湀"
- : params === "QUARTERLY"
- ? "瀛e害"
- : "";
- },
+ },
+ {
+ prop: "frequencyDetail",
+ label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+ minWidth: 200,
+ formatter: (row, column, cellValue) => {
+ // 鍏堝垽鏂槸鍚︽槸瀛楃涓�
+ if (typeof cellValue !== "string") return "";
+ let val = cellValue;
+ const replacements = {
+ MON: "鍛ㄤ竴",
+ TUE: "鍛ㄤ簩",
+ WED: "鍛ㄤ笁",
+ THU: "鍛ㄥ洓",
+ FRI: "鍛ㄤ簲",
+ SAT: "鍛ㄥ叚",
+ SUN: "鍛ㄦ棩",
+ };
+ // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
+ return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
},
- {
- prop: "frequencyDetail",
- label: "寮�濮嬫棩鏈熶笌鏃堕棿",
- minWidth: 200,
- formatter: (row, column, cellValue) => {
- // 鍏堝垽鏂槸鍚︽槸瀛楃涓�
- if (typeof cellValue !== "string") return "";
- let val = cellValue;
- const replacements = {
- MON: "鍛ㄤ竴",
- TUE: "鍛ㄤ簩",
- WED: "鍛ㄤ笁",
- THU: "鍛ㄥ洓",
- FRI: "鍛ㄤ簲",
- SAT: "鍛ㄥ叚",
- SUN: "鍛ㄦ棩",
- };
- // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
- return val.replace(
- /MON|TUE|WED|THU|FRI|SAT|SUN/g,
- match => replacements[match]
- );
- },
- },
- { prop: "registrant", label: "鐧昏浜�", minWidth: 120 },
- {
- prop: "createTime",
- label: "鐧昏鏃ユ湡",
- minWidth: 180,
- formatData: cell => {
- if (!cell) return "-";
- try {
- return dayjs(cell).format("YYYY-MM-DD");
- } catch {
- return cell;
- }
- },
- },
- // {
- // prop: "inspectionResult",
- // label: "宸℃缁撴灉",
- // minWidth: 100,
- // dataType: "tag",
- // formatData: val => {
- // return val == 1 ? "姝e父" : "寮傚父";
- // },
- // formatType: val => {
- // return val == 1 ? "success" : "danger";
- // },
- // },
- { prop: "abnormalDescription", label: "寮傚父鎻忚堪", minWidth: 150 },
- ]);
-
- // 鎿嶄綔鍒楅厤缃�
- const getOperationColumn = operations => {
- if (!operations || operations.length === 0) return null;
-
- const operationConfig = {
- label: "鎿嶄綔",
- width: operations.length > 1 ? 180 : 130,
- fixed: "right",
- align: "center",
- dataType: "action",
- operation: operations
- .map(op => {
- switch (op) {
- case "view":
- return {
- name: "璇︽儏",
- clickFun: openViewDialog,
- color: "#409EFF",
- };
- case "edit":
- return {
- name: "缂栬緫",
- clickFun: handleAdd,
- color: "#409EFF",
- };
- case "upload":
- return {
- name: "涓婁紶",
- clickFun: openUploadDialog,
- color: "#409EFF",
- };
- case "viewFile":
- return {
- name: "鏌ョ湅闄勪欢",
- clickFun: viewFile,
- color: "#67C23A",
- };
- default:
- return null;
- }
- })
- .filter(Boolean),
- };
-
- return operationConfig;
- };
-
- onMounted(() => {
- radioChange("taskManage");
- });
-
- // 鍗曢�夊彉鍖�
- const radioChange = value => {
- if (value === "taskManage") {
- const operationColumn = getOperationColumn(["edit"]);
- tableColumns.value = [
- ...columns.value,
- ...(operationColumn ? [operationColumn] : []),
- ];
- operationsArr.value = ["edit"];
- } else if (value === "task") {
- const operationColumn = getOperationColumn(["view", "upload", "viewFile"]);
- // 宸℃璁板綍涓嶅睍绀�"鏄惁鍚敤"鍒�
- const taskColumns = columns.value.filter(col => col.prop !== "isEnabled");
- tableColumns.value = [
- ...taskColumns,
- ...(operationColumn ? [operationColumn] : []),
- ];
- operationsArr.value = ["view", "upload", "viewFile"];
- }
- pageNum.value = 1;
- pageSize.value = 10;
- getList();
- };
-
- // 鏌ヨ鎿嶄綔
- const handleQuery = () => {
- pageNum.value = 1;
- pageSize.value = 10;
- getList();
- };
- // 鍒嗛〉澶勭悊
- const handlePagination = val => {
- pageNum.value = val.page;
- pageSize.value = val.limit;
- getList();
- };
- // 鑾峰彇鍒楄〃鏁版嵁
- const getList = () => {
- tableLoading.value = true;
-
- const params = {
- ...queryParams,
- size: pageSize.value,
- current: pageNum.value,
- };
-
- let apiCall;
- if (activeRadio.value === "task") {
- apiCall = inspectionTaskList(params);
- } else {
- apiCall = timingTaskList(params);
- }
-
- apiCall
- .then(res => {
- const rawData = res.data.records || [];
- // 澶勭悊 inspector 瀛楁锛屽皢瀛楃涓茶浆鎹负鏁扮粍锛堥�傜敤浜庢墍鏈夋儏鍐碉級
- tableData.value = rawData.map(item => {
- const processedItem = { ...item };
- processedItem.__raw = { ...item };
-
- // 澶勭悊 inspector 瀛楁
- if (processedItem.inspector) {
- if (typeof processedItem.inspector === "string") {
- // 瀛楃涓叉寜閫楀彿鍒嗗壊
- processedItem.inspector = processedItem.inspector
- .split(",")
- .map(s => s.trim())
- .filter(s => s);
- } else if (!Array.isArray(processedItem.inspector)) {
- // 闈炴暟缁勮浆涓烘暟缁�
- processedItem.inspector = [processedItem.inspector];
- }
- } else {
- // 绌哄�艰涓虹┖鏁扮粍
- processedItem.inspector = [];
- }
-
- return processedItem;
- });
- total.value = res.data.total || 0;
- })
- .finally(() => {
- tableLoading.value = false;
- });
- };
-
- // 閲嶇疆鏌ヨ
- const resetQuery = () => {
- for (const key in queryParams) {
- if (!["pageNum", "pageSize"].includes(key)) {
- queryParams[key] = "";
+ },
+ { prop: "registrant", label: "鐧昏浜�", minWidth: 120 },
+ {
+ prop: "createTime",
+ label: "鐧昏鏃ユ湡",
+ minWidth: 180,
+ formatData: (cell) => {
+ if (!cell) return "-";
+ try {
+ return dayjs(cell).format("YYYY-MM-DD");
+ } catch {
+ return cell;
}
- }
- handleQuery();
- };
+ },
+ },
+ { prop: "remarks", label: "澶囨敞", minWidth: 180, showOverflowTooltip: true },
+];
+const recordColumns = [
+ { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 200 },
+ { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 180, slot: "inspector" },
+ {
+ prop: "frequencyType",
+ label: "棰戞",
+ minWidth: 120,
+ formatData: (params) => formatFrequencyType(params),
+ },
+ {
+ prop: "frequencyDetail",
+ label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+ minWidth: 200,
+ formatter: (row, column, cellValue) => formatFrequencyDetail(cellValue),
+ },
+ { prop: "registrant", label: "鐧昏浜�", minWidth: 120 },
+ {
+ prop: "createTime",
+ label: "鐧昏鏃ユ湡",
+ minWidth: 180,
+ formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : "-"),
+ },
+ { prop: "abnormalDescription", label: "寮傚父鎻忚堪", minWidth: 150, showOverflowTooltip: true },
+ { prop: "remarks", label: "澶囨敞", minWidth: 180, showOverflowTooltip: true },
+];
- // 鏂板 / 缂栬緫
- const handleAdd = row => {
- const type = row ? "edit" : "add";
- nextTick(() => {
- formDia.value?.openDialog(type, row);
- });
- };
+// 鎿嶄綔鍒楅厤缃�
+const getOperationColumn = (operations) => {
+ if (!operations || operations.length === 0) return null;
- // 鏌ョ湅闄勪欢
- const viewFile = row => {
- nextTick(() => {
- viewFiles.value?.openDialog(row);
- });
- };
-
- const openUploadDialog = row => {
- nextTick(() => {
- uploadFiles.value?.openDialog("add", row);
- });
- };
-
- const openViewDialog = row => {
- nextTick(() => {
- uploadFiles.value?.openDialog("view", row);
- });
- };
-
- // 鍒犻櫎鎿嶄綔
- const handleDelete = () => {
- if (!selectedRows.value.length) {
- proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
- return;
- }
-
- const deleteIds = selectedRows.value.map(item => item.id);
-
- proxy.$modal
- .confirm("鏄惁纭鍒犻櫎鎵�閫夋暟鎹」锛�")
- .then(() => {
- return delTimingTask(deleteIds);
- })
- .then(() => {
- proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
- handleQuery();
- })
- .catch(() => {});
- };
-
- // 澶氶�夊彉鏇�
- const handleSelectionChange = selection => {
- selectedRows.value = selection;
- };
-
- // 瀵煎嚭
- const handleOut = () => {
- ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
- confirmButtonText: "纭",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(() => {
- // 鏍规嵁褰撳墠閫変腑鐨勬爣绛鹃〉璋冪敤涓嶅悓鐨勫鍑烘帴鍙�
- if (activeRadio.value === "taskManage") {
- // 宸℃浠诲姟
- proxy.download("/timingTask/export", {}, "宸℃浠诲姟.xlsx");
- } else if (activeRadio.value === "task") {
- // 宸℃璁板綍
- proxy.download("/inspectionTask/export", {}, "宸℃璁板綍.xlsx");
+ const operationConfig = {
+ label: "鎿嶄綔",
+ width: operations.length > 1 ? 180 : 130,
+ fixed: "right",
+ align: "center",
+ dataType: "action",
+ operation: operations
+ .map((op) => {
+ switch (op) {
+ case "view":
+ return {
+ name: "璇︽儏",
+ clickFun: openViewDialog,
+ color: "#409EFF",
+ };
+ case "viewTask":
+ return {
+ name: "璇︽儏",
+ clickFun: openTaskDetail,
+ color: "#409EFF",
+ };
+ case "edit":
+ return {
+ name: "缂栬緫",
+ clickFun: handleAdd,
+ color: "#409EFF",
+ };
+ case "upload":
+ return {
+ name: "涓婁紶",
+ clickFun: openUploadDialog,
+ color: "#409EFF",
+ };
+ case "viewFile":
+ return {
+ name: "鏌ョ湅闄勪欢",
+ clickFun: viewFile,
+ color: "#67C23A",
+ };
+ default:
+ return null;
}
})
- .catch(() => {
- proxy.$modal.msg("宸插彇娑�");
- });
+ .filter(Boolean),
};
+
+ return operationConfig;
+};
+
+onMounted(() => {
+ radioChange("taskManage");
+});
+
+// 鍗曢�夊彉鍖�
+const radioChange = (value) => {
+ if (value === "taskManage") {
+ const operationColumn = getOperationColumn(["viewTask", "edit"]);
+ tableColumns.value = [...taskColumns, ...(operationColumn ? [operationColumn] : [])];
+ operationsArr.value = ["viewTask", "edit"];
+ } else if (value === "task") {
+ const operationColumn = getOperationColumn(["view", "upload", "viewFile"]);
+ tableColumns.value = [...recordColumns, ...(operationColumn ? [operationColumn] : [])];
+ operationsArr.value = ["view", "upload", "viewFile"];
+ } else {
+ tableColumns.value = [];
+ operationsArr.value = [];
+ return;
+ }
+ pageNum.value = 1;
+ pageSize.value = 10;
+ getList();
+};
+
+// 鏌ヨ鎿嶄綔
+const handleQuery = () => {
+ pageNum.value = 1;
+ pageSize.value = 10;
+ getList();
+};
+// 鍒嗛〉澶勭悊
+const handlePagination = (val) => {
+ pageNum.value = val.page;
+ pageSize.value = val.limit;
+ getList();
+};
+// 鑾峰彇鍒楄〃鏁版嵁
+const getList = () => {
+ if (activeRadio.value === "items") return;
+ tableLoading.value = true;
+
+ const params = {
+ ...queryParams,
+ size: pageSize.value,
+ current: pageNum.value,
+ };
+
+ let apiCall;
+ if (activeRadio.value === "task") {
+ apiCall = inspectionTaskList(params);
+ } else {
+ apiCall = timingTaskList(params);
+ }
+
+ apiCall
+ .then((res) => {
+ const rawData = res.data.records || [];
+ // 澶勭悊 inspector 瀛楁锛屽皢瀛楃涓茶浆鎹负鏁扮粍锛堥�傜敤浜庢墍鏈夋儏鍐碉級
+ tableData.value = rawData.map((item) => {
+ const processedItem = { ...item };
+ processedItem.__raw = { ...item };
+
+ // 澶勭悊 inspector 瀛楁
+ if (processedItem.inspector) {
+ if (typeof processedItem.inspector === "string") {
+ // 瀛楃涓叉寜閫楀彿鍒嗗壊
+ processedItem.inspector = processedItem.inspector
+ .split(",")
+ .map((s) => s.trim())
+ .filter((s) => s);
+ } else if (!Array.isArray(processedItem.inspector)) {
+ // 闈炴暟缁勮浆涓烘暟缁�
+ processedItem.inspector = [processedItem.inspector];
+ }
+ } else {
+ // 绌哄�艰涓虹┖鏁扮粍
+ processedItem.inspector = [];
+ }
+
+ return processedItem;
+ });
+ total.value = res.data.total || 0;
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+};
+
+// 閲嶇疆鏌ヨ
+const resetQuery = () => {
+ for (const key in queryParams) {
+ if (!["pageNum", "pageSize"].includes(key)) {
+ queryParams[key] = "";
+ }
+ }
+ handleQuery();
+};
+
+// 鏂板 / 缂栬緫
+const handleAdd = (row) => {
+ const type = row ? "edit" : "add";
+ nextTick(() => {
+ formDia.value?.openDialog(type, row);
+ });
+};
+
+const openTaskDetail = (row) => {
+ taskDetail.value = row;
+ taskDetailVisible.value = true;
+};
+
+const formatInspector = (value) => {
+ if (Array.isArray(value)) return value.join("銆�") || "-";
+ return value || "-";
+};
+
+const formatFrequencyType = (type) =>
+ ({
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害",
+ }[type] || "-");
+
+const formatFrequencyDetail = (detail) => {
+ if (typeof detail !== "string" || !detail) return "-";
+ const replacements = {
+ MON: "鍛ㄤ竴",
+ TUE: "鍛ㄤ簩",
+ WED: "鍛ㄤ笁",
+ THU: "鍛ㄥ洓",
+ FRI: "鍛ㄤ簲",
+ SAT: "鍛ㄥ叚",
+ SUN: "鍛ㄦ棩",
+ };
+ return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
+};
+
+// 鏌ョ湅闄勪欢
+const viewFile = (row) => {
+ nextTick(() => {
+ viewFiles.value?.openDialog(row);
+ });
+};
+
+const openUploadDialog = (row) => {
+ nextTick(() => {
+ uploadFiles.value?.openDialog("add", row);
+ });
+};
+
+const openViewDialog = (row) => {
+ nextTick(() => {
+ uploadFiles.value?.openDialog("view", row);
+ });
+};
+
+// 鍒犻櫎鎿嶄綔
+const handleDelete = () => {
+ if (!selectedRows.value.length) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁");
+ return;
+ }
+
+ const deleteIds = selectedRows.value.map((item) => item.id);
+
+ proxy.$modal
+ .confirm("鏄惁纭鍒犻櫎鎵�閫夋暟鎹」锛�")
+ .then(() => {
+ return delTimingTask(deleteIds);
+ })
+ .then(() => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ handleQuery();
+ })
+ .catch(() => {});
+};
+
+// 澶氶�夊彉鏇�
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection;
+};
+
+// 瀵煎嚭
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ // 鏍规嵁褰撳墠閫変腑鐨勬爣绛鹃〉璋冪敤涓嶅悓鐨勫鍑烘帴鍙�
+ if (activeRadio.value === "taskManage") {
+ // 宸℃浠诲姟
+ proxy.download("/timingTask/export", {}, "宸℃浠诲姟.xlsx");
+ } else if (activeRadio.value === "task") {
+ // 宸℃璁板綍
+ proxy.download("/inspectionTask/export", {}, "宸℃璁板綍.xlsx");
+ }
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+};
</script>
<style scoped>
- .person-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 4px;
- }
+.actions {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+}
+.action-buttons {
+ display: flex;
+ gap: 8px;
+}
+.table_list {
+ margin-top: unset;
+}
+.person-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+}
- .person-tag {
- margin-right: 4px;
- margin-bottom: 2px;
- }
+.person-tag {
+ margin-right: 4px;
+ margin-bottom: 2px;
+}
- .no-data {
- color: #909399;
- font-size: 14px;
- }
+.no-data {
+ color: #909399;
+ font-size: 14px;
+}
+.task-detail-items {
+ margin-top: 20px;
+ border: 1px solid var(--el-border-color-lighter);
+ border-radius: 4px;
+}
+.task-detail-heading {
+ padding: 12px 16px;
+ font-weight: 600;
+ border-bottom: 1px solid var(--el-border-color-lighter);
+}
+.task-detail-item {
+ padding: 14px 16px;
+ border-bottom: 1px solid var(--el-border-color-lighter);
+}
+.task-detail-item:last-child {
+ border-bottom: 0;
+}
+.task-detail-project {
+ font-weight: 600;
+ color: var(--el-text-color-primary);
+}
+.task-detail-content {
+ margin: 6px 0 0 20px;
+ color: var(--el-text-color-regular);
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/ItemManager.vue b/src/views/equipmentManagement/upkeep/Form/ItemManager.vue
new file mode 100644
index 0000000..982616e
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/ItemManager.vue
@@ -0,0 +1,331 @@
+<template>
+ <div class="app-container">
+ <div class="search_form">
+ <el-form :model="filters" :inline="true">
+ <el-form-item label="鎵�灞炶澶�">
+ <el-select
+ v-model="filters.deviceLedgerId"
+ clearable
+ filterable
+ placeholder="璇烽�夋嫨璁惧"
+ style="width: 220px"
+ >
+ <el-option
+ v-for="device in deviceOptions"
+ :key="device.id"
+ :label="device.deviceName"
+ :value="device.id"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="淇濆吇棰戠巼">
+ <el-select
+ v-model="filters.frequencyType"
+ clearable
+ placeholder="璇烽�夋嫨棰戠巼"
+ style="width: 200px"
+ >
+ <el-option
+ v-for="item in frequencyOptions"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="淇濆吇鍐呭">
+ <el-input
+ v-model="keyword"
+ clearable
+ placeholder="璇疯緭鍏ヤ繚鍏诲唴瀹�"
+ style="width: 240px"
+ :prefix-icon="Search"
+ @keyup.enter="search"
+ @clear="search"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="search">鎼滅储</el-button>
+ <el-button @click="resetFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+ <div class="table_list">
+ <div class="actions">
+ <el-text size="large">淇濆吇鍐呭娓呭崟</el-text>
+ <el-button type="primary" icon="Plus" @click="openAdd">鏂板淇濆吇鍐呭</el-button>
+ </div>
+ <el-table v-loading="loading" :data="items" border>
+ <el-table-column type="index" label="搴忓彿" width="80" align="center" :index="indexMethod" />
+ <el-table-column
+ prop="itemProject"
+ label="淇濆吇椤圭洰"
+ min-width="160"
+ show-overflow-tooltip
+ />
+ <el-table-column prop="itemName" label="淇濆吇鍐呭" min-width="280" show-overflow-tooltip />
+ <el-table-column label="鎵�灞炶澶�" min-width="180" align="center" show-overflow-tooltip>
+ <template #default="{ row }">{{
+ row.deviceLedgerId ? deviceNameMap[row.deviceLedgerId] || "-" : "閫氱敤"
+ }}</template>
+ </el-table-column>
+ <el-table-column label="棰戠巼" width="120" align="center">
+ <template #default="{ row }">{{ frequencyLabel(row.frequencyType) }}</template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="150" align="center" fixed="right">
+ <template #default="{ row }">
+ <el-button link type="primary" @click="openEdit(row)">缂栬緫</el-button>
+ <el-button link type="danger" @click="removeItem(row)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ <template #empty>
+ <el-empty description="杩樻病鏈変繚鍏诲唴瀹癸紝璇峰厛閫愭潯娣诲姞">
+ <el-button type="primary" icon="Plus" @click="openAdd">鏂板淇濆吇鍐呭</el-button>
+ </el-empty>
+ </template>
+ </el-table>
+ <div class="pagination-wrap">
+ <el-pagination
+ v-model:current-page="pageNum"
+ v-model:page-size="pageSize"
+ background
+ :page-sizes="[10, 20, 50]"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="load"
+ />
+ </div>
+ </div>
+
+ <el-dialog
+ v-model="dialogVisible"
+ :title="form.id ? '缂栬緫淇濆吇鍐呭' : '鏂板淇濆吇鍐呭'"
+ width="520px"
+ align-center
+ destroy-on-close
+ :close-on-click-modal="false"
+ >
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="90px" label-position="right">
+ <el-form-item label="淇濆吇椤圭洰" prop="itemProject">
+ <el-input
+ v-model.trim="form.itemProject"
+ placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
+ maxlength="200"
+ show-word-limit
+ />
+ </el-form-item>
+ <el-form-item label="淇濆吇鍐呭" prop="itemName">
+ <el-input
+ v-model.trim="form.itemName"
+ type="textarea"
+ :rows="4"
+ resize="vertical"
+ placeholder="璇疯緭鍏ヤ繚鍏诲唴瀹�"
+ maxlength="2000"
+ show-word-limit
+ />
+ </el-form-item>
+ <el-form-item label="鎵�灞炶澶�">
+ <el-select
+ v-model="form.deviceLedgerId"
+ clearable
+ filterable
+ placeholder="涓嶉�夋嫨鍒欎负閫氱敤淇濆吇鍐呭"
+ no-data-text="鏆傛棤璁惧锛岃鍏堝湪璁惧鍙拌处涓坊鍔�"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="device in deviceOptions"
+ :key="device.id"
+ :label="device.deviceName"
+ :value="device.id"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="淇濆吇棰戠巼" prop="frequencyType">
+ <el-select v-model="form.frequencyType" placeholder="璇烽�夋嫨淇濆吇棰戠巼" style="width: 100%">
+ <el-option
+ v-for="item in frequencyOptions"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" :loading="saving" @click="save">淇濆瓨</el-button>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup>
+import { computed, onMounted, reactive, ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { Search } from "@element-plus/icons-vue";
+import {
+ addMaintenanceItem,
+ deleteMaintenanceItem,
+ editMaintenanceItem,
+ getMaintenanceItemPage,
+} from "@/api/equipmentManagement/upkeep";
+import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+
+const items = ref([]);
+const loading = ref(false);
+const saving = ref(false);
+const dialogVisible = ref(false);
+const formRef = ref();
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(20);
+const total = ref(0);
+const deviceOptions = ref([]);
+const filters = reactive({ deviceLedgerId: undefined, frequencyType: "" });
+const frequencyOptions = [
+ { label: "姣忔棩", value: "DAILY" },
+ { label: "姣忓懆", value: "WEEKLY" },
+ { label: "姣忔湀", value: "MONTHLY" },
+ { label: "姣忓搴�", value: "QUARTERLY" },
+ { label: "閫氱敤棰戠巼", value: "ALL" },
+];
+const deviceNameMap = computed(() =>
+ Object.fromEntries(deviceOptions.value.map((device) => [String(device.id), device.deviceName]))
+);
+const frequencyLabel = (value) =>
+ frequencyOptions.find((item) => item.value === value)?.label || value || "-";
+const indexMethod = (index) => (pageNum.value - 1) * pageSize.value + index + 1;
+const form = reactive({
+ id: undefined,
+ itemProject: "",
+ itemName: "",
+ deviceLedgerId: undefined,
+ frequencyType: "",
+ sortNum: 0,
+ isActive: 1,
+ remarks: "",
+});
+const rules = {
+ itemProject: [{ required: true, message: "璇疯緭鍏ヤ繚鍏婚」鐩�", trigger: "blur" }],
+ itemName: [{ required: true, message: "璇疯緭鍏ヤ繚鍏诲唴瀹�", trigger: "blur" }],
+ frequencyType: [{ required: true, message: "璇烽�夋嫨淇濆吇棰戠巼", trigger: "change" }],
+};
+
+const load = async () => {
+ loading.value = true;
+ try {
+ const { code, data } = await getMaintenanceItemPage({
+ pageNum: pageNum.value,
+ pageSize: pageSize.value,
+ itemName: keyword.value.trim(),
+ isActive: 1,
+ deviceLedgerId: filters.deviceLedgerId,
+ frequencyType: filters.frequencyType,
+ includeCommon: true,
+ });
+ if (code === 200) {
+ items.value = data?.records || [];
+ total.value = Number(data?.total || 0);
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+
+const search = () => {
+ pageNum.value = 1;
+ load();
+};
+const resetFilters = () => {
+ filters.deviceLedgerId = undefined;
+ filters.frequencyType = "";
+ keyword.value = "";
+ search();
+};
+const handleSizeChange = () => {
+ pageNum.value = 1;
+ load();
+};
+
+const reset = () =>
+ Object.assign(form, {
+ id: undefined,
+ itemProject: "",
+ itemName: "",
+ deviceLedgerId: undefined,
+ frequencyType: "",
+ sortNum: 0,
+ isActive: 1,
+ remarks: "",
+ });
+const openAdd = () => {
+ reset();
+ dialogVisible.value = true;
+};
+const openEdit = (row) => {
+ Object.assign(form, { ...row });
+ dialogVisible.value = true;
+};
+
+const save = async () => {
+ if (
+ !(await formRef.value
+ ?.validate()
+ .then(() => true)
+ .catch(() => false))
+ )
+ return;
+ saving.value = true;
+ try {
+ const { code } = form.id
+ ? await editMaintenanceItem({ ...form })
+ : await addMaintenanceItem({ ...form });
+ if (code === 200) {
+ ElMessage.success("淇濆瓨鎴愬姛");
+ dialogVisible.value = false;
+ pageNum.value = 1;
+ await load();
+ }
+ } finally {
+ saving.value = false;
+ }
+};
+
+const removeItem = async (row) => {
+ try {
+ await ElMessageBox.confirm(`纭畾鍒犻櫎淇濆吇鍐呭鈥�${row.itemName}鈥濆悧锛焋, "鎻愮ず", {
+ type: "warning",
+ });
+ const { code } = await deleteMaintenanceItem(row.id);
+ if (code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ await load();
+ }
+ } catch (_) {
+ // 鐢ㄦ埛鍙栨秷
+ }
+};
+
+onMounted(async () => {
+ const { data } = await getDeviceLedger();
+ deviceOptions.value = data || [];
+ await load();
+});
+</script>
+
+<style scoped>
+.actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+}
+.pagination-wrap {
+ display: flex;
+ justify-content: flex-end;
+ padding-top: 12px;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue b/src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue
new file mode 100644
index 0000000..a485f24
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/MaintenanceItemSelector.vue
@@ -0,0 +1,181 @@
+<template>
+ <el-dialog
+ v-model="dialogVisible"
+ title="閫夋嫨淇濆吇椤圭洰"
+ width="760px"
+ append-to-body
+ destroy-on-close
+ >
+ <div class="selector-toolbar">
+ <el-input
+ v-model="keyword"
+ clearable
+ placeholder="鎸変繚鍏婚」鐩悳绱�"
+ @keyup.enter="search"
+ @clear="search"
+ />
+ <el-button type="primary" @click="search">鎼滅储</el-button>
+ </div>
+
+ <el-table v-loading="loading" :data="rows" border height="360">
+ <el-table-column label="閫夋嫨" width="70" align="center">
+ <template #default="{ row }">
+ <el-checkbox
+ :model-value="isSelected(row.id)"
+ @change="(checked) => toggleItem(row, checked)"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column type="index" label="搴忓彿" width="70" />
+ <el-table-column label="绫诲瀷" width="90" align="center">
+ <template #default="{ row }">
+ <el-tag :type="row.deviceLedgerId ? 'primary' : 'info'" size="small">{{
+ row.deviceLedgerId ? "鏈澶�" : "閫氱敤"
+ }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="itemProject" label="淇濆吇椤圭洰" min-width="300" show-overflow-tooltip />
+ <el-table-column label="棰戠巼" width="110" align="center">
+ <template #default="{ row }">
+ <el-tag :type="row.frequencyType === 'ALL' ? 'info' : 'success'" size="small">{{
+ frequencyLabel(row.frequencyType)
+ }}</el-tag>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <div class="selector-pagination">
+ <el-pagination
+ v-model:current-page="pageNum"
+ v-model:page-size="pageSize"
+ :page-sizes="[10, 20, 50]"
+ :total="total"
+ layout="total, sizes, prev, pager, next, jumper"
+ @size-change="handleSizeChange"
+ @current-change="load"
+ />
+ </div>
+
+ <template #footer>
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="confirm">纭畾閫夋嫨</el-button>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { computed, ref, watch } from "vue";
+import { getMaintenanceItemPage } from "@/api/equipmentManagement/upkeep";
+
+const props = defineProps({
+ visible: { type: Boolean, default: false },
+ selectedItems: { type: Array, default: () => [] },
+ deviceLedgerId: { type: [Number, String], default: undefined },
+ frequencyType: { type: String, default: "" },
+});
+const emit = defineEmits(["update:visible", "confirm"]);
+
+const dialogVisible = computed({
+ get: () => props.visible,
+ set: (value) => emit("update:visible", value),
+});
+const rows = ref([]);
+const loading = ref(false);
+const keyword = ref("");
+const pageNum = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+const selected = ref(new Map());
+const selectedList = computed(() => Array.from(selected.value.values()));
+const frequencyLabel = (value) =>
+ ({ DAILY: "姣忔棩", WEEKLY: "姣忓懆", MONTHLY: "姣忔湀", QUARTERLY: "姣忓搴�", ALL: "閫氱敤棰戠巼" }[
+ value
+ ] ||
+ value ||
+ "閫氱敤棰戠巼");
+
+watch(
+ () => props.visible,
+ (visible) => {
+ if (!visible) return;
+ keyword.value = "";
+ pageNum.value = 1;
+ selected.value = new Map((props.selectedItems || []).map((item) => [String(item.id), item]));
+ if (props.deviceLedgerId && props.frequencyType) load();
+ else {
+ rows.value = [];
+ total.value = 0;
+ }
+ }
+);
+watch(
+ () => [props.deviceLedgerId, props.frequencyType],
+ ([deviceId, frequency]) => {
+ if (!props.visible) return;
+ selected.value = new Map();
+ rows.value = [];
+ total.value = 0;
+ if (deviceId && frequency) {
+ pageNum.value = 1;
+ load();
+ }
+ }
+);
+
+const load = async () => {
+ loading.value = true;
+ try {
+ const { code, data } = await getMaintenanceItemPage({
+ pageNum: pageNum.value,
+ pageSize: pageSize.value,
+ itemProject: keyword.value.trim(),
+ isActive: 1,
+ deviceLedgerId: props.deviceLedgerId,
+ frequencyType: props.frequencyType,
+ includeCommon: true,
+ });
+ if (code === 200) {
+ rows.value = data?.records || [];
+ total.value = Number(data?.total || 0);
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+
+const search = () => {
+ pageNum.value = 1;
+ load();
+};
+const handleSizeChange = () => {
+ pageNum.value = 1;
+ load();
+};
+const isSelected = (id) => selected.value.has(String(id));
+const toggleItem = (item, checked) => {
+ const next = new Map(selected.value);
+ if (checked) next.set(String(item.id), item);
+ else next.delete(String(item.id));
+ selected.value = next;
+};
+const confirm = () => {
+ emit("confirm", selectedList.value);
+ dialogVisible.value = false;
+};
+</script>
+
+<style scoped>
+.selector-toolbar {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 14px;
+}
+.selector-toolbar .el-input {
+ max-width: 420px;
+}
+.selector-pagination {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 14px;
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
index 0fcccb2..fd71e1a 100644
--- a/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -1,71 +1,122 @@
<template>
- <FormDialog v-model="visible"
- :title="'璁惧淇濆吇'"
- width="500px"
- @confirm="sendForm"
- @cancel="handleCancel"
- @close="handleClose">
- <el-form :model="form"
- label-width="100px">
+ <FormDialog
+ v-model="visible"
+ :title="'璁惧淇濆吇'"
+ width="1080px"
+ @confirm="sendForm"
+ @cancel="handleCancel"
+ @close="handleClose"
+ >
+ <el-form :model="form" label-width="100px">
<el-form-item label="瀹為檯淇濆吇浜�">
- <el-input v-model="form.maintenanceActuallyName"
- placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"></el-input>
+ <el-input v-model="form.maintenanceActuallyName" placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"></el-input>
</el-form-item>
<el-form-item label="瀹為檯淇濆吇鏃ユ湡">
- <el-date-picker v-model="form.maintenanceActuallyTime"
- placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
- format="YYYY-MM-DD HH:mm:ss"
- value-format="YYYY-MM-DD HH:mm:ss"
- type="datetime"
- clearable
- style="width: 100%" />
+ <el-date-picker
+ v-model="form.maintenanceActuallyTime"
+ placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
+ format="YYYY-MM-DD HH:mm:ss"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ type="datetime"
+ clearable
+ style="width: 100%"
+ />
+ </el-form-item>
+ <el-form-item label="淇濆吇鍐呭" required>
+ <div v-if="form.maintenanceItems.length" class="maintenance-checklist">
+ <div class="maintenance-checklist__header">
+ <span
+ >宸插畬鎴� {{ completedCount }} /
+ {{ form.maintenanceItems.length }} 椤癸紝璇峰嬀閫夊凡淇濆吇鐨勫唴瀹�</span
+ >
+ <el-button link type="primary" @click="toggleAll">{{
+ completedCount === form.maintenanceItems.length ? "鍏ㄩ儴鍙栨秷" : "鍏ㄩ儴鍕鹃��"
+ }}</el-button>
+ </div>
+ <div
+ v-for="(item, index) in form.maintenanceItems"
+ :key="item.id"
+ class="maintenance-checklist__item"
+ :class="{ 'is-done': item.itemStatus === 1 }"
+ >
+ <el-checkbox
+ class="maintenance-checklist__check"
+ :model-value="item.itemStatus === 1"
+ @change="(checked) => (item.itemStatus = checked ? 1 : 0)"
+ >宸插畬鎴�</el-checkbox
+ >
+ <div class="maintenance-checklist__body">
+ <div class="maintenance-checklist__content">
+ <span class="maintenance-checklist__number">{{ index + 1 }}.</span
+ ><span>{{ item.itemName || item.itemProject || "鏈~鍐欎繚鍏诲唴瀹�" }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <el-empty v-else description="璇ヤ繚鍏昏褰曟病鏈変繚鍏诲唴瀹�" :image-size="60" />
</el-form-item>
<el-form-item label="淇濆吇鐘舵��">
<el-select v-model="form.status">
- <el-option label="寰呬繚鍏�"
- :value="0"></el-option>
- <el-option label="瀹岀粨"
- :value="1"></el-option>
- <el-option label="澶辫触"
- :value="2"></el-option>
+ <el-option label="寰呬繚鍏�" :value="0"></el-option>
+ <el-option label="瀹岀粨" :value="1"></el-option>
+ <el-option label="澶辫触" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="淇濆吇缁撴灉">
- <el-input v-model="form.maintenanceResult"
- placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�"
- type="text" />
+ <el-input v-model="form.maintenanceResult" placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�" type="text" />
</el-form-item>
<el-form-item label="璁惧澶囦欢">
- <el-select v-model="form.sparePartsIds"
- :loading="loadingSparePartOptions"
- placeholder="璇烽�夋嫨璁惧澶囦欢"
- multiple
- filterable>
- <el-option v-for="item in sparePartOptions"
- :key="item.id"
- :label="item.name"
- :value="item.id" />
+ <el-select
+ v-model="form.sparePartsIds"
+ :loading="loadingSparePartOptions"
+ placeholder="璇烽�夋嫨璁惧澶囦欢"
+ multiple
+ filterable
+ >
+ <el-option
+ v-for="item in sparePartOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id"
+ />
</el-select>
</el-form-item>
- <el-form-item v-if="selectedSpareParts.length"
- label="棰嗙敤鏁伴噺">
+ <el-form-item v-if="selectedSpareParts.length" label="棰嗙敤鏁伴噺">
<div style="width: 100%">
- <div v-for="item in selectedSpareParts"
- :key="item.id"
- style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
- <div style="flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
+ <div
+ v-for="item in selectedSpareParts"
+ :key="item.id"
+ style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px"
+ >
+ <div
+ style="
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ "
+ >
{{ item.name }}
- <span v-if="item.quantity !== null && item.quantity !== undefined"
- style="color: #909399;">
+ <span
+ v-if="item.quantity !== null && item.quantity !== undefined"
+ style="color: #909399"
+ >
锛堝簱瀛橈細{{ item.quantity }}锛�
</span>
</div>
- <el-input-number v-model="sparePartQtyMap[item.id]"
- :min="1"
- :max="item.quantity !== null && item.quantity !== undefined ? Number(item.quantity) : undefined"
- :step="1"
- controls-position="right"
- style="width: 180px" />
+ <el-input-number
+ v-model="sparePartQtyMap[item.id]"
+ :min="1"
+ :max="
+ item.quantity !== null && item.quantity !== undefined
+ ? Number(item.quantity)
+ : undefined
+ "
+ :step="1"
+ controls-position="right"
+ style="width: 180px"
+ />
</div>
</div>
</el-form-item>
@@ -77,177 +128,256 @@
</template>
<script setup>
- import FormDialog from "@/components/Dialog/FormDialog.vue";
- import FileUpload from "@/components/AttachmentUpload/file/index.vue";
- import { addMaintenance } from "@/api/equipmentManagement/upkeep";
- import useFormData from "@/hooks/useFormData";
- import dayjs from "dayjs";
- import useUserStore from "@/store/modules/user";
- import { ElMessage } from "element-plus";
- import { computed, ref, nextTick, getCurrentInstance } from "vue";
- import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+import { addMaintenance } from "@/api/equipmentManagement/upkeep";
+import useFormData from "@/hooks/useFormData";
+import dayjs from "dayjs";
+import useUserStore from "@/store/modules/user";
+import { ElMessage } from "element-plus";
+import { computed, ref, nextTick, getCurrentInstance } from "vue";
+import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
- defineOptions({
- name: "淇濆吇妯℃�佹",
- });
+defineOptions({
+ name: "淇濆吇妯℃�佹",
+});
- const emits = defineEmits(["ok"]);
+const emits = defineEmits(["ok"]);
- const { proxy } = getCurrentInstance();
- // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
- const planId = ref();
- const visible = ref(false);
- const loading = ref(false);
- const userStore = useUserStore();
+const { proxy } = getCurrentInstance();
+// 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+const planId = ref();
+const visible = ref(false);
+const loading = ref(false);
+const userStore = useUserStore();
- const { form, resetForm } = useFormData({
- maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
- maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
- maintenanceResult: undefined, // 淇濆吇缁撴灉
- status: 0, // 淇濆吇鐘舵��
- sparePartsIds: [],
- storageBlobDTOs: [],
- });
+const { form, resetForm } = useFormData({
+ maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
+ maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
+ maintenanceResult: undefined, // 淇濆吇缁撴灉
+ status: 0, // 淇濆吇鐘舵��
+ maintenanceItems: [],
+ sparePartsIds: [],
+ storageBlobDTOs: [],
+});
- const sparePartOptions = ref([]);
- const loadingSparePartOptions = ref(true);
- const sparePartQtyMap = ref({});
+const sparePartOptions = ref([]);
+const loadingSparePartOptions = ref(true);
+const sparePartQtyMap = ref({});
- const selectedSpareParts = computed(() => {
- const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : [];
- const set = new Set(ids.map(i => String(i)));
- return (sparePartOptions.value || []).filter(p => set.has(String(p.id)));
- });
+const selectedSpareParts = computed(() => {
+ const ids = Array.isArray(form.sparePartsIds) ? form.sparePartsIds : [];
+ const set = new Set(ids.map((i) => String(i)));
+ return (sparePartOptions.value || []).filter((p) => set.has(String(p.id)));
+});
- const setForm = data => {
- form.maintenanceActuallyName =
- data.maintenanceActuallyName ?? userStore.nickName;
- form.maintenanceActuallyTime = data.maintenanceActuallyTime
- ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
- : dayjs().format("YYYY-MM-DD HH:mm:ss");
- form.maintenanceResult = data.maintenanceResult;
- form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
- // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
- if (Array.isArray(data?.sparePartsIds)) {
- form.sparePartsIds = data.sparePartsIds
- .map(v => Number(v))
- .filter(v => Number.isFinite(v));
- } else if (typeof data?.sparePartsIds === "string") {
- form.sparePartsIds = data.sparePartsIds
- .split(",")
- .map(s => Number(String(s).trim()))
- .filter(v => Number.isFinite(v));
- } else if (typeof data?.sparePartsIds === "number") {
- form.sparePartsIds = [data.sparePartsIds];
- } else {
- form.sparePartsIds = [];
+const completedCount = computed(
+ () => form.maintenanceItems.filter((item) => item.itemStatus === 1).length
+);
+const toggleAll = () => {
+ const status = completedCount.value === form.maintenanceItems.length ? 0 : 1;
+ form.maintenanceItems.forEach((item) => (item.itemStatus = status));
+};
+
+const setForm = (data) => {
+ form.maintenanceActuallyName = data.maintenanceActuallyName ?? userStore.nickName;
+ form.maintenanceActuallyTime = data.maintenanceActuallyTime
+ ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
+ : dayjs().format("YYYY-MM-DD HH:mm:ss");
+ form.maintenanceResult = data.maintenanceResult;
+ form.status = 1; // 榛樿鐘舵�佷负瀹岀粨
+ form.maintenanceItems = (data.maintenanceItems || []).map((item) => ({
+ ...item,
+ itemStatus: Number(item.itemStatus || 0),
+ }));
+ // multiple 閫夋嫨鍣ㄨ姹傛暟缁勶紱鍚庣甯歌繑鍥� "1,2,3"
+ if (Array.isArray(data?.sparePartsIds)) {
+ form.sparePartsIds = data.sparePartsIds.map((v) => Number(v)).filter((v) => Number.isFinite(v));
+ } else if (typeof data?.sparePartsIds === "string") {
+ form.sparePartsIds = data.sparePartsIds
+ .split(",")
+ .map((s) => Number(String(s).trim()))
+ .filter((v) => Number.isFinite(v));
+ } else if (typeof data?.sparePartsIds === "number") {
+ form.sparePartsIds = [data.sparePartsIds];
+ } else {
+ form.sparePartsIds = [];
+ }
+ form.storageBlobDTOs = data.storageBlobVOs || [];
+};
+
+/**
+ * @desc 淇濆瓨淇濆吇
+ */
+const sendForm = async () => {
+ loading.value = true;
+ try {
+ if (!form.maintenanceItems.length) {
+ ElMessage.warning("褰撳墠璁板綍娌℃湁淇濆吇鍐呭锛岃鍏堢紪杈戜繚鍏讳换鍔�");
+ return;
}
- form.storageBlobDTOs = data.storageBlobVOs || [];
- };
-
- /**
- * @desc 淇濆瓨淇濆吇
- */
- const sendForm = async () => {
- loading.value = true;
- try {
- // 棰嗙敤鏁伴噺鏍¢獙
- if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) {
- for (const partId of form.sparePartsIds) {
- const qty = Number(sparePartQtyMap.value?.[partId]);
- if (!Number.isFinite(qty) || qty <= 0) {
- proxy?.$modal?.msgError?.("璇峰~鍐欏浠堕鐢ㄦ暟閲�");
+ // 棰嗙敤鏁伴噺鏍¢獙
+ if (Array.isArray(form.sparePartsIds) && form.sparePartsIds.length > 0) {
+ for (const partId of form.sparePartsIds) {
+ const qty = Number(sparePartQtyMap.value?.[partId]);
+ if (!Number.isFinite(qty) || qty <= 0) {
+ proxy?.$modal?.msgError?.("璇峰~鍐欏浠堕鐢ㄦ暟閲�");
+ return;
+ }
+ const part = sparePartOptions.value.find((p) => String(p.id) === String(partId));
+ const stock = part?.quantity;
+ if (stock !== null && stock !== undefined && Number.isFinite(Number(stock))) {
+ if (qty > Number(stock)) {
+ proxy?.$modal?.msgError?.(
+ `澶囦欢銆�${part?.name || ""}銆嶉鐢ㄦ暟閲忎笉鑳借秴杩囧簱瀛橈紙${stock}锛塦
+ );
return;
}
- const part = sparePartOptions.value.find(
- p => String(p.id) === String(partId)
- );
- const stock = part?.quantity;
- if (
- stock !== null &&
- stock !== undefined &&
- Number.isFinite(Number(stock))
- ) {
- if (qty > Number(stock)) {
- proxy?.$modal?.msgError?.(
- `澶囦欢銆�${part?.name || ""}銆嶉鐢ㄦ暟閲忎笉鑳借秴杩囧簱瀛橈紙${stock}锛塦
- );
- return;
- }
- }
}
}
- const data = {
- id: planId.value,
- ...form,
- sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
- sparePartsQty: form.sparePartsIds
- ? form.sparePartsIds
- .map(id => sparePartQtyMap.value?.[id] ?? 1)
- .join(",")
- : "",
- sparePartsUseList: form.sparePartsIds
- ? form.sparePartsIds.map(id => ({
- id,
- quantity: sparePartQtyMap.value?.[id] ?? 1,
- }))
- : [],
- };
- const { code } = await addMaintenance(data);
- if (code == 200) {
- ElMessage.success("淇濆吇鎴愬姛");
- emits("ok");
- resetForm();
- sparePartQtyMap.value = {};
- visible.value = false;
- }
- } finally {
- loading.value = false;
}
- };
+ const data = {
+ id: planId.value,
+ ...form,
+ maintenanceItems: form.maintenanceItems.map((item) => ({
+ id: item.id,
+ itemStatus: item.itemStatus,
+ })),
+ sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
+ sparePartsQty: form.sparePartsIds
+ ? form.sparePartsIds.map((id) => sparePartQtyMap.value?.[id] ?? 1).join(",")
+ : "",
+ sparePartsUseList: form.sparePartsIds
+ ? form.sparePartsIds.map((id) => ({
+ id,
+ quantity: sparePartQtyMap.value?.[id] ?? 1,
+ }))
+ : [],
+ };
+ const { code } = await addMaintenance(data);
+ if (code == 200) {
+ ElMessage.success("淇濆吇鎴愬姛");
+ emits("ok");
+ resetForm();
+ sparePartQtyMap.value = {};
+ visible.value = false;
+ }
+ } finally {
+ loading.value = false;
+ }
+};
- const fetchSparePartOptions = () => {
- loadingSparePartOptions.value = true;
- // 鍜屽浠剁鐞嗛〉涓�鑷达細/spareParts/listPage 鈫� res.data.records
- getSparePartsList({ current: 1, size: 1000 })
- .then(res => {
- if (res.code === 200) {
- sparePartOptions.value = res?.data?.records || [];
- } else {
- sparePartOptions.value = [];
- }
- })
- .catch(() => {
+const fetchSparePartOptions = () => {
+ loadingSparePartOptions.value = true;
+ // 鍜屽浠剁鐞嗛〉涓�鑷达細/spareParts/listPage 鈫� res.data.records
+ getSparePartsList({ current: 1, size: 1000 })
+ .then((res) => {
+ if (res.code === 200) {
+ sparePartOptions.value = res?.data?.records || [];
+ } else {
sparePartOptions.value = [];
- })
- .finally(() => {
- loadingSparePartOptions.value = false;
- });
- };
+ }
+ })
+ .catch(() => {
+ sparePartOptions.value = [];
+ })
+ .finally(() => {
+ loadingSparePartOptions.value = false;
+ });
+};
- const handleCancel = () => {
- resetForm();
- sparePartQtyMap.value = {};
- visible.value = false;
- };
+const handleCancel = () => {
+ resetForm();
+ sparePartQtyMap.value = {};
+ visible.value = false;
+};
- const handleClose = () => {
- resetForm();
- sparePartQtyMap.value = {};
- visible.value = false;
- };
+const handleClose = () => {
+ resetForm();
+ sparePartQtyMap.value = {};
+ visible.value = false;
+};
- const open = async (id, row) => {
- planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
- visible.value = true;
- await nextTick();
- fetchSparePartOptions();
- setForm(row);
- };
+const open = async (id, row) => {
+ planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+ visible.value = true;
+ await nextTick();
+ fetchSparePartOptions();
+ setForm(row);
+};
- defineExpose({
- open,
- });
+defineExpose({
+ open,
+});
</script>
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.maintenance-checklist {
+ width: 100%;
+ border: 1px solid #bfc7cf;
+ background: #fff;
+ overflow: hidden;
+}
+.maintenance-checklist__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 11px 16px;
+ background: #f3f5f7;
+ border-bottom: 1px solid #bfc7cf;
+ color: #303946;
+ font-size: 14px;
+ font-weight: 600;
+}
+.maintenance-checklist__item {
+ display: grid;
+ grid-template-columns: 42px minmax(0, 1fr) 110px;
+ align-items: start;
+ gap: 12px;
+ padding: 15px 16px;
+ border-bottom: 1px solid #d8dde2;
+}
+.maintenance-checklist__item:last-child {
+ border-bottom: none;
+}
+.maintenance-checklist__item.is-done {
+ background: #f6faf5;
+}
+.maintenance-checklist__check {
+ grid-column: 3;
+ grid-row: 1;
+ justify-self: center;
+ margin: 0;
+}
+.maintenance-checklist__body {
+ grid-column: 1 / 3;
+ grid-row: 1;
+ min-width: 0;
+}
+.maintenance-checklist__content {
+ display: grid;
+ grid-template-columns: 32px minmax(0, 1fr);
+ line-height: 1.75;
+ color: #303946;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+.maintenance-checklist__number {
+ color: #606a75;
+ font-weight: 600;
+}
+:deep(.el-dialog) {
+ max-width: calc(100vw - 32px);
+}
+:deep(.el-dialog__body) {
+ max-height: calc(100vh - 190px);
+ overflow-y: auto;
+}
+@media (max-width: 720px) {
+ .maintenance-checklist__item {
+ grid-template-columns: 30px minmax(0, 1fr) 78px;
+ gap: 8px;
+ padding: 12px 8px;
+ }
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
index 29e218a..acb8f7b 100644
--- a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -2,7 +2,7 @@
<FormDialog
v-model="visible"
:title="id ? '缂栬緫璁惧淇濆吇璁″垝' : '鏂板璁惧淇濆吇璁″垝'"
- width="500px"
+ width="960px"
@confirm="sendForm"
@cancel="handleCancel"
@close="handleClose"
@@ -26,18 +26,46 @@
</el-select>
</el-form-item>
<el-form-item label="瑙勬牸鍨嬪彿">
- <el-input
- v-model="form.deviceModel"
- placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
- disabled
- />
+ <el-input v-model="form.deviceModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" disabled />
</el-form-item>
- <el-form-item label="淇濆吇椤圭洰">
- <el-input
- v-model="form.machineryCategory"
- type="textarea"
- placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
- />
+ <el-form-item label="淇濆吇棰戠巼">
+ <el-select
+ v-model="form.frequencyType"
+ placeholder="璇峰厛閫夋嫨淇濆吇棰戠巼"
+ @change="clearSelectedItems"
+ >
+ <el-option label="姣忔棩" value="DAILY" />
+ <el-option label="姣忓懆" value="WEEKLY" />
+ <el-option label="姣忔湀" value="MONTHLY" />
+ <el-option label="姣忓搴�" value="QUARTERLY" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="淇濆吇鍐呭">
+ <div class="maintenance-selection">
+ <el-button
+ type="primary"
+ plain
+ :disabled="!form.deviceLedgerId || !form.frequencyType"
+ @click="itemSelectorVisible = true"
+ >閫夋嫨淇濆吇鍐呭</el-button
+ >
+ <div v-if="selectedMaintenanceItems.length" class="paper-list">
+ <div class="paper-list__heading">
+ <strong>淇濆吇椤圭洰娓呭崟</strong>
+ <span>鍏� {{ selectedMaintenanceItems.length }} 椤�</span>
+ </div>
+ <div
+ v-for="(item, index) in selectedMaintenanceItems"
+ :key="item.id"
+ class="paper-list__row"
+ >
+ <span class="paper-list__number">{{ index + 1 }}</span>
+ <span class="paper-list__content">{{ item.itemName }}</span>
+ <el-button link type="danger" @click="removeMaintenanceItem(item.id)">绉婚櫎</el-button>
+ </div>
+ </div>
+ <el-empty v-else description="閫夋嫨璁惧鍜岄鐜囧悗锛屾坊鍔犳湰璁″垝鐨勪繚鍏婚」鐩�" :image-size="54" />
+ </div>
</el-form-item>
<el-form-item label="褰曞叆浜�">
<el-select
@@ -64,11 +92,7 @@
</el-select>
</el-form-item>
<el-form-item label="淇濆吇浜�">
- <el-input
- v-model="form.maintenancePerson"
- placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
- clearable
- />
+ <el-input v-model="form.maintenancePerson" placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕" clearable />
</el-form-item>
<el-form-item label="璁″垝淇濆吇鏃ユ湡">
<el-date-picker
@@ -90,22 +114,26 @@
</el-row>
</el-form>
</FormDialog>
+ <MaintenanceItemSelector
+ v-model:visible="itemSelectorVisible"
+ :selected-items="selectedMaintenanceItems"
+ :device-ledger-id="form.deviceLedgerId"
+ :frequency-type="form.frequencyType"
+ @confirm="applyMaintenanceItems"
+ />
</template>
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
-import {
- addUpkeep,
- editUpkeep,
- getUpkeepById,
-} from "@/api/equipmentManagement/upkeep";
+import { addUpkeep, editUpkeep, getUpkeepById } from "@/api/equipmentManagement/upkeep";
import { ElMessage } from "element-plus";
import useFormData from "@/hooks/useFormData";
import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
-import { onMounted } from "vue";
+import { computed, onMounted } from "vue";
import dayjs from "dayjs";
import { userListNoPage } from "@/api/system/user.js";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
+import MaintenanceItemSelector from "./MaintenanceItemSelector.vue";
defineOptions({
name: "璁惧淇濆吇鏂板璁″垝",
@@ -116,8 +144,10 @@
const id = ref();
const visible = ref(false);
const loading = ref(false);
+const itemSelectorVisible = ref(false);
const deviceOptions = ref([]);
+const maintenanceItemOptions = ref([]);
const loadDeviceName = async () => {
const { data } = await getDeviceLedger();
deviceOptions.value = data;
@@ -130,14 +160,39 @@
maintenancePlanTime: undefined, // 璁″垝淇濆吇鏃ユ湡
createUser: undefined, // 褰曞叆浜�
status: 0, //淇濅慨鐘舵��
- machineryCategory: undefined,
+ maintenanceItemIds: [],
+ frequencyType: "",
storageBlobDTOs: [],
maintenancePerson: undefined, // 淇濆吇浜�
});
+const selectedMaintenanceItems = computed(() => {
+ const ids = new Set((form.maintenanceItemIds || []).map(String));
+ return maintenanceItemOptions.value.filter((item) => ids.has(String(item.id)));
+});
+const applyMaintenanceItems = (items) => {
+ maintenanceItemOptions.value = items;
+ form.maintenanceItemIds = items.map((item) => item.id);
+};
+const clearSelectedItems = () => {
+ form.maintenanceItemIds = [];
+ maintenanceItemOptions.value = [];
+};
+const removeMaintenanceItem = (id) => {
+ form.maintenanceItemIds = form.maintenanceItemIds.filter(
+ (itemId) => String(itemId) !== String(id)
+ );
+ maintenanceItemOptions.value = maintenanceItemOptions.value.filter(
+ (item) => String(item.id) !== String(id)
+ );
+};
+
const setDeviceModel = (deviceId) => {
const option = deviceOptions.value.find((item) => item.id === deviceId);
- form.deviceModel = option.deviceModel;
+ if (option) {
+ form.deviceModel = option.deviceModel;
+ clearSelectedItems();
+ }
};
/**
@@ -146,16 +201,21 @@
*/
const setForm = (data) => {
form.deviceLedgerId = data.deviceLedgerId;
+ form.frequencyType = data.frequencyType;
form.deviceName = data.deviceName;
form.deviceModel = data.deviceModel;
form.createUser = Number(data.createUser);
form.status = data.status;
- form.machineryCategory = data.machineryCategory;
+ form.maintenanceItemIds =
+ data.maintenanceItemIds || data.maintenanceItems?.map((item) => item.maintenanceItemId) || [];
+ maintenanceItemOptions.value = (data.maintenanceItems || []).map((item) => ({
+ id: item.maintenanceItemId,
+ itemName: item.itemName,
+ isActive: item.isActive,
+ }));
form.maintenancePerson = data.maintenancePerson;
if (data.maintenancePlanTime) {
- form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
- "YYYY-MM-DD HH:mm:ss"
- );
+ form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format("YYYY-MM-DD HH:mm:ss");
}
form.storageBlobDTOs = data.storageBlobVOs || [];
};
@@ -179,6 +239,14 @@
};
const sendForm = async () => {
+ if (!form.deviceLedgerId || !form.frequencyType) {
+ ElMessage.warning("璇烽�夋嫨璁惧鍜屼繚鍏婚鐜�");
+ return;
+ }
+ if (!form.maintenanceItemIds?.length) {
+ ElMessage.warning("璇烽�夋嫨鑷冲皯涓�涓繚鍏婚」鐩�");
+ return;
+ }
loading.value = true;
try {
const { code } = id.value
@@ -195,11 +263,13 @@
};
const handleCancel = () => {
+ itemSelectorVisible.value = false;
resetForm();
visible.value = false;
};
const handleClose = () => {
+ itemSelectorVisible.value = false;
resetForm();
visible.value = false;
};
@@ -207,6 +277,7 @@
const openModal = () => {
id.value = undefined;
visible.value = true;
+ maintenanceItemOptions.value = [];
};
defineExpose({
@@ -215,4 +286,61 @@
});
</script>
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.maintenance-selection {
+ width: 100%;
+}
+.paper-list {
+ margin-top: 12px;
+ border: 1px solid #cbd2d9;
+ background: #fff;
+}
+.paper-list__heading {
+ display: flex;
+ justify-content: space-between;
+ padding: 10px 14px;
+ border-bottom: 1px solid #cbd2d9;
+ background: #f5f7fa;
+ color: #303946;
+}
+.paper-list__heading span {
+ color: #606a75;
+ font-size: 13px;
+ font-weight: normal;
+}
+.paper-list__row {
+ display: grid;
+ grid-template-columns: 38px minmax(0, 1fr) 52px;
+ align-items: start;
+ gap: 10px;
+ padding: 12px 14px;
+ border-bottom: 1px solid #e1e5e9;
+}
+.paper-list__row:last-child {
+ border-bottom: 0;
+}
+.paper-list__number {
+ color: #596575;
+ text-align: center;
+}
+.paper-list__content {
+ color: #303946;
+ line-height: 1.7;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+:deep(.el-dialog) {
+ max-width: calc(100vw - 32px);
+}
+:deep(.el-dialog__body) {
+ max-height: calc(100vh - 180px);
+ overflow-y: auto;
+}
+@media (max-width: 720px) {
+ .paper-list__row {
+ grid-template-columns: 28px minmax(0, 1fr) 42px;
+ gap: 6px;
+ padding: 10px 8px;
+ }
+}
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
index 074628c..3c60c3a 100644
--- a/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/RecordDetailDia.vue
@@ -1,99 +1,191 @@
<template>
- <FormDialog
- v-model="dialogVisitable"
- title="淇濆吇璁板綍璇︽儏"
- width="800px"
- operation-type="detail"
- @close="cancel"
- >
- <el-descriptions border :column="2">
- <el-descriptions-item label="璁惧鍚嶇О">
- {{ detailData.deviceName || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="瑙勬牸鍨嬪彿">
- {{ detailData.deviceModel || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="璁″垝淇濆吇鏃ユ湡">
- {{ formatDate(detailData.maintenancePlanTime) }}
- </el-descriptions-item>
- <el-descriptions-item label="褰曞叆浜�">
- {{ detailData.createUserName || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="淇濆吇椤圭洰" :span="2">
- {{ detailData.machineryCategory || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="瀹為檯淇濆吇浜�">
- {{ detailData.maintenanceActuallyName || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="瀹為檯淇濆吇鏃ユ湡">
- {{ formatDate(detailData.maintenanceActuallyTime) }}
- </el-descriptions-item>
- <el-descriptions-item label="淇濆吇缁撴灉" :span="2">
- {{ detailData.maintenanceResult || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="鐘舵��" :span="2">
- <el-tag v-if="detailData.status === 2" type="danger">澶辫触</el-tag>
- <el-tag v-else-if="detailData.status === 1" type="success">瀹岀粨</el-tag>
- <el-tag v-else type="warning">寰呬繚鍏�</el-tag>
- </el-descriptions-item>
- </el-descriptions>
+ <FormDialog
+ v-model="dialogVisitable"
+ title="淇濆吇璁板綍璇︽儏"
+ width="860px"
+ operation-type="detail"
+ @close="cancel"
+ >
+ <el-descriptions border :column="2" label-width="110px">
+ <el-descriptions-item label="璁惧鍚嶇О">
+ {{ detailData.deviceName || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瑙勬牸鍨嬪彿">
+ {{ detailData.deviceModel || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="璁″垝淇濆吇鏃ユ湡">
+ {{ formatDate(detailData.maintenancePlanTime) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="褰曞叆浜�">
+ {{ detailData.createUserName || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹為檯淇濆吇浜�">
+ {{ detailData.maintenanceActuallyName || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹為檯淇濆吇鏃ユ湡">
+ {{ formatDate(detailData.maintenanceActuallyTime) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="淇濆吇缁撴灉" :span="2">
+ {{ detailData.maintenanceResult || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐘舵��" :span="2">
+ <el-tag v-if="detailData.status === 2" type="danger" size="small">澶辫触</el-tag>
+ <el-tag v-else-if="detailData.status === 1" type="success" size="small">瀹岀粨</el-tag>
+ <el-tag v-else type="warning" size="small">寰呬繚鍏�</el-tag>
+ </el-descriptions-item>
+ </el-descriptions>
- <div v-if="fileList && fileList.length > 0" class="image-section">
- <div class="image-title">淇濆吇闄勪欢(鍥剧墖)锛�</div>
- <AttachmentUploadImage
- v-model:fileList="fileList"
- :disabled="true"
- />
- </div>
- </FormDialog>
+ <div class="detail-section">
+ <div class="section-title">
+ <span>淇濆吇鍐呭</span>
+ <span class="section-count">鍏� {{ itemCount }} 椤癸紝宸插畬鎴� {{ doneCount }} 椤�</span>
+ </div>
+ <div v-if="itemCount" class="item-list">
+ <div
+ v-for="(item, index) in detailData.maintenanceItems"
+ :key="item.id || index"
+ class="item-row"
+ >
+ <span class="item-index">{{ index + 1 }}</span>
+ <div class="item-body">
+ <div class="item-head">
+ <span class="item-project">{{ item.itemProject || "鏈~鍐欎繚鍏婚」鐩�" }}</span>
+ <el-tag size="small" effect="light" :type="statusMeta(item.itemStatus).type">{{
+ statusMeta(item.itemStatus).label
+ }}</el-tag>
+ </div>
+ <div class="item-content">{{ item.itemName }}</div>
+ </div>
+ </div>
+ </div>
+ <el-empty v-else :image-size="48" description="鏆傛棤淇濆吇鍐呭" />
+ </div>
+
+ <div v-if="fileList && fileList.length > 0" class="image-section">
+ <div class="image-title">淇濆吇闄勪欢(鍥剧墖)锛�</div>
+ <AttachmentUploadImage v-model:fileList="fileList" :disabled="true" />
+ </div>
+ </FormDialog>
</template>
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { ref } from "vue";
+import { computed, ref } from "vue";
import dayjs from "dayjs";
import { attachmentList } from "@/api/basicData/storageAttachment.js";
-import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+import AttachmentUploadImage from "@/components/AttachmentUpload/image/index.vue";
const dialogVisitable = ref(false);
const detailData = ref({});
const fileList = ref([]);
+const itemCount = computed(() => detailData.value.maintenanceItems?.length || 0);
+const doneCount = computed(
+ () => (detailData.value.maintenanceItems || []).filter((item) => item.itemStatus === 1).length
+);
const formatDate = (date) => {
- return date ? dayjs(date).format("YYYY-MM-DD") : "--";
+ return date ? dayjs(date).format("YYYY-MM-DD") : "--";
+};
+
+const statusMeta = (status) => {
+ if (status === 1) return { label: "宸插畬鎴�", type: "success" };
+ if (status === 2) return { label: "寮傚父", type: "danger" };
+ if (Number(detailData.value.status) === 1) return { label: "鏈畬鎴�", type: "warning" };
+ return { label: "寰呭畬鎴�", type: "info" };
};
const openDialog = (row) => {
- dialogVisitable.value = true;
- detailData.value = { ...row };
- fileList.value = [];
+ dialogVisitable.value = true;
+ detailData.value = { ...row };
+ fileList.value = [];
- if (row.id) {
- attachmentList({
- recordType: 'device_maintenance',
- recordId: row.id,
- }).then(res => {
- if (res && res.data) {
- fileList.value = res.data || [];
- }
- });
- }
+ if (row.id) {
+ attachmentList({
+ recordType: "device_maintenance",
+ recordId: row.id,
+ }).then((res) => {
+ if (res && res.data) {
+ fileList.value = res.data || [];
+ }
+ });
+ }
};
const cancel = () => {
- dialogVisitable.value = false;
+ dialogVisitable.value = false;
};
defineExpose({ openDialog });
</script>
<style scoped>
+.detail-section {
+ margin-top: 16px;
+}
+.section-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ font-weight: 600;
+ color: #303133;
+}
+.section-count {
+ font-size: 12px;
+ font-weight: normal;
+ color: #909399;
+}
+.item-list {
+ border: 1px solid #ebeef5;
+ border-radius: 4px;
+ overflow: hidden;
+}
+.item-row {
+ display: flex;
+ gap: 12px;
+ padding: 12px 14px;
+ border-bottom: 1px solid #ebeef5;
+}
+.item-row:last-child {
+ border-bottom: none;
+}
+.item-index {
+ flex-shrink: 0;
+ width: 24px;
+ height: 24px;
+ line-height: 24px;
+ text-align: center;
+ border-radius: 50%;
+ background: #ecf5ff;
+ color: #409eff;
+ font-size: 12px;
+}
+.item-body {
+ flex: 1;
+ min-width: 0;
+}
+.item-head {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 4px;
+}
+.item-project {
+ font-weight: 600;
+ color: #303133;
+}
+.item-content {
+ line-height: 1.6;
+ color: #606266;
+ white-space: pre-wrap;
+ word-break: break-all;
+}
.image-section {
- margin-top: 20px;
+ margin-top: 20px;
}
.image-title {
- font-weight: bold;
- margin-bottom: 10px;
- color: #606266;
+ font-weight: bold;
+ margin-bottom: 10px;
+ color: #606266;
}
</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/detailDia.vue b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
index c80691a..ddf9be4 100644
--- a/src/views/equipmentManagement/upkeep/Form/detailDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/detailDia.vue
@@ -1,118 +1,190 @@
<template>
- <FormDialog
- v-model="dialogVisitable"
- title="淇濆吇浠诲姟璇︽儏"
- width="800px"
- operation-type="detail"
- @close="cancel"
- >
- <el-descriptions border :column="2">
- <el-descriptions-item label="璁惧鍚嶇О">
- {{ detailData.taskName || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="瑙勬牸鍨嬪彿">
- {{ detailData.deviceModel || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="褰曞叆浜�">
- {{ detailData.registrant || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="鐧昏鏃堕棿">
- {{ detailData.registrationDate || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="淇濆吇椤圭洰" :span="2">
- {{ detailData.machineryCategory || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="淇濆吇浜�">
- {{ detailData.maintenancePerson || '--' }}
- </el-descriptions-item>
- <el-descriptions-item label="浠诲姟棰戠巼">
- {{ formatFrequencyType(detailData.frequencyType) }}
- </el-descriptions-item>
- <el-descriptions-item label="鎵ц鏃堕棿">
- {{ formatFrequencyDetail(detailData.frequencyDetail) }}
- </el-descriptions-item>
- <el-descriptions-item label="瀹氭椂浠诲姟">
- <el-tag :type="detailData.isActive === 1 ? 'success' : 'info'">
- {{ detailData.isActive === 1 ? '寮�鍚�' : '鍏抽棴' }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="澶囨敞" :span="2">
- {{ detailData.remarks || '--' }}
- </el-descriptions-item>
- </el-descriptions>
+ <FormDialog
+ v-model="dialogVisitable"
+ title="淇濆吇浠诲姟璇︽儏"
+ width="860px"
+ operation-type="detail"
+ @close="cancel"
+ >
+ <el-descriptions border :column="2" label-width="100px">
+ <el-descriptions-item label="璁惧鍚嶇О">
+ {{ detailData.taskName || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瑙勬牸鍨嬪彿">
+ {{ detailData.deviceModel || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="褰曞叆浜�">
+ {{ detailData.registrant || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐧昏鏃堕棿">
+ {{ detailData.registrationDate || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="淇濆吇浜�">
+ {{ detailData.maintenancePerson || "--" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="浠诲姟棰戠巼">
+ {{ formatFrequencyType(detailData.frequencyType) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鎵ц鏃堕棿">
+ {{ formatFrequencyDetail(detailData.frequencyDetail) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹氭椂浠诲姟">
+ <el-tag :type="detailData.isActive === 1 ? 'success' : 'info'" size="small">
+ {{ detailData.isActive === 1 ? "寮�鍚�" : "鍏抽棴" }}
+ </el-tag>
+ </el-descriptions-item>
+ <el-descriptions-item label="澶囨敞" :span="2">
+ {{ detailData.remarks || "--" }}
+ </el-descriptions-item>
+ </el-descriptions>
- <div v-if="fileList && fileList.length > 0" class="image-section">
- <div class="image-title">璁惧鍥剧墖锛�</div>
- <AttachmentUploadImage
- v-model:fileList="fileList"
- :disabled="true"
- />
- </div>
- </FormDialog>
+ <div class="detail-section">
+ <div class="section-title">
+ <span>淇濆吇鍐呭</span>
+ <span class="section-count">鍏� {{ itemCount }} 椤�</span>
+ </div>
+ <div v-if="itemCount" class="item-list">
+ <div
+ v-for="(item, index) in detailData.maintenanceItems"
+ :key="item.id || index"
+ class="item-row"
+ >
+ <span class="item-index">{{ index + 1 }}</span>
+ <div class="item-body">
+ <div class="item-project">{{ item.itemProject || "鏈~鍐欎繚鍏婚」鐩�" }}</div>
+ <div class="item-content">{{ item.itemName }}</div>
+ </div>
+ </div>
+ </div>
+ <el-empty v-else :image-size="48" description="鏆傛棤淇濆吇鍐呭" />
+ </div>
+
+ <div v-if="fileList && fileList.length > 0" class="image-section">
+ <div class="image-title">璁惧鍥剧墖锛�</div>
+ <AttachmentUploadImage v-model:fileList="fileList" :disabled="true" />
+ </div>
+ </FormDialog>
</template>
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { ref } from "vue";
+import { computed, ref } from "vue";
import { getLedgerById } from "@/api/equipmentManagement/ledger";
-import AttachmentUploadImage from '@/components/AttachmentUpload/image/index.vue';
+import AttachmentUploadImage from "@/components/AttachmentUpload/image/index.vue";
const dialogVisitable = ref(false);
const detailData = ref({});
const fileList = ref([]);
+const itemCount = computed(() => detailData.value.maintenanceItems?.length || 0);
const formatFrequencyType = (type) => {
- const map = {
- DAILY: "姣忔棩",
- WEEKLY: "姣忓懆",
- MONTHLY: "姣忔湀",
- QUARTERLY: "瀛e害",
- };
- return map[type] || "--";
+ const map = {
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害",
+ };
+ return map[type] || "--";
};
const formatFrequencyDetail = (detail) => {
- if (!detail) return "--";
- const replacements = {
- MON: "鍛ㄤ竴",
- TUE: "鍛ㄤ簩",
- WED: "鍛ㄤ笁",
- THU: "鍛ㄥ洓",
- FRI: "鍛ㄤ簲",
- SAT: "鍛ㄥ叚",
- SUN: "鍛ㄦ棩",
- };
- return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]);
+ if (!detail) return "--";
+ const replacements = {
+ MON: "鍛ㄤ竴",
+ TUE: "鍛ㄤ簩",
+ WED: "鍛ㄤ笁",
+ THU: "鍛ㄥ洓",
+ FRI: "鍛ㄤ簲",
+ SAT: "鍛ㄥ叚",
+ SUN: "鍛ㄦ棩",
+ };
+ return detail.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
};
const openDialog = (row) => {
- dialogVisitable.value = true;
- detailData.value = { ...row };
- fileList.value = [];
+ dialogVisitable.value = true;
+ detailData.value = { ...row };
+ fileList.value = [];
- if (row.taskId) {
- getLedgerById(row.taskId).then(res => {
- if (res.code === 200 && res.data) {
- fileList.value = res.data.storageBlobVOs || [];
- }
- });
- }
+ if (row.taskId) {
+ getLedgerById(row.taskId).then((res) => {
+ if (res.code === 200 && res.data) {
+ fileList.value = res.data.storageBlobVOs || [];
+ }
+ });
+ }
};
const cancel = () => {
- dialogVisitable.value = false;
+ dialogVisitable.value = false;
};
defineExpose({ openDialog });
</script>
<style scoped>
+.detail-section {
+ margin-top: 16px;
+}
+.section-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ font-weight: 600;
+ color: #303133;
+}
+.section-count {
+ font-size: 12px;
+ font-weight: normal;
+ color: #909399;
+}
+.item-list {
+ border: 1px solid #ebeef5;
+ border-radius: 4px;
+ overflow: hidden;
+}
+.item-row {
+ display: flex;
+ gap: 12px;
+ padding: 12px 14px;
+ border-bottom: 1px solid #ebeef5;
+}
+.item-row:last-child {
+ border-bottom: none;
+}
+.item-index {
+ flex-shrink: 0;
+ width: 24px;
+ height: 24px;
+ line-height: 24px;
+ text-align: center;
+ border-radius: 50%;
+ background: #ecf5ff;
+ color: #409eff;
+ font-size: 12px;
+}
+.item-body {
+ flex: 1;
+ min-width: 0;
+}
+.item-project {
+ margin-bottom: 4px;
+ font-weight: 600;
+ color: #303133;
+}
+.item-content {
+ line-height: 1.6;
+ color: #606266;
+ white-space: pre-wrap;
+ word-break: break-all;
+}
.image-section {
- margin-top: 20px;
+ margin-top: 20px;
}
.image-title {
- font-weight: bold;
- margin-bottom: 10px;
- color: #606266;
+ font-weight: bold;
+ margin-bottom: 10px;
+ color: #606266;
}
</style>
diff --git a/src/views/equipmentManagement/upkeep/Form/formDia.vue b/src/views/equipmentManagement/upkeep/Form/formDia.vue
index 60dda54..a7a8211 100644
--- a/src/views/equipmentManagement/upkeep/Form/formDia.vue
+++ b/src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -1,349 +1,640 @@
<template>
- <FormDialog
- v-model="dialogVisitable"
- :title="operationType === 'add' ? '鏂板淇濆吇浠诲姟' : '缂栬緫淇濆吇浠诲姟'"
- width="800px"
- :operation-type="operationType"
- @confirm="submitForm"
- @cancel="cancel"
- @close="cancel"
- >
- <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
- <el-row>
- <el-col :span="12">
- <el-form-item label="璁惧鍚嶇О" prop="taskId">
- <el-select v-model="form.taskId" @change="setDeviceModel" filterable>
- <el-option
- v-for="(item, index) in deviceOptions"
- :key="index"
- :label="item.deviceName"
- :value="item.id"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="瑙勬牸鍨嬪彿">
- <el-input
- v-model="form.deviceModel"
- placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
- disabled
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="褰曞叆浜�" prop="inspector">
- <el-select
- v-model="form.inspector"
- filterable
- default-first-option
- :reserve-keyword="false"
- placeholder="璇烽�夋嫨"
- clearable
- >
- <el-option
- v-for="item in userList"
- :label="item.nickName"
- :value="item.userId"
- :key="item.userId"
- />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鐧昏鏃堕棿" prop="registrationDate">
- <el-date-picker
- v-model="form.registrationDate"
- type="date"
- placeholder="閫夋嫨鐧昏鏃ユ湡"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD"
- style="width: 100%"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="淇濆吇椤圭洰" prop="machineryCategory">
- <el-input
- v-model.trim="form.machineryCategory"
- type="textarea"
- placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
- clearable
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="淇濆吇浜�" prop="maintenancePerson">
- <el-input
- v-model.trim="form.maintenancePerson"
- placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
- maxlength="100"
- clearable
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
- <el-select v-model="form.frequencyType" placeholder="璇烽�夋嫨" clearable>
- <el-option label="姣忔棩" value="DAILY"/>
- <el-option label="姣忓懆" value="WEEKLY"/>
- <el-option label="姣忔湀" value="MONTHLY"/>
- <el-option label="瀛e害" value="QUARTERLY"/>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-time-picker v-model="form.frequencyDetail" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
- value-format="HH:mm" />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-select v-model="form.week" placeholder="璇烽�夋嫨" clearable style="width: 50%">
- <el-option label="鍛ㄤ竴" value="MON"/>
- <el-option label="鍛ㄤ簩" value="TUE"/>
- <el-option label="鍛ㄤ笁" value="WED"/>
- <el-option label="鍛ㄥ洓" value="THU"/>
- <el-option label="鍛ㄤ簲" value="FRI"/>
- <el-option label="鍛ㄥ叚" value="SAT"/>
- <el-option label="鍛ㄦ棩" value="SUN"/>
- </el-select>
- <el-time-picker v-model="form.time" placeholder="閫夋嫨鏃堕棿" format="HH:mm"
- value-format="HH:mm" style="width: 50%"/>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-date-picker
- v-model="form.frequencyDetail"
- type="datetime"
- clearable
- placeholder="閫夋嫨寮�濮嬫棩鏈�"
- format="DD,HH:mm"
- value-format="DD,HH:mm"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
- <el-form-item label="鏃ユ湡" prop="frequencyDetail">
- <el-date-picker
- v-model="form.frequencyDetail"
- type="datetime"
- clearable
- placeholder="閫夋嫨寮�濮嬫棩鏈�"
- format="MM,DD,HH:mm"
- value-format="MM,DD,HH:mm"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24">
- <el-form-item label="瀹氭椂浠诲姟">
- <el-switch
- v-model="form.isActive"
- :active-value="1"
- :inactive-value="0"
- active-text="寮�鍚�"
- inactive-text="鍏抽棴"
- inline-prompt
- />
- <span style="margin-left: 12px; color: #909399; font-size: 12px;">
- {{ form.isActive === 1 ? '浠诲姟灏嗘寜璁″垝鎵ц' : '浠诲姟鏆傚仠鎵ц' }}
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="澶囨敞" prop="remarks">
- <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- </FormDialog>
+ <FormDialog
+ v-model="dialogVisitable"
+ :title="operationType === 'add' ? '鏂板淇濆吇浠诲姟' : '缂栬緫淇濆吇浠诲姟'"
+ width="800px"
+ :operation-type="operationType"
+ @confirm="submitForm"
+ @cancel="cancel"
+ @close="cancel"
+ >
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="璁惧鍚嶇О" prop="taskId">
+ <el-select v-model="form.taskId" @change="setDeviceModel" filterable>
+ <el-option
+ v-for="(item, index) in deviceOptions"
+ :key="index"
+ :label="item.deviceName"
+ :value="item.id"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="瑙勬牸鍨嬪彿">
+ <el-input v-model="form.deviceModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" disabled />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="褰曞叆浜�" prop="inspector">
+ <el-select
+ v-model="form.inspector"
+ filterable
+ default-first-option
+ :reserve-keyword="false"
+ placeholder="璇烽�夋嫨"
+ clearable
+ >
+ <el-option
+ v-for="item in userList"
+ :label="item.nickName"
+ :value="item.userId"
+ :key="item.userId"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐧昏鏃堕棿" prop="registrationDate">
+ <el-date-picker
+ v-model="form.registrationDate"
+ type="date"
+ placeholder="閫夋嫨鐧昏鏃ユ湡"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD"
+ style="width: 100%"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="淇濆吇浜�" prop="maintenancePerson">
+ <el-input
+ v-model.trim="form.maintenancePerson"
+ placeholder="璇疯緭鍏ヤ繚鍏讳汉濮撳悕"
+ maxlength="100"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="浠诲姟棰戠巼" prop="frequencyType">
+ <el-select
+ v-model="form.frequencyType"
+ placeholder="璇烽�夋嫨锛堟棩銆佸懆銆佹湀銆佸搴︼級"
+ clearable
+ @change="onFrequencyChange"
+ >
+ <el-option label="姣忔棩" value="DAILY" />
+ <el-option label="姣忓懆" value="WEEKLY" />
+ <el-option label="姣忔湀" value="MONTHLY" />
+ <el-option label="瀛e害" value="QUARTERLY" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
+ <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+ <el-time-picker
+ v-model="form.frequencyDetail"
+ placeholder="閫夋嫨鏃堕棿"
+ format="HH:mm"
+ value-format="HH:mm"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
+ <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+ <el-select v-model="form.week" placeholder="璇烽�夋嫨" clearable style="width: 50%">
+ <el-option label="鍛ㄤ竴" value="MON" />
+ <el-option label="鍛ㄤ簩" value="TUE" />
+ <el-option label="鍛ㄤ笁" value="WED" />
+ <el-option label="鍛ㄥ洓" value="THU" />
+ <el-option label="鍛ㄤ簲" value="FRI" />
+ <el-option label="鍛ㄥ叚" value="SAT" />
+ <el-option label="鍛ㄦ棩" value="SUN" />
+ </el-select>
+ <el-time-picker
+ v-model="form.time"
+ placeholder="閫夋嫨鏃堕棿"
+ format="HH:mm"
+ value-format="HH:mm"
+ style="width: 50%"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
+ <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+ <el-date-picker
+ v-model="form.frequencyDetail"
+ type="datetime"
+ clearable
+ placeholder="閫夋嫨寮�濮嬫棩鏈�"
+ format="DD,HH:mm"
+ value-format="DD,HH:mm"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
+ <el-form-item label="鏃ユ湡" prop="frequencyDetail">
+ <el-date-picker
+ v-model="form.frequencyDetail"
+ type="datetime"
+ clearable
+ placeholder="閫夋嫨寮�濮嬫棩鏈�"
+ format="MM,DD,HH:mm"
+ value-format="MM,DD,HH:mm"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="淇濆吇椤圭洰" prop="maintenanceItemIds">
+ <div class="maintenance-selection">
+ <div class="selection-toolbar">
+ <el-button
+ type="primary"
+ plain
+ :disabled="!form.taskId || !form.frequencyType"
+ @click="itemSelectorVisible = true"
+ >閫夋嫨淇濆吇椤圭洰</el-button
+ >
+ <span v-if="!form.taskId || !form.frequencyType" class="selection-hint"
+ >璇峰厛閫夋嫨璁惧鍜屼换鍔¢鐜囷紝璁惧缁戝畾鐨勪繚鍏婚」鐩皢鑷姩甯﹀嚭</span
+ >
+ <span v-else class="selection-hint"
+ >璁惧缁戝畾椤圭洰宸茶嚜鍔ㄥ甫鍑猴紝鍙澶栭�夋嫨閫氱敤椤圭洰锛屾垨娣诲姞鏈换鍔′笓鐢ㄩ」鐩�</span
+ >
+ </div>
+ <div class="custom-input">
+ <el-input
+ v-model="customItemProject"
+ maxlength="200"
+ clearable
+ placeholder="杈撳叆鏈换鍔′笓鐢ㄧ殑淇濆吇椤圭洰"
+ />
+ <el-input
+ v-model="customItemName"
+ maxlength="2000"
+ clearable
+ placeholder="杈撳叆椤圭洰瀵瑰簲鐨勪繚鍏诲唴瀹�"
+ @keyup.enter="addCustomItem"
+ />
+ <el-button
+ :disabled="!customItemProject.trim() || !customItemName.trim()"
+ @click="addCustomItem"
+ >娣诲姞</el-button
+ >
+ </div>
+ <div class="selected-panel">
+ <div class="selected-header">
+ <span class="selected-title">宸查�� {{ selectedList.length }} 椤�</span>
+ <span v-if="sourceStats.length" class="selected-stats">
+ <span v-for="stat in sourceStats" :key="stat.source" class="selected-stat"
+ >{{ stat.label }} {{ stat.count }}</span
+ >
+ </span>
+ </div>
+ <ol v-if="selectedList.length" class="selected-list">
+ <li v-for="(item, index) in selectedList" :key="item.key" class="selected-row">
+ <span class="row-index">{{ index + 1 }}</span>
+ <el-tag size="small" effect="light" :type="sourceMeta[item.source].type">{{
+ sourceMeta[item.source].label
+ }}</el-tag>
+ <span class="row-text" :title="item.itemProject">{{ item.itemProject }}</span>
+ <el-button link type="danger" @click="removeSelectedItem(item)">绉婚櫎</el-button>
+ </li>
+ </ol>
+ <el-empty v-else :image-size="56" description="灏氭湭閫夋嫨淇濆吇椤圭洰" />
+ </div>
+ </div>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="瀹氭椂浠诲姟">
+ <el-switch
+ v-model="form.isActive"
+ :active-value="1"
+ :inactive-value="0"
+ active-text="寮�鍚�"
+ inactive-text="鍏抽棴"
+ inline-prompt
+ />
+ <span style="margin-left: 12px; color: #909399; font-size: 12px">
+ {{ form.isActive === 1 ? "浠诲姟灏嗘寜璁″垝鎵ц" : "浠诲姟鏆傚仠鎵ц" }}
+ </span>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="澶囨敞" prop="remarks">
+ <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ </FormDialog>
+ <MaintenanceItemSelector
+ v-model:visible="itemSelectorVisible"
+ :selected-items="selectedItems"
+ :device-ledger-id="form.taskId"
+ :frequency-type="form.frequencyType"
+ @confirm="applyMaintenanceItems"
+ />
</template>
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
-import { reactive, ref, getCurrentInstance, toRefs } from "vue";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
+import { computed, reactive, ref, getCurrentInstance, toRefs } from "vue";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
-import { deviceMaintenanceTaskAdd, deviceMaintenanceTaskEdit } from "@/api/equipmentManagement/upkeep";
+import {
+ deviceMaintenanceTaskAdd,
+ deviceMaintenanceTaskEdit,
+ getMaintenanceItemList,
+} from "@/api/equipmentManagement/upkeep";
import { getCurrentDate } from "@/utils/index.js";
import useUserStore from "@/store/modules/user.js";
+import MaintenanceItemSelector from "./MaintenanceItemSelector.vue";
-const { proxy } = getCurrentInstance()
-const emit = defineEmits()
+const { proxy } = getCurrentInstance();
+const emit = defineEmits();
const dialogVisitable = ref(false);
-const operationType = ref('add');
+const operationType = ref("add");
const deviceOptions = ref([]);
+const itemSelectorVisible = ref(false);
const userStore = useUserStore();
const data = reactive({
- form: {
- taskId: undefined,
- taskName: undefined,
- // 褰曞叆浜猴細鍗曢�変竴涓敤鎴� id
- inspector: undefined,
- machineryCategory: "",
- remarks: '',
- frequencyType: '',
- frequencyDetail: '',
- week: '',
- time: '',
- deviceModel: undefined, // 瑙勬牸鍨嬪彿
- registrationDate: '',
- maintenancePerson: '', // 淇濆吇浜�
- isActive: 0 // 瀹氭椂浠诲姟寮�鍏筹細0=鍏抽棴锛�1=寮�鍚�
- },
- rules: {
- taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
- inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" },],
- registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
- machineryCategory: [{ required: true, message: "璇疯緭鍏ヤ繚鍏婚」鐩�", trigger: "blur" }]
- }
-})
-const { form, rules } = toRefs(data)
-const userList = ref([])
+ form: {
+ taskId: undefined,
+ taskName: undefined,
+ // 褰曞叆浜猴細鍗曢�変竴涓敤鎴� id
+ inspector: undefined,
+ maintenanceItemIds: [],
+ remarks: "",
+ frequencyType: "",
+ frequencyDetail: "",
+ week: "",
+ time: "",
+ deviceModel: undefined, // 瑙勬牸鍨嬪彿
+ registrationDate: "",
+ maintenancePerson: "", // 淇濆吇浜�
+ isActive: 0, // 瀹氭椂浠诲姟寮�鍏筹細0=鍏抽棴锛�1=寮�鍚�
+ },
+ rules: {
+ taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
+ inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" }],
+ registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
+ maintenanceItemIds: [
+ { type: "array", required: true, min: 1, message: "璇峰嬀閫変繚鍏婚」鐩�", trigger: "change" },
+ ],
+ frequencyType: [{ required: true, message: "璇烽�夋嫨浠诲姟棰戠巼", trigger: "change" }],
+ frequencyDetail: [
+ {
+ validator: (_, value, callback) => {
+ const valid =
+ form.value.frequencyType === "WEEKLY"
+ ? Boolean(form.value.week && form.value.time)
+ : Boolean(value);
+ callback(valid ? undefined : new Error("璇烽�夋嫨鎵ц鏃ユ湡鍜屾椂闂�"));
+ },
+ trigger: "change",
+ },
+ ],
+ },
+});
+const { form, rules } = toRefs(data);
+const userList = ref([]);
+// 浠庝繚鍏诲唴瀹规竻鍗曚腑閫変腑鐨勯」锛堣澶囩粦瀹氭垨閫氱敤锛�
+const selectedItems = ref([]);
+// 浠呭睘浜庢湰浠诲姟鐨勮嚜瀹氫箟鍐呭锛屼笉鍐欏叆淇濆吇鍐呭娓呭崟
+const customItems = ref([]);
+const customItemProject = ref("");
+const customItemName = ref("");
+const sourceMeta = {
+ device: { label: "鏈澶�", type: "primary" },
+ common: { label: "閫氱敤", type: "info" },
+ custom: { label: "鑷畾涔�", type: "warning" },
+ other: { label: "鍏跺畠璁惧", type: "danger" },
+ saved: { label: "宸蹭繚瀛�", type: "success" },
+};
+const getSource = (item) => {
+ if (item.deviceLedgerId === undefined) return "saved";
+ if (item.deviceLedgerId === null) return "common";
+ return String(item.deviceLedgerId) === String(form.value.taskId) ? "device" : "other";
+};
+const selectedList = computed(() => [
+ ...selectedItems.value.map((item) => ({
+ key: `item-${item.id}`,
+ id: item.id,
+ itemProject: item.itemProject,
+ source: getSource(item),
+ })),
+ ...customItems.value.map((item) => ({
+ key: item.key,
+ id: null,
+ itemProject: item.itemProject,
+ itemName: item.itemName,
+ source: "custom",
+ })),
+]);
+const sourceStats = computed(() =>
+ Object.keys(sourceMeta)
+ .map((source) => ({
+ source,
+ label: sourceMeta[source].label,
+ count: selectedList.value.filter((item) => item.source === source).length,
+ }))
+ .filter((stat) => stat.count > 0)
+);
+const syncItemIds = () => {
+ form.value.maintenanceItemIds = [
+ ...selectedItems.value.map((item) => item.id),
+ ...customItems.value.map((item) => item.key),
+ ];
+ proxy.$refs.formRef?.clearValidate("maintenanceItemIds");
+};
+const applyMaintenanceItems = (items) => {
+ selectedItems.value = items;
+ syncItemIds();
+};
+const addCustomItem = () => {
+ const project = customItemProject.value.trim();
+ const name = customItemName.value.trim();
+ if (!project || !name) return;
+ if (selectedList.value.some((item) => item.itemProject === project)) {
+ proxy.$modal.msgWarning("宸插瓨鍦ㄧ浉鍚岀殑淇濆吇椤圭洰");
+ return;
+ }
+ customItems.value = [
+ ...customItems.value,
+ { key: `custom-${Date.now()}`, itemProject: project, itemName: name },
+ ];
+ customItemProject.value = "";
+ customItemName.value = "";
+ syncItemIds();
+};
+const removeSelectedItem = (item) => {
+ if (item.source === "custom")
+ customItems.value = customItems.value.filter((custom) => custom.key !== item.key);
+ else
+ selectedItems.value = selectedItems.value.filter(
+ (selected) => String(selected.id) !== String(item.id)
+ );
+ syncItemIds();
+};
const loadDeviceName = async () => {
- const { data } = await getDeviceLedger();
- deviceOptions.value = data;
+ const { data } = await getDeviceLedger();
+ deviceOptions.value = data;
};
// 閫夋嫨璁惧鏃讹紝鍥炲~璁惧鍚嶇О(taskName)鍜岃鏍煎瀷鍙�(deviceModel)
-const setDeviceModel = (id) => {
- const option = deviceOptions.value.find((item) => item.id === id);
- if (option) {
- form.value.taskId = option.id;
- form.value.taskName = option.deviceName;
- form.value.deviceModel = option.deviceModel;
- }
-}
+const setDeviceModel = (id, preserveItems = false) => {
+ const option = deviceOptions.value.find((item) => item.id === id);
+ if (option) {
+ form.value.taskId = option.id;
+ form.value.taskName = option.deviceName;
+ form.value.deviceModel = option.deviceModel;
+ if (!preserveItems) autoFillBoundItems(id);
+ }
+};
+const clearSelectedItems = () => {
+ selectedItems.value = [];
+ syncItemIds();
+};
+const onFrequencyChange = () => autoFillBoundItems();
+// 鎸夎澶囧拰棰戠巼鑷姩甯﹀嚭璇ヨ澶囩粦瀹氱殑淇濆吇鍐呭锛涢�氱敤鍐呭锛堟棤璁惧锛夐渶鐢ㄦ埛鎵嬪姩棰濆閫夋嫨
+const autoFillBoundItems = async (deviceId) => {
+ const id = deviceId ?? form.value.taskId;
+ const frequency = form.value.frequencyType;
+ if (!id || !frequency) return clearSelectedItems();
+ const { code, data } = await getMaintenanceItemList({
+ deviceLedgerId: id,
+ frequencyType: frequency,
+ isActive: 1,
+ });
+ if (code !== 200 || id !== form.value.taskId || frequency !== form.value.frequencyType) return;
+ applyMaintenanceItems(data || []);
+};
// 鎵撳紑寮规
const openDialog = async (type, row) => {
- dialogVisitable.value = true
- operationType.value = type
-
- // 閲嶇疆琛ㄥ崟
- resetForm();
-
- // 鍔犺浇鐢ㄦ埛鍒楄〃
- userListNoPageByTenantId().then((res) => {
- userList.value = res.data;
- });
-
- // 鍔犺浇璁惧鍒楄〃
- await loadDeviceName();
-
- if (type === 'edit' && row) {
- form.value = { ...row }
- // 缂栬緫鏃剁敤鎺ュ彛杩斿洖鐨� registrantId 鍥炴樉褰曞叆浜�
- if (row.registrantId) {
- form.value.inspector = row.registrantId
- }
+ dialogVisitable.value = true;
+ operationType.value = type;
- // 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
- if (form.value.taskId) {
- setDeviceModel(form.value.taskId);
- }
- } else if (type === 'add') {
- // 鏂板鏃惰缃櫥璁版棩鏈熶负褰撳ぉ
- form.value.registrationDate = getCurrentDate();
- // 鏂板鏃惰缃綍鍏ヤ汉涓哄綋鍓嶇櫥褰曡处鎴�
- form.value.inspector = userStore.id;
- }
-}
+ // 閲嶇疆琛ㄥ崟
+ resetForm();
+
+ // 鍔犺浇鐢ㄦ埛鍒楄〃
+ userListNoPageByTenantId().then((res) => {
+ userList.value = res.data;
+ });
+ // 鍔犺浇璁惧鍒楄〃
+ await loadDeviceName();
+
+ if (type === "edit" && row) {
+ form.value = { ...row };
+ const savedItems = row.maintenanceItems || [];
+ selectedItems.value = savedItems
+ .filter((item) => item.maintenanceItemId != null)
+ .map((item) => ({
+ id: item.maintenanceItemId,
+ itemProject: item.itemProject,
+ itemName: item.itemName,
+ }));
+ customItems.value = savedItems
+ .filter((item) => item.maintenanceItemId == null)
+ .map((item, index) => ({
+ key: `custom-saved-${index}`,
+ itemProject: item.itemProject,
+ itemName: item.itemName,
+ }));
+ syncItemIds();
+ // 缂栬緫鏃剁敤鎺ュ彛杩斿洖鐨� registrantId 鍥炴樉褰曞叆浜�
+ if (row.registrantId) {
+ form.value.inspector = row.registrantId;
+ }
+
+ // 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
+ if (form.value.taskId) {
+ setDeviceModel(form.value.taskId, true);
+ }
+ } else if (type === "add") {
+ // 鏂板鏃惰缃櫥璁版棩鏈熶负褰撳ぉ
+ form.value.registrationDate = getCurrentDate();
+ // 鏂板鏃惰缃綍鍏ヤ汉涓哄綋鍓嶇櫥褰曡处鎴�
+ form.value.inspector = userStore.id;
+ }
+};
// 鍏抽棴瀵硅瘽妗�
const cancel = () => {
- resetForm()
- dialogVisitable.value = false
- emit('closeDia')
-}
+ itemSelectorVisible.value = false;
+ resetForm();
+ dialogVisitable.value = false;
+ emit("closeDia");
+};
// 閲嶇疆琛ㄥ崟鍑芥暟
const resetForm = () => {
- if (proxy.$refs.formRef) {
- proxy.$refs.formRef.resetFields()
- }
- // 閲嶇疆琛ㄥ崟鏁版嵁纭繚璁惧淇℃伅姝g‘閲嶇疆
- form.value = {
- taskId: undefined,
- taskName: undefined,
- inspector: undefined,
- machineryCategory: "",
- remarks: '',
- frequencyType: '',
- frequencyDetail: '',
- week: '',
- time: '',
- deviceModel: undefined,
- registrationDate: '',
- maintenancePerson: '',
- isActive: 0
- }
-}
+ itemSelectorVisible.value = false;
+ selectedItems.value = [];
+ customItems.value = [];
+ customItemProject.value = "";
+ customItemName.value = "";
+ if (proxy.$refs.formRef) {
+ proxy.$refs.formRef.resetFields();
+ }
+ // 閲嶇疆琛ㄥ崟鏁版嵁纭繚璁惧淇℃伅姝g‘閲嶇疆
+ form.value = {
+ taskId: undefined,
+ taskName: undefined,
+ inspector: undefined,
+ maintenanceItemIds: [],
+ remarks: "",
+ frequencyType: "",
+ frequencyDetail: "",
+ week: "",
+ time: "",
+ deviceModel: undefined,
+ registrationDate: "",
+ maintenancePerson: "",
+ isActive: 0,
+ };
+};
// 鎻愪氦琛ㄥ崟
const submitForm = () => {
- proxy.$refs["formRef"].validate(async valid => {
- if (valid) {
- try {
- const payload = { ...form.value }
- // 涓嶅啀鍚戝悗绔紶淇濆吇浜哄瓧娈碉紝浠呬娇鐢ㄦ帴鍙h姹傜殑 registrant / registrantId
- // 鏍规嵁閫夋嫨鐨�"褰曞叆浜�"璁剧疆 registrant / registrantId
- if (payload.inspector) {
- const selectedUser = userList.value.find(
- (u) => String(u.userId) === String(payload.inspector)
- )
- if (selectedUser) {
- payload.registrantId = selectedUser.userId
- payload.registrant = selectedUser.nickName
- }
- }
- delete payload.inspector
- delete payload.inspectorIds
- delete payload.active
+ proxy.$refs["formRef"].validate(async (valid) => {
+ if (valid) {
+ try {
+ const payload = { ...form.value };
+ payload.maintenanceItemIds = selectedItems.value.map((item) => item.id);
+ payload.customItems = customItems.value.map((item) => ({
+ itemProject: item.itemProject,
+ itemName: item.itemName,
+ }));
+ // 涓嶅啀鍚戝悗绔紶淇濆吇浜哄瓧娈碉紝浠呬娇鐢ㄦ帴鍙h姹傜殑 registrant / registrantId
+ // 鏍规嵁閫夋嫨鐨�"褰曞叆浜�"璁剧疆 registrant / registrantId
+ if (payload.inspector) {
+ const selectedUser = userList.value.find(
+ (u) => String(u.userId) === String(payload.inspector)
+ );
+ if (selectedUser) {
+ payload.registrantId = selectedUser.userId;
+ payload.registrant = selectedUser.nickName;
+ }
+ }
+ delete payload.inspector;
+ delete payload.inspectorIds;
+ delete payload.active;
- if (payload.frequencyType === 'WEEKLY') {
- let frequencyDetail = ''
- frequencyDetail = payload.week + ',' + payload.time
- payload.frequencyDetail = frequencyDetail
- }
+ if (payload.frequencyType === "WEEKLY") {
+ let frequencyDetail = "";
+ frequencyDetail = payload.week + "," + payload.time;
+ payload.frequencyDetail = frequencyDetail;
+ }
- // 褰曞叆鏃ユ湡锛氱洿鎺ヤ娇鐢ㄨ〃鍗曢噷鐨� registrationDate 瀛楁
- // 涓�浜涢粯璁ょ姸鎬佸瓧娈�
- if (payload.status === undefined || payload.status === null || payload.status === '') {
- payload.status = '0' // 榛樿鐘舵�侊紝鍙寜瀹為檯鏋氫妇璋冩暣
- }
- payload.deleted = 0
+ // 褰曞叆鏃ユ湡锛氱洿鎺ヤ娇鐢ㄨ〃鍗曢噷鐨� registrationDate 瀛楁
+ // 涓�浜涢粯璁ょ姸鎬佸瓧娈�
+ if (payload.status === undefined || payload.status === null || payload.status === "") {
+ payload.status = "0"; // 榛樿鐘舵�侊紝鍙寜瀹為檯鏋氫妇璋冩暣
+ }
+ payload.deleted = 0;
- if (operationType.value === 'edit') {
- await deviceMaintenanceTaskEdit(payload)
- } else {
- await deviceMaintenanceTaskAdd(payload)
- }
- cancel()
- proxy.$modal.msgSuccess('鎻愪氦鎴愬姛')
- } catch (error) {
- proxy.$modal.msgError('鎻愪氦澶辫触锛岃閲嶈瘯')
- }
- }
- })
-}
-defineExpose({ openDialog })
+ if (operationType.value === "edit") {
+ await deviceMaintenanceTaskEdit(payload);
+ } else {
+ await deviceMaintenanceTaskAdd(payload);
+ }
+ cancel();
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ } catch (error) {
+ proxy.$modal.msgError("鎻愪氦澶辫触锛岃閲嶈瘯");
+ }
+ }
+ });
+};
+defineExpose({ openDialog });
</script>
<style scoped>
-
+.maintenance-selection {
+ width: 100%;
+}
+.selection-toolbar {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+.selection-hint {
+ color: #909399;
+ font-size: 12px;
+}
+.custom-input {
+ display: flex;
+ gap: 8px;
+ margin-top: 10px;
+}
+.custom-input .el-input:first-child {
+ flex: 0 0 30%;
+}
+.custom-input .el-input:nth-child(2) {
+ flex: 1;
+ min-width: 0;
+}
+.selected-panel {
+ margin-top: 10px;
+ border: 1px solid #ebeef5;
+ border-radius: 4px;
+ background: #fafafa;
+}
+.selected-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 12px;
+ border-bottom: 1px solid #ebeef5;
+}
+.selected-title {
+ font-weight: 600;
+ color: #303133;
+}
+.selected-stats {
+ display: flex;
+ gap: 12px;
+ color: #909399;
+ font-size: 12px;
+}
+.selected-list {
+ max-height: 220px;
+ margin: 0;
+ padding: 4px 0;
+ overflow-y: auto;
+ list-style: none;
+}
+.selected-row {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 6px 12px;
+}
+.selected-row:hover {
+ background: #f0f7ff;
+}
+.row-index {
+ width: 24px;
+ flex-shrink: 0;
+ color: #909399;
+ text-align: right;
+}
+.row-text {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ color: #303133;
+}
</style>
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index cd1adff..4c55031 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -1,192 +1,173 @@
<template>
<div class="app-container">
- <el-tabs v-model="activeTab"
- @tab-change="handleTabChange">
+ <el-tabs v-model="activeTab" @tab-change="handleTabChange">
<!-- 淇濆吇浠诲姟tab -->
- <el-tab-pane label="淇濆吇浠诲姟"
- name="scheduled">
+ <el-tab-pane label="淇濆吇浠诲姟" name="scheduled">
<div class="search_form">
- <el-form :model="scheduledFilters"
- :inline="true">
+ <el-form :model="scheduledFilters" :inline="true">
<el-form-item label="浠诲姟鍚嶇О">
- <el-input v-model="scheduledFilters.taskName"
- style="width: 240px"
- placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
- clearable
- :prefix-icon="Search"
- @change="getScheduledTableData" />
+ <el-input
+ v-model="scheduledFilters.taskName"
+ style="width: 240px"
+ placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
+ clearable
+ :prefix-icon="Search"
+ @change="getScheduledTableData"
+ />
</el-form-item>
<el-form-item label="浠诲姟鐘舵��">
- <el-select v-model="scheduledFilters.status"
- placeholder="璇烽�夋嫨浠诲姟鐘舵��"
- clearable
- style="width: 200px">
- <el-option label="鍚敤"
- value="1" />
- <el-option label="鍋滅敤"
- value="0" />
+ <el-select
+ v-model="scheduledFilters.status"
+ placeholder="璇烽�夋嫨浠诲姟鐘舵��"
+ clearable
+ style="width: 200px"
+ >
+ <el-option label="鍚敤" value="1" />
+ <el-option label="鍋滅敤" value="0" />
</el-select>
</el-form-item>
<el-form-item>
- <el-button type="primary"
- @click="getScheduledTableData">鎼滅储</el-button>
+ <el-button type="primary" @click="getScheduledTableData">鎼滅储</el-button>
<el-button @click="resetScheduledFilters">閲嶇疆</el-button>
</el-form-item>
</el-form>
</div>
<div class="table_list">
<div class="actions">
- <el-text class="mx-1"
- size="large">淇濆吇浠诲姟</el-text>
+ <el-text class="mx-1" size="large">淇濆吇浠诲姟</el-text>
<div>
- <el-button type="primary"
- icon="Plus"
- @click="addScheduledTask">
- 鏂板浠诲姟
- </el-button>
- <el-button type="danger"
- icon="Delete"
- :disabled="scheduledMultipleList.length <= 0"
- @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))">
+ <el-button type="primary" icon="Plus" @click="addScheduledTask"> 鏂板浠诲姟 </el-button>
+ <el-button
+ type="danger"
+ icon="Delete"
+ :disabled="scheduledMultipleList.length <= 0"
+ @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))"
+ >
鎵归噺鍒犻櫎
</el-button>
</div>
</div>
- <PIMTable rowKey="id"
- isSelection
- :column="scheduledColumns"
- :tableData="scheduledDataList"
- :page="{
+ <PIMTable
+ rowKey="id"
+ isSelection
+ :column="scheduledColumns"
+ :tableData="scheduledDataList"
+ :page="{
current: scheduledPagination.currentPage,
size: scheduledPagination.pageSize,
total: scheduledPagination.total,
}"
- @selection-change="handleScheduledSelectionChange"
- @pagination="changeScheduledPage">
+ @selection-change="handleScheduledSelectionChange"
+ @pagination="changeScheduledPage"
+ >
<template #isActiveRef="{ row }">
- <el-tag v-if="row.isActive === 1"
- type="success">寮�鍚�</el-tag>
- <el-tag v-else
- type="info">鍏抽棴</el-tag>
+ <el-tag v-if="row.isActive === 1" type="success">寮�鍚�</el-tag>
+ <el-tag v-else type="info">鍏抽棴</el-tag>
</template>
<template #statusRef="{ row }">
- <el-tag v-if="row.status === 1"
- type="success">鍚敤</el-tag>
- <el-tag v-if="row.status === 0"
- type="danger">鍋滅敤</el-tag>
+ <el-tag v-if="row.status === 1" type="success">鍚敤</el-tag>
+ <el-tag v-if="row.status === 0" type="danger">鍋滅敤</el-tag>
</template>
<template #operation="{ row }">
- <el-button type="primary"
- link
- @click="handleDetail(row)">
- 璇︽儏
- </el-button>
- <el-button type="primary"
- link
- @click="editScheduledTask(row)">
- 缂栬緫
- </el-button>
- <el-button type="danger"
- link
- @click="delScheduledTaskByIds(row.id)">
+ <el-button type="primary" link @click="handleDetail(row)"> 璇︽儏 </el-button>
+ <el-button type="primary" link @click="editScheduledTask(row)"> 缂栬緫 </el-button>
+ <el-button type="danger" link @click="delScheduledTaskByIds(row.id)">
鍒犻櫎
</el-button>
</template>
</PIMTable>
</div>
</el-tab-pane>
+ <el-tab-pane label="淇濆吇鍐呭" name="items">
+ <ItemManager />
+ </el-tab-pane>
<!-- 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛� -->
- <el-tab-pane label="淇濆吇璁板綍"
- name="record">
+ <el-tab-pane label="淇濆吇璁板綍" name="record">
<div class="search_form">
- <el-form :model="filters"
- :inline="true">
+ <el-form :model="filters" :inline="true">
<el-form-item label="璁惧鍚嶇О">
- <el-input v-model="filters.deviceName"
- style="width: 240px"
- placeholder="璇疯緭鍏ヨ澶囧悕绉�"
- clearable
- :prefix-icon="Search"
- @change="getTableData" />
+ <el-input
+ v-model="filters.deviceName"
+ style="width: 240px"
+ placeholder="璇疯緭鍏ヨ澶囧悕绉�"
+ clearable
+ :prefix-icon="Search"
+ @change="getTableData"
+ />
</el-form-item>
<el-form-item label="璁″垝淇濆吇鏃ユ湡">
- <el-date-picker v-model="filters.maintenancePlanTime"
- type="date"
- placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡"
- size="default"
- @change="(date) => handleDateChange(date,2)" />
+ <el-date-picker
+ v-model="filters.maintenancePlanTime"
+ type="date"
+ placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡"
+ size="default"
+ @change="(date) => handleDateChange(date, 2)"
+ />
</el-form-item>
<el-form-item label="瀹為檯淇濆吇鏃ユ湡">
- <el-date-picker v-model="filters.maintenanceActuallyTime"
- type="date"
- placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
- size="default"
- @change="(date) => handleDateChange(date,1)" />
+ <el-date-picker
+ v-model="filters.maintenanceActuallyTime"
+ type="date"
+ placeholder="璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡"
+ size="default"
+ @change="(date) => handleDateChange(date, 1)"
+ />
</el-form-item>
<el-form-item label="瀹為檯淇濆吇浜�">
- <el-input v-model="filters.maintenanceActuallyName"
- style="width: 240px"
- placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
- clearable
- :prefix-icon="Search"
- @change="getTableData" />
+ <el-input
+ v-model="filters.maintenanceActuallyName"
+ style="width: 240px"
+ placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
+ clearable
+ :prefix-icon="Search"
+ @change="getTableData"
+ />
</el-form-item>
<el-form-item>
- <el-button type="primary"
- @click="getTableData">鎼滅储</el-button>
+ <el-button type="primary" @click="getTableData">鎼滅储</el-button>
<el-button @click="resetFilters">閲嶇疆</el-button>
</el-form-item>
</el-form>
</div>
<div class="table_list">
<div class="actions">
- <el-text class="mx-1"
- size="large">淇濆吇璁板綍</el-text>
+ <el-text class="mx-1" size="large">淇濆吇璁板綍</el-text>
<div>
- <el-button type="success"
- icon="Van"
- @click="addPlan">
- 鏂板璁″垝
- </el-button>
- <el-button @click="handleOut">
- 瀵煎嚭
- </el-button>
- <el-button type="danger"
- icon="Delete"
- :disabled="multipleList.length <= 0 || hasFinishedStatus"
- @click="delRepairByIds(multipleList.map((item) => item.id))">
+ <el-button type="success" icon="Van" @click="addPlan"> 鏂板璁″垝 </el-button>
+ <el-button @click="handleOut"> 瀵煎嚭 </el-button>
+ <el-button
+ type="danger"
+ icon="Delete"
+ :disabled="multipleList.length <= 0 || hasFinishedStatus"
+ @click="delRepairByIds(multipleList.map((item) => item.id))"
+ >
鎵归噺鍒犻櫎
</el-button>
</div>
</div>
- <PIMTable rowKey="id"
- isSelection
- :column="columns"
- :tableData="dataList"
- :page="{
- current: pagination.currentPage,
- size: pagination.pageSize,
- total: pagination.total,
- }"
- @selection-change="handleSelectionChange"
- @pagination="changePage">
+ <PIMTable
+ rowKey="id"
+ isSelection
+ :column="columns"
+ :tableData="dataList"
+ :page="{
+ current: pagination.currentPage,
+ size: pagination.pageSize,
+ total: pagination.total,
+ }"
+ @selection-change="handleSelectionChange"
+ @pagination="changePage"
+ >
<template #maintenanceResultRef="{ row }">
- <div>{{ row.maintenanceResult || '-' }}</div>
+ <div>{{ row.maintenanceResult || "-" }}</div>
</template>
<template #statusRef="{ row }">
- <el-tag v-if="row.status === 2"
- type="danger">澶辫触</el-tag>
- <el-tag v-if="row.status === 1"
- type="success">瀹岀粨</el-tag>
- <el-tag v-if="row.status === 0"
- type="warning">寰呬繚鍏�</el-tag>
+ <el-tag v-if="row.status === 2" type="danger">澶辫触</el-tag>
+ <el-tag v-if="row.status === 1" type="success">瀹岀粨</el-tag>
+ <el-tag v-if="row.status === 0" type="warning">寰呬繚鍏�</el-tag>
</template>
<template #operation="{ row }">
- <el-button type="primary"
- link
- @click="handleRecordDetail(row)">
- 璇︽儏
- </el-button>
+ <el-button type="primary" link @click="handleRecordDetail(row)"> 璇︽儏 </el-button>
<!-- 杩欎釜鍔熻兘璺熸柊澧炰繚鍏诲姛鑳戒竴妯′竴鏍凤紝鏈夊暐鎰忎箟锛� -->
<!-- <el-button
type="primary"
@@ -195,509 +176,475 @@
>
鏂板淇濆吇
</el-button> -->
- <el-button type="primary"
- link
- :disabled="row.status === 1"
- @click="editPlan(row.id)">
+ <el-button type="primary" link :disabled="row.status === 1" @click="editPlan(row.id)">
缂栬緫
</el-button>
- <el-button type="success"
- link
- :disabled="row.status === 1"
- @click="addMaintain(row)">
+ <el-button type="success" link :disabled="row.status === 1" @click="addMaintain(row)">
淇濆吇
</el-button>
- <el-button type="danger"
- link
- :disabled="row.status === 1"
- @click="delRepairByIds(row.id)">
+ <el-button
+ type="danger"
+ link
+ :disabled="row.status === 1"
+ @click="delRepairByIds(row.id)"
+ >
鍒犻櫎
</el-button>
- <el-button type="primary"
- link
- @click="openFileDialog(row)">
- 闄勪欢
- </el-button>
+ <el-button type="primary" link @click="openFileDialog(row)"> 闄勪欢 </el-button>
</template>
</PIMTable>
</div>
</el-tab-pane>
</el-tabs>
- <PlanModal ref="planModalRef"
- @ok="getTableData" />
- <MaintenanceModal ref="maintainModalRef"
- @ok="getTableData" />
- <FormDia ref="formDiaRef"
- @closeDia="getScheduledTableData" />
+ <PlanModal ref="planModalRef" @ok="getTableData" />
+ <MaintenanceModal ref="maintainModalRef" @ok="getTableData" />
+ <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" />
<DetailDia ref="detailDiaRef" />
<RecordDetailDia ref="recordDetailDiaRef" />
- <FileList v-if="fileDialogVisible"
- v-model:visible="fileDialogVisible"
- :record-type="'device_maintenance'"
- :record-id="currentMaintenanceTaskId" />
+ <FileList
+ v-if="fileDialogVisible"
+ v-model:visible="fileDialogVisible"
+ :record-type="'device_maintenance'"
+ :record-id="currentMaintenanceTaskId"
+ />
</div>
</template>
<script setup>
- import {
- ref,
- onMounted,
- reactive,
- getCurrentInstance,
- nextTick,
- computed,
- defineAsyncComponent,
- } from "vue";
- import { Search } from "@element-plus/icons-vue";
- import { ElMessage, ElMessageBox } from "element-plus";
- import PlanModal from "./Form/PlanModal.vue";
- import MaintenanceModal from "./Form/MaintenanceModal.vue";
- import FormDia from "./Form/formDia.vue";
- import DetailDia from "./Form/detailDia.vue";
- import RecordDetailDia from "./Form/RecordDetailDia.vue";
- import {
- getUpkeepPage,
- delUpkeep,
- deviceMaintenanceTaskList,
- deviceMaintenanceTaskDel,
- } from "@/api/equipmentManagement/upkeep";
- import dayjs from "dayjs";
+import {
+ ref,
+ onMounted,
+ reactive,
+ getCurrentInstance,
+ nextTick,
+ computed,
+ defineAsyncComponent,
+} from "vue";
+import { Search } from "@element-plus/icons-vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import PlanModal from "./Form/PlanModal.vue";
+import MaintenanceModal from "./Form/MaintenanceModal.vue";
+import FormDia from "./Form/formDia.vue";
+import DetailDia from "./Form/detailDia.vue";
+import RecordDetailDia from "./Form/RecordDetailDia.vue";
+import ItemManager from "./Form/ItemManager.vue";
+import {
+ getUpkeepPage,
+ delUpkeep,
+ deviceMaintenanceTaskList,
+ deviceMaintenanceTaskDel,
+} from "@/api/equipmentManagement/upkeep";
+import dayjs from "dayjs";
- const { proxy } = getCurrentInstance();
- const FileList = defineAsyncComponent(() =>
- import("@/components/Dialog/FileList.vue")
- );
+const { proxy } = getCurrentInstance();
+const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
- // Tab鐩稿叧
- const activeTab = ref("scheduled");
+// Tab鐩稿叧
+const activeTab = ref("scheduled");
- // 璁″垝寮圭獥鎺у埗鍣�
- const planModalRef = ref();
- // 淇濆吇寮圭獥鎺у埗鍣�
- const maintainModalRef = ref();
- // 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
- const formDiaRef = ref();
- // 瀹氭椂浠诲姟璇︽儏寮圭獥鎺у埗鍣�
- const detailDiaRef = ref();
- // 淇濆吇璁板綍璇︽儏寮圭獥鎺у埗鍣�
- const recordDetailDiaRef = ref();
- // 闄勪欢寮圭獥
- const fileListDialogRef = ref(null);
- const fileDialogVisible = ref(false);
- const currentMaintenanceTaskId = ref(null);
+// 璁″垝寮圭獥鎺у埗鍣�
+const planModalRef = ref();
+// 淇濆吇寮圭獥鎺у埗鍣�
+const maintainModalRef = ref();
+// 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
+const formDiaRef = ref();
+// 瀹氭椂浠诲姟璇︽儏寮圭獥鎺у埗鍣�
+const detailDiaRef = ref();
+// 淇濆吇璁板綍璇︽儏寮圭獥鎺у埗鍣�
+const recordDetailDiaRef = ref();
+// 闄勪欢寮圭獥
+const fileListDialogRef = ref(null);
+const fileDialogVisible = ref(false);
+const currentMaintenanceTaskId = ref(null);
- // 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
- const filters = reactive({
- deviceName: "",
- maintenancePlanTime: "",
- maintenanceActuallyTime: "",
- maintenanceActuallyName: "",
- });
+// 淇濆吇璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
+const filters = reactive({
+ deviceName: "",
+ maintenancePlanTime: "",
+ maintenanceActuallyTime: "",
+ maintenanceActuallyName: "",
+});
- const dataList = ref([]);
- const pagination = ref({
- currentPage: 1,
- pageSize: 10,
- total: 0,
- });
- const multipleList = ref([]);
+const dataList = ref([]);
+const pagination = ref({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+});
+const multipleList = ref([]);
- // 淇濆吇浠诲姟tab鐩稿叧鍙橀噺
- const scheduledFilters = reactive({
- taskName: "",
- status: "",
- });
+// 淇濆吇浠诲姟tab鐩稿叧鍙橀噺
+const scheduledFilters = reactive({
+ taskName: "",
+ status: "",
+});
- const scheduledDataList = ref([]);
- const scheduledPagination = reactive({
- currentPage: 1,
- pageSize: 10,
- total: 0,
- });
- const scheduledMultipleList = ref([]);
+const scheduledDataList = ref([]);
+const scheduledPagination = reactive({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+});
+const scheduledMultipleList = ref([]);
- // 淇濆吇浠诲姟琛ㄦ牸鍒楅厤缃�
- const scheduledColumns = ref([
- { prop: "taskName", label: "璁惧鍚嶇О" },
- {
- label: "瑙勬牸鍨嬪彿",
- prop: "deviceModel",
- },
- {
- label: "淇濆吇椤圭洰",
- prop: "machineryCategory",
- minWidth: 120,
- formatData: cell => cell || "--",
- },
- {
- prop: "frequencyType",
- label: "棰戞",
- minWidth: 80,
- // PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
- formatData: cell =>
- ({
- DAILY: "姣忔棩",
- WEEKLY: "姣忓懆",
- MONTHLY: "姣忔湀",
- QUARTERLY: "瀛e害",
- }[cell] || ""),
- },
- {
- prop: "frequencyDetail",
- label: "寮�濮嬫棩鏈熶笌鏃堕棿",
- minWidth: 130,
- // 鍚屾牱鏀圭敤 formatData锛孭IMTable 鍐呴儴浼氭妸鍗曞厓鏍煎�间紶杩涙潵
- formatData: cell => {
- if (typeof cell !== "string") return "";
- let val = cell;
- const replacements = {
- MON: "鍛ㄤ竴",
- TUE: "鍛ㄤ簩",
- WED: "鍛ㄤ笁",
- THU: "鍛ㄥ洓",
- FRI: "鍛ㄤ簲",
- SAT: "鍛ㄥ叚",
- SUN: "鍛ㄦ棩",
- };
- // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
- return val.replace(
- /MON|TUE|WED|THU|FRI|SAT|SUN/g,
- match => replacements[match]
- );
- },
- },
- {
- prop: "isActive",
- label: "瀹氭椂浠诲姟",
- dataType: "slot",
- slot: "isActiveRef",
- align: "center",
- minWidth: 100,
- },
- { prop: "maintenancePerson", label: "淇濆吇浜�", minWidth: 100 },
- { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
- {
- prop: "registrationDate",
- label: "鐧昏鏃ユ湡",
- minWidth: 100,
- formatData: cell =>
- cell ? dayjs(cell).format("YYYY-MM-DD") : "-",
- },
- {
- fixed: "right",
- label: "鎿嶄綔",
- dataType: "slot",
- slot: "operation",
- align: "center",
- width: "160px",
- },
- ]);
-
- // 淇濆吇璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
- const columns = ref([
- {
- label: "璁惧鍚嶇О",
- align: "center",
- prop: "deviceName",
- },
- {
- label: "瑙勬牸鍨嬪彿",
- align: "center",
- prop: "deviceModel",
- },
- {
- label: "璁″垝淇濆吇鏃ユ湡",
- align: "center",
- prop: "maintenancePlanTime",
- formatData: cell => {
- return cell == null ? "-" : dayjs(cell).format("YYYY-MM-DD");
- },
- },
- {
- label: "褰曞叆浜�",
- align: "center",
- prop: "createUserName",
- },
- {
- label: "淇濆吇椤圭洰",
- align: "center",
- prop: "machineryCategory",
- formatData: cell => cell || "--",
- },
- // {
- // label: "褰曞叆鏃ユ湡",
- // align: "center",
- // prop: "createTime",
- // formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
- // width: 200,
- // },
- {
- label: "瀹為檯淇濆吇浜�",
- align: "center",
- prop: "maintenanceActuallyName",
- },
- {
- label: "瀹為檯淇濆吇鏃ユ湡",
- align: "center",
- prop: "maintenanceActuallyTime",
- formatData: cell =>
- cell ? dayjs(cell).format("YYYY-MM-DD") : "-",
- },
- {
- label: "淇濆吇缁撴灉",
- align: "center",
- prop: "maintenanceResult",
- dataType: "slot",
- slot: "maintenanceResultRef",
- },
- {
- label: "鐘舵��",
- align: "center",
- prop: "status",
- dataType: "slot",
- slot: "statusRef",
- },
- {
- fixed: "right",
- label: "鎿嶄綔",
- dataType: "slot",
- slot: "operation",
- align: "center",
- width: "250px",
- },
- ]);
-
- // Tab鍒囨崲澶勭悊
- const handleTabChange = tabName => {
- if (tabName === "record") {
- getTableData();
- } else if (tabName === "scheduled") {
- getScheduledTableData();
- }
- };
-
- // 淇濆吇浠诲姟鐩稿叧鏂规硶
- const getScheduledTableData = async () => {
- try {
- const params = {
- current: scheduledPagination.currentPage,
- size: scheduledPagination.pageSize,
- taskName: scheduledFilters.taskName || undefined,
- status: scheduledFilters.status || undefined,
+// 淇濆吇浠诲姟琛ㄦ牸鍒楅厤缃�
+const scheduledColumns = ref([
+ { prop: "taskName", label: "璁惧鍚嶇О" },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ prop: "deviceModel",
+ },
+ {
+ prop: "frequencyType",
+ label: "棰戞",
+ minWidth: 80,
+ // PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
+ formatData: (cell) =>
+ ({
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害",
+ }[cell] || ""),
+ },
+ {
+ prop: "frequencyDetail",
+ label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+ minWidth: 130,
+ // 鍚屾牱鏀圭敤 formatData锛孭IMTable 鍐呴儴浼氭妸鍗曞厓鏍煎�间紶杩涙潵
+ formatData: (cell) => {
+ if (typeof cell !== "string") return "";
+ let val = cell;
+ const replacements = {
+ MON: "鍛ㄤ竴",
+ TUE: "鍛ㄤ簩",
+ WED: "鍛ㄤ笁",
+ THU: "鍛ㄥ洓",
+ FRI: "鍛ㄤ簲",
+ SAT: "鍛ㄥ叚",
+ SUN: "鍛ㄦ棩",
};
- const { code, data } = await deviceMaintenanceTaskList(params);
- if (code === 200) {
- scheduledDataList.value = data?.records || [];
- scheduledPagination.total = data?.total || 0;
- }
- } catch (error) {
- ElMessage.error("鑾峰彇瀹氭椂浠诲姟鍒楄〃澶辫触");
+ // 浣跨敤姝e垯涓�娆℃�ф浛鎹㈡墍鏈夊尮閰嶉」
+ return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
+ },
+ },
+ {
+ prop: "isActive",
+ label: "瀹氭椂浠诲姟",
+ dataType: "slot",
+ slot: "isActiveRef",
+ align: "center",
+ minWidth: 100,
+ },
+ { prop: "maintenancePerson", label: "淇濆吇浜�", minWidth: 100 },
+ { prop: "registrant", label: "鐧昏浜�", minWidth: 100 },
+ {
+ prop: "registrationDate",
+ label: "鐧昏鏃ユ湡",
+ minWidth: 100,
+ formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : "-"),
+ },
+ {
+ fixed: "right",
+ label: "鎿嶄綔",
+ dataType: "slot",
+ slot: "operation",
+ align: "center",
+ width: "160px",
+ },
+]);
+
+// 淇濆吇璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
+const columns = ref([
+ {
+ label: "璁惧鍚嶇О",
+ align: "center",
+ prop: "deviceName",
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ align: "center",
+ prop: "deviceModel",
+ },
+ {
+ label: "璁″垝淇濆吇鏃ユ湡",
+ align: "center",
+ prop: "maintenancePlanTime",
+ formatData: (cell) => {
+ return cell == null ? "-" : dayjs(cell).format("YYYY-MM-DD");
+ },
+ },
+ {
+ label: "褰曞叆浜�",
+ align: "center",
+ prop: "createUserName",
+ },
+ // {
+ // label: "褰曞叆鏃ユ湡",
+ // align: "center",
+ // prop: "createTime",
+ // formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
+ // width: 200,
+ // },
+ {
+ label: "瀹為檯淇濆吇浜�",
+ align: "center",
+ prop: "maintenanceActuallyName",
+ },
+ {
+ label: "瀹為檯淇濆吇鏃ユ湡",
+ align: "center",
+ prop: "maintenanceActuallyTime",
+ formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : "-"),
+ },
+ {
+ label: "淇濆吇缁撴灉",
+ align: "center",
+ prop: "maintenanceResult",
+ dataType: "slot",
+ slot: "maintenanceResultRef",
+ },
+ {
+ label: "鐘舵��",
+ align: "center",
+ prop: "status",
+ dataType: "slot",
+ slot: "statusRef",
+ },
+ {
+ fixed: "right",
+ label: "鎿嶄綔",
+ dataType: "slot",
+ slot: "operation",
+ align: "center",
+ width: "250px",
+ },
+]);
+
+// Tab鍒囨崲澶勭悊
+const handleTabChange = (tabName) => {
+ if (tabName === "record") {
+ getTableData();
+ } else if (tabName === "scheduled") {
+ getScheduledTableData();
+ }
+};
+
+// 淇濆吇浠诲姟鐩稿叧鏂规硶
+const getScheduledTableData = async () => {
+ try {
+ const params = {
+ current: scheduledPagination.currentPage,
+ size: scheduledPagination.pageSize,
+ taskName: scheduledFilters.taskName || undefined,
+ status: scheduledFilters.status || undefined,
+ };
+ const { code, data } = await deviceMaintenanceTaskList(params);
+ if (code === 200) {
+ scheduledDataList.value = data?.records || [];
+ scheduledPagination.total = data?.total || 0;
}
- };
+ } catch (error) {
+ ElMessage.error("鑾峰彇瀹氭椂浠诲姟鍒楄〃澶辫触");
+ }
+};
- const resetScheduledFilters = () => {
- scheduledFilters.taskName = "";
- scheduledFilters.status = "";
- getScheduledTableData();
- };
+const resetScheduledFilters = () => {
+ scheduledFilters.taskName = "";
+ scheduledFilters.status = "";
+ getScheduledTableData();
+};
- const handleScheduledSelectionChange = selection => {
- scheduledMultipleList.value = selection;
- };
+const handleScheduledSelectionChange = (selection) => {
+ scheduledMultipleList.value = selection;
+};
- const changeScheduledPage = page => {
- scheduledPagination.currentPage = page.page;
- scheduledPagination.pageSize = page.limit;
- getScheduledTableData();
- };
+const changeScheduledPage = (page) => {
+ scheduledPagination.currentPage = page.page;
+ scheduledPagination.pageSize = page.limit;
+ getScheduledTableData();
+};
- const addScheduledTask = () => {
+const addScheduledTask = () => {
+ nextTick(() => {
+ formDiaRef.value?.openDialog("add");
+ });
+};
+
+const editScheduledTask = (row) => {
+ if (row) {
nextTick(() => {
- formDiaRef.value?.openDialog("add");
+ formDiaRef.value?.openDialog("edit", row);
});
- };
+ }
+};
- const editScheduledTask = row => {
- if (row) {
- nextTick(() => {
- formDiaRef.value?.openDialog("edit", row);
- });
+const handleDetail = (row) => {
+ if (row) {
+ nextTick(() => {
+ detailDiaRef.value?.openDialog(row);
+ });
+ }
+};
+
+const delScheduledTaskByIds = async (ids) => {
+ try {
+ await ElMessageBox.confirm("纭畾鍒犻櫎閫変腑鐨勫畾鏃朵换鍔″悧锛�", "鎻愮ず", {
+ type: "warning",
+ });
+ const payload = Array.isArray(ids) ? ids : [ids];
+ await deviceMaintenanceTaskDel(payload);
+ ElMessage.success("鍒犻櫎瀹氭椂浠诲姟鎴愬姛");
+ getScheduledTableData();
+ } catch (error) {
+ // 鐢ㄦ埛鍙栨秷鍒犻櫎
+ }
+};
+
+const handleScheduledOut = () => {
+ ElMessage.info("瀵煎嚭瀹氭椂浠诲姟鍔熻兘寰呭疄鐜�");
+};
+
+// 淇濆吇璁板綍鐩稿叧鏂规硶锛堝師璁惧淇濆吇椤甸潰鏂规硶锛�
+const getTableData = async () => {
+ try {
+ const params = {
+ current: pagination.value.currentPage,
+ size: pagination.value.pageSize,
+ deviceName: filters.deviceName || undefined,
+ maintenancePlanTime: filters.maintenancePlanTime
+ ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD")
+ : undefined,
+ maintenanceActuallyTime: filters.maintenanceActuallyTime
+ ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD")
+ : undefined,
+ maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
+ };
+
+ const { code, data } = await getUpkeepPage(params);
+ if (code === 200) {
+ dataList.value = data.records;
+ pagination.value.total = data.total;
}
- };
+ } catch (error) {
+ console.log(error);
+ }
+};
- const handleDetail = row => {
- if (row) {
- nextTick(() => {
- detailDiaRef.value?.openDialog(row);
- });
- }
- };
+const resetFilters = () => {
+ filters.deviceName = "";
+ filters.maintenancePlanTime = "";
+ filters.maintenanceActuallyTime = "";
+ filters.maintenanceActuallyName = "";
+ getTableData();
+};
- const delScheduledTaskByIds = async ids => {
- try {
- await ElMessageBox.confirm("纭畾鍒犻櫎閫変腑鐨勫畾鏃朵换鍔″悧锛�", "鎻愮ず", {
- type: "warning",
- });
- const payload = Array.isArray(ids) ? ids : [ids];
- await deviceMaintenanceTaskDel(payload);
- ElMessage.success("鍒犻櫎瀹氭椂浠诲姟鎴愬姛");
- getScheduledTableData();
- } catch (error) {
- // 鐢ㄦ埛鍙栨秷鍒犻櫎
- }
- };
+const handleSelectionChange = (selection) => {
+ multipleList.value = selection;
+};
- const handleScheduledOut = () => {
- ElMessage.info("瀵煎嚭瀹氭椂浠诲姟鍔熻兘寰呭疄鐜�");
- };
+// 妫�鏌ラ�変腑鐨勮褰曚腑鏄惁鏈夊畬缁撶姸鎬佺殑
+const hasFinishedStatus = computed(() => {
+ return multipleList.value.some((item) => item.status === 1);
+});
- // 淇濆吇璁板綍鐩稿叧鏂规硶锛堝師璁惧淇濆吇椤甸潰鏂规硶锛�
- const getTableData = async () => {
- try {
- const params = {
- current: pagination.value.currentPage,
- size: pagination.value.pageSize,
- deviceName: filters.deviceName || undefined,
- maintenancePlanTime: filters.maintenancePlanTime
- ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD")
- : undefined,
- maintenanceActuallyTime: filters.maintenanceActuallyTime
- ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD")
- : undefined,
- maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
- };
+const changePage = (page) => {
+ pagination.value.currentPage = page.page;
+ pagination.value.pageSize = page.limit;
+ getTableData();
+};
- const { code, data } = await getUpkeepPage(params);
- if (code === 200) {
- dataList.value = data.records;
- pagination.value.total = data.total;
- }
- } catch (error) {
- console.log(error);
- }
- };
+const addMaintain = (row) => {
+ maintainModalRef.value.open(row.id, row);
+};
- const resetFilters = () => {
- filters.deviceName = "";
- filters.maintenancePlanTime = "";
- filters.maintenanceActuallyTime = "";
- filters.maintenanceActuallyName = "";
- getTableData();
- };
+const handleRecordDetail = (row) => {
+ if (row) {
+ nextTick(() => {
+ recordDetailDiaRef.value?.openDialog(row);
+ });
+ }
+};
- const handleSelectionChange = selection => {
- multipleList.value = selection;
- };
+const addPlan = () => {
+ planModalRef.value.openModal();
+};
- // 妫�鏌ラ�変腑鐨勮褰曚腑鏄惁鏈夊畬缁撶姸鎬佺殑
- const hasFinishedStatus = computed(() => {
- return multipleList.value.some(item => item.status === 1);
- });
+const editPlan = (id) => {
+ planModalRef.value.openEdit(id);
+};
- const changePage = page => {
- pagination.value.currentPage = page.page;
- pagination.value.pageSize = page.limit;
- getTableData();
- };
+const delRepairByIds = async (ids) => {
+ // 妫�鏌ユ槸鍚︽湁瀹岀粨鐘舵�佺殑璁板綍
+ const hasFinished = multipleList.value.some((item) => item.status === 1);
+ if (hasFinished) {
+ ElMessage.warning("涓嶈兘鍒犻櫎鐘舵�佷负瀹岀粨鐨勮褰�");
+ return;
+ }
- const addMaintain = row => {
- maintainModalRef.value.open(row.id, row);
- };
-
- const handleRecordDetail = row => {
- if (row) {
- nextTick(() => {
- recordDetailDiaRef.value?.openDialog(row);
- });
- }
- };
-
- const addPlan = () => {
- planModalRef.value.openModal();
- };
-
- const editPlan = id => {
- planModalRef.value.openEdit(id);
- };
-
- const delRepairByIds = async ids => {
- // 妫�鏌ユ槸鍚︽湁瀹岀粨鐘舵�佺殑璁板綍
- const hasFinished = multipleList.value.some(item => item.status === 1);
- if (hasFinished) {
- ElMessage.warning("涓嶈兘鍒犻櫎鐘舵�佷负瀹岀粨鐨勮褰�");
- return;
- }
-
- try {
- await ElMessageBox.confirm("纭鍒犻櫎淇濆吇鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- });
-
- const { code } = await delUpkeep(ids);
- if (code === 200) {
- ElMessage.success("鍒犻櫎鎴愬姛");
- getTableData();
- }
- } catch (error) {
- // 鐢ㄦ埛鍙栨秷鍒犻櫎
- }
- };
-
- const handleOut = () => {
- ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
- confirmButtonText: "纭",
+ try {
+ await ElMessageBox.confirm("纭鍒犻櫎淇濆吇鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
+ confirmButtonText: "纭畾",
cancelButtonText: "鍙栨秷",
type: "warning",
- })
- .then(() => {
- proxy.download("/device/maintenance/export", {}, "璁惧淇濆吇.xlsx");
- })
- .catch(() => {
- ElMessage.info("宸插彇娑�");
- });
- };
+ });
- const handleDateChange = (date, type) => {
- if (type === 1) {
- filters.maintenanceActuallyTime = date
- ? dayjs(date).format("YYYY-MM-DD")
- : "";
- } else {
- filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
- }
- getTableData();
- };
-
- // 鎵撳紑闄勪欢寮圭獥
- const openFileDialog = async row => {
- currentMaintenanceTaskId.value = row.id;
- fileDialogVisible.value = true;
- };
-
- onMounted(() => {
- // 鏍规嵁榛樿婵�娲荤殑 Tab 璋冪敤瀵瑰簲鐨勬煡璇㈡帴鍙�
- if (activeTab.value === "scheduled") {
- getScheduledTableData();
- } else {
+ const { code } = await delUpkeep(ids);
+ if (code === 200) {
+ ElMessage.success("鍒犻櫎鎴愬姛");
getTableData();
}
- });
+ } catch (error) {
+ // 鐢ㄦ埛鍙栨秷鍒犻櫎
+ }
+};
+
+const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ proxy.download("/device/maintenance/export", {}, "璁惧淇濆吇.xlsx");
+ })
+ .catch(() => {
+ ElMessage.info("宸插彇娑�");
+ });
+};
+
+const handleDateChange = (date, type) => {
+ if (type === 1) {
+ filters.maintenanceActuallyTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
+ } else {
+ filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
+ }
+ getTableData();
+};
+
+// 鎵撳紑闄勪欢寮圭獥
+const openFileDialog = async (row) => {
+ currentMaintenanceTaskId.value = row.id;
+ fileDialogVisible.value = true;
+};
+
+onMounted(() => {
+ // 鏍规嵁榛樿婵�娲荤殑 Tab 璋冪敤瀵瑰簲鐨勬煡璇㈡帴鍙�
+ if (activeTab.value === "scheduled") {
+ getScheduledTableData();
+ } else {
+ getTableData();
+ }
+});
</script>
<style lang="scss" scoped>
- .table_list {
- margin-top: unset;
- }
- .actions {
- display: flex;
- justify-content: space-between;
- margin-bottom: 10px;
- }
+.table_list {
+ margin-top: unset;
+}
+.actions {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
</style>
-
-
-
-
-
--
Gitblit v1.9.3