瀏覽代碼

pms 项目任务 嵌套数据字典 值字段

zhangcl 4 周之前
父節點
當前提交
e464fcebdf

+ 2 - 1
src/locales/en.ts

@@ -260,7 +260,8 @@ export default {
   project: {
     payment: 'Payment',
     overseaFlag: 'Overseas Project',
-    area: 'Area',
+    overseaArea: 'Overseas Area',
+    workArea: 'Work Area',
     wellType: 'Well Type',
     wellCategory: 'Well Category',
     technology: 'Technology',

+ 2 - 1
src/locales/ru.ts

@@ -225,7 +225,8 @@ export default {
   project: {
     payment: '结算方式',
     overseaFlag: '是否海外项目',
-    area: '项目区域',
+    overseaArea: '海外项目区域',
+    workArea: '施工区域',
     wellType: '井型',
     wellCategory: '井别',
     technology: '施工工艺',

+ 2 - 1
src/locales/zh-CN.ts

@@ -262,7 +262,8 @@ export default {
   project: {
     payment: '结算方式',
     overseaFlag: '是否海外项目',
-    area: '项目区域',
+    overseaArea: '海外项目区域',
+    workArea: '施工区域',
     wellType: '井型',
     wellCategory: '井别',
     technology: '施工工艺',

+ 2 - 1
src/utils/dict.ts

@@ -284,5 +284,6 @@ export enum DICT_TYPE {
   PMS_PROJECT_WELL_TYPE = 'rq_iot_project_well_type',  // 日报 项目管理 井型
   PMS_PROJECT_WELL_CATEGORY = 'rq_iot_project_well_category',  // 日报 项目管理 井别
   PMS_PROJECT_TECHNOLOGY = 'rq_iot_project_technology',  // 日报 项目管理 施工工艺
-  PMS_PROJECT_WORKLOAD_UNIT = 'rq_iot_project_measure_unit'  // 日报 项目管理 工作量单位
+  PMS_PROJECT_WORKLOAD_UNIT = 'rq_iot_project_measure_unit',  // 日报 项目管理 工作量单位
+  PMS_PROJECT_WORK_AREA = 'rq_iot_project_work_area'  // 日报 施工区域
 }

+ 163 - 13
src/views/pms/iotprojectinfo/IotProjectInfoForm.vue

@@ -45,7 +45,7 @@
           </el-form-item>
         </el-col>
       </el-row>
-
+      <!--
       <el-row>
         <el-col :span="12">
           <el-form-item label="总数" prop="workloadTotal">
@@ -58,7 +58,7 @@
           </el-form-item>
         </el-col>
       </el-row>
-
+      -->
       <el-row>
         <el-col :span="12">
           <el-form-item label="开始时间" prop="startTime">
@@ -127,7 +127,7 @@
 
       <el-row>
         <el-col :span="12">
-          <el-form-item :label="t('project.overseaFlag')" prop="payment">
+          <el-form-item :label="t('project.overseaFlag')" prop="overseas">
             <el-select v-model="formData.overseas" placeholder="请选择" clearable>
               <el-option
                 v-for="dict in getIntDictOptions(DICT_TYPE.PMS_PROJECT_OVERSEA_FLAG)"
@@ -139,7 +139,7 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item :label="t('project.area')" prop="payment">
+          <el-form-item :label="t('project.overseaArea')" prop="overseasArea">
             <el-select v-model="formData.overseasArea" placeholder="请选择" clearable>
               <el-option
                 v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_AREA)"
@@ -153,7 +153,31 @@
       </el-row>
 
       <el-row>
-        <el-col :span="24">
+        <el-col :span="12">
+          <el-form-item :label="t('project.workArea')" prop="location">
+            <el-autocomplete
+              ref="workAreaAutocomplete"
+              v-model="formData.location"
+              :fetch-suggestions="querySearch"
+              :trigger-on-focus="true"
+              placeholder="请输入施工区域"
+              @focus="handleWorkAreaFocus"
+              @select="handleSelect"
+              :disabled="!workAreaOptions.length"
+              popper-class="work-area-autocomplete"
+            >
+              <template #prefix>
+                <el-icon v-if="loadingWorkAreaOptions" class="is-loading">
+                  <Loading />
+                </el-icon>
+              </template>
+            </el-autocomplete>
+            <div v-if="!workAreaOptions.length" class="el-form-item__error">
+              暂无可用施工区域选项,请手动输入
+            </div>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
           <el-form-item label="备注" prop="remark">
             <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
           </el-form-item>
@@ -214,17 +238,15 @@
 import { IotProjectInfoApi, IotProjectInfoVO } from '@/api/pms/iotprojectinfo'
 import {defaultProps,handleTree} from "@/utils/tree";
 import * as DeptApi from "@/api/system/dept";
-import IotProjectTaskForm from '@/views/pms/iotprojectinfo/IotProjectTaskForm.vue'
 import CustomerList from '@/views/pms/device/CustomerList.vue'
 import {ref} from "vue";
 import {useUserStore} from "@/store/modules/user";
 import {IotProjectTaskApi, IotProjectTaskVO} from "@/api/pms/iotprojecttask";
-import {ElMessageBox} from "element-plus";
-import {updateConfig} from "@/api/infra/config";
 import {useTagsViewStore} from "@/store/modules/tagsView";
 import * as UserApi from "@/api/system/user";
 import {UserVO} from "@/api/system/user";
-import {DICT_TYPE, getIntDictOptions, getStrDictOptions} from "@/utils/dict";
+import {DICT_TYPE, getIntDictOptions, getStrDictOptions, getDictLabel} from "@/utils/dict";
+import { Loading } from '@element-plus/icons-vue'
 
 /** 项目信息 表单 */
 defineOptions({ name: 'IotProjectInfo' })
@@ -251,6 +273,13 @@ const selectedUserIds = ref([]); // 选中的用户ID
 const selectedUserNames = ref(''); // 选中的用户名称显示
 const selectedUserList = ref([]); // 存储选中的用户对象列表
 
+// 添加 workAreaOptions 引用和加载状态
+const workAreaOptions = ref<any[]>([])
+const loadingWorkAreaOptions = ref(false)
+const workAreaAutocomplete = ref() // 添加对el-autocomplete的引用
+// currentDictLabel 响应式变量
+const currentDictLabel = ref(''); // 存储当前项目对应的施工区域字典类型
+
 const formData = ref({
   id: undefined,
   deptId: undefined,
@@ -264,7 +293,10 @@ const formData = ref({
   location: undefined,
   technique: undefined,
   payment: undefined,
-
+  overseas: undefined,
+  overseasArea: undefined,
+  remark: undefined,
+  dictType: undefined,
   userName: useUserStore().getUser.name,
   userId: useUserStore().getUser.userId,
 })
@@ -338,6 +370,38 @@ const fetchUserInfoByIds = async (userIds) => {
   }
 };
 
+// 添加处理施工区域获取焦点的方法
+const handleWorkAreaFocus = async () => {
+  // 如果已经有选项数据,直接显示下拉框
+  if (workAreaOptions.value.length > 0) {
+    // 使用Element Plus提供的方法触发下拉框
+    try {
+      // 直接调用el-autocomplete的focus方法
+      if (workAreaAutocomplete.value && typeof workAreaAutocomplete.value.focus === 'function') {
+        workAreaAutocomplete.value.focus();
+      }
+    } catch (error) {
+      console.error('触发下拉框显示失败:', error)
+    }
+    return
+  }
+
+  // 如果没有选项数据,尝试加载
+  if (formData.value.deptId && !loadingWorkAreaOptions.value) {
+    await loadWorkAreaOptions(formData.value.deptId)
+    // 加载完成后尝试显示下拉框
+    if (workAreaOptions.value.length > 0) {
+      try {
+        if (workAreaAutocomplete.value && typeof workAreaAutocomplete.value.focus === 'function') {
+          workAreaAutocomplete.value.focus();
+        }
+      } catch (error) {
+        console.error('触发下拉框显示失败:', error)
+      }
+    }
+  }
+}
+
 // 根据部门ID获取部门名称
 const getDeptNames = (deptIds) => {
   if (!deptIds || deptIds.length === 0) return '';
@@ -463,9 +527,9 @@ const open = async () => {
         selectedUserIds.value = [...formData.value.responsiblePerson];
       }
 
-      // 如果已有责任人数据,更新显示
-      if (formData.value.responsiblePerson) {
-        // updateSelectedUserNames();
+      // 编辑页面:根据项目所属公司加载施工区域选项
+      if (formData.value.deptId) {
+        await loadWorkAreaOptions(formData.value.deptId);
       }
     } finally {
       formLoading.value = false
@@ -487,6 +551,10 @@ const formRef = ref() // 表单 Ref
 const submitForm = async () => {
   // 校验表单
   await formRef.value.validate()
+
+  // 将当前字典类型赋值给formData
+  formData.value.dictType = currentDictLabel.value;
+
   // 提交请求
   formLoading.value = true
   try {
@@ -722,6 +790,79 @@ const deleteRow = (index) => {
   ElMessage.success('行已删除');
 };
 
+// 添加监听部门ID变化的方法
+watch(() => formData.value.deptId, async (newDeptId, oldDeptId) => {
+  // 只有当部门ID确实发生变化时才加载选项
+  if (newDeptId && newDeptId !== oldDeptId) {
+    await loadWorkAreaOptions(newDeptId);
+  }
+});
+
+// 添加立即执行的监听器,用于处理编辑页面
+watch(() => formData.value.deptId, async (newDeptId) => {
+  if (newDeptId) {
+    await loadWorkAreaOptions(newDeptId);
+  } else {
+    workAreaOptions.value = [];
+  }
+}, { immediate: true });
+
+// 加载工作区域选项的方法
+const loadWorkAreaOptions = async (deptId: number) => {
+  // 如果正在加载,直接返回
+  if (loadingWorkAreaOptions.value) return;
+
+  loadingWorkAreaOptions.value = true;
+  try {
+    // 先尝试通过 getDictLabel 获取字典标签
+    const dictLabel = await getDictLabel(DICT_TYPE.PMS_PROJECT_WORK_AREA, deptId);
+    console.log('当前专业公司的施工区域数据字典类型:' + dictLabel)
+    // 将 dictLabel 存储到 currentDictLabel
+    currentDictLabel.value = dictLabel || ''; // 如果没有获取到,设为空字符串
+
+    if (dictLabel) {
+      // 如果获取到标签,再获取完整的字典选项
+      const dictOptions = getStrDictOptions(dictLabel);
+      console.log('当前专业公司的施工区域数据字典集合长度:' + dictOptions.length)
+      workAreaOptions.value = dictOptions.map(option => ({
+        value: option.label, // 使用标签作为显示值
+        id: option.value     // 保留原始值
+      }));
+    } else {
+      // 如果获取不到标签,清空选项
+      workAreaOptions.value = [];
+    }
+  } catch (error) {
+    console.error('获取工作区域选项失败:', error);
+    workAreaOptions.value = [];
+  } finally {
+    loadingWorkAreaOptions.value = false;
+  }
+}
+
+// 当没有查询字符串时返回所有选项
+const querySearch = (queryString: string, cb: any) => {
+  // 如果没有查询字符串,返回所有选项
+  if (!queryString) {
+    cb(workAreaOptions.value);
+    return;
+  }
+
+  // 有查询字符串时进行筛选
+  const results = workAreaOptions.value.filter(option =>
+    option.value.toLowerCase().includes(queryString.toLowerCase())
+  );
+
+  // 调用 callback 返回建议列表的数据
+  cb(results);
+}
+
+// 添加选择处理方法
+const handleSelect = (item: any) => {
+  // 这里可以根据需要处理选择后的逻辑
+  console.log('选择了:', item.value);
+}
+
 </script>
 
 <style scoped>
@@ -767,4 +908,13 @@ const deleteRow = (index) => {
   width: 100% !important; /* 使面板内部内容宽度占满 */
 }
 
+/* 添加全局样式,用于自定义下拉框 */
+.work-area-autocomplete .el-autocomplete-suggestion__list {
+  max-height: 300px; /* 设置最大高度 */
+  overflow-y: auto; /* 添加垂直滚动条 */
+}
+
+.work-area-autocomplete .el-autocomplete-suggestion__wrap {
+  max-height: 300px; /* 设置最大高度 */
+}
 </style>

+ 175 - 5
src/views/pms/iotprojecttask/IotProjectTaskForm.vue

@@ -229,20 +229,49 @@
 
       <el-row>
         <el-col :span="8">
-          <el-form-item label="施工地点" prop="location">
+          <!-- <el-form-item label="施工地点" prop="location">
             <el-input v-model="currentTask.location" placeholder="请输入施工地点" />
+          </el-form-item> -->
+          <el-form-item :label="t('project.workArea')" prop="location">
+            <el-autocomplete
+              ref="workAreaAutocomplete"
+              v-model="currentTask.location"
+              :fetch-suggestions="querySearch"
+              :trigger-on-focus="true"
+              placeholder="请输入施工区域"
+              @focus="handleWorkAreaFocus"
+              @select="handleSelect"
+              :disabled="!workAreaOptions.length"
+              popper-class="work-area-autocomplete"
+            >
+              <template #prefix>
+                <el-icon v-if="loadingWorkAreaOptions" class="is-loading">
+                  <Loading />
+                </el-icon>
+              </template>
+            </el-autocomplete>
+            <div v-if="!workAreaOptions.length" class="el-form-item__error">
+              暂无可用施工区域选项,请手动输入
+            </div>
           </el-form-item>
         </el-col>
         <el-col :span="8">
           <el-form-item :label="t('project.technology')" prop="technique">
-            <el-select v-model="currentTask.technique" placeholder="请选择施工工艺" clearable>
+            <el-select v-model="currentTask.technique"
+                       placeholder="请选择施工工艺"
+                       clearable
+                       :loading="loadingTechnologyOptions"
+            >
               <el-option
-                v-for="dict in getStrDictOptions(DICT_TYPE.PMS_PROJECT_TECHNOLOGY)"
+                v-for="dict in technologyOptions"
                 :key="dict.value"
                 :label="dict.label"
                 :value="dict.value"
               />
             </el-select>
+            <div v-if="!technologyOptions.length && !loadingTechnologyOptions" class="el-form-item__error">
+              暂无可用施工工艺选项
+            </div>
           </el-form-item>
         </el-col>
         <el-col :span="8">
@@ -511,7 +540,7 @@ import {useTagsViewStore} from "@/store/modules/tagsView";
 import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
 import * as UserApi from "@/api/system/user";
 import {IotProjectTaskAttrsApi, IotProjectTaskAttrsVO} from "@/api/pms/iotprojecttaskattrs";
-import {DICT_TYPE, getIntDictOptions, getStrDictOptions} from "@/utils/dict";
+import {DICT_TYPE, getIntDictOptions, getStrDictOptions, getDictLabel} from "@/utils/dict";
 
 const { query, params, name } = useRoute() // 查询参数
 const id = params.id
@@ -563,6 +592,18 @@ const dynamicAttrs = ref([]); // 存储动态属性列表
 // 跟踪是否已从任务数据中获取动态属性
 const hasDynamicAttrsFromTask = ref(false);
 
+// 添加 workAreaOptions 引用和加载状态
+const workAreaOptions = ref<any[]>([])
+const loadingWorkAreaOptions = ref(false)
+const workAreaAutocomplete = ref() // 添加对el-autocomplete的引用
+// currentDictLabel 响应式变量
+const currentDictLabel = ref(''); // 存储当前项目对应的施工区域字典类型
+
+// 施工工艺相关变量
+const technologyOptions = ref<any[]>([])
+const loadingTechnologyOptions = ref(false)
+const currentTechnologyDictLabel = ref(''); // 存储当前项目对应的施工工艺字典类型
+
 /** 项目信息 表单 */
 defineOptions({ name: 'IotProjectTaskInfo' })
 
@@ -606,7 +647,10 @@ const getProjectInfo = async (contractId: number) => {
     formData.value.manufacturerId = project.manufacturerId;
     formData.value.id = project.id;
     formData.value.deptId = project.deptId; // 保存项目部门ID
-
+    // 获取施工区域数据字典集合
+    await loadWorkAreaOptions(formData.value.deptId);
+    // 获取施工工艺数据字典集合
+    await loadTechnologyOptions(formData.value.deptId);
     // 获取动态属性
     await fetchDynamicAttrs();
   }
@@ -733,6 +777,7 @@ const currentTask = ref({
   wellType: '',
   wellCategory: '',
   location: '',
+  dictType: '',
   technique: '',
   workloadDesign: '',
   workloadUnit: '',
@@ -1329,7 +1374,11 @@ const getAllResponsiblePersonNamesForForm = (responsiblePersonIds: number[]) =>
 
 /** 提交表单 */
 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+
 const submitForm = async () => {
+  // 施工区域的数据字典类型
+  currentTask.value.dictType = currentDictLabel.value;
+
   // 先同步当前任务表单数据到表格
   if (!syncCurrentTaskToTable()) {
     return;
@@ -1365,6 +1414,7 @@ const submitForm = async () => {
     // 返回处理后的任务数据,包含extProperty字段
     return {
       ...task,
+      dictType: task.dictType || currentDictLabel.value, // 确保每个任务都有dictType
       extProperty: extProperties
     };
   });
@@ -1418,6 +1468,126 @@ const resetForm = () => {
   formRef.value?.resetFields()
 }
 
+// 加载工作区域选项的方法
+const loadWorkAreaOptions = async (deptId: number) => {
+  // 如果正在加载,直接返回
+  if (loadingWorkAreaOptions.value) return;
+
+  loadingWorkAreaOptions.value = true;
+  try {
+    // 先尝试通过 getDictLabel 获取字典标签
+    const dictLabel = await getDictLabel(DICT_TYPE.PMS_PROJECT_WORK_AREA, deptId);
+    console.log('当前专业公司的施工区域数据字典类型:' + dictLabel)
+    // 将 dictLabel 存储到 currentDictLabel
+    currentDictLabel.value = dictLabel || ''; // 如果没有获取到,设为空字符串
+
+    if (dictLabel) {
+      // 如果获取到标签,再获取完整的字典选项
+      const dictOptions = getStrDictOptions(dictLabel);
+      console.log('当前专业公司的施工区域数据字典集合长度:' + dictOptions.length)
+      workAreaOptions.value = dictOptions.map(option => ({
+        value: option.label, // 使用标签作为显示值
+        id: option.value     // 保留原始值
+      }));
+    } else {
+      // 如果获取不到标签,清空选项
+      workAreaOptions.value = [];
+    }
+  } catch (error) {
+    console.error('获取工作区域选项失败:', error);
+    workAreaOptions.value = [];
+  } finally {
+    loadingWorkAreaOptions.value = false;
+  }
+}
+
+// 当没有查询字符串时返回所有选项
+const querySearch = (queryString: string, cb: any) => {
+  // 如果没有查询字符串,返回所有选项
+  if (!queryString) {
+    cb(workAreaOptions.value);
+    return;
+  }
+
+  // 有查询字符串时进行筛选
+  const results = workAreaOptions.value.filter(option =>
+    option.value.toLowerCase().includes(queryString.toLowerCase())
+  );
+
+  // 调用 callback 返回建议列表的数据
+  cb(results);
+}
+
+// 添加处理施工区域获取焦点的方法
+const handleWorkAreaFocus = async () => {
+  // 如果已经有选项数据,直接显示下拉框
+  if (workAreaOptions.value.length > 0) {
+    // 使用Element Plus提供的方法触发下拉框
+    try {
+      // 直接调用el-autocomplete的focus方法
+      if (workAreaAutocomplete.value && typeof workAreaAutocomplete.value.focus === 'function') {
+        workAreaAutocomplete.value.focus();
+      }
+    } catch (error) {
+      console.error('触发下拉框显示失败:', error)
+    }
+    return
+  }
+
+  // 如果没有选项数据,尝试加载
+  if (formData.value.deptId && !loadingWorkAreaOptions.value) {
+    await loadWorkAreaOptions(formData.value.deptId)
+    // 加载完成后尝试显示下拉框
+    if (workAreaOptions.value.length > 0) {
+      try {
+        if (workAreaAutocomplete.value && typeof workAreaAutocomplete.value.focus === 'function') {
+          workAreaAutocomplete.value.focus();
+        }
+      } catch (error) {
+        console.error('触发下拉框显示失败:', error)
+      }
+    }
+  }
+}
+
+// 添加选择处理方法
+const handleSelect = (item: any) => {
+  // 这里可以根据需要处理选择后的逻辑
+  console.log('选择了:', item.value);
+}
+
+// 加载施工工艺选项的方法
+const loadTechnologyOptions = async (deptId: number) => {
+  if (loadingTechnologyOptions.value) return;
+
+  loadingTechnologyOptions.value = true;
+  try {
+    // 先尝试通过 getDictLabel 获取字典标签
+    const dictLabel = await getDictLabel(DICT_TYPE.PMS_PROJECT_TECHNOLOGY, deptId);
+    console.log('当前专业公司的施工工艺数据字典类型:' + dictLabel)
+    // 将 dictLabel 存储到 currentTechnologyDictLabel
+    currentTechnologyDictLabel.value = dictLabel || ''; // 如果没有获取到,设为空字符串
+
+    if (dictLabel) {
+      // 如果获取到标签,再获取完整的字典选项
+      const dictOptions = getStrDictOptions(dictLabel);
+      console.log('当前专业公司的施工工艺数据字典集合长度:' + dictOptions.length)
+      technologyOptions.value = dictOptions.map(option => ({
+        value: option.value,
+        label: option.label
+      }));
+    } else {
+      // 如果获取不到标签,清空选项
+      technologyOptions.value = [];
+    }
+  } catch (error) {
+    console.error('获取施工工艺选项失败:', error);
+    technologyOptions.value = [];
+  } finally {
+    loadingTechnologyOptions.value = false;
+  }
+}
+
 // 监听当前任务的变化,设置默认展开的keys
 watch(() => currentTask.value.deptIds, (newVal) => {
   if (newVal && newVal.length > 0) {