2025-06-09 11:27:46 +08:00

499 lines
15 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>
<div class="pump-form">
<el-dialog
v-model="state.isShowDialog"
destroy-on-close
:title="props.title"
draggable
:close-on-click-modal="false"
:close-on-press-escape="false"
width="900px"
>
<el-form ref="pumpFormRef" :model="state.ruleForm" :rules="state.ruleRules" label-width="120px">
<!-- 基本信息 -->
<div class="form-section">
<div class="section-title">基本信息</div>
<el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="设备编号" prop="deviceNo" required>
<el-input v-model="state.ruleForm.deviceNo" placeholder="请输入设备编号" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="资产编号" prop="assetNo" required>
<el-input v-model="state.ruleForm.assetNo" placeholder="请输入资产编号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="设备型号" prop="model" required>
<el-select
v-model="state.ruleForm.model"
placeholder="请选择设备型号"
style="width: 100%"
filterable
allow-create
>
<el-option
v-for="model in state.modelOptions"
:key="model.value"
:label="model.name"
:value="model.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="规格" prop="specification" required>
<el-input v-model="state.ruleForm.specification" placeholder="请输入设备规格" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="设备负责人" prop="principalId" required>
<el-select
v-model="state.ruleForm.principalId"
placeholder="请选择设备负责人"
clearable
filterable
style="width: 100%"
>
<el-option
v-for="user in state.userOptions"
:key="user.id"
:label="`${user.name} (${user.userName})`"
:value="user.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 技术参数 -->
<div class="form-section">
<div class="section-title">技术参数</div>
<el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="工作泵速(g/min)" prop="workingSpeed" required>
<el-input-number
v-model="state.ruleForm.workingSpeed"
:min="0"
:precision="2"
style="width: 100%"
placeholder="请输入工作泵速"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="时长:(s)" prop="workingTime" required>
<el-input-number
v-model="state.ruleForm.workingTime"
:min="0"
style="width: 100%"
placeholder="请输入超时时间"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="泵速系数" prop="speedCoefficient" required>
<el-input-number
v-model="state.ruleForm.speedCoefficient"
:min="0"
:precision="3"
style="width: 100%"
placeholder="请输入泵速系数"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="维护状态" prop="maintenanceFlag">
<el-select
v-model="state.ruleForm.maintenanceFlag"
placeholder="请选择维护状态"
style="width: 100%"
>
<el-option
v-for="status in state.maintenanceStatusOptions"
:key="status.value"
:label="status.label"
:value="status.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 网络配置 -->
<div class="form-section">
<div class="section-title">网络配置</div>
<el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="IP地址" prop="ip" required>
<el-input v-model="state.ruleForm.ip" placeholder="请输入IP地址" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="端口号" prop="port" required>
<el-input v-model="state.ruleForm.port" placeholder="请输入端口号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="25">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-form-item label="服务名称" prop="serviceName">
<el-input v-model="state.ruleForm.serviceName" placeholder="请输入服务名称" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel">取消</el-button>
<el-button type="primary" @click="onSubmit" :loading="state.loading">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="PumpForm">
import { reactive, ref, getCurrentInstance, onMounted } from 'vue'
import { PumpApi } from '/@/api/admin/PumpApi'
import { UserApi } from '/@/api/admin/User'
import { FeedingConfigApi } from '/@/api/admin/FeedingConfigApi'
import { DictApi } from '/@/api/admin/Dict'
import { UserGetPageOutput, PageInputUserGetPageInput, PumpAddInput, PumpUpdateInput, FeedingConfigGetListOutput, DictGetListOutput } from '/@/api/admin/data-contracts'
import eventBus from '/@/utils/mitt'
// 定义父组件传过来的值
const props = defineProps({
title: String,
})
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh'])
// 定义变量内容
const pumpFormRef = ref()
const { proxy } = getCurrentInstance() as any
// 临时类型定义
type PumpFormData = {
id?: number
deviceNo: string
assetNo: string
model: string
specification: string
pumpSpeed: number
principalId: number | undefined
pumpTimeout: number
maintenanceFlag: number
ip: string
port: string
speedCoefficient: number
serviceName: string
isAirPump: boolean
configId: number | undefined,
workingSpeed: number,
workingTime: number,
}
const state = reactive({
isShowDialog: false,
loading: false,
configLoading: false,
ruleForm: {
id: undefined,
deviceNo: '',
assetNo: '',
model: '',
specification: '',
pumpSpeed: 0,
workingSpeed: 0,
workingTime: 0,
principalId: undefined,
pumpTimeout: 0,
maintenanceFlag: 1,
ip: '',
port: '',
speedCoefficient: 0,
serviceName: '',
isAirPump: false,
configId: undefined,
} as PumpFormData,
userOptions: [] as Array<UserGetPageOutput>,
configOptions: [] as Array<FeedingConfigGetListOutput>,
modelOptions: [] as Array<DictGetListOutput>,
maintenanceStatusOptions: [
{ label: 'Offline', value: 0 },
{ label: 'Idle', value: 1 },
{ label: 'Busy', value: 2 },
{ label: 'Error', value: 3 },
],
ruleRules: {
deviceNo: [
{ required: true, message: '设备编号不能为空', trigger: 'blur' },
{ min: 1, max: 50, message: '设备编号长度应在1-50个字符', trigger: 'blur' }
],
assetNo: [
{ required: true, message: '资产编号不能为空', trigger: 'blur' },
{ min: 1, max: 50, message: '资产编号长度应在1-50个字符', trigger: 'blur' }
],
model: [{ required: true, message: '设备型号不能为空', trigger: 'change' }],
specification: [
{ required: true, message: '规格不能为空', trigger: 'blur' },
{ min: 1, max: 100, message: '规格长度应在1-100个字符', trigger: 'blur' }
],
principalId: [{ required: true, message: '设备负责人不能为空', trigger: 'change' }],
pumpSpeed: [{ required: true, message: '泵速不能为空', trigger: 'blur' }],
pumpTimeout: [{ required: true, message: '超时时间不能为空', trigger: 'blur' }],
workingSpeed: [{ required: true, message: '工作泵速不能为空', trigger: 'blur' }],
workingTime: [{ required: true, message: '时长不能为空', trigger: 'blur' }],
speedCoefficient: [{ required: true, message: '泵速系数不能为空', trigger: 'blur' }],
ip: [
{ required: true, message: 'IP地址不能为空', trigger: 'blur' },
{ pattern: /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/, message: '请输入正确的IP地址格式', trigger: 'blur' }
],
port: [
{ required: true, message: '端口号不能为空', trigger: 'blur' },
{ pattern: /^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/, message: '请输入正确的端口号(1-65535)', trigger: 'blur' }
],
},
})
onMounted(() => {
getUserOptions()
getConfigOptions()
getModelOptions()
})
// 打开弹窗
const openDialog = async (row?: any) => {
resetForm()
// 确保用户数据已加载
if (state.userOptions.length === 0) {
await getUserOptions()
}
// 确保配置数据已加载
if (state.configOptions.length === 0) {
await getConfigOptions()
}
// 确保设备型号数据已加载
if (state.modelOptions.length === 0) {
await getModelOptions()
}
if (row && row.id) {
// 编辑模式,获取详情
try {
const res = await new PumpApi().get({ id: row.id })
if (res?.success && res.data) {
state.ruleForm = {
id: res.data.id,
deviceNo: res.data.deviceNo || '',
assetNo: res.data.assetNo || '',
model: res.data.model || '',
specification: res.data.specification || '',
pumpSpeed: res.data.pumpSpeed || 0,
principalId: res.data.principalId,
pumpTimeout: res.data.pumpTimeout || 0,
maintenanceFlag: res.data.maintenanceFlag ?? 1,
ip: res.data.ip || '',
port: res.data.port || '',
speedCoefficient: res.data.speedCoefficient || 0,
serviceName: res.data.serviceName || '',
isAirPump: true, // 固定为false
configId: res.data.configId,
workingSpeed: res.data.workingSpeed || 0,
workingTime: res.data.workingTime || 0,
}
}
} catch (error: any) {
if (error.response?.status === 500) {
proxy.$modal.msgError('服务器内部错误,请检查后台服务')
} else {
proxy.$modal.msgError(`获取详情失败: ${error.response?.data?.msg || error.message}`)
}
return
}
}
state.isShowDialog = true
}
// 关闭弹窗
const closeDialog = () => {
state.isShowDialog = false
resetForm()
}
// 重置表单
const resetForm = () => {
state.ruleForm = {
id: undefined,
deviceNo: '',
assetNo: '',
model: '',
specification: '',
pumpSpeed: 0,
principalId: undefined,
pumpTimeout: 0,
maintenanceFlag: 1,
ip: '',
port: '',
speedCoefficient: 0,
serviceName: '',
isAirPump: false,
configId: undefined,
workingSpeed: 0,
workingTime: 0,
}
}
// 获取用户选项
const getUserOptions = async () => {
try {
const userPageInput = {
currentPage: 1,
pageSize: 1000,
filter: {
orgId: null,
}
} as PageInputUserGetPageInput
const res = await new UserApi().getPage(userPageInput)
if (res?.success) {
state.userOptions = res.data?.list ?? []
}
} catch (error) {
// 静默处理错误
}
}
// 获取泵速策略选项
const getConfigOptions = async () => {
state.configLoading = true
try {
const res = await new FeedingConfigApi().getList()
if (res?.success && res.data) {
state.configOptions = res.data
}
} catch (error) {
// 静默处理错误
} finally {
state.configLoading = false
}
}
// 获取设备型号选项
const getModelOptions = async () => {
try {
const res = await new DictApi().getList(['PUMPTYPE'])
if (res?.success && res.data) {
// 注意API返回的key是小写的 pumptype
state.modelOptions = res.data['pumptype'] || []
}
} catch (error) {
// 静默处理错误
}
}
// 取消
const onCancel = () => {
closeDialog()
}
// 提交
const onSubmit = () => {
pumpFormRef.value.validate(async (valid: boolean) => {
if (!valid) return false
state.loading = true
try {
let res = {} as any
// 确保 isAirPump 为 false
const formData = { ...state.ruleForm, isAirPump: true }
if (formData.id) {
res = await new PumpApi().update(formData as any, { showSuccessMessage: true })
} else {
res = await new PumpApi().add(formData as any, { showSuccessMessage: true })
}
if (res?.success) {
closeDialog()
emit('refresh')
eventBus.emit('refreshAirPump' as keyof MittType<any>)
}
} catch (error: any) {
proxy.$modal.msgError('操作失败')
} finally {
state.loading = false
}
})
}
// 暴露变量
defineExpose({
openDialog,
closeDialog,
})
</script>
<style scoped lang="scss">
.form-section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 2px solid #f0f0f0;
position: relative;
&:before {
content: '';
position: absolute;
left: 0;
bottom: -2px;
width: 40px;
height: 2px;
background: #409eff;
}
}
:deep(.el-form-item) {
margin-bottom: 18px;
}
:deep(.el-switch__label) {
font-size: 13px;
}
</style>