From b9e53d7500e3497f8659fc373e6c707071b6dfb7 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 27 二月 2026 13:57:56 +0800
Subject: [PATCH] 金鹰黄金 1.设备报修和保养添加审批流程 2.设备保养流程添加定任务管理
---
src/views/equipmentManagement/upkeep/Form/ApproveModal.vue | 137 ++
src/views/equipmentManagement/upkeep/index.vue | 870 ++++++++++++----
src/views/equipmentManagement/repair/Modal/MaintainModal.vue | 99 +
src/views/equipmentManagement/upkeep/Form/PlanModal.vue | 188 +++
src/views/equipmentManagement/repair/Modal/RepairModal.vue | 198 ++-
src/views/equipmentManagement/repair/Modal/ApproveModal.vue | 135 ++
src/views/equipmentManagement/repair/index.vue | 259 ++--
src/api/equipmentManagement/upkeep.js | 33
src/api/equipmentManagement/maintenanceTaskFile.js | 28
src/components/Dialog/ImportDialog.vue | 172 +++
/dev/null | 162 ---
src/views/equipmentManagement/upkeep/Form/formDia.vue | 325 ++++++
src/utils/index.js | 13
src/components/Dialog/FileListDialog.vue | 328 ++++++
src/components/Dialog/FormDialog.vue | 73 +
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue | 146 ++
16 files changed, 2,548 insertions(+), 618 deletions(-)
diff --git a/src/api/equipmentManagement/maintenanceTaskFile.js b/src/api/equipmentManagement/maintenanceTaskFile.js
new file mode 100644
index 0000000..8373ae3
--- /dev/null
+++ b/src/api/equipmentManagement/maintenanceTaskFile.js
@@ -0,0 +1,28 @@
+import request from "@/utils/request";
+
+// 鏌ヨ淇濆吇浠诲姟闄勪欢鍒楄〃
+export function listMaintenanceTaskFiles(query) {
+ return request({
+ url: "/maintenanceTaskFile/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+// 鏂板淇濆吇浠诲姟闄勪欢
+export function addMaintenanceTaskFile(data) {
+ return request({
+ url: "/maintenanceTaskFile/add",
+ method: "post",
+ data,
+ });
+}
+
+// 鍒犻櫎淇濆吇浠诲姟闄勪欢
+export function delMaintenanceTaskFile(id) {
+ return request({
+ url: "/maintenanceTaskFile/del",
+ method: "delete",
+ data: Array.isArray(id) ? id : [id],
+ });
+}
diff --git a/src/api/equipmentManagement/upkeep.js b/src/api/equipmentManagement/upkeep.js
index 82ce865..37f6e5f 100644
--- a/src/api/equipmentManagement/upkeep.js
+++ b/src/api/equipmentManagement/upkeep.js
@@ -70,6 +70,39 @@
method: "delete",
});
};
+// 娣诲姞璁惧淇濆吇瀹氭椂浠诲姟
+export const deviceMaintenanceTaskAdd = (params) => {
+ return request({
+ url: '/deviceMaintenanceTask/add',
+ method: "post",
+ data: params,
+ });
+};
+// 淇敼璁惧淇濆吇瀹氭椂浠诲姟
+export const deviceMaintenanceTaskEdit = (params) => {
+ return request({
+ url: '/deviceMaintenanceTask/update',
+ method: "post",
+ data: params,
+ });
+};
+// 璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃
+export const deviceMaintenanceTaskList = (params) => {
+ return request({
+ url: '/deviceMaintenanceTask/listPage',
+ method: "get",
+ params: params,
+ });
+};
+// 璁惧淇濆吇瀹氭椂浠诲姟鍒楄〃
+export const deviceMaintenanceTaskDel = (params) => {
+ return request({
+ url: '/deviceMaintenanceTask/delete',
+ method: "delete",
+ data: params,
+ });
+};
+
// 鏌ヨ璁惧鐨勬姤淇噾棰�-姣忔湀
export const monthlyAmount = (query) => {
return request({
diff --git a/src/components/Dialog/FileListDialog.vue b/src/components/Dialog/FileListDialog.vue
new file mode 100644
index 0000000..fc82411
--- /dev/null
+++ b/src/components/Dialog/FileListDialog.vue
@@ -0,0 +1,328 @@
+<template>
+ <el-dialog v-model="dialogVisible"
+ :title="title"
+ :width="width"
+ :before-close="handleClose">
+ <div class="file-list-toolbar"
+ v-if="showToolbar">
+ <template v-if="useBuiltInUpload">
+ <el-upload v-model:file-list="uploadFileList"
+ class="upload-demo"
+ :action="uploadAction"
+ :headers="uploadHeaders"
+ :show-file-list="false"
+ :on-success="handleDefaultUploadSuccess"
+ :on-error="handleDefaultUploadError">
+ <el-button v-if="showUploadButton"
+ type="primary"
+ size="small">
+ 涓婁紶闄勪欢
+ </el-button>
+ </el-upload>
+ </template>
+ <template v-else>
+ <el-button v-if="showUploadButton"
+ type="primary"
+ size="small"
+ @click="handleUpload">
+ 鏂板闄勪欢
+ </el-button>
+ </template>
+ </div>
+ <el-table :data="tableData"
+ border
+ :height="tableHeight">
+ <el-table-column :label="nameColumnLabel"
+ :prop="nameColumnProp"
+ :min-width="nameColumnMinWidth"
+ show-overflow-tooltip />
+ <el-table-column v-if="showActions"
+ fixed="right"
+ label="鎿嶄綔"
+ :width="actionColumnWidth"
+ align="center">
+ <template #default="scope">
+ <el-button v-if="showDownload"
+ link
+ type="primary"
+ size="small"
+ @click="handleDownload(scope.row)">
+ 涓嬭浇
+ </el-button>
+ <el-button v-if="showPreview"
+ link
+ type="primary"
+ size="small"
+ @click="handlePreview(scope.row)">
+ 棰勮
+ </el-button>
+ <el-button v-if="showDeleteButton"
+ link
+ type="danger"
+ size="small"
+ @click="handleDelete(scope.row, scope.$index)">
+ 鍒犻櫎
+ </el-button>
+ <slot name="actions"
+ :row="scope.row"></slot>
+ </template>
+ </el-table-column>
+ <slot name="columns"></slot>
+ </el-table>
+ <pagination v-if="isShowPagination"
+ style="margin-bottom: 20px;"
+ :total="page.total"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationSearch"
+ @change="handleChange" />
+ </el-dialog>
+ <filePreview v-if="showPreview"
+ ref="filePreviewRef" />
+</template>
+
+<script setup>
+ import { ref, computed, getCurrentInstance } from "vue";
+ import pagination from "@/components/Pagination/index.vue";
+ import { ElMessage } from "element-plus";
+ import filePreview from "@/components/filePreview/index.vue";
+ import { getToken } from "@/utils/auth";
+
+ const props = defineProps({
+ modelValue: {
+ type: Boolean,
+ default: false,
+ },
+ title: {
+ type: String,
+ default: "闄勪欢",
+ },
+ width: {
+ type: String,
+ default: "40%",
+ },
+ tableHeight: {
+ type: String,
+ default: "40vh",
+ },
+ nameColumnLabel: {
+ type: String,
+ default: "闄勪欢鍚嶇О",
+ },
+ nameColumnProp: {
+ type: String,
+ default: "name",
+ },
+ nameColumnMinWidth: {
+ type: [String, Number],
+ default: 400,
+ },
+ actionColumnWidth: {
+ type: [String, Number],
+ default: 160,
+ },
+ showActions: {
+ type: Boolean,
+ default: true,
+ },
+ showDownload: {
+ type: Boolean,
+ default: true,
+ },
+ showPreview: {
+ type: Boolean,
+ default: true,
+ },
+ showUploadButton: {
+ type: Boolean,
+ default: false,
+ },
+ showDeleteButton: {
+ type: Boolean,
+ default: false,
+ },
+ urlField: {
+ type: String,
+ default: "url",
+ },
+ downloadMethod: {
+ type: Function,
+ default: null,
+ },
+ previewMethod: {
+ type: Function,
+ default: null,
+ },
+ uploadMethod: {
+ type: Function,
+ default: null,
+ },
+ deleteMethod: {
+ type: Function,
+ default: null,
+ },
+ rulesRegulationsManagementId: {
+ type: [String, Number],
+ default: "",
+ },
+ uploadUrl: {
+ type: String,
+ default: `${import.meta.env.VITE_APP_BASE_API}/file/upload`,
+ },
+ isShowPagination: {
+ type: Boolean,
+ default: false,
+ },
+ page: {
+ type: Object,
+ default: () => ({
+ current: 1,
+ size: 10,
+ total: 0,
+ }),
+ },
+ });
+
+ const emit = defineEmits([
+ "update:modelValue",
+ "close",
+ "download",
+ "preview",
+ "upload",
+ "delete",
+ ]);
+
+ const { proxy } = getCurrentInstance();
+ const filePreviewRef = ref(null);
+ const uploadFileList = ref([]);
+
+ const dialogVisible = computed({
+ get: () => props.modelValue,
+ set: val => emit("update:modelValue", val),
+ });
+
+ const tableData = ref([]);
+ const showToolbar = computed(() => props.showUploadButton);
+ const useBuiltInUpload = computed(() => !props.uploadMethod);
+ const uploadAction = computed(() => props.uploadUrl);
+ const uploadHeaders = computed(() => ({
+ Authorization: `Bearer ${getToken()}`,
+ }));
+
+ const handleClose = () => {
+ emit("close");
+ dialogVisible.value = false;
+ };
+
+ const handleDownload = row => {
+ if (props.downloadMethod) {
+ props.downloadMethod(row);
+ } else {
+ // 榛樿涓嬭浇鏂规硶
+ proxy.$download.name(row[props.urlField]);
+ }
+ emit("download", row);
+ };
+
+ const handlePreview = row => {
+ if (props.previewMethod) {
+ props.previewMethod(row);
+ } else {
+ // 榛樿棰勮鏂规硶
+ if (filePreviewRef.value) {
+ filePreviewRef.value.open(row[props.urlField]);
+ }
+ }
+ emit("preview", row);
+ };
+ const paginationSearch = page => {
+ props.page.current = page.page;
+ props.page.size = page.limit;
+ emit("pagination", page.page, page.limit);
+ };
+
+ const open = list => {
+ dialogVisible.value = true;
+ tableData.value = list || [];
+ };
+
+ const handleUpload = async () => {
+ if (props.uploadMethod) {
+ // 濡傛灉鎻愪緵浜嗚嚜瀹氫箟涓婁紶鏂规硶锛岀敱鐖剁粍浠惰礋璐f洿鏂板垪琛紙閫氳繃 setList锛�
+ // 杩欓噷涓嶅啀鑷姩娣诲姞锛岄伩鍏嶄笌鐖剁粍浠剁殑 setList 閲嶅
+ await props.uploadMethod();
+ }
+ emit("upload");
+ };
+
+ const handleDelete = async (row, index) => {
+ if (props.deleteMethod) {
+ const result = await props.deleteMethod(row, index);
+ if (result === false) {
+ return;
+ }
+ // 濡傛灉鎻愪緵浜� deleteMethod锛岀敱鐖剁粍浠惰礋璐e埛鏂板垪琛紝涓嶅湪杩欓噷鍒犻櫎
+ } else {
+ // 濡傛灉娌℃湁鎻愪緵 deleteMethod锛屾墠鍦ㄧ粍浠跺唴閮ㄥ垹闄�
+ removeAttachment(index);
+ }
+ emit("delete", row);
+ };
+
+ const addAttachment = item => {
+ tableData.value = [...tableData.value, item];
+ };
+
+ const handleDefaultUploadSuccess = async (res, file) => {
+ if (res?.code !== 200) {
+ ElMessage.error(res?.msg || "鏂囦欢涓婁紶澶辫触");
+ return;
+ }
+ if (!props.rulesRegulationsManagementId) {
+ ElMessage.error("缂哄皯瑙勭珷鍒跺害ID锛屾棤娉曚繚瀛橀檮浠�");
+ return;
+ }
+ const fileName = res?.data?.originalName || file?.name;
+ const fileUrl = res?.data?.tempPath || res?.data?.url;
+ const payload = {
+ fileName,
+ fileUrl,
+ rulesRegulationsManagementId: props.rulesRegulationsManagementId,
+ raw: res?.data || {},
+ };
+ emit("upload", payload);
+ };
+
+ const handleDefaultUploadError = () => {
+ ElMessage.error("鏂囦欢涓婁紶澶辫触");
+ };
+
+ const removeAttachment = index => {
+ if (index > -1 && index < tableData.value.length) {
+ const newList = [...tableData.value];
+ newList.splice(index, 1);
+ tableData.value = newList;
+ }
+ };
+
+ const setList = list => {
+ tableData.value = list || [];
+ };
+
+ defineExpose({
+ open,
+ addAttachment,
+ removeAttachment,
+ setList,
+ handleUpload,
+ handleDelete,
+ });
+</script>
+
+<style scoped>
+ .file-list-toolbar {
+ margin-bottom: 8px;
+ text-align: right;
+ }
+</style>
+
diff --git a/src/components/Dialog/FormDialog.vue b/src/components/Dialog/FormDialog.vue
new file mode 100644
index 0000000..5e21b1d
--- /dev/null
+++ b/src/components/Dialog/FormDialog.vue
@@ -0,0 +1,73 @@
+<template>
+ <el-dialog
+ v-model="dialogVisible"
+ :title="computedTitle"
+ :width="width"
+ @close="handleClose"
+ >
+ <slot></slot>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="handleConfirm">纭</el-button>
+ <el-button @click="handleCancel">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+
+const props = defineProps({
+ modelValue: {
+ type: Boolean,
+ default: false
+ },
+ title: {
+ type: [String, Function],
+ default: ''
+ },
+ operationType: {
+ type: String,
+ default: ''
+ },
+ width: {
+ type: String,
+ default: '70%'
+ }
+})
+
+const emit = defineEmits(['update:modelValue', 'close', 'confirm', 'cancel'])
+
+const dialogVisible = computed({
+ get: () => props.modelValue,
+ set: (val) => emit('update:modelValue', val)
+})
+
+const computedTitle = computed(() => {
+ if (typeof props.title === 'function') {
+ return props.title(props.operationType)
+ }
+ return props.title
+})
+
+const handleClose = () => {
+ emit('close')
+}
+
+const handleConfirm = () => {
+ emit('confirm')
+}
+
+const handleCancel = () => {
+ emit('cancel')
+ dialogVisible.value = false
+}
+</script>
+
+<style scoped>
+.dialog-footer {
+ text-align: center;
+}
+</style>
+
diff --git a/src/components/Dialog/ImportDialog.vue b/src/components/Dialog/ImportDialog.vue
new file mode 100644
index 0000000..5b126dc
--- /dev/null
+++ b/src/components/Dialog/ImportDialog.vue
@@ -0,0 +1,172 @@
+<template>
+ <el-dialog
+ :title="title"
+ v-model="dialogVisible"
+ :width="width"
+ :append-to-body="appendToBody"
+ @close="handleClose"
+ >
+ <el-upload
+ ref="uploadRef"
+ :limit="limit"
+ :accept="accept"
+ :headers="headers"
+ :action="action"
+ :disabled="disabled"
+ :before-upload="beforeUpload"
+ :on-progress="onProgress"
+ :on-success="onSuccess"
+ :on-error="onError"
+ :on-change="onChange"
+ :auto-upload="autoUpload"
+ drag
+ >
+ <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
+ <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+ <template #tip>
+ <div class="el-upload__tip text-center">
+ <span>{{ tipText }}</span>
+ <el-link
+ v-if="showDownloadTemplate"
+ type="primary"
+ :underline="false"
+ style="font-size: 12px; vertical-align: baseline; margin-left: 5px;"
+ @click="handleDownloadTemplate"
+ >涓嬭浇妯℃澘</el-link
+ >
+ </div>
+ </template>
+ </el-upload>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="handleConfirm">纭� 瀹�</el-button>
+ <el-button @click="handleCancel">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+import { computed, ref } from 'vue'
+import { UploadFilled } from '@element-plus/icons-vue'
+
+const props = defineProps({
+ modelValue: {
+ type: Boolean,
+ default: false
+ },
+ title: {
+ type: String,
+ default: '瀵煎叆'
+ },
+ width: {
+ type: String,
+ default: '400px'
+ },
+ appendToBody: {
+ type: Boolean,
+ default: true
+ },
+ limit: {
+ type: Number,
+ default: 1
+ },
+ accept: {
+ type: String,
+ default: '.xlsx, .xls'
+ },
+ headers: {
+ type: Object,
+ default: () => ({})
+ },
+ action: {
+ type: String,
+ required: true
+ },
+ disabled: {
+ type: Boolean,
+ default: false
+ },
+ autoUpload: {
+ type: Boolean,
+ default: false
+ },
+ tipText: {
+ type: String,
+ default: '浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�'
+ },
+ showDownloadTemplate: {
+ type: Boolean,
+ default: true
+ },
+ beforeUpload: {
+ type: Function,
+ default: null
+ },
+ onProgress: {
+ type: Function,
+ default: null
+ },
+ onSuccess: {
+ type: Function,
+ default: null
+ },
+ onError: {
+ type: Function,
+ default: null
+ },
+ onChange: {
+ type: Function,
+ default: null
+ }
+})
+
+const emit = defineEmits(['update:modelValue', 'close', 'confirm', 'cancel', 'download-template'])
+
+const dialogVisible = computed({
+ get: () => props.modelValue,
+ set: (val) => emit('update:modelValue', val)
+})
+
+const uploadRef = ref(null)
+
+const handleClose = () => {
+ emit('close')
+}
+
+const handleConfirm = () => {
+ emit('confirm')
+}
+
+const submit = () => {
+ if (uploadRef.value) {
+ uploadRef.value.submit()
+ }
+}
+
+const handleCancel = () => {
+ emit('cancel')
+ dialogVisible.value = false
+}
+
+const handleDownloadTemplate = () => {
+ emit('download-template')
+}
+
+defineExpose({
+ uploadRef,
+ submit,
+ clearFiles: () => {
+ if (uploadRef.value) {
+ uploadRef.value.clearFiles()
+ }
+ }
+})
+</script>
+
+<style scoped>
+.dialog-footer {
+ text-align: center;
+}
+</style>
+
diff --git a/src/utils/index.js b/src/utils/index.js
index e522c3c..809593f 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -396,3 +396,16 @@
export function isEqual(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
+
+/**
+ * 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
+ * @returns {string} 鏍煎紡鍖栫殑鏃ユ湡瀛楃涓�
+ */
+export function getCurrentDate() {
+ const today = new Date();
+ const year = today.getFullYear();
+ const month = String(today.getMonth() + 1).padStart(2, '0'); // 鏈堜唤浠�0寮�濮�
+ const day = String(today.getDate()).padStart(2, '0');
+ return `${year}-${month}-${day}`;
+}
+
diff --git a/src/views/equipmentManagement/repair/Modal/ApproveModal.vue b/src/views/equipmentManagement/repair/Modal/ApproveModal.vue
new file mode 100644
index 0000000..9077b84
--- /dev/null
+++ b/src/views/equipmentManagement/repair/Modal/ApproveModal.vue
@@ -0,0 +1,135 @@
+<template>
+ <FormDialog
+ v-model="visible"
+ title="鎶ヤ慨瀹℃壒"
+ width="800px"
+ @confirm="handleSubmit"
+ @cancel="handleClose"
+ @close="handleClose"
+ >
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="璁惧鍚嶇О">
+ {{ detail.deviceName || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瑙勬牸鍨嬪彿">
+ {{ detail.deviceModel || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鎶ヤ慨鏃ユ湡">
+ {{ detail.repairTime || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鎶ヤ慨浜�">
+ {{ detail.repairName || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瀹℃壒浜�">
+ {{ detail.auditName || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="褰撳墠鐘舵��">
+ {{ statusText(detail.status) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鏁呴殰鐜拌薄" :span="2">
+ {{ detail.remark || "-" }}
+ </el-descriptions-item>
+ </el-descriptions>
+ <div style="margin-top: 16px">
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="瀹℃壒缁撴灉" prop="decision">
+ <el-radio-group v-model="form.decision">
+ <el-radio :value="0">閫氳繃</el-radio>
+ <el-radio :value="3">涓嶉�氳繃</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-form>
+ </div>
+ </FormDialog>
+</template>
+
+<script setup>
+import { nextTick, ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { editRepair, getRepairById } from "@/api/equipmentManagement/repair";
+
+defineOptions({
+ name: "鎶ヤ慨瀹℃壒寮圭獥",
+});
+
+const emits = defineEmits(["ok"]);
+
+const visible = ref(false);
+const loading = ref(false);
+const id = ref();
+const detail = ref({});
+const formRef = ref();
+const form = ref({
+ decision: undefined, // 0 閫氳繃 3 涓嶉�氳繃
+});
+
+const rules = {
+ decision: [{ required: true, message: "璇烽�夋嫨瀹℃壒缁撴灉", trigger: "change" }],
+};
+
+const statusText = (status) => {
+ const map = {
+ 0: "寰呯淮淇�",
+ 1: "瀹岀粨",
+ 2: "寰呭鏍�",
+ 3: "瀹℃牳涓嶉�氳繃",
+ };
+ return map[status] ?? "-";
+};
+
+const loadDetail = async (repairId) => {
+ const { data } = await getRepairById(repairId);
+ detail.value = data ?? {};
+};
+
+const open = async (repairId) => {
+ id.value = repairId;
+ visible.value = true;
+ await nextTick();
+ await loadDetail(repairId);
+ form.value.decision = undefined;
+};
+
+const handleClose = () => {
+ visible.value = false;
+ id.value = undefined;
+ detail.value = {};
+ form.value.decision = undefined;
+};
+
+const updateStatus = async (status) => {
+ loading.value = true;
+ try {
+ const { code } = await editRepair({ id: id.value, status });
+ if (code === 200) {
+ ElMessage.success("瀹℃壒鎴愬姛");
+ emits("ok");
+ handleClose();
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+
+const handleSubmit = async () => {
+ if (detail.value?.status !== 2) {
+ ElMessage.warning("浠呭緟瀹℃牳鐘舵�佸彲瀹℃壒");
+ return;
+ }
+ await formRef.value?.validate(async (valid) => {
+ if (!valid) return;
+ const isApprove = form.value.decision === 0;
+ ElMessageBox.confirm(`纭瀹℃壒${isApprove ? "閫氳繃" : "涓嶉�氳繃"}锛焋, "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }).then(() => updateStatus(form.value.decision));
+ });
+};
+
+defineExpose({ open });
+</script>
+
+<style scoped></style>
+
diff --git a/src/views/equipmentManagement/repair/Modal/MaintainModal.vue b/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
index 169075b..7058a5a 100644
--- a/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/MaintainModal.vue
@@ -1,5 +1,12 @@
<template>
- <el-dialog v-model="visible" :title="modalOptions.title" direction="ltr" @close="handleDialogClose">
+ <FormDialog
+ v-model="visible"
+ :title="'璁惧缁翠慨'"
+ width="500px"
+ @confirm="sendForm"
+ @cancel="handleCancel"
+ @close="handleClose"
+ >
<el-form :model="form" :rules="rules" label-width="110px" ref="formRef">
<el-form-item label="缁翠慨浜�" prop="maintenanceName">
<el-input v-model="form.maintenanceName" placeholder="璇疯緭鍏ョ淮淇汉" />
@@ -7,9 +14,9 @@
<el-form-item label="缁翠慨缁撴灉" prop="maintenanceResult">
<el-input v-model="form.maintenanceResult" placeholder="璇疯緭鍏ョ淮淇粨鏋�" />
</el-form-item>
- <el-form-item label="鏈缁翠慨閲戦" prop="repairPrice">
- <el-input-number v-model="form.repairPrice" :min="0" :precision="2" style="width: 100%" />
- </el-form-item>
+ <el-form-item label="鏈缁翠慨閲戦" prop="repairPrice">
+ <el-input-number v-model="form.repairPrice" :min="0" :precision="2" style="width: 100%" />
+ </el-form-item>
<el-form-item label="缁翠慨鏃ユ湡" prop="maintenanceTime">
<el-date-picker
v-model="form.maintenanceTime"
@@ -22,22 +29,16 @@
/>
</el-form-item>
</el-form>
- <template #footer>
- <el-button type="primary" @click="sendForm" :loading="loading">
- {{ modalOptions.confirmText }}
- </el-button>
- <el-button @click="handleDialogClose">{{ modalOptions.cancelText }}</el-button>
- </template>
- </el-dialog>
+ </FormDialog>
</template>
<script setup>
-import { ref, nextTick } from "vue";
-import { useModal } from "@/hooks/useModal";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { addMaintain } from "@/api/equipmentManagement/repair";
import useFormData from "@/hooks/useFormData";
import useUserStore from "@/store/modules/user";
import dayjs from "dayjs";
-import { addMaintain } from "@/api/equipmentManagement/repair";
+import { ElMessage } from "element-plus";
defineOptions({
name: "缁翠慨妯℃�佹",
@@ -45,23 +46,19 @@
const emits = defineEmits(["ok"]);
-const {
- id,
- visible,
- loading,
- openModal,
- modalOptions,
- handleConfirm,
- closeModal,
-} = useModal({ title: "璁惧缁翠慨" });
+// 淇濆瓨鎶ヤ慨璁板綍鐨刬d
+const repairId = ref();
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
const userStore = useUserStore();
-const formRef = ref();
const { form, resetForm } = useFormData({
maintenanceName: undefined, // 缁翠慨鍚嶇О
maintenanceResult: undefined, // 缁翠慨缁撴灉
maintenanceTime: undefined, // 缁翠慨鏃ユ湡
- repairPrice: undefined, // 鏈缁翠慨閲戦
+ repairPrice: undefined, // 缁翠慨閲戦
+ status: 0,
});
const rules = {
@@ -74,36 +71,46 @@
const setForm = (data) => {
form.maintenanceName = data.maintenanceName ?? userStore.nickName;
form.maintenanceResult = data.maintenanceResult;
- form.repairPrice = data.repairPrice;
form.maintenanceTime =
- dayjs(data.maintenanceTime).format("YYYY-MM-DD HH:mm:ss") ??
- dayjs().format("YYYY-MM-DD HH:mm:ss");
+ data.maintenanceTime
+ ? dayjs(data.maintenanceTime).format("YYYY-MM-DD HH:mm:ss")
+ : dayjs().format("YYYY-MM-DD HH:mm:ss");
+ form.status = 2; // 缁翠慨鍚庡浐瀹氳繘鍏ュ緟瀹℃牳锛堜笉鍦ㄧ晫闈㈠睍绀猴級
};
const sendForm = async () => {
- await formRef.value.validate(async (valid) => {
- if (!valid) return;
- const { code } = await addMaintain({ id: id.value, ...form });
- if (code == 200) {
- emits("ok");
- resetForm();
- closeModal();
- }
- });
+ await formRef.value.validate(async (valid) => {
+ if (!valid) return;
+ loading.value = true;
+ try {
+ const { code } = await addMaintain({ id: repairId.value, ...form });
+ if (code == 200) {
+ ElMessage.success("缁翠慨鎴愬姛");
+ emits("ok");
+ resetForm();
+ visible.value = false;
+ }
+ } finally {
+ loading.value = false;
+ }
+ })
+};
+
+const handleCancel = () => {
+ resetForm();
+ visible.value = false;
+};
+
+const handleClose = () => {
+ resetForm();
+ visible.value = false;
};
const open = async (id, row) => {
- openModal(id);
+ repairId.value = id; // 淇濆瓨鎶ヤ慨璁板綍鐨刬d
+ visible.value = true;
await nextTick();
setForm(row);
-};
-
-const handleDialogClose = () => {
- resetForm();
- nextTick(() => {
- formRef.value?.clearValidate?.();
- });
- closeModal();
};
defineExpose({
diff --git a/src/views/equipmentManagement/repair/Modal/RepairModal.vue b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
index 9f86722..20c9c8d 100644
--- a/src/views/equipmentManagement/repair/Modal/RepairModal.vue
+++ b/src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -1,10 +1,17 @@
<template>
- <el-dialog v-model="visible" :title="modalOptions.title" @close="close">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
+ <FormDialog
+ v-model="visible"
+ :title="id ? '缂栬緫璁惧鎶ヤ慨' : '鏂板璁惧鎶ヤ慨'"
+ width="800px"
+ @confirm="sendForm"
+ @cancel="handleCancel"
+ @close="handleClose"
+ >
+ <el-form :model="form" :rules="rules" label-width="100px" ref="formRef">
<el-row>
<el-col :span="12">
- <el-form-item label="璁惧鍚嶇О" prop="deviceLedgerId">
- <el-select v-model="form.deviceLedgerId" filterable allow-create default-first-option @change="setDeviceModel">
+ <el-form-item label="璁惧鍚嶇О">
+ <el-select v-model="form.deviceLedgerId" @change="setDeviceModel" filterable>
<el-option
v-for="(item, index) in deviceOptions"
:key="index"
@@ -16,11 +23,15 @@
</el-col>
<el-col :span="12">
<el-form-item label="瑙勬牸鍨嬪彿">
- <el-input v-model="form.deviceModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" disabled />
+ <el-input
+ v-model="form.deviceModel"
+ placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
+ disabled
+ />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="鎶ヤ慨鏃ユ湡" prop="repairTime">
+ <el-form-item label="鎶ヤ慨鏃ユ湡">
<el-date-picker
v-model="form.repairTime"
placeholder="璇烽�夋嫨鎶ヤ慨鏃ユ湡"
@@ -33,82 +44,116 @@
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="鎶ヤ慨浜�" prop="repairName">
+ <el-form-item label="鎶ヤ慨浜�">
<el-input v-model="form.repairName" placeholder="璇疯緭鍏ユ姤淇汉" />
</el-form-item>
</el-col>
+ <el-col :span="12">
+ <el-form-item label="瀹℃壒浜�" prop="auditName">
+ <el-select
+ v-model="form.auditName"
+ placeholder="璇烽�夋嫨瀹℃壒浜�"
+ filterable
+ clearable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="user in userOptions"
+ :key="user.userId"
+ :label="user.nickName"
+ :value="user.nickName"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row v-if="id">
+ <el-col :span="12">
+ <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="3"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
<el-col :span="24">
- <el-form-item label="鏁呴殰鐜拌薄" prop="remark">
- <el-input v-model="form.remark" :rows="2" type="textarea" placeholder="璇疯緭鍏ユ晠闅滅幇璞�" />
+ <el-form-item label="鏁呴殰鐜拌薄">
+ <el-input
+ v-model="form.remark"
+ :rows="2"
+ type="textarea"
+ placeholder="璇疯緭鍏ユ晠闅滅幇璞�"
+ />
</el-form-item>
</el-col>
</el-row>
</el-form>
- <template #footer>
- <el-button type="primary" @click="sendForm" :loading="loading">
- {{ modalOptions.confirmText }}
- </el-button>
- <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
- </template>
- </el-dialog>
-
+ </FormDialog>
</template>
<script setup>
-import { ref, nextTick } from "vue";
-import { useModal } from "@/hooks/useModal";
-import useFormData from "@/hooks/useFormData";
-import useUserStore from "@/store/modules/user";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
import {
addRepair,
editRepair,
getRepairById,
} from "@/api/equipmentManagement/repair";
-import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
import { ElMessage } from "element-plus";
+import dayjs from "dayjs";
+import useFormData from "@/hooks/useFormData";
+import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+import useUserStore from "@/store/modules/user";
+import { userListNoPageByTenantId } from "@/api/system/user";
defineOptions({
name: "璁惧鎶ヤ慨寮圭獥",
});
const emits = defineEmits(["ok"]);
-const {
- id,
- visible,
- loading,
- openModal,
- modalOptions,
- handleConfirm,
- closeModal,
-} = useModal({ title: "璁惧鎶ヤ慨" });
+
+const id = ref();
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
const userStore = useUserStore();
const deviceOptions = ref([]);
-const formRef = ref();
-const { form, resetForm } = useFormData({
- deviceLedgerId: undefined, // 璁惧Id
- deviceName: undefined, // 璁惧鍚嶇О
- deviceModel: undefined, // 瑙勬牸鍨嬪彿
- repairTime: undefined, // 鎶ヤ慨鏃ユ湡
- repairName: userStore.nickName, // 鎶ヤ慨浜�
- remark: undefined, // 鏁呴殰鐜拌薄
-});
-
-const rules = {
- deviceLedgerId: [{ required: true, message: "璇烽�夋嫨璁惧鍚嶇О", trigger: "change" }],
- repairTime: [{ required: true, message: "璇烽�夋嫨鎶ヤ慨鏃ユ湡", trigger: "change" }],
- repairName: [{ required: true, message: "璇疯緭鍏ユ姤淇汉", trigger: "blur" }],
- remark: [{ required: true, message: "璇疯緭鍏ユ晠闅滅幇璞�", trigger: "blur" }],
-};
+const userOptions = ref([]);
const loadDeviceName = async () => {
const { data } = await getDeviceLedger();
deviceOptions.value = data;
};
-const setDeviceModel = (id) => {
- const option = deviceOptions.value.find((item) => item.id === id);
- form.deviceModel = option ? option.deviceModel : undefined;
+const loadUserOptions = async () => {
+ const res = await userListNoPageByTenantId();
+ userOptions.value = res?.data ?? [];
+};
+
+const { form, resetForm } = useFormData({
+ deviceLedgerId: undefined, // 璁惧Id
+ deviceName: undefined, // 璁惧鍚嶇О
+ deviceModel: undefined, // 瑙勬牸鍨嬪彿
+ repairTime: dayjs().format("YYYY-MM-DD"), // 鎶ヤ慨鏃ユ湡锛岄粯璁ゅ綋澶�
+ repairName: userStore.nickName, // 鎶ヤ慨浜�
+ auditName: undefined, // 瀹℃壒浜�
+ remark: undefined, // 鏁呴殰鐜拌薄
+ status: 0, // 鎶ヤ慨鐘舵��
+});
+
+const rules = {
+ auditName: [
+ { required: true, message: "璇烽�夋嫨瀹℃壒浜�", trigger: "change" },
+ ],
+};
+
+const setDeviceModel = (deviceId) => {
+ const option = deviceOptions.value.find((item) => item.id === deviceId);
+ form.deviceModel = option.deviceModel;
};
const setForm = (data) => {
@@ -116,44 +161,55 @@
form.deviceName = data.deviceName;
form.deviceModel = data.deviceModel;
form.repairTime = data.repairTime;
- form.repairName = data.repairName ?? userStore.nickName;
+ form.repairName = data.repairName;
+ form.auditName = data.auditName;
form.remark = data.remark;
+ form.status = data.status;
};
const sendForm = async () => {
- await formRef.value.validate(async (valid) => {
+ await formRef.value?.validate(async (valid) => {
if (!valid) return;
loading.value = true;
- const payload = { ...form };
- const { code } = id.value
- ? await editRepair({ id: id.value, ...payload })
- : await addRepair(payload);
- if (code == 200) {
- ElMessage.success(`${id.value ? "缂栬緫" : "鏂板"}鎶ヤ慨鎴愬姛`);
- closeModal();
- emits("ok");
+ try {
+ const { code } = id.value
+ ? await editRepair({ id: unref(id), ...form })
+ : await addRepair(form);
+ if (code == 200) {
+ ElMessage.success(`${id.value ? "缂栬緫" : "鏂板"}鎶ヤ慨鎴愬姛`);
+ visible.value = false;
+ emits("ok");
+ }
+ } finally {
+ loading.value = false;
}
- loading.value = false;
});
};
+const handleCancel = () => {
+ resetForm();
+ visible.value = false;
+};
+
+const handleClose = () => {
+ resetForm();
+ visible.value = false;
+};
+
const openAdd = async () => {
- openModal();
+ id.value = undefined;
+ visible.value = true;
await nextTick();
- await loadDeviceName();
+ await Promise.all([loadDeviceName(), loadUserOptions()]);
};
const openEdit = async (editId) => {
const { data } = await getRepairById(editId);
- openModal(editId);
+ id.value = editId;
+ visible.value = true;
await nextTick();
- await loadDeviceName();
+ await Promise.all([loadDeviceName(), loadUserOptions()]);
setForm(data);
-};
-
-const close = () => {
- resetForm();
- closeModal();
};
defineExpose({
@@ -161,3 +217,5 @@
openEdit,
});
</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/repair/index.vue b/src/views/equipmentManagement/repair/index.vue
index 1302ef6..86e6848 100644
--- a/src/views/equipmentManagement/repair/index.vue
+++ b/src/views/equipmentManagement/repair/index.vue
@@ -14,7 +14,7 @@
<el-input
v-model="filters.deviceModel"
style="width: 240px"
- placeholder="璇烽�夋嫨瑙勬牸鍨嬪彿"
+ placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
clearable
@change="getTableData"
/>
@@ -64,16 +64,8 @@
<div class="actions">
<el-text class="mx-1" size="large">璁惧鎶ヤ慨</el-text>
<div>
- <el-button type="success" icon="Van" @click="addRepair">
- 鏂板鎶ヤ慨
- </el-button>
- <el-button
- type="primary"
- icon="Plus"
- :disabled="multipleList.length !== 1"
- @click="addMaintain"
- >
- 鏂板缁翠慨
+ <el-button type="success" icon="Van" @click="addRepair">
+ 鏂板鎶ヤ慨
</el-button>
<el-button @click="handleOut">
瀵煎嚭
@@ -81,7 +73,7 @@
<el-button
type="danger"
icon="Delete"
- :disabled="multipleList.length <= 0"
+ :disabled="multipleList.length <= 0 || hasFinishedStatus"
@click="delRepairByIds(multipleList.map((item) => item.id))"
>
鎵归噺鍒犻櫎
@@ -89,33 +81,53 @@
</div>
</div>
<PIMTable
- rowKey="id"
- isSelection
- :column="columns"
- :tableData="dataList"
- :page="{
+ rowKey="id"
+ isSelection
+ :column="columns"
+ :tableData="dataList"
+ :page="{
current: pagination.currentPage,
size: pagination.pageSize,
total: pagination.total,
}"
- @selection-change="handleSelectionChange"
- @pagination="changePage"
+ @selection-change="handleSelectionChange"
+ @pagination="changePage"
>
<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 === 0" type="warning">寰呯淮淇�</el-tag>
+ <el-tag v-else-if="row.status === 1" type="success">瀹岀粨</el-tag>
+ <el-tag v-else-if="row.status === 2" type="info">寰呭鏍�</el-tag>
+ <el-tag v-else-if="row.status === 3" type="danger">瀹℃牳涓嶉�氳繃</el-tag>
</template>
<template #operation="{ row }">
<el-button
type="primary"
link
+ :disabled="row.status === 1"
@click="editRepair(row.id)"
>
缂栬緫
</el-button>
<el-button
+ type="warning"
+ link
+ :disabled="row.status !== 2"
+ @click="openApprove(row.id)"
+ >
+ 瀹℃壒
+ </el-button>
+ <el-button
+ type="success"
+ link
+ :disabled="row.status !== 0"
+ @click="addMaintain(row)"
+ >
+ 缁翠慨
+ </el-button>
+ <el-button
type="danger"
- link
+ link
+ :disabled="row.status === 1"
@click="delRepairByIds(row.id)"
>
鍒犻櫎
@@ -123,29 +135,32 @@
</template>
</PIMTable>
</div>
- <RepairModal ref="repairModalRef" @ok="getTableData" />
- <MaintainModal ref="maintainModalRef" @ok="getTableData" />
+ <RepairModal ref="repairModalRef" @ok="getTableData"/>
+ <MaintainModal ref="maintainModalRef" @ok="getTableData"/>
+ <ApproveModal ref="approveModalRef" @ok="getTableData"/>
</div>
</template>
<script setup>
-import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { getRepairPage, delRepair } from "@/api/equipmentManagement/repair";
-import { onMounted, getCurrentInstance } from "vue";
+import { onMounted, getCurrentInstance, computed } from "vue";
+import {usePaginationApi} from "@/hooks/usePaginationApi";
+import {getRepairPage, delRepair} from "@/api/equipmentManagement/repair";
import RepairModal from "./Modal/RepairModal.vue";
-import { ElMessageBox, ElMessage } from "element-plus";
+import {ElMessageBox, ElMessage} from "element-plus";
import dayjs from "dayjs";
import MaintainModal from "./Modal/MaintainModal.vue";
+import ApproveModal from "./Modal/ApproveModal.vue";
defineOptions({
name: "璁惧鎶ヤ慨",
});
-const { proxy } = getCurrentInstance();
+const {proxy} = getCurrentInstance();
// 妯℃�佹瀹炰緥
const repairModalRef = ref();
const maintainModalRef = ref();
+const approveModalRef = ref();
// 琛ㄦ牸澶氶�夋閫変腑椤�
const multipleList = ref([]);
@@ -160,85 +175,85 @@
resetFilters,
onCurrentChange,
} = usePaginationApi(
- getRepairPage,
- {
- deviceName: undefined,
- deviceModel: undefined,
- remark: undefined,
- maintenanceName: undefined,
- repairTimeStr: undefined,
- maintenanceTimeStr: undefined,
- },
- [
+ getRepairPage,
{
- label: "璁惧鍚嶇О",
- align: "center",
- prop: "deviceName",
+ deviceName: undefined,
+ deviceModel: undefined,
+ remark: undefined,
+ maintenanceName: undefined,
+ repairTimeStr: undefined,
+ maintenanceTimeStr: undefined,
},
- {
- label: "瑙勬牸鍨嬪彿",
- align: "center",
- prop: "deviceModel",
- },
- {
- label: "鎶ヤ慨鏃ユ湡",
- align: "center",
- prop: "repairTime",
- formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
- },
- {
- label: "鎶ヤ慨浜�",
- align: "center",
- prop: "repairName",
- },
- {
- label: "鏁呴殰鐜拌薄",
- align: "center",
- prop: "remark",
- },
- {
- label: "缁翠慨浜�",
- align: "center",
- prop: "maintenanceName",
- },
- {
- label: "缁翠慨缁撴灉",
- align: "center",
- prop: "maintenanceResult",
- },
- {
- label: "缁翠慨鏃ユ湡",
- align: "center",
- prop: "maintenanceTime",
- formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
- },
- {
- label: "鐘舵��",
- align: "center",
- prop: "status",
- dataType: "slot",
- slot: "statusRef",
- },
- {
- fixed: "right",
- label: "鎿嶄綔",
- dataType: "slot",
- slot: "operation",
- align: "center",
- width: "150px",
- },
- ]
+ [
+ {
+ label: "璁惧鍚嶇О",
+ align: "center",
+ prop: "deviceName",
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ align: "center",
+ prop: "deviceModel",
+ },
+ {
+ label: "鎶ヤ慨鏃ユ湡",
+ align: "center",
+ prop: "repairTime",
+ formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
+ },
+ {
+ label: "鎶ヤ慨浜�",
+ align: "center",
+ prop: "repairName",
+ },
+ {
+ label: "鏁呴殰鐜拌薄",
+ align: "center",
+ prop: "remark",
+ },
+ {
+ label: "缁翠慨浜�",
+ align: "center",
+ prop: "maintenanceName",
+ },
+ {
+ label: "缁翠慨缁撴灉",
+ align: "center",
+ prop: "maintenanceResult",
+ },
+ {
+ label: "缁翠慨鏃ユ湡",
+ align: "center",
+ prop: "maintenanceTime",
+ formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""),
+ },
+ {
+ label: "鐘舵��",
+ align: "center",
+ prop: "status",
+ dataType: "slot",
+ slot: "statusRef",
+ },
+ {
+ fixed: "right",
+ label: "鎿嶄綔",
+ dataType: "slot",
+ slot: "operation",
+ align: "center",
+ width: "300px",
+ },
+ ]
);
// type === 1 缁翠慨 2鎶ヤ慨闂�
-const handleDateChange = (value,type) => {
+const handleDateChange = (value, type) => {
filters.maintenanceTimeStr = null
filters.c = null
- if(type === 1){
+ if (type === 1) {
if (value) {
filters.maintenanceTimeStr = dayjs(value).format("YYYY-MM-DD");
}
- }else{
+ } else {
if (value) {
filters.repairTimeStr = dayjs(value).format("YYYY-MM-DD");
}
@@ -251,6 +266,11 @@
multipleList.value = selectionList;
};
+// 妫�鏌ラ�変腑鐨勮褰曚腑鏄惁鏈夊畬缁撶姸鎬佺殑
+const hasFinishedStatus = computed(() => {
+ return multipleList.value.some(item => item.status === 1)
+})
+
// 鏂板鎶ヤ慨
const addRepair = () => {
repairModalRef.value.openAdd();
@@ -262,25 +282,41 @@
};
// 鏂板缁翠慨
-const addMaintain = () => {
- const row = multipleList.value[0];
+const addMaintain = (row) => {
maintainModalRef.value.open(row.id, row);
};
-const changePage = ({ page, limit }) => {
- pagination.currentPage = page;
- pagination.pageSize = limit;
- onCurrentChange(page);
+// 瀹℃壒
+const openApprove = (id) => {
+ approveModalRef.value.open(id);
+};
+
+const changePage = ({page, limit}) => {
+ pagination.currentPage = page;
+ pagination.pageSize = limit;
+ onCurrentChange(page);
};
// 鍗曡鍒犻櫎
const delRepairByIds = async (ids) => {
+ // 妫�鏌ユ槸鍚︽湁瀹岀粨鐘舵�佺殑璁板綍
+ const idsArray = Array.isArray(ids) ? ids : [ids];
+ const hasFinished = idsArray.some(id => {
+ const record = dataList.value.find(item => item.id === id);
+ return record && record.status === 1;
+ });
+
+ if (hasFinished) {
+ ElMessage.warning('涓嶈兘鍒犻櫎鐘舵�佷负瀹岀粨鐨勮褰�');
+ return;
+ }
+
ElMessageBox.confirm("纭鍒犻櫎鎶ヤ慨鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
confirmButtonText: "纭畾",
cancelButtonText: "鍙栨秷",
type: "warning",
}).then(async () => {
- const { code } = await delRepair(ids);
+ const {code} = await delRepair(ids);
if (code === 200) {
ElMessage.success("鍒犻櫎鎴愬姛");
getTableData();
@@ -295,12 +331,12 @@
cancelButtonText: "鍙栨秷",
type: "warning",
})
- .then(() => {
- proxy.download("/device/repair/export", {}, "璁惧鎶ヤ慨.xlsx");
- })
- .catch(() => {
- ElMessage.info("宸插彇娑�");
- });
+ .then(() => {
+ proxy.download("/device/repair/export", {}, "璁惧鎶ヤ慨.xlsx");
+ })
+ .catch(() => {
+ ElMessage.info("宸插彇娑�");
+ });
};
onMounted(() => {
@@ -312,6 +348,7 @@
.table_list {
margin-top: unset;
}
+
.actions {
display: flex;
justify-content: space-between;
diff --git a/src/views/equipmentManagement/upkeep/Form/ApproveModal.vue b/src/views/equipmentManagement/upkeep/Form/ApproveModal.vue
new file mode 100644
index 0000000..eb74cec
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/ApproveModal.vue
@@ -0,0 +1,137 @@
+<template>
+ <FormDialog
+ v-model="visible"
+ title="瀹氭椂浠诲姟瀹℃壒"
+ width="800px"
+ @confirm="handleSubmit"
+ @cancel="handleClose"
+ @close="handleClose"
+ >
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="浠诲姟鍚嶇О">
+ {{ detail.taskName || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="瑙勬牸鍨嬪彿">
+ {{ detail.deviceModel || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="棰戞">
+ {{ frequencyText(detail.frequencyType) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="寮�濮嬫棩鏈熶笌鏃堕棿">
+ {{ detail.frequencyDetail || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐧昏浜�">
+ {{ detail.registrant || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鐧昏鏃ユ湡">
+ {{ detail.registrationDate || "-" }}
+ </el-descriptions-item>
+ <el-descriptions-item label="褰撳墠鐘舵��">
+ {{ statusText(detail.status) }}
+ </el-descriptions-item>
+ <el-descriptions-item label="澶囨敞" :span="2">
+ {{ detail.remarks || "-" }}
+ </el-descriptions-item>
+ </el-descriptions>
+ <div style="margin-top: 16px">
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="瀹℃壒缁撴灉" prop="decision">
+ <el-radio-group v-model="form.decision">
+ <el-radio label="瀹℃牳閫氳繃">瀹℃牳閫氳繃</el-radio>
+ <el-radio label="瀹℃牳涓嶉�氳繃">瀹℃牳涓嶉�氳繃</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-form>
+ </div>
+ </FormDialog>
+</template>
+
+<script setup>
+import { nextTick, ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+import { deviceMaintenanceTaskEdit } from "@/api/equipmentManagement/upkeep";
+
+defineOptions({
+ name: "瀹氭椂浠诲姟瀹℃壒寮圭獥",
+});
+
+const emits = defineEmits(["ok"]);
+
+const visible = ref(false);
+const loading = ref(false);
+const detail = ref({});
+const formRef = ref();
+const form = ref({
+ decision: undefined, // 瀹℃牳閫氳繃 / 瀹℃牳涓嶉�氳繃
+});
+
+const rules = {
+ decision: [{ required: true, message: "璇烽�夋嫨瀹℃壒缁撴灉", trigger: "change" }],
+};
+
+const statusText = (status) => status || "-";
+
+const frequencyText = (type) => {
+ const map = {
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害",
+ };
+ return map[type] ?? "-";
+};
+
+const open = async (row) => {
+ detail.value = { ...(row || {}) };
+ visible.value = true;
+ await nextTick();
+ form.value.decision = undefined;
+};
+
+const handleClose = () => {
+ visible.value = false;
+ detail.value = {};
+ form.value.decision = undefined;
+};
+
+const updateStatus = async (status) => {
+ loading.value = true;
+ try {
+ const payload = { ...(detail.value || {}), status };
+ const { code } = await deviceMaintenanceTaskEdit(payload);
+ if (code === 200) {
+ ElMessage.success("瀹℃壒鎴愬姛");
+ emits("ok");
+ handleClose();
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+
+const handleSubmit = async () => {
+ if (detail.value?.status === "瀹℃牳閫氳繃") {
+ ElMessage.warning("瀹℃牳閫氳繃鍚庝笉鍙啀娆″鎵�");
+ return;
+ }
+ await formRef.value?.validate(async (valid) => {
+ if (!valid) return;
+ const isApprove = form.value.decision === "瀹℃牳閫氳繃";
+ ElMessageBox.confirm(
+ `纭瀹℃壒${isApprove ? "閫氳繃" : "涓嶉�氳繃"}锛焋,
+ "鎻愮ず",
+ {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ ).then(() => updateStatus(form.value.decision));
+ });
+};
+
+defineExpose({ open });
+</script>
+
+<style scoped></style>
+
diff --git a/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
new file mode 100644
index 0000000..2951df7
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -0,0 +1,146 @@
+<template>
+ <FormDialog
+ v-model="visible"
+ :title="'璁惧淇濆吇'"
+ width="500px"
+ @confirm="sendForm"
+ @cancel="handleCancel"
+ @close="handleClose"
+ >
+ <el-form :model="form" :rules="rules" label-width="120px" ref="formRef">
+ <el-form-item label="瀹為檯淇濆吇浜�" prop="maintenanceActuallyName">
+ <el-input
+ v-model="form.maintenanceActuallyName"
+ placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
+ ></el-input>
+ </el-form-item>
+ <el-form-item label="瀹為檯淇濆吇鏃ユ湡" prop="maintenanceActuallyTime">
+ <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="淇濆吇鐘舵��" prop="status">
+ <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-select>
+ </el-form-item>
+ <el-form-item label="淇濆吇缁撴灉" prop="maintenanceResult">
+ <el-input
+ v-model="form.maintenanceResult"
+ placeholder="璇疯緭鍏ヤ繚鍏荤粨鏋�"
+ type="text" />
+ </el-form-item>
+ <el-form-item label="鏈淇濆吇閲戦" prop="maintenancePrice">
+ <el-input-number v-model="form.maintenancePrice" :min="0" :precision="2" style="width: 100%" />
+ </el-form-item>
+ </el-form>
+ </FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.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";
+
+defineOptions({
+ name: "淇濆吇妯℃�佹",
+});
+
+const emits = defineEmits(["ok"]);
+
+// 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+const planId = ref();
+const visible = ref(false);
+const loading = ref(false);
+const formRef = ref();
+const userStore = useUserStore();
+
+const { form, resetForm } = useFormData({
+ maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
+ maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
+ maintenanceResult: undefined, // 淇濆吇缁撴灉
+ maintenancePrice: undefined, // 淇濆吇閲戦
+ status: 0, // 淇濆吇鐘舵��
+});
+
+const rules = {
+ maintenanceActuallyName: [
+ { required: true, message: "璇疯緭鍏ュ疄闄呬繚鍏讳汉", trigger: "blur" },
+ ],
+ maintenanceActuallyTime: [
+ { required: true, message: "璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡", trigger: "change" },
+ ],
+ maintenanceResult: [
+ { required: true, message: "璇疯緭鍏ヤ繚鍏荤粨鏋�", trigger: "blur" },
+ ],
+ maintenancePrice: [
+ { required: true, message: "璇疯緭鍏ユ湰娆′繚鍏婚噾棰�", trigger: "change" },
+ ],
+};
+
+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; // 榛樿鐘舵�佷负瀹岀粨
+};
+
+/**
+ * @desc 淇濆瓨淇濆吇
+ */
+const sendForm = async () => {
+ await formRef.value?.validate(async (valid) => {
+ if (!valid) return;
+ loading.value = true;
+ try {
+ const { code } = await addMaintenance({ id: planId.value, ...form });
+ if (code == 200) {
+ ElMessage.success("淇濆吇鎴愬姛");
+ emits("ok");
+ resetForm();
+ visible.value = false;
+ }
+ } finally {
+ loading.value = false;
+ }
+ });
+};
+
+const handleCancel = () => {
+ resetForm();
+ visible.value = false;
+};
+
+const handleClose = () => {
+ resetForm();
+ visible.value = false;
+};
+
+const open = async (id, row) => {
+ planId.value = id; // 淇濆瓨璁″垝淇濆吇璁板綍鐨刬d
+ visible.value = true;
+ await nextTick();
+ setForm(row);
+};
+
+defineExpose({
+ open,
+});
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
new file mode 100644
index 0000000..19095b9
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -0,0 +1,188 @@
+<template>
+ <FormDialog
+ v-model="visible"
+ :title="id ? '缂栬緫璁惧淇濆吇璁″垝' : '鏂板璁惧淇濆吇璁″垝'"
+ width="500px"
+ @confirm="sendForm"
+ @cancel="handleCancel"
+ @close="handleClose"
+ >
+ <el-form :model="form" label-width="100px">
+ <el-form-item label="璁惧鍚嶇О">
+ <el-select
+ v-model="form.deviceLedgerId"
+ @change="setDeviceModel"
+ placeholder="璇烽�夋嫨璁惧"
+ filterable
+ default-first-option
+ :reserve-keyword="false"
+ >
+ <el-option
+ v-for="(item, index) in deviceOptions"
+ :key="index"
+ :label="item.deviceName"
+ :value="item.id"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="瑙勬牸鍨嬪彿">
+ <el-input
+ v-model="form.deviceModel"
+ placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
+ disabled
+ />
+ </el-form-item>
+ <el-form-item label="褰曞叆浜�">
+ <el-select
+ v-model="form.createUser"
+ placeholder="璇烽�夋嫨"
+ filterable
+ default-first-option
+ :reserve-keyword="false"
+ clearable
+ >
+ <el-option
+ v-for="item in userList"
+ :key="item.userId"
+ :label="item.nickName"
+ :value="item.userId"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item v-if="id" 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-select>
+ </el-form-item>
+ <el-form-item label="璁″垝淇濆吇鏃ユ湡">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.maintenancePlanTime"
+ format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ type="date"
+ placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡鏃ユ湡"
+ clearable
+ />
+ </el-form-item>
+ </el-form>
+ </FormDialog>
+</template>
+
+<script setup>
+import FormDialog from "@/components/Dialog/FormDialog.vue";
+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 dayjs from "dayjs";
+import { userListNoPage } from "@/api/system/user.js";
+
+defineOptions({
+ name: "璁惧淇濆吇鏂板璁″垝",
+});
+
+const emits = defineEmits(["ok"]);
+
+const id = ref();
+const visible = ref(false);
+const loading = ref(false);
+
+const deviceOptions = ref([]);
+const loadDeviceName = async () => {
+ const { data } = await getDeviceLedger();
+ deviceOptions.value = data;
+};
+
+const { form, resetForm } = useFormData({
+ deviceLedgerId: undefined, // 璁惧Id
+ deviceName: undefined, // 璁惧鍚嶇О
+ deviceModel: undefined, // 瑙勬牸鍨嬪彿
+ maintenancePlanTime: undefined, // 璁″垝淇濆吇鏃ユ湡
+ createUser: undefined, // 褰曞叆浜�
+ status: 0, //淇濅慨鐘舵��
+});
+
+const setDeviceModel = (deviceId) => {
+ const option = deviceOptions.value.find((item) => item.id === deviceId);
+ form.deviceModel = option.deviceModel;
+};
+
+/**
+ * @desc 璁剧疆琛ㄥ崟鍐呭
+ * @param data 璁惧淇℃伅
+ */
+const setForm = (data) => {
+ form.deviceLedgerId = data.deviceLedgerId;
+ form.deviceName = data.deviceName;
+ form.deviceModel = data.deviceModel;
+ form.createUser = Number(data.createUser);
+ form.status = data.status;
+ form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
+ "YYYY-MM-DD HH:mm:ss"
+ );
+};
+
+// 鐢ㄦ埛鍒楄〃
+const userList = ref([]);
+
+onMounted(() => {
+ loadDeviceName();
+ userListNoPage().then((res) => {
+ userList.value = res.data;
+ });
+});
+
+const openEdit = async (editId) => {
+ const { data } = await getUpkeepById(editId);
+ id.value = editId;
+ visible.value = true;
+ await nextTick();
+ setForm(data);
+};
+
+const sendForm = async () => {
+ loading.value = true;
+ try {
+ const { code } = id.value
+ ? await editUpkeep({ id: unref(id), ...form })
+ : await addUpkeep(form);
+ if (code == 200) {
+ ElMessage.success(`${id.value ? "缂栬緫" : "鏂板"}璁″垝鎴愬姛`);
+ visible.value = false;
+ emits("ok");
+ }
+ } finally {
+ loading.value = false;
+ }
+};
+
+const handleCancel = () => {
+ resetForm();
+ visible.value = false;
+};
+
+const handleClose = () => {
+ resetForm();
+ visible.value = false;
+};
+
+const openModal = () => {
+ id.value = undefined;
+ visible.value = true;
+};
+
+defineExpose({
+ openModal,
+ openEdit,
+});
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/upkeep/Form/formDia.vue b/src/views/equipmentManagement/upkeep/Form/formDia.vue
new file mode 100644
index 0000000..5a4d7ef
--- /dev/null
+++ b/src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -0,0 +1,325 @@
+<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="auditName">
+ <el-select
+ v-model="form.auditName"
+ filterable
+ placeholder="璇烽�夋嫨瀹℃壒浜�"
+ clearable
+ >
+ <el-option
+ v-for="item in userList"
+ :key="item.userId"
+ :label="item.nickName"
+ :value="item.nickName"
+ />
+ </el-select>
+ </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="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>
+</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 { getDeviceLedger } from "@/api/equipmentManagement/ledger";
+import { deviceMaintenanceTaskAdd, deviceMaintenanceTaskEdit } from "@/api/equipmentManagement/upkeep";
+import { getCurrentDate } from "@/utils/index.js";
+import useUserStore from "@/store/modules/user.js";
+
+const { proxy } = getCurrentInstance()
+const emit = defineEmits()
+const dialogVisitable = ref(false);
+const operationType = ref('add');
+const deviceOptions = ref([]);
+const userStore = useUserStore();
+const data = reactive({
+ form: {
+ taskId: undefined,
+ taskName: undefined,
+ // 褰曞叆浜猴細鍗曢�変竴涓敤鎴� id
+ inspector: undefined,
+ auditName: undefined,
+ remarks: '',
+ frequencyType: '',
+ frequencyDetail: '',
+ week: '',
+ time: '',
+ deviceModel: undefined, // 瑙勬牸鍨嬪彿
+ registrationDate: ''
+ },
+ rules: {
+ taskId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" },],
+ inspector: [{ required: true, message: "璇烽�夋嫨褰曞叆浜�", trigger: "blur" },],
+ registrationDate: [{ required: true, message: "璇烽�夋嫨鐧昏鏃堕棿", trigger: "change" }],
+ auditName: [{ required: true, message: "璇烽�夋嫨瀹℃壒浜�", trigger: "change" }],
+ }
+})
+const { form, rules } = toRefs(data)
+const userList = ref([])
+
+const loadDeviceName = async () => {
+ 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 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
+ }
+
+ // 濡傛灉鏈夎澶嘔D锛岃嚜鍔ㄨ缃澶囦俊鎭�
+ if (form.value.taskId) {
+ setDeviceModel(form.value.taskId);
+ }
+ } else if (type === 'add') {
+ // 鏂板鏃惰缃櫥璁版棩鏈熶负褰撳ぉ
+ form.value.registrationDate = getCurrentDate();
+ // 鏂板鏃惰缃綍鍏ヤ汉涓哄綋鍓嶇櫥褰曡处鎴�
+ form.value.inspector = userStore.id;
+ }
+}
+
+// 鍏抽棴瀵硅瘽妗�
+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: undefined,
+ auditName: undefined,
+ remarks: '',
+ frequencyType: '',
+ frequencyDetail: '',
+ week: '',
+ time: '',
+ deviceModel: undefined,
+ registrationDate: ''
+ }
+}
+
+// 鎻愪氦琛ㄥ崟
+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
+
+ 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 = '寰呭鏍�' // 榛樿鐘舵�侊細寰呭鏍�
+ }
+ payload.active = true
+ 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 })
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue b/src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue
deleted file mode 100644
index c58e413..0000000
--- a/src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
- <el-dialog v-model="visible" :title="modalOptions.title" direction="ltr">
- <el-form :model="form" :rules="rules" label-width="110px" ref="formRef">
- <el-form-item label="瀹為檯淇濆吇浜�" prop="maintenanceActuallyName">
- <el-input
- v-model="form.maintenanceActuallyName"
- placeholder="璇疯緭鍏ュ疄闄呬繚鍏讳汉"
- ></el-input>
- </el-form-item>
- <el-form-item label="瀹為檯淇濆吇鏃ユ湡" prop="maintenanceActuallyTime">
- <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="淇濆吇缁撴灉" prop="maintenanceResult">
- <el-select v-model="form.maintenanceResult" placeholder="璇烽�夋嫨淇濆吇缁撴灉">
- <el-option label="瀹屽ソ" :value="1"></el-option>
- <el-option label="缁翠慨" :value="0"></el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="鏈淇濆吇閲戦" prop="maintenancePrice">
- <el-input-number v-model="form.maintenancePrice" :min="0" :precision="2" style="width: 100%" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button type="primary" @click="sendForm" :loading="loading">
- {{ modalOptions.confirmText }}
- </el-button>
- <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
- </template>
- </el-dialog>
-</template>
-
-<script setup>
-import { ref, nextTick } from "vue";
-import { useModal } from "@/hooks/useModal";
-import useFormData from "@/hooks/useFormData";
-import useUserStore from "@/store/modules/user";
-import dayjs from "dayjs";
-import { addMaintenance } from "@/api/equipmentManagement/upkeep";
-
-defineOptions({
- name: "淇濆吇妯℃�佹",
-});
-
-const emits = defineEmits(["ok"]);
-
-const {
- id,
- visible,
- loading,
- openModal,
- modalOptions,
- handleConfirm,
- closeModal,
-} = useModal({ title: "璁惧淇濆吇" });
-
-/**
- * @desc 淇濆瓨淇濆吇
- */
-const userStore = useUserStore();
-const formRef = ref();
-const { form, resetForm } = useFormData({
- maintenanceActuallyName: undefined, // 瀹為檯淇濆吇浜�
- maintenanceActuallyTime: undefined, // 瀹為檯淇濆吇鏃ユ湡
- maintenanceResult: undefined, // 淇濆吇缁撴灉
- maintenancePrice: undefined, // 淇濆吇閲戦
-});
-
-const rules = {
- maintenanceActuallyName: [
- { required: true, message: "璇疯緭鍏ュ疄闄呬繚鍏讳汉", trigger: "blur" },
- ],
- maintenanceActuallyTime: [
- { required: true, message: "璇烽�夋嫨瀹為檯淇濆吇鏃ユ湡", trigger: "change" },
- ],
- maintenanceResult: [
- { required: true, message: "璇烽�夋嫨淇濆吇缁撴灉", trigger: "change" },
- ],
- maintenancePrice: [
- { required: true, message: "璇疯緭鍏ユ湰娆′繚鍏婚噾棰�", trigger: "change" },
- ],
-};
-
-const sendForm = async () => {
- await formRef.value.validate(async (valid) => {
- if (!valid) return;
- const { code } = await addMaintenance({ id: id.value, ...form });
- if (code == 200) {
- emits("ok");
- resetForm();
- closeModal();
- }
- });
-};
-
-const open = async (id, row) => {
- openModal(id);
- await nextTick();
- if (!row) {
- resetForm();
- form.maintenanceActuallyName = userStore.nickName;
- return;
- }
- form.maintenanceActuallyName = row.maintenanceActuallyName ?? userStore.nickName;
- form.maintenanceActuallyTime = row.maintenanceActuallyTime
- ? dayjs(row.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
- : undefined;
- form.maintenanceResult = row.maintenanceResult;
- form.maintenancePrice = row.maintenancePrice;
-};
-defineExpose({
- open,
-});
-</script>
-
-<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/upkeep/Modal/PlanModal.vue b/src/views/equipmentManagement/upkeep/Modal/PlanModal.vue
deleted file mode 100644
index 3dbbb62..0000000
--- a/src/views/equipmentManagement/upkeep/Modal/PlanModal.vue
+++ /dev/null
@@ -1,162 +0,0 @@
-<template>
- <el-dialog
- v-model="visible"
- :title="modalOptions.title"
- width="30%"
- @close="close"
- >
- <el-form :model="form" :rules="rules" ref="formRef" label-width="110px">
- <el-form-item label="璁惧鍚嶇О" prop="deviceLedgerId">
- <el-select
- v-model="form.deviceLedgerId"
- filterable allow-create default-first-option
- @change="setDeviceModel"
- placeholder="璇烽�夋嫨璁惧"
- >
- <el-option
- v-for="(item, index) in deviceOptions"
- :key="index"
- :label="item.deviceName"
- :value="item.id"
- ></el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="瑙勬牸鍨嬪彿">
- <el-input
- v-model="form.deviceModel"
- placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
- disabled
- />
- </el-form-item>
- <el-form-item label="璁″垝淇濆吇鏃ユ湡" prop="maintenancePlanTime">
- <el-date-picker
- style="width: 100%"
- v-model="form.maintenancePlanTime"
- format="YYYY-MM-DD"
- value-format="YYYY-MM-DD HH:mm:ss"
- type="date"
- placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡鏃ユ湡"
- clearable
- />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button type="primary" @click="sendForm" :loading="loading">
- {{ modalOptions.confirmText }}
- </el-button>
- <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button>
- </template>
- </el-dialog>
-</template>
-
-<script setup>
-import { ref, nextTick, watch } from "vue";
-import { useModal } from "@/hooks/useModal";
-import useFormData from "@/hooks/useFormData";
-import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
-import dayjs from "dayjs";
-import {
- addUpkeep,
- editUpkeep,
- getUpkeepById,
-} from "@/api/equipmentManagement/upkeep";
-import { ElMessage } from "element-plus";
-
-defineOptions({
- name: "璁惧淇濆吇鏂板璁″垝",
-});
-
-const emits = defineEmits(["ok"]);
-const {
- id,
- visible,
- loading,
- openModal,
- modalOptions,
- handleConfirm,
- closeModal,
-} = useModal({ title: "璁惧淇濆吇璁″垝" });
-
-const deviceOptions = ref([]);
-const formRef = ref();
-const { form, resetForm } = useFormData({
- deviceLedgerId: undefined, // 璁惧Id
- deviceName: undefined, // 璁惧鍚嶇О
- deviceModel: undefined, // 瑙勬牸鍨嬪彿
- maintenancePlanTime: undefined, // 璁″垝淇濆吇鏃ユ湡
-});
-
-const rules = {
- deviceLedgerId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
- maintenancePlanTime: [
- { required: true, message: "璇烽�夋嫨璁″垝淇濆吇鏃ユ湡", trigger: "change" },
- ],
-};
-
-const loadDeviceName = async () => {
- const { data } = await getDeviceLedger();
- deviceOptions.value = data;
-};
-
-const setDeviceModel = (id) => {
- const option = deviceOptions.value.find((item) => item.id === id);
- form.deviceModel = option ? option.deviceModel : undefined;
-};
-
-const setForm = (data) => {
- form.deviceLedgerId = data.deviceLedgerId;
- form.deviceName = data.deviceName;
- form.deviceModel = data.deviceModel;
- form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
- "YYYY-MM-DD HH:mm:ss"
- );
-};
-
-const openEdit = async (editId) => {
- const { data } = await getUpkeepById(editId);
- openModal(editId);
- await nextTick();
- await loadDeviceName();
- setForm(data);
-};
-
-const sendForm = async () => {
- await formRef.value.validate(async (valid) => {
- if (!valid) return;
- loading.value = true;
- const payload = { ...form };
- const { code } = id.value
- ? await editUpkeep({ id: id.value, ...payload })
- : await addUpkeep(payload);
- if (code == 200) {
- ElMessage.success(`${id.value ? "缂栬緫" : "鏂板"}璁″垝鎴愬姛`);
- closeModal();
- emits("ok");
- }
- loading.value = false;
- });
-};
-
-const close = () => {
- resetForm();
- closeModal();
-};
-
-// load device options whenever the dialog opens (covers add and edit)
-watch(
- () => visible.value,
- async (val) => {
- if (val) {
- await nextTick();
- await loadDeviceName();
- }
- }
-);
-
-defineExpose({
- openModal,
- openEdit,
-});
-</script>
-
-<style lang="scss" scoped></style>
diff --git a/src/views/equipmentManagement/upkeep/index.vue b/src/views/equipmentManagement/upkeep/index.vue
index 2659ae0..6102415 100644
--- a/src/views/equipmentManagement/upkeep/index.vue
+++ b/src/views/equipmentManagement/upkeep/index.vue
@@ -1,76 +1,163 @@
<template>
<div class="app-container">
- <el-form :model="filters" :inline="true">
- <el-form-item label="璁惧鍚嶇О">
- <el-input
- v-model="filters.deviceName"
- style="width: 240px"
- placeholder="璇疯緭鍏ヨ澶囧悕绉�"
- clearable
- @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-form-item>
- <el-form-item label="瀹為檯淇濆吇鏃ユ湡">
- <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
- @change="getTableData"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" @click="getTableData">鎼滅储</el-button>
- <el-button @click="resetFilters">閲嶇疆</el-button>
- </el-form-item>
- </el-form>
- <div class="table_list">
- <div class="actions">
- <el-text class="mx-1" size="large">璁惧淇濆吇</el-text>
- <div>
- <el-button type="success" icon="Van" @click="addPlan">
- 鏂板璁″垝
- </el-button>
- <el-button
- type="primary"
- icon="Plus"
- :disabled="multipleList.length !== 1"
- @click="addMaintain"
- >
- 鏂板淇濆吇
- </el-button>
- <el-button @click="handleOut">
- 瀵煎嚭
- </el-button>
- <el-button
- type="danger"
- icon="Delete"
- :disabled="multipleList.length <= 0"
- @click="delRepairByIds(multipleList.map((item) => item.id))"
- >
- 鎵归噺鍒犻櫎
- </el-button>
+ <el-tabs v-model="activeTab" @tab-change="handleTabChange">
+ <!-- 瀹氭椂浠诲姟绠$悊tab -->
+ <el-tab-pane label="瀹氭椂浠诲姟绠$悊" name="scheduled">
+ <div class="search_form">
+ <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-form-item>
+ <el-form-item label="浠诲姟鐘舵��">
+ <el-select v-model="scheduledFilters.status" placeholder="璇烽�夋嫨浠诲姟鐘舵��" clearable style="width: 200px">
+ <el-option label="寰呭鏍�" value="寰呭鏍�" />
+ <el-option label="瀹℃牳閫氳繃" value="瀹℃牳閫氳繃" />
+ <el-option label="瀹℃牳涓嶉�氳繃" value="瀹℃牳涓嶉�氳繃" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="getScheduledTableData">鎼滅储</el-button>
+ <el-button @click="resetScheduledFilters">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
</div>
- </div>
- <PIMTable
+ <div class="table_list">
+ <div class="actions">
+ <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>
+ </div>
+ </div>
+ <PIMTable
+ rowKey="id"
+ isSelection
+ :column="scheduledColumns"
+ :tableData="scheduledDataList"
+ :page="{
+ current: scheduledPagination.currentPage,
+ size: scheduledPagination.pageSize,
+ total: scheduledPagination.total,
+ }"
+ @selection-change="handleScheduledSelectionChange"
+ @pagination="changeScheduledPage"
+ >
+ <template #statusRef="{ row }">
+ <el-tag v-if="row.status === '寰呭鏍�'" type="warning">寰呭鏍�</el-tag>
+ <el-tag v-else-if="row.status === '瀹℃牳閫氳繃'" type="success">瀹℃牳閫氳繃</el-tag>
+ <el-tag v-else-if="row.status === '瀹℃牳涓嶉�氳繃'" type="danger">瀹℃牳涓嶉�氳繃</el-tag>
+ <span v-else>{{ row.status }}</span>
+ </template>
+ <template #operation="{ row }">
+ <el-button
+ type="primary"
+ link
+ @click="editScheduledTask(row)"
+ >
+ 缂栬緫
+ </el-button>
+ <el-button
+ type="warning"
+ link
+ :disabled="row.status === '瀹℃牳閫氳繃'"
+ @click="openScheduledApprove(row)"
+ >
+ 瀹℃壒
+ </el-button>
+ <el-button
+ type="danger"
+ link
+ @click="delScheduledTaskByIds(row.id)"
+ >
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </PIMTable>
+ </div>
+ </el-tab-pane>
+
+ <!-- 浠诲姟璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛� -->
+ <el-tab-pane label="浠诲姟璁板綍" name="record">
+ <div class="search_form">
+ <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-form-item>
+ <el-form-item label="璁″垝淇濆吇鏃ユ湡">
+ <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-form-item>
+ <el-form-item label="瀹為檯淇濆吇浜�">
+ <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 @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>
+ <div>
+ <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"
@@ -84,130 +171,186 @@
@pagination="changePage"
>
<template #maintenanceResultRef="{ row }">
- <el-tag v-if="row.maintenanceResult === 1" type="success">
- 瀹屽ソ
- </el-tag>
- <el-tag v-if="row.maintenanceResult === 0" type="danger">
- 缁翠慨
- </el-tag>
+ <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="danger">寰呬繚鍏�</el-tag>
+ <el-tag v-if="row.status === 0" type="warning">寰呬繚鍏�</el-tag>
</template>
<template #operation="{ row }">
+ <!-- 杩欎釜鍔熻兘璺熸柊澧炰繚鍏诲姛鑳戒竴妯′竴鏍凤紝鏈夊暐鎰忎箟锛� -->
+ <!-- <el-button
+ type="primary"
+ text
+ @click="addMaintain(row)"
+ >
+ 鏂板淇濆吇
+ </el-button> -->
<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>
+ <el-button
type="danger"
- link
+ link
+ :disabled="row.status === 1"
@click="delRepairByIds(row.id)"
>
鍒犻櫎
</el-button>
+ <el-button
+ type="primary"
+ link
+ @click="openFileDialog(row)"
+ >
+ 闄勪欢
+ </el-button>
</template>
</PIMTable>
- </div>
+ </div>
+ </el-tab-pane>
+ </el-tabs>
<PlanModal ref="planModalRef" @ok="getTableData" />
<MaintenanceModal ref="maintainModalRef" @ok="getTableData" />
+ <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" />
+ <ApproveModal ref="approveModalRef" @ok="getScheduledTableData" />
+ <FileListDialog
+ ref="fileListDialogRef"
+ v-model="fileDialogVisible"
+ :show-upload-button="true"
+ :show-delete-button="true"
+ :delete-method="handleAttachmentDelete"
+ :name-column-label="'闄勪欢鍚嶇О'"
+ :rulesRegulationsManagementId="currentMaintenanceTaskId"
+ @upload="handleAttachmentUpload" />
</div>
</template>
<script setup>
-import { usePaginationApi } from "@/hooks/usePaginationApi";
-import { getUpkeepPage, delUpkeep } from "@/api/equipmentManagement/upkeep";
-import { onMounted, getCurrentInstance } from "vue";
-import PlanModal from "./Modal/PlanModal.vue";
-import MaintenanceModal from "./Modal/MaintenanceModal.vue";
-import dayjs from "dayjs";
-import { ElMessageBox, ElMessage } from "element-plus";
+import { ref, onMounted, reactive, getCurrentInstance, nextTick, computed } 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 ApproveModal from './Form/ApproveModal.vue'
+import FileListDialog from '@/components/Dialog/FileListDialog.vue'
+import {
+ getUpkeepPage,
+ delUpkeep,
+ deviceMaintenanceTaskList,
+ deviceMaintenanceTaskDel,
+} from '@/api/equipmentManagement/upkeep'
+import {
+ listMaintenanceTaskFiles,
+ addMaintenanceTaskFile,
+ delMaintenanceTaskFile,
+} from '@/api/equipmentManagement/maintenanceTaskFile'
+import dayjs from 'dayjs'
-defineOptions({
- name: "璁惧淇濆吇",
-});
+const { proxy } = getCurrentInstance()
-const { proxy } = getCurrentInstance();
+// Tab鐩稿叧
+const activeTab = ref('scheduled')
// 璁″垝寮圭獥鎺у埗鍣�
-const planModalRef = ref();
+const planModalRef = ref()
// 淇濆吇寮圭獥鎺у埗鍣�
-const maintainModalRef = ref();
+const maintainModalRef = ref()
+// 瀹氭椂浠诲姟寮圭獥鎺у埗鍣�
+const formDiaRef = ref()
+// 淇濆吇瀹℃壒寮圭獥
+const approveModalRef = ref()
+// 闄勪欢寮圭獥
+const fileListDialogRef = ref(null)
+const fileDialogVisible = ref(false)
+const currentMaintenanceTaskId = ref(null)
-// 琛ㄦ牸澶氶�夋閫変腑椤�
-const multipleList = ref([]);
+// 浠诲姟璁板綍tab锛堝師璁惧淇濆吇椤甸潰锛夌浉鍏冲彉閲�
+const filters = reactive({
+ deviceName: '',
+ maintenancePlanTime: '',
+ maintenanceActuallyTime: '',
+ maintenanceActuallyName: '',
+})
-// 澶氶�夊悗鍋氫粈涔�
-const handleSelectionChange = (selectionList) => {
- multipleList.value = selectionList;
-};
+const dataList = ref([])
+const pagination = ref({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+})
+const multipleList = ref([])
-// 琛ㄦ牸閽╁瓙
-const {
- filters,
- columns,
- dataList,
- pagination,
- getTableData,
- resetFilters,
- onCurrentChange,
-} = usePaginationApi(getUpkeepPage, {
- deviceName: undefined,
- maintenancePlanTime: undefined,
- maintenanceActuallyTime: undefined,
- maintenanceActuallyName: undefined,
-}, [
- {
- label: "璁惧鍚嶇О",
- align: "center",
- prop: "deviceName",
- },
- {
- label: "瑙勬牸鍨嬪彿",
- align: "center",
- prop: "deviceModel",
- },
- {
- label: "璁″垝淇濆吇鏃ユ湡",
- align: "center",
- prop: "maintenancePlanTime",
- formatData: (cell) => 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 HH:mm:ss") : "-",
- },
- {
- label: "淇濆吇缁撴灉",
- align: "center",
- prop: "maintenanceResult",
- dataType: "slot",
- slot: "maintenanceResultRef",
- },
+// 瀹氭椂浠诲姟绠$悊tab鐩稿叧鍙橀噺
+const scheduledFilters = reactive({
+ taskName: '',
+ status: '',
+})
+
+const scheduledDataList = ref([])
+const scheduledPagination = reactive({
+ currentPage: 1,
+ pageSize: 10,
+ total: 0,
+})
+const scheduledMultipleList = ref([])
+
+// 瀹氭椂浠诲姟绠$悊琛ㄦ牸鍒楅厤缃�
+const scheduledColumns = ref([
+ { prop: "taskName", label: "璁惧鍚嶇О"},
+ {
+ label: "瑙勬牸鍨嬪彿",
+ prop: "deviceModel",
+ },
+ {
+ prop: "frequencyType",
+ label: "棰戞",
+ minWidth: 150,
+ // PIMTable 浣跨敤鐨勬槸 formatData锛岃�屼笉鏄� Element-Plus 鐨� formatter
+ formatData: (cell) => ({
+ DAILY: "姣忔棩",
+ WEEKLY: "姣忓懆",
+ MONTHLY: "姣忔湀",
+ QUARTERLY: "瀛e害"
+ }[cell] || "")
+ },
+ {
+ prop: "frequencyDetail",
+ label: "寮�濮嬫棩鏈熶笌鏃堕棿",
+ minWidth: 150,
+ // 鍚屾牱鏀圭敤 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: "registrant", label: "鐧昏浜�", minWidth: 100 },
+ { prop: "registrationDate", label: "鐧昏鏃ユ湡", minWidth: 100 },
{
label: "鐘舵��",
align: "center",
@@ -215,86 +358,350 @@
dataType: "slot",
slot: "statusRef",
},
- {
- fixed: "right",
- label: "鎿嶄綔",
- dataType: "slot",
- slot: "operation",
- align: "center",
- width: "150px",
- },
-]);
-// type == 1瀹為檯淇濆吇鏃堕棿 2璁″垝淇濆吇鏃堕棿
-const handleDateChange = (value,type) => {
- filters.maintenanceActuallyTimeReq = null
- filters.maintenancePlanTimeReq = null
- if(type === 1){
- if (value) {
- filters.maintenanceActuallyTimeReq = dayjs(value).format("YYYY-MM-DD");
- }
- }else{
- if (value) {
- filters.maintenancePlanTimeReq = dayjs(value).format("YYYY-MM-DD");
- }
+ {
+ fixed: "right",
+ label: "鎿嶄綔",
+ dataType: "slot",
+ slot: "operation",
+ align: "center",
+ width: "200px",
+ },
+])
+
+// 浠诲姟璁板綍琛ㄦ牸鍒楅厤缃紙鍘熻澶囦繚鍏昏〃鏍煎垪锛�
+const columns = ref([
+ {
+ label: "璁惧鍚嶇О",
+ align: "center",
+ prop: "deviceName",
+ },
+ {
+ label: "瑙勬牸鍨嬪彿",
+ align: "center",
+ prop: "deviceModel",
+ },
+ {
+ label: "璁″垝淇濆吇鏃ユ湡",
+ align: "center",
+ prop: "maintenancePlanTime",
+ formatData: (cell) => 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 HH:mm:ss") : "-",
+ },
+ {
+ 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: "350px",
+ },
+])
+
+// Tab鍒囨崲澶勭悊
+const handleTabChange = (tabName) => {
+ if (tabName === 'record') {
+ getTableData()
+ } else if (tabName === 'scheduled') {
+ getScheduledTableData()
}
- getTableData();
-};
+}
-// 鏂板淇濆吇
-const addMaintain = () => {
- const row = multipleList.value[0];
- maintainModalRef.value.open(row.id, row);
-};
-
-// 鏂板璁″垝
-const addPlan = () => {
- planModalRef.value.openModal();
-};
-
-// 缂栬緫璁″垝
-const editPlan = (id) => {
- planModalRef.value.openEdit(id);
-};
-
-const changePage = ({ page, limit }) => {
- pagination.currentPage = page;
- pagination.pageSize = limit;
- onCurrentChange(page);
-};
-
-// 鍗曡鍒犻櫎
-const delRepairByIds = async (ids) => {
- ElMessageBox.confirm("纭鍒犻櫎鎶ヤ慨鏁版嵁, 姝ゆ搷浣滀笉鍙��?", "璀﹀憡", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- }).then(async () => {
- const { code } = await delUpkeep(ids);
- if (code === 200) {
- ElMessage.success("鍒犻櫎鎴愬姛");
- getTableData();
+// 瀹氭椂浠诲姟绠$悊鐩稿叧鏂规硶
+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 handleScheduledSelectionChange = (selection) => {
+ scheduledMultipleList.value = selection
+}
+
+const changeScheduledPage = (page) => {
+ scheduledPagination.currentPage = page.page
+ scheduledPagination.pageSize = page.limit
+ getScheduledTableData()
+}
+
+const addScheduledTask = () => {
+ nextTick(() => {
+ formDiaRef.value?.openDialog('add');
+ });
+}
+
+const editScheduledTask = (row) => {
+ if (row) {
+ nextTick(() => {
+ formDiaRef.value?.openDialog('edit', 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 resetFilters = () => {
+ filters.deviceName = ''
+ filters.maintenancePlanTime = ''
+ filters.maintenanceActuallyTime = ''
+ filters.maintenanceActuallyName = ''
+ getTableData()
+}
+
+const handleSelectionChange = (selection) => {
+ multipleList.value = selection
+}
+
+// 妫�鏌ラ�変腑鐨勮褰曚腑鏄惁鏈夊畬缁撶姸鎬佺殑
+const hasFinishedStatus = computed(() => {
+ return multipleList.value.some(item => item.status === 1)
+})
+
+const changePage = (page) => {
+ pagination.value.currentPage = page.page
+ pagination.value.pageSize = page.limit
+ getTableData()
+}
+
+const addMaintain = (row) => {
+ maintainModalRef.value.open(row.id, row)
+}
+
+// 瀹氭椂浠诲姟瀹℃壒
+const openScheduledApprove = (row) => {
+ approveModalRef.value.open(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: "纭",
- cancelButtonText: "鍙栨秷",
- type: "warning",
+ ElMessageBox.confirm('閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�', '瀵煎嚭', {
+ confirmButtonText: '纭',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
})
.then(() => {
- proxy.download("/device/maintenance/export", {}, "璁惧淇濆吇.xlsx");
+ proxy.download('/device/maintenance/export', {}, '璁惧淇濆吇.xlsx')
})
.catch(() => {
- ElMessage.info("宸插彇娑�");
- });
-};
+ 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 fetchMaintenanceTaskFiles = async (deviceMaintenanceId) => {
+ try {
+ const params = {
+ current: 1,
+ size: 100,
+ deviceMaintenanceId,
+ rulesRegulationsManagementId:deviceMaintenanceId
+ }
+ const res = await listMaintenanceTaskFiles(params)
+ const records = res?.data?.records || []
+ const mapped = records.map(item => ({
+ id: item.id,
+ name: item.fileName || item.name,
+ url: item.fileUrl || item.url,
+ raw: item,
+ }))
+ fileListDialogRef.value?.setList(mapped)
+ } catch (error) {
+ ElMessage.error('鑾峰彇闄勪欢鍒楄〃澶辫触')
+ }
+}
+
+// 鎵撳紑闄勪欢寮圭獥
+const openFileDialog = async (row) => {
+ currentMaintenanceTaskId.value = row.id
+ fileDialogVisible.value = true
+ await fetchMaintenanceTaskFiles(row.id)
+}
+
+// 鍒锋柊闄勪欢鍒楄〃
+const refreshFileList = async () => {
+ if (!currentMaintenanceTaskId.value) return
+ await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value)
+}
+
+// 涓婁紶闄勪欢
+const handleAttachmentUpload = async (filePayload) => {
+ if (!currentMaintenanceTaskId.value) return
+ try {
+ const payload = {
+ name: filePayload?.fileName || filePayload?.name,
+ url: filePayload?.fileUrl || filePayload?.url,
+ deviceMaintenanceId: currentMaintenanceTaskId.value,
+ }
+ await addMaintenanceTaskFile(payload)
+ ElMessage.success('鏂囦欢涓婁紶鎴愬姛')
+ await refreshFileList()
+ } catch (error) {
+ ElMessage.error('鏂囦欢涓婁紶澶辫触')
+ }
+}
+
+// 鍒犻櫎闄勪欢
+const handleAttachmentDelete = async (row) => {
+ if (!row?.id) return false
+ try {
+ await ElMessageBox.confirm('纭鍒犻櫎璇ラ檮浠讹紵', '鎻愮ず', { type: 'warning' })
+ } catch {
+ return false
+ }
+ try {
+ await delMaintenanceTaskFile(row.id)
+ ElMessage.success('鍒犻櫎鎴愬姛')
+ await refreshFileList()
+ return true
+ } catch (error) {
+ ElMessage.error('鍒犻櫎澶辫触')
+ return false
+ }
+}
onMounted(() => {
- getTableData();
-});
+ // 鏍规嵁榛樿婵�娲荤殑 Tab 璋冪敤瀵瑰簲鐨勬煡璇㈡帴鍙�
+ if (activeTab.value === 'scheduled') {
+ getScheduledTableData()
+ } else {
+ getTableData()
+ }
+})
</script>
<style lang="scss" scoped>
@@ -307,3 +714,8 @@
margin-bottom: 10px;
}
</style>
+
+
+
+
+
--
Gitblit v1.9.3