|
|
<script lang="ts" setup> import { ElMessage } from 'element-plus' import { formulaNameMap } from 'libs/constant' import { cloneDeep } from 'lodash' import { useHomeStore } from 'stores/homeStore' import { computed, inject, nextTick, onMounted, ref, watch, watchEffect } from 'vue'
import { FtMessage } from '@/libs/message' import { convertValuesToString } from '@/libs/utils' import { useFormulaStore } from '@/stores/formulaStore'
const homeStore = useHomeStore()
const formulaStore = useFormulaStore()
const isFlip = ref(true) /** * 当前表单数据 */ const formData = ref<Record<string, any>>({})
/** * 软键盘当前输入值 */ const inputValue = ref<string>('')
/** * 当前聚焦的输入字段名称 */ const focusedInput = ref<string | null>(null)
/** * 注册孙子组件方法的注入函数 */ const registerGrandsonMethods = inject<(methods: any) => void>('registerGrandsonMethods', () => {})
/** * 配方配置列表 */ const formulaConfigList = ref(formulaStore.formulaConfigList)
/** * 标签单位映射表,用于显示各参数的单位 */ const labelUnitMap: Record<string, any> = formulaStore.labelUnitMap
onMounted(() => { formulaStore.getFormualDefaultData() // 获取表单的配置信息
registerGrandsonMethods && registerGrandsonMethods({ getFormData }) formulaStore.initFormulaList() // 更新列表数据
}) /** * 组件挂载时注册方法供父组件调用 */ watchEffect(() => { if (formulaStore.currentSelectedIndex === null) { formData.value = cloneDeep(formulaStore.defaultFormulaInfo || {}) } else { formData.value = cloneDeep(formulaStore.currentSelectedFormulaInfo || {}) } isFlip.value = formulaStore.flip // 后端给的数据类型是字符串型,前端需要的是int型,后端开发说(赵贺)后端不好转换,由前端进行转换.
formData.value = convertValuesToString(formData.value, 'name') })
const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
/** * 获取当前表单数据,将值转换为字符串格式 * @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 }, ) watch( () => formulaStore.currentSelectedIndex, () => { formRef.value?.clearValidate() }, ) const formRef = ref()
/** * 处理表单提交 * 根据不同的type属性值执行不同的保存逻辑 */ const handleSubmit = async () => { // 表单验证
try { const valid = await formRef.value.validate() if (!valid) { return } if (formData.value.formula_id) { // 修改配方
// 判断消毒是否正在执行 且正在执行配方是当前修改配方
if (!deviceState.value && formulaStore.selectedFormulaInfo?.formula_id === formData.value.formula_id) { ElMessage.warning('禁止修改正在执行的配方信息!') return } const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name') formulaStore .editFormula(formulaForm.formula_id, formulaForm as Formula.FormulaItem) .then(() => { FtMessage.success('操作成功') formulaStore.initFormulaList('edit') if (formData.value.formula_id === formulaStore.selectedFormulaInfo?.formula_id) { formulaStore.selectedFormulaInfo = formulaForm as Formula.FormulaItem } }) .catch((e) => { console.log(e) }) } else { // 新增配方
formulaStore.onAddFormula().then((res) => { if (res.ackcode === 0) { const item = res.rely const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name') formulaForm.formula_id = item.formula_id formulaStore .editFormula(item.formula_id, formulaForm as Formula.FormulaItem) .then(() => { FtMessage.success('操作成功') formulaStore.initFormulaList('add') }) .catch((e) => { console.log(e) }) } }) } } catch (e) { console.log(e) } } /** * @computed 计算属性 - 设备状态判断 * @returns {boolean} - 设备是否处于空闲或已完成状态 * @desc 控制按钮可用状态 */ const deviceState = computed(() => { return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished' })
const size = 'default' // 新增配方方法
const addFormula = async () => { formData.value = cloneDeep(formulaStore.defaultFormulaInfo) // formData.value = convertValuesToInt(formulaInfo)
await nextTick() // 等待DOM更新
formData.value.name = '' formData.value.formula_id = null }
// 暴露方法给父组件
defineExpose({ addFormula, }) const validatePass = (rule: any, value: any, callback: any, config: Formula.FormulaConfig) => { if (!value && value !== 0 && value !== '0') { callback(new Error('此为必填项')) } else if (value.substring(0, 1) === '.' || value.split('.').length > 2) { callback(new Error('输入数值项')) } else if (config.val_type === 'int' || config.val_type === 'float') { const temp = Number(value) if (temp < config.val_lower_limit || temp > config.val_upper_limit) { callback(new Error(`输入范围为${config.val_lower_limit}-${config.val_upper_limit}`)) } } callback() } const validateName = (rule: any, value: any, callback: any) => { if (!value && value !== 0 && value !== '0') { callback(new Error('配方名称不能为空')) } else if (value.length > 20) { callback(new Error('配方名称1-20个字符')) } callback() } </script>
<template> <transition name="slide-right"> <div v-if="isFlip" class="formula-form"> <el-form ref="formRef" :model="formData" class="form-box" label-width="auto" label-position="right" :size="size" inline > <el-form-item label="配方名称" style="width: 93%" prop="name" :rules="[ { required: true, validator: (rule, value, callback) => validateName(rule, value, callback), trigger: 'blur', }, ]" > <ft-input v-model="formData.name" name="name" placeholder="配方名称" /> </el-form-item> <el-form-item v-for="item in formulaConfigList.filter(data => data.is_visible_in_formula_page)" :key="item.setting_id" :label="formulaNameMap[item.setting_id]" style="width: 50%" :prop="item.setting_id" :rules="[ { required: true, validator: (rule, value, callback) => validatePass(rule, value, callback, item), trigger: 'blur', }, ]" > <template v-if="item.val_type === 'int'"> <ft-input v-model="formData[item.setting_id]" style="width: 80%" layout-name="number"> <template v-if="labelUnitMap[item.setting_id]" #append> {{ labelUnitMap[item.setting_id] }} </template> </ft-input> </template> <template v-if="item.val_type === 'float'"> <ft-input v-model="formData[item.setting_id]" layout-name="number" style="width: 80%"> <template v-if="labelUnitMap[item.setting_id]" #append> {{ labelUnitMap[item.setting_id] }} </template> </ft-input> </template> <template v-else-if="item.val_type === 'enum'"> <el-select v-model="formData[item.setting_id]" style="width: 80%" placeholder="请选择" readonly> <el-option v-for="log in item.enums" :key="log" :label="log" :value="log" /> </el-select> </template> <template v-else-if="item.val_type === 'boolean'"> <el-radio-group v-model="formData[item.setting_id]"> <el-radio :label="true"> 是 </el-radio> <el-radio :label="false"> 否 </el-radio> </el-radio-group> </template> </el-form-item> </el-form> <div class="default-btn"> <el-button type="primary" class="config-btn" @click="handleSubmit"> 确定 </el-button> </div> </div> </transition> </template>
<style lang="scss" scoped> .formula-form { font-size: 20px !important; align-items: center; height: 100%; .form-box { height: calc(100% - 50px); overflow: auto; } .default-btn { height: 50px; display: flex; justify-content: center; align-items: center; .el-button { width: 100px; } } }
.formula-form-item { display: grid; grid-template-columns: 1fr 1fr; }
.formData-input-config { width: 10vw; } :deep(.el-input__inner) { text-align: left; height: 40px; } :deep(.el-select) { height: 42px; } :deep(.el-select__wrapper) { height: 42px; } :deep(.el-form-item) { margin-right: 0; align-items: center; } :deep(.el-input-group__append) { font-size: 12px; padding: 0 1vw; } /* 进入动画的初始状态 */ .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>
|