فهرست منبع

pms 日报 项目 责任人 穿梭框 样式

zhangcl 1 ماه پیش
والد
کامیت
70232e5b14
2فایلهای تغییر یافته به همراه224 افزوده شده و 6 حذف شده
  1. 15 5
      src/views/pms/iotprojectinfo/IotProjectInfoForm.vue
  2. 209 1
      src/views/pms/iotprojecttask/IotProjectTaskForm.vue

+ 15 - 5
src/views/pms/iotprojectinfo/IotProjectInfoForm.vue

@@ -127,7 +127,7 @@
   <el-dialog
     v-model="userDialogVisible"
     title="选择责任人"
-    width="800px"
+    width="1000px"
     :before-close="handleUserDialogClose"
     class="user-select-dialog"
   >
@@ -176,10 +176,6 @@ 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";
-
-/** 项目信息 表单 */
-defineOptions({ name: 'IotProjectInfo' })
-
 import {useUserStore} from "@/store/modules/user";
 import {IotProjectTaskApi, IotProjectTaskVO} from "@/api/pms/iotprojecttask";
 import {ElMessageBox} from "element-plus";
@@ -188,6 +184,9 @@ import {useTagsViewStore} from "@/store/modules/tagsView";
 import * as UserApi from "@/api/system/user";
 import {UserVO} from "@/api/system/user";
 
+/** 项目信息 表单 */
+defineOptions({ name: 'IotProjectInfo' })
+
 const { params, name } = useRoute() // 查询参数
 const id = params.id
 const { delView } = useTagsViewStore() // 视图操作
@@ -684,8 +683,14 @@ const deleteRow = (index) => {
   padding: 20px 0;
 }
 
+/* 3. 直接调整 el-transfer 左右窗口的宽度 */
+:deep(.el-transfer-panel) {
+  width: 40% !important; /* 强制设置左右面板宽度,确保两侧面板对等 */
+}
+
 .transfer-component {
   width: 100%;
+  min-width: 600px;
 }
 
 :deep(.el-transfer-panel__item) {
@@ -700,4 +705,9 @@ const deleteRow = (index) => {
   display: inline-block;
   max-width: 100%;
 }
+
+:deep(.el-transfer-panel__list) {
+  width: 100% !important; /* 使面板内部内容宽度占满 */
+}
+
 </style>

+ 209 - 1
src/views/pms/iotprojecttask/IotProjectTaskForm.vue

@@ -205,6 +205,34 @@
               </el-tooltip>
             </template>
           </el-table-column>
+
+          <el-table-column prop="responsiblePerson" label="责任人">
+            <template #default="{ row }">
+              <el-tooltip
+                :content="getAllResponsiblePersonNames(row.responsiblePerson)"
+                placement="top"
+                :disabled="!row.responsiblePerson || row.responsiblePerson.length <= 2"
+              >
+                <span v-if="!row.editing" class="responsible-names">
+                  {{ getResponsiblePersonNames(row.responsiblePerson) }}
+                </span>
+                <div v-else>
+                  <el-button
+                    @click="openResponsiblePersonDialog(row)"
+                    type="primary"
+                    size="small"
+                  >
+                    选择责任人
+                  </el-button>
+                  <!--
+                  <span v-if="row.editData.responsiblePersonNames" style="margin-left: 8px;">
+                    {{ row.editData.responsiblePersonNames }}
+                  </span> -->
+                </div>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+
           <el-table-column prop="remark" label="备注">
             <template #default="{ row }">
               <span v-if="!row.editing">{{ row.remark }}</span>
@@ -243,7 +271,7 @@
   <el-dialog
     v-model="deviceDialogVisible"
     title="选择施工设备"
-    width="800px"
+    width="1000px"
     :before-close="handleDeviceDialogClose"
     class="device-select-dialog"
   >
@@ -283,6 +311,44 @@
     </template>
   </el-dialog>
 
+  <!-- 新增责任人选择对话框 -->
+  <el-dialog
+    v-model="responsiblePersonDialogVisible"
+    title="选择责任人"
+    width="1000px"
+    :before-close="handleResponsiblePersonDialogClose"
+    class="responsible-person-select-dialog"
+  >
+    <div class="transfer-container">
+      <el-transfer
+        v-model="selectedResponsiblePersonIds"
+        :data="responsiblePersonList"
+        :titles="['可选人员', '已选人员']"
+        :props="{ key: 'id', label: 'nickname' }"
+        filterable
+        class="transfer-component"
+      >
+        <template #default="{ option }">
+          <el-tooltip
+            effect="dark"
+            placement="top"
+            :content="`${option.nickname} - ${option.deptName || '未分配部门'}`"
+          >
+            <span class="transfer-option-text">
+              {{ option.nickname }} - {{ option.deptName || '未分配部门' }}
+            </span>
+          </el-tooltip>
+        </template>
+      </el-transfer>
+    </div>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="handleResponsiblePersonDialogClose">取消</el-button>
+        <el-button type="primary" @click="confirmResponsiblePersonSelection">确定</el-button>
+      </span>
+    </template>
+  </el-dialog>
+
 </template>
 <script setup lang="ts">
 
@@ -297,6 +363,8 @@ import {ElMessageBox, ElMessage} from "element-plus";
 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 {UserVO} from "@/api/system/user";
 
 const { params, name } = useRoute() // 查询参数
 const id = params.id
@@ -318,6 +386,12 @@ const projectList = ref<IotProjectInfoVO[]>([])
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const loading = ref(true) // 列表的加载中
 
+// 新增责任人相关变量
+const responsiblePersonDialogVisible = ref(false);
+const responsiblePersonList = ref([]); // 所有责任人列表
+const selectedResponsiblePersonIds = ref([]); // 选中的责任人ID
+const currentEditingRowForResponsible = ref(null); // 当前正在编辑责任人的行
+
 /** 项目信息 表单 */
 defineOptions({ name: 'IotProjectTaskInfo' })
 
@@ -338,6 +412,7 @@ const formData = ref({
   manufacturerId: undefined,
   userName: undefined,
   userId: undefined,
+  deptId: undefined, // 新增项目部门ID字段
 })
 
 const close = () => {
@@ -358,6 +433,7 @@ const getProjectInfo = (contractId: number) => {
     formData.value.manufactureName = project.manufactureName;
     formData.value.manufacturerId = project.manufacturerId;
     formData.value.id = project.id;
+    formData.value.deptId = project.deptId; // 保存项目部门ID
   }
 }
 
@@ -442,6 +518,89 @@ const tableData = ref([
   },
 ]);
 
