perf: 添加全局搜索功能

This commit is contained in:
kuaifan 2025-03-02 23:43:18 +08:00
parent 027db7c0ec
commit 5e46b2cd1a
2 changed files with 67 additions and 50 deletions

View File

@ -34,18 +34,24 @@
<div v-else class="search-list"> <div v-else class="search-list">
<ul v-for="(items, type) in list" :key="type"> <ul v-for="(items, type) in list" :key="type">
<li class="item-label">{{typeLabel(type)}}</li> <li class="item-label">{{typeLabel(type)}}</li>
<li v-for="item in items.slice(0, 10)" :key="item.id" @click="onClick(item)"> <li v-for="item in items" :key="item.id" @click="onClick(item)">
<div class="item-icon"> <div class="item-icon">
<EAvatar v-if="item.icon[0]==='avatar'" class="img-avatar" :src="item.icon[1]" :size="38"/> <EAvatar v-if="item.icons[0]==='avatar'" class="img-avatar" :src="item.icons[1]" :size="38"/>
<i v-else-if="item.icon[0]==='department'" class="taskfont icon-avatar department">&#xe75c;</i> <i v-else-if="item.icons[0]==='department'" class="taskfont icon-avatar department">&#xe75c;</i>
<i v-else-if="item.icon[0]==='project'" class="taskfont icon-avatar project">&#xe6f9;</i> <i v-else-if="item.icons[0]==='project'" class="taskfont icon-avatar project">&#xe6f9;</i>
<i v-else-if="item.icon[0]==='task'" class="taskfont icon-avatar task">&#xe6f4;</i> <i v-else-if="item.icons[0]==='task'" class="taskfont icon-avatar task">&#xe6f4;</i>
<UserAvatarTip v-else-if="item.icon[0]==='user'" :userid="item.icon[1]" :size="38"/> <UserAvatar v-else-if="item.icons[0]==='user'" class="user-avatar" :userid="item.icons[1]" :size="38"/>
<Icon v-else-if="item.icon[0]==='people'" class="icon-avatar" type="ios-people" /> <Icon v-else-if="item.icons[0]==='people'" class="icon-avatar" type="ios-people" />
<Icon v-else class="icon-avatar" type="md-person" /> <Icon v-else class="icon-avatar" type="md-person" />
</div> </div>
<div class="item-content"> <div class="item-content">
<div class="item-title">{{item.title}}</div> <div class="item-title">
<div class="title-text">{{item.title}}</div>
<div
v-if="item.activity"
class="title-activity"
:title="item.activity">{{activityFormat(item.activity)}}</div>
</div>
<div class="item-desc"> <div class="item-desc">
<span <span
class="desc-tag no-dark-content" class="desc-tag no-dark-content"
@ -55,7 +61,6 @@
<span class="desc-text" v-html="item.desc"></span> <span class="desc-text" v-html="item.desc"></span>
</div> </div>
</div> </div>
<div v-if="item.action" class="item-action" :title="item.action">{{$A.timeFormat(item.action)}}</div>
</li> </li>
</ul> </ul>
</div> </div>
@ -66,12 +71,10 @@
<script> <script>
import {mapState} from "vuex"; import {mapState} from "vuex";
import UserAvatarTip from "./UserAvatar/tip.vue";
import emitter from "../store/events"; import emitter from "../store/events";
export default { export default {
name: 'SearchBox', name: 'SearchBox',
components: {UserAvatarTip},
props: { props: {
// //
}, },
@ -126,10 +129,13 @@ export default {
list({searchKey, searchResults}) { list({searchKey, searchResults}) {
const items = searchResults.filter(item => item.key === searchKey) const items = searchResults.filter(item => item.key === searchKey)
const groups = {} const groups = {}
items.forEach(item => { items.some(item => {
if (!groups[item.type]) { if (!groups[item.type]) {
groups[item.type] = [] groups[item.type] = []
} }
if (groups[item.type].length > 10) {
return true
}
groups[item.type].push(item) groups[item.type].push(item)
}) })
return groups return groups
@ -162,15 +168,16 @@ export default {
return type; return type;
}, },
within24Hours(date) { activityFormat(date) {
return ($A.dayjs(date).unix() - $A.dayjs().unix()) < 86400 const local = $A.daytz(),
}, time = $A.dayjs(date);
if (local.format("YYYY/MM/DD") === time.format("YYYY/MM/DD")) {
showProfessionDesc(dialog_user) { return time.format("HH:mm")
if (dialog_user && dialog_user.profession) {
return `[${dialog_user.profession}]`
} }
return '' if (local.year() === time.year()) {
return time.format("MM/DD")
}
return time.format("YYYY/MM/DD") || '';
}, },
onClick(item) { onClick(item) {
@ -205,6 +212,7 @@ export default {
pagesize: 10, pagesize: 10,
}, },
}).then(({data}) => { }).then(({data}) => {
const nowTime = $A.dayjs().unix()
const items = data.data.map(item => { const items = data.data.map(item => {
const tags = []; const tags = [];
if (item.complete_at) { if (item.complete_at) {
@ -215,24 +223,24 @@ export default {
} else if (item.overdue) { } else if (item.overdue) {
tags.push({ tags.push({
name: this.$L('超期'), name: this.$L('超期'),
style: 'background-color:red;color:#ddd', style: 'background-color:#f00;color:#ddd',
}) })
} else if (this.within24Hours(item.end_at)) { } else if ($A.dayjs(item.end_at).unix() - nowTime < 86400) {
tags.push({ tags.push({
name: this.$L('即将到期'), name: this.$L('即将到期'),
style: 'background-color:orange;color:#ddd', style: 'background-color:#f80;color:#ddd',
}) })
} }
return { return {
key, key,
type: 'task', type: 'task',
icon: ['task', null], icons: ['task', null],
tags, tags,
id: item.id, id: item.id,
title: item.name, title: item.name,
desc: item.desc, desc: item.desc,
action: item.end_at, activity: item.end_at,
rawData: item, rawData: item,
}; };
@ -261,11 +269,11 @@ export default {
}).then(({data}) => { }).then(({data}) => {
const items = data.data.map(item => { const items = data.data.map(item => {
let icon = 'person'; let icon = 'person';
let ival = null; let desc = null;
if (item.type == 'group') { if (item.type == 'group') {
if (item.avatar) { if (item.avatar) {
icon = 'avatar'; icon = 'avatar';
ival = item.avatar; desc = item.avatar;
} else if (item.group_type == 'department') { } else if (item.group_type == 'department') {
icon = 'department'; icon = 'department';
} else if (item.group_type == 'project') { } else if (item.group_type == 'project') {
@ -277,18 +285,18 @@ export default {
} }
} else if (item.dialog_user) { } else if (item.dialog_user) {
icon = 'user'; icon = 'user';
ival = item.dialog_user.userid desc = item.dialog_user.userid
} }
return { return {
key, key,
type: 'message', type: 'message',
icon: [icon, ival], icons: [icon, desc],
tags: [], tags: [],
id: item.id, id: item.id,
title: item.name, title: item.name,
desc: $A.getMsgSimpleDesc(item.last_msg) || this.showProfessionDesc(item.dialog_user), desc: $A.getMsgSimpleDesc(item.last_msg),
action: item.last_at, activity: item.last_at,
rawData: item, rawData: item,
}; };
@ -319,13 +327,13 @@ export default {
return { return {
key, key,
type: 'contact', type: 'contact',
icon: ['user', item.userid], icons: ['user', item.userid],
tags: [], tags: [],
id: item.userid, id: item.userid,
title: item.nickname, title: item.nickname,
desc: this.showProfessionDesc(item), desc: item?.profession || '',
action: item.line_at, activity: item.line_at,
rawData: item, rawData: item,
}; };

View File

@ -207,23 +207,36 @@
width: 0; width: 0;
margin-left: 12px; margin-left: 12px;
.item-title, .item-title {
display: flex;
align-items: center;
justify-content: space-between;
.title-text {
flex: 1;
width: 0;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.title-activity {
flex-shrink: 0;
padding-left: 24px;
color: rgba($primary-desc-color, 0.7);
}
}
.item-desc { .item-desc {
padding-top: 2px;
max-width: 100%;
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
}
.item-title {
font-weight: 500;
}
.item-desc {
padding-top: 2px;
max-width: 100%;
.desc-tag { .desc-tag {
padding: 2px 4px; padding: 2px 4px;
@ -236,15 +249,11 @@
} }
.desc-text { .desc-text {
opacity: 0.8; font-size: 13px;
color: rgba($primary-desc-color, 0.7);
} }
} }
} }
.item-action {
margin-left: 12px;
opacity: 0.8;
}
} }
} }
} }