feat(M08-D): 建立后台运营总览

This commit is contained in:
Codex
2026-08-10 11:22:13 +08:00
parent b08a2cca43
commit 65f2e7c916
9 changed files with 775 additions and 39 deletions
+30 -28
View File
@@ -26,34 +26,36 @@ export async function registerBusinessStatisticsRoutes(
app: FastifyInstance,
options: BusinessStatisticsRouteOptions
) {
app.get('/app-api/management/statistics', async (request, reply) => {
const actor = await requireActor(request, reply, options);
if (!actor) return;
const query = querySchema.safeParse(request.query);
if (!query.success) return invalid(reply, request.traceId);
const to = query.data.to ?? new Date();
const from = query.data.from ?? new Date(to.getTime() - 30 * 86400000);
const duration = to.getTime() - from.getTime();
if (duration <= 0 || duration > 93 * 86400000) return invalid(reply, request.traceId);
try {
return {
code: 0,
data: await options.repository.overview(actor, {
storeId: query.data.storeId,
from,
to
}),
traceId: request.traceId
};
} catch (error) {
if (!(error instanceof BusinessStatisticsError)) throw error;
return reply.status(403).send({
code: error.code,
message: 'Business statistics permission is required.',
traceId: request.traceId
});
}
});
for (const path of ['/app-api/management/statistics', '/admin-api/statistics']) {
app.get(path, async (request, reply) => {
const actor = await requireActor(request, reply, options);
if (!actor) return;
const query = querySchema.safeParse(request.query);
if (!query.success) return invalid(reply, request.traceId);
const to = query.data.to ?? new Date();
const from = query.data.from ?? new Date(to.getTime() - 30 * 86400000);
const duration = to.getTime() - from.getTime();
if (duration <= 0 || duration > 93 * 86400000) return invalid(reply, request.traceId);
try {
return {
code: 0,
data: await options.repository.overview(actor, {
storeId: query.data.storeId,
from,
to
}),
traceId: request.traceId
};
} catch (error) {
if (!(error instanceof BusinessStatisticsError)) throw error;
return reply.status(403).send({
code: error.code,
message: 'Business statistics permission is required.',
traceId: request.traceId
});
}
});
}
}
async function requireActor(
@@ -111,6 +111,13 @@ assert.equal(response.statusCode, 200);
assert.equal(response.json().data.summary.collectedAmountCents, 21000);
assert.equal(routed.actor.userId, '22');
assert.equal(routed.input.storeId, '11');
const adminResponse = await app.inject({
method: 'GET',
url: '/admin-api/statistics?storeId=11&from=2026-08-01T00%3A00%3A00.000Z&to=2026-09-01T00%3A00%3A00.000Z',
headers: { authorization: `Bearer ${token}` }
});
assert.equal(adminResponse.statusCode, 200);
assert.equal(adminResponse.json().data.summary.orderTotal, 12);
const invalidRange = await app.inject({
method: 'GET',
url: '/app-api/management/statistics?storeId=11&from=2026-01-01&to=2026-09-01',