소스 검색

fix: EmployeeSelector 真实API查询+跨页选中持久

alphah 2 주 전
부모
커밋
de3e48024a

+ 74 - 74
frontend/src/views/module_payment/institution/components/EmployeeSelector.vue

@@ -9,26 +9,12 @@
     <div class="employee-selector">
       <div class="employee-selector__search">
         <el-form :model="searchForm" inline>
-          <el-form-item label="部门">
-            <el-select v-model="searchForm.department_id" placeholder="选择部门" style="width: 120px">
-              <el-option value="" label="全部" />
-              <el-option
-                v-for="dept in departments"
-                :key="dept.value"
-                :label="dept.label"
-                :value="dept.value"
-              />
-            </el-select>
-          </el-form-item>
           <el-form-item label="姓名">
             <el-input v-model="searchForm.name" placeholder="输入员工姓名" style="width: 120px" />
           </el-form-item>
           <el-form-item label="手机号">
             <el-input v-model="searchForm.phone" placeholder="输入员工手机号" style="width: 120px" />
           </el-form-item>
-          <el-form-item label="邮箱">
-            <el-input v-model="searchForm.email" placeholder="请输入邮箱" style="width: 120px" />
-          </el-form-item>
         </el-form>
         <div class="employee-selector__actions">
           <el-button type="default" @click="handleReset">重置</el-button>
@@ -39,7 +25,7 @@
       <div class="employee-selector__tabs">
         <el-tabs v-model="activeTab" @tab-change="handleTabChange">
           <el-tab-pane label="全部" name="all" />
-          <el-tab-pane label="已选 ({{ selectedEmployees.length }}人)" name="selected" />
+          <el-tab-pane label="已选 ({{ selectedIds.length }}人)" name="selected" />
         </el-tabs>
       </div>
 
@@ -47,16 +33,14 @@
         <el-table
           ref="tableRef"
           :data="displayEmployees"
-          :show-header="true"
+          row-key="id"
           border
           :max-height="300"
           @selection-change="handleSelectionChange"
         >
-          <el-table-column type="selection" width="50" />
+          <el-table-column type="selection" width="50" :reserve-selection="true" />
           <el-table-column label="员工姓名" prop="name" />
-          <el-table-column label="员工部门" prop="department" />
-          <el-table-column label="手机号" prop="phone" />
-          <el-table-column label="邮箱" prop="email" />
+          <el-table-column label="手机号" prop="phone" width="140" />
         </el-table>
       </div>
 
@@ -67,6 +51,7 @@
           :total="pagination.total"
           :page-sizes="[10, 20, 50]"
           layout="prev, pager, next, jumper, ->, total, sizes"
+          @current-change="fetchEmployees"
         />
       </div>
 
@@ -79,26 +64,26 @@
 </template>
 
 <script setup lang="ts">
