perf: 优化UserInput组件

This commit is contained in:
kuaifan 2022-01-28 13:04:54 +08:00
parent 3c7619098a
commit ae169810d0
7 changed files with 103 additions and 94 deletions

View File

@ -64,7 +64,7 @@
"stylus-loader": "^6.2.0", "stylus-loader": "^6.2.0",
"tinymce": "^5.10.2", "tinymce": "^5.10.2",
"tui-calendar-hi": "^1.15.1-5", "tui-calendar-hi": "^1.15.1-5",
"view-design-hi": "^4.7.0-10", "view-design-hi": "^4.7.0-11",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-clipboard2": "^0.3.3", "vue-clipboard2": "^0.3.3",
"vue-emoji-picker": "^1.0.3", "vue-emoji-picker": "^1.0.3",

View File

@ -1,22 +1,23 @@
<template> <template>
<div v-if="ready" :class="['common-user', maxHiddenClass]"> <div :class="['common-user', maxHiddenClass]">
<Select <Select
v-model="values" ref="select"
v-model="selects"
:transfer="transfer" :transfer="transfer"
:remote-method="searchUser"
:placeholder="placeholder" :placeholder="placeholder"
:size="size" :size="size"
:loading="loading" :loading="loadIng > 0"
:loading-text="$L('加载中...')" :loading-text="$L('加载中...')"
:default-label="value" :default-label="value"
:default-event-object="true" :default-event-object="true"
:multipleMax="multipleMax" :multiple-max="multipleMax"
:multipleUncancelable="uncancelable" :multiple-uncancelable="uncancelable"
:remote-method="searchUser"
@on-query-change="searchUser"
@on-open-change="openChange"
multiple multiple
filterable filterable
transfer-class-name="common-user-transfer" transfer-class-name="common-user-transfer">
@on-open-change="openChange"
@on-set-default-options="setDefaultOptions">
<div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '')}}</div> <div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '')}}</div>
<slot name="option-prepend"></slot> <slot name="option-prepend"></slot>
<Option <Option
@ -33,7 +34,7 @@
</div> </div>
</Option> </Option>
</Select> </Select>
<div v-if="!initialized" class="common-user-loading"><Loading/></div> <div v-if="loadIng > 0" class="common-user-loading"><Loading/></div>
</div> </div>
</template> </template>
@ -87,36 +88,23 @@
}, },
data() { data() {
return { return {
ready: false, loadIng: 0,
initialized: false,
loading: false,
openLoad: false,
values: [],
selects: [],
list: [], list: [],
options: [],
searchKey: null,
searchHistory: [],
subscribe: null, subscribe: null,
} }
}, },
mounted() { mounted() {
if ($A.isArray(this.value)) {
this.values = $A.cloneJSON(this.value);
} else {
this.$emit('input', this.value ? [this.value] : []);
}
this.$nextTick(() => {
this.ready = true;
});
this.subscribe = Store.subscribe('cacheUserActive', (data) => { this.subscribe = Store.subscribe('cacheUserActive', (data) => {
let index = this.list.findIndex(({userid}) => userid == data.userid); let index = this.list.findIndex(({userid}) => userid == data.userid);
if (index > -1) { if (index > -1) {
this.initialized = true;
this.$set(this.list, index, Object.assign({}, this.list[index], data)); this.$set(this.list, index, Object.assign({}, this.list[index], data));
} this.handleSelectData();
let option = this.options.find(({value}) => value == data.userid);
if (option) {
this.$set(option, 'label', data.nickname)
this.$set(option, 'avatar', data.userimg)
} }
}); });
}, },
@ -128,9 +116,9 @@
}, },
computed: { computed: {
maxHiddenClass() { maxHiddenClass() {
const {multipleMax, maxHiddenInput, values} = this; const {multipleMax, maxHiddenInput, selects} = this;
if (multipleMax && maxHiddenInput) { if (multipleMax && maxHiddenInput) {
if (values.length >= multipleMax) { if (selects.length >= multipleMax) {
return 'hidden-input' return 'hidden-input'
} }
} }
@ -138,61 +126,62 @@
} }
}, },
watch: { watch: {
value(val) { value: {
this.values = val; handler() {
this.valueChange()
}, },
values(val) { immediate: true,
},
selects(val) {
this.$emit('input', val); this.$emit('input', val);
} }
}, },
methods: { methods: {
openChange(show) { searchUser(key) {
if (show && !this.openLoad) { if (typeof key !== "string") key = "";
this.openLoad = true; if (key == this.searchKey) return;
if (this.list.length == this.values.length || this.list.length <= 1) { this.searchKey = key;
this.$nextTick(this.searchUser); //
const history = this.searchHistory.find(item => item.key == key);
if (history) this.list = history.data;
//
if (!history) this.loadIng++;
setTimeout(() => {
if (this.searchKey != key) {
if (!history) this.loadIng--;
return;
} }
}
},
setDefaultOptions(options) {
this.options = options;
options.forEach(({value, label}) => {
this.list.push({
userid: value,
nickname: label,
});
this.$store.dispatch("getUserBasic", {userid: value});
});
if (this.list.length == 0) {
this.initialized = true;
}
},
searchUser(query) {
if (query !== '') {
this.loading = true;
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'users/search', url: 'users/search',
data: { data: {
keys: { keys: {
key: query || '', key,
project_id: this.projectId, project_id: this.projectId,
no_project_id: this.noProjectId, no_project_id: this.noProjectId,
}, },
take: 30 take: 30
}, },
}).then(({data}) => { }).then(({data}) => {
this.loading = false; if (!history) this.loadIng--;
this.list = data; this.list = data;
//
const index = this.searchHistory.findIndex(item => item.key == key);
const tmpData = {
key,
data,
time: $A.Time()
};
if (index > -1) {
this.searchHistory.splice(index, 1, tmpData)
} else {
this.searchHistory.push(tmpData)
}
}).catch(({msg}) => { }).catch(({msg}) => {
this.loading = false; if (!history) this.loadIng--;
this.list = []; this.list = [];
$A.messageWarning(msg); $A.messageWarning(msg);
}); });
} else { }, this.searchHistory.length > 0 ? 300 : 0)
this.list = [];
}
}, },
isDisabled(userid) { isDisabled(userid) {
@ -200,6 +189,48 @@
return false; return false;
} }
return this.disabledChoice.includes(userid) return this.disabledChoice.includes(userid)
},
openChange(show) {
if (show) {
this.$nextTick(this.searchUser);
}
},
valueChange() {
if (this.selects == this.value) {
return
}
if ($A.isArray(this.value)) {
this.selects = $A.cloneJSON(this.value);
} else if (this.value) {
this.selects = [this.value]
} else {
this.selects = [];
}
this.selects.some(userid => {
if (!this.list.find(item => item.userid == userid)) {
this.list.push({userid, nickname: userid});
this.$store.dispatch("getUserBasic", {userid});
}
})
},
handleSelectData() {
this.__handleSelectTimeout && clearTimeout(this.__handleSelectTimeout);
this.__handleSelectTimeout = setTimeout(() => {
if (!this.$refs.select) {
return;
}
const list = this.$refs.select.getValue();
list && list.some(option => {
const data = this.list.find(({userid}) => userid == option.value)
if (data) {
this.$set(option, 'label', data.nickname)
this.$set(option, 'avatar', data.userimg)
}
})
}, 100);
} }
} }
}; };

