浏览代码

feat: 人员分组新交互样式,已知部分应用

wyf 1 年之前
父节点
当前提交
d7cd14162e

+ 99 - 29
src/views/message/components/PersonFilterSelection.vue

@@ -2,38 +2,62 @@
   <div class="person-filter-selection">
     <div class="left">
       <div class="filter-title">
-        <el-input v-model="personFilterValue" style="width: 253px" placeholder="请输入搜索的内容">
-          <template #prepend>
-            <el-select v-model="personFilterType" style="width: 74px" value-key="type">
-              <el-option
-                v-for="item in FILTER_TYPES"
-                :key="item.type"
-                :value="item"
-                :label="item.label"
-              />
-            </el-select>
-          </template>
-        </el-input>
-        <div style="float: right">
-          <el-button
-            type="primary"
-            @click="debouncedGetPersonFilterList"
-            style="width: 65px; height: 32px; margin-right: 11px"
-            >搜 索</el-button
-          >
-        </div>
+        <el-form-item>
+          <el-input v-model="personFilterValue" style="width: 253px" placeholder="请输入搜索的内容">
+            <template #prepend>
+              <el-select
+                v-model="personFilterType"
+                style="width: 74px"
+                value-key="type"
+                :validate-event="false"
+              >
+                <el-option
+                  v-for="item in FILTER_TYPES"
+                  :key="item.type"
+                  :value="item"
+                  :label="item.label"
+                />
+              </el-select>
+            </template>
+          </el-input>
+          <div style="float: right">
+            <el-button
+              type="primary"
+              @click="debouncedHandleFilter"
+              style="width: 65px; height: 32px; margin: 0 11px 0"
+              >搜 索</el-button
+            >
+          </div>
+        </el-form-item>
       </div>
       <!-- 搜索结果展示 -->
       <div
-        v-if="personFilterList && personFilterList.availableUserDTOS.length"
+        v-if="personFilterList?.availableUserDTOS?.length"
         class="filter-result"
+        ref="filterResult"
       >
-        <div v-for="person in personFilterList.availableUserDTOS" :key="person.id">
+        <div
+          class="filter-result-item"
+          v-for="person in personFilterList.availableUserDTOS"
+          :key="person.id"
+        >
           <el-checkbox
             v-model="person.checked"
             @change="handleSelect($event, person)"
           ></el-checkbox>
-          {{ person.nickname }}
+          <div style="margin-left: 8px">
+            {{ person.staffNo + '-' + person.nickname + '(' + person.deptName + ')' }}
+          </div>
+        </div>
+        <!-- todo -->
+        <div
+          id="next-loading"
+          style="text-align: center"
+          v-if="personFilterList.total > personFilterList.availableUserDTOS.length"
+        >
+          <el-icon class="el-input__icon" :size="24">
+            <Loading />
+          </el-icon>
         </div>
       </div>
       <div v-else-if="!personFilterList" class="filter-result-empty">
@@ -44,8 +68,8 @@
         <div>未搜索到相关内容</div><div>请重新搜索</div>
       </div>
     </div>
-    <div class="right" style="margin-left: 16px">
-      <div class="head" style="margin-bottom: 22px">
+    <div class="right">
+      <div class="head">
         <span
           style="font-weight: 400; font-size: 16px; color: rgba(0, 0, 0, 0.88); line-height: 22px"
           >已选择:{{ selectedPersonList.length }}人</span
@@ -70,17 +94,20 @@
 </template>
 
 <script lang="ts" setup>
-  import { onMounted } from 'vue';
+  import { ref, onMounted, onBeforeUnmount } from 'vue';
+  import { Loading } from '@element-plus/icons-vue';
   import { usePersonGroupFilterList } from '../persongroup/hook/usePersonGroupFilterList';
   import { SelectedFilterPersonInfo } from '@/api/message/person-group';
