|
|
@@ -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;
|