feat:模具维修-选择模具交互优化

master
黄伟杰 4 days ago
parent 1bbe6c7b90
commit 2db4fce017

@ -1091,6 +1091,13 @@
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{
"path": "moldRepair/moldSelect",
"style": {
"navigationBarTitleText": "选择模具",
"navigationStyle": "custom"
}
},
{ {
"path": "moldInspectionItems/index", "path": "moldInspectionItems/index",
"style": { "style": {

@ -93,18 +93,16 @@
<input <input
id="mold-repair-scan-input" id="mold-repair-scan-input"
v-model="moldCodeSearch" v-model="moldCodeSearch"
class="mold-scan-input" class="form-input mold-scan-input"
type="text" type="text"
:placeholder="t('moldRepair.scanMoldPlaceholder')" :placeholder="t('moldRepair.scanMoldPlaceholder')"
:disabled="readonlyBase" :disabled="readonlyBase"
@confirm="onMoldCodeSearch" @confirm="onMoldCodeSearch"
/> />
<picker :range="moldLabels" :value="moldIndex" :disabled="readonlyBase" @change="onMoldChange"> <view :class="['picker-field', 'mold-select-field', !formData.moldId ? 'is-placeholder' : '', readonlyBase ? 'is-disabled' : '']" @click="openMoldSelect">
<view :class="['mold-picker', !formData.moldId ? 'is-placeholder' : '']"> <text class="picker-field-text">{{ t('moldRepair.placeholderMold') }}</text>
<text class="picker-field-text">{{ selectedMoldLabel }}</text> <uni-icons v-if="!readonlyBase" type="right" size="16" color="#ffffff"></uni-icons>
<uni-icons v-if="!readonlyBase" type="bottom" size="14" color="#9ca3af"></uni-icons> </view>
</view>
</picker>
</view> </view>
</view> </view>
@ -334,7 +332,6 @@ const statusLabel = computed(() => {
if (normalized === '1') return t('moldRepair.orderStatusDone') if (normalized === '1') return t('moldRepair.orderStatusDone')
return t('moldRepair.orderStatusPending') return t('moldRepair.orderStatusPending')
}) })
const moldLabels = computed(() => moldOptions.value.map((item) => item.label))
const faultLevelOptions = computed(() => { const faultLevelOptions = computed(() => {
const dicts = dictStore.getDict(DICT_TYPE.FAILURE_LEVEL) || [] const dicts = dictStore.getDict(DICT_TYPE.FAILURE_LEVEL) || []
return dicts return dicts
@ -346,14 +343,6 @@ const faultLevelOptions = computed(() => {
}) })
const acceptedByLabel = computed(() => resolveUserLabel(formData.acceptedBy, t('moldRepair.placeholderAcceptedBy'))) const acceptedByLabel = computed(() => resolveUserLabel(formData.acceptedBy, t('moldRepair.placeholderAcceptedBy')))
const confirmByLabel = computed(() => resolveUserLabel(formData.confirmBy, t('moldRepair.placeholderConfirmBy'))) const confirmByLabel = computed(() => resolveUserLabel(formData.confirmBy, t('moldRepair.placeholderConfirmBy')))
const moldIndex = computed(() => {
const index = moldOptions.value.findIndex((item) => String(item.value) === String(formData.moldId || ''))
return index >= 0 ? index : 0
})
const selectedMoldLabel = computed(() => {
const current = moldOptions.value.find((item) => String(item.value) === String(formData.moldId || ''))
return current?.label || t('moldRepair.placeholderMold')
})
const faultImageList = computed(() => splitImages(formData.faultImages)) const faultImageList = computed(() => splitImages(formData.faultImages))
const repairedImageList = computed(() => splitImages(formData.repairedImages)) const repairedImageList = computed(() => splitImages(formData.repairedImages))
@ -373,6 +362,7 @@ onReady(() => {
onShow(() => { onShow(() => {
applySelectedUser() applySelectedUser()
applySelectedMold()
}) })
function focusKeywordNoKeyboard() { function focusKeywordNoKeyboard() {
@ -481,13 +471,12 @@ function onDateChange(field, event) {
formData[field] = String(event?.detail?.value || '') formData[field] = String(event?.detail?.value || '')
} }
function onMoldChange(event) { function openMoldSelect() {
const index = Number(event?.detail?.value || 0) if (readonlyBase.value) return
const current = moldOptions.value[index] uni.navigateTo({
if (!current) return url: `/pages_function/pages/moldRepair/moldSelect?selectedId=${encodeURIComponent(String(formData.moldId || ''))}`
applyMoldOption(current) })
} }
function onMoldCodeSearch(event) { function onMoldCodeSearch(event) {
const code = (event?.detail?.value || '').trim() const code = (event?.detail?.value || '').trim()
if (code) doMoldCodeSearch(code) if (code) doMoldCodeSearch(code)
@ -606,14 +595,24 @@ function reFocusScanInput() {
}) })
} }
function normalizeMoldOption(item) {
const code = item?.code ?? item?.moldCode ?? item?.brandCode ?? ''
const name = item?.name ?? item?.moldName ?? item?.brandName ?? ''
const label = `${code} ${name}`.trim() || String(item?.id ?? '')
return {
value: item?.id,
label,
raw: item
}
}
function applyMoldOption(current) { function applyMoldOption(current) {
formData.moldId = current.value formData.moldId = current.value
formData.moldCode = inputValue(current.raw?.code ?? current.raw?.moldCode) formData.moldCode = inputValue(current.raw?.code ?? current.raw?.moldCode ?? current.raw?.brandCode)
formData.moldName = inputValue(current.raw?.name ?? current.raw?.moldName) formData.moldName = inputValue(current.raw?.name ?? current.raw?.moldName ?? current.raw?.brandName)
formData.specModel = inputValue(current.raw?.spec ?? current.raw?.moldSpec ?? current.raw?.machinerySpec) formData.specModel = inputValue(current.raw?.spec ?? current.raw?.moldSpec ?? current.raw?.machinerySpec)
formData.brand = inputValue(current.raw?.brand ?? current.raw?.moldBrand ?? current.raw?.machineryBrand) formData.brand = inputValue(current.raw?.brand ?? current.raw?.moldBrand ?? current.raw?.machineryBrand)
} }
function onShutdownChange(event) { function onShutdownChange(event) {
const value = String(event?.detail?.value || '') const value = String(event?.detail?.value || '')
if (value === 'true') selectShutdown(true) if (value === 'true') selectShutdown(true)
@ -682,6 +681,18 @@ function applySelectedUser() {
} }
} }
function applySelectedMold() {
const result = getApp().globalData._moldRepairMoldSelectResult
if (!result?.mold) return
getApp().globalData._moldRepairMoldSelectResult = null
const mold = result.mold
const option = normalizeMoldOption(mold)
if (!moldOptions.value.some((item) => String(item.value) === String(option.value))) {
moldOptions.value = [option, ...moldOptions.value]
}
applyMoldOption(option)
}
function getTodayDate() { function getTodayDate() {
return formatPickerDate(Date.now()) return formatPickerDate(Date.now())
} }
@ -964,7 +975,7 @@ function goBack() {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 16rpx; // gap: 16rpx;
} }
.form-textarea { .form-textarea {
@ -989,44 +1000,21 @@ function goBack() {
.mold-scan-input { .mold-scan-input {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
height: 84rpx;
line-height: 84rpx;
padding: 0 20rpx;
border: 1rpx solid #d9dde5;
border-radius: 14rpx;
background: #ffffff;
font-size: 26rpx;
color: #374151;
box-sizing: border-box;
} }
.mold-picker { .mold-select-field {
flex-shrink: 0; flex-shrink: 0;
width: 180rpx; width: 190rpx;
height: 84rpx; background: #1f4b79;
line-height: 84rpx; color: #ffffff;
padding: 0 14rpx;
font-size: 26rpx;
color: #111827;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8rpx;
border: 1rpx solid #d9dde5;
border-radius: 14rpx;
background: #ffffff;
box-sizing: border-box;
}
.mold-picker.is-placeholder {
color: #9ca3af;
} }
.mold-picker.is-disabled { .mold-select-field.is-placeholder,
color: #9ca3af; .mold-select-field.is-disabled {
color: #ffffff;
} }
.mold-picker .picker-field-text { .mold-select-field .picker-field-text {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
overflow: hidden; overflow: hidden;

@ -0,0 +1,283 @@
<template>
<view class="page-container">
<NavBar :title="t('moldRepair.placeholderMold')" />
<view class="search-bar">
<view class="search-input-wrap">
<text class="search-icon iconfont icon-search"></text>
<input
id="mold-repair-mold-select-search-input"
v-model="searchText"
class="search-input"
type="text"
:placeholder="t('moldRepair.scanMoldPlaceholder')"
placeholder-class="search-placeholder"
confirm-type="search"
@input="onSearchInput"
@confirm="loadMolds"
/>
<text v-if="searchText" class="search-clear" @click="clearSearch">x</text>
</view>
</view>
<scroll-view v-if="moldList.length > 0" scroll-y class="mold-list">
<view
v-for="mold in moldList"
:key="mold.id"
class="mold-card"
:class="{ active: String(selectedId) === String(mold.id) }"
@click="selectedId = mold.id"
>
<text class="mold-name">{{ textValue(mold.name || mold.moldName || mold.brandName) }}</text>
<view class="mold-meta">
<text class="mold-meta-text">{{ textValue(mold.code || mold.moldCode || mold.brandCode) }}</text>
<text v-if="mold.spec || mold.moldSpec || mold.machinerySpec" class="mold-meta-divider">|</text>
<text v-if="mold.spec || mold.moldSpec || mold.machinerySpec" class="mold-meta-text">{{ textValue(mold.spec || mold.moldSpec || mold.machinerySpec) }}</text>
</view>
<view v-if="mold.brand || mold.moldBrand || mold.machineryBrand" class="mold-meta">
<text class="mold-meta-text">{{ textValue(mold.brand || mold.moldBrand || mold.machineryBrand) }}</text>
</view>
</view>
</scroll-view>
<view v-else class="empty-wrap">
<text v-if="loading" class="empty-text">{{ t('functionCommon.loading') }}</text>
<text v-else class="empty-text">{{ t('moldRepair.moldNotFound') }}</text>
</view>
<view class="bottom-actions">
<view class="bottom-btn confirm-btn" @click="handleConfirm">
{{ t('functionCommon.confirm') }}
</view>
</view>
<sv-focus-no-keyboard ref="focusNoKeyboardRef"></sv-focus-no-keyboard>
</view>
</template>
<script setup>
import { nextTick, ref } from 'vue'
import { onLoad, onReady, onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getBrandList, getMoldBrandPage } from '@/api/mes/mold'
const { t } = useI18n()
const selectedId = ref('')
const searchText = ref('')
const moldList = ref([])
const loading = ref(false)
const focusNoKeyboardRef = ref(null)
const searchInputSelector = '#mold-repair-mold-select-search-input input, input#mold-repair-mold-select-search-input'
let searchTimer = null
onLoad(async (options) => {
selectedId.value = String(options?.selectedId || '')
focusSearchNoKeyboard()
await loadMolds()
})
onShow(() => {
focusSearchNoKeyboard()
})
onReady(() => {
focusSearchNoKeyboard()
setTimeout(focusSearchNoKeyboard, 300)
setTimeout(focusSearchNoKeyboard, 800)
})
function focusSearchNoKeyboard() {
nextTick(() => {
setTimeout(() => {
focusNoKeyboardRef.value?.focus(searchInputSelector)
}, 80)
})
}
function onSearchInput() {
if (searchTimer) clearTimeout(searchTimer)
searchTimer = setTimeout(() => {
loadMolds()
}, 300)
}
function clearSearch() {
searchText.value = ''
loadMolds()
}
async function loadMolds() {
if (searchTimer) {
clearTimeout(searchTimer)
searchTimer = null
}
loading.value = true
try {
const keyword = searchText.value.trim()
const res = keyword
? await getMoldBrandPage({ code: keyword, name: keyword, pageNo: 1, pageSize: 50 })
: await getBrandList()
moldList.value = normalizeMoldList(res)
} catch (error) {
moldList.value = []
} finally {
loading.value = false
}
}
function normalizeMoldList(res) {
const root = res && res.data !== undefined ? res.data : res
const pageResult = root?.pageResult || root?.data?.pageResult || root?.data || root || {}
const data = Array.isArray(root)
? root
: (Array.isArray(root?.data)
? root.data
: (pageResult?.list || pageResult?.rows || pageResult?.records || []))
return (Array.isArray(data) ? data : []).filter((item) => item && item.id !== undefined && item.id !== null)
}
function handleConfirm() {
if (!selectedId.value) {
uni.showToast({ title: t('moldRepair.validatorMoldRequired'), icon: 'none' })
return
}
const mold = moldList.value.find((item) => String(item.id) === String(selectedId.value))
if (!mold) {
uni.showToast({ title: t('moldRepair.validatorMoldRequired'), icon: 'none' })
return
}
getApp().globalData._moldRepairMoldSelectResult = { mold }
uni.navigateBack()
}
function textValue(value) {
if (value === 0) return '0'
if (value === null || value === undefined) return '-'
const text = String(value).trim()
return text || '-'
}
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background: #f5f6f8;
padding-bottom: 140rpx;
}
.search-bar {
padding: 16rpx 24rpx;
background: #fff;
}
.search-input-wrap {
display: flex;
align-items: center;
height: 72rpx;
padding: 0 16rpx;
background: #f5f6f8;
border-radius: 36rpx;
}
.search-icon {
font-size: 32rpx;
color: #999;
margin-right: 12rpx;
}
.search-input {
flex: 1;
font-size: 28rpx;
color: #333;
}
.search-placeholder {
color: #bbb;
}
.search-clear {
font-size: 28rpx;
color: #999;
padding: 8rpx;
}
.mold-list {
padding: 16rpx 24rpx;
}
.mold-card {
background: #fff;
border-radius: 14rpx;
padding: 28rpx 24rpx;
margin-bottom: 16rpx;
border: 2rpx solid transparent;
&.active {
border-color: #2563eb;
background: #f0f5ff;
}
}
.mold-name {
font-size: 30rpx;
font-weight: 700;
color: #1a1a1a;
}
.mold-meta {
display: flex;
align-items: center;
gap: 10rpx;
margin-top: 10rpx;
}
.mold-meta-text {
font-size: 24rpx;
color: #7a8494;
line-height: 1.3;
}
.mold-meta-divider {
font-size: 22rpx;
color: #c3cad5;
}
.empty-wrap {
padding: 120rpx 0;
text-align: center;
}
.empty-text {
font-size: 28rpx;
color: #9ca3af;
}
.bottom-actions {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
gap: 20rpx;
padding: 20rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
background: #fff;
box-shadow: 0 -6rpx 18rpx rgba(15, 23, 42, 0.06);
}
.bottom-btn {
flex: 1;
height: 88rpx;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
font-weight: 600;
}
.confirm-btn {
background: #1f4b79;
color: #fff;
}
</style>
Loading…
Cancel
Save