View File

@ -332,7 +332,7 @@
:mask-closable="false"> :mask-closable="false">
<Form :model="userData" label-width="auto" @submit.native.prevent> <Form :model="userData" label-width="auto" @submit.native.prevent>
<FormItem prop="userids" :label="$L('项目成员')"> <FormItem prop="userids" :label="$L('项目成员')">
<UserInput v-if="userShow" v-model="userData.userids" :uncancelable="userData.uncancelable" :multiple-max="100" :placeholder="$L('选择项目成员')"/> <UserInput v-model="userData.userids" :uncancelable="userData.uncancelable" :multiple-max="100" :placeholder="$L('选择项目成员')"/>
</FormItem> </FormItem>
</Form> </Form>
<div slot="footer" class="adaption"> <div slot="footer" class="adaption">
@ -394,7 +394,7 @@
:mask-closable="false"> :mask-closable="false">
<Form :model="transferData" label-width="auto" @submit.native.prevent> <Form :model="transferData" label-width="auto" @submit.native.prevent>
<FormItem prop="owner_userid" :label="$L('项目负责人')"> <FormItem prop="owner_userid" :label="$L('项目负责人')">
<UserInput v-if="transferShow" v-model="transferData.owner_userid" :multiple-max="1" :placeholder="$L('选择项目负责人')"/> <UserInput v-model="transferData.owner_userid" :multiple-max="1" :placeholder="$L('选择项目负责人')"/>
</FormItem> </FormItem>
</Form> </Form>
<div slot="footer" class="adaption"> <div slot="footer" class="adaption">

