|
|
<script lang="ts" setup> import { FtMessage } from '@/libs/message' import { compareJSON, convertValuesToInt, convertValuesToString } from '@/libs/utils' import { useFormulaStore } from '@/stores/formulaStore' import { sendCmd, syncSendCmd } from 'apis/system' import SelectModal from 'components/common/SelectModal/index.vue' import SoftKeyboard from 'components/common/SoftKeyboard/index.vue' import { formulaNameMap } from 'libs/constant' import { cloneDeep } from 'lodash' import { inject, onMounted, ref, watch, watchEffect } from 'vue'
/** * 配方表单组件 - 用于配置和管理各种配方参数 * 支持三种模式:主页模式(home)、设置模式(setting)和配方管理模式(formula) * @component * @props {string} type - 组件使用模式,可选值:'home' | 'setting' | 'formula' */
const props = defineProps<{ type: string }>()
const nameLength = 10
const formulaStore = useFormulaStore()
const targetInputRef = ref<HTMLInputElement | null>(null)
const isFlip = ref(true) /** * 当前表单数据 * 不同模式下有不同的初始值: * - home: 当前选中的配方 * - setting: 默认配方信息 * - formula: 当前选中的配方或默认配方 */ const formData = ref<Record<string, any>>({ ...formulaStore.defaultFormulaInfo, })
/** * 软键盘当前输入值 */ const inputValue = ref<string>('')
/** * 软键盘是否可见 */ const keyboardVisible = ref(false)
/** * 软键盘类型:'text' 或 'number' */ const keyboardType = ref<'text' | 'number'>('number')
/** * 软键盘组件引用 */ const softKeyboardRef = ref()
/** * 当前聚焦的输入字段名称 */ const focusedInput = ref<string | null>(null)
/** * 注册孙子组件方法的注入函数 */ const registerGrandsonMethods = inject<(methods: any) => void>('registerGrandsonMethods', () => {})
/** * 配方配置列表 */ const formulaConfigList = ref(formulaStore.formulaConfigList)
/** * 日志级别选项列表 */ const options = ref(formulaStore.logLevelOptions)
/** * 标签单位映射表,用于显示各参数的单位 */ const labelUnitMap: Record<string, any> = { injection_pump_speed: 'g/min', continued_gs: 'ppm', stoped_gs: 'ppm', continued_humi: '%RH', stoped_humi: '%RH', continued_satur: '%RS', stoped_satur: '%RS', loglevel: 'Log', }
const currentFormulaItem = ref()
/** * 组件挂载时注册方法供父组件调用 */ onMounted(() => { registerGrandsonMethods && registerGrandsonMethods({ getFormData }) })
/** * 模态框是否打开 */ const isModalOpen = ref(false)
/** * 打开模态框 */ const openModal = () => { isModalOpen.value = true }
/** * 监听配方配置列表和表单数据变化 * 根据不同的type属性值初始化表单数据 */ watchEffect(() => { formulaConfigList.value = formulaStore.formulaConfigList if (props.type === 'home') { formData.value = cloneDeep(formulaStore.selectedFormulaInfo) || cloneDeep(formulaStore.defaultFormulaInfo) } else if (props.type === 'setting') { formData.value = cloneDeep(formulaStore.defaultFormulaInfo) } else { formData.value = cloneDeep(formulaStore.currentSelectedFormulaInfo) || cloneDeep(formulaStore.defaultFormulaInfo) } isFlip.value = formulaStore.flip // 后端给的数据类型是字符串型,前端需要的是int型,后端开发说(赵贺)后端不好转换,由前端进行转换.
formData.value = convertValuesToInt(formData.value) })
/** * 监听软键盘输入值变化,更新表单数据 * @param {string | number} newVal - 新的输入值 */ watch(inputValue, (newVal: string | number) => { console.log('inputValue-----------', inputValue) if (focusedInput.value) { if (focusedInput.value !== 'name') { newVal = Number(newVal) if (currentFormulaItem.value && newVal > currentFormulaItem.value.val_upper_limit) { newVal = currentFormulaItem.value.val_upper_limit } formData.value[focusedInput.value] = newVal } else { if (formData.value.name && formData.value.name.length > nameLength) { inputValue.value = formData.value.name } } } })
// watch(formData, (newVal) => {
// if (newVal && newVal.length > nameLength) {
// formData.value.name = newVal.name.slice(0, nameLength)
// }
// }, { deep: true })
/** * 获取当前表单数据,将值转换为字符串格式 * @returns {Record<string, string>} 转换后的表单数据 */ const getFormData = () => { return convertValuesToString(formData.value, 'name') }
/** * 监听表单数据变化,同步更新软键盘输入值 * @param {Record<string, any>} newValue - 新的表单数据 */ watch(formData, (newValue) => { if (focusedInput.value) { inputValue.value = newValue[focusedInput.value].toString() } }, { deep: true })
/** * 处理表单提交 * 根据不同的type属性值执行不同的保存逻辑 */ const handleSubmit = () => { if (props.type !== 'setting' && !formData.value.name) { FtMessage.warning('请输入配方名称') return }
// 配方管理的【确定】
if (props.type === 'formula') { onSaveFormula() }
// 设置中的【确定】
if (props.type === 'setting') { onSaveSetting() } }
/** * 保存配方 * 根据是否有formula_id决定是添加新配方还是编辑已有配方 */ const onSaveFormula = () => { if (formData.value.formula_id) { const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name') onEditFormula(formulaForm.formula_id, formulaForm as Formula.FormulaItem) } else { onAddFormula() } }
/** * 保存设置 * 比较当前表单数据与默认配方数据的差异,只更新有变化的字段 */ const onSaveSetting = async () => { // 修改默认值
const diff = compareJSON(formulaStore.defaultFormulaInfo, formData.value) const diffKeys = Object.keys(diff) if (diffKeys.length) { await Promise.all(diffKeys.map(async (key) => { await setSettingFormulaConfig(key, diff[key].newVal) })) FtMessage.success('配方修改成功') } }
/** * 设置配方配置项值 * @param {string} settingName - 设置名称 * @param {string} settingVal - 设置值 * @returns {Promise<void>} */ const setSettingFormulaConfig = async (settingName: string, settingVal: string) => { await sendCmd({ className: 'SettingMgrService', fnName: 'setSettingVal', params: { settingName, settingVal: settingVal.toString(), }, }) formulaStore.getFormualDefaultData() }
/** * 添加新配方 * 先调用API创建新配方,然后更新配方数据 */ const onAddFormula = () => { const params = { className: 'SettingMgrService', fnName: 'addNewFormula', } syncSendCmd(params).then((res) => { if (res.ackcode === 0) { const item = res.rely const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name') // formulaForm.name = item.name
formulaForm.formula_id = item.formula_id onEditFormula(item.formula_id, formulaForm as Formula.FormulaItem) } }) }
/** * 编辑配方 * @param {string} formula_id - 配方ID * @param {Formula.FormulaItem} formulaForm - 配方表单数据 */ const onEditFormula = (formula_id: string, formulaForm: Formula.FormulaItem) => { const editParams = { className: 'SettingMgrService', fnName: 'updateFormula', params: { formula_id, formula: cloneDeep(formulaForm), }, } syncSendCmd(editParams).then(() => { FtMessage.success('操作成功') formulaStore.initFormulaList() // formData.value = formulaForm
formulaStore.updateSelectedFormulaData(formulaForm) }) }
/** * 打开软键盘 * @param {Event} e - 事件对象 * @param item */ const openKeyboard = (e: any, item: Formula.FormulaItem) => { setTimeout(() => { keyboardVisible.value = true const labelName: string = e.target.name openKeyboardType(labelName) const formValue = formData.value[labelName] inputValue.value = formValue.toString() focusedInput.value = e.target.name currentFormulaItem.value = item
const inputDom = e.target as HTMLInputElement targetInputRef.value = inputDom }, 100) }
/** * 取消操作,重置配方数据 */ const handleCancel = () => { formulaStore.initFormulaData() }
/** * 恢复默认设置 */ const handleResetDefault = async () => { await sendCmd({ className: 'SettingMgrService', fnName: 'factoryResetSettings', }) await formulaStore.getFormualDefaultData() }
/** * 确认输入值 * @param {string} value - 输入值 */ const handleConfirm = (value: string) => { console.log('确认输入:', value) }
/** * 确认日志级别选择 * @param {any} value - 选择的值 */ const handleLogConfirm = (value: any) => { isModalOpen.value = false formData.value.loglevel = value formulaStore.loglevel = value }
/** * 取消日志级别选择 */ const handleLogCancel = () => { isModalOpen.value = false }
/** * 根据标签名称确定软键盘类型 * @param {string} labelName - 标签名称 */ const openKeyboardType = (labelName: string) => { keyboardType.value = labelName === 'name' ? 'text' : 'number' } </script>
<template> <transition name="slide-right"> <div v-if="isFlip" class="formula-form"> <el-form :model="formData" label-width="auto" label-position="right" class="formulaFormItem" inline> <el-form-item v-if="type !== 'setting'" label="配方名称" style="margin-top:20px"> <el-input v-model="formData.name" v-prevent-keyboard name="name" placeholder="配方名称" :disabled="type === 'home'" class="formdata-input-home" @focus="openKeyboard" /> </el-form-item> <el-form-item v-for="(item) in formulaConfigList" :key="item.setting_id" :label="formulaNameMap[item.setting_id]" style="margin-top:20px" > <template v-if="item.val_type === 'int'"> <el-input v-model.number="formData[item.setting_id]" v-prevent-keyboard type="number" :name="item.setting_id" :controls="false" class="formdata-input-home" :disabled="!item.is_visible_in_setting_page" @focus="(e) => openKeyboard(e, item)" > <template v-if="labelUnitMap[item.setting_id]" #append>{{ labelUnitMap[item.setting_id] }}</template> </el-input> </template> <template v-else-if="item.val_type === 'enum'"> <el-input v-model="formData[item.setting_id]" v-prevent-keyboard placeholder="请选择" class="formdata-input-home" readonly @focus="openModal" > <template #append>{{ labelUnitMap[item.setting_id] }}</template> </el-input> </template> <template v-else-if="item.val_type === 'boolean'"> <el-radio-group v-model="formData[item.setting_id]" class="formdata-input-home" :disabled="!item.is_visible_in_setting_page" > <el-radio :label="true"> 是 </el-radio> <el-radio :label="false"> 否 </el-radio> </el-radio-group> </template> </el-form-item> </el-form> <div v-if="type !== 'home'" class="formula-form-btn" :style="{ marginLeft: '33%' }"> <slot name="formulaBtn"> <div class="default-btn"> <el-button type="primary" class="config-btn" @click="handleSubmit"> 确定 </el-button> <el-button v-if="type === 'setting'" class="config-btn" @click="handleResetDefault"> 恢复默认值 </el-button> <el-button v-else class="config-btn" @click="handleCancel"> 取消 </el-button> </div> </slot> </div> <Teleport to="body"> <SoftKeyboard ref="softKeyboardRef" v-model="inputValue" :is-visible="keyboardVisible" :keyboard-type="keyboardType" :target-input="targetInputRef" @confirm="handleConfirm" @update-keyboard-visible="(visible) => keyboardVisible = visible" @close="keyboardVisible = false" /> </Teleport> <SelectModal v-if="isModalOpen" :options="options" :selected-value="formData.loglevel" placeholder="请选择" @confirm="handleLogConfirm" @cancel="handleLogCancel" /> </div> </transition> </template>
<style lang="scss" scoped> .formula-form{ font-size: 20px !important; padding: 5px; padding-left: 15px; height: 81vh; overflow: auto; .formulaFormItem{ display: grid; grid-template-columns: 1fr 1fr; } .formula-form-btn{ } .default-btn{ margin-top: 1rem; } .config-btn{ height: 3rem; width: 8rem; } }
.formdata-input-home{ width: 15vw; }
.formula-form-item{ display: grid; grid-template-columns: 1fr 1fr; }
.formData-input-config{ width: 10vw; } ::v-deep .el-input__inner{ text-align: left; } ::v-deep .el-form-item{ margin-right: 0; } ::v-deep .el-input__inner{ height: 45px; } ::v-deep .el-form-item{ align-items: center; }
/* 进入动画的初始状态 */ .slide-right-enter-from { transform: translateX(100%); } /* 进入动画的结束状态(也可以理解为激活状态) */ .slide-right-enter-to { transform: translateX(0); } /* 进入动画的过渡曲线等 */ .slide-right-enter-active { transition: transform 0.3s ease-in-out; } /* 离开动画的初始状态(激活状态) */ .slide-right-leave-from { transform: translateX(0); } /* 离开动画的结束状态 */ .slide-right-leave-to { transform: translateX(100%); } /* 离开动画的过渡曲线等 */ .slide-right-leave-active { transition: transform 0.3s ease-in-out; } </style>
|