feat: 明细表中的选人组件可以将文字部分保存到独立字段,以加快渲染速度
This commit is contained in:
@ -34,7 +34,7 @@
|
||||
const emits = defineEmits(['change', 'changeNames', 'close', 'options-change', 'update:value']);
|
||||
import { getDepartmentTrees } from '/@/api/system/department';
|
||||
import { CloseOutlined } from '@ant-design/icons-vue';
|
||||
import { camelCaseString } from '/@/utils/event/design';
|
||||
import { camelCaseString } from '/@/utils/stringUtil';
|
||||
|
||||
const visible = ref(false);
|
||||
const departNames = ref();
|
||||
@ -76,7 +76,7 @@
|
||||
(val) => {
|
||||
if (val) {
|
||||
if (props.sepTextField && !valChanged.value) {
|
||||
departNames.value = props.row[camelCaseString(props.sepTextField, true)];
|
||||
departNames.value = props.row[camelCaseString(props.sepTextField)];
|
||||
} else {
|
||||
getDefaultList(val);
|
||||
}
|
||||
@ -99,9 +99,14 @@
|
||||
let nameList = selectedNodes.value.map((item) => item.name);
|
||||
const names = nameList.join(',');
|
||||
departNames.value = names;
|
||||
if (props.sepTextField) {
|
||||
props.row[camelCaseString(props.sepTextField, true)] = names;
|
||||
updateSepTextField(names);
|
||||
}
|
||||
|
||||
function updateSepTextField(v) {
|
||||
if (!props.sepTextField || !props.row) {
|
||||
return;
|
||||
}
|
||||
props.row[props.sepTextField] = v;
|
||||
}
|
||||
|
||||
function resetTreeList(list) {
|
||||
@ -142,9 +147,7 @@
|
||||
const ids = idList.join(',');
|
||||
emits('update:value', ids);
|
||||
departNames.value = names;
|
||||
if (props.sepTextField) {
|
||||
props.row[camelCaseString(props.sepTextField, true)] = names;
|
||||
}
|
||||
updateSepTextField(names);
|
||||
}
|
||||
|
||||
function deleteItem() {
|
||||
|
||||
@ -8,58 +8,47 @@
|
||||
<Icon :icon="suffix" />
|
||||
</template>
|
||||
</a-input>
|
||||
<ModalPanel :visible="visible" :width="900" :title="t('选择人员')" @submit="submit" @close="close"
|
||||
class="select-user-model">
|
||||
<ModalPanel :title="t('选择人员')" :visible="visible" :width="900" class="select-user-model" @close="close" @submit="submit">
|
||||
<div class="select-user">
|
||||
<div class="select-user-left">
|
||||
<a-tabs v-model:activeKey="activeKey" :tabBarGutter="20">
|
||||
<a-tab-pane key="department" tab="组织架构">
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="allPerson" tab="所有人">
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="department" tab="组织架构"></a-tab-pane>
|
||||
<a-tab-pane key="allPerson" tab="所有人"></a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="person-search">
|
||||
<a-form-item label="" name="name">
|
||||
<a-input v-model:value="selectPersonNames" :placeholder="searchPlaceholder" :size="size"
|
||||
class="search-input">
|
||||
</a-input>
|
||||
<a-input v-model:value="selectPersonNames" :placeholder="searchPlaceholder" :size="size" class="search-input"></a-input>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="select-user-box" v-show="activeKey === 'department'">
|
||||
<div v-show="activeKey === 'department'" class="select-user-box">
|
||||
<div class="department-tree">
|
||||
<a-spin class="loading-box" :spinning="treeLoading" />
|
||||
<a-spin :spinning="treeLoading" class="loading-box" />
|
||||
<div class="department-tree-box">
|
||||
<!-- <div class="department-tree-title sub-title">
|
||||
组织
|
||||
</div> -->
|
||||
<SelectDepartmentTreeV2 @changeValue="departChange" class="tree-select"
|
||||
v-if="visible && activeKey === 'department'" @queryCompleted="departCompleted">
|
||||
</SelectDepartmentTreeV2>
|
||||
<SelectDepartmentTreeV2 v-if="visible && activeKey === 'department'" class="tree-select" @changeValue="departChange" @queryCompleted="departCompleted"></SelectDepartmentTreeV2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-select-box">
|
||||
<!-- <div class="user-select-title sub-title">
|
||||
可选列表
|
||||
</div> -->
|
||||
<SelectUserListV2 :data="searchDepartMemberList" @selectId="changeDepMemberSelect"
|
||||
emptyDescription="暂无人员">
|
||||
</SelectUserListV2>
|
||||
<div class="user-select-pagination" v-if="false">
|
||||
<a-pagination v-model:current="searchDepartMemberParams.limit" :pageSize="searchDepartMemberParams.size"
|
||||
:total="searchDepartMemberTotal" />
|
||||
<SelectUserListV2 :data="searchDepartMemberList" emptyDescription="暂无人员" @selectId="changeDepMemberSelect"></SelectUserListV2>
|
||||
<div v-if="false" class="user-select-pagination">
|
||||
<a-pagination v-model:current="searchDepartMemberParams.limit" :pageSize="searchDepartMemberParams.size" :total="searchDepartMemberTotal" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="all-user-select-box" v-show="activeKey === 'allPerson'">
|
||||
<!-- <div class="all-user-select-title sub-title">
|
||||
可选列表
|
||||
</div> -->
|
||||
<div v-show="activeKey === 'allPerson'" class="all-user-select-box">
|
||||
<SelectUserListV2 :data="searchAllMemberList" @selectId="changeMemberSelect"></SelectUserListV2>
|
||||
<div class="all-user-select-pagination" v-if="searchAllMemberTotal > 25">
|
||||
<div v-if="searchAllMemberTotal > 25" class="all-user-select-pagination">
|
||||
<a-form-item label="" name="pagination">
|
||||
<a-pagination size="small" showLessItems :total="searchAllMemberTotal" :show-size-changer="false"
|
||||
v-model:current="searchAllMemberParams.limit" :pageSize="searchAllMemberParams.size"
|
||||
@change="changeAllMemberPage" hideOnSinglePage :show-total="total => `共${total}人`" />
|
||||
<a-pagination
|
||||
v-model:current="searchAllMemberParams.limit"
|
||||
:pageSize="searchAllMemberParams.size"
|
||||
:show-size-changer="false"
|
||||
:show-total="(total) => `共${total}人`"
|
||||
:total="searchAllMemberTotal"
|
||||
hideOnSinglePage
|
||||
showLessItems
|
||||
size="small"
|
||||
@change="changeAllMemberPage"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
@ -68,31 +57,31 @@
|
||||
<!-- <div class="selected-user-title sub-title">
|
||||
已选列表
|
||||
</div> -->
|
||||
<SelectUserListV2 :data="selectedMemberList" viewList canDel @delId="delMember"
|
||||
emptyDescription="暂无已选择人员,<br> 请从左侧添加人员">
|
||||
</SelectUserListV2>
|
||||
<SelectUserListV2 :data="selectedMemberList" canDel emptyDescription="暂无已选择人员,<br> 请从左侧添加人员" viewList @delId="delMember"></SelectUserListV2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ModalPanel>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
<script setup>
|
||||
import { watch, ref } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { ModalPanel } from '/@/components/ModalPanel/index';
|
||||
import { getUserPageListNew, getUserMulti } from '/@/api/system/user';
|
||||
import SelectDepartmentTreeV2 from './SelectDepartmentTreeV2.vue'
|
||||
import SelectDepartmentTreeV2 from './SelectDepartmentTreeV2.vue';
|
||||
import SelectUserListV2 from './SelectUserListV2.vue';
|
||||
import { camelCaseString } from '/@/utils/stringUtil';
|
||||
|
||||
const emits = defineEmits(['update:value', 'selectedId', 'change']);
|
||||
const { t } = useI18n();
|
||||
const userNames = ref('')
|
||||
const treeLoading = ref(true)
|
||||
const visible = ref(false)
|
||||
const activeKey = ref('department')
|
||||
const selectedMemberList = ref([])
|
||||
const selectPersonNames = ref('')
|
||||
const userNames = ref('');
|
||||
const treeLoading = ref(true);
|
||||
const visible = ref(false);
|
||||
const activeKey = ref('department');
|
||||
const selectedMemberList = ref([]);
|
||||
const selectPersonNames = ref('');
|
||||
const valChanged = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
@ -108,15 +97,25 @@ const props = defineProps({
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
row: Object, // 行数据,在表格里用的到
|
||||
sepTextField: String // 将文本表示存储在独立字段
|
||||
});
|
||||
let timeoutId = null;
|
||||
let resetMemberList = []
|
||||
const searchPlaceholder = '请输入姓名或工号搜索'
|
||||
let resetMemberList = [];
|
||||
const searchPlaceholder = '请输入姓名或工号搜索';
|
||||
|
||||
function updateSepTextField(v) {
|
||||
if (!props.sepTextField || !props.row) {
|
||||
return;
|
||||
}
|
||||
props.row[camelCaseString(props.sepTextField)] = v;
|
||||
}
|
||||
|
||||
// 防止输入多次调用搜索接口导致问题,使用防抖
|
||||
watch(selectPersonNames, (newValue) => {
|
||||
if (newValue && activeKey.value !== 'allPerson') {
|
||||
activeKey.value = 'allPerson'
|
||||
activeKey.value = 'allPerson';
|
||||
}
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
@ -125,151 +124,183 @@ watch(selectPersonNames, (newValue) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
// 调用搜索接口
|
||||
console.log('执行搜索API操作, 查询参数为:', newValue);
|
||||
searchNameChanged(newValue)
|
||||
searchNameChanged(newValue);
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
watch(activeKey, (newValue) => {
|
||||
searchAllMemberList.value = []
|
||||
searchAllMemberTotal.value = 0
|
||||
searchDepartMemberList.value = []
|
||||
treeLoading.value = true
|
||||
searchAllMemberList.value = [];
|
||||
searchAllMemberTotal.value = 0;
|
||||
searchDepartMemberList.value = [];
|
||||
treeLoading.value = true;
|
||||
if (newValue !== 'allPerson') {
|
||||
selectPersonNames.value = ''
|
||||
selectPersonNames.value = '';
|
||||
} else {
|
||||
if (!timeoutId) {
|
||||
searchNameChanged('')
|
||||
searchNameChanged('');
|
||||
}
|
||||
}
|
||||
})
|
||||
watch(props, async () => {
|
||||
});
|
||||
watch(
|
||||
props,
|
||||
async () => {
|
||||
if (props.value && !valChanged.value && props.sepTextField) {
|
||||
const idArr = props.value.split(',');
|
||||
const valStr = props.row[camelCaseString(props.sepTextField)];
|
||||
const valArr = valStr.split(',');
|
||||
userNames.value = valStr;
|
||||
const initValue = idArr.map((id, index) => {
|
||||
return {
|
||||
id,
|
||||
name: valArr[index]
|
||||
};
|
||||
});
|
||||
selectedMemberList.value = initValue;
|
||||
resetMemberList = cloneDeep(initValue);
|
||||
return;
|
||||
}
|
||||
if (props.value && !resetMemberList.length) {
|
||||
const list = await getUserMulti(props.value)
|
||||
selectedMemberList.value = list
|
||||
resetMemberList = cloneDeep(list)
|
||||
const nameList = resetMemberList.map(item => {
|
||||
return item.name
|
||||
})
|
||||
userNames.value = nameList.join(',')
|
||||
const list = await getUserMulti(props.value);
|
||||
selectedMemberList.value = list;
|
||||
resetMemberList = cloneDeep(list);
|
||||
const nameList = resetMemberList.map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
userNames.value = nameList.join(',');
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
})
|
||||
}
|
||||
);
|
||||
const searchDepartMemberParams = ref({
|
||||
limit: 1,
|
||||
size: 10000,
|
||||
departmentId: ''
|
||||
})
|
||||
const searchDepartMemberTotal = ref(0)
|
||||
const searchDepartMemberList = ref()
|
||||
});
|
||||
const searchDepartMemberTotal = ref(0);
|
||||
const searchDepartMemberList = ref([]);
|
||||
const searchAllMemberParams = ref({
|
||||
limit: 1,
|
||||
size: 25,
|
||||
isSearchAll: true,
|
||||
keyword: ''
|
||||
})
|
||||
const searchAllMemberTotal = ref(0)
|
||||
const searchAllMemberList = ref()
|
||||
async function departChange(e) {
|
||||
searchDepartMemberParams.value.departmentId = e[0].id
|
||||
let res = await getUserList(searchDepartMemberParams.value)
|
||||
searchDepartMemberTotal.value = res.total
|
||||
searchDepartMemberList.value = setSelected(res.list)
|
||||
}
|
||||
async function searchNameChanged(val) {
|
||||
searchAllMemberParams.value.limit = 1
|
||||
searchAllMemberParams.value.keyword = val
|
||||
getAllMemberList()
|
||||
}
|
||||
async function getAllMemberList() {
|
||||
let res = await getUserList(searchAllMemberParams.value)
|
||||
searchAllMemberTotal.value = res.total
|
||||
searchAllMemberList.value = setSelected(res.list)
|
||||
});
|
||||
const searchAllMemberTotal = ref(0);
|
||||
const searchAllMemberList = ref([]);
|
||||
|
||||
async function departChange(e) {
|
||||
searchDepartMemberParams.value.departmentId = e[0].id;
|
||||
let res = await getUserList(searchDepartMemberParams.value);
|
||||
searchDepartMemberTotal.value = res.total;
|
||||
searchDepartMemberList.value = setSelected(res.list);
|
||||
}
|
||||
|
||||
async function searchNameChanged(val) {
|
||||
searchAllMemberParams.value.limit = 1;
|
||||
searchAllMemberParams.value.keyword = val;
|
||||
getAllMemberList();
|
||||
}
|
||||
|
||||
async function getAllMemberList() {
|
||||
let res = await getUserList(searchAllMemberParams.value);
|
||||
searchAllMemberTotal.value = res.total;
|
||||
searchAllMemberList.value = setSelected(res.list);
|
||||
}
|
||||
|
||||
function setSelected(list) {
|
||||
const idList = selectedMemberList.value.map(item => item.id)
|
||||
const ids = idList.join(',')
|
||||
list.forEach(item => {
|
||||
const idList = selectedMemberList.value.map((item) => item.id);
|
||||
const ids = idList.join(',');
|
||||
list.forEach((item) => {
|
||||
if (ids?.includes(item.id)) {
|
||||
item.selected = true
|
||||
item.selected = true;
|
||||
} else {
|
||||
item.selected = false
|
||||
item.selected = false;
|
||||
}
|
||||
})
|
||||
return list
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
async function getUserList(params) {
|
||||
return await getUserPageListNew(params)
|
||||
return await getUserPageListNew(params);
|
||||
}
|
||||
|
||||
function departCompleted() {
|
||||
treeLoading.value = false
|
||||
treeLoading.value = false;
|
||||
}
|
||||
|
||||
function changeDepMemberSelect(id) {
|
||||
let list = searchDepartMemberList.value
|
||||
searchDepartMemberList.value = handleListSelected(list, id)
|
||||
let list = searchDepartMemberList.value;
|
||||
searchDepartMemberList.value = handleListSelected(list, id);
|
||||
}
|
||||
|
||||
function changeMemberSelect(id) {
|
||||
let list = searchAllMemberList.value
|
||||
searchAllMemberList.value = handleListSelected(list, id)
|
||||
let list = searchAllMemberList.value;
|
||||
searchAllMemberList.value = handleListSelected(list, id);
|
||||
}
|
||||
|
||||
function handleListSelected(list, id) {
|
||||
let selected = false
|
||||
let selectedItem
|
||||
list.forEach(item => {
|
||||
let selected = false;
|
||||
let selectedItem;
|
||||
list.forEach((item) => {
|
||||
if (item.id === id) {
|
||||
item.selected = !!!item.selected
|
||||
selected = item.selected
|
||||
selectedItem = item
|
||||
item.selected = !!!item.selected;
|
||||
selected = item.selected;
|
||||
selectedItem = item;
|
||||
}
|
||||
})
|
||||
let memberList = selectedMemberList.value
|
||||
});
|
||||
let memberList = selectedMemberList.value;
|
||||
if (selected) {
|
||||
memberList.push(selectedItem)
|
||||
selectedMemberList.value = memberList
|
||||
memberList.push(selectedItem);
|
||||
selectedMemberList.value = memberList;
|
||||
} else {
|
||||
selectedMemberList.value = memberList.filter(m => m.id !== id)
|
||||
selectedMemberList.value = memberList.filter((m) => m.id !== id);
|
||||
}
|
||||
return list
|
||||
return list;
|
||||
}
|
||||
|
||||
function changeAllMemberPage(page) {
|
||||
searchAllMemberParams.value.limit = page
|
||||
getAllMemberList()
|
||||
searchAllMemberParams.value.limit = page;
|
||||
getAllMemberList();
|
||||
}
|
||||
|
||||
function show() {
|
||||
visible.value = true
|
||||
treeLoading.value = true
|
||||
visible.value = true;
|
||||
treeLoading.value = true;
|
||||
}
|
||||
|
||||
function delMember(id) {
|
||||
if (activeKey.value === 'department') {
|
||||
changeDepMemberSelect(id)
|
||||
changeDepMemberSelect(id);
|
||||
} else {
|
||||
changeMemberSelect(id)
|
||||
changeMemberSelect(id);
|
||||
}
|
||||
}
|
||||
|
||||
function submit() {
|
||||
let idsList = []
|
||||
let namesList = []
|
||||
selectedMemberList.value.forEach(item => {
|
||||
idsList.push(item.id)
|
||||
namesList.push(item.name)
|
||||
})
|
||||
const ids = idsList.join(',')
|
||||
const names = namesList.join(',')
|
||||
resetMemberList = cloneDeep(selectedMemberList.value)
|
||||
userNames.value = names
|
||||
let idsList = [];
|
||||
let namesList = [];
|
||||
selectedMemberList.value.forEach((item) => {
|
||||
idsList.push(item.id);
|
||||
namesList.push(item.name);
|
||||
});
|
||||
const ids = idsList.join(',');
|
||||
const names = namesList.join(',');
|
||||
resetMemberList = cloneDeep(selectedMemberList.value);
|
||||
userNames.value = names;
|
||||
updateSepTextField(names);
|
||||
emits('update:value', ids);
|
||||
emits('selectedId', ids);
|
||||
emits('change', ids, selectedMemberList.value);
|
||||
valChanged.value = false;
|
||||
close();
|
||||
}
|
||||
|
||||
function close() {
|
||||
selectedMemberList.value = cloneDeep(resetMemberList)
|
||||
selectedMemberList.value = cloneDeep(resetMemberList);
|
||||
visible.value = false;
|
||||
activeKey.value = 'department'
|
||||
searchDepartMemberList.value = []
|
||||
searchAllMemberList.value = []
|
||||
activeKey.value = 'department';
|
||||
searchDepartMemberList.value = [];
|
||||
searchAllMemberList.value = [];
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
@ -289,7 +320,6 @@ function close() {
|
||||
color: rgba(144, 147, 153, 0.7);
|
||||
}
|
||||
|
||||
|
||||
.select-user {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
@ -348,7 +378,8 @@ function close() {
|
||||
flex-direction: column;
|
||||
padding: 4px 8px;
|
||||
|
||||
.department-tree-title {}
|
||||
.department-tree-title {
|
||||
}
|
||||
|
||||
.tree-select {
|
||||
flex: 1;
|
||||
@ -365,7 +396,8 @@ function close() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.user-select-title {}
|
||||
.user-select-title {
|
||||
}
|
||||
|
||||
.user-select-list {
|
||||
flex: 1;
|
||||
@ -394,7 +426,8 @@ function close() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.all-user-select-title {}
|
||||
.all-user-select-title {
|
||||
}
|
||||
|
||||
.all-user-select-pagination {
|
||||
height: 40px;
|
||||
@ -407,8 +440,6 @@ function close() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.select-user-right {
|
||||
@ -417,7 +448,8 @@ function close() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.selected-user-title {}
|
||||
.selected-user-title {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -27,11 +27,8 @@ export function changeToPinyin(label: string, isUpper?: boolean) {
|
||||
|
||||
/* 如果没有下划线,不需要处理
|
||||
如果有下划线,用下划线切割,第一个下划线左边的全部小写,后面的首字母大写,首字母后面的全部小写 */
|
||||
export function camelCaseString(string: string, skipNoUnderline = false) {
|
||||
export function camelCaseString(string: string) {
|
||||
if (!string) return;
|
||||
if (skipNoUnderline && string.indexOf('_') < 0) {
|
||||
return string;
|
||||
}
|
||||
const stringLower = string.toLowerCase();
|
||||
const len = stringLower.length;
|
||||
let str = '';
|
||||
|
||||
20
src/utils/stringUtil.js
Normal file
20
src/utils/stringUtil.js
Normal file
@ -0,0 +1,20 @@
|
||||
export function camelCaseString(string) {
|
||||
if (!string) return;
|
||||
if (string.indexOf('_') < 0) {
|
||||
return string;
|
||||
}
|
||||
const stringLower = string.toLowerCase();
|
||||
const len = stringLower.length;
|
||||
let str = '';
|
||||
for (let i = 0; i < len; i++) {
|
||||
const c = stringLower.charAt(i);
|
||||
if (c === '_') {
|
||||
if (++i < len) {
|
||||
str = str.concat(stringLower.charAt(i).toUpperCase());
|
||||
}
|
||||
} else {
|
||||
str = str.concat(c);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
Reference in New Issue
Block a user