mirror of
https://github.com/kuaifan/dootask.git
synced 2026-09-11 22:49:11 +00:00
feat(app): support hiding AI interfaces
This commit is contained in:
parent
9dfcdc7b07
commit
b05b0874f8
@ -156,6 +156,7 @@ class SystemController extends AbstractController
|
|||||||
$setting['unclaimed_task_reminder_time'] = $setting['unclaimed_task_reminder_time'] ?: '';
|
$setting['unclaimed_task_reminder_time'] = $setting['unclaimed_task_reminder_time'] ?: '';
|
||||||
$setting['task_ai_auto_analyze'] = $setting['task_ai_auto_analyze'] ?: 'open';
|
$setting['task_ai_auto_analyze'] = $setting['task_ai_auto_analyze'] ?: 'open';
|
||||||
$setting['department_owner_project_view'] = $setting['department_owner_project_view'] ?: 'open';
|
$setting['department_owner_project_view'] = $setting['department_owner_project_view'] ?: 'open';
|
||||||
|
$setting['app_ai_hidden'] = config('dootask.app_ai_hidden');
|
||||||
$setting['server_timezone'] = config('app.timezone');
|
$setting['server_timezone'] = config('app.timezone');
|
||||||
$setting['server_version'] = Base::getVersion();
|
$setting['server_version'] = Base::getVersion();
|
||||||
// 指定人员名单仅管理员可见
|
// 指定人员名单仅管理员可见
|
||||||
|
|||||||
@ -8,6 +8,9 @@ return [
|
|||||||
// 许可证显示开关:设为 'hidden' 时隐藏系统许可证信息(Doo::license)
|
// 许可证显示开关:设为 'hidden' 时隐藏系统许可证信息(Doo::license)
|
||||||
'system_license' => env('SYSTEM_LICENSE'),
|
'system_license' => env('SYSTEM_LICENSE'),
|
||||||
|
|
||||||
|
// 移动 APP AI 界面开关:设为 true 时仅在移动 APP 隐藏 AI 相关界面
|
||||||
|
'app_ai_hidden' => filter_var(env('APP_AI_HIDDEN', false), FILTER_VALIDATE_BOOLEAN),
|
||||||
|
|
||||||
// 演示账号:登录页展示的演示账号(SystemController::demo)
|
// 演示账号:登录页展示的演示账号(SystemController::demo)
|
||||||
'demo_account' => env('DEMO_ACCOUNT'),
|
'demo_account' => env('DEMO_ACCOUNT'),
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,8 @@ negative:
|
|||||||
- 移动端缺失的复杂功能不会硬塞,大屏复杂操作仍建议在桌面端完成
|
- 移动端缺失的复杂功能不会硬塞,大屏复杂操作仍建议在桌面端完成
|
||||||
- 桌面端独有的能力(截图、全局快捷键、托盘)由原生 OS 集成,移动端无对应概念
|
- 桌面端独有的能力(截图、全局快捷键、托盘)由原生 OS 集成,移动端无对应概念
|
||||||
- 微应用 / 插件部分能在移动端打开(走 WebView),但触屏不一定可用
|
- 微应用 / 插件部分能在移动端打开(走 WebView),但触屏不一定可用
|
||||||
last_verified: v1.7.90
|
- 部署环境可通过 APP_AI_HIDDEN=true 隐藏移动 APP 的 AI 界面,但不会关闭 Web、Electron 或服务端 AI 接口
|
||||||
|
last_verified: v1.9.18
|
||||||
---
|
---
|
||||||
|
|
||||||
# 移动端与桌面端功能差异
|
# 移动端与桌面端功能差异
|
||||||
@ -31,7 +32,7 @@ last_verified: v1.7.90
|
|||||||
- 项目(成员、视图基本浏览)
|
- 项目(成员、视图基本浏览)
|
||||||
- 文件(上传、下载、预览)
|
- 文件(上传、下载、预览)
|
||||||
- 通知与日程
|
- 通知与日程
|
||||||
- AI 助手(基础对话)
|
- AI 助手(基础对话;部署环境未隐藏移动 APP AI 界面时)
|
||||||
|
|
||||||
## 移动端独有
|
## 移动端独有
|
||||||
- 底部 Tabbar 原生导航
|
- 底部 Tabbar 原生导航
|
||||||
@ -61,6 +62,9 @@ last_verified: v1.7.90
|
|||||||
| 报表 / 仪表盘 | 完整图表 + 编辑 | 仅查看 |
|
| 报表 / 仪表盘 | 完整图表 + 编辑 | 仅查看 |
|
||||||
| 会议 | 创建 / 主持 / 屏幕共享 | 主要参会,部分高级功能受限 |
|
| 会议 | 创建 / 主持 / 屏幕共享 | 主要参会,部分高级功能受限 |
|
||||||
|
|
||||||
|
## AI 界面部署开关
|
||||||
|
部署管理员可设置 `APP_AI_HIDDEN=true`,仅在 iOS / Android APP 隐藏 AI 助手、AI 微应用、AI 生成与分析入口,以及邮箱符合 `ai-*@bot.system` 的 AI 机器人单聊入口。任务、项目或普通群聊中已有的 AI 消息仍会显示并正常通知;Web 和 Electron 客户端不受影响,该配置也不会禁用服务端 AI 接口或删除会话、消息。
|
||||||
|
|
||||||
## 选哪端做什么
|
## 选哪端做什么
|
||||||
- **创建复杂任务 / 编辑长文档** → 桌面端
|
- **创建复杂任务 / 编辑长文档** → 桌面端
|
||||||
- **快速回消息 / 收推送 / 移动审批** → 移动端
|
- **快速回消息 / 收推送 / 移动审批** → 移动端
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
<UserDetail/>
|
<UserDetail/>
|
||||||
|
|
||||||
<!--AI 助理-->
|
<!--AI 助理-->
|
||||||
<AIAssistant/>
|
<AIAssistant v-if="aiVisible"/>
|
||||||
|
|
||||||
<!--返回效果-->
|
<!--返回效果-->
|
||||||
<MobileBack v-if="isFirstPage"/>
|
<MobileBack v-if="isFirstPage"/>
|
||||||
@ -100,7 +100,7 @@ import MobileNotification from "./components/Mobile/Notification.vue";
|
|||||||
import MobileBack from "./components/Mobile/Back.vue";
|
import MobileBack from "./components/Mobile/Back.vue";
|
||||||
import DropdownMenu from "./components/DropdownMenu";
|
import DropdownMenu from "./components/DropdownMenu";
|
||||||
import {ctrlPressed} from "./mixins/ctrlPressed";
|
import {ctrlPressed} from "./mixins/ctrlPressed";
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import emitter from "./store/events";
|
import emitter from "./store/events";
|
||||||
import AIAssistant from "./components/AIAssistant";
|
import AIAssistant from "./components/AIAssistant";
|
||||||
import UserDetail from "./pages/manage/components/UserDetail.vue";
|
import UserDetail from "./pages/manage/components/UserDetail.vue";
|
||||||
@ -152,6 +152,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
...mapState(['ws', 'themeConf', 'windowOrientation', 'safeAreaSize', 'isFirstPage', 'mobileTabbar', 'themeName']),
|
...mapState(['ws', 'themeConf', 'windowOrientation', 'safeAreaSize', 'isFirstPage', 'mobileTabbar', 'themeName']),
|
||||||
|
|
||||||
statusColor({routeName, windowLandscape}) {
|
statusColor({routeName, windowLandscape}) {
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapGetters} from "vuex";
|
||||||
import emitter from "../../store/events";
|
import emitter from "../../store/events";
|
||||||
import {createOperationModule} from "./operation-module";
|
import {createOperationModule} from "./operation-module";
|
||||||
import {loadFloatButtonVisible} from "./float-button-preference";
|
import {loadFloatButtonVisible} from "./float-button-preference";
|
||||||
@ -61,14 +61,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['microAppsIds']),
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
aiInstalled() {
|
|
||||||
return this.microAppsIds?.includes('ai');
|
|
||||||
},
|
|
||||||
|
|
||||||
visible() {
|
visible() {
|
||||||
return this.aiInstalled &&
|
return this.aiVisible &&
|
||||||
this.userId > 0 &&
|
this.userId > 0 &&
|
||||||
this.positionLoaded &&
|
this.positionLoaded &&
|
||||||
this.visibilityLoaded &&
|
this.visibilityLoaded &&
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters, mapState} from "vuex";
|
import {mapGetters} from "vuex";
|
||||||
import NetworkException from "../NetworkException";
|
import NetworkException from "../NetworkException";
|
||||||
import emitter from "../../store/events";
|
import emitter from "../../store/events";
|
||||||
|
|
||||||
@ -55,8 +55,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['cacheDialogs']),
|
...mapGetters(['dashboardTask', 'visibleDialogs']),
|
||||||
...mapGetters(['dashboardTask']),
|
|
||||||
|
|
||||||
// 父『应用』入口聚合角标(规则收敛在 appBadges 模块 getter)
|
// 父『应用』入口聚合角标(规则收敛在 appBadges 模块 getter)
|
||||||
...mapGetters('appBadges', {
|
...mapGetters('appBadges', {
|
||||||
@ -71,7 +70,7 @@ export default {
|
|||||||
msgUnreadMention() {
|
msgUnreadMention() {
|
||||||
let num = 0; // 未读
|
let num = 0; // 未读
|
||||||
let mention = 0; // 提及
|
let mention = 0; // 提及
|
||||||
this.cacheDialogs.some(dialog => {
|
this.visibleDialogs.some(dialog => {
|
||||||
num += $A.getDialogUnread(dialog, false);
|
num += $A.getDialogUnread(dialog, false);
|
||||||
mention += $A.getDialogMention(dialog);
|
mention += $A.getDialogMention(dialog);
|
||||||
})
|
})
|
||||||
@ -109,7 +108,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
msgAllUnread() {
|
msgAllUnread() {
|
||||||
let num = 0;
|
let num = 0;
|
||||||
this.cacheDialogs.some(dialog => {
|
this.visibleDialogs.some(dialog => {
|
||||||
num += $A.getDialogNum(dialog);
|
num += $A.getDialogNum(dialog);
|
||||||
})
|
})
|
||||||
return num;
|
return num;
|
||||||
@ -120,7 +119,7 @@ export default {
|
|||||||
* @returns {string|null}
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
msgTodoTotal() {
|
msgTodoTotal() {
|
||||||
let todoNum = this.cacheDialogs.reduce((total, current) => total + (current.todo_num || 0), 0)
|
let todoNum = this.visibleDialogs.reduce((total, current) => total + (current.todo_num || 0), 0)
|
||||||
if (todoNum > 0) {
|
if (todoNum > 0) {
|
||||||
if (todoNum > 999) {
|
if (todoNum > 999) {
|
||||||
todoNum = "999+"
|
todoNum = "999+"
|
||||||
|
|||||||
@ -91,7 +91,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import emitter from "../store/events";
|
import emitter from "../store/events";
|
||||||
import transformEmojiToHtml from "../utils/emoji";
|
import transformEmojiToHtml from "../utils/emoji";
|
||||||
import {SEARCH_AI_SYSTEM_PROMPT, withLanguagePreferencePrompt} from "../utils/ai";
|
import {SEARCH_AI_SYSTEM_PROMPT, withLanguagePreferencePrompt} from "../utils/ai";
|
||||||
@ -147,6 +147,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['aiVisible', 'appAiHidden']),
|
||||||
|
|
||||||
...mapState([
|
...mapState([
|
||||||
'themeName',
|
'themeName',
|
||||||
'keyboardShow',
|
'keyboardShow',
|
||||||
@ -156,7 +158,7 @@ export default {
|
|||||||
aiSearchAvailable() {
|
aiSearchAvailable() {
|
||||||
return this.microAppsIds
|
return this.microAppsIds
|
||||||
&& this.microAppsIds.includes('search')
|
&& this.microAppsIds.includes('search')
|
||||||
&& this.microAppsIds.includes('ai')
|
&& this.aiVisible
|
||||||
},
|
},
|
||||||
|
|
||||||
isFullscreen({windowWidth}) {
|
isFullscreen({windowWidth}) {
|
||||||
@ -164,7 +166,18 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
items({searchKey, searchResults, action}) {
|
items({searchKey, searchResults, action}) {
|
||||||
return searchResults.filter(item => item.key === searchKey && (!action || item.type === action))
|
return searchResults.filter(item => {
|
||||||
|
if (item.key !== searchKey || (action && item.type !== action)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!this.appAiHidden) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (item.type === 'message') {
|
||||||
|
return !$A.isAiBotDialog(item.rawData)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
total() {
|
total() {
|
||||||
|
|||||||
@ -234,6 +234,11 @@ export default {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
// 是否隐藏 AI 机器人
|
||||||
|
hideAiBot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
// 是否显示禁用的
|
// 是否显示禁用的
|
||||||
showDisable: {
|
showDisable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -403,9 +408,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState(['cacheDialogs']),
|
||||||
'cacheDialogs',
|
|
||||||
]),
|
|
||||||
|
|
||||||
isFullscreen({windowWidth}) {
|
isFullscreen({windowWidth}) {
|
||||||
return windowWidth < 576
|
return windowWidth < 576
|
||||||
@ -424,7 +427,7 @@ export default {
|
|||||||
return recents
|
return recents
|
||||||
|
|
||||||
case 'contact':
|
case 'contact':
|
||||||
return contacts
|
return this.hideAiBot ? contacts.filter(item => !$A.isAiBotUser(item)) : contacts
|
||||||
|
|
||||||
case 'project':
|
case 'project':
|
||||||
return projects
|
return projects
|
||||||
@ -595,6 +598,9 @@ export default {
|
|||||||
|
|
||||||
searchRecent() {
|
searchRecent() {
|
||||||
this.recents = this.cacheDialogs.filter(dialog => {
|
this.recents = this.cacheDialogs.filter(dialog => {
|
||||||
|
if (this.hideAiBot && $A.isAiBotDialog(dialog)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if (this.onlyGroup && dialog.type != 'group') {
|
if (this.onlyGroup && dialog.type != 'group') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
18
resources/assets/js/functions/web.js
vendored
18
resources/assets/js/functions/web.js
vendored
@ -213,6 +213,24 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
|
|||||||
return tags;
|
return tags;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为 AI 机器人账号
|
||||||
|
* @param user
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isAiBotUser(user) {
|
||||||
|
return !!user?.bot && /^ai-[^@]+@bot\.system$/.test(user.email || '')
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为 AI 机器人单聊
|
||||||
|
* @param dialog
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isAiBotDialog(dialog) {
|
||||||
|
return dialog?.type === 'user' && this.isAiBotUser(dialog)
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对话完成
|
* 对话完成
|
||||||
* @param dialog
|
* @param dialog
|
||||||
|
|||||||
@ -272,7 +272,7 @@
|
|||||||
<Icon type="ios-arrow-down"></Icon>
|
<Icon type="ios-arrow-down"></Icon>
|
||||||
</Button>
|
</Button>
|
||||||
<DropdownMenu slot="list">
|
<DropdownMenu slot="list">
|
||||||
<DropdownItem v-if="aiInstalled" name="aiAssistant">{{$L('AI 助手')}} ({{mateName}}+I)</DropdownItem>
|
<DropdownItem v-if="aiVisible" name="aiAssistant">{{$L('AI 助手')}} ({{mateName}}+I)</DropdownItem>
|
||||||
<DropdownItem name="task">{{$L('新建任务')}} ({{mateName}}+K)</DropdownItem>
|
<DropdownItem name="task">{{$L('新建任务')}} ({{mateName}}+K)</DropdownItem>
|
||||||
<DropdownItem name="project">{{$L('新建项目')}} ({{mateName}}+B)</DropdownItem>
|
<DropdownItem name="project">{{$L('新建项目')}} ({{mateName}}+B)</DropdownItem>
|
||||||
<DropdownItem name="group">{{$L('创建群组')}} ({{mateName}}+U)</DropdownItem>
|
<DropdownItem name="group">{{$L('创建群组')}} ({{mateName}}+U)</DropdownItem>
|
||||||
@ -313,6 +313,7 @@
|
|||||||
<div class="page-manage-project-ai-wrapper">
|
<div class="page-manage-project-ai-wrapper">
|
||||||
<Input ref="projectName" type="text" v-model="addData.name"></Input>
|
<Input ref="projectName" type="text" v-model="addData.name"></Input>
|
||||||
<div
|
<div
|
||||||
|
v-if="aiVisible"
|
||||||
class="project-ai-button"
|
class="project-ai-button"
|
||||||
type="text"
|
type="text"
|
||||||
@click="onProjectAI">
|
@click="onProjectAI">
|
||||||
@ -651,11 +652,10 @@ export default {
|
|||||||
'departmentOwnerProjectsRefreshing',
|
'departmentOwnerProjectsRefreshing',
|
||||||
'departmentOwnerProjectViewEnabled',
|
'departmentOwnerProjectViewEnabled',
|
||||||
|
|
||||||
'mcpServerStatus',
|
'mcpServerStatus'
|
||||||
'microAppsIds'
|
|
||||||
]),
|
]),
|
||||||
|
|
||||||
...mapGetters(['dashboardTask', "filterMicroAppsMenusMain"]),
|
...mapGetters(['aiVisible', 'dashboardTask', "filterMicroAppsMenusMain", 'visibleDialogs']),
|
||||||
|
|
||||||
// 父『应用』入口聚合角标(规则收敛在 appBadges 模块 getter)
|
// 父『应用』入口聚合角标(规则收敛在 appBadges 模块 getter)
|
||||||
...mapGetters('appBadges', {
|
...mapGetters('appBadges', {
|
||||||
@ -663,10 +663,6 @@ export default {
|
|||||||
applicationBadgeDot: 'applicationDot',
|
applicationBadgeDot: 'applicationDot',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
aiInstalled() {
|
|
||||||
return this.microAppsIds?.includes('ai');
|
|
||||||
},
|
|
||||||
|
|
||||||
departmentOwnerViewAvailable() {
|
departmentOwnerViewAvailable() {
|
||||||
return this.systemConfig.department_owner_project_view === 'open' && (this.userInfo.managed_departments || []).length > 0;
|
return this.systemConfig.department_owner_project_view === 'open' && (this.userInfo.managed_departments || []).length > 0;
|
||||||
},
|
},
|
||||||
@ -701,7 +697,7 @@ export default {
|
|||||||
msgUnreadMention() {
|
msgUnreadMention() {
|
||||||
let num = 0; // 未读
|
let num = 0; // 未读
|
||||||
let mention = 0; // 提及
|
let mention = 0; // 提及
|
||||||
this.cacheDialogs.some(dialog => {
|
this.visibleDialogs.some(dialog => {
|
||||||
num += $A.getDialogUnread(dialog, false);
|
num += $A.getDialogUnread(dialog, false);
|
||||||
mention += $A.getDialogMention(dialog);
|
mention += $A.getDialogMention(dialog);
|
||||||
})
|
})
|
||||||
@ -739,7 +735,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
msgAllUnread() {
|
msgAllUnread() {
|
||||||
let num = 0;
|
let num = 0;
|
||||||
this.cacheDialogs.some(dialog => {
|
this.visibleDialogs.some(dialog => {
|
||||||
num += $A.getDialogNum(dialog);
|
num += $A.getDialogNum(dialog);
|
||||||
})
|
})
|
||||||
return num;
|
return num;
|
||||||
@ -750,7 +746,7 @@ export default {
|
|||||||
* @returns {string|null}
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
msgTodoTotal() {
|
msgTodoTotal() {
|
||||||
let todoNum = this.cacheDialogs.reduce((total, current) => total + (current.todo_num || 0), 0)
|
let todoNum = this.visibleDialogs.reduce((total, current) => total + (current.todo_num || 0), 0)
|
||||||
if (todoNum > 0) {
|
if (todoNum > 0) {
|
||||||
if (todoNum > 99) {
|
if (todoNum > 99) {
|
||||||
todoNum = "99+"
|
todoNum = "99+"
|
||||||
@ -1486,7 +1482,7 @@ export default {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 73: // I - AI助手
|
case 73: // I - AI助手
|
||||||
if (this.aiInstalled) {
|
if (this.aiVisible) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.onOpenAIAssistant();
|
this.onOpenAIAssistant();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,7 +152,7 @@
|
|||||||
<em>{{$L('上传文件')}}</em>
|
<em>{{$L('上传文件')}}</em>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="dialogId > 0" class="chat-input-popover-item" @click="onToolbar('ai')">
|
<div v-if="dialogId > 0 && aiVisible" class="chat-input-popover-item" @click="onToolbar('ai')">
|
||||||
<i class="taskfont"></i>
|
<i class="taskfont"></i>
|
||||||
<em>{{$L('AI 生成')}}</em>
|
<em>{{$L('AI 生成')}}</em>
|
||||||
</div>
|
</div>
|
||||||
@ -606,7 +606,7 @@ export default {
|
|||||||
'viewportHeight',
|
'viewportHeight',
|
||||||
]),
|
]),
|
||||||
|
|
||||||
...mapGetters(['getDialogDraft', 'getDialogQuote']),
|
...mapGetters(['aiVisible', 'getDialogDraft', 'getDialogQuote']),
|
||||||
|
|
||||||
isEnterSend({cacheKeyboard}) {
|
isEnterSend({cacheKeyboard}) {
|
||||||
if (this.$isEEUIApp) {
|
if (this.$isEEUIApp) {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
ref="forwardSelect"
|
ref="forwardSelect"
|
||||||
:title="title"
|
:title="title"
|
||||||
:show-bot="showBot"
|
:show-bot="showBot"
|
||||||
|
:hide-ai-bot="appAiHidden"
|
||||||
:multiple-max="userMaxSelect"
|
:multiple-max="userMaxSelect"
|
||||||
:before-submit="onSelectBefore"
|
:before-submit="onSelectBefore"
|
||||||
:show-select-all="false"
|
:show-select-all="false"
|
||||||
@ -31,6 +32,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import UserSelect from "../../../../components/UserSelect.vue";
|
import UserSelect from "../../../../components/UserSelect.vue";
|
||||||
import ForwardConfirm from "./confirm.vue";
|
import ForwardConfirm from "./confirm.vue";
|
||||||
|
import {mapGetters} from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Forwarder",
|
name: "Forwarder",
|
||||||
@ -94,6 +96,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['appAiHidden']),
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onSelection() {
|
onSelection() {
|
||||||
this.$refs.forwardSelect.onSelection()
|
this.$refs.forwardSelect.onSelection()
|
||||||
|
|||||||
@ -435,7 +435,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem :label="$L('AI任务分析')" prop="ai_auto_analyze">
|
<FormItem v-if="aiVisible" :label="$L('AI任务分析')" prop="ai_auto_analyze">
|
||||||
<RadioGroup v-model="settingData.ai_auto_analyze">
|
<RadioGroup v-model="settingData.ai_auto_analyze">
|
||||||
<Radio label="open" :disabled="systemConfig.task_ai_auto_analyze === 'close'">{{$L('开启')}}</Radio>
|
<Radio label="open" :disabled="systemConfig.task_ai_auto_analyze === 'close'">{{$L('开启')}}</Radio>
|
||||||
<Radio label="close">{{$L('关闭')}}</Radio>
|
<Radio label="close">{{$L('关闭')}}</Radio>
|
||||||
@ -765,7 +765,7 @@ export default {
|
|||||||
'systemConfig',
|
'systemConfig',
|
||||||
]),
|
]),
|
||||||
|
|
||||||
...mapGetters(['projectData', 'transforTasks']),
|
...mapGetters(['aiVisible', 'projectData', 'transforTasks']),
|
||||||
|
|
||||||
tabTypeActive() {
|
tabTypeActive() {
|
||||||
return this.projectData.cacheParameter.menuType
|
return this.projectData.cacheParameter.menuType
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div ref="reportContent" @click="onClick" class="report-content user-select-auto" v-html="currentDetail.content"></div>
|
<div ref="reportContent" @click="onClick" class="report-content user-select-auto" v-html="currentDetail.content"></div>
|
||||||
<div v-if="currentDetail.id" class="report-ai-analysis">
|
<div v-if="currentDetail.id && aiVisible" class="report-ai-analysis">
|
||||||
<div class="analysis-header">
|
<div class="analysis-header">
|
||||||
<div class="analysis-title">{{ $L("AI 分析") }}</div>
|
<div class="analysis-title">{{ $L("AI 分析") }}</div>
|
||||||
<Button
|
<Button
|
||||||
@ -72,7 +72,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
const VMPreview = () => import('../../../components/VMEditor/preview');
|
const VMPreview = () => import('../../../components/VMEditor/preview');
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import emitter from "../../../store/events";
|
import emitter from "../../../store/events";
|
||||||
import {extractPlainText} from "../../../utils/text";
|
import {extractPlainText} from "../../../utils/text";
|
||||||
import {REPORT_ANALYSIS_SYSTEM_PROMPT, withLanguagePreferencePrompt} from "../../../utils/ai";
|
import {REPORT_ANALYSIS_SYSTEM_PROMPT, withLanguagePreferencePrompt} from "../../../utils/ai";
|
||||||
@ -97,6 +97,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
...mapState(['formOptions', 'userInfo']),
|
...mapState(['formOptions', 'userInfo']),
|
||||||
currentDetail() {
|
currentDetail() {
|
||||||
return this.detail || this.data || {};
|
return this.detail || this.data || {};
|
||||||
|
|||||||
@ -46,6 +46,7 @@
|
|||||||
<div class="report-bottoms">
|
<div class="report-bottoms">
|
||||||
<Button type="primary" @click="handleSubmit" :loading="loadIng > 0" class="report-bottom">{{$L(id > 0 ? '修改' : '提交')}}</Button>
|
<Button type="primary" @click="handleSubmit" :loading="loadIng > 0" class="report-bottom">{{$L(id > 0 ? '修改' : '提交')}}</Button>
|
||||||
<Button
|
<Button
|
||||||
|
v-if="aiVisible"
|
||||||
type="default"
|
type="default"
|
||||||
class="report-bottom"
|
class="report-bottom"
|
||||||
@click="onOrganize">
|
@click="onOrganize">
|
||||||
@ -60,7 +61,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import UserSelect from "../../../components/UserSelect.vue";
|
import UserSelect from "../../../components/UserSelect.vue";
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import emitter from "../../../store/events";
|
import emitter from "../../../store/events";
|
||||||
import {MarkdownConver} from "../../../utils/markdown";
|
import {MarkdownConver} from "../../../utils/markdown";
|
||||||
import {extractPlainText} from "../../../utils/text";
|
import {extractPlainText} from "../../../utils/text";
|
||||||
@ -112,6 +113,8 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
...mapState(['formOptions']),
|
...mapState(['formOptions']),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
:placeholder="$L('任务描述')"
|
:placeholder="$L('任务描述')"
|
||||||
enterkeyhint="done"
|
enterkeyhint="done"
|
||||||
@on-keydown="onKeydown"/>
|
@on-keydown="onKeydown"/>
|
||||||
<div class="ai-btn" @click="onAI">
|
<div v-if="aiVisible" class="ai-btn" @click="onAI">
|
||||||
<i class="taskfont"></i>
|
<i class="taskfont"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -201,7 +201,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import emitter from "../../../store/events";
|
import emitter from "../../../store/events";
|
||||||
import UserSelect from "../../../components/UserSelect.vue";
|
import UserSelect from "../../../components/UserSelect.vue";
|
||||||
import TaskExistTips from "./TaskExistTips.vue";
|
import TaskExistTips from "./TaskExistTips.vue";
|
||||||
@ -292,6 +292,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
...mapState(['cacheProjects', 'projectId', 'cacheColumns', 'taskPriority', 'taskTemplates', 'formOptions']),
|
...mapState(['cacheProjects', 'projectId', 'cacheColumns', 'taskPriority', 'taskTemplates', 'formOptions']),
|
||||||
|
|
||||||
taskTemplateShareEnabled() {
|
taskTemplateShareEnabled() {
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="profile-actions">
|
<div v-if="!aiConversationHidden" class="profile-actions">
|
||||||
<Button @click="onOpenDialog"><i class="taskfont"></i>{{ $L("开始聊天") }}</Button>
|
<Button @click="onOpenDialog"><i class="taskfont"></i>{{ $L("开始聊天") }}</Button>
|
||||||
<Button @click="onCreateGroup"><i class="taskfont"></i>{{ $L("创建群组") }}</Button>
|
<Button @click="onCreateGroup"><i class="taskfont"></i>{{ $L("创建群组") }}</Button>
|
||||||
</div>
|
</div>
|
||||||
@ -131,7 +131,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import emitter from "../../../store/events";
|
import emitter from "../../../store/events";
|
||||||
import { mapState } from "vuex";
|
import { mapGetters, mapState } from "vuex";
|
||||||
import transformEmojiToHtml from "../../../utils/emoji";
|
import transformEmojiToHtml from "../../../utils/emoji";
|
||||||
import UserTagsModal from "./UserTagsModal.vue";
|
import UserTagsModal from "./UserTagsModal.vue";
|
||||||
import CommonDialogModal from "./CommonDialogModal.vue";
|
import CommonDialogModal from "./CommonDialogModal.vue";
|
||||||
@ -182,6 +182,12 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['appAiHidden']),
|
||||||
|
|
||||||
|
aiConversationHidden() {
|
||||||
|
return this.appAiHidden && $A.isAiBotUser(this.userData)
|
||||||
|
},
|
||||||
|
|
||||||
isFullscreen({ windowWidth }) {
|
isFullscreen({ windowWidth }) {
|
||||||
return windowWidth < 576;
|
return windowWidth < 576;
|
||||||
},
|
},
|
||||||
@ -464,4 +470,4 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -380,7 +380,12 @@ export default {
|
|||||||
'longpressData'
|
'longpressData'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
...mapGetters(['getDialogDraft', 'tagDialogDraft']),
|
...mapGetters([
|
||||||
|
'appAiHidden',
|
||||||
|
'getDialogDraft',
|
||||||
|
'tagDialogDraft',
|
||||||
|
'visibleDialogs',
|
||||||
|
]),
|
||||||
|
|
||||||
contactAvatarSize() {
|
contactAvatarSize() {
|
||||||
return this.windowPortrait ? 36 : 30
|
return this.windowPortrait ? 36 : 30
|
||||||
@ -389,19 +394,19 @@ export default {
|
|||||||
dialogList() {
|
dialogList() {
|
||||||
const {dialogActive, dialogSearchKey, dialogSearchList} = this
|
const {dialogActive, dialogSearchKey, dialogSearchList} = this
|
||||||
if (dialogSearchList.length > 0) {
|
if (dialogSearchList.length > 0) {
|
||||||
return dialogSearchList.sort((a, b) => {
|
return dialogSearchList.filter(dialog => !this.appAiHidden || !$A.isAiBotDialog(dialog)).sort((a, b) => {
|
||||||
// 搜索结果排在后面
|
// 搜索结果排在后面
|
||||||
return (a.is_search === true ? 1 : 0) - (b.is_search === true ? 1 : 0)
|
return (a.is_search === true ? 1 : 0) - (b.is_search === true ? 1 : 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (dialogActive == '' && dialogSearchKey == '') {
|
if (dialogActive == '' && dialogSearchKey == '') {
|
||||||
return this.cacheDialogs.filter(dialog => this.filterDialog(dialog)).sort(this.dialogSort);
|
return this.visibleDialogs.filter(dialog => this.filterDialog(dialog)).sort(this.dialogSort);
|
||||||
}
|
}
|
||||||
if (dialogActive == 'mark' && !dialogSearchKey) {
|
if (dialogActive == 'mark' && !dialogSearchKey) {
|
||||||
const lists = [];
|
const lists = [];
|
||||||
this.dialogMsgs.filter(h => h.tag).forEach(h => {
|
this.dialogMsgs.filter(h => h.tag).forEach(h => {
|
||||||
let dialog = $A.cloneJSON(this.cacheDialogs).find(p => p.id == h.dialog_id)
|
let dialog = $A.cloneJSON(this.cacheDialogs).find(p => p.id == h.dialog_id)
|
||||||
if (dialog) {
|
if (dialog && (!this.appAiHidden || !$A.isAiBotDialog(dialog))) {
|
||||||
dialog.last_msg = h;
|
dialog.last_msg = h;
|
||||||
dialog.search_msg_id = h.id;
|
dialog.search_msg_id = h.id;
|
||||||
lists.push(dialog);
|
lists.push(dialog);
|
||||||
@ -409,7 +414,7 @@ export default {
|
|||||||
});
|
});
|
||||||
return lists;
|
return lists;
|
||||||
}
|
}
|
||||||
const list = this.cacheDialogs.filter(dialog => {
|
const list = this.visibleDialogs.filter(dialog => {
|
||||||
if (!this.filterDialog(dialog)) {
|
if (!this.filterDialog(dialog)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -508,7 +513,7 @@ export default {
|
|||||||
msgUnread() {
|
msgUnread() {
|
||||||
return function (type) {
|
return function (type) {
|
||||||
let num = 0
|
let num = 0
|
||||||
this.cacheDialogs.some((dialog) => {
|
this.visibleDialogs.some((dialog) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'project':
|
case 'project':
|
||||||
case 'task':
|
case 'task':
|
||||||
@ -839,6 +844,9 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
filterDialog(dialog) {
|
filterDialog(dialog) {
|
||||||
|
if (this.appAiHidden && $A.isAiBotDialog(dialog)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if ((dialog.id > 0 && dialog.id == this.dialogId) || dialog.top_at || dialog.todo_num > 0 || $A.getDialogNum(dialog) > 0) {
|
if ((dialog.id > 0 && dialog.id == this.dialogId) || dialog.top_at || dialog.todo_num > 0 || $A.getDialogNum(dialog) > 0) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -158,7 +158,7 @@
|
|||||||
:placeholder="$L('请选择提醒时间')"
|
:placeholder="$L('请选择提醒时间')"
|
||||||
transfer/>
|
transfer/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem :label="$L('AI任务分析')" prop="taskAiAutoAnalyze">
|
<FormItem v-if="aiVisible" :label="$L('AI任务分析')" prop="taskAiAutoAnalyze">
|
||||||
<RadioGroup v-model="formDatum.task_ai_auto_analyze">
|
<RadioGroup v-model="formDatum.task_ai_auto_analyze">
|
||||||
<Radio label="open">{{$L('开启')}}</Radio>
|
<Radio label="open">{{$L('开启')}}</Radio>
|
||||||
<Radio label="close">{{$L('关闭')}}</Radio>
|
<Radio label="close">{{$L('关闭')}}</Radio>
|
||||||
@ -354,7 +354,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import UserSelect from "../../../../components/UserSelect.vue";
|
import UserSelect from "../../../../components/UserSelect.vue";
|
||||||
import SystemColumnTemplate from "./SystemColumnTemplate.vue";
|
import SystemColumnTemplate from "./SystemColumnTemplate.vue";
|
||||||
import SystemFileSetting from "./SystemFileSetting.vue";
|
import SystemFileSetting from "./SystemFileSetting.vue";
|
||||||
@ -394,6 +394,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
...mapState(['formOptions']),
|
...mapState(['formOptions']),
|
||||||
|
|
||||||
projectAddAll() {
|
projectAddAll() {
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import MobileNavTitle from "../../../components/Mobile/NavTitle.vue";
|
import MobileNavTitle from "../../../components/Mobile/NavTitle.vue";
|
||||||
import emitter from "../../../store/events";
|
import emitter from "../../../store/events";
|
||||||
@ -72,11 +72,9 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['userInfo', 'userIsAdmin', 'clientNewVersion', 'systemConfig', 'microAppsIds']),
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
aiInstalled() {
|
...mapState(['userInfo', 'userIsAdmin', 'clientNewVersion', 'systemConfig']),
|
||||||
return this.microAppsIds?.includes('ai');
|
|
||||||
},
|
|
||||||
|
|
||||||
showContent() {
|
showContent() {
|
||||||
return this.$route.path.match(/^\/manage\/setting\/\w+$/)
|
return this.$route.path.match(/^\/manage\/setting\/\w+$/)
|
||||||
@ -95,7 +93,7 @@ export default {
|
|||||||
menu.push({path: 'keyboard', name: '键盘设置'})
|
menu.push({path: 'keyboard', name: '键盘设置'})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.aiInstalled) {
|
if (this.aiVisible) {
|
||||||
menu.push({path: 'assistant', name: 'AI 助手设置'})
|
menu.push({path: 'assistant', name: 'AI 助手设置'})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,14 +145,14 @@ export default {
|
|||||||
handler(name) {
|
handler(name) {
|
||||||
if (name === 'manage-setting' && this.windowLandscape) {
|
if (name === 'manage-setting' && this.windowLandscape) {
|
||||||
this.goForward({name: 'manage-setting-personal'}, true);
|
this.goForward({name: 'manage-setting-personal'}, true);
|
||||||
} else if (name === 'manage-setting-assistant' && !this.aiInstalled) {
|
} else if (name === 'manage-setting-assistant' && !this.aiVisible) {
|
||||||
this.goForward({name: 'manage-setting-personal'}, true);
|
this.goForward({name: 'manage-setting-personal'}, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
},
|
},
|
||||||
microAppsIds() {
|
aiVisible(visible) {
|
||||||
if (this.routeName === 'manage-setting-assistant' && !this.aiInstalled) {
|
if (this.routeName === 'manage-setting-assistant' && !visible) {
|
||||||
this.goForward({name: 'manage-setting-personal'}, true);
|
this.goForward({name: 'manage-setting-personal'}, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
{{mateName}}<div class="input-box-push">+</div>{{altName}}<div class="input-box-push">+</div>L
|
{{mateName}}<div class="input-box-push">+</div>{{altName}}<div class="input-box-push">+</div>L
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem v-if="aiInstalled" :label="$L('AI 助手')">
|
<FormItem v-if="aiVisible" :label="$L('AI 助手')">
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
{{mateName}}<div class="input-box-push">+</div>I
|
{{mateName}}<div class="input-box-push">+</div>I
|
||||||
</div>
|
</div>
|
||||||
@ -75,15 +75,11 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapGetters} from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['microAppsIds']),
|
...mapGetters(['aiVisible']),
|
||||||
|
|
||||||
aiInstalled() {
|
|
||||||
return this.microAppsIds?.includes('ai');
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
5
resources/assets/js/store/actions.js
vendored
5
resources/assets/js/store/actions.js
vendored
@ -5401,7 +5401,7 @@ export default {
|
|||||||
* - props 传递参数
|
* - props 传递参数
|
||||||
* 更多说明详见 https://appstore.dootask.com/development/manual
|
* 更多说明详见 https://appstore.dootask.com/development/manual
|
||||||
*/
|
*/
|
||||||
async openMicroApp({state}, data) {
|
async openMicroApp({state, getters}, data) {
|
||||||
// 参数基础校验:必须是对象且包含 id/name/url
|
// 参数基础校验:必须是对象且包含 id/name/url
|
||||||
if (!data || !$A.isJson(data)) {
|
if (!data || !$A.isJson(data)) {
|
||||||
return
|
return
|
||||||
@ -5419,6 +5419,9 @@ export default {
|
|||||||
$A.modalWarning(`应用「${data.id}」未安装`)
|
$A.modalWarning(`应用「${data.id}」未安装`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (microAppId === 'ai' && !getters.aiVisible) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 以「匹配到的应用菜单第一个 menu(microAppsMenus 中该应用的第一条记录)」作为基础数据,合并出本次打开的 data
|
// 以「匹配到的应用菜单第一个 menu(microAppsMenus 中该应用的第一条记录)」作为基础数据,合并出本次打开的 data
|
||||||
if (data.skip_base_menu !== true) {
|
if (data.skip_base_menu !== true) {
|
||||||
|
|||||||
42
resources/assets/js/store/getters.js
vendored
42
resources/assets/js/store/getters.js
vendored
@ -278,6 +278,36 @@ export default {
|
|||||||
return quote || null
|
return quote || null
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI 界面是否可见
|
||||||
|
* 移动 APP 等待系统配置加载完成后再展示,避免启动时闪现。
|
||||||
|
*/
|
||||||
|
aiVisible(state, getters) {
|
||||||
|
const installed = state.microAppsIds?.includes('ai')
|
||||||
|
if (!$A.isEEUIApp) {
|
||||||
|
return installed
|
||||||
|
}
|
||||||
|
return installed && state.systemConfig.__state === 'success' && !getters.appAiHidden
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动 APP 是否隐藏 AI 功能
|
||||||
|
*/
|
||||||
|
appAiHidden(state) {
|
||||||
|
return $A.isEEUIApp
|
||||||
|
&& (state.systemConfig.__state !== 'success' || state.systemConfig.app_ai_hidden === true)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前客户端可见的会话
|
||||||
|
*/
|
||||||
|
visibleDialogs(state, getters) {
|
||||||
|
if (!getters.appAiHidden) {
|
||||||
|
return state.cacheDialogs
|
||||||
|
}
|
||||||
|
return state.cacheDialogs.filter(dialog => !$A.isAiBotDialog(dialog))
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取应用菜单
|
* 获取应用菜单
|
||||||
* 过滤出location为application的菜单项
|
* 过滤出location为application的菜单项
|
||||||
@ -285,9 +315,9 @@ export default {
|
|||||||
* @param {Object} state
|
* @param {Object} state
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
filterMicroAppsMenus: (state) => {
|
filterMicroAppsMenus: (state, getters) => {
|
||||||
return state.microAppsMenus.filter(item => {
|
return state.microAppsMenus.filter(item => {
|
||||||
return item.location === 'application'
|
return item.location === 'application' && (item.id !== 'ai' || getters.aiVisible)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -298,9 +328,9 @@ export default {
|
|||||||
* @param {Object} state
|
* @param {Object} state
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
filterMicroAppsMenusAdmin: (state) => {
|
filterMicroAppsMenusAdmin: (state, getters) => {
|
||||||
return state.microAppsMenus.filter(item => {
|
return state.microAppsMenus.filter(item => {
|
||||||
return item.location === 'application/admin'
|
return item.location === 'application/admin' && (item.id !== 'ai' || getters.aiVisible)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -311,9 +341,9 @@ export default {
|
|||||||
* @param {Object} state
|
* @param {Object} state
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
filterMicroAppsMenusMain: (state) => {
|
filterMicroAppsMenusMain: (state, getters) => {
|
||||||
return state.microAppsMenus.filter(item => {
|
return state.microAppsMenus.filter(item => {
|
||||||
return item.location === 'main/menu'
|
return item.location === 'main/menu' && (item.id !== 'ai' || getters.aiVisible)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
types/dootask-globals.d.ts
vendored
4
types/dootask-globals.d.ts
vendored
@ -468,6 +468,10 @@ interface DooTaskGlobal {
|
|||||||
timeOptionShortcuts(): Array<{ text: string; value(): [Date, Date] }>;
|
timeOptionShortcuts(): Array<{ text: string; value(): [Date, Date] }>;
|
||||||
/** 对话标签(已完成/已删除/已归档) */
|
/** 对话标签(已完成/已删除/已归档) */
|
||||||
dialogTags(dialog: any): Array<{ color: string; text: string }>;
|
dialogTags(dialog: any): Array<{ color: string; text: string }>;
|
||||||
|
/** 是否为 AI 机器人账号 */
|
||||||
|
isAiBotUser(user: any): boolean;
|
||||||
|
/** 是否为 AI 机器人单聊 */
|
||||||
|
isAiBotDialog(dialog: any): boolean;
|
||||||
/** 对话是否完成(返回 success 标签) */
|
/** 对话是否完成(返回 success 标签) */
|
||||||
dialogCompleted(dialog: any): { color: string; text: string } | undefined;
|
dialogCompleted(dialog: any): { color: string; text: string } | undefined;
|
||||||
/** 返回对话未读数量(不含免打扰,但如果免打扰中有@则返回@数量) */
|
/** 返回对话未读数量(不含免打扰,但如果免打扰中有@则返回@数量) */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user