const { z } = require("zod"); const { AppError } = require("../utils/AppError"); const { sendData } = require("../utils/reply"); const { buildAuditLogData } = require("../utils/audit"); const { DEFAULT_MODULE_VISIBILITY, getWorkspaceSetting, getSystemNavigation, normalizeModuleVisibilityJson, upsertWorkspaceSetting, } = require("../services/workspaceSettings"); const MODULE_VISIBILITY_SCHEMA = z.record(z.string(), z.enum(["main", "admin", "hidden"])).optional(); const PATCH_SCHEMA = z .object({ moduleVisibility: MODULE_VISIBILITY_SCHEMA, }) .strict() .refine((value) => Object.keys(value).length > 0, { message: "empty_patch" }); function buildValidationError(details, statusCode = 400) { return new AppError({ code: "VALID_001", message: "参数校验失败", statusCode, details }); } function parseBody(schema, body) { const parsed = schema.safeParse(body ?? {}); if (!parsed.success) { throw buildValidationError(parsed.error.flatten()); } return parsed.data; } async function writeWorkspaceAuditLog(fastify, request, workspace) { try { await fastify.prisma.auditLog.create({ data: buildAuditLogData(request, { actorId: request.employee.id, action: "WORKSPACE_SETTING_UPDATED", targetType: "workspace_setting", targetId: workspace.id, extra: { moduleVisibility: workspace.moduleVisibility }, }), }); } catch (error) { request.log.error({ err: error, workspaceId: workspace.id }, "workspace setting audit failed"); } } async function systemWorkspaceRoutes(fastify) { fastify.get("/system/workspace", { preHandler: fastify.authenticate }, async (request, reply) => { const workspace = await getWorkspaceSetting(fastify.prisma); return sendData(reply, request, { ...workspace, defaults: DEFAULT_MODULE_VISIBILITY, }); }); fastify.patch("/system/workspace", { preHandler: fastify.requirePermission("system.settings") }, async (request, reply) => { const body = parseBody(PATCH_SCHEMA, request.body); const workspace = await upsertWorkspaceSetting(fastify.prisma, request.employee.id, { moduleVisibility: normalizeModuleVisibilityJson(body.moduleVisibility ?? null), }); await writeWorkspaceAuditLog(fastify, request, workspace); return sendData(reply, request, { item: workspace }); }); fastify.get("/system/navigation", { preHandler: fastify.authenticate }, async (request, reply) => { const data = await getSystemNavigation({ prisma: fastify.prisma, config: fastify.config, employee: request.employee, hasPermission: fastify.hasPermission, }); return sendData(reply, request, data); }); } module.exports = systemWorkspaceRoutes;