-import { ref, computed, watch, nextTick } from "vue";
+import { ref, computed, watch } from "vue";
+import EmployeeAPI from "@/api/module_payment/employee";
 
 interface Employee {
   id: string;
   name: string;
-  department: string;
   phone: string;
-  email: string;
 }
 
 interface Props {
   visible: boolean;
   selectedIds: string[];
+  enterpriseId: string;
 }
 
 const props = defineProps<Props>();
 
 const emit = defineEmits<{
   (e: "update:visible", value: boolean): void;
-  (e: "confirm", employees: Employee[]): void;
+  (e: "confirm", ids: string[]): void;
 }>();
 
 const visibleProxy = computed({
@@ -106,77 +91,98 @@ const visibleProxy = computed({
   set: (v: boolean) => emit("update:visible", v),
 });
 
-const searchForm = ref({
-  department_id: "",
-  name: "",
-  phone: "",
-  email: "",
-});
-
+const searchForm = ref({ name: "", phone: "" });
 const activeTab = ref("all");
+const pagination = ref({ page_no: 1, page_size: 10, total: 0 });
 
-const pagination = ref({
-  page_no: 1,
-  page_size: 10,
-  total: 2,
-});
-
-const departments = ref([
-  { value: "dept1", label: "研发部" },
-  { value: "dept2", label: "产品部" },
-  { value: "dept3", label: "运营部" },
-]);
-
-const allEmployees = ref<Employee[]>([
-  { id: "emp1", name: "湖南钱程似锦技术服务有限公司", department: "湖南钱程似锦技术服务有限公司", phone: "-", email: "-" },
-  { id: "emp2", name: "湖南钱程似锦技术服务有限公司", department: "湖南钱程似锦技术服务有限公司", phone: "-", email: "-" },
-]);
-
-const selectedEmployees = ref<Employee[]>([]);
+const allEmployees = ref<Employee[]>([]);
 const tableRef = ref();
 
-function handleSelectionChange(val: Employee[]) {
-  selectedEmployees.value = val;
-}
+// 追踪已选 ID 集合(跨页持久)
+const internalSelectedIds = ref<string[]>([]);
 
-watch(() => props.visible, (v) => {
-  if (v) {
-    nextTick(() => selectedEmployees.value = allEmployees.value.filter(emp => props.selectedIds.includes(emp.id)));
+watch(
+  () => props.visible,
+  (v) => {
+    if (v) {
+      internalSelectedIds.value = [...props.selectedIds];
+      fetchEmployees();
+    }
   }
-});
+);
+
+async function fetchEmployees() {
+  try {
+    const params: Record<string, unknown> = {
+      page_no: pagination.value.page_no,
+      page_size: pagination.value.page_size,
+      enterprise_id: props.enterpriseId,
+    };
+    if (searchForm.value.name) params.employee_name = searchForm.value.name;
+    if (searchForm.value.phone) params.employee_mobile = searchForm.value.phone;
+
+    const res = await EmployeeAPI.listEmployee(params);
+    const data = res?.data?.data || res?.data;
+    const list = data?.items || data?.list || [];
+    allEmployees.value = (list).map((item: any) => ({
+      id: item.employee_id || item.id,
+      name: item.employee_name || "-",
+      phone: item.employee_mobile || "-",
+    }));
+    pagination.value.total = data?.total || 0;
+
+    // 重新勾选已选条目
+    nextTick(() => {
+      if (tableRef.value) {
+        allEmployees.value.forEach((row) => {
+          if (internalSelectedIds.value.includes(row.id)) {
+            tableRef.value.toggleRowSelection(row, true);
+          }
+        });
+      }
+    });
+  } catch (e) {
+    console.error("获取员工列表失败", e);
+  }
+}
+
+function handleSelectionChange(rows: Employee[]) {
+  // 只更新当前页的选中状态
+  const currentIds = rows.map((r) => r.id);
+  const otherIds = internalSelectedIds.value.filter(
+    (id) => !allEmployees.value.some((e) => e.id === id)
+  );
+  internalSelectedIds.value = [...new Set([...otherIds, ...currentIds])];
+}
 
 const displayEmployees = computed(() => {
   if (activeTab.value === "selected") {
-    return selectedEmployees.value;
+    return allEmployees.value.filter((e) => internalSelectedIds.value.includes(e.id));
   }
   return allEmployees.value;
 });
 
-
 function handleClose() {
-  selectedEmployees.value = [];
   emit("update:visible", false);
 }
 
 function handleReset() {
-  searchForm.value = {
-    department_id: "",
-    name: "",
-    phone: "",
-    email: "",
-  };
+  searchForm.value = { name: "", phone: "" };
+  pagination.value.page_no = 1;
+  fetchEmployees();
 }
 
 function handleSearch() {
   pagination.value.page_no = 1;
+  fetchEmployees();
 }
 
 function handleTabChange() {
-  pagination.value.page_no = 1;
+  // 不重置
 }
 
 function handleConfirm() {
-  emit("confirm", selectedEmployees.value);
+  emit("confirm", internalSelectedIds.value);
   emit("update:visible", false);
 }
 </script>
@@ -188,33 +194,27 @@ function handleConfirm() {
   gap: 16px;
   height: 100%;
 }
-
 .employee-selector__search {
   display: flex;
   justify-content: space-between;
   align-items: flex-start;
 }
-
 .employee-selector__actions {
   display: flex;
   gap: 8px;
 }
-
 .employee-selector__tabs {
   background: #f5f7fa;
   padding: 8px;
 }
-
 .employee-selector__table {
   flex: 1;
   overflow: hidden;
 }
-
 .employee-selector__pagination {
   padding: 8px 0;
   border-top: 1px solid #ebeef5;
 }
-
 .employee-selector__footer {
   display: flex;
   justify-content: flex-end;
@@ -222,4 +222,4 @@ function handleConfirm() {
   padding-top: 16px;
   border-top: 1px solid #ebeef5;
 }
-</style>
+</style>

+ 3 - 3
frontend/src/views/module_payment/institution/components/InstitutionForm.vue

@@ -217,7 +217,7 @@
     </el-form>
 
     <EmployeeSelector v-model:visible="showEmployeeSelector" :selected-ids="formData.employee_ids"
-      @confirm="handleEmployeeConfirm" />
+      :enterprise-id="formData.enterprise_id" @confirm="handleEmployeeConfirm" />
   </div>
 </template>
 
@@ -313,8 +313,8 @@ const selectedEmployeeNames = computed(() => {
   });
 });
 
-function handleEmployeeConfirm(employees: any[]) {
-  formData.employee_ids = employees.map((e: any) => e.id);
+function handleEmployeeConfirm(ids: string[]) {
+  formData.employee_ids = ids;
 }
 
 watch(