From 36d41897b36fc174b0269442caf7e504e98905de Mon Sep 17 00:00:00 2001 From: zhongwenkai <3478244299@qq.com> Date: Thu, 11 Jun 2026 17:19:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=8A=E4=B8=8B=E6=A8=A1=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=96=B0=E5=A2=9E=E6=93=8D=E4=BD=9C=E4=BA=BA=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E4=B8=8E=E5=A4=87=E6=B3=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/en-US.js | 3 + src/locales/zh-CN.js | 3 + .../pages/moldoperate/dismount.vue | 231 ++++++++++++++++- .../pages/moldoperate/index.vue | 234 +++++++++++++++++- 4 files changed, 467 insertions(+), 4 deletions(-) diff --git a/src/locales/en-US.js b/src/locales/en-US.js index 362ec8e..5c80b77 100644 --- a/src/locales/en-US.js +++ b/src/locales/en-US.js @@ -338,6 +338,7 @@ export default { validatorOperateTypeRequired: 'Operation type is required', validatorDeviceRequired: 'Device is required', validatorMoldRequired: 'Select at least one mold for mounting', + validatorOperatorRequired: 'Please select operator', validatorLowerMoldRequired: 'Select at least one mold for dismounting', loadEditFailed: 'Failed to load edit data', confirmDelete: 'Confirm delete this mold operate record?', @@ -372,6 +373,8 @@ export default { historySuffix: ' History', historyTitle: 'Mold Operate History', searchPlaceholder: 'Search device/mold name', + operator: 'Operator', + placeholderOperator: 'Select operator', filterAll: 'All', filterToday: 'Today', filterWeek: 'This Week', diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js index 01e0b99..ea2ae7f 100644 --- a/src/locales/zh-CN.js +++ b/src/locales/zh-CN.js @@ -338,6 +338,7 @@ export default { validatorOperateTypeRequired: '操作类型不能为空', validatorDeviceRequired: '设备不能为空', validatorMoldRequired: '请至少选择一个上模模具', + validatorOperatorRequired: '请选择操作人', validatorLowerMoldRequired: '请至少选择一个下模模具', loadEditFailed: '加载编辑数据失败', confirmDelete: '确认删除该上下模记录吗?', @@ -372,6 +373,8 @@ export default { historySuffix: '历史', historyTitle: '上下模历史', searchPlaceholder: '搜索设备/模具名称', + operator: '操作人', + placeholderOperator: '请选择操作人', filterAll: '全部', filterToday: '今天', filterWeek: '本周', diff --git a/src/pages_function/pages/moldoperate/dismount.vue b/src/pages_function/pages/moldoperate/dismount.vue index 3ca9a14..7a320c0 100644 --- a/src/pages_function/pages/moldoperate/dismount.vue +++ b/src/pages_function/pages/moldoperate/dismount.vue @@ -113,6 +113,60 @@ + + + + + {{ t('moldOperate.operator') + ' & ' + t('moldOperate.remark') }} + + + + + *{{ t('moldOperate.operator') }} + + + + {{ selectedOperator ? selectedOperator.label : t('moldOperate.placeholderOperator') }} + + + + + + + {{ item.label }} + + + 暂无数据 + + + + + + + + {{ t('moldOperate.remark') }} + + + + + + {{ t('moldOperate.confirmDismount') }} @@ -150,6 +204,7 @@ import { onShow } from '@dcloudio/uni-app' import { useI18n } from 'vue-i18n' import { getLowerMoldList, getDeviceLedgerList, createMoldOperate } from '@/api/mes/moldoperate' import { getDeviceLineTree } from '@/api/mes/deviceLine' +import { getSimpleUserList } from '@/api/system/user' const { t } = useI18n() @@ -225,6 +280,13 @@ const lowerMoldLoading = ref(false) const moldsLoaded = ref(false) const tempSelectedMoldId = ref(null) +// ---- 操作人与备注 ---- +const remarkText = ref('') +const operatorOptions = ref([]) +const selectedOperator = ref(null) +const operatorIndex = ref(-1) +const showOperatorDropdown = ref(false) + // ---- 工具函数 ---- function textValue(v) { if (v === 0) return '0' @@ -442,6 +504,34 @@ function confirmLowerMoldSelection() { function closeLowerMoldPicker() { lowerMoldPickerRef.value?.close() } +// ---- 操作人列表加载 ---- +async function loadOperators() { + try { + const res = await getSimpleUserList() + const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : []) + operatorOptions.value = data.map((u) => ({ + value: u.id || u.userId, + label: u.nickname || u.userName || u.name || String(u.id || '') + })) + } catch (e) { + console.error('loadOperators error', e) + } +} + +function toggleOperatorDropdown() { + showOperatorDropdown.value = !showOperatorDropdown.value +} + +function closeOperatorDropdown() { + showOperatorDropdown.value = false +} + +function handleSelectOperator(item, idx) { + selectedOperator.value = item + operatorIndex.value = idx + closeOperatorDropdown() +} + function goToHistory() { uni.navigateTo({ url: '/pages_function/pages/moldoperate/history?type=down' }) } @@ -460,6 +550,10 @@ function validForm() { uni.showToast({ title: t('moldOperate.validatorLowerMoldRequired'), icon: 'none' }) return false } + if (!selectedOperator.value) { + uni.showToast({ title: t('moldOperate.validatorOperatorRequired'), icon: 'none' }) + return false + } return true } @@ -474,6 +568,13 @@ async function handleConfirm() { lineId: device.deviceLine != null ? String(device.deviceLine) : undefined, lineName: device.deviceLine != null ? getTopLineName(device.deviceLine) : (device.lineName || undefined) } + // 添加操作人和备注 + if (selectedOperator.value) { + payload.operatorId = selectedOperator.value.value + } + if (remarkText.value.trim()) { + payload.remark = remarkText.value.trim() + } console.log('[下模] 提交参数 =', JSON.stringify(payload)) await createMoldOperate(payload) uni.showToast({ title: t('functionCommon.createSuccess'), icon: 'success' }) @@ -489,6 +590,9 @@ async function handleConfirm() { selectedDevice.value = {} selectedMold.value = {} lowerMoldOptions.value = [] + remarkText.value = '' + selectedOperator.value = null + operatorIndex.value = -1 } catch (e) { console.error('[下模] 保存失败 =', e) const errMsg = e?.msg || (typeof e === 'string' ? e : e?.message) || '系统异常' @@ -497,7 +601,7 @@ async function handleConfirm() { } onShow(async () => { - await Promise.allSettled([loadDevices(), loadLineTree()]) + await Promise.allSettled([loadDevices(), loadLineTree(), loadOperators()]) // 从 globalData 读取设备选择页回传的设备 const device = getApp().globalData._deviceSelectResult if (device) { @@ -606,7 +710,6 @@ onShow(async () => { margin: 16rpx 24rpx; background: #ffffff; border-radius: 14rpx; - overflow: hidden; } .section-title-bar { @@ -735,6 +838,130 @@ onShow(async () => { } } +/* ====== 表单行(操作人/备注) ====== */ +.form-row { + margin-top: 18rpx; + + &:first-child { + margin-top: 0; + } +} + +.form-cell { + width: 100%; + + .form-label { + display: block; + font-size: 24rpx; + color: #999; + margin-bottom: 8rpx; + + .required { + color: #dc2626; + margin-right: 4rpx; + } + } +} + +/* ====== 下拉选择器(操作人) ====== */ +.select-dropdown { + position: relative; + width: 100%; +} + +.dropdown-input { + display: flex; + align-items: center; + height: 72rpx; + padding: 0 20rpx; + border: 1rpx solid #e0e0e0; + border-radius: 10rpx; + font-size: 27rpx; + color: #333; + background: #f9fafb; +} + +.dropdown-value { + flex: 1; + + &.placeholder { + color: #bbb; + } +} + +.dropdown-arrow { + position: absolute; + right: 16rpx; + top: 50%; + transform: translateY(-50%); + pointer-events: none; +} + +/* ====== 下拉面板(在输入框下方展开) ====== */ +.dropdown-panel { + position: absolute; + top: 76rpx; + left: 0; + right: 0; + z-index: 99; + background: #ffffff; + border: 1rpx solid #e0e0e0; + border-radius: 12rpx; + box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1); + overflow: hidden; +} + +.dropdown-scroll { + max-height: 400rpx; +} + +.dropdown-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 22rpx 28rpx; + font-size: 27rpx; + color: #333; + border-bottom: 1rpx solid #f5f5f5; + + &:last-child { + border-bottom: none; + } + + &:active { + background: #f5f7fa; + } + + &.active { + color: #1f7cff; + background: #f0f7ff; + } +} + +.dropdown-item-text { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dropdown-empty { + padding: 32rpx; + text-align: center; + font-size: 26rpx; + color: #999; +} + +.form-input { + height: 72rpx; + padding: 0 20rpx; + border: 1rpx solid #e0e0e0; + border-radius: 10rpx; + font-size: 27rpx; + color: #333; + background: #f9fafb; +} + /* ====== 空提示 ====== */ .empty-mold-hint { padding: 40rpx 24rpx; diff --git a/src/pages_function/pages/moldoperate/index.vue b/src/pages_function/pages/moldoperate/index.vue index 682000c..2b0346f 100644 --- a/src/pages_function/pages/moldoperate/index.vue +++ b/src/pages_function/pages/moldoperate/index.vue @@ -107,6 +107,62 @@ + + + + + {{ t('moldOperate.operator') + ' & ' + t('moldOperate.remark') }} + + + + + *{{ t('moldOperate.operator') }} + + + + + {{ selectedOperator ? selectedOperator.label : t('moldOperate.placeholderOperator') }} + + + + + + + + {{ item.label }} + + + 暂无数据 + + + + + + + + {{ t('moldOperate.remark') }} + + + + + + {{ t('functionCommon.cancel') }} @@ -121,6 +177,7 @@ import { computed, ref } from 'vue' import { onShow } from '@dcloudio/uni-app' import { useI18n } from 'vue-i18n' import { getDeviceLedgerList, createMoldOperate } from '@/api/mes/moldoperate' +import { getSimpleUserList } from '@/api/system/user' const { t } = useI18n() @@ -160,6 +217,10 @@ const selectedDevice = ref({}) const selectedMountMolds = ref([]) const tempSelectedDeviceId = ref(null) +const remarkText = ref('') +const operatorOptions = ref([]) +const selectedOperator = ref(null) +const operatorIndex = ref(-1) // 设备状态 - 上模 const deviceStatusClass = computed(() => { @@ -241,6 +302,36 @@ const currentMoldDisplay = computed(() => { return textValue(selectedDevice.value.currentMold) }) +// ---- 操作人列表加载 ---- +async function loadOperators() { + try { + const res = await getSimpleUserList() + const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : []) + operatorOptions.value = data.map((u) => ({ + value: u.id || u.userId, + label: u.nickname || u.userName || u.name || String(u.id || '') + })) + } catch (e) { + console.error('loadOperators error', e) + } +} + +const showOperatorDropdown = ref(false) + +function toggleOperatorDropdown() { + showOperatorDropdown.value = !showOperatorDropdown.value +} + +function closeOperatorDropdown() { + showOperatorDropdown.value = false +} + +function handleSelectOperator(item, idx) { + selectedOperator.value = item + operatorIndex.value = idx + closeOperatorDropdown() +} + function selectDevice(device) { selectedDevice.value = device || {} tempSelectedDeviceId.value = device ? device.id : null @@ -272,6 +363,10 @@ function validFormMount() { uni.showToast({ title: t('moldOperate.validatorMoldRequired'), icon: 'none' }) return false } + if (!selectedOperator.value) { + uni.showToast({ title: t('moldOperate.validatorOperatorRequired'), icon: 'none' }) + return false + } return true } @@ -286,6 +381,13 @@ async function handleConfirmMount() { lineName: selectedDevice.value.workshopName || '', lineId: selectedDevice.value.deviceLine || '' } + // 添加操作人和备注 + if (selectedOperator.value) { + payload.operatorId = selectedOperator.value.value + } + if (remarkText.value.trim()) { + payload.remark = remarkText.value.trim() + } console.log('=== 上模提交参数 ===', JSON.stringify(payload)) console.log('=== deviceId type:', typeof payload.deviceId, 'value:', payload.deviceId) console.log('=== moldId type:', typeof payload.moldId, 'value:', payload.moldId) @@ -347,6 +449,9 @@ function handleScan() { function handleCancel() { selectedDevice.value = {} selectedMountMolds.value = [] + remarkText.value = '' + selectedOperator.value = null + operatorIndex.value = -1 } function goBack() { @@ -358,7 +463,7 @@ function goToHistory() { } onShow(async () => { - await Promise.allSettled([loadDevices()]) + await Promise.allSettled([loadDevices(), loadOperators()]) // 从 globalData 读取设备选择页回传的设备 const device = getApp().globalData._deviceSelectResult if (device) { @@ -473,7 +578,6 @@ onShow(async () => { margin: 16rpx 24rpx; background: #ffffff; border-radius: 14rpx; - overflow: hidden; } .section-title-bar { @@ -592,6 +696,132 @@ onShow(async () => { .change-text { font-size: 26rpx; color: #666; } } +/* ====== 表单行(操作人/备注) ====== */ +.form-row { + margin-top: 18rpx; + + &:first-child { + margin-top: 0; + } +} + +.form-cell { + width: 100%; + + .form-label { + display: block; + font-size: 24rpx; + color: #999; + margin-bottom: 8rpx; + + .required { + color: #dc2626; + margin-right: 4rpx; + } + } +} + + + +/* ====== 下拉选择器(操作人) ====== */ +.select-dropdown { + position: relative; + width: 100%; +} + +.dropdown-input { + display: flex; + align-items: center; + height: 72rpx; + padding: 0 20rpx; + border: 1rpx solid #e0e0e0; + border-radius: 10rpx; + font-size: 27rpx; + color: #333; + background: #f9fafb; +} + +.dropdown-value { + flex: 1; + + &.placeholder { + color: #bbb; + } +} + +.dropdown-arrow { + position: absolute; + right: 16rpx; + top: 50%; + transform: translateY(-50%); + pointer-events: none; +} + +/* ====== 下拉面板(在输入框下方展开) ====== */ +.dropdown-panel { + position: absolute; + top: 76rpx; + left: 0; + right: 0; + z-index: 99; + background: #ffffff; + border: 1rpx solid #e0e0e0; + border-radius: 12rpx; + box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1); + overflow: hidden; +} + +.dropdown-scroll { + max-height: 400rpx; +} + +.dropdown-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 22rpx 28rpx; + font-size: 27rpx; + color: #333; + border-bottom: 1rpx solid #f5f5f5; + + &:last-child { + border-bottom: none; + } + + &:active { + background: #f5f7fa; + } + + &.active { + color: #1f7cff; + background: #f0f7ff; + } +} + +.dropdown-item-text { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dropdown-empty { + padding: 32rpx; + text-align: center; + font-size: 26rpx; + color: #999; +} + +.form-input { + height: 72rpx; + padding: 0 20rpx; + border: 1rpx solid #e0e0e0; + border-radius: 10rpx; + font-size: 27rpx; + color: #333; + background: #f9fafb; +} + /* ====== 空提示 ====== */ .empty-mold-hint { padding: 40rpx 24rpx;