push
This commit is contained in:
596
lib/component/shuttleFrame/shuttleFrameDeptOrMember.vue
Normal file
596
lib/component/shuttleFrame/shuttleFrameDeptOrMember.vue
Normal file
@@ -0,0 +1,596 @@
|
||||
<!-- eslint-disable vue/v-on-event-hyphenation -->
|
||||
<template>
|
||||
<div>
|
||||
<div class="search-input">
|
||||
<a-input
|
||||
v-model:value="searchValue"
|
||||
:placeholder="placeholder"
|
||||
@pressEnter="onSearch"
|
||||
:bordered="false" />
|
||||
<ns-icon class="iconfont" style="margin: auto" name="search" />
|
||||
</div>
|
||||
<div class="checkbox-content">
|
||||
<p class="selectLevel">
|
||||
<span
|
||||
v-for="(item, index) in selectLevel"
|
||||
:key="index"
|
||||
@click="checkSelectLevel(item, index)">
|
||||
<span v-if="index != 0">></span>
|
||||
<span
|
||||
:class="index == selectLevel.length - 1 ? 'selectLevel-last-span' : 'selectLevel-span'"
|
||||
>{{ item.name }}</span
|
||||
>
|
||||
</span>
|
||||
</p>
|
||||
<div class="candidate-content" v-if="candidateValues.length > 0">
|
||||
<div style="padding: 4px 0px" v-if="filterMultiple">
|
||||
<a-checkbox
|
||||
:indeterminate="state.indeterminate"
|
||||
v-model:checked="state.checkAll"
|
||||
@change="onCheckAllChange">
|
||||
全选
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<div v-for="(item, index) in candidateValues" :key="index" class="checkbox">
|
||||
<a-checkbox
|
||||
v-if="filterMultiple"
|
||||
v-model:checked="item.checked"
|
||||
@change="onCheckChange($event, item)"
|
||||
>{{ item.name }}</a-checkbox
|
||||
>
|
||||
<a-radio v-else v-model:checked="item.checked" @click="onCheckChangeRadio(item)">{{
|
||||
item.name
|
||||
}}</a-radio>
|
||||
<span
|
||||
v-if="searchType == 'dept'"
|
||||
@click="checkSubordinate(item)"
|
||||
:class="
|
||||
item.subordinateDisable ? 'checkbox-subordinate-disable' : 'checkbox-subordinate'
|
||||
">
|
||||
<ns-icon
|
||||
class="iconfont"
|
||||
style="margin: auto; width: 12px; height: 12px"
|
||||
:name="item.subordinateDisable ? 'subordinate-dis' : 'subordinate'" />
|
||||
下级</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="candidateValues.length <= 0 && ifLoading">
|
||||
<a-result title="暂无相关部门/人员">
|
||||
<template #icon>
|
||||
<ns-icon
|
||||
class="iconfont"
|
||||
style="margin: auto; width: 120px; height: 120px"
|
||||
name="noSearchData" />
|
||||
</template>
|
||||
</a-result>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, inject, reactive } from 'vue';
|
||||
import { watch } from 'vue';
|
||||
import { defineComponent, ref, onMounted } from 'vue';
|
||||
import { http } from '../../util/http';
|
||||
import { remove } from 'lodash-es';
|
||||
import { unref } from 'vue';
|
||||
import { compareArrays } from './util';
|
||||
import { Emitter } from 'mitt';
|
||||
|
||||
//单独部门/人员 只区分单选或多选
|
||||
export default defineComponent({
|
||||
name: 'NsShuttleFrameDeptOrMember',
|
||||
props: {
|
||||
//是否多选
|
||||
filterMultiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: String,
|
||||
searchType: {
|
||||
type: String,
|
||||
default: 'account',
|
||||
},
|
||||
// componentRef: String,
|
||||
api: {
|
||||
type: Object,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
default: {
|
||||
account: '/api/passport/passport/objs/DepartmentAccounts',
|
||||
dept: '/api/passport/passport/objs/Department',
|
||||
},
|
||||
},
|
||||
},
|
||||
emits: ['selected'],
|
||||
setup(props, ctx) {
|
||||
const lmEmitter = inject('lmEmitter') as Emitter<emitEvents>;
|
||||
// function initData() {
|
||||
// if (props.searchType == 'dept') {
|
||||
// organizationGet();
|
||||
// } else {
|
||||
// accountGet();
|
||||
// }
|
||||
// }
|
||||
// initData();
|
||||
|
||||
lmEmitter.on('deleteAllSelected', (data) => {
|
||||
deleteAllSelected();
|
||||
});
|
||||
|
||||
lmEmitter.on('deleteSelected', (data) => {
|
||||
deleteSelected(data);
|
||||
});
|
||||
|
||||
//全部的值
|
||||
const departmentAllData = ref([]);
|
||||
const accountAllData = ref([]);
|
||||
const ifLoading = ref(false);
|
||||
//展示的候选值
|
||||
const candidateValues = ref([]);
|
||||
//选中的层级
|
||||
const selectLevel = ref<any>([]);
|
||||
//选中的值
|
||||
const selectedValue = ref<any>([]);
|
||||
|
||||
//获取部门的值
|
||||
async function organizationGet() {
|
||||
let data = await http.get(
|
||||
props.api.dept,
|
||||
{ pageSize: 9999, levelID: 0 },
|
||||
{ timeout: 120 * 1000 },
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
//获取人员的值
|
||||
async function accountGet() {
|
||||
await http.get(props.api.account, { pageSize: 9999 }, { timeout: 120 * 1000 });
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
indeterminate: false,
|
||||
checkAll: false,
|
||||
checkedList: [],
|
||||
});
|
||||
|
||||
const onCheckAllChange = (e: any) => {
|
||||
Object.assign(state, {
|
||||
indeterminate: false,
|
||||
checkAll: e.target.checked,
|
||||
});
|
||||
//全选
|
||||
if (e.target.checked) {
|
||||
//selectedValue.value 需要不影响之前的选中
|
||||
state.checkedList = [];
|
||||
candidateValues.value.map((item) => {
|
||||
state.checkedList.push(item.ID);
|
||||
const ret = selectedValue.value.find((ev: { id: any }) => {
|
||||
return ev.id === item.ID;
|
||||
});
|
||||
if (ret == undefined) {
|
||||
selectedValue.value.push({
|
||||
type: props.searchType,
|
||||
id: item.ID,
|
||||
name: item.name,
|
||||
});
|
||||
}
|
||||
item.subordinateDisable = true;
|
||||
item.checked = e.target.checked;
|
||||
});
|
||||
} else {
|
||||
state.checkedList = [];
|
||||
candidateValues.value.map((item) => {
|
||||
remove(unref(selectedValue.value), (elem: object) => {
|
||||
return elem.id === item.ID;
|
||||
});
|
||||
item.subordinateDisable = false;
|
||||
item.checked = e.target.checked;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => state.checkedList,
|
||||
(val) => {
|
||||
state.indeterminate = !!val.length && val.length < candidateValues.value.length;
|
||||
state.checkAll =
|
||||
val.length === candidateValues.value.length && candidateValues.value.length > 0;
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// watch(
|
||||
// () => selectedValue.value,
|
||||
// (val) => {
|
||||
// val.map((elem) => {
|
||||
// elem.componentRef = props.componentRef;
|
||||
// });
|
||||
// },
|
||||
// { immediate: true, deep: true },
|
||||
// );
|
||||
|
||||
const selectedValueCopy = computed(() => JSON.parse(JSON.stringify(selectedValue.value)));
|
||||
watch(
|
||||
() => selectedValueCopy.value,
|
||||
(newData, old) => {
|
||||
let val = [];
|
||||
let delVal = [];
|
||||
if (props.filterMultiple) {
|
||||
//新增
|
||||
if (!old || newData.length > old.length) {
|
||||
val = compareArrays(newData, old);
|
||||
ctx.emit('selected', val, 'add');
|
||||
}
|
||||
//删除
|
||||
else {
|
||||
delVal = compareArrays(old, newData);
|
||||
ctx.emit('selected', delVal, 'del');
|
||||
}
|
||||
} else {
|
||||
//取消选择
|
||||
if (newData.length == 0 && old) {
|
||||
ctx.emit('selected', old, 'del');
|
||||
}
|
||||
//切换选择
|
||||
else if (old) {
|
||||
ctx.emit('selected', newData, 'add');
|
||||
ctx.emit('selected', old, 'del');
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
const onCheckChange = (e: any, item: object) => {
|
||||
if (e.target.checked) {
|
||||
state.checkedList.push(item.ID);
|
||||
selectedValue.value.push({
|
||||
type: props.searchType,
|
||||
id: item.ID,
|
||||
name: item.name,
|
||||
});
|
||||
candidateValues.value.map((elem) => {
|
||||
if (item.ID === elem.ID) {
|
||||
elem.subordinateDisable = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
remove(unref(state.checkedList), (elem: object) => {
|
||||
return elem === item.ID;
|
||||
});
|
||||
remove(unref(selectedValue.value), (elem: object) => {
|
||||
return elem.id === item.ID;
|
||||
});
|
||||
candidateValues.value.map((elem) => {
|
||||
if (item.ID === elem.ID) {
|
||||
elem.checked = false;
|
||||
elem.subordinateDisable = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function checkSubordinate(item: { subordinateDisable: any; ID: any; name: any }) {
|
||||
if (item.subordinateDisable) return;
|
||||
state.checkedList = [];
|
||||
selectLevel.value.push({
|
||||
id: item.ID,
|
||||
name: item.name,
|
||||
});
|
||||
candidateValues.value = departmentAllData.value.filter(function (elem) {
|
||||
return elem.levelID == item.ID;
|
||||
});
|
||||
}
|
||||
|
||||
function checkSelectLevel(item: { id: any }, index: number) {
|
||||
if (index == selectLevel.value.length - 1) return;
|
||||
selectLevel.value.forEach((elem: { id: any }, index: number) => {
|
||||
if (elem.id == item.id) {
|
||||
selectLevel.value.splice(index + 1, selectLevel.value.length - 1);
|
||||
}
|
||||
});
|
||||
candidateValues.value = departmentAllData.value.filter(function (elem) {
|
||||
return elem.levelID == item.id;
|
||||
});
|
||||
if (!props.filterMultiple) {
|
||||
let ifSelected = candidateValues.value.filter(function (elem) {
|
||||
return elem.checked == true;
|
||||
});
|
||||
//说明选中了,之前的选中要删除
|
||||
if (ifSelected.length > 0 && ifSelected[0].ID !== selectedValue.value[0].id) {
|
||||
candidateValues.value.map((elem) => {
|
||||
elem.checked = false;
|
||||
elem.subordinateDisable = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedValue() {
|
||||
// selectedValue.value.map((elem) => {
|
||||
// elem.componentRef = props.componentRef;
|
||||
// });
|
||||
return selectedValue.value;
|
||||
}
|
||||
|
||||
//单选场景
|
||||
const onCheckChangeRadio = (item: object) => {
|
||||
console.log(item.checked);
|
||||
if (!item.checked) {
|
||||
selectedValue.value = [
|
||||
{
|
||||
type: props.searchType,
|
||||
id: item.ID,
|
||||
name: item.name,
|
||||
},
|
||||
];
|
||||
candidateValues.value.map((elem) => {
|
||||
elem.checked = item.ID === elem.ID;
|
||||
elem.subordinateDisable = item.ID === elem.ID;
|
||||
});
|
||||
} else {
|
||||
remove(unref(selectedValue.value), (elem: object) => {
|
||||
return elem.id === item.ID;
|
||||
});
|
||||
candidateValues.value.map((elem) => {
|
||||
if (item.ID === elem.ID) {
|
||||
elem.checked = false;
|
||||
elem.subordinateDisable = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('selectedValue', selectedValue.value);
|
||||
};
|
||||
|
||||
//删除已选择
|
||||
function deleteSelected(item: { type: string; id: object }) {
|
||||
console.log('deleteSelected', item);
|
||||
if (item.type == 'dept') {
|
||||
candidateValues.value.map((elem) => {
|
||||
if (elem.ID == item.id) {
|
||||
elem.subordinateDisable = false;
|
||||
elem.checked = false;
|
||||
}
|
||||
});
|
||||
remove(unref(state.checkedList), (elem: object) => {
|
||||
return elem.deptID === item.id && elem.type == item.type;
|
||||
});
|
||||
} else {
|
||||
candidateValues.value.map((elem) => {
|
||||
if (elem.ID == item.id) {
|
||||
elem.checked = false;
|
||||
}
|
||||
});
|
||||
remove(unref(state.checkedList), (elem: object) => {
|
||||
return elem === item.id;
|
||||
});
|
||||
}
|
||||
remove(unref(selectedValue.value), (elem: object) => {
|
||||
return elem.id === item.id && elem.type == item.type;
|
||||
});
|
||||
}
|
||||
|
||||
//清空已选择
|
||||
function deleteAllSelected() {
|
||||
state.checkedList = [];
|
||||
selectedValue.value = [];
|
||||
candidateValues.value.map((elem) => {
|
||||
elem.checked = false;
|
||||
});
|
||||
}
|
||||
|
||||
const searchValue = ref();
|
||||
|
||||
function onSearch() {
|
||||
if (selectLevel.value.length > 1) {
|
||||
selectLevel.value = selectLevel.value.splice(0, selectLevel.value.length - 1);
|
||||
}
|
||||
if (props.searchType == 'account') {
|
||||
candidateValues.value = accountAllData.value.filter(function (item) {
|
||||
return item.name.includes(searchValue.value);
|
||||
});
|
||||
} else {
|
||||
candidateValues.value = departmentAllData.value.filter(function (item) {
|
||||
return item.name.includes(searchValue.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function formatOrganizationData(data: { data: string | any[] }) {
|
||||
if (data.data.length > 0) {
|
||||
selectLevel.value.push({
|
||||
id: 0,
|
||||
name: data.data[0].tenant,
|
||||
});
|
||||
let selectedList: any[] = [];
|
||||
selectedValue.value.map((item: { id: any }) => {
|
||||
selectedList.push(item.id);
|
||||
});
|
||||
departmentAllData.value = data.data;
|
||||
initSelectedOrgan();
|
||||
}
|
||||
}
|
||||
|
||||
function initSelectedOrgan() {
|
||||
let selectedList: any[] = [];
|
||||
selectedValue.value.map((item: { id: any }) => {
|
||||
selectedList.push(item.id);
|
||||
});
|
||||
departmentAllData.value.map((item) => {
|
||||
item.subordinateDisable = selectedList.includes(item.ID);
|
||||
item.checked = selectedList.includes(item.ID);
|
||||
});
|
||||
candidateValues.value = departmentAllData.value.filter(function (item: {
|
||||
checked: boolean;
|
||||
ID: any;
|
||||
levelID: number;
|
||||
}) {
|
||||
return item.levelID == 0;
|
||||
});
|
||||
}
|
||||
|
||||
function formatAccountData(data: { data: { tenant: any }[] }) {
|
||||
if (data.data.length > 0) {
|
||||
selectLevel.value.push({
|
||||
id: 0,
|
||||
name: data.data[0].tenant,
|
||||
});
|
||||
let selectedList: any[] = [];
|
||||
selectedValue.value.map((item: { id: any }) => {
|
||||
selectedList.push(item.id);
|
||||
});
|
||||
data.data.map((item: { subordinateDisable: boolean; ID: any; checked: boolean }) => {
|
||||
item.subordinateDisable = selectedList.includes(item.ID);
|
||||
item.checked = selectedList.includes(item.ID);
|
||||
});
|
||||
accountAllData.value = data.data;
|
||||
candidateValues.value = data.data.filter(function (item: {
|
||||
checked: boolean;
|
||||
levelID: number;
|
||||
}) {
|
||||
return item.levelID == 0;
|
||||
});
|
||||
candidateValues.value = data.data;
|
||||
}
|
||||
}
|
||||
|
||||
//初始化值
|
||||
lmEmitter.on('setDefaultDataMOD', (data: any) => {
|
||||
if (props.searchType == 'account') {
|
||||
accountGet().then((res) => {
|
||||
formatAccountData(res);
|
||||
if (data.length <= 0) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
//单选
|
||||
initSelectedValue(accountAllData.value, data, 'account');
|
||||
}, 100);
|
||||
});
|
||||
} else {
|
||||
organizationGet().then((res) => {
|
||||
formatOrganizationData(res);
|
||||
if (data.length <= 0) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
initSelectedValue(departmentAllData.value, data, 'dept');
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function initSelectedValue(list: any[], data: any[], type: string) {
|
||||
//单选
|
||||
if (!props.filterMultiple) {
|
||||
let item = list.filter(function (elem: { name: any }) {
|
||||
return elem.name == data[0].name;
|
||||
});
|
||||
data[0].id = item[0].ID;
|
||||
}
|
||||
//多选
|
||||
else {
|
||||
let nameList: any[] = [];
|
||||
data.map((item: { name: any }) => {
|
||||
nameList.push(item.name);
|
||||
});
|
||||
let dataList = list.filter(function (elem: { name: any }) {
|
||||
return nameList.includes(elem.name);
|
||||
});
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
try {
|
||||
dataList.map((dl: { name: any }) => {
|
||||
if (dl.name == data[index].name) {
|
||||
throw dl;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
data[index].id = error.ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectedValue.value = data;
|
||||
ifLoading.value = true;
|
||||
if (type == 'dept') {
|
||||
initSelectedOrgan();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
candidateValues,
|
||||
onCheckAllChange,
|
||||
searchValue,
|
||||
onSearch,
|
||||
onCheckChange,
|
||||
state,
|
||||
checkSubordinate,
|
||||
selectLevel,
|
||||
checkSelectLevel,
|
||||
selectedValue,
|
||||
getSelectedValue,
|
||||
onCheckChangeRadio,
|
||||
deleteSelected,
|
||||
deleteAllSelected,
|
||||
ifLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.search-input {
|
||||
display: flex;
|
||||
border: 1px solid #dcdfe2;
|
||||
border-radius: 8px;
|
||||
padding-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.checkbox {
|
||||
padding: 4px 0;
|
||||
|
||||
&-subordinate {
|
||||
float: right;
|
||||
color: @primary-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
&-subordinate-disable {
|
||||
float: right;
|
||||
color: #9b9b9b;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
.selectLevel {
|
||||
margin-bottom: 2px;
|
||||
|
||||
&-last-span {
|
||||
color: #9b9b9b;
|
||||
padding: 0px 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
&-span {
|
||||
padding: 0px 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.checkbox-content {
|
||||
//overflow-y: auto;
|
||||
// min-height: 250px;
|
||||
// max-height: 350px;
|
||||
// height: 250px;
|
||||
}
|
||||
.candidate-content {
|
||||
height: 250px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
:deep(.ant-result) {
|
||||
padding: 24px;
|
||||
}
|
||||
:deep(.ant-result-icon) {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
:deep(.ant-result-title) {
|
||||
color: #747677;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user