feat(收口): 补齐 8 月迭代缺口并同步 Spec 与证据链
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled

- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕
- 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败
- 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影
- 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序
- 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列
- 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名
- 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
This commit is contained in:
2026-09-18 15:34:29 +08:00
parent 5e78809b93
commit 5ed6b39deb
142 changed files with 7878 additions and 964 deletions

View File

@@ -20,9 +20,13 @@ const operationsReportEmptyValue = "-"
// 合计行的分组列值。
const operationsReportTotalGroup = "合计"
// 序号列表头;分组行按导出展示顺序从 1 连续递增,合计行留空不写入任何数字或文字。
const operationsReportSerialHeader = "序号"
// OperationsActivationDataSource 设备激活情况报表导出数据源。
//
// 导出列与页面展示字段一致并包含合计行,不含任何文字总结;
// 导出列与页面展示字段一致并包含合计行,首列为「序号」:分组行按展示顺序从 1 连续递增,
// 合计行的序号列留空且其余各列的既有表示不变;导出不含任何文字总结;
// 行集合与汇总查询完全一致:两侧共用同一个查询实现,因此筛选与口径不会漂移。
// 本场景只对超级管理员与平台账号开放:受控入口已做角色门禁,这里再按任务内冻结的账号类型复核一次,
// 阻止通过通用导出入口以代理身份创建本场景任务后读到运营报表数据。
@@ -81,12 +85,13 @@ func (s *OperationsActivationDataSource) build(ctx context.Context, params Expor
return nil, err
}
headers := []string{
response.GroupName, "采购数量", "累计激活数", "激活率", "新增激活数",
operationsReportSerialHeader, response.GroupName, "采购数量", "累计激活数", "激活率", "新增激活数",
"累计在网数", "活跃用户数", "累计用量(GB)", "单用户卡均(GB)", "含零预测卡均(GB)", "不含零预测卡均(GB)",
}
rows := make([][]string, 0, len(response.Items)+1)
for _, item := range response.Items {
for index, item := range response.Items {
rows = append(rows, []string{
strconv.Itoa(index + 1),
item.GroupValue,
formatOptionalInt64(item.PurchasedDeviceCount),
formatOptionalInt64(item.ActivatedDeviceCount),
@@ -103,6 +108,8 @@ func (s *OperationsActivationDataSource) build(ctx context.Context, params Expor
if response.Totals != nil {
total := response.Totals
rows = append(rows, []string{
// 合计行序号列留空,其余各列沿用既有表示。
"",
operationsReportTotalGroup,
formatOptionalInt64(total.PurchasedDeviceCount),
formatOptionalInt64(total.ActivatedDeviceCount),
@@ -121,7 +128,8 @@ func (s *OperationsActivationDataSource) build(ctx context.Context, params Expor
// OperationsRenewalDataSource 套餐续费情况报表导出数据源。
//
// 导出列与页面展示字段一致并包含合计行,不含任何文字总结;
// 导出列与页面展示字段一致并包含合计行,首列为「序号」:分组行按展示顺序从 1 连续递增,
// 合计行的序号列留空且其余各列的既有表示不变;导出不含任何文字总结;
// 行集合与汇总查询完全一致:两侧共用同一个查询实现,因此筛选与口径不会漂移。
// 本场景同样按任务内冻结的账号类型复核导出资格。
type OperationsRenewalDataSource struct {
@@ -178,10 +186,11 @@ func (s *OperationsRenewalDataSource) build(ctx context.Context, params ExportPa
if err != nil {
return nil, err
}
headers := []string{response.GroupName, "到期资产数", "续费资产数", "续费率", "新增未续费数"}
headers := []string{operationsReportSerialHeader, response.GroupName, "到期资产数", "续费资产数", "续费率", "新增未续费数"}
rows := make([][]string, 0, len(response.Items)+1)
for _, item := range response.Items {
for index, item := range response.Items {
rows = append(rows, []string{
strconv.Itoa(index + 1),
item.GroupValue,
formatOptionalInt64(item.DueAssetCount),
formatOptionalInt64(item.RenewedAssetCount),
@@ -192,6 +201,8 @@ func (s *OperationsRenewalDataSource) build(ctx context.Context, params ExportPa
if response.Totals != nil {
total := response.Totals
rows = append(rows, []string{
// 合计行序号列留空,其余各列沿用既有表示。
"",
operationsReportTotalGroup,
formatOptionalInt64(total.DueAssetCount),
formatOptionalInt64(total.RenewedAssetCount),