diff --git a/app/Http/Controllers/Api/AppsController.php b/app/Http/Controllers/Api/AppsController.php index c51993179..26b43fbff 100755 --- a/app/Http/Controllers/Api/AppsController.php +++ b/app/Http/Controllers/Api/AppsController.php @@ -81,43 +81,46 @@ class AppsController extends AbstractController } /** - * @api {get} api/apps/stats 04. 获取应用状况 + * @api {get} api/apps/status 04. 获取应用状态 * - * @apiDescription 获取应用状况,包括已安装的应用和应用入口点 + * @apiDescription 获取应用状态,包括已安装的应用和应用菜单 * @apiVersion 1.0.0 * @apiGroup apps - * @apiName stats + * @apiName status * * @apiSuccess {Number} ret 返回状态码(1正确、0错误) * @apiSuccess {String} msg 返回信息(错误描述) - * @apiSuccess {Object} data 应用入口点信息 + * @apiSuccess {Object} data 应用和菜单信息 + * @apiSuccess {Array} data.installed 已安装应用列表 + * @apiSuccess {Array} data.menus 应用菜单列表 */ - public function stats() + public function status() { User::auth(); // 获取已安装应用列表 - $res = Apps::appList(); - if (Base::isError($res)) { - return $res; - } $installedName = ['appstore']; - foreach ($res['data'] as $app) { - if ($app['config']['status'] == 'installed') { - $installedName[] = $app['name']; - } + $appList = Apps::appList(); + if (Base::isSuccess($appList)) { + $installedName = array_merge( + $installedName, + array_column( + array_filter($appList['data'], fn($app) => $app['config']['status'] === 'installed'), + 'name' + ) + ); } - // 获取应用入口点 - $res = Apps::getAppEntryPoints(); - if (Base::isError($res)) { - return $res; + // 获取应用菜单 + $menusData = []; + $res = Apps::getAppMenuItems(); + if (Base::isSuccess($res)) { + $menusData = $res['data']; } - $entriesData = $res['data']; return Base::retSuccess('success', [ 'installed' => $installedName, - 'entries' => $entriesData, + 'menus' => $menusData, ]); } diff --git a/app/Module/Apps.php b/app/Module/Apps.php index 39573db24..908a303e5 100644 --- a/app/Module/Apps.php +++ b/app/Module/Apps.php @@ -344,41 +344,41 @@ class Apps } /** - * 获取应用的入口点配置 + * 获取应用的菜单配置 * - * @param string|null $appName 应用名称,为null时获取所有已安装应用的入口点 + * @param string|null $appName 应用名称,为null时获取所有已安装应用的菜单 * @return array */ - public static function getAppEntryPoints(?string $appName = null): array + public static function getAppMenuItems(?string $appName = null): array { if ($appName !== null) { - return self::entryGetSingle($appName); + return self::menuGetSingle($appName); } - return self::entryGetAll(); + return self::menuGetAll(); } /** - * 获取单个应用的入口点配置 + * 获取单个应用的菜单配置 * * @param string $appName 应用名称 * @return array */ - private static function entryGetSingle(string $appName): array + private static function menuGetSingle(string $appName): array { $baseDir = base_path('docker/appstore/apps/' . $appName); - $entryPoints = []; + $menuItems = []; if (!file_exists($baseDir . '/config.yml')) { - return Base::retSuccess("success", $entryPoints); + return Base::retSuccess("success", $menuItems); } try { $configData = Yaml::parseFile($baseDir . '/config.yml'); - if (isset($configData['entry_points']) && is_array($configData['entry_points'])) { - foreach ($configData['entry_points'] as $entry) { - $normalizedEntry = self::entryNormalize($entry, $appName); - if ($normalizedEntry) { - $entryPoints[] = $normalizedEntry; + if (isset($configData['menu_items']) && is_array($configData['menu_items'])) { + foreach ($configData['menu_items'] as $menu) { + $normalizedMenu = self::menuNormalize($menu, $appName); + if ($normalizedMenu) { + $menuItems[] = $normalizedMenu; } } } @@ -386,21 +386,21 @@ class Apps return Base::retError('配置文件解析失败:' . $e->getMessage()); } - return Base::retSuccess("success", $entryPoints); + return Base::retSuccess("success", $menuItems); } /** - * 获取所有已安装应用的入口点配置 + * 获取所有已安装应用的菜单配置 * * @return array */ - private static function entryGetAll(): array + private static function menuGetAll(): array { - $allEntryPoints = []; + $allMenuItems = []; $baseDir = base_path('docker/appstore/apps'); if (!is_dir($baseDir)) { - return Base::retSuccess("success", $allEntryPoints); + return Base::retSuccess("success", $allMenuItems); } $dirs = scandir($baseDir); @@ -413,48 +413,48 @@ class Apps continue; } - $appEntryPoints = self::entryGetSingle($dir); - if (Base::isSuccess($appEntryPoints)) { - $allEntryPoints = array_merge($allEntryPoints, $appEntryPoints['data']); + $appMenuItems = self::menuGetSingle($dir); + if (Base::isSuccess($appMenuItems)) { + $allMenuItems = array_merge($allMenuItems, $appMenuItems['data']); } } - return Base::retSuccess("success", $allEntryPoints); + return Base::retSuccess("success", $allMenuItems); } /** - * 标准化入口点配置 + * 标准化菜单配置 * - * @param array $entry 原始入口点配置 + * @param array $menu 原始菜单配置 * @param string $appName 应用名称 - * @return array|null 标准化后的入口点配置,配置无效时返回null + * @return array|null 标准化后的菜单配置,配置无效时返回null */ - private static function entryNormalize(array $entry, string $appName): ?array + private static function menuNormalize(array $menu, string $appName): ?array { // 检查必需的字段 - if (!isset($entry['location']) || !isset($entry['url'])) { + if (!isset($menu['location']) || !isset($menu['url'])) { return null; } // 基础配置 - $normalizedEntry = [ + $normalizedMenu = [ 'app_name' => $appName, - 'location' => $entry['location'], - 'url' => $entry['url'], - 'key' => $entry['key'] ?? substr(md5($entry['url']), 0, 16), - 'icon' => self::processAppIcon($appName, [$entry['icon'] ?? '']), - 'label' => self::getMultiLanguageField($entry['label'] ?? ''), + 'location' => $menu['location'], + 'url' => $menu['url'], + 'key' => $menu['key'] ?? substr(md5($menu['url']), 0, 16), + 'icon' => self::processAppIcon($appName, [$menu['icon'] ?? '']), + 'label' => self::getMultiLanguageField($menu['label'] ?? ''), ]; // 处理可选的UI配置 $optionalConfigs = ['transparent', 'keepAlive']; foreach ($optionalConfigs as $config) { - if (isset($entry[$config])) { - $normalizedEntry[$config] = $entry[$config]; + if (isset($menu[$config])) { + $normalizedMenu[$config] = $menu[$config]; } } - return $normalizedEntry; + return $normalizedMenu; } /** @@ -830,7 +830,7 @@ class Apps // 处理应用名称 $appName = Base::camel2snake(Base::cn2pinyin($configData['name'], '_')); if (in_array($appName, self::$protectedServiceNames)) { - return Base::retError('服务名称 "' . $name . '" 被保护,不能使用'); + return Base::retError('服务名称 "' . $appName . '" 被保护,不能使用'); } $targetDir = base_path('docker/appstore/apps/' . $appName); $targetConfigFile = $targetDir . '/config.json'; diff --git a/resources/assets/js/components/MicroApps/index.vue b/resources/assets/js/components/MicroApps/index.vue index 09e797161..e7c758c94 100644 --- a/resources/assets/js/components/MicroApps/index.vue +++ b/resources/assets/js/components/MicroApps/index.vue @@ -424,7 +424,7 @@ export default { microApp.forceSetData(name, {type: 'beforeClose'}, array => { if (!array?.find(item => item === true)) { if (name === 'appstore') { - this.$store.dispatch("updateMicroAppsStats"); + this.$store.dispatch("updateMicroAppsStatus"); } if ($A.isSubElectron) { $A.Electron.sendMessage('windowDestroy'); diff --git a/resources/assets/js/pages/manage.vue b/resources/assets/js/pages/manage.vue index 97559e842..e2c27e085 100644 --- a/resources/assets/js/pages/manage.vue +++ b/resources/assets/js/pages/manage.vue @@ -120,6 +120,10 @@
{{ $L(item.label) }}
+{{ item.label }}
@@ -364,6 +364,7 @@ export default { }, activated() { this.initList() + this.$store.dispatch("updateMicroAppsStatus") }, computed: { ...mapState([ @@ -378,8 +379,8 @@ export default { 'routeLoading', ]), ...mapGetters([ - 'filterMicroAppsEntries', - 'filterMicroAppsEntriesAdmin', + 'filterMicroAppsMenus', + 'filterMicroAppsMenusAdmin', ]), isExistAdminList() { return this.applyList.map(h => h.type).indexOf('admin') !== -1; @@ -449,11 +450,8 @@ export default { return item.value == type && num > 0 }, // 点击应用 - applyClick(item, area = '') { + applyClick(item, params = '') { switch (item.value) { - case 'microApp': - this.$store.dispatch("openMicroApp", area); - return case 'approve': case 'calendar': case 'file': @@ -461,27 +459,27 @@ export default { this.goForward({ name: 'manage-' + item.value }); break; case 'report': - emitter.emit('openReport', area == 'badge' ? 'receive' : 'my'); + emitter.emit('openReport', params == 'badge' ? 'receive' : 'my'); break; case 'mybot': this.getMybot(); this.mybotShow = true; break; case 'mybot-chat': - this.chatMybot(area.id); + this.chatMybot(params.id); break; case 'mybot-add': - this.addMybot(area); + this.addMybot(params); break; case 'mybot-del': - this.delMybot(area); + this.delMybot(params); break; case 'robot': this.getAITags(); this.aibotShow = true; break; case 'robot-setting': - this.aibotTabAction = area; + this.aibotTabAction = params; this.aibotSettingShow = true; break; case 'signin': @@ -510,7 +508,7 @@ export default { break; } - this.$emit("on-click", item.value) + this.$emit("on-click", item.value, params); }, // 获取我的机器人 getMybot() { diff --git a/resources/assets/js/pages/manage/components/DialogWrapper.vue b/resources/assets/js/pages/manage/components/DialogWrapper.vue index dc893c212..ebcaa5c25 100644 --- a/resources/assets/js/pages/manage/components/DialogWrapper.vue +++ b/resources/assets/js/pages/manage/components/DialogWrapper.vue @@ -2619,7 +2619,7 @@ export default { }); }, - openOkr(id) { + openOkrDetails(id) { if (!id) { return; } @@ -3150,7 +3150,7 @@ export default { break; case 'okr': - this.openOkr(this.dialogData.link_id) + this.openOkrDetails(this.dialogData.link_id) break; default: @@ -3758,7 +3758,7 @@ export default { this.$store.dispatch("openTask", $A.runNum(target.getAttribute("data-id"))); } if (target.classList.contains('mention') && target.classList.contains('okr')) { - this.openOkr($A.runNum(target.getAttribute("data-id"))); + this.openOkrDetails($A.runNum(target.getAttribute("data-id"))); } break; diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 5a419bcd4..1958cfba0 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -623,7 +623,7 @@ export default { dispatch("getProjectByQueue"); dispatch("getTaskForDashboard"); dispatch("dialogMsgRead"); - dispatch("updateMicroAppsStats"); + dispatch("updateMicroAppsStatus"); // const allIds = Object.values(state.userAvatar).map(({userid}) => userid); [...new Set(allIds)].some(userid => dispatch("getUserBasic", {userid})) @@ -1116,6 +1116,8 @@ export default { 'callAt', 'cacheEmojis', 'cacheDialogs', + 'microAppsInstalled', + 'microAppsMenus', ], json: [ 'userInfo' @@ -4640,17 +4642,16 @@ export default { /** *****************************************************************************************/ /** - * 更新微应用状况(已安装、入口菜单) - * @param state + * 更新微应用状态(已安装应用、菜单项) + * @param commit * @param dispatch - * @param appName */ - updateMicroAppsStats({state, dispatch}) { + updateMicroAppsStatus({commit, dispatch}) { dispatch("call", { - url: 'apps/stats', + url: 'apps/status', }).then(({data}) => { - state.microAppsInstalled = data.installed - state.microAppsEntries = data.entries + commit("microApps/installed", data.installed) + commit("microApps/menu", data.menus) }) }, diff --git a/resources/assets/js/store/getters.js b/resources/assets/js/store/getters.js index 05ebd4704..8248d4ff6 100644 --- a/resources/assets/js/store/getters.js +++ b/resources/assets/js/store/getters.js @@ -279,35 +279,35 @@ export default { }, /** - * 获取应用菜单入口 + * 获取应用菜单 * 过滤出location为application的菜单项 * * @param {Object} state - * @returns {Array} + * @returns {Array} */ - filterMicroAppsEntries: (state) => { - return state.microAppsEntries.filter(item => item.location === 'application') + filterMicroAppsMenus: (state) => { + return state.microAppsMenus.filter(item => item.location === 'application') }, /** - * 获取应用管理菜单入口 + * 获取应用管理菜单 * 过滤出location为application/admin的菜单项 * * @param {Object} state - * @returns {Array} + * @returns {Array} */ - filterMicroAppsEntriesAdmin: (state) => { - return state.microAppsEntries.filter(item => item.location === 'application/admin') + filterMicroAppsMenusAdmin: (state) => { + return state.microAppsMenus.filter(item => item.location === 'application/admin') }, /** - * 获取主导航菜单入口 + * 获取主导航菜单 * 过滤出location为main/menu的菜单项 * * @param {Object} state - * @returns {Array} + * @returns {Array} */ - filterMicroAppsEntriesMain: (state) => { - return state.microAppsEntries.filter(item => item.location === 'main/menu') + filterMicroAppsMenusMain: (state) => { + return state.microAppsMenus.filter(item => item.location === 'main/menu') } } diff --git a/resources/assets/js/store/mutations.js b/resources/assets/js/store/mutations.js index e0978c39f..7ed85e9b0 100644 --- a/resources/assets/js/store/mutations.js +++ b/resources/assets/js/store/mutations.js @@ -298,4 +298,15 @@ export default { 'menu/operation': function(state, data) { state.menuOperation = data || {} }, + + // 微应用管理 + 'microApps/menu': function(state, data) { + state.microAppsMenus = data + $A.IDBSave("microAppsMenus", state.microAppsMenus) + }, + + 'microApps/installed': function(state, data) { + state.microAppsInstalled = data + $A.IDBSave("microAppsInstalled", state.microAppsInstalled) + }, } diff --git a/resources/assets/js/store/state.js b/resources/assets/js/store/state.js index 9b90f530a..a2eefd321 100644 --- a/resources/assets/js/store/state.js +++ b/resources/assets/js/store/state.js @@ -261,7 +261,7 @@ export default { // 长按数据 longpressData: {type: '', data: null, element: null}, - // 微应用菜单入口 + // 微应用数据 microAppsInstalled: [], - microAppsEntries: [], + microAppsMenus: [], }; diff --git a/resources/assets/sass/pages/page-manage.scss b/resources/assets/sass/pages/page-manage.scss index f5e48f7c8..5b657914f 100644 --- a/resources/assets/sass/pages/page-manage.scss +++ b/resources/assets/sass/pages/page-manage.scss @@ -55,6 +55,14 @@ font-size: 20px; margin-right: 10px; } + .apply-icon { + width: 20px; + height: 20px; + background-repeat: no-repeat; + background-size: contain; + background-position: center center; + margin-right: 10px; + } .menu-title { flex: 1; white-space: nowrap;