+// 打开责任人选择对话框
+const openResponsiblePersonDialog = async (row) => {
+  if (!formData.value.deptId) {
+    ElMessage.warning('请先选择合同以确定项目部门');
+    return;
+  }
+
+  currentEditingRowForResponsible.value = row;
+  selectedResponsiblePersonIds.value = [...(row.editData.responsiblePerson || [])];
+
+  try {
+    const params = {
+      deptIds: [formData.value.deptId] // 使用当前项目所属部门的deptId
+    };
+    const response = await UserApi.companyDeptsEmployee(params);
+    responsiblePersonList.value = response;
+    responsiblePersonDialogVisible.value = true;
+  } catch (error) {
+    ElMessage.error('获取责任人列表失败');
+    console.error('获取责任人列表失败:', error);
+  }
+};
+
+// 确认责任人选择
+const confirmResponsiblePersonSelection = () => {
+  if (currentEditingRowForResponsible.value) {
+    // 更新责任人ID
+    currentEditingRowForResponsible.value.editData.responsiblePerson = [...selectedResponsiblePersonIds.value];
+
+    // 更新责任人名称显示
+    const selectedPersons = responsiblePersonList.value.filter(person =>
+      selectedResponsiblePersonIds.value.includes(person.id)
+    );
+    currentEditingRowForResponsible.value.editData.responsiblePersonNames = selectedPersons
+      .map(person => person.nickname)
+      .join(', ');
+  }
+
+  responsiblePersonDialogVisible.value = false;
+};
+
+// 关闭责任人选择对话框
+const handleResponsiblePersonDialogClose = () => {
+  responsiblePersonDialogVisible.value = false;
+};
+
+// 根据责任人ID获取责任人名称
+const getResponsiblePersonNames = (responsiblePersonIds: number[]) => {
+  if (!responsiblePersonIds || responsiblePersonIds.length === 0) return '';
+
+  // 获取所有有效责任人名称
+  const personNames = responsiblePersonIds
+    .map(id => {
+      const person = responsiblePersonList.value.find(p => p.id === id);
+      return person ? person.nickname : '';
+    })
+    .filter(name => name !== undefined && name !== '');
+
+  if (personNames.length === 0) return '';
+
+  // 如果责任人数量超过2个,显示前两个加省略号
+  if (personNames.length > 2) {
+    return `${personNames[0]}, ${personNames[1]}...`;
+  }
+
+  // 责任人数量不超过2个,正常显示所有
+  return personNames.join(', ');
+};
+
+// 获取所有责任人名称(用于tooltip提示)
+const getAllResponsiblePersonNames = (responsiblePersonIds: number[]) => {
+  if (!responsiblePersonIds || responsiblePersonIds.length === 0) return '无责任人';
+
+  const personNames = responsiblePersonIds
+    .map(id => {
+      const person = responsiblePersonList.value.find(p => p.id === id);
+      return person ? person.nickname : '未知人员';
+    })
+    .filter(name => name !== '未知人员');
+
+  return personNames.join(', ') || '无有效责任人';
+};
+
 // 设备选择相关变量
 const deviceDialogVisible = ref(false);
 const currentEditingRow = ref(null);