View File

@ -143,7 +143,7 @@
:mask-closable="false"> :mask-closable="false">
<Form :model="userData" label-width="auto" @submit.native.prevent> <Form :model="userData" label-width="auto" @submit.native.prevent>
<FormItem prop="userids" :label="$L('状态负责人')"> <FormItem prop="userids" :label="$L('状态负责人')">
<UserInput v-if="userShow" v-model="userData.userids" :project-id="projectId" :multiple-max="5" :placeholder="$L('选择状态负责人')"/> <UserInput v-model="userData.userids" :project-id="projectId" :multiple-max="5" :placeholder="$L('选择状态负责人')"/>
</FormItem> </FormItem>
<FormItem prop="usertype" :label="$L('流转模式')"> <FormItem prop="usertype" :label="$L('流转模式')">
<RadioGroup v-model="userData.usertype"> <RadioGroup v-model="userData.usertype">

View File

@ -39,7 +39,6 @@
<Col span="22"> <Col span="22">
<div class="report-users"> <div class="report-users">
<UserInput <UserInput
v-if="userInputShow"
v-model="reportData.receive" v-model="reportData.receive"
:disabledChoice="[userId]" :disabledChoice="[userId]"
:placeholder="$L('选择接收人')" /> :placeholder="$L('选择接收人')" />
@ -94,7 +93,6 @@ export default {
offset: 0 // -1 offset: 0 // -1
}, },
disabledType: false, disabledType: false,
userInputShow: true,
prevCycleText: "", prevCycleText: "",
nextCycleText: "", nextCycleText: "",
}; };
@ -210,7 +208,6 @@ export default {
}, },
getDetail(reportId) { getDetail(reportId) {
this.userInputShow = false;
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'report/detail', url: 'report/detail',
data: { data: {
@ -224,12 +221,10 @@ export default {
this.reportData.type = data.type_val; this.reportData.type = data.type_val;
this.reportData.id = reportId; this.reportData.id = reportId;
this.disabledType = true; this.disabledType = true;
this.userInputShow = true;
// msg // msg
}).catch(({msg}) => { }).catch(({msg}) => {
// msg // msg
$A.messageError(msg); $A.messageError(msg);
this.userInputShow = true;
}); });
}, },
@ -252,18 +247,15 @@ export default {
// //
getLastSubmitter() { getLastSubmitter() {
this.userInputShow = false;
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'report/last_submitter', url: 'report/last_submitter',
}).then(({data, msg}) => { }).then(({data, msg}) => {
// data // data
this.reportData.receive = data; this.reportData.receive = data;
this.userInputShow = true;
// msg // msg
}).catch(({msg}) => { }).catch(({msg}) => {
// msg // msg
$A.messageError(msg); $A.messageError(msg);
this.userInputShow = true;
}); });
}, },

View File

