From c8db4a7e7360c5197b6c709a79e53962879dc28f Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 25 Jun 2026 16:24:16 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=82=B9?= =?UTF-8?q?=E6=A3=80=E4=BB=BB=E5=8A=A1-=E6=B7=BB=E5=8A=A0=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E9=A1=B9=E7=9B=AE=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/mes/taskManagement.js | 17 + src/locales/en-US.js | 16 +- src/locales/zh-CN.js | 16 +- .../pages/equipmentInspectionTasks/detail.vue | 102 +++++- .../pages/equipmentInspectionTasks/index.vue | 326 +++++++++++++----- .../pages/equipmentMaintenance/index.vue | 9 +- 6 files changed, 376 insertions(+), 110 deletions(-) diff --git a/src/api/mes/taskManagement.js b/src/api/mes/taskManagement.js index 94b4d89..3e9210c 100644 --- a/src/api/mes/taskManagement.js +++ b/src/api/mes/taskManagement.js @@ -15,3 +15,20 @@ export function createTaskManagementTicket(id) { params: { id } }) } + + +export function getPlanMaintenancePage(params = {}) { + return request({ + url: '/admin-api/mes/plan-maintenance/page', + method: 'get', + params + }) +} + +export function getPlanMaintenanceSubjectList(id) { + return request({ + url: '/admin-api/mes/plan-maintenance/getSubjectList', + method: 'get', + params: { id } + }) +} diff --git a/src/locales/en-US.js b/src/locales/en-US.js index 4130779..991503e 100644 --- a/src/locales/en-US.js +++ b/src/locales/en-US.js @@ -526,7 +526,21 @@ export default { empty: 'No equipment inspection tasks', createTicketSuccess: 'Work order created successfully', createTicketFail: 'Work order creation failed', - lineFilter: 'Line', }, + lineFilter: 'Line', moreFilter: 'More Filters', + filterScope: 'Filter Scope', + placeholderProjectForm: 'Select inspection template', + placeholderDeviceList: 'Select equipment', + selectedCount: '{count} selected', + noPlanData: 'No inspection templates', + noDeviceData: 'No equipment data', + confirmCreateTicketContent: 'Create a work order from \"{name}\"?', + subjectListTitle: 'Template Items', + noSubjectData: 'No template items', + subjectCode: 'Item Code', + subjectName: 'Item Name', + inspectionMethod: 'Inspection Method', + judgmentCriteria: 'Criteria', + }, equipmentInspectionRecord: { moduleName: 'Equipment Inspection Records', subTitle: 'Equipment inspection record list', diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js index b877cbb..238e22a 100644 --- a/src/locales/zh-CN.js +++ b/src/locales/zh-CN.js @@ -526,7 +526,21 @@ export default { empty: '暂无设备点检任务数据', createTicketSuccess: '工单创建成功', createTicketFail: '工单创建失败', - lineFilter: '产线', }, + lineFilter: '产线', moreFilter: '更多筛选', + filterScope: '筛选范围', + placeholderProjectForm: '请选择点检模板', + placeholderDeviceList: '请选择设备', + selectedCount: '已选择 {count} 项', + noPlanData: '暂无点检模板', + noDeviceData: '暂无设备数据', + confirmCreateTicketContent: '确认根据\"{name}\"新增工单吗?', + subjectListTitle: '模板项目', + noSubjectData: '暂无模板项目', + subjectCode: '项目编码', + subjectName: '项目名称', + inspectionMethod: '点检方式', + judgmentCriteria: '判定标准', + }, equipmentInspectionRecord: { moduleName: '设备点检记录', subTitle: '设备点检记录查询', diff --git a/src/pages_function/pages/equipmentInspectionTasks/detail.vue b/src/pages_function/pages/equipmentInspectionTasks/detail.vue index bc49eee..6e0659f 100644 --- a/src/pages_function/pages/equipmentInspectionTasks/detail.vue +++ b/src/pages_function/pages/equipmentInspectionTasks/detail.vue @@ -53,6 +53,35 @@ {{ formatDateTime(detailData.updateTime) }} + + + {{ t('equipmentInspectionTasks.subjectListTitle') }} + {{ t('functionCommon.loading') }} + {{ t('equipmentInspectionTasks.noSubjectData') }} + + + {{ index + 1 }} + + + {{ t('equipmentInspectionTasks.subjectCode') }} + {{ textValue(item.subjectCode) }} + + + {{ t('equipmentInspectionTasks.subjectName') }} + {{ textValue(item.subjectName) }} + + + {{ t('equipmentInspectionTasks.inspectionMethod') }} + {{ inspectionMethodText(item.inspectionMethod) }} + + + {{ t('equipmentInspectionTasks.judgmentCriteria') }} + {{ textValue(item.judgmentCriteria) }} + + + + + @@ -69,13 +98,16 @@ import { computed, reactive, ref } from 'vue' import { onLoad } from '@dcloudio/uni-app' import { useI18n } from 'vue-i18n' import NavBar from '@/components/common/NavBar.vue' -import { createTaskManagementTicket } from '@/api/mes/taskManagement' +import { createTaskManagementTicket, getPlanMaintenanceSubjectList } from '@/api/mes/taskManagement' import { getDeviceLedgerList } from '@/api/mes/deviceLedger' +import { DICT_TYPE, getDictLabel, initAllDict } from '@/utils/dict' const { t } = useI18n() const detailData = reactive({}) const ticketLoading = ref(false) const deviceOptions = ref([]) +const subjectList = ref([]) +const subjectLoading = ref(false) const taskTypeText = computed(() => { const normalized = Number(detailData.taskType) if (normalized === 1) return t('equipmentInspectionTasks.taskTypeInspect') @@ -120,6 +152,38 @@ function parseIdsValue(value) { return String(value).split(',').map((item) => item.trim()).filter(Boolean) } +function firstIdValue(value) { + return parseIdsValue(value)[0] || '' +} + +function inspectionMethodText(value) { + return getDictLabel(DICT_TYPE.INSPECTION_METHOD, value, textValue(value)) +} + +function normalizeListData(res) { + const root = res && res.data !== undefined ? res.data : res + const data = Array.isArray(root) ? root : (root?.list || root?.data?.list || root?.records || root?.data || []) + return Array.isArray(data) ? data : [] +} + +async function loadSubjectList() { + const planId = firstIdValue(detailData.projectForm) + if (!planId) { + subjectList.value = [] + return + } + subjectLoading.value = true + try { + const res = await getPlanMaintenanceSubjectList(planId) + subjectList.value = normalizeListData(res) + } catch (error) { + subjectList.value = [] + uni.showToast({ title: t('functionCommon.loadFailed'), icon: 'none' }) + } finally { + subjectLoading.value = false + } +} + onLoad(async () => { try { const cached = uni.getStorageSync('equipmentInspectionTasksDetail') @@ -127,22 +191,30 @@ onLoad(async () => { Object.assign(detailData, JSON.parse(cached)) uni.removeStorageSync('equipmentInspectionTasksDetail') } - await Promise.all([ensureDeviceOptionsLoaded()]) + await initAllDict() + await Promise.all([ensureDeviceOptionsLoaded(), loadSubjectList()]) } catch (error) { } }) async function handleCreateTicket() { if (!detailData.id || ticketLoading.value) return - ticketLoading.value = true - try { - await createTaskManagementTicket(detailData.id) - uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' }) - } catch (error) { - uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' }) - } finally { - ticketLoading.value = false - } + uni.showModal({ + title: t('functionCommon.confirmTitle'), + content: t('equipmentInspectionTasks.confirmCreateTicketContent', { name: textValue(detailData.name) }), + success: async (res) => { + if (!res.confirm) return + ticketLoading.value = true + try { + await createTaskManagementTicket(detailData.id) + uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' }) + } catch (error) { + uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' }) + } finally { + ticketLoading.value = false + } + } + }) } function isEnabled(value) { @@ -219,4 +291,12 @@ function formatDateTime(value) { .action-btn-disabled { background: #94a3b8; } +.hint { text-align: center; color: #909399; padding: 24rpx 0; font-size: 26rpx; } +.subject-list { display: flex; flex-direction: column; gap: 16rpx; } +.subject-card { display: flex; background: #f7f9fc; border-radius: 14rpx; padding: 20rpx; gap: 16rpx; } +.subject-index { min-width: 48rpx; height: 48rpx; border-radius: 10rpx; background: #1a3a5c; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 24rpx; font-weight: 700; } +.subject-body { flex: 1; display: flex; flex-direction: column; gap: 8rpx; } +.subject-row { display: flex; justify-content: space-between; align-items: center; } +.subject-label { font-size: 24rpx; color: #8a9099; } +.subject-value { font-size: 26rpx; color: #30363d; max-width: 60%; text-align: right; } diff --git a/src/pages_function/pages/equipmentInspectionTasks/index.vue b/src/pages_function/pages/equipmentInspectionTasks/index.vue index cab54c0..64dfa73 100644 --- a/src/pages_function/pages/equipmentInspectionTasks/index.vue +++ b/src/pages_function/pages/equipmentInspectionTasks/index.vue @@ -3,28 +3,37 @@ - - {{ selectedLineLabel }} - - - - + + + {{ selectedLineLabel }} + + + + + {{ currentTaskTypeLabel }} + + + - - - {{ currentTaskTypeLabel }} - + + + + + + + + + - - {{ t('functionCommon.reset') }} + @@ -63,6 +72,60 @@ + + + + + {{ t('equipmentInspectionTasks.moreFilter') }} + + + + + {{ t('equipmentInspectionTasks.filterScope') }} + + + {{ t('equipmentInspectionTasks.projectFormName') }} + + {{ selectedPlanLabel }} + + + + + {{ option.name }} + + + {{ t('equipmentInspectionTasks.noPlanData') }} + + + + {{ t('equipmentInspectionTasks.deviceList') }} + + {{ selectedDeviceLabel }} + + + + + {{ option.label }} + + + {{ t('equipmentInspectionTasks.noDeviceData') }} + + + + + + {{ t('functionCommon.reset') }} + {{ t('functionCommon.confirm') }} + + + + { let searchTimer = null const taskTypeOptions = computed(() => [ - { label: t('functionCommon.all'), value: '' }, { label: t('equipmentInspectionTasks.taskTypeInspect'), value: '1' }, { label: t('equipmentInspectionTasks.taskTypeMaintain'), value: '2' } ]) @@ -141,13 +209,28 @@ const taskTypeIndex = computed(() => { return index >= 0 ? index : 0 }) const currentTaskTypeLabel = computed(() => { + if (selectedTaskType.value === '') return t('equipmentInspectionTasks.taskType') const current = taskTypeOptions.value.find((item) => item.value === selectedTaskType.value) - return current ? current.label : t('functionCommon.all') + return current ? current.label : t('equipmentInspectionTasks.taskType') }) +const drawerPlanOptions = computed(() => planOptions.value.map((item) => ({ + id: String(item.id), + name: item.planName || item.name || String(item.id || '') +}))) + +const drawerDeviceOptions = computed(() => deviceOptions.value.map((item) => ({ + id: String(item.id), + label: item.label || item.deviceName || String(item.id || '') +}))) + +const selectedPlanLabel = computed(() => formatSelectedSummary(selectedPlanIds.value, drawerPlanOptions.value, 'name', t('equipmentInspectionTasks.placeholderProjectForm'))) +const selectedDeviceLabel = computed(() => formatSelectedSummary(selectedDeviceIds.value, drawerDeviceOptions.value, 'label', t('equipmentInspectionTasks.placeholderDeviceList'))) + onLoad(async () => { activateKeywordFocus() - await Promise.all([loadLineTree(), ensureDeviceOptionsLoaded(), fetchList(true)]) + await Promise.all([loadLineTree(), ensurePlanOptionsLoaded(), ensureDeviceOptionsLoaded()]) + await fetchList(true) }) onShow(() => { @@ -168,6 +251,17 @@ onReachBottom(() => { loadMore() }) +async function ensurePlanOptionsLoaded() { + try { + const res = await getPlanMaintenancePage({ pageNo: 1, pageSize: 100 }) + const root = res && res.data !== undefined ? res.data : res + const data = Array.isArray(root) ? root : (root?.list || root?.data?.list || root?.records || []) + planOptions.value = (Array.isArray(data) ? data : []).filter((item) => item && item.id !== undefined && item.id !== null) + } catch (error) { + planOptions.value = [] + } +} + async function ensureDeviceOptionsLoaded() { try { const res = await getDeviceLedgerList() @@ -205,8 +299,9 @@ async function fetchList(reset) { pageNo: pageNo.value, pageSize: pageSize.value, name: deviceId ? undefined : keyword || undefined, - deviceIds: deviceId ? [deviceId] : undefined, + deviceIds: selectedDeviceIds.value.length ? selectedDeviceIds.value.join(',') : (deviceId ? [deviceId] : undefined), taskType: selectedTaskType.value || undefined, + projectForm: selectedPlanIds.value.length ? selectedPlanIds.value.join(',') : undefined, deviceLineId: selectedLineId.value || undefined } const res = await getTaskManagementPage(params) @@ -307,6 +402,56 @@ function normalizePageData(res) { } } +function openFilterDrawer() { + filterPopupRef.value?.open() +} + +function closeFilterDrawer() { + filterPopupRef.value?.close() +} + +async function confirmFilterDrawer() { + planPanelOpen.value = false + devicePanelOpen.value = false + closeFilterDrawer() + await fetchList(true) +} + +function togglePlanPanel() { + planPanelOpen.value = !planPanelOpen.value + devicePanelOpen.value = false +} + +function toggleDevicePanel() { + devicePanelOpen.value = !devicePanelOpen.value + planPanelOpen.value = false +} + +function togglePlanOption(option) { + toggleStringSelection(selectedPlanIds, option?.id) +} + +function toggleDeviceOption(option) { + toggleStringSelection(selectedDeviceIds, option?.id) +} + +function toggleStringSelection(targetRef, value) { + const id = String(value ?? '') + if (!id) return + const current = targetRef.value.map((item) => String(item)) + targetRef.value = current.includes(id) ? current.filter((item) => item !== id) : [...current, id] +} + +function formatSelectedSummary(ids, options, labelKey, placeholder) { + const selected = Array.isArray(ids) ? ids : [] + if (!selected.length) return placeholder + if (selected.length === 1) { + const found = options.find((item) => String(item.id) === String(selected[0])) + return found?.[labelKey] || placeholder + } + return t('equipmentInspectionTasks.selectedCount', { count: selected.length }) +} + function handleSearch() { clearSearchTimer() uni.hideKeyboard() @@ -324,6 +469,11 @@ async function resetFilters() { clearSearchTimer() searchKeyword.value = '' selectedTaskType.value = '' + selectedPlanIds.value = [] + selectedDeviceIds.value = [] + planPanelOpen.value = false + devicePanelOpen.value = false + closeFilterDrawer() resetLineFilter() activateKeywordFocus() await nextTick() @@ -355,15 +505,22 @@ function openDetail(item) { async function handleCreateTicket(item) { if (!item?.id || ticketLoadingId.value) return - ticketLoadingId.value = item.id - try { - await createTaskManagementTicket(item.id) - uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' }) - } catch (error) { - uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' }) - } finally { - ticketLoadingId.value = null - } + uni.showModal({ + title: t('functionCommon.confirmTitle'), + content: t('equipmentInspectionTasks.confirmCreateTicketContent', { name: textValue(item.name) }), + success: async (res) => { + if (!res.confirm) return + ticketLoadingId.value = item.id + try { + await createTaskManagementTicket(item.id) + uni.showToast({ title: t('equipmentInspectionTasks.createTicketSuccess'), icon: 'success' }) + } catch (error) { + uni.showToast({ title: t('equipmentInspectionTasks.createTicketFail'), icon: 'none' }) + } finally { + ticketLoadingId.value = null + } + } + }) } function onScroll(event) { @@ -446,65 +603,50 @@ function formatDate(value) {