R52 A1-A6:完成 AP 运营深度操作
- AP 概览页 Tab 工作台化(待付款/异常付款/风险标记/对账异常) - AP 导出端点支持 CSV/XLSX 与筛选 - 风险标记 resolve/dismiss 支持说明审计留痕 - 支付批次深链、高风险复核提示、对账确认权限收口 - OpenClaw 浏览器级回归全部通过
这个提交包含在:
@@ -12,6 +12,9 @@ const QUERY_SCHEMA = z.object({
|
||||
status: z.enum(["open", "resolved", "dismissed"]).optional(),
|
||||
source: z.string().trim().max(32).optional(),
|
||||
});
|
||||
const ACTION_BODY_SCHEMA = z.object({
|
||||
note: z.string().trim().max(500).nullable().optional(),
|
||||
}).strict();
|
||||
|
||||
function buildValidationError(details, statusCode = 400) {
|
||||
return new AppError({
|
||||
@@ -58,6 +61,22 @@ function parseId(value) {
|
||||
return parsed.data;
|
||||
}
|
||||
|
||||
function parseBody(body) {
|
||||
const parsed = ACTION_BODY_SCHEMA.safeParse(body ?? {});
|
||||
if (!parsed.success) {
|
||||
throw buildValidationError(parsed.error.flatten());
|
||||
}
|
||||
return parsed.data;
|
||||
}
|
||||
|
||||
function normalizeNote(value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
const trimmed = String(value).trim();
|
||||
return trimmed || null;
|
||||
}
|
||||
|
||||
async function riskFlagsRoutes(fastify) {
|
||||
fastify.get("/risk-flags", { preHandler: fastify.authenticate }, async (request, reply) => {
|
||||
ensureListPermission(fastify, request);
|
||||
@@ -78,6 +97,8 @@ async function riskFlagsRoutes(fastify) {
|
||||
fastify.post(`/risk-flags/:id/${action}`, { preHandler: fastify.authenticate }, async (request, reply) => {
|
||||
ensureManagePermission(fastify, request);
|
||||
const riskFlagId = parseId(request.params?.id);
|
||||
const body = parseBody(request.body);
|
||||
const note = normalizeNote(body.note);
|
||||
const current = await fastify.prisma.entityRiskFlag.findUnique({ where: { id: riskFlagId } });
|
||||
if (!current) {
|
||||
throw new AppError({ code: "SYS_404", message: "Not Found", statusCode: 404 });
|
||||
@@ -105,6 +126,7 @@ async function riskFlagsRoutes(fastify) {
|
||||
entityType: updated.entity_type,
|
||||
entityId: updated.entity_id,
|
||||
riskCode: updated.risk_code,
|
||||
note,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户