mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-25 20:08:12 +00:00
feat: Enhance AIAssistant and SearchBox components with improved link handling and search functionality
- Updated AIAssistant to support parsing of additional message links in the format dootask://message/id1/id2. - Modified search methods in SearchBox to streamline API calls and remove AI search logic, improving performance and clarity. - Cleaned up unused AI search code and adjusted search result handling for better data presentation. - Updated documentation to reflect new link formats for tasks, projects, files, and messages.
This commit is contained in:
parent
1e94ce501e
commit
a52dc14369
@ -918,25 +918,28 @@ export default {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
// 解析 dootask:// 协议链接
|
// 解析 dootask:// 协议链接
|
||||||
// 格式: dootask://type/id 例如 dootask://task/123
|
// 格式: dootask://type/id 或 dootask://type/id1/id2 例如 dootask://task/123 或 dootask://message/789/1234
|
||||||
const match = href.match(/^dootask:\/\/(\w+)\/(\d+)$/);
|
const match = href.match(/^dootask:\/\/(\w+)\/(\d+)(?:\/(\d+))?$/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, type, id] = match;
|
const [, type, id, id2] = match;
|
||||||
const numId = parseInt(id, 10);
|
const numId = parseInt(id, 10);
|
||||||
|
const numId2 = id2 ? parseInt(id2, 10) : null;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'task':
|
case 'task':
|
||||||
this.$store.dispatch('openTask', {id: numId});
|
this.$store.dispatch('openTask', {id: (numId2 && numId2 > 0) ? numId2 : numId});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'project':
|
case 'project':
|
||||||
|
this.showModal = false;
|
||||||
this.goForward({name: 'manage-project', params: {projectId: numId}});
|
this.goForward({name: 'manage-project', params: {projectId: numId}});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'file':
|
case 'file':
|
||||||
|
this.showModal = false;
|
||||||
this.goForward({name: 'manage-file', params: {folderId: 0, fileId: null, shakeId: numId}});
|
this.goForward({name: 'manage-file', params: {folderId: 0, fileId: null, shakeId: numId}});
|
||||||
this.$store.state.fileShakeId = numId;
|
this.$store.state.fileShakeId = numId;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -949,6 +952,16 @@ export default {
|
|||||||
$A.modalError(msg || this.$L('打开会话失败'));
|
$A.modalError(msg || this.$L('打开会话失败'));
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'message':
|
||||||
|
this.$store.dispatch('openDialog', numId).then(() => {
|
||||||
|
if (numId2) {
|
||||||
|
this.$store.state.dialogSearchMsgId = numId2;
|
||||||
|
}
|
||||||
|
}).catch(({msg}) => {
|
||||||
|
$A.modalError(msg || this.$L('打开会话失败'));
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide">
|
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide">
|
||||||
<Input type="search" ref="searchKey" v-model="searchKey" :placeholder="$L('请输入关键字')"/>
|
<Input type="search" ref="searchKey" v-model="searchKey" :placeholder="$L('请输入关键字')"/>
|
||||||
</Form>
|
</Form>
|
||||||
<div v-if="aiSearchAvailable" class="search-ai" :class="{active: aiSearch}" @click="toggleAiSearch">
|
<div v-if="aiSearchAvailable" class="search-ai" @click="toggleAiSearch">
|
||||||
<i class="taskfont"></i>
|
<i class="taskfont"></i>
|
||||||
<span>{{ $L('AI 搜索') }}</span>
|
<span>{{ $L('AI 搜索') }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -91,7 +91,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState, mapGetters} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import emitter from "../store/events";
|
import emitter from "../store/events";
|
||||||
import transformEmojiToHtml from "../utils/emoji";
|
import transformEmojiToHtml from "../utils/emoji";
|
||||||
|
|
||||||
@ -120,8 +120,6 @@ export default {
|
|||||||
{type: 'file', name: '文件', icon: ''},
|
{type: 'file', name: '文件', icon: ''},
|
||||||
],
|
],
|
||||||
action: '',
|
action: '',
|
||||||
|
|
||||||
aiSearch: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -347,16 +345,7 @@ export default {
|
|||||||
|
|
||||||
searchTask(key) {
|
searchTask(key) {
|
||||||
this.loadIng++;
|
this.loadIng++;
|
||||||
// 如果开启了 AI 搜索,使用新的 AI 搜索接口
|
this.$store.dispatch("call", {
|
||||||
const useAiSearch = this.aiSearchAvailable && this.aiSearch;
|
|
||||||
const requestConfig = useAiSearch ? {
|
|
||||||
url: 'search/task',
|
|
||||||
data: {
|
|
||||||
key,
|
|
||||||
search_type: 'hybrid',
|
|
||||||
take: this.action ? 50 : 10,
|
|
||||||
},
|
|
||||||
} : {
|
|
||||||
url: 'project/task/lists',
|
url: 'project/task/lists',
|
||||||
data: {
|
data: {
|
||||||
keys: {name: key},
|
keys: {name: key},
|
||||||
@ -364,19 +353,10 @@ export default {
|
|||||||
scope: 'all_project',
|
scope: 'all_project',
|
||||||
pagesize: this.action ? 50 : 10,
|
pagesize: this.action ? 50 : 10,
|
||||||
},
|
},
|
||||||
};
|
}).then(({data}) => {
|
||||||
this.$store.dispatch("call", requestConfig).then(({data}) => {
|
|
||||||
const nowTime = $A.dayjs().unix()
|
const nowTime = $A.dayjs().unix()
|
||||||
const rawData = useAiSearch ? data : data.data;
|
const items = data.data.map(item => {
|
||||||
const items = rawData.map(item => {
|
|
||||||
const tags = [];
|
const tags = [];
|
||||||
// AI 搜索标记
|
|
||||||
if (useAiSearch && item.content_preview) {
|
|
||||||
tags.push({
|
|
||||||
name: 'AI',
|
|
||||||
style: 'background-color:#4F46E5',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (item.complete_at) {
|
if (item.complete_at) {
|
||||||
tags.push({
|
tags.push({
|
||||||
name: this.$L('已完成'),
|
name: this.$L('已完成'),
|
||||||
@ -407,7 +387,7 @@ export default {
|
|||||||
|
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.name,
|
title: item.name,
|
||||||
desc: item.content_preview ? this.truncateContent(item.content_preview) : item.desc,
|
desc: item.desc,
|
||||||
activity: item.end_at,
|
activity: item.end_at,
|
||||||
|
|
||||||
rawData: item,
|
rawData: item,
|
||||||
@ -421,16 +401,7 @@ export default {
|
|||||||
|
|
||||||
searchProject(key) {
|
searchProject(key) {
|
||||||
this.loadIng++;
|
this.loadIng++;
|
||||||
// 如果开启了 AI 搜索,使用新的 AI 搜索接口
|
this.$store.dispatch("call", {
|
||||||
const useAiSearch = this.aiSearchAvailable && this.aiSearch;
|
|
||||||
const requestConfig = useAiSearch ? {
|
|
||||||
url: 'search/project',
|
|
||||||
data: {
|
|
||||||
key,
|
|
||||||
search_type: 'hybrid',
|
|
||||||
take: this.action ? 50 : 10,
|
|
||||||
},
|
|
||||||
} : {
|
|
||||||
url: 'project/lists',
|
url: 'project/lists',
|
||||||
data: {
|
data: {
|
||||||
keys: {
|
keys: {
|
||||||
@ -439,18 +410,9 @@ export default {
|
|||||||
archived: 'all',
|
archived: 'all',
|
||||||
pagesize: this.action ? 50 : 10,
|
pagesize: this.action ? 50 : 10,
|
||||||
},
|
},
|
||||||
};
|
}).then(({data}) => {
|
||||||
this.$store.dispatch("call", requestConfig).then(({data}) => {
|
const items = data.data.map(item => {
|
||||||
const rawData = useAiSearch ? data : data.data;
|
|
||||||
const items = rawData.map(item => {
|
|
||||||
const tags = [];
|
const tags = [];
|
||||||
// AI 搜索标记
|
|
||||||
if (useAiSearch && item.desc_preview) {
|
|
||||||
tags.push({
|
|
||||||
name: 'AI',
|
|
||||||
style: 'background-color:#4F46E5',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (item.owner) {
|
if (item.owner) {
|
||||||
tags.push({
|
tags.push({
|
||||||
name: this.$L('负责人'),
|
name: this.$L('负责人'),
|
||||||
@ -471,7 +433,7 @@ export default {
|
|||||||
|
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.name,
|
title: item.name,
|
||||||
desc: item.desc_preview ? this.truncateContent(item.desc_preview) : (item.desc || ''),
|
desc: item.desc || '',
|
||||||
activity: item.updated_at,
|
activity: item.updated_at,
|
||||||
|
|
||||||
rawData: item,
|
rawData: item,
|
||||||
@ -535,43 +497,23 @@ export default {
|
|||||||
|
|
||||||
searchContact(key) {
|
searchContact(key) {
|
||||||
this.loadIng++;
|
this.loadIng++;
|
||||||
// 如果开启了 AI 搜索,使用新的 AI 搜索接口
|
this.$store.dispatch("call", {
|
||||||
const useAiSearch = this.aiSearchAvailable && this.aiSearch;
|
|
||||||
const requestConfig = useAiSearch ? {
|
|
||||||
url: 'search/contact',
|
|
||||||
data: {
|
|
||||||
key,
|
|
||||||
search_type: 'hybrid',
|
|
||||||
take: this.action ? 50 : 10,
|
|
||||||
},
|
|
||||||
} : {
|
|
||||||
url: 'users/search',
|
url: 'users/search',
|
||||||
data: {
|
data: {
|
||||||
keys: {key},
|
keys: {key},
|
||||||
pagesize: this.action ? 50 : 10,
|
pagesize: this.action ? 50 : 10,
|
||||||
},
|
},
|
||||||
};
|
}).then(({data}) => {
|
||||||
this.$store.dispatch("call", requestConfig).then(({data}) => {
|
|
||||||
const items = data.map(item => {
|
const items = data.map(item => {
|
||||||
const tags = [];
|
|
||||||
// AI 搜索标记
|
|
||||||
if (useAiSearch && item.introduction_preview) {
|
|
||||||
tags.push({
|
|
||||||
name: 'AI',
|
|
||||||
style: 'background-color:#4F46E5',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
type: 'contact',
|
type: 'contact',
|
||||||
icons: ['user', item.userid],
|
icons: ['user', item.userid],
|
||||||
tags,
|
tags: [],
|
||||||
|
|
||||||
id: item.userid,
|
id: item.userid,
|
||||||
title: item.nickname,
|
title: item.nickname,
|
||||||
desc: item.introduction_preview
|
desc: item.profession || '',
|
||||||
? this.truncateContent(item.introduction_preview)
|
|
||||||
: (item.profession || ''),
|
|
||||||
activity: item.line_at,
|
activity: item.line_at,
|
||||||
|
|
||||||
rawData: item,
|
rawData: item,
|
||||||
@ -585,23 +527,13 @@ export default {
|
|||||||
|
|
||||||
searchFile(key) {
|
searchFile(key) {
|
||||||
this.loadIng++;
|
this.loadIng++;
|
||||||
// 如果开启了 AI 搜索,使用统一的 AI 搜索接口
|
this.$store.dispatch("call", {
|
||||||
const useAiSearch = this.aiSearchAvailable && this.aiSearch;
|
|
||||||
const requestConfig = useAiSearch ? {
|
|
||||||
url: 'search/file',
|
|
||||||
data: {
|
|
||||||
key,
|
|
||||||
search_type: 'hybrid',
|
|
||||||
take: this.action ? 50 : 10,
|
|
||||||
},
|
|
||||||
} : {
|
|
||||||
url: 'file/search',
|
url: 'file/search',
|
||||||
data: {
|
data: {
|
||||||
key,
|
key,
|
||||||
take: this.action ? 50 : 10,
|
take: this.action ? 50 : 10,
|
||||||
},
|
},
|
||||||
};
|
}).then(({data}) => {
|
||||||
this.$store.dispatch("call", requestConfig).then(({data}) => {
|
|
||||||
const items = data.map(item => {
|
const items = data.map(item => {
|
||||||
const tags = [];
|
const tags = [];
|
||||||
if (item.share) {
|
if (item.share) {
|
||||||
@ -610,13 +542,6 @@ export default {
|
|||||||
style: 'background-color:#0bc037',
|
style: 'background-color:#0bc037',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// AI 搜索标记
|
|
||||||
if (useAiSearch && item.content_preview) {
|
|
||||||
tags.push({
|
|
||||||
name: 'AI',
|
|
||||||
style: 'background-color:#4F46E5',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
type: 'file',
|
type: 'file',
|
||||||
@ -625,9 +550,7 @@ export default {
|
|||||||
|
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.name,
|
title: item.name,
|
||||||
desc: item.content_preview
|
desc: item.type === 'folder' ? '' : $A.bytesToSize(item.size),
|
||||||
? this.truncateContent(item.content_preview)
|
|
||||||
: (item.type === 'folder' ? '' : $A.bytesToSize(item.size)),
|
|
||||||
activity: item.updated_at,
|
activity: item.updated_at,
|
||||||
|
|
||||||
rawData: item,
|
rawData: item,
|
||||||
@ -639,13 +562,6 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
truncateContent(content) {
|
|
||||||
if (!content) return '';
|
|
||||||
const maxLen = 100;
|
|
||||||
const text = content.replace(/\s+/g, ' ').trim();
|
|
||||||
return text.length > maxLen ? text.substring(0, maxLen) + '...' : text;
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleAiSearch() {
|
toggleAiSearch() {
|
||||||
const keyword = this.searchKey.trim();
|
const keyword = this.searchKey.trim();
|
||||||
emitter.emit('openAIAssistant', {
|
emitter.emit('openAIAssistant', {
|
||||||
@ -675,14 +591,17 @@ export default {
|
|||||||
'',
|
'',
|
||||||
'## 链接格式要求',
|
'## 链接格式要求',
|
||||||
'在返回结果时,请使用以下格式创建可点击的链接:',
|
'在返回结果时,请使用以下格式创建可点击的链接:',
|
||||||
'- 任务: [任务名称](dootask://task/任务ID)',
|
'- 任务: [任务名称](dootask://task/任务ID/主任务ID)',
|
||||||
'- 项目: [项目名称](dootask://project/项目ID)',
|
'- 项目: [项目名称](dootask://project/项目ID)',
|
||||||
'- 文件: [文件名称](dootask://file/文件ID)',
|
'- 文件: [文件名称](dootask://file/文件ID)',
|
||||||
'- 联系人: [联系人名称](dootask://contact/用户ID)',
|
'- 联系人: [联系人名称](dootask://contact/用户ID)',
|
||||||
|
'- 消息: [消息内容预览](dootask://message/对话ID/消息ID)',
|
||||||
'',
|
'',
|
||||||
'示例:',
|
'示例:',
|
||||||
'- [完成项目报告](dootask://task/123)',
|
'- [完成项目报告](dootask://task/123/0)(主任务)',
|
||||||
|
'- [编写测试用例](dootask://task/456/123)(子任务)',
|
||||||
'- [产品开发项目](dootask://project/456)',
|
'- [产品开发项目](dootask://project/456)',
|
||||||
|
'- [关于报销的讨论](dootask://message/789/1234)',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const prepared = [
|
const prepared = [
|
||||||
|
|||||||
@ -106,11 +106,6 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: #e8e8e8;
|
background-color: #e8e8e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
resources/assets/sass/dark.scss
vendored
9
resources/assets/sass/dark.scss
vendored
@ -715,15 +715,6 @@ body.dark-mode-reverse {
|
|||||||
.ivu-modal {
|
.ivu-modal {
|
||||||
.ivu-modal-content {
|
.ivu-modal-content {
|
||||||
.ivu-modal-body {
|
.ivu-modal-body {
|
||||||
.search-header {
|
|
||||||
.search-input {
|
|
||||||
.search-ai {
|
|
||||||
&.active {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.search-body {
|
.search-body {
|
||||||
border-top-color: #e9e9e9;
|
border-top-color: #e9e9e9;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user