|
|
@@ -145,6 +145,64 @@
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
|
|
|
+ <!-- 动态属性区域:施工工艺与当日生产动态之间 -->
|
|
|
+ <el-row v-if="dynamicAttrs.length > 0">
|
|
|
+ <el-col
|
|
|
+ v-for="attr in dynamicAttrs"
|
|
|
+ :key="attr.id"
|
|
|
+ :span="attr.dataType === 'textarea' ? 24 : 12"
|
|
|
+ >
|
|
|
+ <el-form-item
|
|
|
+ :label="attr.name + (attr.unit ? `(${attr.unit})` : '')"
|
|
|
+ :prop="'dynamicFields.' + attr.identifier"
|
|
|
+ :rules="getDynamicAttrRules(attr)"
|
|
|
+ >
|
|
|
+ <!-- 文本类型 -->
|
|
|
+ <el-input
|
|
|
+ v-if="attr.dataType === 'text'"
|
|
|
+ v-model="formData.dynamicFields[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 文本域类型 -->
|
|
|
+ <el-input
|
|
|
+ v-else-if="attr.dataType === 'textarea'"
|
|
|
+ v-model="formData.dynamicFields[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 数字类型 -->
|
|
|
+ <el-input
|
|
|
+ v-else-if="attr.dataType === 'double'"
|
|
|
+ v-model="formData.dynamicFields[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ type="number"
|
|
|
+ :min="attr.minValue || undefined"
|
|
|
+ :max="attr.maxValue || undefined"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 日期类型 -->
|
|
|
+ <el-date-picker
|
|
|
+ v-else-if="attr.dataType === 'date'"
|
|
|
+ v-model="formData.dynamicFields[attr.identifier]"
|
|
|
+ type="date"
|
|
|
+ value-format="x"
|
|
|
+ :placeholder="`选择${attr.name}`"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 默认文本输入 -->
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ v-model="formData.dynamicFields[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
<!-- 第三行:当日生产动态 -->
|
|
|
<el-row>
|
|
|
<el-col :span="24">
|
|
|
@@ -211,6 +269,7 @@ import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
|
import {DICT_TYPE, getDictLabel, getStrDictOptions} from '@/utils/dict'
|
|
|
import { IotRdDailyReportApi } from '@/api/pms/iotrddailyreport'
|
|
|
+import { IotDailyReportAttrsApi } from '@/api/pms/iotdailyreportattrs'
|
|
|
import * as DeptApi from '@/api/system/dept'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
import dayjs from 'dayjs'
|
|
|
@@ -232,10 +291,8 @@ const id = params.id // 瑞都日报id
|
|
|
// 日报数据
|
|
|
const dailyReportData = ref<any>({})
|
|
|
|
|
|
-// 施工工艺相关变量
|
|
|
-const technologyOptions = ref<any[]>([])
|
|
|
-const loadingTechnologyOptions = ref(false)
|
|
|
-const currentTechnologyDictLabel = ref(''); // 存储当前项目对应的施工工艺字典类型
|
|
|
+// 动态属性相关变量
|
|
|
+const dynamicAttrs = ref<any[]>([]) // 存储动态属性列表
|
|
|
|
|
|
// 表单数据
|
|
|
const formData = ref({
|
|
|
@@ -259,7 +316,10 @@ const formData = ref({
|
|
|
techniqueIds: [], // 施工工艺
|
|
|
productionStatus: '', // 当日生产动态
|
|
|
nextPlan: '', // 下步工作计划
|
|
|
- externalRental: '' // 外租设备
|
|
|
+ externalRental: '', // 外租设备
|
|
|
+
|
|
|
+ // 添加动态字段对象
|
|
|
+ dynamicFields: {} as Record<string, any>
|
|
|
})
|
|
|
|
|
|
// 表单验证规则
|
|
|
@@ -270,6 +330,11 @@ const formRules = reactive({
|
|
|
productionStatus: [{ required: true, message: '当日生产动态不能为空', trigger: 'blur' }]
|
|
|
})
|
|
|
|
|
|
+const queryParams = reactive({
|
|
|
+ deptId: undefined,
|
|
|
+ techniqueIds: [],
|
|
|
+})
|
|
|
+
|
|
|
// 下拉选项
|
|
|
const rdStatusOptions = getStrDictOptions(DICT_TYPE.PMS_PROJECT_RD_STATUS) // 施工状态
|
|
|
const techniqueOptions = getStrDictOptions(DICT_TYPE.PMS_PROJECT_RD_TECHNOLOGY) // 瑞都施工工艺
|
|
|
@@ -326,6 +391,13 @@ const submitForm = async () => {
|
|
|
formData.value.endTime = endDate.format('HH:mm:ss')
|
|
|
}
|
|
|
|
|
|
+ // 准备提交数据,包含动态字段
|
|
|
+ const submitData = {
|
|
|
+ ...formData.value,
|
|
|
+ // 将动态字段合并到提交数据中或单独处理,根据后端接口需求调整
|
|
|
+ dynamicFields: formData.value.dynamicFields
|
|
|
+ }
|
|
|
+
|
|
|
// 提交请求
|
|
|
formLoading.value = true
|
|
|
try {
|
|
|
@@ -347,6 +419,143 @@ const resetForm = () => {
|
|
|
formRef.value?.resetFields()
|
|
|
}
|
|
|
|
|
|
+// 初始化动态属性
|
|
|
+const initDynamicAttrs = (reportData: any) => {
|
|
|
+ if (reportData.dailyReportAttrs && reportData.dailyReportAttrs.length > 0) {
|
|
|
+ dynamicAttrs.value = reportData.dailyReportAttrs
|
|
|
+
|
|
|
+ // 初始化动态字段的值
|
|
|
+ const initialDynamicFields: Record<string, any> = {}
|
|
|
+ reportData.dailyReportAttrs.forEach((attr: any) => {
|
|
|
+ // 优先使用实际值,如果没有则使用默认值
|
|
|
+ const value = (attr.extProperty && attr.extProperty.actualValue !== undefined &&
|
|
|
+ attr.extProperty.actualValue !== null && attr.extProperty.actualValue !== '')
|
|
|
+ ? attr.extProperty.actualValue
|
|
|
+ : (attr.defaultValue || (attr.extProperty?.defaultValue || ''))
|
|
|
+
|
|
|
+ initialDynamicFields[attr.identifier] = value
|
|
|
+ })
|
|
|
+
|
|
|
+ formData.value.dynamicFields = initialDynamicFields
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取动态字段的验证规则
|
|
|
+const getDynamicAttrRules = (attr: any) => {
|
|
|
+ const rules = []
|
|
|
+ if (attr.required === 1) {
|
|
|
+ rules.push({
|
|
|
+ required: true,
|
|
|
+ message: `${attr.name}不能为空`,
|
|
|
+ trigger: 'blur'
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数字类型验证
|
|
|
+ if (attr.dataType === 'double') {
|
|
|
+ rules.push({
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ if (value === '' || value === null || value === undefined) {
|
|
|
+ callback()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const numValue = Number(value)
|
|
|
+ if (isNaN(numValue)) {
|
|
|
+ callback(new Error(`${attr.name}必须是数字`))
|
|
|
+ } else if (attr.minValue && numValue < Number(attr.minValue)) {
|
|
|
+ callback(new Error(`${attr.name}不能小于${attr.minValue}`))
|
|
|
+ } else if (attr.maxValue && numValue > Number(attr.maxValue)) {
|
|
|
+ callback(new Error(`${attr.name}不能大于${attr.maxValue}`))
|
|
|
+ } else {
|
|
|
+ callback()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ trigger: 'blur'
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return rules
|
|
|
+}
|
|
|
+
|
|
|
+// 更新动态属性(处理交集、新增和删除)
|
|
|
+const updateDynamicAttrs = async (newAttrs: any[], newTechniqueIds: string[], oldTechniqueIds?: string[]) => {
|
|
|
+ const oldAttrs = [...dynamicAttrs.value]
|
|
|
+ const oldDynamicFields = { ...formData.value.dynamicFields }
|
|
|
+
|
|
|
+ // 计算需要保留的字段(交集)
|
|
|
+ const commonAttrs = oldAttrs.filter(oldAttr =>
|
|
|
+ newAttrs.some(newAttr => newAttr.identifier === oldAttr.identifier)
|
|
|
+ )
|
|
|
+
|
|
|
+ // 计算需要新增的字段
|
|
|
+ const addedAttrs = newAttrs.filter(newAttr =>
|
|
|
+ !oldAttrs.some(oldAttr => oldAttr.identifier === newAttr.identifier)
|
|
|
+ )
|
|
|
+
|
|
|
+ // 计算需要删除的字段
|
|
|
+ const removedAttrs = oldAttrs.filter(oldAttr =>
|
|
|
+ !newAttrs.some(newAttr => newAttr.identifier === oldAttr.identifier)
|
|
|
+ )
|
|
|
+
|
|
|
+ // 构建新的动态属性数组
|
|
|
+ const updatedAttrs = [...commonAttrs, ...addedAttrs]
|
|
|
+
|
|
|
+ // 构建新的动态字段对象
|
|
|
+ const updatedDynamicFields = { ...oldDynamicFields }
|
|
|
+
|
|
|
+ // 移除已删除的字段
|
|
|
+ removedAttrs.forEach(attr => {
|
|
|
+ delete updatedDynamicFields[attr.identifier]
|
|
|
+ })
|
|
|
+
|
|
|
+ // 初始化新增字段的值
|
|
|
+ addedAttrs.forEach(attr => {
|
|
|
+ if (!updatedDynamicFields[attr.identifier]) {
|
|
|
+ // 如果有默认值使用默认值,否则为空
|
|
|
+ updatedDynamicFields[attr.identifier] = attr.defaultValue ||
|
|
|
+ (attr.extProperty?.defaultValue || '')
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 更新响应式数据
|
|
|
+ dynamicAttrs.value = updatedAttrs
|
|
|
+ formData.value.dynamicFields = updatedDynamicFields
|
|
|
+}
|
|
|
+
|
|
|
+// 加载动态属性
|
|
|
+const loadDynamicAttrs = async (newTechniqueIds: string[], oldTechniqueIds?: string[]) => {
|
|
|
+ try {
|
|
|
+ formLoading.value = true
|
|
|
+
|
|
|
+ const queryParams = {
|
|
|
+ techniqueIds: newTechniqueIds.join(',')
|
|
|
+ }
|
|
|
+
|
|
|
+ const response = await IotDailyReportAttrsApi.dailyReportAttrs(queryParams)
|
|
|
+ const newAttrs = response || []
|
|
|
+
|
|
|
+ // 处理动态属性更新
|
|
|
+ await updateDynamicAttrs(newAttrs, newTechniqueIds, oldTechniqueIds)
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载动态属性失败:', error)
|
|
|
+ message.error('加载动态属性失败')
|
|
|
+ } finally {
|
|
|
+ formLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 监听施工工艺变化
|
|
|
+watch(() => formData.value.techniqueIds, async (newTechniqueIds, oldTechniqueIds) => {
|
|
|
+ if (newTechniqueIds && newTechniqueIds.length > 0) {
|
|
|
+ await loadDynamicAttrs(newTechniqueIds, oldTechniqueIds)
|
|
|
+ } else {
|
|
|
+ dynamicAttrs.value = []
|
|
|
+ formData.value.dynamicFields = {}
|
|
|
+ }
|
|
|
+}, { deep: true })
|
|
|
+
|
|
|
// 初始化表单数据
|
|
|
const initFormData = (reportData: any) => {
|
|
|
formData.value = {
|
|
|
@@ -360,9 +569,10 @@ const initFormData = (reportData: any) => {
|
|
|
externalRental: reportData.externalRental || '',
|
|
|
startTime: reportData.startTime || undefined,
|
|
|
endTime: reportData.endTime || undefined,
|
|
|
- companyId: reportData.companyId || ''
|
|
|
+ companyId: reportData.companyId || '',
|
|
|
+ dynamicFields: {} // 确保有初始值
|
|
|
}
|
|
|
-
|
|
|
+ queryParams.deptId = reportData.companyId
|
|
|
// 设置时间范围选择器
|
|
|
if (reportData.startTime && reportData.startTime[0] && reportData.endTime && reportData.endTime[0]) {
|
|
|
formData.value.timeRange = [
|
|
|
@@ -370,7 +580,8 @@ const initFormData = (reportData: any) => {
|
|
|
new Date(reportData.endTime[0])
|
|
|
]
|
|
|
}
|
|
|
-
|
|
|
+ // 初始化动态属性
|
|
|
+ initDynamicAttrs(reportData)
|
|
|
}
|
|
|
|
|
|
onMounted(async () => {
|