feat(ui): 按钮级权限守卫与数量显示格式化

按钮级权限(与后端 @permission_required 用同一批权限码):
- 出库记录页「退回」按钮   -> v-permission="'outbound_return'"
- 不良品看板「修复回库」   -> v-permission="'defective_restock'"
- 不良品看板「报废销毁」   -> v-permission="'defective_scrap'"

  两个处置按钮是**独立权限**,可能有人只有其一,故分别判定、分别隐藏;
  两者都无时显示「无处置权限」。均保留响应式的 v-if 兜底——v-permission
  只在 mounted 执行一次,而 Element Plus 表格行会重渲染,两者用同一权限码
  判定一致。hasPermission() 内部已对 SUPER_ADMIN 放行,与后端装饰器的
  超管旁路对齐。

  另外去掉了出库记录页原本套用的 username === 'IRIS' 特例放行:退回是实物
  交接的 SOP 动作,后端不认这个特例,前端也不该认,否则会出现「按钮可见但
  接口 403」的错位。

数量显示格式化(新增 utils/format.ts,该文件原本是 0 字节空文件):
- formatQty()    显示用:1.0000 -> '1',2.5000 -> '2.5'
- normalizeQty() 数值用:同上但返回 number,供 el-input-number 的
                 v-model / :max —— 喂字符串会让步进与边界比较退化

  应用于 不良品看板(退回总数、剩余待处理、两个弹窗的在管数量与输入框)、
  出库记录页(已退 N 提示、退回弹窗三项数字)、退回记录页(退回数量列)。

  同时移除三个 el-input-number 上的 :precision="4" —— 它会把 1 强制渲染成
  1.0000,是截图上多余小数点的直接来源。数量本身仍支持小数(后端按
  numeric(19,4) 收),只是不再强制补零。

  表格列原本不受影响(接口返回 JSON 数字,1.0 经 JS 解析即 1),但后端有一批
  运算是 float 累加,可能吐出 0.30000000000000004 这类尾巴,格式化按
  numeric(19,4) 量纲先收敛到 4 位再做归一。
This commit is contained in:
yueli
2026-09-16 16:46:20 +08:00
parent 27436f5efe
commit 511e822d12
3 changed files with 122 additions and 37 deletions

View File

@ -0,0 +1,36 @@
// ============================================================================
// 通用格式化工具
// ============================================================================
/**
* 数量显示格式化 —— 整数不显示小数点,小数去除末尾多余的 0。
*
* 1.0000 -> '1'
* 2.5000 -> '2.5'
* 0.30000000000000004 -> '0.3' (后端 float 累加产生的尾巴)
* null / undefined / '' -> fallback
*
* ★ 为什么先 toFixed(4) 再 Number
* 本系统数量列在库中一律为 numeric(19,4),但后端有一批运算写成
* `float(a) + float(b)`,累加后可能带出 0.30000000000000004 这类二进制
* 浮点尾数。先按量纲精度收敛到 4 位,再交给 Number 归一 —— Number('0.3000')
* 即 0.3String() 后自然就是 '0.3'。
*/
export function formatQty(value: any, fallback = '0'): string {
if (value === null || value === undefined || value === '') return fallback
const n = Number(value)
if (!Number.isFinite(n)) return fallback
return String(Number(n.toFixed(4)))
}
/**
* 数量归一化为 number —— 供 el-input-number 等**需要数值而非字符串**的
* 组件使用。作用同 formatQty只是保留 number 类型。
*
* ★ 不要把 formatQty 的返回值喂给 el-input-number传字符串会让 v-model
* 失去数值语义,组件内部的步进/边界比较也会退化。
*/
export function normalizeQty(value: any, fallback = 0): number {
const n = Number(value)
return Number.isFinite(n) ? Number(n.toFixed(4)) : fallback
}