修改设备维修增加条件

master
liutao 1 week ago
parent 5b170f26c7
commit 818f7737e7

@ -951,6 +951,7 @@ export default {
validatorFaultLevelRequired: 'Please select the failure level',
validatorIsShutdownRequired: 'Please select whether shutdown is required',
validatorFaultPhenomenonRequired: 'Please enter the fault phenomenon',
lineFilter: 'Line',
validatorRepairStatusRequired: 'Please select the repair result',
validatorFinishDateRequired: 'Please select the completion date',
validatorConfirmDateRequired: 'Please select the acceptance date'

@ -954,6 +954,7 @@ export default {
validatorFaultLevelRequired: '请选择故障等级',
validatorIsShutdownRequired: '请选择是否停机',
validatorFaultPhenomenonRequired: '请输入故障现象',
lineFilter: '产线',
validatorRepairStatusRequired: '请选择维修结果',
validatorFinishDateRequired: '请选择完成日期',
validatorConfirmDateRequired: '请选择验收日期'

@ -3,6 +3,10 @@
<NavBar :title="t('equipmentMaintenance.moduleName')" />
<view class="filter-bar">
<view class="line-filter" @click="openLineCascader">
<text :class="['line-filter-text', selectedLineId === '' ? 'placeholder' : '']">{{ selectedLineLabel }}</text>
<uni-icons type="bottom" size="14" color="#a8adb7"></uni-icons>
</view>
<view class="keyword-box">
<input
v-model="searchKeyword"
@ -23,9 +27,6 @@
</view>
</picker>
<view class="reset-filter-btn" @click="resetFilters">{{ t('functionCommon.reset') }}</view>
<view class="scan-btn" @click="handleScan">
<uni-icons type="scan" size="22" color="#111827"></uni-icons>
</view>
</view>
<scroll-view
@ -81,6 +82,20 @@
<view class="add-btn" @click="openForm('create')">
<text class="add-icon">+</text>
</view>
<up-cascader
:key="lineCascaderKey"
v-model:show="lineCascaderShow"
v-model="lineCascaderValue"
:data="lineCascaderOptions"
value-key="value"
label-key="label"
children-key="children"
header-direction="row"
:options-cols="2"
:auto-close="false"
@confirm="onLineCascaderConfirm"
/>
</view>
</template>
@ -93,10 +108,16 @@ import {
deleteDvRepair,
getDvRepairPage
} from '@/api/mes/dvrepair'
import { getDeviceLineTree } from '@/api/mes/deviceLine'
const { t } = useI18n()
const searchKeyword = ref('')
const selectedStatus = ref('')
const selectedLineId = ref('')
const lineTree = ref([])
const lineCascaderShow = ref(false)
const lineCascaderValue = ref([])
const lineCascaderKey = ref(0)
const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
@ -108,7 +129,6 @@ const initialized = ref(false)
const scrollTop = ref(0)
const showGoTop = ref(false)
const keywordFocus = ref(false)
const selectedMachineryId = ref('')
const statusOptions = computed(() => [
{ label: t('functionCommon.all'), value: '' },
@ -127,21 +147,86 @@ const selectedStatusLabel = computed(() => {
return current ? current.label : t('functionCommon.all')
})
onLoad(async () => {
initialized.value = true
activateKeywordFocus()
await fetchList(true)
const selectedLineLabel = computed(() => {
if (selectedLineId.value === '') return t('equipmentMaintenance.lineFilter')
const found = lineOptions.value.find(item => String(item.id) === String(selectedLineId.value))
return found?.name || t('equipmentMaintenance.lineFilter')
})
onShow(async () => {
activateKeywordFocus()
if (!initialized.value) return
await fetchList(true)
const lineOptions = computed(() => {
return flattenLineTree(lineTree.value, 1)
})
onReachBottom(() => {
loadMore()
})
const lineCascaderOptions = computed(() => [
{ label: t('functionCommon.all'), value: '' },
...normalizeLineTreeForCascader(lineTree.value)
])
function flattenLineTree(nodes, level) {
const result = []
;(Array.isArray(nodes) ? nodes : []).forEach((node) => {
result.push({
id: node.id,
name: node.name || node.label || String(node.id || ''),
level
})
if (Array.isArray(node.children) && node.children.length) {
result.push(...flattenLineTree(node.children, level + 1))
}
})
return result
}
function normalizeLineTreeForCascader(nodes) {
return (Array.isArray(nodes) ? nodes : []).map((node) => {
const children = normalizeLineTreeForCascader(node.children)
const item = {
label: node.name || node.label || String(node.id || ''),
value: String(node.id ?? '')
}
if (children.length) item.children = children
return item
})
}
function findLinePath(nodes, id, parents = []) {
const target = String(id)
for (const node of Array.isArray(nodes) ? nodes : []) {
const currentPath = [...parents, String(node.id ?? '')]
if (String(node.id) === target) return currentPath
const childPath = findLinePath(node.children, id, currentPath)
if (childPath.length) return childPath
}
return []
}
async function fetchDeviceLineTree() {
try {
const res = await getDeviceLineTree()
const root = res && res.data !== undefined ? res.data : res
const treeData = Array.isArray(root) ? root : (Array.isArray(root?.data) ? root.data : [])
lineTree.value = normalizeLineTree(treeData)
} catch (_) {
lineTree.value = []
}
}
function normalizeLineTree(nodes) {
return (Array.isArray(nodes) ? nodes : []).map((node) => {
const children = normalizeLineTree(node.children)
const item = {
...node,
id: String(node.id ?? ''),
name: node.name || node.label || String(node.id || '')
}
if (children.length) {
item.children = children
} else {
delete item.children
}
return item
})
}
async function fetchList(reset) {
if (reset) {
@ -162,35 +247,50 @@ async function fetchList(reset) {
pageSize: pageSize.value,
repairCode: keyword || undefined,
machineryCode: keyword || undefined,
machineryId: selectedMachineryId.value || undefined,
deviceLine: selectedLineId.value === '' ? undefined : selectedLineId.value,
repairStatus: selectedStatus.value === '' ? undefined : selectedStatus.value
}
const res = await getDvRepairPage(params)
const page = normalizePageData(res)
total.value = page.total
list.value = reset ? page.list : [...list.value, ...page.list]
finished.value = list.value.length >= total.value || page.list.length < pageSize.value
} catch (error) {
if (!reset) {
pageNo.value = Math.max(1, pageNo.value - 1)
}
uni.showToast({ title: t('functionCommon.loadFailed'), icon: 'none' })
const root = res && res.data !== undefined ? res.data : res
const candidateList = root?.list || root?.rows || root?.records || root?.data?.list || root?.data?.rows || root?.data?.records || []
const candidateTotal = root?.total ?? root?.data?.total ?? (Array.isArray(candidateList) ? candidateList.length : 0)
onFetchResult({ list: Array.isArray(candidateList) ? candidateList : [], total: Number(candidateTotal || 0) })
} catch (e) {
onFetchResult({ list: [], total: 0 })
if (!reset) pageNo.value = Math.max(1, pageNo.value - 1)
} finally {
loading.value = false
loadingMore.value = false
}
}
function normalizePageData(res) {
const root = res && res.data !== undefined ? res.data : res
const candidateList = root?.list || root?.rows || root?.records || root?.data?.list || root?.data?.rows || root?.data?.records || []
const candidateTotal = root?.total ?? root?.data?.total ?? (Array.isArray(candidateList) ? candidateList.length : 0)
return {
list: Array.isArray(candidateList) ? candidateList : [],
total: Number(candidateTotal || 0)
function onFetchResult(result) {
const data = result || { list: [], total: 0 }
if (pageNo.value === 1) {
list.value = data.list
} else {
list.value = list.value.concat(data.list)
}
total.value = data.total
const loadedCount = list.value.length
finished.value = loadedCount >= total.value || data.list.length < pageSize.value
}
onLoad(async () => {
initialized.value = true
await fetchDeviceLineTree()
await fetchList(true)
})
onShow(async () => {
if (!initialized.value) return
await fetchList(true)
})
onReachBottom(() => {
loadMore()
})
function activateKeywordFocus() {
keywordFocus.value = false
nextTick(() => {
@ -203,10 +303,25 @@ function handleSearch() {
fetchList(true)
}
function openLineCascader() {
lineCascaderShow.value = true
}
function onLineCascaderConfirm(values) {
const selectedValues = Array.isArray(values) ? values : []
const nextValue = selectedValues[selectedValues.length - 1] ?? ''
selectedLineId.value = nextValue === '' ? '' : String(nextValue)
lineCascaderValue.value = nextValue === '' ? [] : selectedValues.map(item => String(item))
fetchList(true)
}
async function resetFilters() {
searchKeyword.value = ''
selectedStatus.value = ''
selectedMachineryId.value = ''
selectedLineId.value = ''
lineCascaderValue.value = []
lineCascaderShow.value = false
lineCascaderKey.value += 1
activateKeywordFocus()
await fetchList(true)
}
@ -217,51 +332,6 @@ function onStatusFilterChange(event) {
fetchList(true)
}
async function handleScan() {
try {
const res = await uni.scanCode({ scanType: ['qrCode', 'barCode'] })
const result = String(res?.result || '').trim()
if (!result) {
uni.showToast({ title: t('equipmentMaintenance.scanUnrecognized'), icon: 'none' })
return
}
const scan = parseEquipmentScanResult(result)
if (!scan.id) {
uni.showToast({ title: t('equipmentMaintenance.scanEquipmentRequired'), icon: 'none' })
return
}
selectedMachineryId.value = scan.id
searchKeyword.value = ''
await fetchList(true)
} catch (error) {
const message = String(error?.errMsg || '')
if (message.includes('cancel')) return
uni.showToast({ title: t('equipmentMaintenance.scanFailed'), icon: 'none' })
}
}
function parseEquipmentScanResult(result) {
const text = String(result || '').trim()
const directMatch = text.match(/^([A-Z_]+)-(\d+)$/i)
if (directMatch) {
return {
type: directMatch[1].toUpperCase(),
id: directMatch[1].toUpperCase() === 'EQUIPMENT' ? directMatch[2] : ''
}
}
try {
const parsed = JSON.parse(text)
const type = String(parsed?.type || parsed?.bizType || parsed?.codeType || '').toUpperCase()
const id = String(parsed?.id || parsed?.machineryId || parsed?.deviceId || '').trim()
return {
type,
id: type === 'EQUIPMENT' && id ? id : ''
}
} catch {
return { type: '', id: '' }
}
}
function canEdit(item) {
return !isProcessedRepair(item?.repairStatus)
}
@ -410,16 +480,16 @@ function textValue(value) {
.filter-bar {
display: grid;
grid-template-columns: minmax(0, 1fr) 150rpx 96rpx 64rpx;
grid-template-columns: minmax(0, 1fr) 150rpx 110rpx;
align-items: center;
gap: 14rpx;
padding: 18rpx 4rpx 20rpx;
padding: 18rpx 4rpx 16rpx;
}
.line-filter,
.keyword-box,
.status-box,
.reset-filter-btn,
.scan-btn {
.reset-filter-btn {
height: 66rpx;
background: #ffffff;
border: 1rpx solid #d9dde5;
@ -428,6 +498,26 @@ function textValue(value) {
align-items: center;
}
.line-filter {
grid-column: 1 / -1;
justify-content: space-between;
padding: 0 18rpx;
border-radius: 8rpx;
}
.line-filter-text {
font-size: 26rpx;
color: #374151;
max-width: 85%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line-filter-text.placeholder {
color: #a8adb7;
}
.keyword-box {
padding: 0 20rpx;
}
@ -456,19 +546,14 @@ function textValue(value) {
color: #a8adb7;
}
.scan-btn {
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
}
.reset-filter-btn {
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #4b5563;
border-radius: 8rpx;
cursor: pointer;
}
.list-scroll {
@ -480,15 +565,15 @@ function textValue(value) {
}
.repair-card {
margin-bottom: 18rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
border-radius: 16rpx;
background: #ffffff;
box-shadow: none;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
overflow: hidden;
}
.card-main {
padding: 24rpx;
padding: 28rpx 24rpx;
}
.card-top,
@ -500,9 +585,9 @@ function textValue(value) {
}
.repair-code {
max-width: 420rpx;
font-size: 36rpx;
line-height: 44rpx;
max-width: 460rpx;
font-size: 32rpx;
line-height: 42rpx;
color: #24456b;
font-weight: 700;
}
@ -514,9 +599,9 @@ function textValue(value) {
}
.repair-status-tag {
padding: 8rpx 18rpx;
padding: 6rpx 20rpx;
border-radius: 999rpx;
font-size: 24rpx;
font-size: 22rpx;
font-weight: 600;
line-height: 1.2;
}
@ -537,21 +622,22 @@ function textValue(value) {
align-items: center;
justify-content: space-between;
gap: 20rpx;
margin-top: 14rpx;
margin-top: 16rpx;
}
.equipment-label {
font-size: 28rpx;
font-size: 26rpx;
color: #9ca3af;
font-weight: 600;
font-weight: 500;
flex-shrink: 0;
}
.equipment-value {
flex: 1;
text-align: right;
font-size: 30rpx;
font-size: 28rpx;
color: #9ca3af;
font-weight: 500;
}
.text-warning {
@ -605,8 +691,8 @@ function textValue(value) {
}
.card-actions {
padding: 18rpx 24rpx;
border-top: 1rpx solid #f1f5f9;
padding: 16rpx 24rpx;
border-top: 1rpx solid #f0f2f5;
justify-content: flex-end;
gap: 28rpx;
}
@ -627,7 +713,7 @@ function textValue(value) {
}
.state-text.empty {
padding-top: 160rpx;
padding-top: 200rpx;
}
.add-btn,
@ -647,6 +733,7 @@ function textValue(value) {
right: 28rpx;
bottom: calc(56rpx + env(safe-area-inset-bottom));
background: #1f4b79;
box-shadow: 0 8rpx 24rpx rgba(31, 75, 121, 0.35);
}
.go-top-btn {
@ -660,4 +747,4 @@ function textValue(value) {
line-height: 1;
margin-top: -4rpx;
}
</style>
</style>

Loading…
Cancel
Save