+  import { debounce } from 'lodash-es';
+
   const {
     FILTER_TYPES,
     personFilterType,
     personFilterValue,
-    // personFilterParams,
     personFilterList,
     selectedPersonList,
-    debouncedGetPersonFilterList,
+    getPersonFilterList,
+    getNextPersonFilterList,
     handleAddSelectedPerson,
     handleRemoveSelectedPerson,
   } = usePersonGroupFilterList();
@@ -94,6 +121,32 @@
     if (props.initSelected) selectedPersonList.value = [...props.initSelected];
   });
 
+  let observer: IntersectionObserver;
+
+  const filterResult = ref();
+  const handleFilter = () => {
+    getPersonFilterList().then(() => {
+      filterResult.value.scrollTop = 0;
+      const loading = document.getElementById('next-loading');
+      if (loading) {
+        if (observer) observer.unobserve(loading);
+        observer = new IntersectionObserver(
+          (entries) => {
+            if (entries[0].isIntersecting) {
+              getNextPersonFilterList();
+            }
+          },
+          {
+            threshold: 0.9,
+          },
+        );
+        observer.observe(loading);
+      }
+    });
+  };
+
+  const debouncedHandleFilter = debounce(handleFilter, 500);
+
   const handleSelect = (v: boolean, person: any) => {
     if (v) {
       handleAddSelectedPerson(person);
@@ -107,6 +160,12 @@
   const handleSubmit = () => {
     emit('submit', selectedPersonList.value);
   };
+
+  onBeforeUnmount(() => {
+    if (observer) {
+      observer.disconnect();
+    }
+  });
 </script>
 
 <style lang="scss" scoped>
@@ -126,7 +185,16 @@
         display: flex;
         flex-direction: column;
         gap: 8px;
-        margin-top: 16px;
+        height: 392px;
+        overflow: auto;
+        .filter-result-item {
+          display: flex;
+          align-items: center;
+          font-weight: 500;
+          font-size: 14px;
+          color: #303133;
+          line-height: 22px;
+        }
       }
       .filter-result-empty {
         display: flex;
@@ -145,6 +213,7 @@
       flex: 1;
       height: 100%;
       position: relative;
+      margin-left: 16px;
       .head {
         display: flex;
         align-items: center;
@@ -152,6 +221,7 @@
         font-size: 16px;
         color: rgba(0, 0, 0, 0.88);
         line-height: 22px;
+        margin: 6px 0 6px;
       }
       .selected {
         display: flex;

+ 28 - 16
src/views/message/components/PushObject.vue

@@ -57,7 +57,12 @@
           @click="userInfo = true"
           :disabled="disabled"
         >
-          <el-option v-for="user in selectedUser" :key="user.id" :label="user.name" :value="user">
+          <el-option
+            v-for="user in selectedUser"
+            :key="user.id"
+            :label="user.staffNo + '-' + user.nickname"
+            :value="user"
+          >
           </el-option>
         </el-select>
       </el-form-item>
@@ -85,13 +90,20 @@
     :width="731"
     :destroy-on-close="true"
   >
-    <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" />
+    <!-- <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" /> -->
+    <PersonFilterSelection
+      @cancel="handleCancle"
+      @submit="handleSubmit"
+      :init-selected="selectedUser"
+    />
   </el-dialog>
 </template>
 
 <script setup lang="ts">
   import { onMounted, ref, reactive, watch, watchEffect } from 'vue';
-  import SelectTree from '../persongroup/components/SelectTree.vue';
+  // import SelectTree from '../persongroup/components/SelectTree.vue';
+  import { SelectedFilterPersonInfo } from '@/api/message/person-group';
+  import PersonFilterSelection from '@/views/message/components/PersonFilterSelection.vue';
   import Group from './Group.vue';
   import { recipientTypeName } from '../constant';
   import { ToPushObjectqueryUserGroupList, queryUserGroupDetail } from '@/api/message/person-group';
@@ -115,16 +127,16 @@
     name: string;
     description: string;
   }
-  interface UserList {
-    id: string;
-    name: string;
-    userId: number;
-  }
-  const selectedUser = ref<UserList[]>([]);
+  // interface UserList {
+  //   id: string;
+  //   name: string;
+  //   userId: number;
+  // }
+  const selectedUser = ref<SelectedFilterPersonInfo[]>([]);
   interface RuleForm {
     recipientType?: number;
     userGroupList: number[];
-    customUserList: UserList[];
+    customUserList: SelectedFilterPersonInfo[];
   }
   const ruleForm = reactive<RuleForm>({
     userGroupList: [],
@@ -193,22 +205,22 @@
           ? []
           : ruleForm.recipientType === 1
           ? []
-          : ruleForm.customUserList.map((item) => item.userId),
+          : ruleForm.customUserList.map((item) => item.id),
     };
   };
   const handleCancle = () => {
     userInfo.value = false;
   };
-  const handleSubmit = (selectedData: UserList[]) => {
+  const handleSubmit = (selectedData: SelectedFilterPersonInfo[]) => {
     selectedUser.value = selectedData;
     ruleForm.customUserList = selectedUser.value;
     userInfo.value = false;
   };
-  const formatCustomUserList = (customList: customUserList[]): UserList[] => {
+  const formatCustomUserList = (customList: customUserList[]): SelectedFilterPersonInfo[] => {
     return customList.map((item) => ({
-      id: `u${item.userId}`,
-      userId: item.userId,
-      name: `${item.userLoginName}-${item.userNickname}`,
+      id: item.userId,
+      staffNo: item.userLoginName,
+      nickname: item.userNickname,
     }));
   };
   defineExpose({

+ 10 - 4
src/views/message/persongroup/hook/usePersonGroupFilterList.ts

@@ -6,7 +6,6 @@ import {
   queryPersonFilterList,
 } from '@/api/message/person-group';
 import { ref } from 'vue';
-import { debounce } from 'lodash-es';
 
 export const usePersonGroupFilterList = () => {
   const FILTER_TYPES = [
@@ -39,8 +38,14 @@ export const usePersonGroupFilterList = () => {
         personFilterList.value.availableUserDTOS,
       );
   };
-  // 查询事件加防抖
-  const debouncedGetPersonFilterList = debounce(getPersonFilterList, 500);
+  // 查询翻页事件
+  const getNextPersonFilterList = async () => {
+    personFilterParams.value.pageNumber++;
+    const res = await queryPersonFilterList(personFilterParams.value);
+    res.availableUserDTOS = checkPersonList(res.availableUserDTOS);
+    personFilterList.value!.total = res.total;
+    personFilterList.value!.availableUserDTOS.push(...res.availableUserDTOS);
+  };
   // 查询结果
   const personFilterList = ref<QueryPersonFilterListReturn>();
   // 已选择人员
@@ -83,7 +88,8 @@ export const usePersonGroupFilterList = () => {
     personFilterParams,
     personFilterList,
     selectedPersonList,
-    debouncedGetPersonFilterList,
+    getPersonFilterList,
+    getNextPersonFilterList,
     handleAddSelectedPerson,
     handleRemoveSelectedPerson,
   };

+ 1 - 1
src/views/message/reportmessage/CustomReport.vue

@@ -123,7 +123,7 @@
         placeholder="请选择人员"
         style="width: 526px; margin-top: 10px"
         :prop="`customPushConfigList[` + index + `].customUserList`"
-        :rules="{ required: true, message: '请选择推送人员', trigger: 'change' }"
+        :rules="{ required: true, message: '请选择推送人员', trigger: 'blur' }"
       >
         <el-col :span="18">
           <CustomPersonSelection

+ 1 - 1
src/views/message/reportmessage/MonthReport.vue

@@ -78,7 +78,7 @@
       required
       prop="customUserList.value"
       style="width: 526px; margin-top: 10px"
-      :rules="{ required: true, message: '请选择推送人员', trigger: ['change'] }"
+      :rules="{ required: true, message: '请选择推送人员', trigger: 'blur' }"
     >
       <el-col :span="18">
         <DefaultPersonSelection :form="form" :disableType="disableType" />

+ 1 - 1
src/views/message/reportmessage/WeekReport.vue

@@ -77,7 +77,7 @@
       required
       prop="customUserList.value"
       style="width: 526px; margin-top: 10px"
-      :rules="{ required: true, message: '请选择推送人员', trigger: ['change'] }"
+      :rules="{ required: true, message: '请选择推送人员', trigger: 'blur' }"
     >
       <el-col :span="18">
         <DefaultPersonSelection :form="form" :disableType="disableType" />

+ 1 - 1
src/views/message/reportmessage/YearReport.vue

@@ -76,7 +76,7 @@
       required
       prop="customUserList.value"
       style="width: 526px; margin-top: 10px"
-      :rules="{ required: true, message: '请选择推送人员', trigger: ['change'] }"
+      :rules="{ required: true, message: '请选择推送人员', trigger: 'blur' }"
     >
       <el-col :span="18">
         <DefaultPersonSelection :form="form" :disableType="disableType" />

+ 23 - 11
src/views/message/reportmessage/components/CustomPersonSelection.vue

@@ -8,8 +8,12 @@
       @click="dialogVisible = !disableType.contentDisable"
       :disabled="disableType.contentDisable"
     >
-      <el-option v-for="user in selectedUser" :key="user.id" :label="user.name" :value="user">
-      </el-option>
+      <el-option
+        v-for="user in selectedUser"
+        :key="user.id"
+        :label="user.staffNo + '-' + user.nickname"
+        :value="user"
+      />
     </el-select>
     <el-dialog
       v-model="dialogVisible"
@@ -19,30 +23,38 @@
       style="height: 583px"
       :width="731"
       :destroy-on-close="true"
+      :append-to-body="true"
       class="workShopDialog"
     >
-      <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" />
+      <!-- <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" /> -->
+      <PersonFilterSelection
+        @cancel="handleCancle"
+        @submit="handleSubmit"
+        :init-selected="selectedUser"
+      />
     </el-dialog>
   </div>
 </template>
 
 <script lang="ts" setup>
   import { ref, onMounted, watch } from 'vue';
-  import SelectTree from '@/views/message/persongroup/components/SelectTree.vue';
-  interface UserList {
-    id: string;
-    name: string;
-    userId: number;
-  }
+  import { SelectedFilterPersonInfo } from '@/api/message/person-group';
+  // import SelectTree from '@/views/message/persongroup/components/SelectTree.vue';
+  import PersonFilterSelection from '@/views/message/components/PersonFilterSelection.vue';
+  // interface UserList {
+  //   id: string;
+  //   name: string;
+  //   userId: number;
+  // }
   const dialogVisible = ref<boolean>(false);
-  const selectedUser = ref<UserList[]>([]);
+  const selectedUser = ref<SelectedFilterPersonInfo[]>([]);
 
   const prop = defineProps(['form', 'disableType', 'index', 'ruleFormRef']);
 
   const handleCancle = () => {
     dialogVisible.value = false;
   };
-  const handleSubmit = (selectedData: UserList[]) => {
+  const handleSubmit = (selectedData: SelectedFilterPersonInfo[]) => {
     selectedUser.value = selectedData;
     prop.form.customPushConfigList[prop.index].customUserList.length = 0;
     prop.form.customPushConfigList[prop.index].customUserList.push(...selectedUser.value);

+ 23 - 11
src/views/message/reportmessage/components/DefaultPersonSelection.vue

@@ -8,8 +8,12 @@
       @click="dialogVisible = !disableType.contentDisable"
       :disabled="disableType.contentDisable"
     >
-      <el-option v-for="user in selectedUser" :key="user.id" :label="user.name" :value="user">
-      </el-option>
+      <el-option
+        v-for="user in selectedUser"
+        :key="user.id"
+        :label="user.staffNo + '-' + user.nickname"
+        :value="user"
+      />
     </el-select>
     <el-dialog
       v-model="dialogVisible"
@@ -19,30 +23,38 @@
       style="height: 583px"
       :width="731"
       :destroy-on-close="true"
+      :append-to-body="true"
       class="workShopDialog"
     >
-      <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" />
+      <!-- <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" /> -->
+      <PersonFilterSelection
+        @cancel="handleCancle"
+        @submit="handleSubmit"
+        :init-selected="selectedUser"
+      />
     </el-dialog>
   </div>
 </template>
 
 <script lang="ts" setup>
   import { ref, onMounted, watch } from 'vue';
-  import SelectTree from '@/views/message/persongroup/components/SelectTree.vue';
-  interface UserList {
-    id: string;
-    name: string;
-    userId: number;
-  }
+  import { SelectedFilterPersonInfo } from '@/api/message/person-group';
+  // import SelectTree from '@/views/message/persongroup/components/SelectTree.vue';
+  import PersonFilterSelection from '@/views/message/components/PersonFilterSelection.vue';
+  // interface UserList {
+  //   id: string;
+  //   name: string;
+  //   userId: number;
+  // }
   const dialogVisible = ref<boolean>(false);
-  const selectedUser = ref<UserList[]>([]);
+  const selectedUser = ref<SelectedFilterPersonInfo[]>([]);
 
   const prop = defineProps(['form', 'disableType']);
 
   const handleCancle = () => {
     dialogVisible.value = false;
   };
-  const handleSubmit = (selectedData: UserList[]) => {
+  const handleSubmit = (selectedData: SelectedFilterPersonInfo[]) => {
     selectedUser.value = selectedData;
     prop.form.customUserList.value = selectedUser.value;
     dialogVisible.value = false;

+ 23 - 11
src/views/message/reportmessage/components/DesignatedPersonSelection.vue

@@ -8,8 +8,12 @@
       @click="dialogVisible = !disableType.contentDisable"
       :disabled="disableType.contentDisable"
     >
-      <el-option v-for="user in selectedUser" :key="user.id" :label="user.name" :value="user">
-      </el-option>
+      <el-option
+        v-for="user in selectedUser"
+        :key="user.id"
+        :label="user.staffNo + '-' + user.nickname"
+        :value="user"
+      />
     </el-select>
     <el-dialog
       v-model="dialogVisible"
@@ -19,30 +23,38 @@
       style="height: 583px"
       :width="731"
       :destroy-on-close="true"
+      :append-to-body="true"
       class="workShopDialog"
     >
-      <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" />
+      <!-- <SelectTree @cancel="handleCancle" @submit="handleSubmit" :selectedUser="selectedUser" /> -->
+      <PersonFilterSelection
+        @cancel="handleCancle"
+        @submit="handleSubmit"
+        :init-selected="selectedUser"
+      />
     </el-dialog>
   </div>
 </template>
 
 <script lang="ts" setup>
   import { ref, onBeforeUpdate, watch } from 'vue';
-  import SelectTree from '@/views/message/persongroup/components/SelectTree.vue';
-  interface UserList {
-    id: string;
-    name: string;
-    userId: number;
-  }
+  import { SelectedFilterPersonInfo } from '@/api/message/person-group';
+  // import SelectTree from '@/views/message/persongroup/components/SelectTree.vue';
+  import PersonFilterSelection from '@/views/message/components/PersonFilterSelection.vue';
+  // interface UserList {
+  //   id: string;
+  //   name: string;
+  //   userId: number;
+  // }
   const dialogVisible = ref<boolean>(false);
-  const selectedUser = ref<UserList[]>([]);
+  const selectedUser = ref<SelectedFilterPersonInfo[]>([]);
 
   const prop = defineProps(['form', 'disableType']);
 
   const handleCancle = () => {
     dialogVisible.value = false;
   };
-  const handleSubmit = (selectedData: UserList[]) => {
+  const handleSubmit = (selectedData: SelectedFilterPersonInfo[]) => {
     selectedUser.value = selectedData;
     prop.form.designatedUserList.value = selectedUser.value;
     dialogVisible.value = false;