Ver código fonte

feat: ScopeDialog改用部门下拉框和员工选择器,与创建制度一致

alphah 2 semanas atrás
pai
commit
260d4adfbd

+ 4 - 2
backend/app/plugin/module_payment/expense/institution/service.py

@@ -1047,8 +1047,10 @@ class InstitutionScopeService:
         result = AlipayEbppInvoiceInstitutionScopeModifyResponse()
         result.parse_response_content(response)
         if not result.is_success():
-            log.error(f"设置制度成员失败: {result.code} - {result.msg}")
-            raise CustomException(msg=f"设置制度成员失败: {result.msg}")
+            sub_msg = getattr(result, 'sub_msg', '') or ''
+            err_detail = f"{result.msg}" + (f" - {sub_msg}" if sub_msg else "")
+            log.error(f"设置制度成员失败: {result.code} - {err_detail}")
+            raise CustomException(msg=f"设置制度成员失败: {sub_msg or result.msg}")
 
         return {"result": True}
 

BIN
frontend/dist.zip


+ 96 - 44
frontend/src/views/module_payment/institution/components/ScopeDialog.vue

@@ -17,30 +17,28 @@
         </el-select>
       </el-form-item>
 
-      <el-form-item
-        v-if="formData.adapter_type === 'EMPLOYEE_SELECT'"
-        label="归属ID类型"
-      >
-        <el-select v-model="formData.owner_type" style="width: 100%">
-          <el-option
-            v-for="item in OWNER_TYPE_OPTIONS"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
-          />
+      <!-- 按部门 -->
+      <el-form-item v-if="formData.adapter_type === 'EMPLOYEE_DEPARTMENT'" label="选择部门">
+        <el-select v-model="formData.department_id" placeholder="请选择部门" style="width: 100%">
+          <el-option v-for="dept in departmentOptions" :key="dept.value" :label="dept.label" :value="dept.value" />
         </el-select>
       </el-form-item>
 
-      <el-form-item
-        v-if="formData.adapter_type === 'EMPLOYEE_SELECT'"
-        label="员工ID列表"
-      >
-        <el-input
-          v-model="ownerIdsInput"
-          type="textarea"
-          :rows="3"
-          placeholder="请输入员工ID,多个用换行分隔"
-        />
+      <!-- 按员工 -->
+      <el-form-item v-if="formData.adapter_type === 'EMPLOYEE_SELECT'" label="选择员工">
+        <div>
+          <el-button type="primary" plain @click="showEmployeeSelector = true">
+            选择员工
+          </el-button>
+          <div v-if="selectedEmployeeIds.length > 0" class="selected-tags" style="margin-top: 8px;">
+            <el-tag v-for="id in selectedEmployeeIds" :key="id" closable @close="removeEmployee(id)" style="margin: 2px">
+              {{ getEmployeeName(id) || id }}
+            </el-tag>
+          </div>
+          <div v-else class="tip-text" style="color: #999; margin-top: 4px; font-size: 12px;">
+            请点击按钮选择员工
+          </div>
+        </div>
       </el-form-item>
     </el-form>
 
@@ -48,15 +46,25 @@
       <el-button @click="handleClose">取消</el-button>
       <el-button type="primary" :loading="loading" @click="handleSubmit">确定</el-button>
     </template>
+
+    <!-- 员工选择弹窗 -->
+    <EmployeeSelector
+      v-model:visible="showEmployeeSelector"
+      :selected-ids="selectedEmployeeIds"
+      :enterprise-id="props.enterpriseId || ''"
+      @confirm="handleEmployeeConfirm"
+    />
   </el-dialog>
 </template>
 
 <script setup lang="ts">
 import InstitutionAPI, {
   ADAPTER_TYPE_OPTIONS,
-  OWNER_TYPE_OPTIONS,
   ScopeModify,
 } from "@/api/module_payment/institution";
+import DepartmentAPI from "@/api/module_payment/department";
+import EmployeeAPI from "@/api/module_payment/employee";
+import EmployeeSelector from "./EmployeeSelector.vue";
 import { ElMessage } from "element-plus";
 import { ref, watch, computed } from "vue";
 
@@ -79,23 +87,56 @@ const visible = computed({
 });
 
 const loading = ref(false);
+const showEmployeeSelector = ref(false);
+const departmentOptions = ref<{ value: string; label: string }[]>([]);
+const employeeMap = ref<Record<string, string>>({});
 
 const formData = ref({
   adapter_type: "EMPLOYEE_ALL",
-  owner_type: "EMPLOYEE",
+  department_id: undefined as string | undefined,
 });
