wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBoardRouter = createBoardRouter;
const express_1 = __importDefault(require("express"));
const node_path_1 = __importDefault(require("node:path"));
const node_url_1 = require("node:url");
const loadConfig_js_1 = require("../config/loadConfig.js");
const requireAuth_js_1 = require("../middleware/requireAuth.js");
const scenarioLookup_js_1 = require("../services/scenarioLookup.js");
const ldapAuth_js_1 = require("../utils/ldapAuth.js");
const resolveShareUrl_js_1 = require("../utils/resolveShareUrl.js");
const calendarMonth_js_1 = require("../utils/calendarMonth.js");
const __dirname = node_path_1.default.dirname((0, node_url_1.fileURLToPath)(import.meta.url));
function createBoardRouter(appCfg) {
    const router = express_1.default.Router();
    const scenarios = (0, loadConfig_js_1.loadScenariosConfig)();
    router.get("/check/", (req, res) => {
        if (req.session.user) {
            res.status(200).type("text/plain").send("ok");
            return;
        }
        res.status(401).type("text/plain").send("unauthorized");
    });
    router.get("/login", (req, res) => {
        if (req.session.user) {
            res.redirect("/board/");
            return;
        }
        res.render("login", {
            basePath: "/board",
            error: null,
        });
    });
    router.use(express_1.default.json());
    router.post("/api/login", async (req, res) => {
        const username = String(req.body?.username ?? "").trim();
        const password = String(req.body?.password ?? "");
        if (!username || !password) {
            res.status(400).json({ ok: false, error: "缺少用户名或密码" });
            return;
        }
        const ldapCfg = (0, loadConfig_js_1.loadLdapConfig)();
        const result = await (0, ldapAuth_js_1.verifyCredentials)(username, password, ldapCfg);
        if (!result.ok) {
            const status = result.reason === "connection_error" ? 503 : 401;
            const msg = result.reason === "user_not_found"
                ? "用户不存在"
                : result.reason === "connection_error"
                    ? "目录服务不可用"
                    : "用户名或密码错误";
            res.status(status).json({ ok: false, error: msg });
            return;
        }
        req.session.user = { username };
        const next = String(req.body?.next ?? "");
        const safeNext = next.startsWith("/board/") && !next.includes("//") ? next : "/board/";
        res.json({ ok: true, redirect: safeNext });
    });
    router.post("/api/logout", (req, res) => {
        req.session.destroy((err) => {
            if (err) {
                res.status(500).json({ ok: false, error: "登出失败" });
                return;
            }
            res.clearCookie("board.sid", { path: "/" });
            res.json({ ok: true });
        });
    });
    router.use("/static", express_1.default.static(node_path_1.default.join(__dirname, "../../public/board")));
    router.get("/", requireAuth_js_1.requireAuth, (req, res) => {
        res.render("home", {
            basePath: "/board",
            username: req.session.user.username,
            categories: (0, scenarioLookup_js_1.flattenForClient)(scenarios),
            pageImagesJson: JSON.stringify((0, scenarioLookup_js_1.buildPageImageMap)(scenarios)),
        });
    });
    router.get("/warehouse-calendar", requireAuth_js_1.requireAuth, (req, res) => {
        const now = new Date();
        const qy = Number(req.query.year);
        const qm = Number(req.query.month);
        const year = Number.isFinite(qy) && qy >= 2000 && qy <= 2100 ? qy : now.getFullYear();
        const month = Number.isFinite(qm) && qm >= 1 && qm <= 12 ? qm : now.getMonth() + 1;
        const plansCfg = (0, loadConfig_js_1.loadWarehousePlansConfig)();
        const rows = (0, calendarMonth_js_1.buildMonthRows)(year, month, plansCfg.plans ?? {});
        const monthTitle = new Date(year, month - 1, 1).toLocaleString("zh-CN", {
            year: "numeric",
            month: "long",
        });
        res.render("warehouseCalendar", {
            basePath: "/board",
            username: req.session.user.username,
            year,
            month,
            monthTitle,
            rows,
            weekdayLabels: ["一", "二", "三", "四", "五", "六", "日"],
        });
    });
    router.get("/view", requireAuth_js_1.requireAuth, (req, res) => {
        const scenarioId = String(req.query.scenarioId ?? "");
        const pageId = String(req.query.pageId ?? "");
        const resolved = (0, scenarioLookup_js_1.findPageByIds)(scenarios, scenarioId, pageId);
        if (!resolved) {
            res.status(404).send("场景或页面不存在");
            return;
        }
        res.render("view", {
            basePath: "/board",
            title: resolved.page.title,
            shareUrl: (0, resolveShareUrl_js_1.resolveShareUrl)(appCfg.dataEasePublicBase, resolved.page.shareUrl),
            scenarioId: resolved.scenarioId,
            scenarioName: resolved.scenarioName,
            pageId: resolved.page.id,
            pageTitle: resolved.page.title,
        });
    });
    return router;
}
//# sourceMappingURL=boardRouter.js.map