|
@@ -331,7 +331,64 @@
|
|
|
</el-tooltip>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="16">
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 动态属性部分 -->
|
|
|
+ <el-row v-if="dynamicAttrs.length > 0">
|
|
|
+ <el-col v-for="attr in dynamicAttrs" :key="attr.id" :span="attr.dataType === 'textarea' ? 24 : 8">
|
|
|
+ <el-form-item
|
|
|
+ :label="attr.name + (attr.unit ? `(${attr.unit})` : '')"
|
|
|
+ :prop="attr.identifier"
|
|
|
+ :rules="getDynamicAttrRules(attr)"
|
|
|
+ >
|
|
|
+ <!-- 文本类型 -->
|
|
|
+ <el-input
|
|
|
+ v-if="attr.dataType === 'text'"
|
|
|
+ v-model="currentTask[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 文本域类型 -->
|
|
|
+ <el-input
|
|
|
+ v-else-if="attr.dataType === 'textarea'"
|
|
|
+ v-model="currentTask[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 数字类型 -->
|
|
|
+ <el-input
|
|
|
+ v-else-if="attr.dataType === 'double'"
|
|
|
+ v-model="currentTask[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="currentTask[attr.identifier]"
|
|
|
+ type="date"
|
|
|
+ value-format="x"
|
|
|
+ :placeholder="`选择${attr.name}`"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 默认文本输入 -->
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ v-model="currentTask[attr.identifier]"
|
|
|
+ :placeholder="`请输入${attr.name}`"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="24">
|
|
|
<el-form-item label="备注" prop="remark">
|
|
|
<el-input v-model="currentTask.remark" placeholder="请输入备注" type="textarea" />
|
|
|
</el-form-item>
|
|
@@ -449,7 +506,7 @@ import {useTagsViewStore} from "@/store/modules/tagsView";
|
|
|
import {companyLevelChildrenDepts} from "@/api/system/dept";
|
|
|
import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
|
|
|
import * as UserApi from "@/api/system/user";
|
|
|
-import {selectedDeptsEmployee, UserVO} from "@/api/system/user";
|
|
|
+import {IotProjectTaskAttrsApi, IotProjectTaskAttrsVO} from "@/api/pms/iotprojecttaskattrs";
|
|
|
import {DICT_TYPE, getIntDictOptions, getStrDictOptions} from "@/utils/dict";
|
|
|
|
|
|
const { query, params, name } = useRoute() // 查询参数
|
|
@@ -492,6 +549,12 @@ const responsiblePersonList = ref([]); // 所有责任人列表
|
|
|
const selectedResponsiblePersonIds = ref([]); // 选中的责任人ID
|
|
|
const currentEditingRowForResponsible = ref(null); // 当前正在编辑责任人的行
|
|
|
|
|
|
+// 动态属性相关变量
|
|
|
+const dynamicAttrs = ref([]); // 存储动态属性列表
|
|
|
+
|
|
|
+// 跟踪是否已从任务数据中获取动态属性
|
|
|
+const hasDynamicAttrsFromTask = ref(false);
|
|
|
+
|
|
|
/** 项目信息 表单 */
|
|
|
defineOptions({ name: 'IotProjectTaskInfo' })
|
|
|
|
|
@@ -521,7 +584,7 @@ const close = () => {
|
|
|
push({ name: 'IotProjectTask', params:{}})
|
|
|
}
|
|
|
|
|
|
-const getProjectInfo = (contractId: number) => {
|
|
|
+const getProjectInfo = async (contractId: number) => {
|
|
|
const project = projectList.value.find(item => item.id === contractId);
|
|
|
if (project) {
|
|
|
formData.value.contractName = project.contractName;
|
|
@@ -535,6 +598,9 @@ const getProjectInfo = (contractId: number) => {
|
|
|
formData.value.manufacturerId = project.manufacturerId;
|
|
|
formData.value.id = project.id;
|
|
|
formData.value.deptId = project.deptId; // 保存项目部门ID
|
|
|
+
|
|
|
+ // 获取动态属性
|
|
|
+ await fetchDynamicAttrs();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -623,6 +689,35 @@ const getDeviceNames = (deviceIds: number[]) => {
|
|
|
return deviceNames.join(', ');
|
|
|
};
|
|
|
|
|
|
+// 初始化动态属性到当前任务
|
|
|
+/* const initDynamicAttrsToCurrentTask = () => {
|
|
|
+ dynamicAttrs.value.forEach(attr => {
|
|
|
+ // 如果当前任务中还没有这个属性,则初始化
|
|
|
+ if (!currentTask.value.hasOwnProperty(attr.identifier)) {
|
|
|
+ // 如果是编辑模式且有已有值,使用已有值,否则使用默认值
|
|
|
+ if (formType.value === 'update' && tableData.value[0] && tableData.value[0][attr.identifier] !== undefined) {
|
|
|
+ currentTask.value[attr.identifier] = tableData.value[0][attr.identifier];
|
|
|
+ } else {
|
|
|
+ currentTask.value[attr.identifier] = attr.defaultValue || '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+}; */
|
|
|
+
|
|
|
+const initDynamicAttrsToCurrentTask = () => {
|
|
|
+ dynamicAttrs.value.forEach(attr => {
|
|
|
+ if (!currentTask.value.hasOwnProperty(attr.identifier)) {
|
|
|
+ // 如果是从任务数据中获取的属性,并且有实际值,使用实际值
|
|
|
+ if (hasDynamicAttrsFromTask.value && attr.actualValue !== undefined && attr.actualValue !== null && attr.actualValue !== '') {
|
|
|
+ currentTask.value[attr.identifier] = attr.actualValue;
|
|
|
+ } else {
|
|
|
+ // 否则使用默认值
|
|
|
+ currentTask.value[attr.identifier] = attr.defaultValue || '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
// 当前编辑的任务
|
|
|
const currentTask = ref({
|
|
|
id: undefined,
|
|
@@ -657,6 +752,40 @@ const taskFormRules = reactive({
|
|
|
responsiblePerson: [{ required: true, message: '责任人不能为空', trigger: 'change' }],
|
|
|
});
|
|
|
|
|
|
+// 动态属性验证规则
|
|
|
+const getDynamicAttrRules = (attr) => {
|
|
|
+ const rules = [];
|
|
|
+ if (attr.required === 1) {
|
|
|
+ rules.push({ required: true, message: `${attr.name}不能为空`, trigger: 'blur' });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数字类型验证
|
|
|
+ if (attr.dataType === 'double') {
|
|
|
+ rules.push({
|
|
|
+ validator: (rule, value, callback) => {
|
|
|
+ if (value === '' || value === null || value === undefined) {
|
|
|
+ callback();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const numValue = Number(value);
|
|
|
+ if (isNaN(numValue)) {
|
|
|
+ callback(new Error(`${attr.name}必须是数字`));
|
|
|
+ } else if (attr.minValue !== null && numValue < Number(attr.minValue)) {
|
|
|
+ // callback(new Error(`${attr.name}不能小于${attr.minValue}`));
|
|
|
+ } else if (attr.maxValue !== null && numValue > Number(attr.maxValue)) {
|
|
|
+ // callback(new Error(`${attr.name}不能大于${attr.maxValue}`));
|
|
|
+ } else {
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ trigger: 'blur'
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return rules;
|
|
|
+};
|
|
|
+
|
|
|
const tableData = ref([]);
|
|
|
|
|
|
// 打开责任人选择对话框(用于表单)
|
|
@@ -681,6 +810,34 @@ const openResponsiblePersonDialogForForm = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 获取动态属性
|
|
|
+const fetchDynamicAttrs = async () => {
|
|
|
+ // 如果已经通过任务数据获取了动态属性,则不再调用接口
|
|
|
+ if (hasDynamicAttrsFromTask.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!formData.value.deptId) {
|
|
|
+ console.warn('部门ID为空,无法获取动态属性');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const queryParams = {
|
|
|
+ deptId: formData.value.deptId
|
|
|
+ };
|
|
|
+
|
|
|
+ const response = await IotProjectTaskAttrsApi.getIotProjectTaskAttrsList(queryParams);
|
|
|
+ dynamicAttrs.value = response || [];
|
|
|
+
|
|
|
+ // 初始化动态属性到当前任务
|
|
|
+ initDynamicAttrsToCurrentTask();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取动态属性失败:', error);
|
|
|
+ ElMessage.error('获取动态属性失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// 打开设备选择对话框(用于表单)
|
|
|
const openDeviceDialogForForm = async () => {
|
|
|
if (!currentTask.value.deptIds || currentTask.value.deptIds.length === 0) {
|
|
@@ -820,6 +977,10 @@ const resetTaskForm = () => {
|
|
|
remark: '',
|
|
|
projectId: formData.value.id
|
|
|
};
|
|
|
+
|
|
|
+ // 重新初始化动态属性
|
|
|
+ initDynamicAttrsToCurrentTask();
|
|
|
+
|
|
|
isNewTask.value = false;
|
|
|
taskFormRef.value?.resetFields();
|
|
|
};
|
|
@@ -944,6 +1105,7 @@ const getAllDeviceNames = (deviceIds: number[]) => {
|
|
|
const open = async () => {
|
|
|
resetForm()
|
|
|
resetTaskForm();
|
|
|
+ hasDynamicAttrsFromTask.value = false; // 重置标志
|
|
|
|
|
|
// 修改时,设置数据
|
|
|
if (id) {
|
|
@@ -999,8 +1161,25 @@ const open = async () => {
|
|
|
// 使用深拷贝,避免修改表单时直接影响表格数据
|
|
|
currentTask.value = JSON.parse(JSON.stringify(tableData.value[0]));
|
|
|
isNewTask.value = false;
|
|
|
- }
|
|
|
|
|
|
+ // 新增代码:检查任务数据中是否有extProperty
|
|
|
+ if (tableData.value[0].extProperty && tableData.value[0].extProperty.length > 0) {
|
|
|
+ // 使用任务数据中的extProperty作为动态属性
|
|
|
+ dynamicAttrs.value = tableData.value[0].extProperty;
|
|
|
+ hasDynamicAttrsFromTask.value = true;
|
|
|
+
|
|
|
+ // 将extProperty中的值设置到当前任务
|
|
|
+ tableData.value[0].extProperty.forEach(attr => {
|
|
|
+ if (attr.identifier) {
|
|
|
+ // 优先使用actualValue,如果没有则使用defaultValue
|
|
|
+ currentTask.value[attr.identifier] =
|
|
|
+ attr.actualValue !== undefined && attr.actualValue !== null && attr.actualValue !== ''
|
|
|
+ ? attr.actualValue
|
|
|
+ : attr.defaultValue || '';
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
} finally {
|
|
|
formLoading.value = false
|
|
|
}
|
|
@@ -1156,6 +1335,32 @@ const submitForm = async () => {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // 处理动态属性数据
|
|
|
+ const processedTableData = tableData.value.map(task => {
|
|
|
+ // 为每个任务构建extProperty数组
|
|
|
+ const extProperties = dynamicAttrs.value.map(attr => {
|
|
|
+ return {
|
|
|
+ name: attr.name,
|
|
|
+ sort: attr.sort,
|
|
|
+ unit: attr.unit,
|
|
|
+ actualValue: task[attr.identifier] || '', // 从任务中获取用户填写的值
|
|
|
+ dataType: attr.dataType,
|
|
|
+ maxValue: attr.maxValue,
|
|
|
+ minValue: attr.minValue,
|
|
|
+ required: attr.required,
|
|
|
+ accessMode: attr.accessMode,
|
|
|
+ identifier: attr.identifier,
|
|
|
+ defaultValue: attr.defaultValue
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ // 返回处理后的任务数据,包含extProperty字段
|
|
|
+ return {
|
|
|
+ ...task,
|
|
|
+ extProperty: extProperties
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
// 提交请求
|
|
|
formLoading.value = true
|
|
|
try {
|
|
@@ -1164,7 +1369,7 @@ const submitForm = async () => {
|
|
|
})
|
|
|
|
|
|
const data = {
|
|
|
- taskList: tableData.value
|
|
|
+ taskList: processedTableData
|
|
|
}
|
|
|
if (formType.value === 'create') {
|
|
|
await IotProjectTaskApi.createIotProjectTask(data)
|