no message

This commit is contained in:
kuaifan 2025-03-03 22:48:09 +08:00
parent f4e6fd060e
commit d73a152a36
5 changed files with 155 additions and 62 deletions

View File

@ -106,6 +106,7 @@ class FileController extends AbstractController
* *
* @apiParam {String} [link] 通过分享地址搜索https://t.hitosea.com/single/file/ODcwOCwzOSxpa0JBS2lmVQ== * @apiParam {String} [link] 通过分享地址搜索https://t.hitosea.com/single/file/ODcwOCwzOSxpa0JBS2lmVQ==
* @apiParam {String} [key] 关键词 * @apiParam {String} [key] 关键词
* @apiParam {Number} [take] 获取数量默认50最大100
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述) * @apiSuccess {String} msg 返回信息(错误描述)
@ -118,7 +119,7 @@ class FileController extends AbstractController
$link = trim(Request::input('link')); $link = trim(Request::input('link'));
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
$id = 0; $id = 0;
$take = 50; $take = Base::getPaginate(100, 50, 'take');
if (preg_match("/\/single\/file\/(.*?)$/i", $link, $match)) { if (preg_match("/\/single\/file\/(.*?)$/i", $link, $match)) {
$id = intval(FileLink::whereCode($match[1])->value('file_id')); $id = intval(FileLink::whereCode($match[1])->value('file_id'));
$take = 1; $take = 1;

View File

@ -60,7 +60,7 @@
"stylus-loader": "^7.1.0", "stylus-loader": "^7.1.0",
"tinymce": "^5.10.3", "tinymce": "^5.10.3",
"tui-calendar-hi": "^1.15.1-5", "tui-calendar-hi": "^1.15.1-5",
"view-design-hi": "^4.7.0-65", "view-design-hi": "^4.7.0-66",
"vite": "^2.9.15", "vite": "^2.9.15",
"vite-plugin-file-copy": "^1.0.0", "vite-plugin-file-copy": "^1.0.0",
"vite-plugin-require": "^1.1.10", "vite-plugin-require": "^1.1.10",

View File

@ -14,12 +14,24 @@
<Loading v-if="loadIng > 0"/> <Loading v-if="loadIng > 0"/>
<Icon v-else type="ios-search" /> <Icon v-else type="ios-search" />
</div> </div>
<Input ref="searchKey" v-model="searchKey" :placeholder="$L('请输入关键字')"/> <Input ref="searchKey" v-model="searchKey" :placeholder="$L('请输入关键字')" type="search" @on-enter="onEnter"/>
</div> </div>
<i class="taskfont search-close" @click="onHide">&#xe6e5;</i> <i class="taskfont search-close" @click="onHide">&#xe6e5;</i>
</div> </div>
<div class="search-body" @touchstart="onTouchstart"> <div class="search-body" @touchstart="onTouchstart">
<div class="search-tags">
<div
v-for="tag in tags"
:key="tag.type"
class="tag-item"
:class="{action: tag.type === action}"
@click="onTag(tag.type, $event)">
<i class="taskfont" v-html="tag.icon"></i>
<span>{{$L(tag.name)}}</span>
<i v-if="tag.type === action" class="taskfont tag-close">&#xe747;</i>
</div>
</div>
<template v-if="listLength === 0"> <template v-if="listLength === 0">
<div v-if="loadIng > 0 || !searchKey.trim()" class="search-empty"> <div v-if="loadIng > 0 || !searchKey.trim()" class="search-empty">
<i class="taskfont">&#xe60b;</i> <i class="taskfont">&#xe60b;</i>
@ -33,7 +45,7 @@
</template> </template>
<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 v-if="!action" class="item-label">{{typeLabel(type)}}</li>
<li v-for="item in items" :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">
<div v-if="item.icons[0]==='file'" :class="`no-dark-content file-icon ${item.icons[1]}`"></div> <div v-if="item.icons[0]==='file'" :class="`no-dark-content file-icon ${item.icons[1]}`"></div>
@ -92,6 +104,15 @@ export default {
searchTimer: null, searchTimer: null,
showModal: false, showModal: false,
tags: [
{type: 'task', name: '任务', icon: '&#xe6f4;'},
{type: 'project', name: '项目', icon: '&#xe6f9;'},
{type: 'message', name: '消息', icon: '&#xe6eb;'},
{type: 'contact', name: '联系人', icon: '&#xe6b2;'},
{type: 'file', name: '文件', icon: '&#xe6f3;'},
],
action: '',
} }
}, },
@ -104,26 +125,12 @@ export default {
}, },
watch: { watch: {
searchKey: { searchKey() {
handler: function () { this.preSearch()
if (!this.searchKey.trim()) { },
return;
} action() {
if (this.searchTimer) { this.preSearch()
clearTimeout(this.searchTimer)
this.searchTimer = null;
this.loadIng--;
}
this.loadIng++;
this.searchTimer = setTimeout(() => {
if (this.searchKey.trim()) {
this.onSearch()
}
this.searchTimer = null;
this.loadIng--;
}, 500)
},
immediate: true
}, },
showModal(v) { showModal(v) {
@ -137,22 +144,22 @@ export default {
'keyboardType' 'keyboardType'
]), ]),
list({searchKey, searchResults}) { list({searchKey, searchResults, action}) {
const items = searchResults.filter(item => item.key === searchKey) const items = searchResults.filter(item => item.key === searchKey && (!action || item.type === action))
const groups = {} const groups = {}
items.forEach(item => { items.forEach(item => {
if (!groups[item.type]) { if (!groups[item.type]) {
groups[item.type] = [] groups[item.type] = []
} }
if (groups[item.type].length < 10) { if (groups[item.type].length < 10 || action) {
groups[item.type].push(item) groups[item.type].push(item)
} }
}) })
return groups return groups
}, },
listLength({searchKey, searchResults}) { listLength({searchKey, searchResults, action}) {
const items = searchResults.filter(item => item.key === searchKey) const items = searchResults.filter(item => item.key === searchKey && (!action || item.type === action))
return items.length return items.length
}, },
@ -163,17 +170,9 @@ export default {
methods: { methods: {
typeLabel(type) { typeLabel(type) {
switch (type) { const tag = this.tags.find(item => item.type === type);
case 'task': if (tag) {
return this.$L('任务') return this.$L(tag.name);
case 'project':
return this.$L('项目')
case 'message':
return this.$L('消息')
case 'contact':
return this.$L('联系人')
case 'file':
return this.$L('文件')
} }
return type; return type;
}, },
@ -238,6 +237,15 @@ export default {
} }
}, },
onTag(type, e) {
this.action = this.action !== type ? type : '';
$A.scrollToView(e.target, {
block: 'nearest',
inline: 'nearest',
behavior: 'smooth'
})
},
onShow() { onShow() {
this.showModal = true this.showModal = true
this.$nextTick(() => { this.$nextTick(() => {
@ -258,15 +266,48 @@ export default {
this.showModal = false this.showModal = false
}, },
onSearch() { onEnter() {
this.searchTask(this.searchKey) this.preSearch();
this.searchProject(this.searchKey) $A.eeuiAppKeyboardHide();
this.searchMessage(this.searchKey)
this.searchContact(this.searchKey)
this.searchFile(this.searchKey)
}, },
pushResults(items) { preSearch() {
if (!this.searchKey.trim()) {
return;
}
if (this.searchTimer) {
clearTimeout(this.searchTimer)
this.searchTimer = null;
this.loadIng--;
}
this.loadIng++;
this.searchTimer = setTimeout(() => {
if (this.searchKey.trim()) {
this.onSearch()
}
this.searchTimer = null;
this.loadIng--;
}, 500)
},
onSearch() {
if (this.action) {
this.distSearch(this.action)
return;
}
this.tags.forEach(({type}) => this.distSearch(type))
},
distSearch(type) {
const func = this[`search${type.charAt(0).toUpperCase()}${type.slice(1)}`]
if (typeof func === 'function') {
func(this.searchKey)
return true
}
return false
},
echoSearch(items) {
items.forEach(item => { items.forEach(item => {
const index = this.searchResults.findIndex(({id, type}) => id === item.id && type === item.type) const index = this.searchResults.findIndex(({id, type}) => id === item.id && type === item.type)
if (index > -1) { if (index > -1) {
@ -284,7 +325,7 @@ export default {
data: { data: {
keys: {name: key}, keys: {name: key},
archived: 'all', archived: 'all',
pagesize: 10, pagesize: this.action ? 50 : 10,
}, },
}).then(({data}) => { }).then(({data}) => {
const nowTime = $A.dayjs().unix() const nowTime = $A.dayjs().unix()
@ -320,7 +361,7 @@ export default {
rawData: item, rawData: item,
}; };
}); });
this.pushResults(items) this.echoSearch(items)
}).finally(_ => { }).finally(_ => {
this.loadIng--; this.loadIng--;
}) })
@ -335,7 +376,7 @@ export default {
name: key name: key
}, },
archived: 'all', archived: 'all',
pagesize: 10, pagesize: this.action ? 50 : 10,
}, },
}).then(({data}) => { }).then(({data}) => {
const items = data.data.map(item => { const items = data.data.map(item => {
@ -366,7 +407,7 @@ export default {
rawData: item, rawData: item,
}; };
}) })
this.pushResults(items) this.echoSearch(items)
}).finally(_ => { }).finally(_ => {
this.loadIng--; this.loadIng--;
}) })
@ -378,7 +419,7 @@ export default {
url: 'dialog/msg/esearch', url: 'dialog/msg/esearch',
data: { data: {
key, key,
pagesize: 10, pagesize: this.action ? 50 : 10,
}, },
}).then(({data}) => { }).then(({data}) => {
const items = data.data.map(item => { const items = data.data.map(item => {
@ -415,7 +456,7 @@ export default {
rawData: item, rawData: item,
}; };
}) })
this.pushResults(items) this.echoSearch(items)
}).finally(_ => { }).finally(_ => {
this.loadIng--; this.loadIng--;
}) })
@ -427,7 +468,7 @@ export default {
url: 'users/search', url: 'users/search',
data: { data: {
keys: {key}, keys: {key},
pagesize: 10, pagesize: this.action ? 50 : 10,
}, },
}).then(({data}) => { }).then(({data}) => {
const items = data.map(item => { const items = data.map(item => {
@ -445,7 +486,7 @@ export default {
rawData: item, rawData: item,
}; };
}) })
this.pushResults(items) this.echoSearch(items)
}).finally(_ => { }).finally(_ => {
this.loadIng--; this.loadIng--;
}) })
@ -455,7 +496,10 @@ export default {
this.loadIng++; this.loadIng++;
this.$store.dispatch("call", { this.$store.dispatch("call", {
url: 'file/search', url: 'file/search',
data: {key}, data: {
key,
take: this.action ? 50 : 10,
},
}).then(({data}) => { }).then(({data}) => {
const items = data.map(item => { const items = data.map(item => {
const tags = []; const tags = [];
@ -479,7 +523,7 @@ export default {
rawData: item, rawData: item,
}; };
}) })
this.pushResults(items) this.echoSearch(items)
}).finally(_ => { }).finally(_ => {
this.loadIng--; this.loadIng--;
}) })

