13 changed files with 747 additions and 365 deletions
-
4src/components/audit/History.vue
-
256src/components/formula/FormulaConfig.vue
-
62src/components/formula/FormulaTable.vue
-
188src/components/formula/HomeFormulaConfig.vue
-
343src/components/formula/SettingFormulaConfig.vue
-
32src/components/home/HomeSetting.vue
-
9src/components/home/config.vue
-
15src/components/setting/User.vue
-
180src/stores/formulaStore.ts
-
1src/types/formula.d.ts
-
8src/views/formula/index.vue
-
2src/views/home/chart.vue
-
12src/views/setting/index.vue
@ -0,0 +1,188 @@ |
|||||
|
<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 props = defineProps<{ |
||||
|
formulaNameVisible: boolean |
||||
|
}>() |
||||
|
const formulaStore = useFormulaStore() |
||||
|
/** |
||||
|
* 获取当前表单数据,将值转换为字符串格式 |
||||
|
* @returns {Record<string, string>} 转换后的表单数据 |
||||
|
*/ |
||||
|
const getFormData = () => { |
||||
|
return convertValuesToString(formData.value, 'name') |
||||
|
} |
||||
|
/** |
||||
|
* 注册孙子组件方法的注入函数 |
||||
|
*/ |
||||
|
const registerGrandsonMethods = inject<(methods: any) => void>('registerGrandsonMethods', () => {}) |
||||
|
onMounted(() => { |
||||
|
registerGrandsonMethods && registerGrandsonMethods({ getFormData }) |
||||
|
}) |
||||
|
/** |
||||
|
* 当前表单数据 |
||||
|
* - home: 当前选中的配方 或者默认配方 |
||||
|
*/ |
||||
|
const formData = ref<Record<string, any>>({}) |
||||
|
/** |
||||
|
* 标签单位映射表,用于显示各参数的单位 |
||||
|
*/ |
||||
|
const labelUnitMap: Record<string, any> = formulaStore.labelUnitMap |
||||
|
/** |
||||
|
* 监听事件 |
||||
|
*/ |
||||
|
watchEffect(() => { |
||||
|
formData.value = formulaStore.selectedFormulaInfo !== null ? convertValuesToInt(formulaStore.selectedFormulaInfo) : convertValuesToInt(formulaStore.defaultFormulaInfo) |
||||
|
}) |
||||
|
/** |
||||
|
* 配方配置列表 |
||||
|
*/ |
||||
|
const formulaConfigList = formulaStore.formulaConfigList |
||||
|
const size = 'default' |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="formula-form"> |
||||
|
<el-form |
||||
|
:disabled="true" |
||||
|
:model="formData" |
||||
|
label-width="auto" |
||||
|
label-position="right" |
||||
|
:size="size" |
||||
|
inline |
||||
|
> |
||||
|
<el-form-item v-if="props.formulaNameVisible" label="配方名称" style="width: 93%"> |
||||
|
<el-input |
||||
|
v-model="formData.name" |
||||
|
v-prevent-keyboard |
||||
|
name="name" |
||||
|
placeholder="配方名称" |
||||
|
:disabled="true" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item |
||||
|
v-for="item in formulaConfigList" |
||||
|
:key="item.setting_id" |
||||
|
:label="formulaNameMap[item.setting_id]" |
||||
|
style="width: 50%" |
||||
|
> |
||||
|
<template v-if="item.is_visible_in_rt_page && 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.is_visible_in_rt_page && 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.is_visible_in_rt_page && item.val_type === 'enum'"> |
||||
|
<el-input |
||||
|
v-model="formData[item.setting_id]" |
||||
|
v-prevent-keyboard |
||||
|
style="width: 80%" |
||||
|
placeholder="请选择" |
||||
|
readonly |
||||
|
:disabled="!item.is_editable" |
||||
|
> |
||||
|
<template #append> |
||||
|
{{ labelUnitMap[item.setting_id] }} |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</template> |
||||
|
<template v-else-if="item.is_visible_in_rt_page && 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> |
@ -0,0 +1,343 @@ |
|||||
|
<script lang="ts" setup> |
||||
|
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 { onMounted, ref, watch, watchEffect } from 'vue' |
||||
|
|
||||
|
import { FtMessage } from '@/libs/message' |
||||
|
import { compareJSON, convertValuesToInt } from '@/libs/utils' |
||||
|
import { useFormulaStore } from '@/stores/formulaStore' |
||||
|
|
||||
|
const props = defineProps<{ |
||||
|
editable: boolean |
||||
|
}>() |
||||
|
const formulaStore = useFormulaStore() |
||||
|
|
||||
|
const targetInputRef = ref<HTMLInputElement | null>(null) |
||||
|
|
||||
|
/** |
||||
|
* 当前表单数据 |
||||
|
* 不同模式下有不同的初始值: |
||||
|
* - 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 options = ref(formulaStore.logLevelOptions) |
||||
|
|
||||
|
/** |
||||
|
* 标签单位映射表,用于显示各参数的单位 |
||||
|
*/ |
||||
|
const labelUnitMap: Record<string, any> = formulaStore.labelUnitMap |
||||
|
/** |
||||
|
* 配方配置列表 |
||||
|
*/ |
||||
|
const formulaConfigList = ref(formulaStore.formulaConfigList) |
||||
|
/** |
||||
|
* 组件挂载时注册方法供父组件调用 |
||||
|
*/ |
||||
|
watchEffect(() => { |
||||
|
formData.value = cloneDeep(formulaStore.defaultFormulaInfo) |
||||
|
formData.value = convertValuesToInt(formData.value) |
||||
|
}) |
||||
|
/** |
||||
|
* 模态框是否打开 |
||||
|
*/ |
||||
|
const isModalOpen = ref(false) |
||||
|
|
||||
|
/** |
||||
|
* 打开模态框 |
||||
|
*/ |
||||
|
const openModal = () => { |
||||
|
isModalOpen.value = true |
||||
|
} |
||||
|
const currentFormulaItem = ref() |
||||
|
/** |
||||
|
* 监听软键盘输入值变化,更新表单数据 |
||||
|
* @param {string | number} newVal - 新的输入值 |
||||
|
*/ |
||||
|
watch(inputValue, (newVal: string | number) => { |
||||
|
if (focusedInput.value) { |
||||
|
newVal = Number(newVal) |
||||
|
if (currentFormulaItem.value && newVal > currentFormulaItem.value.val_upper_limit) { |
||||
|
newVal = currentFormulaItem.value.val_upper_limit |
||||
|
} |
||||
|
formData.value[focusedInput.value] = newVal |
||||
|
} |
||||
|
}) |
||||
|
/** |
||||
|
* 监听表单数据变化,同步更新软键盘输入值 |
||||
|
* @param {Record<string, any>} newValue - 新的表单数据 |
||||
|
*/ |
||||
|
watch( |
||||
|
formData, |
||||
|
(newValue) => { |
||||
|
if (focusedInput.value) { |
||||
|
inputValue.value = newValue[focusedInput.value].toString() |
||||
|
} |
||||
|
}, |
||||
|
{ deep: true }, |
||||
|
) |
||||
|
const formRef = ref(null) |
||||
|
// 挂载 |
||||
|
onMounted(() => { |
||||
|
formulaStore.getFormualDefaultData() |
||||
|
}) |
||||
|
/** |
||||
|
* 处理表单提交 |
||||
|
* 根据不同的type属性值执行不同的保存逻辑 |
||||
|
*/ |
||||
|
const handleSubmit = () => { |
||||
|
// 修改默认值 |
||||
|
const diff = compareJSON(formulaStore.defaultFormulaInfo, formData.value) |
||||
|
const diffKeys = Object.keys(diff) |
||||
|
if (diffKeys.length) { |
||||
|
Promise.all( |
||||
|
diffKeys.map(async (key) => { |
||||
|
await formulaStore.setSettingFormulaConfig(key, diff[key].newVal || diff[key].obj2) |
||||
|
}), |
||||
|
) |
||||
|
FtMessage.success('配方修改成功') |
||||
|
} |
||||
|
formulaStore.getFormualDefaultData() |
||||
|
} |
||||
|
/** |
||||
|
* 打开软键盘 |
||||
|
* @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) |
||||
|
} |
||||
|
/** |
||||
|
* 确认输入值 |
||||
|
* @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.updateLogLevel(value) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 取消日志级别选择 |
||||
|
*/ |
||||
|
const handleLogCancel = () => { |
||||
|
isModalOpen.value = false |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据标签名称确定软键盘类型 |
||||
|
* @param {string} labelName - 标签名称 |
||||
|
*/ |
||||
|
const openKeyboardType = (labelName: string) => { |
||||
|
keyboardType.value = labelName === 'name' ? 'text' : 'number' |
||||
|
} |
||||
|
const size = 'default' |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<div class="formula-form"> |
||||
|
<el-form |
||||
|
ref="formRef" |
||||
|
:disabled="props.editable" |
||||
|
:model="formData" |
||||
|
label-width="auto" |
||||
|
label-position="right" |
||||
|
:size="size" |
||||
|
inline |
||||
|
> |
||||
|
<el-form-item |
||||
|
v-for="item in formulaConfigList" |
||||
|
:key="item.setting_id" |
||||
|
:label="formulaNameMap[item.setting_id]" |
||||
|
style="width: 50%" |
||||
|
> |
||||
|
<template v-if="item.is_visible_in_setting_page && 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="!props.editable" |
||||
|
@focus="e => openKeyboard(e, item)" |
||||
|
> |
||||
|
<template v-if="labelUnitMap[item.setting_id]" #append> |
||||
|
{{ labelUnitMap[item.setting_id] }} |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</template> |
||||
|
<template v-if="item.is_visible_in_setting_page && 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="!props.editable" |
||||
|
@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.is_visible_in_setting_page && item.val_type === 'enum'"> |
||||
|
<el-input |
||||
|
v-model="formData[item.setting_id]" |
||||
|
v-prevent-keyboard |
||||
|
style="width: 80%" |
||||
|
placeholder="请选择" |
||||
|
readonly |
||||
|
:disabled="!props.editable" |
||||
|
@focus="openModal" |
||||
|
> |
||||
|
<template #append> |
||||
|
{{ labelUnitMap[item.setting_id] }} |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</template> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div :style="{ marginLeft: '33%' }"> |
||||
|
<slot name="formulaBtn"> |
||||
|
<div class="default-btn"> |
||||
|
<el-button v-if="editable" type="primary" class="config-btn" @click="handleSubmit"> |
||||
|
确定 |
||||
|
</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> |
||||
|
</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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue