消毒机设备
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.

353 lines
9.9 KiB

2 months ago
2 weeks ago
2 months ago
2 months ago
3 weeks ago
2 weeks ago
2 months ago
2 months ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
3 weeks ago
2 weeks ago
2 weeks ago
2 months ago
2 months ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
3 weeks ago
2 months ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
2 weeks ago
2 weeks ago
3 weeks ago
3 weeks ago
3 weeks ago
2 months ago
3 weeks ago
3 weeks ago
2 months ago
  1. <script lang="ts" setup>
  2. import { ElMessage } from 'element-plus'
  3. import { formulaNameMap } from 'libs/constant'
  4. import { cloneDeep } from 'lodash'
  5. import { useHomeStore } from 'stores/homeStore'
  6. import { computed, inject, nextTick, onMounted, ref, watch, watchEffect } from 'vue'
  7. import { FtMessage } from '@/libs/message'
  8. import { convertValuesToString } from '@/libs/utils'
  9. import { useFormulaStore } from '@/stores/formulaStore'
  10. const homeStore = useHomeStore()
  11. const formulaStore = useFormulaStore()
  12. const isFlip = ref(true)
  13. /**
  14. * 当前表单数据
  15. */
  16. const formData = ref<Record<string, any>>({})
  17. /**
  18. * 软键盘当前输入值
  19. */
  20. const inputValue = ref<string>('')
  21. /**
  22. * 当前聚焦的输入字段名称
  23. */
  24. const focusedInput = ref<string | null>(null)
  25. /**
  26. * 注册孙子组件方法的注入函数
  27. */
  28. const registerGrandsonMethods = inject<(methods: any) => void>('registerGrandsonMethods', () => {})
  29. /**
  30. * 配方配置列表
  31. */
  32. const formulaConfigList = ref(formulaStore.formulaConfigList)
  33. /**
  34. * 标签单位映射表用于显示各参数的单位
  35. */
  36. const labelUnitMap: Record<string, any> = formulaStore.labelUnitMap
  37. onMounted(() => {
  38. formulaStore.getFormualDefaultData() // 获取表单的配置信息
  39. registerGrandsonMethods && registerGrandsonMethods({ getFormData })
  40. formulaStore.initFormulaList() // 更新列表数据
  41. })
  42. /**
  43. * 组件挂载时注册方法供父组件调用
  44. */
  45. watchEffect(() => {
  46. if (formulaStore.currentSelectedIndex === null) {
  47. formData.value = cloneDeep(formulaStore.defaultFormulaInfo || {})
  48. }
  49. else {
  50. formData.value = cloneDeep(formulaStore.currentSelectedFormulaInfo || {})
  51. }
  52. isFlip.value = formulaStore.flip
  53. // 后端给的数据类型是字符串型,前端需要的是int型,后端开发说(赵贺)后端不好转换,由前端进行转换.
  54. formData.value = convertValuesToString(formData.value, 'name')
  55. })
  56. const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
  57. /**
  58. * 获取当前表单数据将值转换为字符串格式
  59. * @returns {Record<string, string>} 转换后的表单数据
  60. */
  61. const getFormData = () => {
  62. return convertValuesToString(formData.value, 'name')
  63. }
  64. /**
  65. * 监听表单数据变化同步更新软键盘输入值
  66. * @param {Record<string, any>} newValue - 新的表单数据
  67. */
  68. watch(
  69. formData,
  70. (newValue) => {
  71. if (focusedInput.value) {
  72. inputValue.value = newValue[focusedInput.value].toString()
  73. }
  74. },
  75. { deep: true },
  76. )
  77. watch(
  78. () => formulaStore.currentSelectedIndex,
  79. () => {
  80. formRef.value?.clearValidate()
  81. },
  82. )
  83. const formRef = ref()
  84. /**
  85. * 处理表单提交
  86. * 根据不同的type属性值执行不同的保存逻辑
  87. */
  88. const handleSubmit = async () => {
  89. // 表单验证
  90. try {
  91. const valid = await formRef.value.validate()
  92. if (!valid) {
  93. return
  94. }
  95. if (formData.value.formula_id) {
  96. // 修改配方
  97. // 判断消毒是否正在执行 且正在执行配方是当前修改配方
  98. if (!deviceState.value && formulaStore.selectedFormulaInfo?.formula_id === formData.value.formula_id) {
  99. ElMessage.warning('禁止修改正在执行的配方信息!')
  100. return
  101. }
  102. const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name')
  103. formulaStore
  104. .editFormula(formulaForm.formula_id, formulaForm as Formula.FormulaItem)
  105. .then(() => {
  106. FtMessage.success('操作成功')
  107. formulaStore.initFormulaList('edit')
  108. if (formData.value.formula_id === formulaStore.selectedFormulaInfo?.formula_id) {
  109. formulaStore.selectedFormulaInfo = formulaForm as Formula.FormulaItem
  110. }
  111. })
  112. .catch((e) => {
  113. console.log(e)
  114. })
  115. }
  116. else {
  117. // 新增配方
  118. formulaStore.onAddFormula().then((res) => {
  119. if (res.ackcode === 0) {
  120. const item = res.rely
  121. const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name')
  122. formulaForm.formula_id = item.formula_id
  123. formulaStore
  124. .editFormula(item.formula_id, formulaForm as Formula.FormulaItem)
  125. .then(() => {
  126. FtMessage.success('操作成功')
  127. formulaStore.initFormulaList('add')
  128. })
  129. .catch((e) => {
  130. console.log(e)
  131. })
  132. }
  133. })
  134. }
  135. }
  136. catch (e) {
  137. console.log(e)
  138. }
  139. }
  140. /**
  141. * @computed 计算属性 - 设备状态判断
  142. * @returns {boolean} - 设备是否处于空闲或已完成状态
  143. * @desc 控制按钮可用状态
  144. */
  145. const deviceState = computed(() => {
  146. return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
  147. })
  148. const size = 'default'
  149. // 新增配方方法
  150. const addFormula = async () => {
  151. formData.value = cloneDeep(formulaStore.defaultFormulaInfo)
  152. // formData.value = convertValuesToInt(formulaInfo)
  153. await nextTick() // 等待DOM更新
  154. formData.value.name = ''
  155. formData.value.formula_id = null
  156. }
  157. // 暴露方法给父组件
  158. defineExpose({
  159. addFormula,
  160. })
  161. const validatePass = (rule: any, value: any, callback: any, config: Formula.FormulaConfig) => {
  162. if (!value && value !== 0 && value !== '0') {
  163. callback(new Error('此为必填项'))
  164. }
  165. else if (value.substring(0, 1) === '.' || value.split('.').length > 2) {
  166. callback(new Error('输入数值项'))
  167. }
  168. else if (config.val_type === 'int' || config.val_type === 'float') {
  169. const temp = Number(value)
  170. if (temp < config.val_lower_limit || temp > config.val_upper_limit) {
  171. callback(new Error(`输入范围为${config.val_lower_limit}-${config.val_upper_limit}`))
  172. }
  173. }
  174. callback()
  175. }
  176. const validateName = (rule: any, value: any, callback: any) => {
  177. if (!value && value !== 0 && value !== '0') {
  178. callback(new Error('配方名称不能为空'))
  179. }
  180. else if (value.length > 20) {
  181. callback(new Error('配方名称1-20个字符'))
  182. }
  183. callback()
  184. }
  185. </script>
  186. <template>
  187. <transition name="slide-right">
  188. <div v-if="isFlip" class="formula-form">
  189. <el-form
  190. ref="formRef"
  191. :model="formData"
  192. class="form-box"
  193. label-width="auto"
  194. label-position="right"
  195. :size="size"
  196. inline
  197. >
  198. <el-form-item
  199. label="配方名称"
  200. style="width: 93%"
  201. prop="name"
  202. :rules="[
  203. {
  204. required: true,
  205. validator: (rule, value, callback) => validateName(rule, value, callback),
  206. trigger: 'blur',
  207. },
  208. ]"
  209. >
  210. <ft-input v-model="formData.name" name="name" placeholder="配方名称" />
  211. </el-form-item>
  212. <el-form-item
  213. v-for="item in formulaConfigList.filter(data => data.is_visible_in_formula_page)"
  214. :key="item.setting_id"
  215. :label="formulaNameMap[item.setting_id]"
  216. style="width: 50%"
  217. :prop="item.setting_id"
  218. :rules="[
  219. {
  220. required: true,
  221. validator: (rule, value, callback) => validatePass(rule, value, callback, item),
  222. trigger: 'blur',
  223. },
  224. ]"
  225. >
  226. <template v-if="item.val_type === 'int'">
  227. <ft-input v-model="formData[item.setting_id]" style="width: 80%" layout-name="number">
  228. <template v-if="labelUnitMap[item.setting_id]" #append>
  229. {{ labelUnitMap[item.setting_id] }}
  230. </template>
  231. </ft-input>
  232. </template>
  233. <template v-if="item.val_type === 'float'">
  234. <ft-input v-model="formData[item.setting_id]" layout-name="number" style="width: 80%">
  235. <template v-if="labelUnitMap[item.setting_id]" #append>
  236. {{ labelUnitMap[item.setting_id] }}
  237. </template>
  238. </ft-input>
  239. </template>
  240. <template v-else-if="item.val_type === 'enum'">
  241. <el-select v-model="formData[item.setting_id]" style="width: 80%" placeholder="请选择" readonly>
  242. <el-option v-for="log in item.enums" :key="log" :label="log" :value="log" />
  243. </el-select>
  244. </template>
  245. <template v-else-if="item.val_type === 'boolean'">
  246. <el-radio-group v-model="formData[item.setting_id]">
  247. <el-radio :label="true">
  248. </el-radio>
  249. <el-radio :label="false">
  250. </el-radio>
  251. </el-radio-group>
  252. </template>
  253. </el-form-item>
  254. </el-form>
  255. <div class="default-btn">
  256. <el-button type="primary" class="config-btn" @click="handleSubmit">
  257. 确定
  258. </el-button>
  259. </div>
  260. </div>
  261. </transition>
  262. </template>
  263. <style lang="scss" scoped>
  264. .formula-form {
  265. font-size: 20px !important;
  266. align-items: center;
  267. height: 100%;
  268. .form-box {
  269. height: calc(100% - 50px);
  270. overflow: auto;
  271. }
  272. .default-btn {
  273. height: 50px;
  274. display: flex;
  275. justify-content: center;
  276. align-items: center;
  277. .el-button {
  278. width: 100px;
  279. }
  280. }
  281. }
  282. .formula-form-item {
  283. display: grid;
  284. grid-template-columns: 1fr 1fr;
  285. }
  286. .formData-input-config {
  287. width: 10vw;
  288. }
  289. :deep(.el-input__inner) {
  290. text-align: left;
  291. height: 40px;
  292. }
  293. :deep(.el-select) {
  294. height: 42px;
  295. }
  296. :deep(.el-select__wrapper) {
  297. height: 42px;
  298. }
  299. :deep(.el-form-item) {
  300. margin-right: 0;
  301. align-items: center;
  302. }
  303. :deep(.el-input-group__append) {
  304. font-size: 12px;
  305. padding: 0 1vw;
  306. }
  307. /* 进入动画的初始状态 */
  308. .slide-right-enter-from {
  309. transform: translateX(100%);
  310. }
  311. /* 进入动画的结束状态(也可以理解为激活状态) */
  312. .slide-right-enter-to {
  313. transform: translateX(0);
  314. }
  315. /* 进入动画的过渡曲线等 */
  316. .slide-right-enter-active {
  317. transition: transform 0.3s ease-in-out;
  318. }
  319. /* 离开动画的初始状态(激活状态) */
  320. .slide-right-leave-from {
  321. transform: translateX(0);
  322. }
  323. /* 离开动画的结束状态 */
  324. .slide-right-leave-to {
  325. transform: translateX(100%);
  326. }
  327. /* 离开动画的过渡曲线等 */
  328. .slide-right-leave-active {
  329. transition: transform 0.3s ease-in-out;
  330. }
  331. </style>