跨端: harmony 管理页(用户管理)+ P4c 壁纸上传入口 —— 「功能做全再交付」的两块
pi 的交付清单里缺的两块(`docs/GUI-PLAN-HARMONY.md` 原先把管理后台划在首版之外, 用户明确要求「功能做全再给我」之后收进来)。 标 `跨端:` 是因为本次的判据落在 `client/electron/test/`(鸿蒙的判据目录一向量在那里), 代码本体全在 `client/harmony/`。 ## 管理页(用户管理) - `pages/AdminUsersPage.ets`:新建 / 编辑(显示名·角色·白名单)/ 启停 / 重置密码。 排布照 `AdminUsersPage.tsx`,包括「受限」徽标的口径(普通用户且白名单非空才显示)、 最后登录缺席与空串都显示「从未登录」、管理员对白名单两项忽略。 - 入口在设置页底部,**仅管理员可见**(`role === 'admin'` 严格相等,与 `App.tsx` 同口径)。 读不到身份时**不**显示也不报错(乐观放行会让每个普通用户看到一个点进去 403 的入口)。 - `api/AdminApi.ets` + `model/AdminUsers.ts`(纯逻辑,零 import ⇒ 判据能真跑)。 - 启停**只发 status 一个字段** —— 服务端是部分更新,多发字段会把显示名与白名单一起改掉。 - `model/Models.ets` 补管理端 DTO;`main_pages.json` 注册路由。 ## P4c 壁纸上传 - `model/ImagePrep.ts`:阈值与两档策略(2560/0.85 → 1280/0.78,入口 20MB,压后上限 3.5MiB)。 **一处有意不对齐 WebUI** 并写明理由:WebUI 卡 data-URL 长度(含 base64 膨胀), 鸿蒙内存直传 ArrayBuffer,卡的是字节数。 - `common/BackgroundPicker.ets`:不设 / 预设 / 自定义图片 + 浓度与模糊滑杆。 上传链:picker → 判可不可以 → 逐档按 desiredSize 解码压缩 → 上传 → **请页面以服务端为准重新同步**。 失败**必带原因**(服务端 415/413 文案原样透出)。 - `ApiClient.uploadBytes`:MultiFormData.data 收 ArrayBuffer(核了 SDK,since 11;本工程 23) ⇒ 内存直传,不需要 base64、也不需要临时文件。 - 用户取消选图**不算失败**,什么都不说。 ## 顺带修掉的两处真问题(都是变异测试逼出来的) 1. **压缩循环的第二档此前是死代码**:循环里的 break 与循环外那句 shouldRetryWithActual 互相抵消 —— 把循环里那处改成 `if (true)`(永远只压一档)整套判据照样全绿。 收成一处判定(overLimit),循环外只读结论。 2. **壁纸的模糊档一直是「只写不读」**(计划文档 §7.12 登记过):滑杆能拖、值能存、 blurStyleFor 也写了,就是**没有调用点**,壁纸一点没糊。本次补上调用点 (壁纸层 .blur(px) = 图片内容模糊;导航条材质由 blurStyleFor 映射)。 同时按 §7.12 的原承诺更新了那一行。 ## 一并修正的旧判据(都是"太宽/太窄",不是放宽标准) - 「模糊归属」:原文「壁纸层不许有**任何**模糊调用」把**图片内容模糊**与**面板材质** 混为一谈(WebUI 侧核实:.app-backdrop 的 filter 与它之上那层的 backdrop-filter 是两个不同的量)⇒ 改成按两种模糊分别钉。 - 「bgBlur 只写不读,消费侧必须为 0」:值不再成立,**形状保留**(逐文件登记 + 计数 + 理由), 标题与断言里的假话一并改掉。 - isDarkMode 那条 `/dark\s*\)/` 断的是**参数顺序**(加一个入参就误红)⇒ 改成"dark 在实参里"。 - 导航材质三处断言原本钉 `Theme.navMaterial` 字面量 ⇒ 改成钉新的映射写法。 ## 判据 新增 `harmony-admin.test.mjs`(22 条)、`harmony-imageprep.test.mjs`(29 条); `harmony-presets.test.mjs` 加 1 条(模糊档搬运与归一,含 -0 那个洞)。 全量 203 条:**201 通过**,2 条失败为**改动前就红**的既有项 (BUILD_INFO 比对、词表↔余额)—— 用 stash 对照验证过。 两个新判据文件上跑了 **48 个变异体,全部被抓**(含"接线"类:删掉「受限」徽标、 组件自己宣布成功、release 不 await、按原图尺寸解码…), 其中 2 个变异体**红不了**,因此又补了 5 条判据(纯逻辑接线、退档判定只有一处、 两档都超限必拒、解码尺寸用的是目标尺寸而非原图尺寸、模糊档搬运)。 (数字口径:按 runner 的真实条件"锚点恰好命中 1 次才算跑过"统计; 另有 4 条锚点不命中、根本没跑,不算在这 48 里。我第一次写的是"40"—— 凭记忆累加的,错了,已更正。) **未验**:本机无设备/无模拟器 ⇒ 全部观感未验(管理页排版、滑杆手感、模糊在真机上的 实际档位观感)。代码齐 ≠ 真机验过。
This commit is contained in:
@ -238,6 +238,23 @@ export class BackgroundPlan {
|
||||
*/
|
||||
presetSubstitutedFrom: string = '';
|
||||
layers: PresetLayer[] = [];
|
||||
/**
|
||||
* 模糊强度(**服务端给的 px 原值**,0~40;由 `model/Appearance.ts` 的 `blurStyleFor`
|
||||
* 映射成系统材质档)。
|
||||
*
|
||||
* ★ 为什么这里放的是 px 而不是"材质档字符串":这一层是**纯逻辑**(零 `@ohos` 依赖),
|
||||
* 而"px → 材质档"那张表的**唯一**权威在 `Appearance.ts`(它连同边界 0/8/20
|
||||
* 一起被判据钉住)。在这里再抄一份分档,就会有两张表 —— 而两张表迟早会分叉。
|
||||
* ⇒ 计划只**搬运**这个值,页面拿它去问 `blurStyleFor`。
|
||||
*
|
||||
* ★ 为什么现在才有人消费它:服务端那个模糊字段一直是"**只写不读**"——
|
||||
* 服务端存、两端同步、`blurStyleFor` 也写了、就是**没有任何调用点**
|
||||
* (`harmony-appearance.test.mjs` 有一条判据把"消费侧出现次数为 0"钉住,
|
||||
* 就是为了让"有人开始消费"这一刻**必须停下来**补映射判据而不是偷偷把 0 改成 1)。
|
||||
* P4c 加背景选择器时踩到了这条线:滑杆能拖、值能存,但壁纸**一点没糊**。
|
||||
* 所以这次把映射的**调用点**补上(映射表与它的判据早就在了)。
|
||||
*/
|
||||
blurPx: number = 0;
|
||||
/**
|
||||
* 遮盖浓度(0~1):**两档都用**(预设档也压),用系统遮罩色刷一层。
|
||||
*
|
||||
@ -262,9 +279,11 @@ export class BackgroundPlan {
|
||||
* 这里决定**画成什么**。`image` 档但图没取回来 → `none`:
|
||||
* 宁可什么都不画,也不要画一块空白(用户会以为壁纸坏了)。
|
||||
*/
|
||||
export function resolveBackground(bgKind: string, presetId: string, scrim: number, hasImage: boolean, dark: boolean): BackgroundPlan {
|
||||
export function resolveBackground(bgKind: string, presetId: string, scrim: number, hasImage: boolean, dark: boolean, blurPx: number = 0): BackgroundPlan {
|
||||
const plan: BackgroundPlan = new BackgroundPlan();
|
||||
plan.dark = dark;
|
||||
// 模糊是**全档通用**的(WebUI 的 `--bg-blur` 也不区分档位),所以先搬运、各档都带上
|
||||
plan.blurPx = normalizeBlur(blurPx);
|
||||
if (bgKind === 'preset') {
|
||||
plan.kind = 'preset';
|
||||
plan.presetId = normalizePreset(presetId);
|
||||
@ -284,6 +303,36 @@ export function resolveBackground(bgKind: string, presetId: string, scrim: numbe
|
||||
return plan;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模糊 px 归一:0~40 的整数。
|
||||
*
|
||||
* ★ 边界 40 与 `model/Appearance.ts` 的 `clampNumber(bgBlur, 0, 40, 4)` **必须同值** ——
|
||||
* 两边不一致的话,服务端存 40、这边按 80 画,判定与显示就对不上了
|
||||
* (`blurStyleFor` 里面也有一次 clamp,那是它自己的防线,不是这里可以放松的理由)。
|
||||
*/
|
||||
export function normalizeBlur(px: number): number {
|
||||
if (!Number.isFinite(px)) {
|
||||
return 0;
|
||||
}
|
||||
const r: number = Math.round(px);
|
||||
/*
|
||||
* ★ 判 `!(r > 0)` 而不是 `r < 0` —— 因为 `Math.round(-0.4)` 是 **-0**,
|
||||
* 而 `-0 < 0` 是 **false**(`-0 === 0`)。用 `r < 0` 会让 `-0` 漏过去,
|
||||
* 于是 `blur(-0)` 被喂进 ArkUI —— 这是个**静默**的怪值(判据把它抓出来了:
|
||||
* `assert.equal(normalizeBlur(-0.4), 0)` 报的是 `+ -0`,一眼看不出问题在哪)。
|
||||
*/
|
||||
if (!(r > 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (r > MAX_BLUR_PX) {
|
||||
return MAX_BLUR_PX;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/** 模糊上限(px)。与 `model/Appearance.ts` 的 clamp 上界同值。 */
|
||||
export const MAX_BLUR_PX: number = 40;
|
||||
|
||||
/** 预设缩略图/选择器要显示的清单(id + 标签) */
|
||||
export function presetChoices(): string[] {
|
||||
return PRESET_IDS;
|
||||
|
||||
Reference in New Issue
Block a user