feat(P19AI1-1,P19AI1-2): 实现AI建议引擎与权限门禁后端
这个提交包含在:
@@ -0,0 +1,115 @@
|
||||
const { z } = require("zod");
|
||||
|
||||
const { AppError } = require("../utils/AppError");
|
||||
const { sendData } = require("../utils/reply");
|
||||
const {
|
||||
getAiStatus,
|
||||
generateReimbursementSuggestion,
|
||||
generatePurchaseSuggestion,
|
||||
generateAssetSuggestion,
|
||||
} = require("../services/ai/suggestions");
|
||||
|
||||
const UUID_SCHEMA = z.string().uuid();
|
||||
|
||||
function parseUuid(value, fieldName) {
|
||||
const parsed = UUID_SCHEMA.safeParse(value);
|
||||
if (!parsed.success) {
|
||||
throw new AppError({
|
||||
code: "VALID_001",
|
||||
message: "参数校验失败",
|
||||
statusCode: 400,
|
||||
details: { [fieldName]: "invalid_uuid" },
|
||||
});
|
||||
}
|
||||
|
||||
return parsed.data;
|
||||
}
|
||||
|
||||
async function aiRoutes(fastify) {
|
||||
fastify.get(
|
||||
"/ai/status",
|
||||
{
|
||||
preHandler: fastify.authenticate,
|
||||
schema: {
|
||||
tags: ["ai"],
|
||||
summary: "获取 AI 建议工作台状态",
|
||||
security: [{ bearerAuth: [] }],
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const status = await getAiStatus(fastify.prisma, fastify.config, request.employee);
|
||||
return sendData(reply, request, status);
|
||||
},
|
||||
);
|
||||
|
||||
fastify.post(
|
||||
"/ai/suggestions/reimbursements/:reimbursementId",
|
||||
{
|
||||
preHandler: fastify.authenticate,
|
||||
schema: {
|
||||
tags: ["ai"],
|
||||
summary: "生成报销详情 AI 建议",
|
||||
security: [{ bearerAuth: [] }],
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const reimbursementId = parseUuid(request.params?.reimbursementId, "reimbursementId");
|
||||
const result = await generateReimbursementSuggestion(
|
||||
fastify.prisma,
|
||||
fastify.config,
|
||||
request,
|
||||
reimbursementId,
|
||||
);
|
||||
return sendData(reply, request, result);
|
||||
},
|
||||
);
|
||||
|
||||
fastify.post(
|
||||
"/ai/suggestions/purchase-requests/:purchaseRequestId",
|
||||
{
|
||||
preHandler: fastify.authenticate,
|
||||
schema: {
|
||||
tags: ["ai"],
|
||||
summary: "生成采购详情 AI 建议",
|
||||
security: [{ bearerAuth: [] }],
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const purchaseRequestId = parseUuid(request.params?.purchaseRequestId, "purchaseRequestId");
|
||||
const result = await generatePurchaseSuggestion(
|
||||
fastify.prisma,
|
||||
fastify.config,
|
||||
request,
|
||||
purchaseRequestId,
|
||||
);
|
||||
return sendData(reply, request, result);
|
||||
},
|
||||
);
|
||||
|
||||
fastify.post(
|
||||
"/ai/suggestions/assets/:assetId",
|
||||
{
|
||||
preHandler: fastify.authenticate,
|
||||
schema: {
|
||||
tags: ["ai"],
|
||||
summary: "生成资产详情 AI 建议",
|
||||
security: [{ bearerAuth: [] }],
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const assetId = parseUuid(request.params?.assetId, "assetId");
|
||||
const result = await generateAssetSuggestion(
|
||||
fastify.prisma,
|
||||
fastify.config,
|
||||
request,
|
||||
assetId,
|
||||
);
|
||||
return sendData(reply, request, result);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = aiRoutes;
|
||||
module.exports.__testables = {
|
||||
parseUuid,
|
||||
};
|
||||
在新工单中引用
屏蔽一个用户