fix(application): 自定义应用可见范围统一 app 顶层,修复全员可见失效与编辑回填重置

前后端对 visible_to 存放层级约定不一致导致两个 bug:
- 新增应用设为全员可见,普通成员仍看不到(前端存在 menu 级,后端只认 app 级,落库恒回落为 admin)
- 再次编辑时可见范围被重置为"仅管理员"(响应无条件剥离 visible_to,回填丢失)

统一以 app 顶层为唯一权威来源:
- 前端保存时提到 app 顶层,回填时从 app 顶层读回(数组转下拉框字符串)
- 后端响应新增 keepVisible,管理员保存/读取场景保留 visible_to,普通成员仍剥离

同步 ai-kb application/menu-admin last_verified。
This commit is contained in:
kuaifan 2026-07-13 23:54:23 +00:00
parent e72758f313
commit 9b14120055
4 changed files with 18 additions and 7 deletions

View File

@ -778,14 +778,14 @@ class SystemController extends AbstractController
} }
$apps = Setting::normalizeCustomMicroApps($list); $apps = Setting::normalizeCustomMicroApps($list);
$setting = Base::setting('microapp_menu', $apps); $setting = Base::setting('microapp_menu', $apps);
$setting = Setting::formatCustomMicroAppsForResponse($setting); $setting = Setting::formatCustomMicroAppsForResponse($setting, true);
} else { } else {
$setting = Base::setting('microapp_menu'); $setting = Base::setting('microapp_menu');
if (!is_array($setting)) { if (!is_array($setting)) {
$setting = []; $setting = [];
} }
$setting = Setting::filterCustomMicroAppsForUser($setting, $user); $setting = Setting::filterCustomMicroAppsForUser($setting, $user);
$setting = Setting::formatCustomMicroAppsForResponse($setting); $setting = Setting::formatCustomMicroAppsForResponse($setting, $user && $user->isAdmin());
} }
return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting); return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting);
} }

View File

@ -358,12 +358,17 @@ class Setting extends AbstractModel
/** /**
* 将存储结构转换成 appstore 接口同款格式 * 将存储结构转换成 appstore 接口同款格式
* @param array $apps * @param array $apps
* @param bool $keepVisible 是否保留可见范围(仅管理员编辑场景需要,用于回填)
* @return array * @return array
*/ */
public static function formatCustomMicroAppsForResponse(array $apps) public static function formatCustomMicroAppsForResponse(array $apps, bool $keepVisible = false)
{ {
return array_values(array_map(function ($app) { return array_values(array_map(function ($app) use ($keepVisible) {
unset($app['visible_to']); if ($keepVisible) {
$app['visible_to'] = self::normalizeCustomMicroVisible($app['visible_to'] ?? ['admin']);
} else {
unset($app['visible_to']);
}
if (!empty($app['menu_items']) && is_array($app['menu_items'])) { if (!empty($app['menu_items']) && is_array($app['menu_items'])) {
$app['menu_items'] = array_values(array_map(function ($menu) { $app['menu_items'] = array_values(array_map(function ($menu) {
$menu['keep_alive'] = isset($menu['keep_alive']) ? (bool)$menu['keep_alive'] : true; $menu['keep_alive'] = isset($menu['keep_alive']) ? (bool)$menu['keep_alive'] : true;

View File

@ -19,7 +19,7 @@ negative:
- 仅管理员可见入口和保存接口 - 仅管理员可见入口和保存接口
- 自定义菜单只是注册一个 URL/iframe 入口DooTask 不托管业务页面 - 自定义菜单只是注册一个 URL/iframe 入口DooTask 不托管业务页面
- 配置项里没有"权限继承项目角色"的开关 - 配置项里没有"权限继承项目角色"的开关
last_verified: v1.7.90 last_verified: v1.8.64
--- ---
# 管理员自定义全员应用菜单 # 管理员自定义全员应用菜单

View File

@ -659,9 +659,14 @@ export default {
} }
return list.map(app => { return list.map(app => {
const draft = createCustomMicroMenu(); const draft = createCustomMicroMenu();
return Object.assign({}, draft, app, { const merged = Object.assign({}, draft, app, {
menu: Object.assign({}, draft.menu, $A.isArray(app.menu_items) && app.menu_items.length > 0 ? app.menu_items[0] : {}), menu: Object.assign({}, draft.menu, $A.isArray(app.menu_items) && app.menu_items.length > 0 ? app.menu_items[0] : {}),
}); });
// app admin/all
merged.menu.visible_to = $A.isArray(app.visible_to)
? (app.visible_to.includes('all') ? 'all' : 'admin')
: (app.visible_to || 'admin');
return merged;
}); });
}, },
pickCustomMenuLabel(label, fallback = '') { pickCustomMenuLabel(label, fallback = '') {
@ -739,6 +744,7 @@ export default {
id, id,
name: (item.name || '').trim(), name: (item.name || '').trim(),
version: item.version || 'custom', version: item.version || 'custom',
visible_to: item.menu.visible_to || 'admin',
menu_items: [Object.assign({}, item.menu, { url, label })], menu_items: [Object.assign({}, item.menu, { url, label })],
}; };
}, },