mirror of
https://github.com/kuaifan/dootask.git
synced 2026-10-29 22:10:42 +00:00
feat: 系统功能应用统一管理内置功能入口
- 新增 SystemFunctions 模块与 api/apps/functions 接口,读取 system-functions 应用的安装状态和开关字段 - 工作报告、日历、我的收藏、最近打开、签到打卡的入口(应用中心、头像菜单、左侧导航)统一受开关控制,卸载后全部隐藏 - 导出签到数据随签到打卡一起隐藏;日历停用后访问日历页跳回仪表盘 - 头像菜单按分组计算分割线,隐藏菜单项后不留多余分割线 - 新增迁移:无配置时自动安装并全部启用,已有配置不覆盖 - 同步 ai-kb 与 api-map
This commit is contained in:
parent
4c357ef36f
commit
1c90a11211
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api;
|
||||
use App\Models\User;
|
||||
use App\Module\Badge;
|
||||
use App\Module\Base;
|
||||
use App\Module\SystemFunctions;
|
||||
use Request;
|
||||
|
||||
/**
|
||||
@ -14,6 +15,7 @@ use Request;
|
||||
* api/apps/badge/set -> badge__set() 应用密钥鉴权,绝对设置/清除角标
|
||||
* api/apps/badge/clear -> badge__clear() 当前用户 token 鉴权,清除自己的角标
|
||||
* api/apps/badge/list -> badge__list() 当前用户 token 鉴权,拉取自己全部角标(初始同步)
|
||||
* api/apps/functions -> functions() 当前用户 token 鉴权,获取「系统功能」应用的功能开关
|
||||
*/
|
||||
class AppsController extends AbstractController
|
||||
{
|
||||
@ -91,4 +93,25 @@ class AppsController extends AbstractController
|
||||
$user = User::auth();
|
||||
return Base::retSuccess('success', Badge::userBadges((int)$user->userid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/apps/functions 获取系统功能开关
|
||||
*
|
||||
* @apiDescription 需要token身份。返回「系统功能」应用是否已安装,以及工作报告、日历、我的收藏、最近打开、签到打卡的启用状态。
|
||||
* 应用未安装时全部为 false;前端据此统一显示或隐藏这些功能的入口。
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup apps
|
||||
* @apiName functions
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
* @apiSuccess {Boolean} data.installed 应用是否已安装
|
||||
* @apiSuccess {Object} data.functions 功能开关(report/calendar/favorite/recent/checkin => Boolean)
|
||||
*/
|
||||
public function functions()
|
||||
{
|
||||
User::auth();
|
||||
return Base::retSuccess('success', SystemFunctions::status());
|
||||
}
|
||||
}
|
||||
|
||||
103
app/Module/SystemFunctions.php
Normal file
103
app/Module/SystemFunctions.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Module;
|
||||
|
||||
use App\Services\RequestContext;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* 「系统功能」内置应用(appstore 应用 system-functions)。
|
||||
*
|
||||
* 该应用不启动容器,只通过应用字段保存各内置功能的开关;
|
||||
* 主程序据此统一控制工作报告、日历、我的收藏、最近打开、签到打卡的入口。
|
||||
* 仅控制入口显示,不拦截接口、不影响数据。
|
||||
*/
|
||||
class SystemFunctions
|
||||
{
|
||||
const APP_ID = 'system-functions';
|
||||
|
||||
/**
|
||||
* 功能标识 => 应用字段名
|
||||
*/
|
||||
const FUNCTIONS = [
|
||||
'report' => 'REPORT',
|
||||
'calendar' => 'CALENDAR',
|
||||
'favorite' => 'FAVORITE',
|
||||
'recent' => 'RECENT',
|
||||
'checkin' => 'CHECKIN',
|
||||
];
|
||||
|
||||
/**
|
||||
* 应用安装配置文件路径
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function configFile(): string
|
||||
{
|
||||
return base_path('docker/appstore/config/' . self::APP_ID . '/config.yml');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用安装状态与各功能的启用状态。
|
||||
* 应用未安装时全部为停用;已安装时缺失的字段视为启用(字段默认值即启用)。
|
||||
*
|
||||
* @return array ['installed' => bool, 'functions' => ['report' => bool, ...]]
|
||||
*/
|
||||
public static function status(): array
|
||||
{
|
||||
$key = 'system_functions_status';
|
||||
if (RequestContext::has($key)) {
|
||||
return RequestContext::get($key);
|
||||
}
|
||||
$params = Apps::isInstalled(self::APP_ID) ? self::readParams() : null;
|
||||
$functions = [];
|
||||
foreach (self::FUNCTIONS as $name => $field) {
|
||||
$functions[$name] = $params !== null && self::isOn($params[$field] ?? true);
|
||||
}
|
||||
return RequestContext::save($key, [
|
||||
'installed' => $params !== null,
|
||||
'functions' => $functions,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定功能是否启用
|
||||
*
|
||||
* @param string $name 功能标识(report/calendar/favorite/recent/checkin)
|
||||
* @return bool
|
||||
*/
|
||||
public static function enabled(string $name): bool
|
||||
{
|
||||
return (bool)(self::status()['functions'][$name] ?? false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取应用安装参数
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function readParams(): array
|
||||
{
|
||||
try {
|
||||
$config = Yaml::parseFile(self::configFile());
|
||||
} catch (\Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
$params = is_array($config) ? ($config['params'] ?? []) : [];
|
||||
return is_array($params) ? $params : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 开关值是否为开启(兼容布尔值与字符串)
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
private static function isOn($value): bool
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return !in_array(strtolower(trim($value)), ['', '0', 'false', 'off', 'no'], true);
|
||||
}
|
||||
return (bool)$value;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* 默认安装「系统功能」应用并启用全部功能。
|
||||
*
|
||||
* 应用的安装状态保存在 docker/appstore/config/system-functions/config.yml(与其它应用同源),
|
||||
* 因此这里写的是配置文件而不是数据表。仅在配置文件不存在时写入:
|
||||
* 已有配置(包括管理员卸载后留下的未安装状态、自行调整过的开关)一律不覆盖。
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
$appId = 'system-functions';
|
||||
$configDir = base_path('docker/appstore/config/' . $appId);
|
||||
$configFile = $configDir . '/config.yml';
|
||||
if (file_exists($configFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_dir($configDir) && !@mkdir($configDir, 0755, true) && !is_dir($configDir)) {
|
||||
throw new RuntimeException("无法创建目录:{$configDir}");
|
||||
}
|
||||
|
||||
$config = [
|
||||
'install_at' => date('Y-m-d H:i:s'),
|
||||
'install_num' => 1,
|
||||
'install_version' => $this->latestVersion($appId),
|
||||
'status' => 'installed',
|
||||
'params' => [
|
||||
'REPORT' => true,
|
||||
'CALENDAR' => true,
|
||||
'FAVORITE' => true,
|
||||
'RECENT' => true,
|
||||
'CHECKIN' => true,
|
||||
],
|
||||
'resources' => [
|
||||
'cpu_limit' => '0',
|
||||
'memory_limit' => '0',
|
||||
],
|
||||
];
|
||||
if (@file_put_contents($configFile, Yaml::dump($config, 4, 4)) === false) {
|
||||
throw new RuntimeException("无法写入配置文件:{$configFile}");
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// 不回滚:无法区分配置是本迁移写入的还是管理员后续调整的
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用包内的最新版本号;应用包尚未同步到本地时使用首个版本。
|
||||
*/
|
||||
private function latestVersion(string $appId): string
|
||||
{
|
||||
$latest = '1.0.0';
|
||||
foreach (glob(base_path("docker/appstore/apps/{$appId}/*"), GLOB_ONLYDIR) ?: [] as $dir) {
|
||||
$version = basename($dir);
|
||||
if (preg_match('/^v?\d+(\.\d+){1,2}$/', $version) && version_compare(ltrim($version, 'v'), ltrim($latest, 'v'), '>')) {
|
||||
$latest = $version;
|
||||
}
|
||||
}
|
||||
return $latest;
|
||||
}
|
||||
};
|
||||
@ -663,6 +663,19 @@ features:
|
||||
- compliance.howto
|
||||
- compliance.entry.menu-map
|
||||
|
||||
- id: system-functions
|
||||
name: 系统功能(内置功能入口开关:工作报告/日历/我的收藏/最近打开/签到打卡)
|
||||
scope: admin
|
||||
batch: B4
|
||||
priority: P0
|
||||
chunk_count_est: 3
|
||||
owner: ~
|
||||
status: drafted
|
||||
chunks:
|
||||
- system-functions.overview.concept
|
||||
- system-functions.toggle.howto
|
||||
- system-functions.entry-missing.faq
|
||||
|
||||
- id: appstore
|
||||
name: 应用市场(AppStore 管理)
|
||||
scope: admin
|
||||
|
||||
@ -17,7 +17,7 @@ prerequisites: []
|
||||
negative:
|
||||
- 应用中心不是「应用市场」(AppStore),后者是管理员安装/卸载插件的独立入口
|
||||
- 普通成员看不到管理员应用区(如 LDAP、邮件通知、数据导出等)
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 应用中心是什么
|
||||
@ -34,6 +34,9 @@ last_verified: v1.7.90
|
||||
- **管理员应用**:仅系统管理员可见(LDAP、邮件通知、APP 推送、举报管理、数据导出、团队管理)
|
||||
- **微应用**:由已安装插件提供(OKR、思维导图、流程图、在线文档、Memos、KPI 等),列表随安装情况变化
|
||||
|
||||
## 受「系统功能」应用控制的卡片
|
||||
工作报告、我的收藏、最近打开、签到打卡(以及竖屏下的日历)这几张系统应用卡片,只有在「系统功能」应用已安装且对应开关开启时才显示。该应用自身不会在应用中心生成卡片,同一功能只会出现一张卡片。详见 [[system-functions.overview.concept]]。
|
||||
|
||||
## 个性化
|
||||
- 拖拽:长按卡片可调整顺序(仅影响个人视图)
|
||||
- 管理员可在「自定义应用菜单」里调整全员可见的应用项
|
||||
|
||||
49
resources/ai-kb/zh/concept/system-functions/overview.md
Normal file
49
resources/ai-kb/zh/concept/system-functions/overview.md
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
id: system-functions.overview.concept
|
||||
title: 「系统功能」应用是什么
|
||||
type: concept
|
||||
feature: system-functions
|
||||
scope: end-user
|
||||
locale: zh
|
||||
aliases:
|
||||
- 系统功能应用
|
||||
- 系统功能是什么
|
||||
- system-functions
|
||||
- 内置功能开关
|
||||
- 怎么隐藏日历
|
||||
- 怎么关闭工作报告入口
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites: []
|
||||
negative:
|
||||
- 「系统功能」只控制入口是否显示,不会删除报告、收藏、签到等已有数据
|
||||
- 「系统功能」不启动任何容器,安装时没有 CPU、内存、镜像拉取等高级设置
|
||||
- 「系统功能」自身不会在应用中心生成卡片,也不会新增菜单
|
||||
- 不支持按成员或部门单独开关,开关对全员生效
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 「系统功能」应用是什么
|
||||
|
||||
## 定义
|
||||
「系统功能」(应用 ID:system-functions)是 DooTask 的内置应用,用来统一管理五个内置功能的入口:工作报告、日历、我的收藏、最近打开、签到打卡。它在应用商店(AppStore)中安装、配置和卸载。
|
||||
|
||||
## 关键属性
|
||||
- 每个功能对应一个开关字段,默认全部开启
|
||||
- 新部署和升级上来的实例会自动安装「系统功能」并启用全部功能;已有配置不会被覆盖
|
||||
- 开关对该功能的所有入口统一生效:应用中心卡片、头像下拉菜单、左侧导航
|
||||
- 卸载「系统功能」后,五个功能的入口全部隐藏;重新安装即可恢复
|
||||
|
||||
## 各功能受控的入口
|
||||
| 功能 | 受控入口 |
|
||||
|---|---|
|
||||
| 工作报告 | 应用中心「工作报告」卡片及未读角标、头像菜单「工作报告」 |
|
||||
| 日历 | 左侧导航「日历」、竖屏应用中心「日历」卡片;停用后访问日历页会回到仪表盘 |
|
||||
| 我的收藏 | 头像菜单「我的收藏」、应用中心「我的收藏」卡片 |
|
||||
| 最近打开 | 头像菜单「最近打开的任务」、应用中心「最近打开」卡片 |
|
||||
| 签到打卡 | 应用中心「签到打卡」卡片、「导出签到数据」入口 |
|
||||
|
||||
## 与其他概念的关系
|
||||
- 修改开关的步骤见 [[system-functions.toggle.howto]]
|
||||
- 入口找不到时的排查见 [[system-functions.entry-missing.faq]]
|
||||
- 应用中心整体说明见 [[application.center.concept]]
|
||||
42
resources/ai-kb/zh/faq/system-functions/entry-missing.md
Normal file
42
resources/ai-kb/zh/faq/system-functions/entry-missing.md
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
id: system-functions.entry-missing.faq
|
||||
title: 为什么找不到工作报告、日历、我的收藏、最近打开或签到打卡的入口
|
||||
type: faq
|
||||
feature: system-functions
|
||||
scope: end-user
|
||||
locale: zh
|
||||
aliases:
|
||||
- 日历不见了
|
||||
- 工作报告入口没了
|
||||
- 找不到我的收藏
|
||||
- 最近打开不见了
|
||||
- 签到打卡卡片消失
|
||||
- 左侧栏没有日历
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites: []
|
||||
negative:
|
||||
- 入口隐藏不代表数据丢失,重新启用后原有数据仍在
|
||||
- 普通成员无法自行恢复入口,需要联系系统管理员
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 为什么找不到工作报告、日历、我的收藏、最近打开或签到打卡的入口
|
||||
|
||||
## 原因
|
||||
这五个功能的入口由「系统功能」应用统一控制,出现以下任一情况时入口会隐藏:
|
||||
1. 管理员在「系统功能」应用里关闭了对应功能的开关
|
||||
2. 管理员卸载了「系统功能」应用(此时五个功能的入口全部隐藏)
|
||||
|
||||
## 怎么确认
|
||||
- 某一个功能的入口在应用中心、头像菜单、左侧导航同时消失:多半是该功能的开关被关闭
|
||||
- 五个功能的入口同时消失:多半是「系统功能」应用被卸载
|
||||
|
||||
## 解决办法
|
||||
- 普通成员:联系系统管理员启用
|
||||
- 管理员:在应用商店打开「系统功能」应用,安装或重新安装并打开对应开关,步骤见 [[system-functions.toggle.howto]]
|
||||
|
||||
## 其他可能
|
||||
- 「工作报告」在系统管理员的头像菜单里本来就不显示,管理员请从应用中心进入
|
||||
- 「日历」卡片只在竖屏(移动端)的应用中心显示,桌面端在左侧导航
|
||||
- 「签到打卡」还可能被管理员在「签到设置」里整体关闭
|
||||
@ -14,8 +14,9 @@ aliases:
|
||||
related_tools: []
|
||||
related_pages: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「签到打卡」开关为开启(默认开启)
|
||||
- 需要系统管理员身份
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 怎么导出签到数据
|
||||
@ -50,3 +51,6 @@ last_verified: v1.7.90
|
||||
- 不支持单次导出超过 100 个成员,更多需要分批
|
||||
- 不支持按部门一键全选,需手动勾选
|
||||
- 不支持原始多次打卡明细,只导首签和末签两个时间
|
||||
|
||||
## 入口不显示时
|
||||
「导出签到数据」入口受「系统功能」应用控制:管理员在应用商店停用了「签到打卡」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -14,6 +14,7 @@ aliases:
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「签到打卡」开关为开启(默认开启)
|
||||
- 需要系统管理员权限
|
||||
- 系统设置中签到功能已开启(`checkinSetting.open = open`)
|
||||
negative:
|
||||
@ -21,7 +22,7 @@ negative:
|
||||
- 单次最多 100 个成员
|
||||
- 日期范围最多 35 天
|
||||
- 必填成员 / 日期 / 时间三个参数,缺一不可
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 导出签到数据
|
||||
@ -52,3 +53,6 @@ last_verified: v1.7.90
|
||||
- 不支持导出无班次成员
|
||||
- 不支持跨月超 35 天一次导
|
||||
- 不支持自定义结果判定规则(用系统全局设置)
|
||||
|
||||
## 入口不显示时
|
||||
「导出签到数据」入口受「系统功能」应用控制:管理员在应用商店停用了「签到打卡」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
53
resources/ai-kb/zh/howto/system-functions/toggle.md
Normal file
53
resources/ai-kb/zh/howto/system-functions/toggle.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
id: system-functions.toggle.howto
|
||||
title: 怎么启用或停用系统功能(工作报告、日历、收藏、最近打开、签到)
|
||||
type: howto
|
||||
feature: system-functions
|
||||
scope: admin
|
||||
locale: zh
|
||||
aliases:
|
||||
- 怎么隐藏日历
|
||||
- 关闭签到打卡入口
|
||||
- 停用工作报告
|
||||
- 恢复我的收藏入口
|
||||
- 系统功能怎么设置
|
||||
- 卸载系统功能
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites:
|
||||
- 需要系统管理员权限
|
||||
- 应用商店(AppStore)可用
|
||||
negative:
|
||||
- 普通成员不能修改这些开关
|
||||
- 停用或卸载不会删除任何数据,只隐藏入口
|
||||
- 安装页没有「高级设置」,因为该应用不启动容器
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 怎么启用或停用系统功能(工作报告、日历、收藏、最近打开、签到)
|
||||
|
||||
## 入口
|
||||
- 桌面端:左侧栏「应用」→ 管理员区「应用商店」→ 找到「系统功能」应用
|
||||
|
||||
## 操作步骤
|
||||
1. 在应用商店打开「系统功能」应用
|
||||
2. 进入该应用的安装页(已安装时按钮为「重新安装」,未安装时为「安装」)
|
||||
3. 在「应用配置」里按需打开或关闭五个开关:工作报告、日历、我的收藏、最近打开、签到打卡
|
||||
4. 点击「重新安装」提交,配置立即保存,无需等待容器启动
|
||||
5. 回到主界面,入口随即按新配置显示或隐藏;其他成员刷新页面或重新进入「应用」后生效
|
||||
|
||||
## 字段默认值
|
||||
| 开关 | 默认 |
|
||||
|---|---|
|
||||
| 工作报告 | 开启 |
|
||||
| 日历 | 开启 |
|
||||
| 我的收藏 | 开启 |
|
||||
| 最近打开 | 开启 |
|
||||
| 签到打卡 | 开启 |
|
||||
|
||||
## 一次隐藏全部入口
|
||||
在应用商店卸载「系统功能」应用,五个功能的入口全部隐藏。重新安装后恢复。
|
||||
|
||||
## 相关
|
||||
- 应用说明见 [[system-functions.overview.concept]]
|
||||
- 入口找不到的排查见 [[system-functions.entry-missing.faq]]
|
||||
@ -13,12 +13,13 @@ aliases:
|
||||
- calendar 在哪
|
||||
related_tools: [list_tasks]
|
||||
related_pages: [calendar]
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「日历」开关为开启(默认开启)
|
||||
negative:
|
||||
- 日历只显示有 end_at 的任务,不显示会议、签到等其他事件
|
||||
- 移动端日历只读,不能拖动改时间
|
||||
- 日历不支持其他人的视图
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 日历入口在哪
|
||||
@ -50,3 +51,6 @@ last_verified: v1.7.90
|
||||
- 不显示会议(B2 模块)、签到、报告
|
||||
- 不支持订阅他人日历
|
||||
- 详见 [[calendar.meeting-not-shown.faq]]
|
||||
|
||||
## 入口不显示时
|
||||
「日历」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「日历」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -13,11 +13,12 @@ aliases:
|
||||
- 签到打卡入口
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「签到打卡」开关为开启(默认开启)
|
||||
negative:
|
||||
- 左侧栏没有「签到」一级入口,必须从「应用」展开
|
||||
- 应用中心看不到「签到打卡」卡片时,多半是被管理员在「签到设置」里整体关闭了
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 签到打卡入口在哪
|
||||
@ -43,3 +44,6 @@ last_verified: v1.7.90
|
||||
- 任何登录成员都能看到「签到打卡」卡片
|
||||
- 全局「签到设置」按钮仅管理员可见
|
||||
- 个别能力(如人脸上传 / 修改 MAC)受「允许修改」开关控制,默认允许
|
||||
|
||||
## 入口不显示时
|
||||
「签到打卡」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「签到打卡」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -13,12 +13,13 @@ aliases:
|
||||
- 最近浏览入口
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「我的收藏」开关为开启(默认开启)
|
||||
negative:
|
||||
- 没有顶部导航的独立入口,必须通过「应用」中心进入
|
||||
- 不在左侧栏一级菜单上,不会默认置顶
|
||||
- 桌面端和移动端入口结构一致,没有平台差异化路径
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 我的收藏 / 最近打开入口
|
||||
@ -55,3 +56,6 @@ last_verified: v1.7.90
|
||||
- 添加收藏:[[favorite.add.howto]]
|
||||
- 取消收藏:[[favorite.remove.howto]]
|
||||
- 收藏与最近的概念区别:[[favorite.concept]]
|
||||
|
||||
## 入口不显示时
|
||||
「我的收藏」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「我的收藏」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -13,12 +13,13 @@ aliases:
|
||||
- 打卡机器人在哪
|
||||
related_tools: []
|
||||
related_pages: [application, messenger]
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「签到打卡」开关为开启(默认开启)
|
||||
negative:
|
||||
- 没有左侧一级菜单,必须从「应用」展开
|
||||
- 不支持快捷键
|
||||
- 「签到打卡」卡片被管理员关闭时不会显示
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 签到打卡入口在哪
|
||||
@ -39,3 +40,6 @@ last_verified: v1.7.90
|
||||
- 签到入口总览:[[checkin.entry.menu-map]]
|
||||
- 怎么打卡:[[checkin.regular.howto]]
|
||||
- 管理员配置规则:[[checkin.rule.concept]]
|
||||
|
||||
## 入口不显示时
|
||||
「签到打卡」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「签到打卡」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -12,11 +12,12 @@ aliases:
|
||||
- 我收藏过的怎么看
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「我的收藏」开关为开启(默认开启)
|
||||
negative:
|
||||
- 没有左侧栏一级入口,藏在「应用」中心和头像下拉里
|
||||
- 没有快捷键
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 我的收藏入口在哪
|
||||
@ -39,3 +40,6 @@ last_verified: v1.7.90
|
||||
- 收藏入口与最近打开:[[favorite.entry.menu-map]]
|
||||
- 添加收藏:[[favorite.add.howto]]
|
||||
- 与最近打开的区别:[[favorite.concept]]
|
||||
|
||||
## 入口不显示时
|
||||
「我的收藏」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「我的收藏」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -12,11 +12,12 @@ aliases:
|
||||
- 历史浏览记录
|
||||
related_tools: []
|
||||
related_pages: [application]
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「最近打开」开关为开启(默认开启)
|
||||
negative:
|
||||
- 「最近打开」只记录任务 / 文件 / 任务附件 / 消息附件,不包含项目和会话
|
||||
- 不支持手动清空全部记录
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 最近打开入口在哪
|
||||
@ -39,3 +40,6 @@ last_verified: v1.7.90
|
||||
|
||||
## 相关
|
||||
- 收藏与最近的总入口:[[favorite.entry.menu-map]]
|
||||
|
||||
## 入口不显示时
|
||||
「最近打开」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「最近打开」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -14,11 +14,12 @@ aliases:
|
||||
- 打开汇报
|
||||
related_tools: []
|
||||
related_pages: []
|
||||
prerequisites: []
|
||||
prerequisites:
|
||||
- 「系统功能」应用已安装且其中的「工作报告」开关为开启(默认开启)
|
||||
negative:
|
||||
- 「工作报告」不在左侧主导航栏,是右上角头像菜单 + 应用中心系统应用
|
||||
- 普通成员菜单显示「工作报告」;系统管理员菜单中不直接显示该项,可改走应用中心
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.9.36
|
||||
---
|
||||
|
||||
# 工作报告入口在哪
|
||||
@ -41,3 +42,6 @@ last_verified: v1.7.90
|
||||
## 权限要求
|
||||
- end-user 可见,所有登录用户都能写和收报告
|
||||
- 不需要插件,是主程序内置功能
|
||||
|
||||
## 入口不显示时
|
||||
「工作报告」的所有入口受「系统功能」应用控制:管理员在应用商店停用了「工作报告」开关,或卸载了「系统功能」应用时,入口会统一隐藏(数据不会删除)。恢复方法见 [[system-functions.toggle.howto]]。
|
||||
|
||||
@ -206,6 +206,9 @@ class ActionExecutor {
|
||||
* 导航到日历页面
|
||||
*/
|
||||
async navigateToCalendar() {
|
||||
if (!this.store?.getters?.systemFunctionEnabled?.('calendar')) {
|
||||
throw new Error('日历功能未启用');
|
||||
}
|
||||
window.$A.goForward({ name: 'manage-calendar' });
|
||||
return { navigated: true, page: 'calendar' };
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
<DropdownItem name="allUser">{{$L('团队管理')}}</DropdownItem>
|
||||
<DropdownItem name="exportTask">{{$L('导出任务统计')}}</DropdownItem>
|
||||
<DropdownItem name="exportOverdueTask">{{$L('导出超期任务')}}</DropdownItem>
|
||||
<DropdownItem name="exportCheckin">{{$L('导出签到数据')}}</DropdownItem>
|
||||
<DropdownItem v-if="systemFunctionEnabled('checkin')" name="exportCheckin">{{$L('导出签到数据')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
<!-- 部门负责人视角 -->
|
||||
@ -141,7 +141,7 @@
|
||||
<Badge v-else-if="dashboardTask.today_count > 0" class="menu-badge" type="info" :overflow-count="999" :count="dashboardTask.today_count"/>
|
||||
<Badge v-else-if="dashboardTask.todo_count > 0" class="menu-badge" type="primary" :overflow-count="999" :count="dashboardTask.todo_count"/>
|
||||
</li>
|
||||
<li @click="toggleRoute('calendar')" :class="classNameRoute('calendar')">
|
||||
<li v-if="systemFunctionEnabled('calendar')" @click="toggleRoute('calendar')" :class="classNameRoute('calendar')">
|
||||
<i class="taskfont"></i>
|
||||
<div class="menu-title">{{$L('日历')}}</div>
|
||||
</li>
|
||||
@ -655,7 +655,7 @@ export default {
|
||||
'mcpServerStatus'
|
||||
]),
|
||||
|
||||
...mapGetters(['aiVisible', 'dashboardTask', "filterMicroAppsMenusMain", 'visibleDialogs']),
|
||||
...mapGetters(['aiVisible', 'dashboardTask', "filterMicroAppsMenusMain", 'visibleDialogs', 'systemFunctionEnabled']),
|
||||
|
||||
// 父『应用』入口聚合角标(规则收敛在 appBadges 模块 getter)
|
||||
...mapGetters('appBadges', {
|
||||
@ -663,6 +663,14 @@ export default {
|
||||
applicationBadgeDot: 'applicationDot',
|
||||
}),
|
||||
|
||||
/**
|
||||
* 当前处于日历页且日历已明确停用(开关尚未加载时不判定为停用)
|
||||
* @returns {boolean}
|
||||
*/
|
||||
calendarDisabled() {
|
||||
return this.routeName === 'manage-calendar' && this.$store.state.systemFunctions.calendar === false;
|
||||
},
|
||||
|
||||
departmentOwnerViewAvailable() {
|
||||
return this.systemConfig.department_owner_project_view === 'open' && (this.userInfo.managed_departments || []).length > 0;
|
||||
},
|
||||
@ -783,51 +791,64 @@ export default {
|
||||
* @returns {Array}
|
||||
*/
|
||||
menu() {
|
||||
const {userIsAdmin} = this;
|
||||
const array = [
|
||||
{path: 'taskBrowse', name: '最近打开的任务'},
|
||||
{path: 'favorite', name: '我的收藏'},
|
||||
{path: 'download', name: '下载内容', visible: !!this.$Electron},
|
||||
{path: 'mcpServer', name: '启用桌面 MCP 服务器', visible: !!this.$Electron, selected: this.mcpServerStatus.running === 'running'},
|
||||
const {userIsAdmin, systemFunctionEnabled} = this;
|
||||
// 按分组组织:每组(第一组除外)的首个可见项显示分割线。
|
||||
// 先过滤不可见的菜单项再计算分割线,隐藏任意项都不会留下多余的分割线。
|
||||
const groups = [
|
||||
[
|
||||
{path: 'taskBrowse', name: '最近打开的任务', visible: systemFunctionEnabled('recent')},
|
||||
{path: 'favorite', name: '我的收藏', visible: systemFunctionEnabled('favorite')},
|
||||
{path: 'download', name: '下载内容', visible: !!this.$Electron},
|
||||
{path: 'mcpServer', name: '启用桌面 MCP 服务器', visible: !!this.$Electron, selected: this.mcpServerStatus.running === 'running'},
|
||||
],
|
||||
];
|
||||
const departmentOwnerView = this.departmentOwnerViewAvailable ? [{
|
||||
path: 'departmentOwnerView',
|
||||
name: '负责人视角',
|
||||
selected: this.departmentOwnerProjectViewEnabled,
|
||||
selectedCount: this.departmentOwnerProjectViewEnabled ? this.cacheDepartmentOwnerIds.length : 0,
|
||||
}] : [];
|
||||
if (userIsAdmin) {
|
||||
array.push(...[
|
||||
{path: 'personal', name: '个人设置', divided: true},
|
||||
{path: 'system', name: '系统设置'},
|
||||
{path: 'license', name: 'License Key'},
|
||||
|
||||
{path: 'downloadClient', name: '客户端下载', divided: true, visible: this.showDownloadClient},
|
||||
{path: 'version', name: '更新版本', divided: true, visible: !!this.clientNewVersion},
|
||||
|
||||
{path: 'allProject', name: '所有项目', divided: true},
|
||||
{path: 'archivedProject', name: '已归档的项目'},
|
||||
|
||||
{path: 'team', name: '团队管理', divided: true},
|
||||
])
|
||||
groups.push(
|
||||
[
|
||||
{path: 'personal', name: '个人设置'},
|
||||
{path: 'system', name: '系统设置'},
|
||||
{path: 'license', name: 'License Key'},
|
||||
],
|
||||
[{path: 'downloadClient', name: '客户端下载', visible: this.showDownloadClient}],
|
||||
[{path: 'version', name: '更新版本', visible: !!this.clientNewVersion}],
|
||||
[
|
||||
{path: 'allProject', name: '所有项目'},
|
||||
{path: 'archivedProject', name: '已归档的项目'},
|
||||
],
|
||||
[
|
||||
{path: 'team', name: '团队管理'},
|
||||
...departmentOwnerView,
|
||||
],
|
||||
)
|
||||
} else {
|
||||
array.push(...[
|
||||
{path: 'personal', name: '个人设置', divided: true},
|
||||
{path: 'downloadClient', name: '客户端下载', divided: true, visible: this.showDownloadClient},
|
||||
{path: 'version', name: '更新版本', divided: true, visible: !!this.clientNewVersion},
|
||||
|
||||
{path: 'workReport', name: '工作报告', divided: true},
|
||||
{path: 'archivedProject', name: '已归档的项目'},
|
||||
])
|
||||
groups.push(
|
||||
[{path: 'personal', name: '个人设置'}],
|
||||
[{path: 'downloadClient', name: '客户端下载', visible: this.showDownloadClient}],
|
||||
[{path: 'version', name: '更新版本', visible: !!this.clientNewVersion}],
|
||||
[
|
||||
{path: 'workReport', name: '工作报告', visible: systemFunctionEnabled('report')},
|
||||
{path: 'archivedProject', name: '已归档的项目'},
|
||||
],
|
||||
departmentOwnerView,
|
||||
)
|
||||
}
|
||||
if (this.departmentOwnerViewAvailable) {
|
||||
array.push({
|
||||
path: 'departmentOwnerView',
|
||||
name: '负责人视角',
|
||||
divided: !userIsAdmin,
|
||||
visible: true,
|
||||
selected: this.departmentOwnerProjectViewEnabled,
|
||||
selectedCount: this.departmentOwnerProjectViewEnabled ? this.cacheDepartmentOwnerIds.length : 0,
|
||||
});
|
||||
}
|
||||
array.push(...[
|
||||
{path: 'clearCache', name: '清除缓存', divided: true},
|
||||
groups.push([
|
||||
{path: 'clearCache', name: '清除缓存'},
|
||||
{path: 'logout', name: '退出登录', style: {color: '#f40'}}
|
||||
])
|
||||
const array = [];
|
||||
groups.forEach(group => {
|
||||
const items = group.filter(item => item.visible !== false);
|
||||
items.forEach((item, index) => {
|
||||
array.push(Object.assign({}, item, {divided: index === 0 && array.length > 0}));
|
||||
});
|
||||
});
|
||||
return array
|
||||
},
|
||||
|
||||
@ -913,6 +934,16 @@ export default {
|
||||
this.chackPass();
|
||||
},
|
||||
|
||||
// 日历被停用(或「系统功能」已卸载)时,不允许停留在日历页
|
||||
calendarDisabled: {
|
||||
handler(disabled) {
|
||||
if (disabled) {
|
||||
this.goForward({name: 'manage-dashboard'}, true);
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
|
||||
userInfo() {
|
||||
this.chackPass();
|
||||
},
|
||||
|
||||
@ -541,15 +541,16 @@ export default {
|
||||
...mapGetters([
|
||||
'filterMicroAppsMenus',
|
||||
'filterMicroAppsMenusAdmin',
|
||||
'systemFunctionEnabled',
|
||||
]),
|
||||
applyList() {
|
||||
const list = [
|
||||
// 常用应用
|
||||
{value: "favorite", label: "我的收藏", sort: 45},
|
||||
{value: "recent", label: "最近打开", sort: 47},
|
||||
{value: "report", label: "工作报告", sort: 50},
|
||||
{value: "favorite", label: "我的收藏", sort: 45, show: this.systemFunctionEnabled('favorite')},
|
||||
{value: "recent", label: "最近打开", sort: 47, show: this.systemFunctionEnabled('recent')},
|
||||
{value: "report", label: "工作报告", sort: 50, show: this.systemFunctionEnabled('report')},
|
||||
{value: "mybot", label: "我的机器人", sort: 55},
|
||||
{value: "signin", label: "签到打卡", sort: 70},
|
||||
{value: "signin", label: "签到打卡", sort: 70, show: this.systemFunctionEnabled('checkin')},
|
||||
{value: "meeting", label: "在线会议", sort: 80},
|
||||
{value: "createGroup", label: "创建群组", sort: 85},
|
||||
{value: "word-chain", label: "群接龙", sort: 90},
|
||||
@ -569,7 +570,7 @@ export default {
|
||||
// 竖屏模式
|
||||
if (this.windowPortrait) {
|
||||
list.push(...[
|
||||
{value: "calendar", label: "日历", sort: 10},
|
||||
{value: "calendar", label: "日历", sort: 10, show: this.systemFunctionEnabled('calendar')},
|
||||
{value: "file", label: "文件", sort: 20},
|
||||
{value: "setting", label: "设置", sort: 140},
|
||||
])
|
||||
@ -992,8 +993,10 @@ export default {
|
||||
const list = [
|
||||
{label: this.$L('导出任务统计'), value: 'task'},
|
||||
{label: this.$L('导出超期任务'), value: 'overdue'},
|
||||
{label: this.$L('导出签到数据'), value: 'checkin'},
|
||||
];
|
||||
if (this.systemFunctionEnabled('checkin')) {
|
||||
list.push({label: this.$L('导出签到数据'), value: 'checkin'});
|
||||
}
|
||||
this.$store.commit('menu/operation', {
|
||||
event: menuEvent,
|
||||
list,
|
||||
|
||||
8
resources/assets/js/store/actions.js
vendored
8
resources/assets/js/store/actions.js
vendored
@ -1206,7 +1206,8 @@ export default {
|
||||
'taskRelatedCache',
|
||||
'dialogCommonCountCache',
|
||||
'collaborationFileCache',
|
||||
'mcpServerStatus'
|
||||
'mcpServerStatus',
|
||||
'systemFunctions'
|
||||
]
|
||||
};
|
||||
|
||||
@ -5500,6 +5501,11 @@ export default {
|
||||
* @param dispatch
|
||||
*/
|
||||
async updateMicroAppsStatus({commit, state, dispatch}) {
|
||||
// 系统功能开关:不依赖应用商店接口,商店不可用时也能更新
|
||||
dispatch('call', {url: 'apps/functions'}).then(({data}) => {
|
||||
commit("systemFunctions/save", data?.functions)
|
||||
}).catch(() => {})
|
||||
//
|
||||
const {data: {code, data}} = await axios.get($A.mainUrl('appstore/api/v1/internal/installed'), {
|
||||
headers: {
|
||||
Token: state.userToken,
|
||||
|
||||
11
resources/assets/js/store/getters.js
vendored
11
resources/assets/js/store/getters.js
vendored
@ -308,6 +308,17 @@ export default {
|
||||
return state.cacheDialogs.filter(dialog => !$A.isAiBotDialog(dialog))
|
||||
},
|
||||
|
||||
/**
|
||||
* 系统功能是否启用(「系统功能」应用未安装或该功能被停用时为 false)
|
||||
* 工作报告、日历、我的收藏、最近打开、签到打卡的所有入口统一以此判断
|
||||
*
|
||||
* @param {Object} state
|
||||
* @returns {function(string): boolean} 参数为功能标识:report/calendar/favorite/recent/checkin
|
||||
*/
|
||||
systemFunctionEnabled: (state) => (name) => {
|
||||
return state.systemFunctions?.[name] === true
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取应用菜单
|
||||
* 过滤出location为application的菜单项
|
||||
|
||||
@ -122,10 +122,11 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* 父『应用』入口聚合数字:工作报告未读 + 所有插件角标数字之和
|
||||
* 父『应用』入口聚合数字:工作报告未读(功能启用时)+ 所有插件角标数字之和
|
||||
*/
|
||||
applicationCount: (state, getters, rootState) => {
|
||||
return (Number(rootState.reportUnreadNumber) || 0) + getters.totalCount
|
||||
applicationCount: (state, getters, rootState, rootGetters) => {
|
||||
const reportCount = rootGetters.systemFunctionEnabled('report') ? (Number(rootState.reportUnreadNumber) || 0) : 0
|
||||
return reportCount + getters.totalCount
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
9
resources/assets/js/store/mutations.js
vendored
9
resources/assets/js/store/mutations.js
vendored
@ -463,6 +463,10 @@ export default {
|
||||
// 更新菜单
|
||||
const menus = [];
|
||||
data.forEach((item) => {
|
||||
// 「系统功能」只控制内置入口的显示,自身不产生应用菜单,避免与内置入口重复
|
||||
if (item.id === 'system-functions') {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(item.menu_items) && item.menu_items.length > 0) {
|
||||
menus.push(...item.menu_items.map(menu => Object.assign({}, menu, {id: item.id})));
|
||||
}
|
||||
@ -483,6 +487,11 @@ export default {
|
||||
$A.IDBSave("microAppsMenus", state.microAppsMenus = menus);
|
||||
},
|
||||
|
||||
// 系统功能开关
|
||||
'systemFunctions/save': function(state, data) {
|
||||
$A.IDBSave("systemFunctions", state.systemFunctions = $A.isJson(data) ? data : {});
|
||||
},
|
||||
|
||||
// MCP 服务器状态
|
||||
'mcp/server/status': function(state, data) {
|
||||
$A.IDBSave("mcpServerStatus", state.mcpServerStatus = data);
|
||||
|
||||
3
resources/assets/js/store/state.js
vendored
3
resources/assets/js/store/state.js
vendored
@ -301,6 +301,9 @@ export default {
|
||||
microAppsIds: [],
|
||||
microAppsMenus: [],
|
||||
|
||||
// 系统功能开关(「系统功能」应用,功能标识 => 是否启用;未安装时全部为 false)
|
||||
systemFunctions: {},
|
||||
|
||||
// MCP 服务器状态
|
||||
mcpServerStatus: {running: 'stopped'},
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
> 此文件由 `php artisan doc:api-map` 生成,勿手改。
|
||||
|
||||
接口总数:329
|
||||
接口总数:330
|
||||
|
||||
## 路由规则
|
||||
|
||||
@ -420,6 +420,7 @@ API 使用动态路由(见 `routes/web.php`),URL 段映射为控制器方
|
||||
| api/apps/badge/set | badge__set() | post | 设置角标(应用密钥鉴权) |
|
||||
| api/apps/badge/clear | badge__clear() | post | 清除角标(当前用户 token 鉴权) |
|
||||
| api/apps/badge/list | badge__list() | get | 拉取自己全部角标 |
|
||||
| api/apps/functions | functions() | get | 获取系统功能开关 |
|
||||
|
||||
## test(TestController)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user