Merge remote-tracking branch 'origin/master'

master
zhongwenkai 6 days ago
commit 3a848c6a3a

4213
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -9,6 +9,14 @@ export function getMoldRepairPage(params = {}) {
})
}
export function getMoldRepairList(params = {}) {
return request({
url: '/admin-api/mes/mold-repair/list',
method: 'get',
params
})
}
export function getMoldRepair(id) {
return request({
url: '/admin-api/mes/mold-repair/get',
@ -64,4 +72,4 @@ export function uploadRepairImage(filePath, name = 'file') {
filePath,
showLoading: false
})
}
}

@ -916,12 +916,27 @@ export default {
maintainHistory: 'Maintenance',
repairHistory: 'Repair',
operator: 'Operator',
inspectionMethod: 'Inspection Method',
criteria: 'Criteria',
inspectionTime: 'Inspection Time',
maintainMethod: 'Maintenance Method',
maintainTime: 'Maintenance Time',
repairName: 'Repair Order Name',
faultPhenomenon: 'Fault Phenomenon',
faultDescription: 'Fault Description',
replacementParts: 'Replacement Parts',
repairContent: 'Repair Content',
finishDate: 'Finish Date',
faultImages: 'Fault Images',
repairedImages: 'After-repair Images',
noHistoryData: 'No history data',
resultPending: 'Pending',
resultPass: 'Pass',
resultFail: 'Fail',
repairPending: 'Pending',
repairProcessing: 'Processing',
repairCompleted: 'Completed'
repairCompleted: 'Completed',
repairAbnormal: 'Abnormal'
},
equipmentMaintenance: {
moduleName: 'Equipment Repair',
@ -1302,6 +1317,8 @@ export default {
mold: 'Mold',
moldCode: 'Mold Code',
moldName: 'Mold Name',
specModel: 'Spec Model',
brand: 'Brand',
faultLevel: 'Fault Level',
isShutdown: 'Is Shutdown',
status: 'Status',
@ -1328,6 +1345,8 @@ export default {
statusPending: 'Pending',
statusPassed: 'Passed',
statusRejected: 'Rejected',
orderStatusPending: 'Pending',
orderStatusDone: 'Completed',
placeholderRepairCode: 'Enter repair code',
placeholderRepairName: 'Enter repair name',
placeholderRequireDate: 'Select require date',

@ -919,12 +919,27 @@ export default {
maintainHistory: '保养记录',
repairHistory: '报修记录',
operator: '操作人',
inspectionMethod: '点检方式',
criteria: '判定标准',
inspectionTime: '点检时间',
maintainMethod: '保养方式',
maintainTime: '保养时间',
repairName: '维修单名称',
faultPhenomenon: '故障现象',
faultDescription: '故障描述',
replacementParts: '更换配件',
repairContent: '维修内容',
finishDate: '完成日期',
faultImages: '故障图片',
repairedImages: '维修后图片',
noHistoryData: '暂无历史记录',
resultPending: '待处理',
resultPass: '合格',
resultFail: '不合格',
repairPending: '待处理',
repairProcessing: '处理中',
repairCompleted: '已完成'
repairCompleted: '已完成',
repairAbnormal: '异常'
},
equipmentMaintenance: {
moduleName: '设备维修',
@ -1305,6 +1320,8 @@ export default {
mold: '模具',
moldCode: '模具编码',
moldName: '模具名称',
specModel: '规格型号',
brand: '品牌',
faultLevel: '故障等级',
isShutdown: '是否停机',
status: '单据状态',
@ -1331,6 +1348,8 @@ export default {
statusPending: '待维修',
statusPassed: '通过',
statusRejected: '不通过',
orderStatusPending: '待处理',
orderStatusDone: '已完成',
placeholderRepairCode: '请输入维修单编号',
placeholderRepairName: '请输入维修单名称',
placeholderRequireDate: '请选择报修日期',

@ -94,59 +94,119 @@
</view>
<!-- 历史记录Tabs -->
<view class="info-card">
<view class="tab-bar">
<view
v-for="tab in tabs"
:key="tab.key"
:class="['tab-item', activeTab === tab.key ? 'active' : '']"
@click="switchTab(tab.key)"
>
<text class="tab-text">{{ tab.label }}</text>
</view>
<view class="tab-card">
<view class="tabs-wrap">
<u-tabs
activeColor="#2463eb"
:list="tabList"
:current="currentTab"
:is-scroll="false"
@change="handleTabChange"
/>
</view>
<!-- 点检历史 -->
<view v-if="activeTab === 'check'" class="tab-content">
<view v-if="!inspectionList.length" class="empty-tip">{{ t('equipmentLedger.noHistoryData') }}</view>
<view v-for="(item, idx) in inspectionList" :key="idx" class="history-item">
<view class="history-header">
<text class="history-time">{{ formatDateTime(item.inspectionTime) }}</text>
<text :class="['history-result', getResultClass(item.inspectionResult)]">{{ getResultText(item.inspectionResult) }}</text>
<view v-if="currentTab === 0">
<view v-if="!inspectionGroups.length" class="hint">{{ t('equipmentLedger.noHistoryData') }}</view>
<view v-for="group in inspectionGroups" :key="group.key" class="record-card">
<view class="timeline-meta">
<text class="timeline-time">{{ group.time }}</text>
<text class="timeline-operator">{{ group.operator }}</text>
</view>
<view class="history-body">
<text class="history-name">{{ item.inspectionItemName || item.name || '-' }}</text>
<text class="history-operator">{{ t('equipmentLedger.operator') }}: {{ item.operatorName || item.inspectorName || '-' }}</text>
<view v-for="item in group.items" :key="item.key" class="history-item">
<view class="history-title-row">
<text class="history-item-name">{{ item.name }}</text>
<text class="result-badge" :class="`result-${item.resultType}`">{{ item.resultLabel }}</text>
</view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.inspectionMethod') }}</text><text class="record-value">{{ textValue(item.method) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.criteria') }}</text><text class="record-value">{{ textValue(item.criteria) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.inspectionTime') }}</text><text class="record-value">{{ textValue(item.taskTimeLabel) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.remark') }}</text><text class="record-value">{{ textValue(item.remark) }}</text></view>
<view v-if="item.images.length" class="history-images">
<image
v-for="img in item.images"
:key="img"
class="history-image"
:src="img"
mode="aspectFill"
@click="previewImages(item.images, img)"
/>
</view>
</view>
</view>
</view>
<!-- 保养历史 -->
<view v-if="activeTab === 'maintain'" class="tab-content">
<view v-if="!maintainList.length" class="empty-tip">{{ t('equipmentLedger.noHistoryData') }}</view>
<view v-for="(item, idx) in maintainList" :key="idx" class="history-item">
<view class="history-header">
<text class="history-time">{{ formatDateTime(item.maintainTime || item.inspectionTime) }}</text>
<text :class="['history-result', getResultClass(item.maintainResult || item.inspectionResult)]">{{ getResultText(item.maintainResult || item.inspectionResult) }}</text>
<view v-else-if="currentTab === 1">
<view v-if="!maintainGroups.length" class="hint">{{ t('equipmentLedger.noHistoryData') }}</view>
<view v-for="group in maintainGroups" :key="group.key" class="record-card">
<view class="timeline-meta">
<text class="timeline-time">{{ group.time }}</text>
<text class="timeline-operator">{{ group.operator }}</text>
</view>
<view class="history-body">
<text class="history-name">{{ item.maintainItemName || item.inspectionItemName || item.name || '-' }}</text>
<text class="history-operator">{{ t('equipmentLedger.operator') }}: {{ item.operatorName || item.inspectorName || '-' }}</text>
<view v-for="item in group.items" :key="item.key" class="history-item">
<view class="history-title-row">
<text class="history-item-name">{{ item.name }}</text>
<text class="result-badge" :class="`result-${item.resultType}`">{{ item.resultLabel }}</text>
</view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.maintainMethod') }}</text><text class="record-value">{{ textValue(item.method) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.criteria') }}</text><text class="record-value">{{ textValue(item.criteria) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.maintainTime') }}</text><text class="record-value">{{ textValue(item.taskTimeLabel) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.remark') }}</text><text class="record-value">{{ textValue(item.remark) }}</text></view>
<view v-if="item.images.length" class="history-images">
<image
v-for="img in item.images"
:key="img"
class="history-image"
:src="img"
mode="aspectFill"
@click="previewImages(item.images, img)"
/>
</view>
</view>
</view>
</view>
<!-- 报修历史 -->
<view v-if="activeTab === 'repair'" class="tab-content">
<view v-if="!repairList.length" class="empty-tip">{{ t('equipmentLedger.noHistoryData') }}</view>
<view v-for="(item, idx) in repairList" :key="idx" class="history-item">
<view class="history-header">
<text class="history-time">{{ formatDateTime(item.createTime) }}</text>
<text :class="['history-result', getRepairStatusClass(item.status)]">{{ getRepairStatusText(item.status) }}</text>
<view v-else-if="currentTab === 2">
<view v-if="!repairRecords.length" class="hint">{{ t('equipmentLedger.noHistoryData') }}</view>
<view v-for="row in repairRecords" :key="row.key" class="record-card">
<view class="record-head">
<text class="record-title">{{ textValue(row.repairCode || row.repairName) }}</text>
<text class="result-badge" :class="`result-${row.resultType}`">{{ row.resultLabel }}</text>
</view>
<view class="history-body">
<text class="history-name">{{ item.repairNo || item.description || '-' }}</text>
<text class="history-operator">{{ t('equipmentLedger.operator') }}: {{ item.creatorName || '-' }}</text>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.repairName') }}</text><text class="record-value">{{ textValue(row.repairName) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.faultPhenomenon') }}</text><text class="record-value">{{ textValue(row.faultPhenomenon) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.faultDescription') }}</text><text class="record-value">{{ textValue(row.faultDescription) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.replacementParts') }}</text><text class="record-value">{{ textValue(row.replacementParts) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.repairContent') }}</text><text class="record-value">{{ textValue(row.repairContent) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.finishDate') }}</text><text class="record-value">{{ textValue(row.finishDateLabel) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('equipmentLedger.remark') }}</text><text class="record-value">{{ textValue(row.remark) }}</text></view>
<view v-if="row.faultImageList.length" class="image-block">
<text class="image-title">{{ t('equipmentLedger.faultImages') }}</text>
<view class="history-images">
<image
v-for="img in row.faultImageList"
:key="img"
class="history-image"
:src="img"
mode="aspectFill"
@click="previewImages(row.faultImageList, img)"
/>
</view>
</view>
<view v-if="row.repairedImageList.length" class="image-block">
<text class="image-title">{{ t('equipmentLedger.repairedImages') }}</text>
<view class="history-images">
<image
v-for="img in row.repairedImageList"
:key="img"
class="history-image"
:src="img"
mode="aspectFill"
@click="previewImages(row.repairedImageList, img)"
/>
</view>
</view>
</view>
</view>
@ -172,16 +232,16 @@ const dictStore = useDictStore()
const detailId = ref(undefined)
const detailData = ref(null)
const deviceTypeList = ref([])
const activeTab = ref('check')
const currentTab = ref(0)
const inspectionList = ref([])
const maintainList = ref([])
const repairList = ref([])
const statusUpdating = ref(false)
const tabs = computed(() => [
{ key: 'check', label: t('equipmentLedger.checkHistory') },
{ key: 'maintain', label: t('equipmentLedger.maintainHistory') },
{ key: 'repair', label: t('equipmentLedger.repairHistory') }
const tabList = computed(() => [
{ name: t('equipmentLedger.checkHistory') },
{ name: t('equipmentLedger.maintainHistory') },
{ name: t('equipmentLedger.repairHistory') }
])
const statusOptions = computed(() => {
@ -198,6 +258,46 @@ const scheduledText = computed(() => {
return Number(val) === 1 ? t('equipmentLedger.yes') : t('equipmentLedger.no')
})
const inspectionGroups = computed(() =>
buildStepGroups(inspectionList.value, {
timeFieldCandidates: ['taskTime', 'inspectionTime', 'createTime'],
nameFieldCandidates: ['inspectionItemName', 'name', 'itemName'],
resultFieldCandidates: ['inspectionResult', 'result'],
methodFieldCandidates: ['inspectionMethod', 'method'],
criteriaFieldCandidates: ['judgmentCriteria', 'criteria'],
imagesFieldCandidates: ['images'],
remarkFieldCandidates: ['remark']
})
)
const maintainGroups = computed(() =>
buildStepGroups(maintainList.value, {
timeFieldCandidates: ['taskTime', 'maintainTime', 'inspectionTime', 'createTime'],
nameFieldCandidates: ['maintainItemName', 'inspectionItemName', 'name', 'itemName'],
resultFieldCandidates: ['maintainResult', 'inspectionResult', 'result'],
methodFieldCandidates: ['inspectionMethod', 'maintainMethod', 'method'],
criteriaFieldCandidates: ['judgmentCriteria', 'criteria'],
imagesFieldCandidates: ['images'],
remarkFieldCandidates: ['remark']
})
)
const repairRecords = computed(() => {
const rows = Array.isArray(repairList.value) ? repairList.value : []
return rows.map((row, index) => {
const resultMeta = formatRepairResult(row?.repairResult !== undefined ? row.repairResult : row?.result)
return {
...row,
key: String(row?.id ?? row?.repairCode ?? index),
finishDateLabel: formatDateTime(row?.finishDate || row?.createTime),
resultLabel: resultMeta.label,
resultType: resultMeta.type,
faultImageList: parseImages(row?.faultImages),
repairedImageList: parseImages(row?.repairedImages)
}
})
})
onLoad(async (query) => {
const id = query?.id ? decodeURIComponent(String(query.id)) : ''
detailId.value = id || undefined
@ -255,32 +355,43 @@ function normalizeDetail(res) {
return {}
}
function normalizeListData(res) {
const root = res && res.data !== undefined ? res.data : res
if (Array.isArray(root)) return root
if (Array.isArray(root?.data)) return root.data
if (Array.isArray(root?.list)) return root.list
if (Array.isArray(root?.rows)) return root.rows
if (Array.isArray(root?.records)) return root.records
if (Array.isArray(root?.data?.list)) return root.data.list
if (Array.isArray(root?.data?.rows)) return root.data.rows
if (Array.isArray(root?.data?.records)) return root.data.records
return []
}
async function fetchInspectionHistory() {
try {
const res = await request({ url: '/admin-api/mes/ticket-management/getInspectionByDeviceId', method: 'get', params: { deviceId: detailId.value } })
const data = res && res.data !== undefined ? res.data : res
inspectionList.value = Array.isArray(data) ? data : []
inspectionList.value = normalizeListData(res)
} catch (e) { inspectionList.value = [] }
}
async function fetchMaintainHistory() {
try {
const res = await request({ url: '/admin-api/mes/ticket-management/getMaintenanceByDeviceId', method: 'get', params: { deviceId: detailId.value } })
const data = res && res.data !== undefined ? res.data : res
maintainList.value = Array.isArray(data) ? data : []
maintainList.value = normalizeListData(res)
} catch (e) { maintainList.value = [] }
}
async function fetchRepairHistory() {
try {
const res = await request({ url: '/admin-api/mes/dv-repair/getRepairListByDeviceId', method: 'get', params: { deviceId: detailId.value } })
const data = res && res.data !== undefined ? res.data : res
repairList.value = Array.isArray(data) ? data : []
repairList.value = normalizeListData(res)
} catch (e) { repairList.value = [] }
}
function switchTab(key) {
activeTab.value = key
function handleTabChange(e) {
const idx = e && typeof e === 'object' ? e.index : e
currentTab.value = Number(idx === undefined ? 0 : idx)
}
function getStatusText(status) {
@ -321,32 +432,6 @@ async function onStatusChange(e) {
}
}
function getResultText(result) {
if (result === 'PASS' || result === 'pass' || result === 'OK' || result === 'ok' || result === 1 || result === '1') return t('equipmentLedger.resultPass')
if (result === 'FAIL' || result === 'fail' || result === 'NG' || result === 'ng' || result === 0 || result === '0') return t('equipmentLedger.resultFail')
return textValue(result)
}
function getResultClass(result) {
if (result === 'PASS' || result === 'pass' || result === 'OK' || result === 'ok' || result === 1 || result === '1') return 'text-success'
if (result === 'FAIL' || result === 'fail' || result === 'NG' || result === 'ng' || result === 0 || result === '0') return 'text-danger'
return ''
}
function getRepairStatusText(status) {
if (status === 0 || status === '0') return t('equipmentLedger.repairPending')
if (status === 1 || status === '1') return t('equipmentLedger.repairProcessing')
if (status === 2 || status === '2') return t('equipmentLedger.repairCompleted')
return textValue(status)
}
function getRepairStatusClass(status) {
if (status === 0 || status === '0') return 'text-warning'
if (status === 1 || status === '1') return 'text-primary'
if (status === 2 || status === '2') return 'text-success'
return ''
}
function fieldValue(field) {
return textValue(detailData.value ? detailData.value[field] : undefined)
}
@ -360,6 +445,77 @@ function textValue(value) {
return text || '-'
}
function parseImages(value) {
if (!value) return []
if (Array.isArray(value)) return value.map(String).filter(Boolean)
return String(value)
.replace(/[`'"]/g, '')
.split(',')
.map((item) => item.trim())
.filter(Boolean)
}
function pickFirst(obj, keys) {
for (const key of keys) {
if (obj && obj[key] !== undefined && obj[key] !== null && String(obj[key]).trim() !== '') {
return obj[key]
}
}
return undefined
}
function formatResult(value) {
const raw = value === null || value === undefined ? '' : String(value).trim()
const upper = raw.toUpperCase()
if (!raw) return { label: '-', type: 'info' }
if (raw === '0') return { label: t('equipmentLedger.resultPending'), type: 'info' }
if (raw === '1' || upper === 'OK' || upper === 'PASS') return { label: t('equipmentLedger.resultPass'), type: 'success' }
if (raw === '2' || upper === 'NG' || upper === 'FAIL') return { label: t('equipmentLedger.resultFail'), type: 'danger' }
return { label: raw, type: 'info' }
}
function formatRepairResult(value) {
const raw = value === null || value === undefined ? '' : String(value).trim()
if (raw === '1') return { label: t('equipmentLedger.repairCompleted'), type: 'success' }
if (raw === '2') return { label: t('equipmentLedger.repairAbnormal'), type: 'danger' }
if (raw === '0') return { label: t('equipmentLedger.repairProcessing'), type: 'warning' }
return { label: textValue(value), type: 'info' }
}
function buildStepGroups(rows, options) {
const groupsMap = new Map()
const list = Array.isArray(rows) ? rows : []
for (const row of list) {
const time = formatDateTime(pickFirst(row, options.timeFieldCandidates) || row?.createTime)
const operator = textValue(row?.operator || row?.operatorName || row?.inspectorName || row?.creatorName || row?.creator)
const groupKey = `${row?.managementId || ''}_${time}_${operator}`
const name = pickFirst(row, options.nameFieldCandidates) || '-'
const resultMeta = formatResult(pickFirst(row, options.resultFieldCandidates))
const item = {
key: String(row?.id ?? `${groupKey}_${name}`),
name: textValue(name),
resultLabel: resultMeta.label,
resultType: resultMeta.type,
method: pickFirst(row, options.methodFieldCandidates),
criteria: pickFirst(row, options.criteriaFieldCandidates),
remark: pickFirst(row, options.remarkFieldCandidates),
images: parseImages(pickFirst(row, options.imagesFieldCandidates)),
taskTimeLabel: formatDateTime(row?.taskTime || row?.maintainTime || row?.inspectionTime || row?.createTime)
}
if (!groupsMap.has(groupKey)) {
groupsMap.set(groupKey, { key: groupKey, time: time || '-', operator, items: [item] })
} else {
groupsMap.get(groupKey).items.push(item)
}
}
return Array.from(groupsMap.values())
}
function previewImages(list, current) {
if (!list || !list.length) return
uni.previewImage({ urls: list, current })
}
function formatDateValue(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) {
@ -417,19 +573,30 @@ function formatDateTime(value) {
.text-primary { color: #1a3a5c; }
.remark-row { border-bottom: none; }
.remark-value { white-space: pre-wrap; }
.tab-bar { display: flex; border-bottom: 2rpx solid #edf0f3; margin-bottom: 20rpx; }
.tab-item { flex: 1; text-align: center; padding: 16rpx 0; position: relative; }
.tab-text { font-size: 28rpx; color: #8a9099; }
.tab-item.active .tab-text { color: #1a3a5c; font-weight: 700; }
.tab-item.active::after { content: ''; position: absolute; bottom: -2rpx; left: 30%; right: 30%; height: 4rpx; background: #1a3a5c; border-radius: 2rpx; }
.tab-content { min-height: 200rpx; }
.empty-tip { text-align: center; padding: 40rpx 0; color: #99a1aa; font-size: 26rpx; }
.history-item { padding: 20rpx 0; border-bottom: 1rpx solid #f0f2f5; }
.history-item:last-child { border-bottom: none; }
.history-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10rpx; }
.history-time { font-size: 24rpx; color: #8a9099; }
.history-result { font-size: 26rpx; font-weight: 600; }
.history-body { display: flex; justify-content: space-between; align-items: center; }
.history-name { font-size: 28rpx; color: #30363d; }
.history-operator { font-size: 24rpx; color: #8a9099; }
.tab-card { margin-top: 20rpx; background: #ffffff; border-radius: 20rpx; padding: 28rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); }
.tabs-wrap { margin-bottom: 20rpx; }
.hint { padding: 40rpx 0; text-align: center; font-size: 28rpx; color: #94a3b8; }
.record-card { margin-bottom: 20rpx; padding: 24rpx; border-radius: 22rpx; background: linear-gradient(180deg, #ffffff 0%, #fbfcfe 100%); border: 1rpx solid #edf2f7; }
.record-head { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; margin-bottom: 16rpx; }
.record-title { flex: 1; min-width: 0; font-size: 30rpx; color: #1f2937; font-weight: 700; }
.record-label { font-size: 24rpx; color: #94a3b8; flex-shrink: 0; min-width: 150rpx; }
.record-value { flex: 1; font-size: 27rpx; color: #1f2937; font-weight: 500; line-height: 1.4; word-break: break-all; text-align: right; }
.record-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 20rpx; margin-bottom: 10rpx; }
.record-row:last-child { margin-bottom: 0; }
.timeline-meta { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; margin-bottom: 18rpx; }
.timeline-time { font-size: 28rpx; color: #1f4f81; font-weight: 700; }
.timeline-operator { font-size: 24rpx; color: #64748b; }
.history-item { padding: 20rpx; border-radius: 18rpx; background: #f8fbff; margin-bottom: 16rpx; }
.history-item:last-child { margin-bottom: 0; }
.history-title-row { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; margin-bottom: 12rpx; }
.history-item-name { flex: 1; min-width: 0; font-size: 28rpx; color: #1f2937; font-weight: 700; }
.result-badge { padding: 8rpx 18rpx; border-radius: 999rpx; font-size: 22rpx; font-weight: 600; }
.result-success { background: rgba(34, 197, 94, 0.12); color: #16a34a; }
.result-warning { background: rgba(245, 158, 11, 0.14); color: #d97706; }
.result-danger { background: rgba(239, 68, 68, 0.12); color: #dc2626; }
.result-info { background: rgba(148, 163, 184, 0.16); color: #64748b; }
.image-block { margin-top: 14rpx; }
.image-title { display: block; margin-bottom: 10rpx; font-size: 24rpx; color: #94a3b8; }
.history-images { display: flex; flex-wrap: wrap; gap: 12rpx; margin-top: 14rpx; }
.history-image { width: 150rpx; height: 150rpx; border-radius: 14rpx; background: #edf2f7; }
</style>

@ -125,7 +125,7 @@
<view v-else-if="currentTab === 2">
<view v-if="repairLoading" class="hint">{{ t('functionCommon.loading') }}</view>
<view v-else-if="!repairRecords.length" class="hint">{{ t('moldLedger.noRepair') }}</view>
<view v-for="row in repairRecords" :key="row.key" class="record-card">
<view v-for="row in repairRecords" :key="row.key" class="record-card" @click="openRepairDetail(row)">
<view class="record-head">
<text class="record-title">{{ detailValue(row.repairCode || row.subjectName || row.repairName) }}</text>
<text class="result-badge" :class="`result-${row.resultType}`">{{ row.resultLabel }}</text>
@ -138,7 +138,7 @@
detailValue(row.finishDateLabel) }}</text></view>
<view class="record-row"><text class="record-label">{{ t('moldLedger.remark') }}</text><text class="record-value">{{
detailValue(row.remark) }}</text></view>
<view v-if="row.images.length" class="history-images">
<view v-if="row.images.length" class="history-images" @click.stop>
<image v-for="img in row.images" :key="img" class="history-image" :src="img" mode="aspectFill"
@click="previewImages(row.images, img)" />
</view>
@ -206,10 +206,10 @@ import {
getMoldBrandDetail,
getMoldInspectionByMoldId,
getMoldMaintenanceByMoldId,
getMoldPage,
getMoldRepairListByMoldId
getMoldPage
} from '@/api/mes/mold'
import { getMoldOperatePage } from '@/api/mes/moldoperate'
import { getMoldRepairList } from '@/api/mes/moldrepair'
import { DICT_TYPE, getDictLabel, initAllDict } from '@/utils/dict'
const { t } = useI18n()
@ -245,7 +245,7 @@ const childMoldCount = computed(() => childMolds.value.length || detailData.valu
const statusLabel = computed(() => getDictLabel(DICT_TYPE.ERP_MOLD_STATUS, detailData.value?.status, detailValue(detailData.value?.status)))
const statusTagType = computed(() => {
const label = String(statusLabel.value || '')
if (label.includes('正常') || label.includes('使用')) return 'success'
if (label.includes('正常') || label.includes('使用') || label.includes('在机') || label.includes('在库')) return 'success'
if (label.includes('维修') || label.includes('警')) return 'warning'
if (label.includes('报废') || label.includes('停')) return 'error'
return 'primary'
@ -278,14 +278,14 @@ const maintainGroups = computed(() =>
const repairRecords = computed(() => {
const rows = Array.isArray(repairList.value) ? repairList.value : []
return rows.map((row, index) => {
const resultMeta = formatRepairResult(row?.repairResult !== undefined ? row.repairResult : row?.result)
const resultMeta = formatRepairResult(row?.repairResult ?? row?.repairStatus ?? row?.result)
return {
...row,
key: String(row?.id ?? row?.repairCode ?? index),
finishDateLabel: formatDateTime(row?.finishDate || row?.createTime),
resultLabel: resultMeta.label,
resultType: resultMeta.type,
images: parseImages(row?.malfunctionUrl || row?.malfunctionImages || row?.images)
images: parseImages(row?.malfunctionUrl || row?.malfunctionImages || row?.images || row?.faultImages)
}
})
})
@ -384,7 +384,7 @@ async function fetchRepairRecords() {
if (!brandId.value) return
repairLoading.value = true
try {
const res = await getMoldRepairListByMoldId(brandId.value)
const res = await getMoldRepairList({ moldId: brandId.value })
repairList.value = normalizeListData(res)
} catch (e) {
repairList.value = []
@ -467,7 +467,7 @@ function moldTypeText(type) {
function statusTextClass(status) {
const label = moldStatusText(status)
if (label.includes('正常') || label.includes('使用')) return 'text-success'
if (label.includes('正常') || label.includes('使用') || label.includes('在机') || label.includes('在库')) return 'text-success'
if (label.includes('维修') || label.includes('警')) return 'text-warning'
if (label.includes('报废') || label.includes('停')) return 'text-danger'
return 'text-default'
@ -583,6 +583,17 @@ function previewImages(list, current) {
if (!list || !list.length) return
uni.previewImage({ urls: list, current })
}
function openRepairDetail(row) {
const id = row?.id
if (id === undefined || id === null || id === '') {
uni.showToast({ title: t('moldRepair.noId'), icon: 'none' })
return
}
uni.navigateTo({
url: `/pages_function/pages/moldRepair/form?mode=detail&id=${encodeURIComponent(String(id))}`
})
}
</script>
<style lang="scss" scoped>

@ -105,6 +105,16 @@
<text class="form-label">{{ t('moldRepair.moldCode') }}</text>
<input v-model="formData.moldCode" class="form-input" type="text" :placeholder="t('moldRepair.placeholderMoldCodeAuto')" disabled />
</view>
<view class="form-item">
<text class="form-label">{{ t('moldRepair.specModel') }}</text>
<input v-model="formData.specModel" class="form-input" type="text" :placeholder="t('moldRepair.placeholderMoldCodeAuto')" disabled />
</view>
<view class="form-item">
<text class="form-label">{{ t('moldRepair.brand') }}</text>
<input v-model="formData.brand" class="form-input" type="text" :placeholder="t('moldRepair.placeholderMoldCodeAuto')" disabled />
</view>
</view>
<view class="section-card">
@ -252,6 +262,8 @@ const formData = reactive({
moldId: undefined,
moldCode: '',
moldName: '',
specModel: '',
brand: '',
requireDate: today,
finishDate: today,
confirmDate: today,
@ -289,10 +301,9 @@ const repairCodeDisabled = computed(() => Boolean(formData.isCode) || mode.value
const showRepairSection = computed(() => mode.value === 'repair' || mode.value === 'detail' || String(formData.repairStatus || '0') !== '0' || String(formData.status || '0') === '1')
const submitButtonText = computed(() => t('functionCommon.save'))
const statusLabel = computed(() => {
const normalized = String(formData.repairStatus || '0')
if (normalized === '1') return t('moldRepair.statusPassed')
if (normalized === '2') return t('moldRepair.statusRejected')
return t('moldRepair.statusPending')
const normalized = String(formData.status || '0')
if (normalized === '1') return t('moldRepair.orderStatusDone')
return t('moldRepair.orderStatusPending')
})
const moldLabels = computed(() => moldOptions.value.map((item) => item.label))
const faultLevelOptions = computed(() => {
@ -377,6 +388,8 @@ async function fetchDetail(id) {
formData.moldId = detail?.moldId ?? detail?.machineryId
formData.moldCode = inputValue(detail?.moldCode ?? detail?.machineryCode)
formData.moldName = inputValue(detail?.moldName ?? detail?.machineryName)
formData.specModel = inputValue(detail?.machinerySpec ?? detail?.moldSpec)
formData.brand = inputValue(detail?.machineryBrand ?? detail?.moldBrand)
formData.requireDate = defaultDateValue(detail?.requireDate)
formData.finishDate = defaultDateValue(detail?.finishDate)
formData.confirmDate = defaultDateValue(detail?.confirmDate)
@ -502,7 +515,7 @@ function onRepairStatusChange(event) {
function resolveUserLabel(value, placeholder) {
if (value === undefined || value === null || value === '') return placeholder
const current = users.value.find((item) => String(item.id) === String(value) || item.nickname === String(value))
return current?.nickname || current?.name || placeholder
return current?.nickname || current?.name || String(value)
}
function normalizeUserId(value) {

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save