diff --git a/src/pages_function/pages/equipmentMaintenance/form.vue b/src/pages_function/pages/equipmentMaintenance/form.vue
index 4d4fa4c..2f6de46 100644
--- a/src/pages_function/pages/equipmentMaintenance/form.vue
+++ b/src/pages_function/pages/equipmentMaintenance/form.vue
@@ -108,16 +108,24 @@
-
- {{ selectedDeviceLabel }}
-
+
+ {{ selectedDeviceLabel }}
+
+
{{ t('equipmentMaintenance.component') }}
-
- {{ selectedComponentLabel }}
-
+
+ {{ selectedComponentLabel }}
+
+
@@ -232,6 +240,86 @@
+
+
+
+
+
+
+
+
@@ -261,6 +349,10 @@ const users = ref([])
const deviceOptions = ref([])
const componentOptions = ref([])
const loading = ref(false)
+const devicePickerRef = ref(null)
+const deviceSearchKeyword = ref('')
+const componentPickerRef = ref(null)
+const componentSearchKeyword = ref('')
const formData = reactive({
id: undefined,
@@ -275,9 +367,9 @@ const formData = reactive({
machineryBrand: '',
machinerySpec: '',
machineryTypeId: 1,
- requireDate: '',
- finishDate: '',
- confirmDate: '',
+ requireDate: todayPickerDate(),
+ finishDate: todayPickerDate(),
+ confirmDate: todayPickerDate(),
repairStatus: '0',
repairResult: '0',
acceptedBy: '',
@@ -318,7 +410,6 @@ const statusLabel = computed(() => {
return t('equipmentMaintenance.statusPending')
})
const userLabels = computed(() => users.value.map((item) => item.nickname || item.name || String(item.id || '')))
-const deviceLabels = computed(() => deviceOptions.value.map((item) => item.label))
const faultLevelOptions = computed(() => {
const dicts = dictStore.getDict(DICT_TYPE.FAILURE_LEVEL) || []
return dicts
@@ -333,14 +424,32 @@ const confirmByIndex = computed(() => findUserIndex(formData.confirmBy))
const acceptedByLabel = computed(() => resolveUserLabel(formData.acceptedBy, t('equipmentMaintenance.placeholderAcceptedBy')))
const confirmByLabel = computed(() => resolveUserLabel(formData.confirmBy, t('equipmentMaintenance.placeholderConfirmBy')))
const showComponentSelect = computed(() => Number(formData.machineryTypeId || 1) === 2)
-const deviceIndex = computed(() => {
- const index = deviceOptions.value.findIndex((item) => String(item.value) === String(formData.deviceId || ''))
- return index >= 0 ? index : 0
-})
const selectedDeviceLabel = computed(() => {
const current = deviceOptions.value.find((item) => String(item.value) === String(formData.deviceId || ''))
return current?.label || t('equipmentMaintenance.placeholderDevice')
})
+const filteredDeviceOptions = computed(() => {
+ const keyword = deviceSearchKeyword.value.trim().toLowerCase()
+ if (!keyword) return deviceOptions.value
+ const keywordId = extractEquipmentKeywordId(keyword)
+ return deviceOptions.value.filter((item) => {
+ const raw = item.raw || {}
+ const fields = [
+ item.label,
+ item.value,
+ raw.id,
+ raw.deviceId,
+ raw.machineryId,
+ raw.machineryid,
+ raw.deviceCode,
+ raw.deviceName,
+ raw.deviceBrand,
+ raw.deviceSpec
+ ]
+ return fields.some((field) => String(field || '').toLowerCase().includes(keyword))
+ || (keywordId && matchesDeviceOptionId(item, keywordId))
+ })
+})
const filteredComponentOptions = computed(() => {
const source = Array.isArray(componentOptions.value) ? componentOptions.value : []
const currentDeviceId = String(formData.deviceId || '').trim()
@@ -348,10 +457,22 @@ const filteredComponentOptions = computed(() => {
const matched = source.filter((item) => matchesComponentDevice(item?.raw, currentDeviceId))
return matched.length ? matched : source
})
-const componentLabels = computed(() => filteredComponentOptions.value.map((item) => item.label))
-const componentIndex = computed(() => {
- const index = filteredComponentOptions.value.findIndex((item) => String(item.value) === String(formData.componentId || ''))
- return index >= 0 ? index : 0
+const searchableComponentOptions = computed(() => {
+ const keyword = componentSearchKeyword.value.trim().toLowerCase()
+ if (!keyword) return filteredComponentOptions.value
+ return filteredComponentOptions.value.filter((item) => {
+ const raw = item.raw || {}
+ const fields = [
+ item.label,
+ raw.code,
+ raw.componentCode,
+ raw.name,
+ raw.componentName,
+ raw.deviceName,
+ raw.deviceCode
+ ]
+ return fields.some((field) => String(field || '').toLowerCase().includes(keyword))
+ })
})
const selectedComponentLabel = computed(() => {
const current = filteredComponentOptions.value.find((item) => String(item.value) === String(formData.componentId || ''))
@@ -433,9 +554,9 @@ async function fetchDetail(id) {
formData.machineryBrand = inputValue(detail?.machineryBrand)
formData.machinerySpec = inputValue(detail?.machinerySpec)
formData.machineryTypeId = Number(detail?.machineryTypeId || 1) || 1
- formData.requireDate = formatPickerDate(detail?.requireDate)
- formData.finishDate = formatPickerDate(detail?.finishDate)
- formData.confirmDate = formatPickerDate(detail?.confirmDate)
+ formData.requireDate = formatPickerDate(detail?.requireDate) || todayPickerDate()
+ formData.finishDate = formatPickerDate(detail?.finishDate) || todayPickerDate()
+ formData.confirmDate = formatPickerDate(detail?.confirmDate) || todayPickerDate()
formData.repairStatus = normalizedRepairStatus
formData.repairResult = normalizedRepairStatus
formData.acceptedBy = normalizeUserId(detail?.acceptedBy)
@@ -513,17 +634,61 @@ function onUserChange(field, event) {
formData[field] = current ? String(current.id) : ''
}
-function onDeviceChange(event) {
- const index = Number(event?.detail?.value || 0)
- const current = deviceOptions.value[index]
- if (!current) return
+function openDevicePicker() {
+ if (readonlyBase.value) return
+ devicePickerRef.value?.open?.()
+}
+
+function closeDevicePicker() {
+ devicePickerRef.value?.close?.()
+}
+
+function clearDeviceSearch() {
+ deviceSearchKeyword.value = ''
+}
+
+function selectDeviceOption(current) {
+ if (!current || readonlyBase.value) return
applyDeviceOption(current)
+ clearDeviceSearch()
+ closeDevicePicker()
}
-function onComponentChange(event) {
- const index = Number(event?.detail?.value || 0)
- const current = filteredComponentOptions.value[index]
- formData.componentId = current ? current.value : undefined
+function deviceMetaText(item) {
+ const raw = item?.raw || {}
+ return [raw.deviceBrand, raw.deviceSpec].map(inputValue).filter(Boolean).join(' / ')
+}
+
+function openComponentPicker() {
+ if (readonlyBase.value) return
+ componentPickerRef.value?.open?.()
+}
+
+function closeComponentPicker() {
+ componentPickerRef.value?.close?.()
+}
+
+function clearComponentSearch() {
+ componentSearchKeyword.value = ''
+}
+
+function selectComponentOption(current) {
+ if (!current || readonlyBase.value) return
+ formData.componentId = current.value
+ clearComponentSearch()
+ closeComponentPicker()
+}
+
+function componentMetaText(item) {
+ const raw = item?.raw || {}
+ return [
+ raw.deviceName,
+ raw.deviceCode,
+ raw.spec,
+ raw.componentSpec,
+ raw.model,
+ raw.componentModel
+ ].map(inputValue).filter(Boolean).join(' / ')
}
function selectMachineryType(value) {
@@ -552,7 +717,7 @@ async function handleDeviceScan() {
uni.showToast({ title: t('equipmentMaintenance.scanEquipmentRequired'), icon: 'none' })
return
}
- const matched = deviceOptions.value.find((item) => String(item.value) === String(scan.id))
+ const matched = deviceOptions.value.find((item) => matchesDeviceOptionId(item, scan.id))
if (!matched) {
uni.showToast({ title: t('equipmentMaintenance.deviceNotFound'), icon: 'none' })
return
@@ -587,6 +752,28 @@ function parseEquipmentScanResult(result) {
}
}
+function extractEquipmentKeywordId(keyword) {
+ const match = String(keyword || '').trim().match(/-(\d+)$/)
+ return match ? match[1] : ''
+}
+
+function getDeviceOptionIds(item) {
+ const raw = item?.raw || {}
+ return [
+ item?.value,
+ raw.id,
+ raw.deviceId,
+ raw.machineryId,
+ raw.machineryid
+ ].filter((value) => value !== undefined && value !== null && value !== '')
+}
+
+function matchesDeviceOptionId(item, id) {
+ const target = String(id || '').trim()
+ if (!target) return false
+ return getDeviceOptionIds(item).some((value) => String(value) === target)
+}
+
function applyDeviceOption(current) {
formData.deviceId = current.value
formData.machineryId = current.value
@@ -671,6 +858,10 @@ function datePickerValue(value) {
return value || formatPickerDate(Date.now())
}
+function todayPickerDate() {
+ return formatPickerDate(Date.now())
+}
+
function formatPickerDate(value) {
if (value === undefined || value === null || value === '') return ''
const date = parseDate(value)
@@ -1002,6 +1193,23 @@ function goBack() {
color: #9ca3af;
}
+.picker-field {
+ justify-content: space-between;
+ gap: 12rpx;
+}
+
+.picker-field.is-disabled {
+ color: #64748b;
+}
+
+.picker-field-text {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
.code-row {
display: flex;
align-items: center;
@@ -1161,4 +1369,146 @@ function goBack() {
background: #1f4b79;
color: #ffffff;
}
+
+.device-picker-popup {
+ height: 72vh;
+ background: #ffffff;
+ border-radius: 22rpx 22rpx 0 0;
+ overflow: hidden;
+}
+
+.device-picker-header {
+ position: relative;
+ height: 92rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-bottom: 1rpx solid #eef2f7;
+}
+
+.device-picker-title {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #111827;
+}
+
+.device-picker-close {
+ position: absolute;
+ right: 24rpx;
+ top: 14rpx;
+ width: 56rpx;
+ height: 56rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #64748b;
+ font-size: 42rpx;
+ line-height: 1;
+}
+
+.device-picker-search {
+ padding: 18rpx 24rpx 14rpx;
+}
+
+.device-search-box {
+ height: 74rpx;
+ padding: 0 20rpx;
+ border-radius: 14rpx;
+ background: #f8fafc;
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+}
+
+.device-search-input {
+ flex: 1;
+ height: 74rpx;
+ min-width: 0;
+ font-size: 28rpx;
+ color: #111827;
+}
+
+.device-search-clear {
+ width: 44rpx;
+ height: 44rpx;
+ border-radius: 50%;
+ background: #e2e8f0;
+ color: #64748b;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 30rpx;
+ line-height: 1;
+}
+
+.device-picker-scroll {
+ height: calc(72vh - 184rpx);
+ padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
+ box-sizing: border-box;
+}
+
+.device-picker-item {
+ margin: 0 24rpx 14rpx;
+ padding: 20rpx;
+ border-radius: 16rpx;
+ background: #f8fafc;
+ border: 2rpx solid transparent;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16rpx;
+}
+
+.device-picker-item.is-selected {
+ background: #eef6ff;
+ border-color: #bfdbfe;
+}
+
+.device-item-main {
+ flex: 1;
+ min-width: 0;
+}
+
+.device-item-title {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ min-width: 0;
+}
+
+.device-item-code {
+ flex-shrink: 0;
+ max-width: 52%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 28rpx;
+ font-weight: 700;
+ color: #111827;
+}
+
+.device-item-name {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 28rpx;
+ color: #334155;
+}
+
+.device-item-meta {
+ margin-top: 8rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 24rpx;
+ color: #64748b;
+}
+
+.device-picker-empty {
+ padding: 72rpx 24rpx;
+ text-align: center;
+ color: #94a3b8;
+ font-size: 28rpx;
+}