@@ -522,10 +681,16 @@ const open = async () => {
 
       // 1. 收集所有设备ID
       const allDeviceIds = new Set<number>();
+      // 收集所有责任人ID
+      const allResponsiblePersonIds = new Set<number>();
+
       data.list.forEach(item => {
         if (item.deviceIds?.length) {
           item.deviceIds.forEach(id => allDeviceIds.add(id));
         }
+        if (item.responsiblePerson?.length) {
+          item.responsiblePerson.forEach(id => allResponsiblePersonIds.add(id));
+        }
       });
 
       // 2. 批量获取设备信息
@@ -543,6 +708,18 @@ const open = async () => {
         });
       }
 
+      // 批量获取责任人信息
+      if (allResponsiblePersonIds.size > 0) {
+        const personIdsArray = Array.from(allResponsiblePersonIds);
+        const params = {
+          userIds: personIdsArray
+        };
+        const persons = await UserApi.companyDeptsEmployee(params);
+
+        // 更新责任人列表
+        responsiblePersonList.value = persons;
+      }
+
       tableData.value.forEach(item=>{
         item.editData = {
           ...item,
@@ -689,6 +866,8 @@ const addNewRow = () => {
     deptIds: [],
     deviceIds: [],
     deviceCodes: '',
+    responsiblePerson: [], // 新增责任人字段
+    responsiblePersonNames: '', // 新增责任人名称字段
     remark:'',
     editing: true,
     editData: {
@@ -700,6 +879,8 @@ const addNewRow = () => {
       deptIds: [],
       deviceIds: [],
       deviceCodes: '',
+      responsiblePerson: [], // 新增责任人字段
+      responsiblePersonNames: '', // 新增责任人名称字段
       remark:'',
     },
     originalData: {},
@@ -724,6 +905,8 @@ const editRow = (row) => {
     deptIds: row.deptIds,
     deviceIds: row.deviceIds,
     deviceCodes: row.deviceCodes,
+    responsiblePerson: row.responsiblePerson ? [...row.responsiblePerson] : [], // 复制责任人数组
+    responsiblePersonNames: row.responsiblePersonNames, // 复制责任人名称
     remark: row.remark,
   };
   // 进入编辑状态
@@ -777,6 +960,9 @@ const saveRow = (row) => {
   // row.deviceCodes = row.editData.deviceCodes;
   // 关键修改:根据设备ID列表生成设备代码
 
+  row.responsiblePerson = row.editData.responsiblePerson; // 保存责任人ID
+  row.responsiblePersonNames = row.editData.responsiblePersonNames; // 保存责任人名称
+
   if (currentEditingRow.value) {
     // 更新设备ID
     currentEditingRow.value.editData.deviceIds = [...selectedDeviceIds.value];
@@ -823,6 +1009,8 @@ const saveAll = () => {
       row.deptIds = row.editData.deptIds;
       row.deviceIds = row.editData.deviceIds;
       row.deviceCodes = row.editData.deviceCodes;
+      row.responsiblePerson = row.editData.responsiblePerson; // 保存责任人ID
+      row.responsiblePersonNames = row.editData.responsiblePersonNames; // 保存责任人名称
       row.remark = row.editData.remark;
     }
   });
@@ -843,6 +1031,8 @@ const cancelEdit = (row) => {
     row.deptIds = row.originalData.deptIds;
     row.deviceIds = row.originalData.deviceIds;
     row.deviceCodes = row.originalData.deviceCodes;
+    row.responsiblePerson = row.originalData.responsiblePerson; // 恢复责任人ID
+    row.responsiblePersonNames = row.originalData.responsiblePersonNames; // 恢复责任人名称
     row.remark = row.originalData.remark;
   } else {
     // 如果是新增行,则删除
@@ -885,6 +1075,12 @@ const deleteRow = (index) => {
 /* 2. 穿梭框组件:控制宽度,避免过窄或过宽 */
 .transfer-component {
   width: 100%; /* 占对话框90%宽度,兼顾美观和内容显示 */
+  min-width: 600px;
+}
+
+/* 3. 直接调整 el-transfer 左右窗口的宽度 */
+:deep(.el-transfer-panel) {
+  width: 40% !important; /* 强制设置左右面板宽度,确保两侧面板对等 */
 }
 
 /* 3. 深度选择器:修改el-transfer选项样式(解决内容省略问题) */
@@ -910,4 +1106,16 @@ const deleteRow = (index) => {
   max-width: 200px; /* 根据实际列宽调整 */
 }
 
+:deep(.el-transfer-panel__list) {
+  width: 100% !important; /* 使面板内部内容宽度占满 */
+}
+
+/* 责任人名称显示区域样式 */
+.responsible-names {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  max-width: 200px; /* 根据实际列宽调整 */
+}
+
 </style>