|
@@ -63,32 +63,75 @@
|
|
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
|
|
<el-table-column label="设备编码" align="center" prop="deviceCode" />
|
|
|
<el-table-column label="设备名称" align="center" prop="deviceName" />
|
|
|
- <el-table-column label="所属部门" align="center" prop="deptName" />
|
|
|
- <el-table-column label="设备状态" align="center" prop="deviceStatus" >
|
|
|
+ <el-table-column label="运行时间(H)" align="center" prop="runningTime" :formatter="erpPriceTableColumnFormatter"/>
|
|
|
+ <el-table-column label="运行公里数(KM)" align="center" prop="runningKilometers" :formatter="erpPriceTableColumnFormatter"/>
|
|
|
+ <el-table-column label="BOM节点" align="center" prop="name" />
|
|
|
+ <el-table-column label="里程" key="mileageRule">
|
|
|
<template #default="scope">
|
|
|
- <dict-tag :type="DICT_TYPE.PMS_DEVICE_STATUS" :value="scope.row.deviceStatus" />
|
|
|
+ <el-switch
|
|
|
+ v-model="scope.row.mileageRule"
|
|
|
+ :active-value="0"
|
|
|
+ :inactive-value="1"
|
|
|
+ />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="资产性质" align="center" prop="assetProperty" >
|
|
|
+ <el-table-column label="里程周期(H)" align="center" prop="nextRunningKilometers" :formatter="erpPriceTableColumnFormatter">
|
|
|
<template #default="scope">
|
|
|
- <dict-tag :type="DICT_TYPE.PMS_ASSET_PROPERTY" :value="scope.row.assetProperty" />
|
|
|
+ <el-input v-model="scope.row.nextRunningKilometers" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="运行时间" key="runningTimeRule">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-switch
|
|
|
+ v-model="scope.row.runningTimeRule"
|
|
|
+ :active-value="0"
|
|
|
+ :inactive-value="1"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="时间周期(H)" align="center" prop="nextRunningTime" :formatter="erpPriceTableColumnFormatter">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-input v-model="scope.row.nextRunningTime" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="自然日期" key="naturalDateRule">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-switch
|
|
|
+ v-model="scope.row.naturalDateRule"
|
|
|
+ :active-value="0"
|
|
|
+ :inactive-value="1"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="自然日期(D)" align="center" prop="nextNaturalDate" :formatter="erpPriceTableColumnFormatter">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-input v-model="scope.row.nextNaturalDate" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="备注" align="center" prop="remark" />
|
|
|
<el-table-column label="操作" align="center" min-width="120px">
|
|
|
<template #default="scope">
|
|
|
<div style="display: flex; justify-content: center; align-items: center; width: 100%">
|
|
|
- <div>
|
|
|
+ <div>
|
|
|
<Icon style="vertical-align: middle; color: #ea3434" icon="ep:zoom-out" />
|
|
|
<el-button
|
|
|
style="vertical-align: middle"
|
|
|
link
|
|
|
type="danger"
|
|
|
- @click="handleDelete(scope.row.id)"
|
|
|
+ @click="handleDelete(scope.row.id+'-'+scope.row.bomNodeId)"
|
|
|
>
|
|
|
移除
|
|
|
</el-button>
|
|
|
</div>
|
|
|
+ <!-- 新增配置按钮 -->
|
|
|
+ <div style="margin-left: 12px">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ @click="openConfigDialog(scope.row)"
|
|
|
+ >
|
|
|
+ 配置
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
@@ -104,17 +147,73 @@
|
|
|
</el-form>
|
|
|
</ContentWrap>
|
|
|
<MainPlanDeviceList ref="deviceFormRef" @choose="deviceChoose" />
|
|
|
+ <!-- 新增配置对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="configDialog.visible"
|
|
|
+ :title="`设备 ${configDialog.current?.deviceCode+'-'+configDialog.current?.name} 保养配置`"
|
|
|
+ width="600px"
|
|
|
+ >
|
|
|
+ <el-form :model="configDialog.form" label-width="160px">
|
|
|
+ <!-- 里程配置 -->
|
|
|
+ <el-form-item
|
|
|
+ v-if="configDialog.current?.mileageRule === 0"
|
|
|
+ label="上次保养里程数(KM)"
|
|
|
+ prop="lastRunningKilometers"
|
|
|
+ >
|
|
|
+ <el-input-number
|
|
|
+ v-model="configDialog.form.lastRunningKilometers"
|
|
|
+ :precision="2"
|
|
|
+ :min="0"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <!-- 运行时间配置 -->
|
|
|
+ <el-form-item
|
|
|
+ v-if="configDialog.current?.runningTimeRule === 0"
|
|
|
+ label="上次保养运行时间(H)"
|
|
|
+ prop="lastRunningTime"
|
|
|
+ >
|
|
|
+ <el-input-number
|
|
|
+ v-model="configDialog.form.lastRunningTime"
|
|
|
+ :precision="1"
|
|
|
+ :min="0"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <!-- 自然日期配置 -->
|
|
|
+ <el-form-item
|
|
|
+ v-if="configDialog.current?.naturalDateRule === 0"
|
|
|
+ label="上次保养自然日期(D)"
|
|
|
+ prop="lastNaturalDate"
|
|
|
+ >
|
|
|
+ <el-input-number
|
|
|
+ v-model="configDialog.form.lastNaturalDate"
|
|
|
+ :precision="1"
|
|
|
+ :min="0"
|
|
|
+ controls-position="right"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="configDialog.visible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="saveConfig">保存</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
import { IotMaintainApi, IotMaintainVO } from '@/api/pms/maintain'
|
|
|
+import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
|
|
|
import * as UserApi from '@/api/system/user'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
import { ref } from 'vue'
|
|
|
-import { IotMaintainMaterialVO } from '@/api/pms/maintain/material'
|
|
|
+import { IotMaintenanceBomApi, IotMaintenanceBomVO } from '@/api/pms/iotmaintenancebom'
|
|
|
+import { IotMaintenancePlanApi, IotMaintenancePlanVO } from '@/api/pms/maintenance'
|
|
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
|
import {CACHE_KEY, useCache} from "@/hooks/web/useCache";
|
|
|
-import {DICT_TYPE} from "@/utils/dict";
|
|
|
import MainPlanDeviceList from "@/views/pms/maintenance/MainPlanDeviceList.vue";
|
|
|
+import * as DeptApi from "@/api/system/dept";
|
|
|
+import {erpPriceTableColumnFormatter} from "@/utils";
|
|
|
|
|
|
/** 保养计划 表单 */
|
|
|
defineOptions({ name: 'IotAddMainPlan' })
|
|
@@ -124,37 +223,24 @@ const message = useMessage() // 消息弹窗
|
|
|
const { delView } = useTagsViewStore() // 视图操作
|
|
|
const { currentRoute, push } = useRouter()
|
|
|
const deptUsers = ref<UserApi.UserVO[]>([]) // 用户列表
|
|
|
+const dept = ref() // 当前登录人所属部门对象
|
|
|
const dialogTitle = ref('') // 弹窗的标题
|
|
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
|
|
const deviceLabel = ref('') // 表单的类型:create - 新增;update - 修改
|
|
|
-const list = ref<IotMaintainMaterialVO[]>([]) // 列表的数据
|
|
|
+const list = ref<IotMaintenanceBomVO[]>([]) // 设备bom关联列表的数据
|
|
|
+const deviceIds = ref<number[]>([]) // 已经选择的设备id数组
|
|
|
const { params, name } = useRoute() // 查询参数
|
|
|
const id = params.id
|
|
|
const formData = ref({
|
|
|
id: undefined,
|
|
|
- name: undefined,
|
|
|
+ deptId: undefined,
|
|
|
+ name: '',
|
|
|
serialNumber: undefined,
|
|
|
+ responsiblePerson: undefined,
|
|
|
+ remark: undefined,
|
|
|
failureName: undefined,
|
|
|
- deviceId: undefined,
|
|
|
status: undefined,
|
|
|
- type: undefined,
|
|
|
- ifStop: undefined,
|
|
|
- failureTime: undefined,
|
|
|
- failureInfluence: undefined,
|
|
|
- failureSystem: undefined,
|
|
|
- description: undefined,
|
|
|
- pic: undefined,
|
|
|
- solution: undefined,
|
|
|
- maintainStartTime: undefined,
|
|
|
- maintainEndTime: undefined,
|
|
|
- remark: undefined,
|
|
|
- deviceName: undefined,
|
|
|
- processInstanceId: undefined,
|
|
|
- auditStatus: undefined,
|
|
|
- deptId: undefined,
|
|
|
- responsiblePerson: undefined,
|
|
|
- maintainDescription: undefined,
|
|
|
})
|
|
|
const formRules = reactive({
|
|
|
name: [{ required: true, message: '计划名称不能为空', trigger: 'blur' }],
|
|
@@ -162,26 +248,85 @@ const formRules = reactive({
|
|
|
})
|
|
|
const formRef = ref() // 表单 Ref
|
|
|
|
|
|
-const deviceChoose = (selectedDevices) => {
|
|
|
- // formData.value.deviceId = row.id
|
|
|
- // formData.value.deviceName = row.deviceName
|
|
|
- // formData.value.deptId = row.deptId
|
|
|
- // deviceLabel.value = row.deviceName
|
|
|
+// 新增配置相关状态
|
|
|
+const configDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ current: null as IotMaintenanceBomVO | null,
|
|
|
+ form: {
|
|
|
+ lastRunningKilometers: 0,
|
|
|
+ lastRunningTime: 0,
|
|
|
+ lastNaturalDate: 0
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 打开配置对话框
|
|
|
+const openConfigDialog = (row: IotMaintenanceBomVO) => {
|
|
|
+ configDialog.current = row
|
|
|
+ configDialog.form = {
|
|
|
+ lastRunningKilometers: row.lastRunningKilometers || 0,
|
|
|
+ lastRunningTime: row.lastRunningTime || 0,
|
|
|
+ lastNaturalDate: row.lastNaturalDate || 0
|
|
|
+ }
|
|
|
+ configDialog.visible = true
|
|
|
+}
|
|
|
+
|
|
|
+// 保存配置
|
|
|
+const saveConfig = () => {
|
|
|
+ if (!configDialog.current) return
|
|
|
+ // 更新当前行的数据
|
|
|
+ Object.assign(configDialog.current, configDialog.form)
|
|
|
+ configDialog.visible = false
|
|
|
+}
|
|
|
+
|
|
|
+const queryParams = reactive({
|
|
|
+ deviceIds: undefined
|
|
|
+})
|
|
|
+
|
|
|
+const deviceChoose = async(selectedDevices) => {
|
|
|
+ const newIds = selectedDevices.map(device => device.id)
|
|
|
+ deviceIds.value = [...new Set([...deviceIds.value, ...newIds])]
|
|
|
+ const params = {
|
|
|
+ deviceIds: deviceIds.value.join(',') // 明确传递数组参数
|
|
|
+ }
|
|
|
+ // console.log('请求参数:', JSON.parse(JSON.stringify(params.deviceIds)))
|
|
|
+ queryParams.deviceIds = JSON.parse(JSON.stringify(params.deviceIds))
|
|
|
+ // 根据选择的设备筛选出设备关系的分类BOM中与保养相关的节点项
|
|
|
+ const res = await IotDeviceApi.deviceAssociateBomList(queryParams)
|
|
|
+ const rawData = res || []
|
|
|
+ if(rawData.length === 0){
|
|
|
+ message.error('选择的设备不存在待保养BOM项')
|
|
|
+ }
|
|
|
+ if (!Array.isArray(rawData)) {
|
|
|
+ console.error('接口返回数据结构异常:', rawData)
|
|
|
+ return
|
|
|
+ }
|
|
|
// 转换数据结构(根据你的接口定义调整)
|
|
|
- const newItems = selectedDevices.map(device => ({
|
|
|
+ const newItems = rawData.map(device => ({
|
|
|
+ assetClass: device.assetClass,
|
|
|
deviceCode: device.deviceCode,
|
|
|
deviceName: device.deviceName,
|
|
|
deviceStatus: device.deviceStatus,
|
|
|
deptName: device.deptName,
|
|
|
+ name: device.name,
|
|
|
+ code: device.code,
|
|
|
assetProperty: device.assetProperty,
|
|
|
remark: null, // 初始化备注
|
|
|
- id: device.id // 移除操作需要
|
|
|
+ deviceId: device.id, // 移除操作需要
|
|
|
+ bomNodeId: device.bomNodeId,
|
|
|
+ runningTime: 0,
|
|
|
+ runningKilometers: 0,
|
|
|
+ nextRunningKilometers: 0,
|
|
|
+ nextRunningTime: 0,
|
|
|
+ nextNaturalDate: 0,
|
|
|
}))
|
|
|
-
|
|
|
+ // 获取选择的设备相关的id数组
|
|
|
+ newItems.forEach(item => {
|
|
|
+ deviceIds.value.push(item.deviceId)
|
|
|
+ })
|
|
|
// 合并到现有列表(去重)
|
|
|
newItems.forEach(item => {
|
|
|
const exists = list.value.some(
|
|
|
- existing => existing.id === item.id
|
|
|
+ existing => (existing.deviceId === item.deviceId && existing.bomNodeId === item.bomNodeId)
|
|
|
)
|
|
|
if (!exists) {
|
|
|
list.value.push(item)
|
|
@@ -223,23 +368,19 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成
|
|
|
const submitForm = async () => {
|
|
|
// 校验表单
|
|
|
await formRef.value.validate()
|
|
|
- if (list.value.length > 0) {
|
|
|
- const nullList = list.value.filter((item) => item.depleteCount===null)
|
|
|
- if (nullList.length > 0) {
|
|
|
- message.error('请填写消耗数量')
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ // 校验表格数据
|
|
|
+ const isValid = validateTableData()
|
|
|
+ if (!isValid) return
|
|
|
// 提交请求
|
|
|
formLoading.value = true
|
|
|
try {
|
|
|
const data = {
|
|
|
- maintain: formData.value,
|
|
|
- maintainMaterials: list.value
|
|
|
+ mainPlan: formData.value,
|
|
|
+ mainPlanBom: list.value
|
|
|
}
|
|
|
+ // console.log('列表数据:'+data.mainPlanBom[0].lastRunningKilometers)
|
|
|
if (formType.value === 'create') {
|
|
|
- await IotMaintainApi.createIotMaintain(data)
|
|
|
+ await IotMaintenancePlanApi.createIotMaintenancePlan(data)
|
|
|
message.success(t('common.createSuccess'))
|
|
|
close()
|
|
|
} else {
|
|
@@ -254,6 +395,76 @@ const submitForm = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/** 校验表格数据 */
|
|
|
+const validateTableData = (): boolean => {
|
|
|
+ let isValid = true
|
|
|
+ const errorMessages: string[] = []
|
|
|
+ const noRulesErrorMessages: string[] = [] // 未设置任何保养项规则 的错误提示信息
|
|
|
+ const noRules: string[] = [] // 行记录中设置了保养规则的记录数量
|
|
|
+ const configErrors: string[] = [] // 保养规则配置弹出框
|
|
|
+ let shouldBreak = false;
|
|
|
+ list.value.forEach((row, index) => {
|
|
|
+ if (shouldBreak) return;
|
|
|
+ const rowNumber = index + 1 // 用户可见的行号从1开始
|
|
|
+ const deviceIdentifier = `${row.deviceCode}-${row.name}` // 设备标识
|
|
|
+ // 校验逻辑
|
|
|
+ const checkConfig = (ruleName: string, ruleValue: number, configField: keyof typeof row) => {
|
|
|
+ if (ruleValue === 0) { // 规则开启
|
|
|
+ if (!row[configField] || row[configField] <= 0) {
|
|
|
+ configErrors.push(`第 ${rowNumber} 行(${deviceIdentifier}):请点击【配置】维护${ruleName}上次保养值`)
|
|
|
+ isValid = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 里程校验逻辑
|
|
|
+ if (row.mileageRule === 0) { // 假设 0 表示开启状态
|
|
|
+ if (!row.nextRunningKilometers || row.nextRunningKilometers <= 0) {
|
|
|
+ errorMessages.push(`第 ${rowNumber} 行:开启里程规则必须填写有效的里程周期`)
|
|
|
+ isValid = false
|
|
|
+ }
|
|
|
+ // 再校验配置值
|
|
|
+ checkConfig('里程', row.mileageRule, 'lastRunningKilometers')
|
|
|
+ } else {
|
|
|
+ noRules.push(`第 ${rowNumber} 行:未设置里程规则`)
|
|
|
+ }
|
|
|
+ // 运行时间校验逻辑
|
|
|
+ if (row.runningTimeRule === 0) {
|
|
|
+ if (!row.nextRunningTime || row.nextRunningTime <= 0) {
|
|
|
+ errorMessages.push(`第 ${rowNumber} 行:开启运行时间规则必须填写有效的时间周期`)
|
|
|
+ isValid = false
|
|
|
+ }
|
|
|
+ checkConfig('运行时间', row.runningTimeRule, 'lastRunningTime')
|
|
|
+ } else {
|
|
|
+ noRules.push(`第 ${rowNumber} 行:未设置运行时间规则`)
|
|
|
+ }
|
|
|
+ // 自然日期校验逻辑
|
|
|
+ if (row.naturalDateRule === 0) {
|
|
|
+ if (!row.nextNaturalDate || row.nextNaturalDate <= 0) {
|
|
|
+ errorMessages.push(`第 ${rowNumber} 行:开启自然日期规则必须填写有效的自然日期周期`)
|
|
|
+ isValid = false
|
|
|
+ }
|
|
|
+ checkConfig('自然日期', row.naturalDateRule, 'lastNaturalDate')
|
|
|
+ } else {
|
|
|
+ noRules.push(`第 ${rowNumber} 行:未设置自然日期规则`)
|
|
|
+ }
|
|
|
+ // 如果选中的一行记录未设置任何保养规则 提示 ‘保养项未设置任何保养规则’
|
|
|
+ if (noRules.length === 3) {
|
|
|
+ isValid = false
|
|
|
+ shouldBreak = true; // 设置标志变量为true,退出循环
|
|
|
+ noRulesErrorMessages.push('保养项至少设置1个保养规则')
|
|
|
+ }
|
|
|
+ noRules.length = 0;
|
|
|
+ })
|
|
|
+ if (errorMessages.length > 0) {
|
|
|
+ message.error('设置保养规则后,请维护对应的周期值')
|
|
|
+ } else if (noRulesErrorMessages.length > 0) {
|
|
|
+ message.error(noRulesErrorMessages.pop())
|
|
|
+ } else if (configErrors.length > 0) {
|
|
|
+ message.error(configErrors.pop())
|
|
|
+ }
|
|
|
+ return isValid
|
|
|
+}
|
|
|
+
|
|
|
/** 重置表单 */
|
|
|
const resetForm = () => {
|
|
|
formData.value = {
|
|
@@ -280,7 +491,12 @@ const resetForm = () => {
|
|
|
}
|
|
|
onMounted(async () => {
|
|
|
const deptId = useUserStore().getUser.deptId
|
|
|
+ // 查询当前登录人所属部门名称
|
|
|
+ dept.value = await DeptApi.getDept(deptId)
|
|
|
+ // 根据当前登录人部门信息生成生成 保养计划 名称
|
|
|
+ formData.value.name = dept.value.name + '-保养计划'
|
|
|
deptUsers.value = await UserApi.getDeptUsersByDeptId(deptId)
|
|
|
+ formData.value.deptId = deptId
|
|
|
if (id){
|
|
|
formType.value = 'update'
|
|
|
const iotMaintain = await IotMaintainApi.getIotMaintain(id);
|
|
@@ -293,12 +509,13 @@ onMounted(async () => {
|
|
|
formData.value.responsiblePerson = userInfo.user.id;
|
|
|
}
|
|
|
})
|
|
|
-const handleDelete = async (id: number) => {
|
|
|
+const handleDelete = async (str: string) => {
|
|
|
try {
|
|
|
- const index = list.value.findIndex((item) => item.code === id)
|
|
|
+ const index = list.value.findIndex((item) => (item.id+'-'+item.bomNodeId) === str)
|
|
|
if (index !== -1) {
|
|
|
// 通过 splice 删除元素
|
|
|
list.value.splice(index, 1)
|
|
|
+ deviceIds.value = []
|
|
|
}
|
|
|
} catch {}
|
|
|
}
|