fix: keep absent brief SMS content empty

This commit is contained in:
hectorzhao
2026-09-03 09:37:24 +08:00
parent fe5b25a7e4
commit 068b8047dd
4 changed files with 13 additions and 9 deletions
@@ -95,8 +95,10 @@ export class ReportChannelExportService {
const values = fields.map( const values = fields.map(
(field) => resolveExportValue(item.snapshot, field.code, field.name) ?? field.defaultValue ?? '', (field) => resolveExportValue(item.snapshot, field.code, field.name) ?? field.defaultValue ?? '',
); );
const smsContentIndex = fields.findIndex((field) => field.name.trim() === '短信内容'); const smsContentField = fields.find((field) => field.name.trim() === '短信内容');
const smsContentValue = smsContentIndex >= 0 ? values[smsContentIndex] : ''; const smsContentValue = smsContentField
? resolveExportValue(item.snapshot, smsContentField.code, smsContentField.name) ?? ''
: '';
const smsContent = isFileRef(smsContentValue) ? '' : String(smsContentValue ?? ''); const smsContent = isFileRef(smsContentValue) ? '' : String(smsContentValue ?? '');
const missing = fields.filter((field, index) => field.required && !hasValue(values[index])); const missing = fields.filter((field, index) => field.required && !hasValue(values[index]));
const missingReason = const missingReason =
@@ -149,7 +149,7 @@ describe('ReportMaterialsService', () => {
]); ]);
}); });
it('expands one selected signature to every routed channel and embeds images in each XLSX', async () => { it('expands one selected signature to every routed channel, embeds images and snapshots the first material SMS content', async () => {
const uploadedWorkbooks: Buffer[] = []; const uploadedWorkbooks: Buffer[] = [];
let batchItemSequence = 0; let batchItemSequence = 0;
let exportSequence = 0; let exportSequence = 0;
@@ -189,6 +189,8 @@ describe('ReportMaterialsService', () => {
drainageInfo: { drainageInfo: {
signatureReportValues: { signatureReportValues: {
license: { fileObjectId: 'image-1', fileName: 'license.png', contentType: 'image/png' }, license: { fileObjectId: 'image-1', fileName: 'license.png', contentType: 'image/png' },
sms_content_primary: '第一条短信内容',
sms_content_secondary: '第二条短信内容',
}, },
}, },
tenant: { name: '测试企业' }, tenant: { name: '测试企业' },
@@ -223,7 +225,7 @@ describe('ReportMaterialsService', () => {
), ),
}, },
channelReportField: { channelReportField: {
findMany: jest.fn().mockResolvedValue([ findMany: jest.fn().mockImplementation(({ where }: { where: { channelId: string } }) => Promise.resolve([
{ {
code: 'sign', code: 'sign',
name: '短信签名', name: '短信签名',
@@ -247,7 +249,7 @@ describe('ReportMaterialsService', () => {
defaultValue: null, defaultValue: null,
}, },
{ {
code: 'sms_content_primary', code: where.channelId === 'channel-b' ? 'sms_content_missing' : 'sms_content_primary',
name: '短信内容', name: '短信内容',
exportName: '短信内容一', exportName: '短信内容一',
required: false, required: false,
@@ -268,7 +270,7 @@ describe('ReportMaterialsService', () => {
transform: null, transform: null,
defaultValue: '第二条短信内容', defaultValue: '第二条短信内容',
}, },
]), ])),
}, },
channelSignatureReportTask: { channelSignatureReportTask: {
findMany: jest.fn().mockResolvedValue([]), findMany: jest.fn().mockResolvedValue([]),
@@ -331,7 +333,7 @@ describe('ReportMaterialsService', () => {
snapshot: expect.objectContaining({ snapshot: expect.objectContaining({
briefSmsContentByChannel: { briefSmsContentByChannel: {
'channel-a': '第一条短信内容', 'channel-a': '第一条短信内容',
'channel-b': '第一条短信内容', 'channel-b': '',
}, },
}), }),
}, },
@@ -107,7 +107,7 @@
2. 通道简报 2. 通道简报
- 每个通道一份,日期取批次生成时间,批次号取 `batchNo` - 每个通道一份,日期取批次生成时间,批次号取 `batchNo`
- 签名资料行格式为“短信签名:【签名】,短信内容:内容”;引流资料行格式为“引流信息:URL或号码,短信内容:内容”。 - 签名资料行格式为“短信签名:【签名】,短信内容:内容”;引流资料行格式为“引流信息:URL或号码,短信内容:内容”。
- “短信内容”只从该通道按 `sortOrder ASC, createdAt ASC` 排列的字段库中取第一个名称为“短信内容”的字段;没有则留空,后续同名字段不参与简报。 - “短信内容”只从该通道按 `sortOrder ASC, createdAt ASC` 排列的字段库中取第一个名称为“短信内容”的字段,并读取资料中的实际字段值;没有字段或资料未提供该字段值时留空,不使用通道缺省值,后续同名字段不参与简报。
- 简报取值写入现有批次 JSON 快照,不新增数据库字段或 migration;字段库或签名资料后续变化不得改写历史批次简报。 - 简报取值写入现有批次 JSON 快照,不新增数据库字段或 migration;字段库或签名资料后续变化不得改写历史批次简报。
- 页面支持查看全文和一键复制,复制失败时保留可手工选择的原文。 - 页面支持查看全文和一键复制,复制失败时保留可手工选择的原文。
3. 通道文件 3. 通道文件
+1 -1
View File
@@ -5022,7 +5022,7 @@ npm run verify:phase8
| TC-REPORT-WORKBENCH-012 | 查看企业签名表头和签名列表 | 签名列不显示升序、降序或其他排序按钮;列表不显示逐行待生成明细字段;默认按创建时间倒序 | | TC-REPORT-WORKBENCH-012 | 查看企业签名表头和签名列表 | 签名列不显示升序、降序或其他排序按钮;列表不显示逐行待生成明细字段;默认按创建时间倒序 |
| TC-REPORT-WORKBENCH-013 | 通道报备明细当前页有10条数据,点击“全选当前页” | 当前页10条全部选中,按钮变为“取消全选”,批量数为10;翻页或查询后选择清空,不选中其他页面数据 | | TC-REPORT-WORKBENCH-013 | 通道报备明细当前页有10条数据,点击“全选当前页” | 当前页10条全部选中,按钮变为“取消全选”,批量数为10;翻页或查询后选择清空,不选中其他页面数据 |
| TC-REPORT-WORKBENCH-014 | 生成同时包含签名和引流资料、覆盖多个通道的批次 | 每个通道生成一份简报;日期取批次生成日期,批次号一致;签名行和引流行分别按已确认格式展示,且可一键复制完整原文 | | TC-REPORT-WORKBENCH-014 | 生成同时包含签名和引流资料、覆盖多个通道的批次 | 每个通道生成一份简报;日期取批次生成日期,批次号一致;签名行和引流行分别按已确认格式展示,且可一键复制完整原文 |
| TC-REPORT-WORKBENCH-015 | 通道配置0个、1个或多个名称为“短信内容”的字段 | 0个时简报短信内容为空;1个时取该字段;多个时严格按`sortOrder ASC, createdAt ASC`取第一个字段值,后续同名字段不参与 | | TC-REPORT-WORKBENCH-015 | 通道配置0个、1个或多个名称为“短信内容”的字段 | 0个时简报短信内容为空;1个时取资料中该字段的实际值;多个时严格按`sortOrder ASC, createdAt ASC`取第一个字段在资料中的实际值,后续同名字段不参与;资料未提供首字段时保持为空,不得使用通道缺省值冒充资料内容 |
| TC-REPORT-WORKBENCH-016 | 批次生成后修改字段库或签名/引流资料 | 历史批次简报仍使用生成时固化的批次快照,不随当前资料改变;不新增数据库migration,不触发短信发送或队列 | | TC-REPORT-WORKBENCH-016 | 批次生成后修改字段库或签名/引流资料 | 历史批次简报仍使用生成时固化的批次快照,不随当前资料改变;不新增数据库migration,不触发短信发送或队列 |
## TC-HIGH-FREQUENCY-QUERY-20260902 高频查询与按需详情 ## TC-HIGH-FREQUENCY-QUERY-20260902 高频查询与按需详情