Files
form-center-front/src/views/admin/AppSettings.vue
T
chenxing 531f7641fb t16:快应用注册表入口——系统设置第三个 tab(注册/改名/复制入口链接/删除)
- api/module/apps.ts:C17 四端点,寻址一律按 appCode(库内 id 不外露,V5)。
- types/data.ts 增 AppRow(四业务字段 + entryUrl);无角色/授权字段(V59 的界面侧表达)。
- views/admin/Apps.vue:注册(C10 格式与保留字做即时预检,但保存失败以后端 msg 为准并留在弹窗里)、
  改名(code 不随改,输入框禁用)、复制应用入口(后端给站内路径,前端补 origin,生产/本地都能点开)、
  删除(在用禁删与"编码不复用"两类拒绝一律原样提示,前端不复制规则,同 AdminListPanel 口径)。
  页面上没有任何"给这个应用配谁能用"的入口——那是有意的。
- AppSettings.vue:tab 值改闭集判定(roles/apps/dicts),?tab=apps 可深链;
  入口本身仍由 capabilities.schoolAdmin 决定(S3 第三支路),不做"进了页再藏 tab"。

门禁:npx vue-tsc --noEmit exit 0;npm run build ✓ built in 12.16s。
2026-10-20 14:30:28 +08:00

66 lines
2.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
/**
* 应用设置(`/admin/app`,T10 方案 §3/§6.1):一行模块位置,页内三个 tab。
*
* - **角色设置** = 校级表单管理员名单(`school_admin`);
* - **快应用** = app 注册表(契约 v2 §5.2/C17,T16;零角色列,入口链接由中心生成);
* - **字典管理** = 原 `/admin/dicts` 整页迁入(`Dicts.vue` 原样复用,守卫行随本行换到 `/admin/app`)。
*
* 三条口径:
* 1. **tab 不占模块行、不进导航**(同设计器子页),所以高亮/面包屑挂本行;`?tab=dicts|apps` 可深链,
* 旧地址 `/admin/dicts` 由路由重定向到这里的字典 tab;
* ——深链落在模板的 {@code :model-value} 上:view-ui-plus 的 Tabs 受控 prop 是 modelValue,
* 写 {@code :value} 会落进 attrs 不被消费(T10 验收轮实拍证伪过一次),勿"顺手改回";
* 2. 不在闭集里的 tab 值一律回落缺省(角色设置),与 {@code Fill.vue} 的 mode 白名单同一条写法;
* 3. **一行把关三个 tab 与全部维护 API**:能不能进来由 capabilities.schoolAdmin(契约 v2 §2.4 第三支路)
* 决定,前端不做"进了页再按身份藏 tab"——藏按钮不等于授权(契约 §7 身份行)。
*/
import { computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import AdminListPanel from "@/components/admin/AdminListPanel.vue";
import Apps from "./Apps.vue";
import Dicts from "./Dicts.vue";
const route = useRoute();
const router = useRouter();
const TABS = ["roles", "apps", "dicts"] as const;
/** 缺省落角色设置;只认闭集内的值,其它 query 一律按缺省 */
const tab = computed(() => {
const raw = String(route.query.tab ?? "");
return (TABS as readonly string[]).includes(raw) ? raw : "roles";
});
function change(next: string) {
router.replace({ path: "/admin/app", query: { ...route.query, tab: next } });
}
</script>
<template>
<div class="page-wrapper yh-fill">
<div class="main-container">
<Tabs :model-value="tab" @on-click="change">
<TabPane label="角色设置" name="roles">
<AdminListPanel mode="school" />
</TabPane>
<TabPane label="快应用" name="apps">
<Apps />
</TabPane>
<TabPane label="字典管理" name="dicts">
<Dicts />
</TabPane>
</Tabs>
</div>
</div>
</template>
<style scoped>
/* 迁入的字典页原本是一整页(自带 page-wrapper 的填充高度),嵌进 tab 后高度要交回内容本身,
否则 yh-fill 会把 tab 面板撑成视口高、列表区跟着溢出滚动条。 */
:deep(.page-wrapper.yh-fill) {
height: auto;
padding: 0;
}
</style>