-
-const ownerIdsInput = ref("");
+const selectedEmployeeIds = ref<string[]>([]);
 
 watch(
   () => props.modelValue,
   async (val) => {
     if (val && props.institutionId) {
-      await fetchScope();
+      await Promise.all([fetchScope(), loadDepartments(), loadEmployees()]);
     }
   }
 );
 
+async function loadDepartments() {
+  if (!props.enterpriseId) return;
+  try {
+    const res = await DepartmentAPI.listDepartment({ enterprise_id: props.enterpriseId, page_no: 1, page_size: 200 });
+    const items = res?.data?.data?.items || [];
+    departmentOptions.value = items.map((d: any) => ({
+      value: d.department_id,
+      label: d.department_name,
+    }));
+  } catch (e) {
+    console.error("加载部门列表失败", e);
+  }
+}
+
+async function loadEmployees() {
+  if (!props.enterpriseId) return;
+  try {
+    const res = await EmployeeAPI.listEmployee({ enterprise_id: props.enterpriseId, page_no: 1, page_size: 500 });
+    const items = res?.data?.data?.items || [];
+    const map: Record<string, string> = {};
+    for (const emp of items) {
+      if (emp.employee_id) {
+        map[emp.employee_id] = emp.employee_name || emp.employee_id;
+      }
+    }
+    employeeMap.value = map;
+  } catch (e) {
+    console.error("加载员工列表失败", e);
+  }
+}
+
 async function fetchScope() {
   if (!props.institutionId) return;
   try {
@@ -103,11 +144,13 @@ async function fetchScope() {
       enterprise_id: props.enterpriseId,
     });
     const data = res.data.data;
-    if (data && data.scope_info_list && data.scope_info_list.length > 0) {
-      const first = data.scope_info_list[0];
-      formData.value.adapter_type = first.adapter_type || "EMPLOYEE_ALL";
-      if (first.owner_id_list && first.owner_id_list.length > 0) {
-        ownerIdsInput.value = first.owner_id_list.join("\n");
+    if (data) {
+      const adapter = data.adapter_type || "EMPLOYEE_ALL";
+      formData.value.adapter_type = adapter;
+      if (adapter === "EMPLOYEE_DEPARTMENT" && data.owner_id_list?.length > 0) {
+        formData.value.department_id = String(data.owner_id_list[0]);
+      } else if (adapter === "EMPLOYEE_SELECT" && data.owner_id_list?.length > 0) {
+        selectedEmployeeIds.value = data.owner_id_list.map(String);
       }
     }
   } catch (error) {
@@ -115,13 +158,22 @@ async function fetchScope() {
   }
 }
 
+function getEmployeeName(id: string): string {
+  return employeeMap.value[id] || "";
+}
+
+function removeEmployee(id: string) {
+  selectedEmployeeIds.value = selectedEmployeeIds.value.filter((e) => e !== id);
+}
+
+function handleEmployeeConfirm(ids: string[]) {
+  selectedEmployeeIds.value = ids;
+}
+
 function handleClose() {
   visible.value = false;
-  ownerIdsInput.value = "";
-  formData.value = {
-    adapter_type: "EMPLOYEE_ALL",
-    owner_type: "EMPLOYEE",
-  };
+  formData.value = { adapter_type: "EMPLOYEE_ALL", department_id: undefined };
+  selectedEmployeeIds.value = [];
 }
 
 async function handleSubmit() {
@@ -129,17 +181,17 @@ async function handleSubmit() {
 
   loading.value = true;
   try {
-    const ownerIds = ownerIdsInput.value
-      .split("\n")
-      .map((s) => s.trim())
-      .filter((s) => s.length > 0);
-
     const submitData: ScopeModify = {
       adapter_type: formData.value.adapter_type,
-      owner_type: formData.value.owner_type,
-      add_owner_id_list: ownerIds.length > 0 ? ownerIds : undefined,
+      owner_type: "EMPLOYEE",
     };
 
+    if (formData.value.adapter_type === "EMPLOYEE_SELECT" && selectedEmployeeIds.value.length > 0) {
+      submitData.add_owner_id_list = selectedEmployeeIds.value;
+    } else if (formData.value.adapter_type === "EMPLOYEE_DEPARTMENT" && formData.value.department_id) {
+      submitData.add_owner_id_list = [formData.value.department_id];
+    }
+
     await InstitutionAPI.modifyScope(props.institutionId, submitData);
     ElMessage.success("修改成功");
     emit("success");
@@ -150,4 +202,4 @@ async function handleSubmit() {
     loading.value = false;
   }
 }
-</script>
+</script>