NPP_Vue/src/views/admin/feedingconfig/components/feeding-config-form.vue

563 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
v-model="dialogVisible"
:title="title"
width="1200px"
class="custom-dialog"
draggable
:close-on-click-modal="false"
:close-on-press-escape="false"
append-to-body
destroy-on-close
:style="{ height: '95vh' }"
@close="close"
>
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-width="220px"
size="default"
v-loading="loading"
>
<el-row :gutter="25">
<!-- 阶段 -->
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<el-card shadow="hover" class="group-card">
<div class="section-title">阶段</div>
<el-form-item label="策略名称" prop="configName" required>
<el-input v-model="formData.configName" clearable placeholder="请输入策略名称" />
</el-form-item>
<el-form-item label="两段式" prop="isTwoStep">
<el-switch v-model="formData.isTwoStep" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item v-if="formData.isTwoStep !== 1" label="总理论时长" prop="totalTheoryTime" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.totalTheoryTime" disabled style="flex: 1;" />
<span style="margin-left: 8px; white-space: nowrap;">分钟</span>
</div>
</el-form-item>
<div class="sub-group" v-if="formData.isTwoStep !== 1">
<div class="sub-title">校准</div>
<el-form-item v-if="formData.isTwoStep !== 1" label="校准阶段时长" prop="calibrateDuration" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.calibrateDuration" :min="120" :max="300" style="flex: 1;" placeholder="请输入120-300之间的秒数" />
<span style="margin-left: 8px; white-space: nowrap;">秒</span>
</div>
</el-form-item>
<el-form-item v-if="formData.isTwoStep !== 1" label="校准阶段补料占总量百分比" prop="calibrateVolumePercent" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.calibrateVolumePercent" :min="6" :max="20" style="flex: 1;" placeholder="请输入6-20之间的百分比" />
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<el-form-item v-if="formData.isTwoStep !== 1" label="校准理论速度" prop="calibrateTheorySpeed" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.calibrateTheorySpeed" :min="0" style="flex: 1;" disabled />
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
</div>
<div class="sub-group">
<div class="sub-title">高速</div>
<el-form-item label="高速阶段泵速百分比" prop="highSpeedPercent" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number
v-model="formData.highSpeedPercent"
:min="formData.isTwoStep === 1 ? 1 : 2"
:max="formData.isTwoStep === 1 ? 100 : 50"
style="flex: 1;"
:placeholder="formData.isTwoStep === 1 ? '请输入1-100之间的百分比' : '请输入2-50之间的百分比'"
/>
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<el-form-item label="高速阶段补料占总量百分比" prop="highSpeedVolumePercent" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number
v-model="formData.highSpeedVolumePercent"
:min="formData.isTwoStep === 1 ? 50 : 60"
:max="formData.isTwoStep === 1 ? 90 : 80"
style="flex: 1;"
:placeholder="formData.isTwoStep === 1 ? '请输入50-90之间的百分比' : '请输入60-80之间的百分比'"
/>
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<el-form-item v-if="formData.isTwoStep !== 1" label="高速理论时长" prop="highSpeedTheoryTime" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.highSpeedTheoryTime" :min="0" style="flex: 1;" disabled />
<span style="margin-left: 8px; white-space: nowrap;">分钟</span>
</div>
</el-form-item>
</div>
<div class="sub-group">
<div class="sub-title">低速</div>
<el-form-item label="低速阶段泵速百分比" prop="lowSpeedPercent" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number
v-model="formData.lowSpeedPercent"
:min="formData.isTwoStep === 1 ? 1 : 0.5"
:max="formData.isTwoStep === 1 ? 100 : 20"
style="flex: 1;"
:placeholder="formData.isTwoStep === 1 ? '请输入1-100之间的百分比' : '请输入0.5-20之间的百分比'"
/>
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<el-form-item v-if="formData.isTwoStep !== 1" label="低速阶段补料占总量百分比" prop="lowSpeedVolumePercent" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.lowSpeedVolumePercent" :min="2" :max="50" style="flex: 1;" placeholder="请输入2-50之间的百分比" />
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<el-form-item v-if="formData.isTwoStep !== 1" label="低速理论时长" prop="lowSpeedTheoryTime" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.lowSpeedTheoryTime" :min="0" style="flex: 1;" disabled />
<span style="margin-left: 8px; white-space: nowrap;">分钟</span>
</div>
</el-form-item>
</div>
</el-card>
</el-col>
<!-- 监控 -->
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<el-card shadow="hover" class="group-card">
<div class="section-title">监控</div>
<el-form-item prop="intervalTime" required>
<template #label>
环控间隔时间
<el-tooltip content="监控每次启动间隔时间" placement="top">
<el-icon style="margin-left: 4px; margin-top: 6px; color: #909399; cursor: pointer;">
<QuestionFilled />
</el-icon>
</el-tooltip>
</template>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.intervalTime" :min="1" style="flex: 1;" placeholder="请输入大于0的秒数" />
<span style="margin-left: 8px; white-space: nowrap;">秒</span>
</div>
</el-form-item>
<el-form-item label="补料超量百分比" prop="excessPercentage" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.excessPercentage" :min="1" style="flex: 1;" placeholder="请输入大于0的百分比" />
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<el-form-item label="超时时间" prop="timeOutSeconds" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.timeOutSeconds" :min="1" style="flex: 1;" placeholder="请输入大于0的秒数" />
<span style="margin-left: 8px; white-space: nowrap;">秒</span>
</div>
</el-form-item>
<el-form-item label="终点百分比" prop="terminalVolumePercent" required>
<div style="display: flex; align-items: center; width: 100%;">
<el-input-number v-model="formData.terminalVolumePercent" :min="98" :max="100" style="flex: 1;" placeholder="请输入98-100之间的百分比" />
<span style="margin-left: 8px; white-space: nowrap;">%</span>
</div>
</el-form-item>
<div class="sub-group">
<div class="sub-title">抖动</div>
<el-form-item label="抖动环控时间系数" prop="ditherIntervalCoefficient" required>
<el-input-number v-model="formData.ditherIntervalCoefficient" :min="1" :max="5" style="width:100%" placeholder="请输入1-5之间的数值" />
</el-form-item>
<el-form-item label="抖动系数" prop="ditherCoefficient" required>
<el-input-number v-model="formData.ditherCoefficient" :min="2" :max="10" style="width:100%" placeholder="请输入2-10之间的数值" />
</el-form-item>
<el-form-item label="抖动观察时间系数" prop="ditherMonitorTime" required>
<el-input-number v-model="formData.ditherMonitorTime" :min="1" style="width:100%" placeholder="请输入大于0的数值" />
</el-form-item>
<el-form-item label="抖动地秤系数" prop="ditherScaleCoefficient" required>
<el-input-number v-model="formData.ditherScaleCoefficient" :min="1" style="width:100%" placeholder="请输入大于0的数值" />
</el-form-item>
</div>
<div class="sub-group">
<div class="sub-title">返水</div>
<el-form-item label="返水环控时间系数" prop="rebateIntervalCoefficient" required>
<el-input-number v-model="formData.rebateIntervalCoefficient" disabled style="width:100%" placeholder="自动等于抖动环控时间系数" />
</el-form-item>
<el-form-item label="返水系数" prop="rebateCoefficient" required>
<el-input-number v-model="formData.rebateCoefficient" :max="-1" style="width:100%" placeholder="请输入小于等于-1的数值" />
</el-form-item>
</div>
<div class="sub-group">
<div class="sub-title">堵塞</div>
<el-form-item label="堵塞环控时间系数" prop="jamIntervalCoefficient" required>
<el-input-number v-model="formData.jamIntervalCoefficient" :min="1" style="width:100%" placeholder="请输入大于0的数值" />
</el-form-item>
<el-form-item label="堵塞系数" prop="jamCoefficient" required>
<el-input-number v-model="formData.jamCoefficient" :min="0" :max="1" style="width:100%" placeholder="请输入0-1之间的数值" />
</el-form-item>
</div>
</el-card>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="close" size="default">取 消</el-button>
<el-button type="primary" @click="handleSubmit" size="default" :loading="loading"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue'
import { ElMessage } from 'element-plus'
import type { FormInstance } from 'element-plus'
import { UspFeedingConfigApi } from '/@/api/admin/UspFeedingConfigApi'
import { QuestionFilled } from '@element-plus/icons-vue'
const props = defineProps<{
modelValue: boolean
title: string
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
(e: 'refresh'): void
}>()
const formRef = ref<FormInstance>()
const formData = reactive({
configName: '',
totalTheoryTime: undefined as number | undefined,
calibrateDuration: undefined as number | undefined,
calibrateVolumePercent: undefined as number | undefined,
calibrateTheorySpeed: undefined as number | undefined,
highSpeedPercent: undefined as number | undefined,
highSpeedVolumePercent: undefined as number | undefined,
highSpeedTheoryTime: undefined as number | undefined,
lowSpeedPercent: undefined as number | undefined,
lowSpeedVolumePercent: undefined as number | undefined,
lowSpeedTheoryTime: undefined as number | undefined,
intervalTime: undefined as number | undefined,
excessPercentage: undefined as number | undefined,
timeOutSeconds: undefined as number | undefined,
terminalVolumePercent: undefined as number | undefined,
ditherIntervalCoefficient: undefined as number | undefined,
ditherCoefficient: undefined as number | undefined,
ditherMonitorTime: undefined as number | undefined,
ditherScaleCoefficient: undefined as number | undefined,
rebateIntervalCoefficient: undefined as number | undefined,
rebateCoefficient: undefined as number | undefined,
jamIntervalCoefficient: undefined as number | undefined,
jamCoefficient: undefined as number | undefined,
enabled: true,
isTwoStep: 0,
id: undefined as number | undefined
})
const rules = {
configName: [{ required: true, message: '请输入策略名称', trigger: ['blur', 'change'] }],
totalTheoryTime: [{ required: true, message: '请输入总理论时长', trigger: ['blur', 'change'] }],
calibrateDuration: [{ required: true, message: '请输入校准阶段时长', trigger: ['blur', 'change'] }],
calibrateVolumePercent: [{ required: true, message: '请输入校准阶段补料占总量百分比', trigger: ['blur', 'change'] }],
calibrateTheorySpeed: [{ required: true, message: '请输入校准理论速度', trigger: ['blur', 'change'] }],
highSpeedPercent: [{ required: true, message: '请输入高速阶段泵速百分比', trigger: ['blur', 'change'] }],
highSpeedVolumePercent: [{ required: true, message: '请输入高速阶段补料占总量百分比', trigger: ['blur', 'change'] }],
highSpeedTheoryTime: [{ required: true, message: '请输入高速理论时长', trigger: ['blur', 'change'] }],
lowSpeedPercent: [{ required: true, message: '请输入低速阶段泵速百分比', trigger: ['blur', 'change'] }],
lowSpeedVolumePercent: [{ required: true, message: '请输入低速阶段补料占总量百分比', trigger: ['blur', 'change'] }],
lowSpeedTheoryTime: [{ required: true, message: '请输入低速理论时长', trigger: ['blur', 'change'] }],
intervalTime: [{ required: true, message: '请输入环控间隔时间', trigger: ['blur', 'change'] }],
excessPercentage: [{ required: true, message: '请输入补料超量百分比', trigger: ['blur', 'change'] }],
timeOutSeconds: [{ required: true, message: '请输入超时时间', trigger: ['blur', 'change'] }],
terminalVolumePercent: [{ required: true, message: '请输入终点百分比', trigger: ['blur', 'change'] }],
ditherIntervalCoefficient: [{ required: true, message: '请输入抖动环控时间系数', trigger: ['blur', 'change'] }],
ditherCoefficient: [{ required: true, message: '请输入抖动系数', trigger: ['blur', 'change'] }],
ditherMonitorTime: [{ required: true, message: '请输入抖动观察时间系数', trigger: ['blur', 'change'] }],
ditherScaleCoefficient: [{ required: true, message: '请输入抖动地秤系数', trigger: ['blur', 'change'] }],
rebateIntervalCoefficient: [{ required: true, message: '请输入返水环控时间系数', trigger: ['blur', 'change'] }],
rebateCoefficient: [{ required: true, message: '请输入返水系数', trigger: ['blur', 'change'] }],
jamIntervalCoefficient: [{ required: true, message: '请输入堵塞环控时间系数', trigger: ['blur', 'change'] }],
jamCoefficient: [{ required: true, message: '请输入堵塞系数', trigger: ['blur', 'change'] }]
}
const loading = ref(false)
const dialogVisible = ref(false)
const api = new UspFeedingConfigApi()
watch(
() => props.modelValue,
(val) => {
dialogVisible.value = val
}
)
watch(
() => dialogVisible.value,
(val) => {
emit('update:modelValue', val)
if (!val) resetForm()
}
)
watch(
() => [formData.calibrateVolumePercent, formData.calibrateDuration, formData.isTwoStep],
([volume, duration]) => {
if (formData.isTwoStep === 1) return;
if (typeof volume === 'number' && typeof duration === 'number' && duration > 0) {
formData.calibrateTheorySpeed = Number((volume / duration * 60).toFixed(2)) as number
} else {
formData.calibrateTheorySpeed = undefined
}
}
)
// 新增:高速理论时长自动计算
watch(
() => [formData.highSpeedVolumePercent, formData.highSpeedPercent, formData.isTwoStep],
([volume, percent]) => {
if (formData.isTwoStep === 1) return;
if (typeof volume === 'number' && typeof percent === 'number' && percent > 0) {
formData.highSpeedTheoryTime = Number((volume / percent).toFixed(2)) as number
} else {
formData.highSpeedTheoryTime = undefined
}
}
)
// 新增:低速理论时长自动计算
watch(
() => [formData.lowSpeedVolumePercent, formData.lowSpeedPercent, formData.isTwoStep],
([volume, percent]) => {
if (formData.isTwoStep === 1) return;
if (typeof volume === 'number' && typeof percent === 'number' && percent > 0) {
formData.lowSpeedTheoryTime = Number((volume / percent).toFixed(2)) as number
} else {
formData.lowSpeedTheoryTime = undefined
}
}
)
// 新增:总理论时长自动计算
watch(
() => [formData.calibrateDuration, formData.highSpeedTheoryTime, formData.lowSpeedTheoryTime, formData.isTwoStep],
([calibrateDuration, highSpeedTheoryTime, lowSpeedTheoryTime]) => {
if (formData.isTwoStep === 1) return;
if (typeof calibrateDuration === 'number' && typeof highSpeedTheoryTime === 'number' && typeof lowSpeedTheoryTime === 'number') {
formData.totalTheoryTime = Number(((calibrateDuration / 60) + highSpeedTheoryTime + lowSpeedTheoryTime).toFixed(2)) as number
} else {
formData.totalTheoryTime = undefined
}
}
)
watch(
() => [formData.isTwoStep, formData.highSpeedPercent],
([isTwoStep, highSpeedPercent]) => {
if (isTwoStep === 1) {
formData.lowSpeedVolumePercent = 100 - Number(highSpeedPercent || 0)
}
}
)
// 自动同步返水环控时间系数 = 抖动环控时间系数
watch(
() => formData.ditherIntervalCoefficient,
(val) => {
formData.rebateIntervalCoefficient = val
}
)
function resetForm() {
formRef.value?.resetFields()
Object.assign(formData, {
configName: '',
totalTheoryTime: undefined,
calibrateDuration: undefined,
calibrateVolumePercent: undefined,
calibrateTheorySpeed: undefined,
highSpeedPercent: undefined,
highSpeedVolumePercent: undefined,
highSpeedTheoryTime: undefined,
lowSpeedPercent: undefined,
lowSpeedVolumePercent: undefined,
lowSpeedTheoryTime: undefined,
intervalTime: undefined,
excessPercentage: undefined,
timeOutSeconds: undefined,
terminalVolumePercent: undefined,
ditherIntervalCoefficient: undefined,
ditherCoefficient: undefined,
ditherMonitorTime: undefined,
ditherScaleCoefficient: undefined,
rebateIntervalCoefficient: undefined,
rebateCoefficient: undefined,
jamIntervalCoefficient: undefined,
jamCoefficient: undefined,
enabled: true,
isTwoStep: 0,
id: undefined
})
}
function setFormData(data: any) {
Object.assign(formData, data)
}
function close() {
dialogVisible.value = false
}
async function open(row?: any) {
dialogVisible.value = true
if (row && row.id) {
loading.value = true
try {
const res = await api.get({ id: row.id })
if (res.success && res.data) setFormData(res.data)
else ElMessage.warning(res.msg || '获取数据失败')
} catch (error) {
console.error(error)
ElMessage.error('获取数据出错')
} finally {
loading.value = false
}
} else resetForm()
}
async function handleSubmit() {
if (!formRef.value) return
// 只有 isTwoStep !== 1 时才校验百分比之和
if (formData.isTwoStep !== 1) {
const sum = Number(formData.calibrateVolumePercent) + Number(formData.highSpeedVolumePercent) + Number(formData.lowSpeedVolumePercent)
if (sum !== 100) {
ElMessage.warning('补料占总量百分比之和必须等于100')
return
}
}
await formRef.value.validate(async (valid: boolean) => {
if (!valid) return
loading.value = true
try {
// 处理所有undefined为null
const data: Record<string, any> = { ...formData }
Object.keys(data).forEach((key: string) => {
if (typeof data[key] === 'undefined') data[key] = null
})
if (data.id == null) delete data.id
if (formData.id) {
const updateInput = {
...data,
setSpeed: data.calibrateTheorySpeed,
speedDiff: 0,
feedTime: data.totalTheoryTime,
id: data.id,
configName: data.configName,
intervalTime: data.intervalTime,
calibrateDuration: data.calibrateDuration,
calibrateVolumePercent: data.calibrateVolumePercent,
highSpeedPercent: data.highSpeedPercent,
highSpeedVolumePercent: data.highSpeedVolumePercent,
lowSpeedPercent: data.lowSpeedPercent,
lowSpeedVolumePercent: data.lowSpeedVolumePercent,
ditherIntervalCoefficient: data.ditherIntervalCoefficient,
ditherCoefficient: data.ditherCoefficient,
ditherMonitorTime: data.ditherMonitorTime,
ditherScaleCoefficient: data.ditherScaleCoefficient,
rebateIntervalCoefficient: data.rebateIntervalCoefficient,
rebateCoefficient: data.rebateCoefficient,
jamIntervalCoefficient: data.jamIntervalCoefficient,
jamCoefficient: data.jamCoefficient,
excessPercentage: data.excessPercentage,
timeOutSeconds: data.timeOutSeconds,
terminalVolumePercent: data.terminalVolumePercent,
enabled: data.enabled,
isTwoStep: data.isTwoStep
}
await api.update(updateInput)
ElMessage.success('修改成功')
} else {
const addInput = {
...data,
setSpeed: data.calibrateTheorySpeed,
speedDiff: 0,
feedTime: data.totalTheoryTime
}
delete (addInput as any).id
await api.add(addInput)
ElMessage.success('新增成功')
}
emit('refresh')
close()
} catch (error) {
console.error(error)
ElMessage.error('提交失败')
} finally {
loading.value = false
}
})
}
defineExpose({ open })
</script>
<style scoped>
.group-card {
margin-bottom: 15px;
border-radius: 10px;
box-shadow: 0 2px 12px #f0f1f2;
background: #fff;
}
.section-title {
font-size: 18px;
font-weight: bold;
color: #409EFF;
margin-bottom: 18px;
letter-spacing: 2px;
}
.sub-group {
background: #f7fafd;
border-radius: 8px;
padding: 12px 16px 4px 16px;
margin-bottom: 18px;
margin-top: 18px;
}
.sub-title {
font-size: 15px;
color: #6ca0dc;
font-weight: bold;
margin-bottom: 10px;
letter-spacing: 1px;
}
.el-form-item {
margin-bottom: 18px !important;
}
@media (max-width: 1200px) {
.group-card {
margin-bottom: 16px;
}
}
.ant-card::before, .ant-card::after,
.el-card::before, .el-card::after {
border: none !important;
box-shadow: none !important;
}
/* 针对所有 input、select、textarea */
form input,
form select,
form textarea {
border: none !important;
box-shadow: none !important;
outline: none !important;
}
/* 针对常见UI库的表单项容器 */
.ant-input, .el-input__inner, .n-input__input {
border: none !important;
box-shadow: none !important;
outline: none !important;
}
/* 针对分组容器 */
.ant-card, .el-card, .card, .fieldset, .form-group {
border: none !important;
box-shadow: none !important;
}
</style>