t13:前端换形——audience 数组多选 + 冻结/匿名窗口开关,fillable 行去 canFill/myTier

- types/form.ts:AUDIENCE 改字符串码闭集(含 ANONYMOUS)+ audienceText();
  FormView/FormConfigRequest 加 audience 数组、frozen、anonCookieMinutes
- types/data.ts:FillableForm 去 canFill/myTier(C2,入集即可填);
  DATA_SCOPE_LABELS 由四枚举改两档(ALL/SELF,§19 作废-1)
- FormConfigModal:面向人群改复选组(多选共集)+ 冻结开关(文案指路"喂外部业务应用的表单请开启")
  + 匿名防重窗口;含 ANONYMOUS 时限次置灰并在提交前挡(与后端同判据)
- Forms.vue 面向列、My.vue「可填写」卡集、fill.ts/routes.ts 注记同步换形
- AppContext.vue:填报 tab 直接吃入集行;数据/统计两档的驱动位改由 T14 的 managed 端点接,
  本批不留"按 myTier 猜"的兼容分支(壳零自有权限逻辑)
- mock:formapi/dataapi 的 audience 数组形态 + 匿名×限次跨字段约束
This commit is contained in:
chenxing
2026-10-20 12:54:26 +08:00
parent 25dc3eb2e5
commit 4a7db3d22c
11 changed files with 174 additions and 88 deletions
+11 -14
View File
@@ -41,20 +41,17 @@ const rawTree = ref<IModule[]>([]);
const loading = ref(false);
const errorText = ref("");
/** 填报 tab 的行:后端 canFill 判定(层②"只能代填"的行 canFill=false,不进这张列表) */
const fillCards = computed(() => fillRows.value.filter((r) => r.canFill));
/** 数据管理候选=层②∪层③;统计候选=层③(与后端 FillAccessService 的三个谓词一一对应) */
const manageRows = computed(() => fillRows.value.filter((r) => r.myTier === "MANAGE" || r.myTier === "ADMIN"));
const adminRows = computed(() => fillRows.value.filter((r) => r.myTier === "ADMIN"));
function codesOf(rows: FillableForm[]): string[] {
const codes: string[] = [];
for (const row of rows) if (!codes.includes(row.code)) codes.push(row.code);
return codes;
}
const dataCodes = computed(() => codesOf(manageRows.value));
const statsCodes = computed(() => codesOf(adminRows.value));
/** 填报 tab 的行:契约 v2 C2 之后入集即等价于可填(行里没有 canFill,前端不再筛) */
const fillCards = computed(() => fillRows.value);
/**
* 数据管理/统计两档的驱动位在 T13 这一批处于<b>换轨空窗</b>:
* 原驱动是 P95 的 `myTier`(三层模型的最高层),随 §19 作废-3 一起删掉了;
* 新驱动是 T14 的 `GET /api/form/my/managed`(创建人 ∪ form_admin 的"我管理的表单")。
* 本批同一次执行内就会接上,空窗期这两档不出现在壳上——<b>刻意不留"按 myTier 猜"的兼容分支</b>,
* 免得留下第二套判定口径(红线:壳零自有权限逻辑)。
*/
const dataCodes = computed<string[]>(() => []);
const statsCodes = computed<string[]>(() => []);
const showDataTab = computed(() => dataCodes.value.length > 0);
const showStatsTab = computed(() => statsCodes.value.length > 0);