@ -45,12 +45,10 @@
:width="240" :width="240"
placement="bottom" placement="bottom"
@on-popper-show="openOwner" @on-popper-show="openOwner"
@on-popper-hide="ownerShow=false"
@on-ok="onOwner" @on-ok="onOwner"
transfer> transfer>
<div slot="content"> <div slot="content">
<UserInput <UserInput
v-if="ownerShow"
v-model="ownerData.owner_userid" v-model="ownerData.owner_userid"
:multiple-max="1" :multiple-max="1"
:project-id="taskDetail.project_id" :project-id="taskDetail.project_id"
@ -193,12 +191,10 @@
class="item-content user" class="item-content user"
placement="bottom" placement="bottom"
@on-popper-show="openOwner" @on-popper-show="openOwner"
@on-popper-hide="ownerShow=false"
@on-ok="onOwner" @on-ok="onOwner"
transfer> transfer>
<div slot="content"> <div slot="content">
<UserInput <UserInput
v-if="ownerShow"
v-model="ownerData.owner_userid" v-model="ownerData.owner_userid"
:multiple-max="10" :multiple-max="10"
:project-id="taskDetail.project_id" :project-id="taskDetail.project_id"
@ -223,12 +219,10 @@
class="item-content user" class="item-content user"
placement="bottom" placement="bottom"
@on-popper-show="openAssist" @on-popper-show="openAssist"
@on-popper-hide="assistShow=false"
@on-ok="onAssist" @on-ok="onAssist"
transfer> transfer>
<div slot="content"> <div slot="content">
<UserInput <UserInput
v-if="assistShow"
v-model="assistData.assist_userid" v-model="assistData.assist_userid"
:multiple-max="10" :multiple-max="10"
:project-id="taskDetail.project_id" :project-id="taskDetail.project_id"
@ -448,14 +442,12 @@ export default {
taskDetail: {}, taskDetail: {},
ownerShow: false,
ownerData: {}, ownerData: {},
ownerLoad: 0, ownerLoad: 0,
receiveShow: false, receiveShow: false,
assistForce: false, assistForce: false,
assistShow: false,
assistData: {}, assistData: {},
assistLoad: 0, assistLoad: 0,
@ -797,7 +789,6 @@ export default {
const list = this.getOwner.map(({userid}) => userid) const list = this.getOwner.map(({userid}) => userid)
this.$set(this.taskDetail, 'owner_userid', list) this.$set(this.taskDetail, 'owner_userid', list)
this.$set(this.ownerData, 'owner_userid', list) this.$set(this.ownerData, 'owner_userid', list)
this.ownerShow = true;
}, },
onOwner(pick) { onOwner(pick) {
@ -833,13 +824,11 @@ export default {
this.$store.dispatch("taskUpdate", data).then(({msg}) => { this.$store.dispatch("taskUpdate", data).then(({msg}) => {
$A.messageSuccess(msg); $A.messageSuccess(msg);
this.ownerLoad--; this.ownerLoad--;
this.ownerShow = false;
this.receiveShow = false; this.receiveShow = false;
this.$store.dispatch("getTaskOne", this.taskDetail.id).catch(() => {}) this.$store.dispatch("getTaskOne", this.taskDetail.id).catch(() => {})
}).catch(({msg}) => { }).catch(({msg}) => {
$A.modalError(msg); $A.modalError(msg);
this.ownerLoad--; this.ownerLoad--;
this.ownerShow = false;
this.receiveShow = false; this.receiveShow = false;
}) })
}, },
@ -849,7 +838,6 @@ export default {
this.$set(this.taskDetail, 'assist_userid', list) this.$set(this.taskDetail, 'assist_userid', list)
this.$set(this.assistData, 'assist_userid', list); this.$set(this.assistData, 'assist_userid', list);
this.$set(this.assistData, 'disabled', this.getOwner.map(({userid}) => userid)) this.$set(this.assistData, 'disabled', this.getOwner.map(({userid}) => userid))
this.assistShow = true;
}, },
onAssist() { onAssist() {
@ -865,12 +853,10 @@ export default {
}).then(({msg}) => { }).then(({msg}) => {
$A.messageSuccess(msg); $A.messageSuccess(msg);
this.assistLoad--; this.assistLoad--;
this.assistShow = false;
this.$store.dispatch("getTaskOne", this.taskDetail.id).catch(() => {}) this.$store.dispatch("getTaskOne", this.taskDetail.id).catch(() => {})
}).catch(({msg}) => { }).catch(({msg}) => {
$A.modalError(msg); $A.modalError(msg);
this.assistLoad--; this.assistLoad--;
this.assistShow = false;
}) })
}, },

View File

@ -273,11 +273,11 @@ export default {
dispatch("call", { dispatch("call", {
url: 'users/basic', url: 'users/basic',
data: { data: {
userid: array.map(({userid}) => userid) userid: [...new Set(array.map(({userid}) => userid))]
}, },
}).then(result => { }).then(result => {
time = $A.Time(); time = $A.Time();
array.forEach((value) => { array.forEach(value => {
let data = result.data.find(({userid}) => userid == value.userid) || Object.assign(value, {email: ""}); let data = result.data.find(({userid}) => userid == value.userid) || Object.assign(value, {email: ""});
data._time = time; data._time = time;
dispatch("saveUserBasic", data); dispatch("saveUserBasic", data);