| | |
| | | // æ·»å 设å¤ä¿å
»å®æ¶ä»»å¡ |
| | | export const deviceMaintenanceTaskAdd = (params) => { |
| | | return request({ |
| | | url: '/deviceMaintenanceTask/add', |
| | | url: "/deviceMaintenanceTask/add", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | |
| | | // ä¿®æ¹è®¾å¤ä¿å
»å®æ¶ä»»å¡ |
| | | export const deviceMaintenanceTaskEdit = (params) => { |
| | | return request({ |
| | | url: '/deviceMaintenanceTask/update', |
| | | url: "/deviceMaintenanceTask/update", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | |
| | | // 设å¤ä¿å
»å®æ¶ä»»å¡å表 |
| | | export const deviceMaintenanceTaskList = (params) => { |
| | | return request({ |
| | | url: '/deviceMaintenanceTask/listPage', |
| | | url: "/deviceMaintenanceTask/listPage", |
| | | method: "get", |
| | | params: params, |
| | | }); |
| | |
| | | // 设å¤ä¿å
»å®æ¶ä»»å¡å表 |
| | | 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", |
| | | }); |
| | | }; |
| | |
| | | // å·¡æ£ç®¡ç |
| | | 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 |
| | | }) |
| | | } |
| | | 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" }); |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| | |
| | | <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="å£åº¦" 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é¢ççåæ¾ï¼å°frequencyDetailæå为weekåtime |
| | | 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 = '' |
| | | } |
| | | |
| | | // 妿æè®¾å¤IDï¼èªå¨è®¾ç½®è®¾å¤ä¿¡æ¯ |
| | | 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() |
| | | } |
| | | // éç½®è¡¨åæ°æ®ç¡®ä¿è®¾å¤ä¿¡æ¯æ£ç¡®éç½® |
| | | 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> |
| | | .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> |
| | |
| | | <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> |
| | |
| | | </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">æ£å¸¸</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> |
| | |
| | | </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> |
| | |
| | | </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="设å¤è¿è¡æ£å¸¸" |
| | | :sub-title="operationType === 'view' ? '' : 'æ éä¸ä¼ ç
§ç'" /> |
| | | <el-result |
| | | v-if="hasException === false" |
| | | icon="success" |
| | | title="设å¤è¿è¡æ£å¸¸" |
| | | :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: "å£åº¦", |
| | | }; |
| | | 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: "å£åº¦", |
| | | }; |
| | | 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> |
| | |
| | | <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" |
| | | ? "å£åº¦" |
| | | : ""; |
| | | }, |
| | | { |
| | | prop: "frequencyType", |
| | | label: "颿¬¡", |
| | | minWidth: 120, |
| | | formatData: params => { |
| | | return params === "DAILY" |
| | | ? "æ¯æ¥" |
| | | : params === "WEEKLY" |
| | | ? "æ¯å¨" |
| | | : params === "MONTHLY" |
| | | ? "æ¯æ" |
| | | : params === "QUARTERLY" |
| | | ? "å£åº¦" |
| | | : ""; |
| | | }, |
| | | }, |
| | | { |
| | | 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: "卿¥", |
| | | }; |
| | | // ä½¿ç¨æ£å䏿¬¡æ§æ¿æ¢ææå¹é
项 |
| | | 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: "卿¥", |
| | | }; |
| | | // ä½¿ç¨æ£å䏿¬¡æ§æ¿æ¢ææå¹é
项 |
| | | 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 ? "æ£å¸¸" : "å¼å¸¸"; |
| | | // }, |
| | | // 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: "å£åº¦", |
| | | }[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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | </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(); |
| | | // ä¿å计åä¿å
»è®°å½çid |
| | | const planId = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | // ä¿å计åä¿å
»è®°å½çid |
| | | 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; // ä¿å计åä¿å
»è®°å½çid |
| | | visible.value = true; |
| | | await nextTick(); |
| | | fetchSparePartOptions(); |
| | | setForm(row); |
| | | }; |
| | | const open = async (id, row) => { |
| | | planId.value = id; // ä¿å计åä¿å
»è®°å½çid |
| | | 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> |
| | |
| | | <FormDialog |
| | | v-model="visible" |
| | | :title="id ? 'ç¼è¾è®¾å¤ä¿å
»è®¡å' : 'æ°å¢è®¾å¤ä¿å
»è®¡å'" |
| | | width="500px" |
| | | width="960px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose" |
| | |
| | | </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 |
| | |
| | | </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 |
| | |
| | | </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: "设å¤ä¿å
»æ°å¢è®¡å", |
| | |
| | | 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; |
| | |
| | | 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(); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | |
| | | */ |
| | | 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 || []; |
| | | }; |
| | |
| | | }; |
| | | |
| | | 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 |
| | |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | itemSelectorVisible.value = false; |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | itemSelectorVisible.value = false; |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | |
| | | const openModal = () => { |
| | | id.value = undefined; |
| | | visible.value = true; |
| | | maintenanceItemOptions.value = []; |
| | | }; |
| | | |
| | | defineExpose({ |
| | |
| | | }); |
| | | </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> |
| | |
| | | <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> |
| | |
| | | <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: "å£åº¦", |
| | | }; |
| | | return map[type] || "--"; |
| | | const map = { |
| | | DAILY: "æ¯æ¥", |
| | | WEEKLY: "æ¯å¨", |
| | | MONTHLY: "æ¯æ", |
| | | QUARTERLY: "å£åº¦", |
| | | }; |
| | | 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> |
| | |
| | | <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="å£åº¦" 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="å£åº¦" 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; |
| | | |
| | | // 妿æè®¾å¤IDï¼èªå¨è®¾ç½®è®¾å¤ä¿¡æ¯ |
| | | 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; |
| | | } |
| | | |
| | | // 妿æè®¾å¤IDï¼èªå¨è®¾ç½®è®¾å¤ä¿¡æ¯ |
| | | 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() |
| | | } |
| | | // éç½®è¡¨åæ°æ®ç¡®ä¿è®¾å¤ä¿¡æ¯æ£ç¡®éç½® |
| | | 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(); |
| | | } |
| | | // éç½®è¡¨åæ°æ®ç¡®ä¿è®¾å¤ä¿¡æ¯æ£ç¡®éç½® |
| | | 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 } |
| | | // ä¸åååç«¯ä¼ ä¿å
»äººå段ï¼ä»
ä½¿ç¨æ¥å£è¦æ±ç 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, |
| | | })); |
| | | // ä¸åååç«¯ä¼ ä¿å
»äººå段ï¼ä»
ä½¿ç¨æ¥å£è¦æ±ç 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> |
| | |
| | | <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" |
| | |
| | | > |
| | | æ°å¢ä¿å
» |
| | | </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: "å£åº¦", |
| | | }[cell] || ""), |
| | | }, |
| | | { |
| | | prop: "frequencyDetail", |
| | | label: "å¼å§æ¥æä¸æ¶é´", |
| | | minWidth: 130, |
| | | // åæ ·æ¹ç¨ formatDataï¼PIMTable å
é¨ä¼æåå
æ ¼å¼ä¼ è¿æ¥ |
| | | formatData: cell => { |
| | | if (typeof cell !== "string") return ""; |
| | | let val = cell; |
| | | const replacements = { |
| | | MON: "å¨ä¸", |
| | | TUE: "å¨äº", |
| | | WED: "å¨ä¸", |
| | | THU: "å¨å", |
| | | FRI: "å¨äº", |
| | | SAT: "å¨å
", |
| | | SUN: "卿¥", |
| | | }; |
| | | // ä½¿ç¨æ£å䏿¬¡æ§æ¿æ¢ææå¹é
项 |
| | | 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: "å£åº¦", |
| | | }[cell] || ""), |
| | | }, |
| | | { |
| | | prop: "frequencyDetail", |
| | | label: "å¼å§æ¥æä¸æ¶é´", |
| | | minWidth: 130, |
| | | // åæ ·æ¹ç¨ formatDataï¼PIMTable å
é¨ä¼æåå
æ ¼å¼ä¼ è¿æ¥ |
| | | 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("è·å宿¶ä»»å¡å表失败"); |
| | | // ä½¿ç¨æ£å䏿¬¡æ§æ¿æ¢ææå¹é
项 |
| | | 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> |
| | | |
| | | |
| | | |
| | | |
| | | |