mirror of
https://github.com/kuaifan/dootask.git
synced 2026-08-14 16:58:45 +00:00
插件/微应用可在自己的菜单入口显示数字或红点角标,插件未打开也生效。 - 后端:新增 app_badges 表 + AppBadge 模型 + Module/Badge 业务编排 + AppsController(badge__set 应用密钥鉴权 / badge__clear 用户鉴权) - 每应用独立密钥 APP_SECRET:按 appid 持久化于 appstore config.yml,鉴权校验 - 推送:复用 PushTask 下发 appBadge WS 消息;microapp_menu 附带初始角标 - 前端:appBadges Vuex module + WS 处理 + 三处菜单渲染(应用卡片/主菜单入口/ 父『应用』入口聚合)+ 移动端 Tabbar + 打开即清(badge_clear_on_open) - 用户离职级联清理;同步 ai-kb 角标知识
216 lines
6.9 KiB
Vue
216 lines
6.9 KiB
Vue
<template>
|
||
<div class="mobile-tabbar">
|
||
<NetworkException v-if="windowPortrait" type="alert"/>
|
||
<ul class="tabbar-box">
|
||
<li
|
||
v-for="(item, index) in navList"
|
||
:key="index"
|
||
:class="{active: activeName === item.name}"
|
||
@click="toggleRoute(item.name)">
|
||
<i class="taskfont" v-html="item.icon"></i>
|
||
<div class="tabbar-title">{{ $L(item.label) }}</div>
|
||
<template v-if="item.name === 'dashboard'">
|
||
<Badge v-if="dashboardTask.overdue_count > 0" class="tabbar-badge" type="error" :overflow-count="999" :count="dashboardTask.overdue_count"/>
|
||
<Badge v-else-if="dashboardTask.today_count > 0" class="tabbar-badge" type="info" :overflow-count="999" :count="dashboardTask.today_count"/>
|
||
<Badge v-else-if="dashboardTask.todo_count > 0" class="tabbar-badge" type="primary" :overflow-count="999" :count="dashboardTask.todo_count"/>
|
||
</template>
|
||
<template v-else-if="item.name === 'dialog'">
|
||
<Badge class="tabbar-badge" :overflow-count="999" :text="msgUnreadMention"/>
|
||
</template>
|
||
<template v-else-if="item.name === 'application'">
|
||
<Badge v-if="applicationBadgeCount > 0" class="tabbar-badge" :overflow-count="999" :count="applicationBadgeCount"/>
|
||
<Badge v-else-if="applicationBadgeDot" class="tabbar-badge" dot/>
|
||
</template>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import {mapGetters, mapState} from "vuex";
|
||
import NetworkException from "../NetworkException";
|
||
import emitter from "../../store/events";
|
||
|
||
export default {
|
||
name: "MobileTabbar",
|
||
components: {NetworkException},
|
||
data() {
|
||
return {
|
||
navList: [
|
||
{icon: '', name: 'dashboard', label: '仪表盘'},
|
||
{icon: '', name: 'project', label: '项目'},
|
||
{icon: '', name: 'dialog', label: '消息'},
|
||
{icon: '', name: 'contacts', label: '通讯录'},
|
||
{icon: '', name: 'application', label: '应用'},
|
||
],
|
||
};
|
||
},
|
||
|
||
mounted() {
|
||
emitter.on('dialogMsgPush', this.updateBadge);
|
||
},
|
||
|
||
beforeDestroy() {
|
||
emitter.off('dialogMsgPush', this.updateBadge);
|
||
},
|
||
|
||
computed: {
|
||
...mapState(['cacheDialogs']),
|
||
...mapGetters(['dashboardTask']),
|
||
|
||
// 父『应用』入口聚合角标(规则收敛在 appBadges 模块 getter)
|
||
...mapGetters('appBadges', {
|
||
applicationBadgeCount: 'applicationCount',
|
||
applicationBadgeDot: 'applicationDot',
|
||
}),
|
||
|
||
/**
|
||
* 综合数(未读、提及、待办)
|
||
* @returns {string|string}
|
||
*/
|
||
msgUnreadMention() {
|
||
let num = 0; // 未读
|
||
let mention = 0; // 提及
|
||
this.cacheDialogs.some(dialog => {
|
||
num += $A.getDialogUnread(dialog, false);
|
||
mention += $A.getDialogMention(dialog);
|
||
})
|
||
if (num > 999) {
|
||
num = "999+"
|
||
}
|
||
if (mention > 999) {
|
||
mention = "999+"
|
||
}
|
||
const todoNum = this.msgTodoTotal // 待办
|
||
if (todoNum) {
|
||
if (mention) {
|
||
return `@${mention}·${todoNum}`
|
||
}
|
||
if (num) {
|
||
return `${num}·${todoNum}`
|
||
}
|
||
return todoNum;
|
||
}
|
||
if (num) {
|
||
if (mention) {
|
||
return `${num}·@${mention}`
|
||
}
|
||
return String(num)
|
||
}
|
||
if (mention) {
|
||
return `@${mention}`
|
||
}
|
||
return "";
|
||
},
|
||
|
||
/**
|
||
* 未读消息数
|
||
* @returns {number}
|
||
*/
|
||
msgAllUnread() {
|
||
let num = 0;
|
||
this.cacheDialogs.some(dialog => {
|
||
num += $A.getDialogNum(dialog);
|
||
})
|
||
return num;
|
||
},
|
||
|
||
/**
|
||
* 待办消息数
|
||
* @returns {string|null}
|
||
*/
|
||
msgTodoTotal() {
|
||
let todoNum = this.cacheDialogs.reduce((total, current) => total + (current.todo_num || 0), 0)
|
||
if (todoNum > 0) {
|
||
if (todoNum > 999) {
|
||
todoNum = "999+"
|
||
} else if (todoNum === 1) {
|
||
todoNum = ""
|
||
}
|
||
return `${this.$L("待办")}${todoNum}`
|
||
}
|
||
return null;
|
||
},
|
||
|
||
/**
|
||
* 未读消息 + 逾期任务
|
||
* @returns {number|*}
|
||
*/
|
||
unreadAndOverdue() {
|
||
if (this.userId > 0) {
|
||
return this.msgAllUnread + this.dashboardTask.overdue_count
|
||
} else {
|
||
return 0
|
||
}
|
||
},
|
||
|
||
activeName() {
|
||
if (['manage-calendar', 'manage-file', 'manage-setting', 'manage-application'].includes(this.routeName)) {
|
||
return 'application';
|
||
}
|
||
|
||
if (this.routeName === 'manage-dashboard') {
|
||
return 'dashboard';
|
||
}
|
||
|
||
if (this.routeName === 'manage-project' && !/^\d+$/.test(this.$route.params.projectId)) {
|
||
return 'project';
|
||
}
|
||
if (this.routeName === 'manage-messenger') {
|
||
if (this.$route.params.dialogAction === 'contacts') {
|
||
return 'contacts'
|
||
} else {
|
||
return 'dialog'
|
||
}
|
||
}
|
||
return ''
|
||
},
|
||
},
|
||
|
||
watch: {
|
||
windowActive() {
|
||
this.updateBadge();
|
||
},
|
||
},
|
||
|
||
methods: {
|
||
toggleRoute(path) {
|
||
this.$emit("on-click", path)
|
||
//
|
||
let location;
|
||
switch (path) {
|
||
case 'project':
|
||
location = {name: 'manage-project', params: {projectId: 'all'}};
|
||
break;
|
||
|
||
case 'dialog':
|
||
location = {name: 'manage-messenger', params: {dialogAction: 'dialog'}};
|
||
if (this.routeName === 'manage-messenger') {
|
||
emitter.emit('clickAgainDialog', true);
|
||
}
|
||
break;
|
||
|
||
case 'contacts':
|
||
location = {name: 'manage-messenger', params: {dialogAction: 'contacts'}};
|
||
break;
|
||
|
||
default:
|
||
location = {name: 'manage-' + path};
|
||
break;
|
||
}
|
||
this.goForward(location);
|
||
},
|
||
|
||
updateBadge() {
|
||
if (this.windowActive) {
|
||
return
|
||
}
|
||
$A.eeuiAppSendMessage({
|
||
action: 'setBdageNotify',
|
||
bdage: this.unreadAndOverdue,
|
||
});
|
||
},
|
||
},
|
||
};
|
||
</script>
|