Browse Source

运行参数和消毒设置分开

master
王梦远 2 weeks ago
parent
commit
ff9e382745
  1. 34
      src/components/formula/HomeFormulaConfig.vue
  2. 196
      src/components/formula/RunFormulaConfig.vue
  3. 114
      src/components/home/HomeSetting.vue
  4. 46
      src/components/home/Runtime.vue
  5. 4
      src/components/home/config.vue
  6. 18
      src/stores/formulaStore.ts

34
src/components/formula/HomeFormulaConfig.vue

@ -5,9 +5,6 @@ import { inject, onMounted, ref, watchEffect } from 'vue'
import { convertValuesToInt, convertValuesToString } from '@/libs/utils'
import { useFormulaStore } from '@/stores/formulaStore'
const props = defineProps<{
formulaNameVisible: boolean
}>()
const formulaStore = useFormulaStore()
/**
* 获取当前表单数据将值转换为字符串格式
@ -36,25 +33,13 @@ const labelUnitMap: Record<string, any> = formulaStore.labelUnitMap
* 监听事件
*/
watchEffect(() => {
formData.value = formulaStore.selectedFormulaInfo !== null ? convertValuesToInt(formulaStore.selectedFormulaInfo) : convertValuesToInt(formulaStore.defaultFormulaInfo)
formData.value = formulaStore.selectedFormulaInfo !== null ? convertValuesToInt(formulaStore.selectedFormulaInfo) : convertValuesToInt(formulaStore.defaultFormulaInfo as Record<string, any>)
})
/**
* 配方配置列表
*/
const formulaConfigList = formulaStore.formulaConfigList
const size = 'default'
const validatePass = (rule: any, value: any, callback: any, config: Formula.FormulaConfig) => {
if (!value && value !== 0 && value !== '0') {
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()
}
</script>
<template>
@ -66,7 +51,7 @@ const validatePass = (rule: any, value: any, callback: any, config: Formula.Form
:size="size"
inline
>
<el-form-item v-if="props.formulaNameVisible" label="配方名称" style="width: 93%">
<el-form-item label="配方名称" style="width: 93%">
<el-input
v-model="formData.name"
v-prevent-keyboard
@ -81,13 +66,6 @@ const validatePass = (rule: any, value: any, callback: any, config: Formula.Form
: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'">
<el-input
@ -97,7 +75,7 @@ const validatePass = (rule: any, value: any, callback: any, config: Formula.Form
type="number"
:name="item.setting_id"
:controls="false"
:disabled="!(item.is_editable && !props.formulaNameVisible)"
:disabled="true"
>
<template v-if="labelUnitMap[item.setting_id]" #append>
{{ labelUnitMap[item.setting_id] }}
@ -112,7 +90,7 @@ const validatePass = (rule: any, value: any, callback: any, config: Formula.Form
type="number"
:name="item.setting_id"
:controls="false"
:disabled="!(item.is_editable && !props.formulaNameVisible)"
:disabled="true"
>
<template v-if="labelUnitMap[item.setting_id]" #append>
{{ labelUnitMap[item.setting_id] }}
@ -125,14 +103,14 @@ const validatePass = (rule: any, value: any, callback: any, config: Formula.Form
v-prevent-keyboard
style="width: 80%;height:40px"
placeholder="请选择"
:disabled="!(item.is_editable && !props.formulaNameVisible)"
:disabled="true"
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]" :disabled="!item.is_editable">
<el-radio-group v-model="formData[item.setting_id]" :disabled="true">
<el-radio :label="true">
</el-radio>

196
src/components/formula/RunFormulaConfig.vue

@ -0,0 +1,196 @@
<script lang="ts" setup>
import { formulaNameMap } from 'libs/constant'
import { inject, onMounted, ref, watchEffect } from 'vue'
import { convertValuesToInt, convertValuesToString } from '@/libs/utils'
import { useFormulaStore } from '@/stores/formulaStore'
const formulaStore = useFormulaStore()
const runtimeFormRef = ref()
const saveFormData = () => {
runtimeFormRef.value.validate((valid: any) => {
if (valid) {
return convertValuesToString(formData.value, 'name')
}
return null
})
}
/**
* 注册孙子组件方法的注入函数
*/
const registerGrandsonMethods = inject<(methods: any) => void>('registerGrandsonMethods', () => {})
onMounted(() => {
registerGrandsonMethods && registerGrandsonMethods({ saveFormData })
})
/**
* 当前表单数据
* - home: 当前选中的配方 或者默认配方
*/
const formData = ref<Record<string, any>>({})
/**
* 标签单位映射表用于显示各参数的单位
*/
const labelUnitMap: Record<string, any> = formulaStore.labelUnitMap
/**
* 监听事件
*/
watchEffect(() => {
formData.value = convertValuesToInt(formulaStore.getRealtimeConfig())
})
/**
* 配方配置列表
*/
const formulaConfigList = formulaStore.formulaConfigList
const size = 'default'
const validatePass = (rule: any, value: any, callback: any, config: Formula.FormulaConfig) => {
if (!value && value !== 0 && value !== '0') {
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()
}
</script>
<template>
<div class="formula-form">
<el-form
ref="runtimeFormRef"
:model="formData"
label-width="auto"
label-position="right"
:size="size"
inline
>
<el-form-item
v-for="item in formulaConfigList.filter((data) => data.is_visible_in_rt_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'">
<el-input
v-model.number="formData[item.setting_id]"
v-prevent-keyboard
style="width: 80%"
type="number"
:name="item.setting_id"
:controls="false"
:disabled="!(item.is_editable)"
>
<template v-if="labelUnitMap[item.setting_id]" #append>
{{ labelUnitMap[item.setting_id] }}
</template>
</el-input>
</template>
<template v-if="item.val_type === 'float'">
<el-input
v-model.number="formData[item.setting_id]"
v-prevent-keyboard
style="width: 80%"
type="number"
:name="item.setting_id"
:controls="false"
:disabled="!(item.is_editable)"
>
<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-select
v-model="formData[item.setting_id]"
v-prevent-keyboard
style="width: 80%;height:40px"
placeholder="请选择"
:disabled="!(item.is_editable)"
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]" :disabled="!item.is_editable">
<el-radio :label="true">
</el-radio>
<el-radio :label="false">
</el-radio>
</el-radio-group>
</template>
</el-form-item>
</el-form>
</div>
</template>
<style lang="scss" scoped>
.formula-form {
font-size: 20px !important;
padding: 5px;
padding-left: 15px;
align-items: center;
.default-btn {
margin-top: 1rem;
}
.config-btn {
height: 3rem;
width: 8rem;
}
}
.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-form-item) {
margin-right: 0;
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>

114
src/components/home/HomeSetting.vue

@ -1,9 +1,9 @@
<script lang="ts" setup>
import { sendCmd, syncSendCmd } from 'apis/system'
// import homeChart from 'assets/images/home/home-chart.svg'
import { syncSendCmd } from 'apis/system'
import BtButton from 'components/common/BTButton/index.vue'
import CascadingSelectModal from 'components/common/CascadingSelectModal/index.vue'
import Config from 'components/home/config.vue'
import Runtime from 'components/home/Runtime.vue'
import { compareJSON } from 'libs/utils'
import { cloneDeep } from 'lodash'
import { computed, onMounted, provide, ref, watchEffect } from 'vue'
@ -20,9 +20,9 @@ import { useHomeStore } from '@/stores/homeStore'
*/
//
const configRef = ref()
const runtimeRef = ref()
provide<(methods: Home.GrandsonMethods) => void>('registerGrandsonMethods', (methods) => {
configRef.value = methods
runtimeRef.value = methods
})
//
@ -37,7 +37,8 @@ const optionsLeft = ref<System.Option[]>([]) // 压力类型选项(左列)
const optionsRight = ref<System.Option[]>([]) //
const selectedValue = ref() //
const disinfectionState = ref(homeStore.disinfectionState) //
const disinfectFormulaVisible = ref(false) //
const disinfectConfigVisible = ref(false) //
const disinfectRuntimeVisible = ref(false)
const selectedByFormulas = ref(cloneDeep(formulaStore.selectedFormulaInfo)) //
const pressureConfig = ref(homeStore.pressureConfig)
const defaultIntensityValue = ref()
@ -86,17 +87,17 @@ const getPressureConfig = async () => {
const deviceState = computed(() => {
return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
})
const disinfectFormulaTitle = ref<string>('消毒设置')
/**
* @function 打开消毒设置对话框
* @desc 根据当前选中配方或默认配方初始化设置
*/
const onDisinfectConfig = (title: string) => {
const onDisinfectConfig = () => {
formulaStore.updateSelectedFormula(selectedByFormulas.value || cloneDeep(formulaStore.defaultFormulaInfo))
disinfectFormulaVisible.value = true
disinfectFormulaTitle.value = title
disinfectConfigVisible.value = true
}
const onDisinfectRuntime = () => {
disinfectRuntimeVisible.value = true
}
/**
* @function 导航到图表页面
* @desc 路由跳转至消毒图表页面
@ -106,57 +107,30 @@ const onShowChart = () => {
}
/**
* @function 保存消毒参数
* @function 保存消毒运行参数
* @desc 处理表单数据保存逻辑区分消毒中与非消毒状态
*/
const onSave = async () => {
const formData = configRef.value?.getFormData()
const formData = runtimeRef.value?.getFormData()
if (!formData) {
return
}
formulaStore.updateSelectedFormula(cloneDeep(formData)) //
if (!homeStore.isDeviceIdle) {
//
const res = await sendCmd({
className: 'DisinfectionCtrlServiceExt',
fnName: 'getRealtimeConfig',
params: {},
})
const diff = compareJSON(res, formData)
const diffKeys = Object.keys(diff)
if (diffKeys.length) {
await Promise.all(
diffKeys.map(async (key) => {
await setRealtimeConfig(key, diff[key].newVal)
}),
)
FtMessage.success('修改成功')
}
}
else {
//
if (formData.formula_id) {
formulaStore.updateSelectedFormula(formData)
}
//
const res = formulaStore.getRealtimeConfig()
const diff = compareJSON(res, formData)
const diffKeys = Object.keys(diff)
if (diffKeys.length) {
await Promise.all(
diffKeys.map(async (key) => {
await formulaStore.setRealtimeConfig(key, diff[key].newVal)
}),
)
FtMessage.success('修改成功')
}
onClose() //
onCloseRuntime() //
}
/**
* @function 设置实时消毒参数
* @param {string} key - 参数键名
* @param {string} val - 参数值
* @desc 向设备发送实时参数修改指令
*/
const setRealtimeConfig = async (key: string, val: string) => {
await syncSendCmd({
className: 'DisinfectionCtrlServiceExt',
fnName: 'setRealtimeConfig',
params: { key, val },
})
}
/**
* @function 确认压力选择
* @param {string|number[]} value - 选中的压力配置值[类型, 强度]
* @desc 关闭模态框并更新压力配置
@ -178,10 +152,12 @@ const handleCancel = () => {
* @function 关闭消毒设置对话框
* @desc 重置对话框状态
*/
const onClose = () => {
disinfectFormulaVisible.value = false
const onCloseConfig = () => {
disinfectConfigVisible.value = false
}
const onCloseRuntime = () => {
disinfectRuntimeVisible.value = false
}
const settingWidth = computed(() => {
if (__DEVICE_TYPE__ === deviceStore.deviceTypeMap.LargeSpaceDM_B) {
return '12rem'
@ -214,7 +190,7 @@ const settingWidth = computed(() => {
:width="settingWidth"
text-color="#1989fa"
height="3rem"
@click="onDisinfectConfig('消毒设置')"
@click="onDisinfectConfig()"
/>
<BtButton
v-else
@ -224,14 +200,34 @@ const settingWidth = computed(() => {
:width="settingWidth"
text-color="#1989fa"
height="3rem"
@click="onDisinfectConfig('运行参数')"
@click="onDisinfectRuntime()"
/>
</div>
</div>
</div>
<ft-dialog v-model="disinfectFormulaVisible" :title="disinfectFormulaTitle" width="80vw">
<!-- 消毒设置 -->
<ft-dialog v-model="disinfectConfigVisible" title="消毒设置" width="80vw">
<div style="height: 80vh; overflow: auto">
<Config />
</div>
<template #footer>
<div class="config-btn">
<BtButton
button-text="关闭"
border-radius="5px"
width="7rem"
text-size="1.5rem"
text-color="#1989fa"
height="3rem"
@click="onCloseConfig"
/>
</div>
</template>
</ft-dialog>
<!-- 运行参数 -->
<ft-dialog v-model="disinfectRuntimeVisible" title="运行参数" width="80vw">
<div style="height: 80vh; overflow: auto">
<Config ref="configRef" />
<Runtime ref="runtimeRef" />
</div>
<template #footer>
<div class="config-btn">
@ -242,7 +238,7 @@ const settingWidth = computed(() => {
text-size="1.5rem"
text-color="#1989fa"
height="3rem"
@click="onClose"
@click="onCloseRuntime"
/>
<BtButton
v-if="!deviceState"

46
src/components/home/Runtime.vue

@ -0,0 +1,46 @@
<script lang="ts" setup>
import RunFormulaConfig from 'components/formula/RunFormulaConfig.vue'
import { onMounted } from 'vue'
/**
* 配方选择页面组件
* @description 负责处理配方选择逻辑设备状态判断及界面交互
*/
/**
* @hook 生命周期钩子 - 挂载完成时执行
* @description 初始化时检查配方列表若为空则重新获取
*/
onMounted(() => {
})
</script>
<template>
<div class="main-content">
<div class="formula-config">
<RunFormulaConfig/>
</div>
</div>
</template>
<style lang="scss" scoped>
.main-content {
overflow: hidden;
//height: auto;
//background: $gradient-color;
padding: 15px;
.formula-config {
display: grid;
padding: 10px;
width: 100%;
}
.formula-config-form {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5px;
}
.formdata-input {
width: 10vw;
}
}
</style>

4
src/components/home/config.vue

@ -101,7 +101,7 @@ const onDefaultFormula = () => {
<template>
<div class="main-content">
<div v-if="isDeviceIdle">
<div>
<bt-button type="primary" button-text="选择配方" width="12vw" height="5vh" @click="onChooseFormula">
<template #icon>
<el-icon>
@ -118,7 +118,7 @@ const onDefaultFormula = () => {
</bt-button>
</div>
<div class="formula-config">
<HomeFormulaConfig :formula-name-visible="isDeviceIdle" type="setting" />
<HomeFormulaConfig/>
</div>
<SelectModal
v-if="isModalOpen"

18
src/stores/formulaStore.ts

@ -321,6 +321,22 @@ export const useFormulaStore = defineStore('formula', () => {
}
return syncSendCmd(params)
}
const getRealtimeConfig = () => {
const params = {
className: 'DisinfectionCtrlServiceExt',
fnName: 'getRealtimeConfig',
params: {},
}
return syncSendCmd(params)
}
const setRealtimeConfig = (key: string, val: string) => {
const params = {
className: 'DisinfectionCtrlServiceExt',
fnName: 'setRealtimeConfig',
params: { key, val },
}
return syncSendCmd(params)
}
return {
// 属性
logEnums,
@ -354,5 +370,7 @@ export const useFormulaStore = defineStore('formula', () => {
editFormula,
delFormula,
startFormula,
getRealtimeConfig,
setRealtimeConfig,
}
})
Loading…
Cancel
Save