From 8a61186cfd1afda57f496dd6c5ddb4796799be00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=9D=BF=20=E5=BC=A0?= Date: Sat, 10 Oct 2026 16:10:53 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=AE=A1=E5=88=92=20Task=207=20?= =?UTF-8?q?=E7=89=87=E6=AE=B5=E7=9A=84=20BOM=20=E6=94=B9=E6=88=90=E8=BD=AC?= =?UTF-8?q?=E4=B9=89=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 内联的零宽字符在编辑器里看不见也改不动,写文件时极易悄悄落成真字符——实现这个 Task 的过程中在源码、提交信息、记忆文件里各踩了一次。改成 JS 转义写法后源码可见。 片段同步为已提交的实现与测试版本:测试引入 BOM 常量,实现片段注释也对齐。 把文档里的两个片段抽出来覆盖真实文件实跑,2 个用例通过。 --- .../plans/2026-10-10-material-bulk-import.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/superpowers/plans/2026-10-10-material-bulk-import.md b/docs/superpowers/plans/2026-10-10-material-bulk-import.md index aa85d4af..9f646d25 100644 --- a/docs/superpowers/plans/2026-10-10-material-bulk-import.md +++ b/docs/superpowers/plans/2026-10-10-material-bulk-import.md @@ -2006,18 +2006,22 @@ git commit -m "feat: 物料导入与模板下载接口" import { describe, expect, test } from 'vitest' import { buildCsv } from './exportCsv' +// BOM 用转义写,不内联那个零宽字符:内联的话看不见也改不动, +// 一旦被编辑器或编码转换吃掉,测试就会以一个极难看懂的方式失败。 +const BOM = '\uFEFF' + describe('buildCsv', () => { test('用逗号分隔并在行尾换行', () => { const csv = buildCsv([ ['行号', '失败原因'], [3, '物料名称不能为空'] ]) - expect(csv).toBe('行号,失败原因\r\n3,物料名称不能为空\r\n') + expect(csv).toBe(BOM + '行号,失败原因\r\n3,物料名称不能为空\r\n') }) test('包含逗号、引号、换行的字段用双引号包裹并转义', () => { const csv = buildCsv([['规格', '备注'], ['M8,30', '含"引号"'], ['两\n行', '']]) - expect(csv).toBe('规格,备注\r\n"M8,30","含""引号"""\r\n"两\n行",\r\n') + expect(csv).toBe(BOM + '规格,备注\r\n"M8,30","含""引号"""\r\n"两\n行",\r\n') }) }) ``` @@ -2032,11 +2036,11 @@ Expected: FAIL(模块不存在) 创建 `frontend/src/utils/exportCsv.js`: ```js -// 生成 CSV 文本。带 UTF-8 BOM,Excel 打开中文才不会乱码;字段里的 -// 逗号、引号、换行按 RFC 4180 用双引号包裹并转义。 +// 生成 CSV 文本。带 UTF-8 BOM(写成转义而不是内联零宽字符,源码里才看得见), +// Excel 打开中文才不会乱码;字段里的逗号、引号、换行按 RFC 4180 用双引号包裹并转义。 export function buildCsv(rows) { const lines = rows.map(row => row.map(escapeCsvCell).join(',')) - return '' + lines.map(line => line + '\r\n').join('') + return '\uFEFF' + lines.map(line => line + '\r\n').join('') } function escapeCsvCell(value) {