You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
541 lines
14 KiB
541 lines
14 KiB
<script lang="ts" setup>
|
|
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'
|
|
|
|
import { FtMessage } from '@/libs/message'
|
|
import { compareJSON, convertValuesToInt, convertValuesToString } from '@/libs/utils'
|
|
import { useFormulaStore } from '@/stores/formulaStore'
|
|
|
|
/**
|
|
* 配方表单组件 - 用于配置和管理各种配方参数
|
|
* 支持三种模式:主页模式(home)、设置模式(setting)和配方管理模式(formula)
|
|
* @component
|
|
* @props {string} type - 组件使用模式,可选值:'home' | 'setting' | 'formula'
|
|
*/
|
|
|
|
const props = defineProps<{
|
|
type: string
|
|
}>()
|
|
|
|
const nameLeng = 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',
|
|
max_humidity: '%RH',
|
|
pre_heat_time_s: '秒',
|
|
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) => {
|
|
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 (newVal && newVal.toString().length > nameLeng) {
|
|
inputValue.value = formData.value[focusedInput.value]
|
|
return
|
|
}
|
|
formData.value[focusedInput.value] = newVal
|
|
}
|
|
}
|
|
})
|
|
|
|
/**
|
|
* 获取当前表单数据,将值转换为字符串格式
|
|
* @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="配方名称"
|
|
maxlength="10"
|
|
: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: 40px;
|
|
}
|
|
::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>
|