mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-19 14:18:10 +00:00
no message
This commit is contained in:
parent
f4e6fd060e
commit
d73a152a36
@ -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;
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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"></i>
|
<i class="taskfont search-close" @click="onHide"></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"></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"></i>
|
<i class="taskfont"></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: ''},
|
||||||
|
{type: 'project', name: '项目', icon: ''},
|
||||||
|
{type: 'message', name: '消息', icon: ''},
|
||||||
|
{type: 'contact', name: '联系人', icon: ''},
|
||||||
|
{type: 'file', name: '文件', icon: ''},
|
||||||
|
],
|
||||||
|
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--;
|
||||||
})
|
})
|
||||||
|
|||||||
50
resources/assets/sass/components/search-box.scss
vendored
50
resources/assets/sass/components/search-box.scss
vendored
@ -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%;
|
||||||
|
|||||||
8
resources/assets/sass/dark.scss
vendored
8
resources/assets/sass/dark.scss
vendored
@ -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 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user