View File

@ -98,13 +98,52 @@
flex-direction: column; flex-direction: column;
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
.search-tags {
flex-shrink: 0;
display: flex;
gap: 12px;
overflow-x: auto;
overflow-y: hidden;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
padding: 16px 20px 0;
&::-webkit-scrollbar {
display: none;
}
.tag-item {
flex-shrink: 0;
border: 1px solid #d5d5d5;
border-radius: 8px;
padding: 3px 12px;
line-height: 24px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
cursor: pointer;
transition: all 0.2s ease;
.tag-close {
font-size: 13px;
}
&.action {
background-color: #8bcf70;
border-color: #8bcf70;
color: #fff;
}
}
}
.search-empty { .search-empty {
height: 248px; height: 268px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
padding: 24px; padding: 16px 24px 48px;
> i { > i {
font-size: 44px; font-size: 44px;
@ -128,11 +167,11 @@
.search-list { .search-list {
overflow: auto; overflow: auto;
max-height: calc(100vh - 255px); max-height: calc(100vh - 305px);
overscroll-behavior: contain; overscroll-behavior: contain;
@media (max-height: 900px) { @media (max-height: 900px) {
max-height: calc(100vh - 125px); max-height: calc(100vh - 175px);
} }
> ul { > ul {
@ -151,7 +190,7 @@
} }
&.item-label { &.item-label {
padding: 8px 10px; padding: 8px 12px;
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 9; z-index: 9;
@ -173,6 +212,7 @@
.file-icon { .file-icon {
display: flex; display: flex;
&:before { &:before {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

@ -635,6 +635,14 @@ body.dark-mode-reverse {
.search-body { .search-body {
border-top-color: #e9e9e9; border-top-color: #e9e9e9;
.search-tags {
.tag-item {
&.action {
color: #000;
}
}
}
.search-list { .search-list {
ul { ul {
> li { > li {