mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-11 18:42:54 +00:00
845 lines
29 KiB
Vue
Executable File
845 lines
29 KiB
Vue
Executable File
<template>
|
||
<div class="common-user-select" :class="warpClass">
|
||
<ul v-if="!module">
|
||
<li v-for="userid in values" v-if="userid" @click="onSelection">
|
||
<UserAvatar :userid="userid" :size="avatarSize" :show-icon="avatarIcon" :show-name="avatarName"/>
|
||
</li>
|
||
<li v-if="addIcon || values.length === 0" class="add-icon" :style="addStyle" @click="onSelection"></li>
|
||
</ul>
|
||
|
||
<Modal
|
||
v-model="showModal"
|
||
class-name="common-user-select-modal"
|
||
:mask-closable="false"
|
||
:closable="!isFullscreen"
|
||
:fullscreen="isFullscreen"
|
||
:footer-hide="isFullscreen"
|
||
width="640">
|
||
|
||
<!-- 顶部 -->
|
||
<template #header>
|
||
<div v-if="isFullscreen" class="user-modal-header">
|
||
<div class="user-modal-close" @click="showModal=false">{{$L('关闭')}}</div>
|
||
<div class="user-modal-title">
|
||
<span ref="headerTitle" @click="onClickTitle">{{localTitle}}</span>
|
||
</div>
|
||
<div ref="headerSubmit" class="user-modal-submit" @click="onSubmit">
|
||
<div v-if="submittIng > 0" class="submit-loading"><Loading /></div>
|
||
{{$L('确定')}}
|
||
<template v-if="selects.length > 0">
|
||
({{selects.length}}<span v-if="multipleMax">/{{multipleMax}}</span>)
|
||
</template>
|
||
</div>
|
||
</div>
|
||
<div v-else class="ivu-modal-header-inner">{{localTitle}}</div>
|
||
</template>
|
||
<template #close>
|
||
<i class="ivu-icon ivu-icon-ios-close"></i>
|
||
</template>
|
||
|
||
<!-- 搜索 -->
|
||
<div class="user-modal-search">
|
||
<Scrollbar ref="selected" class="search-selected" v-if="selects.length > 0" enable-x :enable-y="false">
|
||
<ul>
|
||
<li v-for="item in formatSelect(selects)" :data-id="item.userid" @click.stop="onRemoveItem(item.userid)">
|
||
<template v-if="item.type=='group'">
|
||
<EAvatar v-if="item.avatar" class="img-avatar" :src="item.avatar" :size="32"></EAvatar>
|
||
<i v-else-if="item.group_type=='department'" class="taskfont icon-avatar department"></i>
|
||
<i v-else-if="item.group_type=='project'" class="taskfont icon-avatar project"></i>
|
||
<i v-else-if="item.group_type=='task'" class="taskfont icon-avatar task"></i>
|
||
<i v-else-if="item.group_type=='okr'" class="taskfont icon-avatar task"></i>
|
||
<Icon v-else class="icon-avatar" type="ios-people" />
|
||
</template>
|
||
<UserAvatar v-else :userid="item.userid"/>
|
||
</li>
|
||
</ul>
|
||
</Scrollbar>
|
||
<div class="search-input">
|
||
<div class="search-pre">
|
||
<Loading v-if="loadIng > 0"/>
|
||
<Icon v-else type="ios-search" />
|
||
</div>
|
||
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide">
|
||
<Input
|
||
type="search"
|
||
v-model="searchKey"
|
||
:placeholder="localPlaceholder"
|
||
@on-keydown="onKeydown"
|
||
@on-keyup="onKeyup"
|
||
clearable/>
|
||
</Form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 切换 -->
|
||
<ul v-if="isWhole" class="user-modal-switch">
|
||
<li
|
||
v-for="item in switchItems" :key="item.key"
|
||
:class="{active:switchActive===item.key}"
|
||
@click="switchActive=item.key">{{ $L(item.label) }}</li>
|
||
</ul>
|
||
|
||
<!-- 列表 -->
|
||
<Scrollbar v-if="lists.length > 0" class="user-modal-list">
|
||
<!-- 项目 -->
|
||
<ul v-if="switchActive == 'project'" class="user-modal-project">
|
||
<li
|
||
v-for="item in lists"
|
||
:class="selectClass(item.userid_list)"
|
||
@click="onSelectProject(item.userid_list)">
|
||
<Icon class="user-modal-icon" :type="selectIcon(item.userid_list)" />
|
||
<div class="user-modal-avatar">
|
||
<i class="taskfont icon-avatar"></i>
|
||
<div class="project-name">
|
||
<div class="label">{{item.name}}</div>
|
||
<div class="subtitle">
|
||
{{item.userid_list.length}} {{$L('项目成员')}}
|
||
<em class="all">{{$L('已全选')}}</em>
|
||
<em class="some">{{$L('已选部分')}}</em>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<!-- 会员、会话 -->
|
||
<ul v-else>
|
||
<li
|
||
v-if="showSelectAll"
|
||
:class="selectClass('all')"
|
||
@click="onSelectAll">
|
||
<Icon class="user-modal-icon" :type="selectIcon('all')" />
|
||
<div class="user-modal-all">{{$L('全选')}}</div>
|
||
</li>
|
||
<li
|
||
v-for="item in lists"
|
||
:class="{
|
||
selected: selects.includes(item.userid),
|
||
disabled: isNoChoice(item.userid)
|
||
}"
|
||
@click="onSelectItem(item)">
|
||
<Icon v-if="selects.includes(item.userid)" class="user-modal-icon" type="ios-checkmark-circle" />
|
||
<Icon v-else-if="isNoChoice(item.userid)" class="user-modal-icon" type="ios-remove-circle-outline" />
|
||
<Icon v-else class="user-modal-icon" type="ios-radio-button-off" />
|
||
<div v-if="item.type=='group'" class="user-modal-avatar">
|
||
<EAvatar v-if="item.avatar" class="img-avatar" :src="item.avatar" :size="40"></EAvatar>
|
||
<i v-else-if="item.group_type=='department'" class="taskfont icon-avatar department"></i>
|
||
<i v-else-if="item.group_type=='project'" class="taskfont icon-avatar project"></i>
|
||
<i v-else-if="item.group_type=='task'" class="taskfont icon-avatar task"></i>
|
||
<i v-else-if="item.group_type=='okr'" class="taskfont icon-avatar task"></i>
|
||
<Icon v-else class="icon-avatar" type="ios-people" />
|
||
<div class="avatar-name">
|
||
<span>{{item.name}}</span>
|
||
</div>
|
||
</div>
|
||
<UserAvatar v-else class="user-modal-avatar" :userid="item.userid" :size="40" show-name/>
|
||
</li>
|
||
</ul>
|
||
</Scrollbar>
|
||
<!-- 空 -->
|
||
<div v-else class="user-modal-empty">
|
||
<Loading v-if="waitIng > 0"/>
|
||
<template v-else>
|
||
<div class="empty-icon"><Icon type="ios-cafe-outline" /></div>
|
||
<div class="empty-text">{{$L('暂无结果')}}</div>
|
||
</template>
|
||
</div>
|
||
|
||
<!-- 底部 -->
|
||
<template #footer>
|
||
<Button type="primary" :loading="submittIng > 0" @click="onSubmit">
|
||
{{$L('确定')}}
|
||
<template v-if="selects.length > 0">
|
||
({{selects.length}}<span v-if="multipleMax">/{{multipleMax}}</span>)
|
||
</template>
|
||
</Button>
|
||
</template>
|
||
</Modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import {mapState} from "vuex";
|
||
|
||
export default {
|
||
name: 'UserSelect',
|
||
props: {
|
||
value: {
|
||
type: [String, Number, Array],
|
||
default: () => {
|
||
return [];
|
||
}
|
||
},
|
||
// 不允许取消的列表
|
||
uncancelable: {
|
||
type: Array,
|
||
default: () => {
|
||
return [];
|
||
}
|
||
},
|
||
// 禁止选择的列表
|
||
disabledChoice: {
|
||
type: Array,
|
||
default: () => {
|
||
return [];
|
||
}
|
||
},
|
||
|
||
// 指定项目ID
|
||
projectId: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
// 指定非项目ID
|
||
noProjectId: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
// 指定会话ID
|
||
dialogId: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
|
||
// 是否显示机器人
|
||
showBot: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 是否显示禁用的
|
||
showDisable: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 最大选择数量
|
||
multipleMax: {
|
||
type: Number,
|
||
},
|
||
|
||
// 头像大小
|
||
avatarSize: {
|
||
type: Number,
|
||
default: 28
|
||
},
|
||
// 是否显示头像
|
||
avatarIcon: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
// 是否显示名称
|
||
avatarName: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 是否显示添加按钮(已选择为空时强制true)
|
||
addIcon: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
// 显示边框
|
||
border: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
|
||
// 弹窗标题
|
||
title: {
|
||
type: String,
|
||
},
|
||
// 搜索提示
|
||
placeholder: {
|
||
type: String,
|
||
},
|
||
|
||
// 显示全选项
|
||
showSelectAll: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
// 显示所有会话(会话返回格式:d:{会话ID},建议配合 module=true 一起使用)
|
||
showDialog: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
// 模块化(通过 api 方法调用)
|
||
module: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
|
||
// 是否禁用(禁止打开选择)
|
||
disabled: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
|
||
// 仅显示群组
|
||
onlyGroup: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
|
||
// 提交前的回调
|
||
beforeSubmit: Function
|
||
},
|
||
data() {
|
||
return {
|
||
switchItems: [
|
||
{key: 'recent', label: '最近'},
|
||
{key: 'contact', label: '通讯录'},
|
||
{key: 'project', label: '项目成员'},
|
||
],
|
||
switchActive: 'recent',
|
||
|
||
loadIng: 0, // 搜索框等待效果
|
||
waitIng: 0, // 页面等待效果
|
||
submittIng: 0, // 提交按钮等待效果
|
||
backspaceDelete: false, // 是否按删除键删除
|
||
|
||
values: [],
|
||
selects: [],
|
||
|
||
recents: [],
|
||
contacts: [],
|
||
projects: [],
|
||
|
||
showModal: false,
|
||
|
||
searchKey: null,
|
||
searchCache: [],
|
||
}
|
||
},
|
||
watch: {
|
||
value: {
|
||
handler(value) {
|
||
if (typeof value === 'number') {
|
||
this.$emit('input', value > 0 ? [value] : [])
|
||
} else if (typeof value === 'string') {
|
||
value = value.indexOf(',') > -1 ? value.split(',') : [value]
|
||
this.$emit('input', value.map(item => $A.runNum(item)).filter(item => item > 0))
|
||
}
|
||
this.values = value
|
||
},
|
||
immediate: true
|
||
},
|
||
|
||
isWhole: {
|
||
handler(value) {
|
||
if (value || this.onlyGroup) {
|
||
this.switchActive = 'recent'
|
||
} else {
|
||
this.switchActive = 'contact'
|
||
}
|
||
},
|
||
immediate: true
|
||
},
|
||
|
||
showModal(v) {
|
||
if (v) {
|
||
this.searchBefore()
|
||
this.upTitleWidth()
|
||
} else {
|
||
this.searchKey = ""
|
||
}
|
||
this.$emit("on-show-change", v)
|
||
//
|
||
$A.eeuiAppSetScrollDisabled(v && this.windowPortrait)
|
||
},
|
||
|
||
searchKey() {
|
||
this.searchBefore()
|
||
},
|
||
|
||
switchActive() {
|
||
this.searchBefore()
|
||
},
|
||
|
||
isFullscreen(value) {
|
||
if (value) {
|
||
this.upTitleWidth()
|
||
}
|
||
},
|
||
|
||
'selects.length'() {
|
||
this.upTitleWidth()
|
||
}
|
||
},
|
||
computed: {
|
||
...mapState([
|
||
'cacheDialogs',
|
||
]),
|
||
|
||
isFullscreen({windowWidth}) {
|
||
return windowWidth < 576
|
||
},
|
||
|
||
isWhole({projectId, noProjectId, dialogId, onlyGroup}) {
|
||
return projectId === 0 && noProjectId === 0 && dialogId === 0 && !onlyGroup
|
||
},
|
||
|
||
lists({switchActive, searchKey, recents, contacts, projects}) {
|
||
switch (switchActive) {
|
||
case 'recent':
|
||
if (searchKey) {
|
||
return recents.filter(item => $A.strExists(`${item.name} ${item.email} ${item.pinyin}`, searchKey))
|
||
}
|
||
return recents
|
||
|
||
case 'contact':
|
||
return contacts
|
||
|
||
case 'project':
|
||
return projects
|
||
}
|
||
return []
|
||
},
|
||
|
||
isSelectAll({lists, selects}) {
|
||
return lists.length > 0 && lists.filter(item => selects.includes(item.userid)).length === lists.length;
|
||
},
|
||
|
||
warpClass() {
|
||
return {
|
||
'select-module': this.module,
|
||
'select-border': this.border,
|
||
'select-whole': this.isWhole,
|
||
}
|
||
},
|
||
|
||
addStyle({avatarSize}) {
|
||
return {
|
||
width: avatarSize + 'px',
|
||
height: avatarSize + 'px',
|
||
}
|
||
},
|
||
|
||
localTitle({title}) {
|
||
if (title === undefined) {
|
||
return this.$L('选择会员')
|
||
} else {
|
||
return title;
|
||
}
|
||
},
|
||
|
||
localPlaceholder({placeholder}) {
|
||
if (placeholder === undefined) {
|
||
return this.$L('搜索')
|
||
} else {
|
||
return placeholder;
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
upTitleWidth() {
|
||
if (!this.isFullscreen) {
|
||
return
|
||
}
|
||
this.$nextTick(() => {
|
||
const headerTitle = this.$refs.headerTitle;
|
||
const headerSubmit = this.$refs.headerSubmit;
|
||
if (headerTitle && headerSubmit) {
|
||
headerTitle.style.width = (this.windowWidth - headerSubmit.clientWidth * 2) + 'px';
|
||
}
|
||
})
|
||
},
|
||
|
||
isUncancelable(value) {
|
||
if (this.uncancelable.length === 0) {
|
||
return false;
|
||
}
|
||
return this.uncancelable.includes(value);
|
||
},
|
||
|
||
isDisabled(userid) {
|
||
if (this.disabledChoice.length === 0) {
|
||
return false;
|
||
}
|
||
return this.disabledChoice.includes(userid)
|
||
},
|
||
|
||
isNoChoice(userid) {
|
||
return this.isUncancelable(userid) || this.isDisabled(userid)
|
||
},
|
||
|
||
formatSelect(list) {
|
||
return list.map(userid => {
|
||
if ($A.leftExists(userid, 'd:')) {
|
||
return this.recents.find(item => item.userid === userid)
|
||
}
|
||
return {
|
||
type: 'user',
|
||
userid,
|
||
}
|
||
})
|
||
},
|
||
|
||
selectIcon(value) {
|
||
if (value === 'all') {
|
||
return this.isSelectAll ? 'ios-checkmark-circle' : 'ios-radio-button-off';
|
||
}
|
||
if ($A.isArray(value) && value.length > 0) {
|
||
const len = value.filter(value => this.selects.includes(value)).length
|
||
if (len === value.length) {
|
||
return 'ios-checkmark-circle';
|
||
}
|
||
if (len > 0) {
|
||
return 'ios-remove-circle';
|
||
}
|
||
}
|
||
return 'ios-radio-button-off';
|
||
},
|
||
|
||
selectClass(value) {
|
||
switch (this.selectIcon(value)) {
|
||
case 'ios-checkmark-circle':
|
||
return 'selected';
|
||
case 'ios-remove-circle':
|
||
return 'somed';
|
||
}
|
||
return '';
|
||
},
|
||
|
||
searchBefore() {
|
||
if (!this.showModal) {
|
||
return
|
||
}
|
||
if (this.switchActive === 'recent') {
|
||
this.searchRecent()
|
||
} else if (this.switchActive === 'contact') {
|
||
this.searchContact()
|
||
} else if (this.switchActive === 'project') {
|
||
this.searchProject()
|
||
}
|
||
},
|
||
|
||
searchRecent() {
|
||
this.recents = this.cacheDialogs.filter(dialog => {
|
||
if (this.onlyGroup && dialog.type != 'group') {
|
||
return false
|
||
}
|
||
if (dialog.name === undefined || dialog.dialog_delete === 1) {
|
||
return false
|
||
}
|
||
if (!this.showBot && dialog.bot) {
|
||
return false
|
||
}
|
||
return this.showDialog || dialog.type === 'user'
|
||
}).sort((a, b) => {
|
||
if (a.top_at || b.top_at) {
|
||
return $A.sortDay(b.top_at, a.top_at);
|
||
}
|
||
if (a.todo_num > 0 || b.todo_num > 0) {
|
||
return $A.sortFloat(b.todo_num, a.todo_num);
|
||
}
|
||
return $A.sortDay(b.last_at, a.last_at);
|
||
}).map(({id, name, pinyin, email, type, group_type, avatar, dialog_user}) => {
|
||
return {
|
||
name,
|
||
pinyin,
|
||
email,
|
||
type,
|
||
group_type,
|
||
avatar,
|
||
userid: type === 'user' ? dialog_user.userid : `d:${id}`,
|
||
}
|
||
});
|
||
},
|
||
|
||
searchContact() {
|
||
const key = this.searchKey;
|
||
const cache = this.searchCache.find(item => item.type === 'contact' && item.key == key);
|
||
if (cache) {
|
||
this.contacts = cache.data
|
||
if (!cache.more) {
|
||
return
|
||
}
|
||
}
|
||
//
|
||
this.waitIng++
|
||
setTimeout(() => {
|
||
if (this.searchKey != key) {
|
||
this.waitIng--
|
||
return;
|
||
}
|
||
setTimeout(() => {
|
||
this.loadIng++
|
||
}, 300)
|
||
this.searchRequest(key, 1, () => {
|
||
this.loadIng--;
|
||
this.waitIng--;
|
||
})
|
||
}, this.searchCache.length > 0 ? 300 : 0)
|
||
},
|
||
|
||
searchRequest(key, page, cb) {
|
||
this.$store.dispatch("call", {
|
||
url: 'users/search',
|
||
data: {
|
||
keys: {
|
||
key,
|
||
project_id: this.projectId,
|
||
no_project_id: this.noProjectId,
|
||
dialog_id: this.dialogId,
|
||
bot: this.showBot && key ? 2 : 0,
|
||
disable: this.showDisable && key ? 2 : 0,
|
||
},
|
||
page,
|
||
pagesize: 50
|
||
},
|
||
}).then(({data}) => {
|
||
if (this.searchKey != key) {
|
||
cb()
|
||
return
|
||
}
|
||
const items = data.data.map(item => Object.assign(item, {type: 'user'}))
|
||
if (data.current_page > 1) {
|
||
items.unshift(...this.contacts)
|
||
}
|
||
this.contacts = items
|
||
//
|
||
const index = this.searchCache.findIndex(item => item.type === 'contact' && item.key == key);
|
||
const tmpData = {type: 'contact', key, data: items, time: $A.dayjs().unix(), more: data.current_page < data.last_page};
|
||
if (index > -1) {
|
||
this.searchCache.splice(index, 1, tmpData)
|
||
} else {
|
||
this.searchCache.push(tmpData)
|
||
}
|
||
//
|
||
if (!tmpData.more) {
|
||
cb()
|
||
return;
|
||
}
|
||
if (data.current_page % 5 === 0) {
|
||
$A.modalConfirm({
|
||
content: "数据已超过" + data.to + "条,是否继续加载?",
|
||
onOk: () => {
|
||
this.searchRequest(key, data.current_page + 1, cb)
|
||
},
|
||
onCancel: cb
|
||
});
|
||
} else {
|
||
this.searchRequest(key, data.current_page + 1, cb)
|
||
|
||
}
|
||
}).catch(({msg}) => {
|
||
if (page === 1) {
|
||
this.contacts = []
|
||
}
|
||
$A.messageWarning(msg)
|
||
cb()
|
||
});
|
||
},
|
||
|
||
searchProject() {
|
||
const key = this.searchKey;
|
||
const cache = this.searchCache.find(item => item.type === 'project' && item.key == key);
|
||
if (cache) {
|
||
this.projects = cache.data
|
||
if (!cache.more) {
|
||
return
|
||
}
|
||
}
|
||
//
|
||
this.waitIng++
|
||
setTimeout(() => {
|
||
if (this.searchKey != key) {
|
||
this.waitIng--
|
||
return;
|
||
}
|
||
setTimeout(() => {
|
||
this.loadIng++
|
||
}, 300)
|
||
this.$store.dispatch("call", {
|
||
url: 'project/lists',
|
||
data: {
|
||
type: 'team',
|
||
keys: {
|
||
name: key,
|
||
},
|
||
getuserid: 'yes',
|
||
getstatistics: 'no'
|
||
},
|
||
}).then(({data}) => {
|
||
if (this.searchKey != key) {
|
||
return
|
||
}
|
||
//
|
||
const items = data.data.map(item => Object.assign(item, {type: 'project'}))
|
||
this.projects = items
|
||
//
|
||
const index = this.searchCache.findIndex(item => item.type === 'project' && item.key == key);
|
||
const tmpData = {type: 'project', key, data: items, time: $A.dayjs().unix(), more: false};
|
||
if (index > -1) {
|
||
this.searchCache.splice(index, 1, tmpData)
|
||
} else {
|
||
this.searchCache.push(tmpData)
|
||
}
|
||
}).catch(({msg}) => {
|
||
this.projects = []
|
||
$A.messageWarning(msg)
|
||
}).finally(_ => {
|
||
this.loadIng--;
|
||
this.waitIng--;
|
||
});
|
||
}, this.searchCache.length > 0 ? 300 : 0)
|
||
},
|
||
|
||
onSelection() {
|
||
if (this.disabled) {
|
||
return
|
||
}
|
||
this.$nextTick(_ => {
|
||
this.selects = $A.cloneJSON(this.values)
|
||
this.showModal = true
|
||
})
|
||
},
|
||
|
||
onSelectAll() {
|
||
if (this.isSelectAll) {
|
||
this.selects = $A.cloneJSON(this.uncancelable)
|
||
return
|
||
}
|
||
this.lists.some(item => {
|
||
if (this.isDisabled(item.userid)) {
|
||
return false
|
||
}
|
||
if (this.multipleMax && this.selects.length >= this.multipleMax) {
|
||
$A.messageWarning("已超过最大选择数量")
|
||
return true
|
||
}
|
||
if (!this.selects.includes(item.userid)) {
|
||
this.selects.push(item.userid)
|
||
}
|
||
})
|
||
},
|
||
|
||
onSelectItem({userid}) {
|
||
if (this.selects.includes(userid)) {
|
||
if (this.isUncancelable(userid)) {
|
||
return
|
||
}
|
||
this.selects = this.selects.filter(value => value != userid)
|
||
} else {
|
||
if (this.isDisabled(userid)) {
|
||
return
|
||
}
|
||
if (this.multipleMax && this.selects.length >= this.multipleMax) {
|
||
if (this.multipleMax > 1) {
|
||
$A.messageWarning("已超过最大选择数量")
|
||
return
|
||
}
|
||
this.selects = []
|
||
}
|
||
this.selects.push(userid)
|
||
// 滚动到选中的位置
|
||
this.$nextTick(() => {
|
||
$A.scrollIntoViewIfNeeded(this.$refs.selected.querySelector(`li[data-id="${userid}"]`), true)
|
||
})
|
||
}
|
||
},
|
||
|
||
onSelectProject(userid_list) {
|
||
switch (this.selectIcon(userid_list)) {
|
||
case 'ios-checkmark-circle':
|
||
// 去除
|
||
const removeList = userid_list.filter(userid => !this.isUncancelable(userid))
|
||
if (removeList.length != userid_list.length) {
|
||
$A.messageWarning("部分成员禁止取消")
|
||
}
|
||
this.selects = this.selects.filter(userid => !removeList.includes(userid))
|
||
break;
|
||
default:
|
||
// 添加
|
||
const addList = userid_list.filter(userid => !this.isDisabled(userid))
|
||
if (addList.length != userid_list.length) {
|
||
$A.messageWarning("部分成员禁止选择")
|
||
}
|
||
this.selects = this.selects.concat(addList.filter(userid => !this.selects.includes(userid)))
|
||
// 超过最大数量
|
||
if (this.multipleMax && this.selects.length > this.multipleMax) {
|
||
$A.messageWarning("已超过最大选择数量")
|
||
this.selects = this.selects.slice(0, this.multipleMax)
|
||
}
|
||
break;
|
||
}
|
||
},
|
||
|
||
onRemoveItem(userid) {
|
||
if (this.isUncancelable(userid)) {
|
||
return
|
||
}
|
||
this.selects = this.selects.filter(value => value != userid)
|
||
},
|
||
|
||
onClickTitle() {
|
||
const $content = this.$refs.headerTitle;
|
||
const range = document.createRange();
|
||
range.setStart($content, 0);
|
||
range.setEnd($content, $content.childNodes.length || 0);
|
||
const rangeWidth = range.getBoundingClientRect().width;
|
||
if (Math.floor(rangeWidth) > Math.floor($content.offsetWidth)) {
|
||
$A.modalInfo({
|
||
title: this.$L("全标题"),
|
||
content: this.localTitle,
|
||
language: false,
|
||
})
|
||
}
|
||
},
|
||
|
||
onSubmit() {
|
||
if (this.submittIng > 0) {
|
||
return
|
||
}
|
||
const clone = $A.cloneJSON(this.values)
|
||
this.values = $A.cloneJSON(this.selects)
|
||
this.$emit('input', this.values)
|
||
this.$emit('on-submit', this.values)
|
||
|
||
if (!this.beforeSubmit) {
|
||
this.hide()
|
||
return
|
||
}
|
||
const before = this.beforeSubmit();
|
||
if (before && before.then) {
|
||
this.submittIng++
|
||
before.then(() => {
|
||
this.hide()
|
||
}).catch(() => {
|
||
this.values = clone
|
||
this.$emit('input', this.values)
|
||
}).finally(() => {
|
||
this.submittIng--
|
||
})
|
||
} else {
|
||
this.hide()
|
||
}
|
||
},
|
||
|
||
onKeydown(event) {
|
||
// 按下删除键时,判断是否符合删除条件
|
||
this.backspaceDelete = event.key === 'Backspace' && !this.searchKey && this.selects.length > 0;
|
||
},
|
||
|
||
onKeyup(event) {
|
||
if (event.key === 'Backspace' && this.backspaceDelete) {
|
||
// 从最后一个元素开始向前遍历,找到第一个不是不可取消的元素
|
||
for (let i = this.selects.length - 1; i >= 0; i--) {
|
||
const userid = this.selects[i];
|
||
if (!this.isUncancelable(userid)) {
|
||
this.onRemoveItem(userid);
|
||
break; // 找到并移除后立即退出循环
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
show() {
|
||
this.onSelection()
|
||
},
|
||
|
||
hide() {
|
||
this.showModal = false
|
||
},
|
||
}
|
||
};
|
||
</script>
|