fix:save_to_json

This commit is contained in:
dichgrem
2025-12-26 11:00:57 +08:00
parent d076ee1d3a
commit 61655580fd
9 changed files with 550 additions and 303 deletions

View File

@@ -5,137 +5,299 @@ import fs from "fs";
import path from "path";
function mockPlugin() {
const mockDir = path.resolve(process.cwd(), "mock");
const filePath = (file) => path.resolve(mockDir, file);
const send = (res, obj, code = 200) => {
res.statusCode = code;
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.end(JSON.stringify(obj));
};
const readJson = (file, fallback) => {
const p = filePath(file);
if (!fs.existsSync(p)) return fallback;
try {
return JSON.parse(fs.readFileSync(p, "utf-8") || "null") ?? fallback;
} catch {
return fallback;
}
};
const writeJson = (file, data) => {
const p = filePath(file);
fs.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
};
const readBodyJson = (req) =>
new Promise((resolve, reject) => {
let body = "";
req.on("data", (c) => (body += c));
req.on("end", () => {
try {
resolve(JSON.parse(body || "{}"));
} catch (e) {
reject(e);
}
});
});
const getPathname = (req) => {
try {
return new URL(req.url, "http://localhost").pathname;
} catch {
return req.url;
}
};
// 统一 success
const ok = (res) => send(res, { error: 0, msg: "success" });
// ===== 业务联动:积分更新规则 =====
// yearScore: score=duration*2看起来是 1小时=2分
const POINTS_PER_HOUR = 2;
const addScore = (deltaHour) => {
const deltaScore = (Number(deltaHour) || 0) * POINTS_PER_HOUR;
// userInfo.json
const ui = readJson("userInfo.json", { error: 0, data: {} });
ui.data = ui.data || {};
ui.data.totalScore = (Number(ui.data.totalScore) || 0) + deltaScore;
writeJson("userInfo.json", ui);
// userScore.json
const us = readJson("userScore.json", { error: 0, data: {} });
us.data = us.data || {};
us.data.totalScore = (Number(us.data.totalScore) || 0) + deltaScore;
writeJson("userScore.json", us);
// scoreOverview.json
const ov = readJson("scoreOverview.json", { error: 0, data: {} });
ov.data = ov.data || {};
ov.data.totalScore = (Number(ov.data.totalScore) || 0) + deltaScore;
writeJson("scoreOverview.json", ov);
// yearScore.json
const ys = readJson("yearScore.json", { error: 0, data: {} });
ys.data = ys.data || {};
ys.data.times = (Number(ys.data.times) || 0) + 1;
ys.data.duration =
(Number(ys.data.duration) || 0) + (Number(deltaHour) || 0);
ys.data.score = (Number(ys.data.score) || 0) + deltaScore;
writeJson("yearScore.json", ys);
};
return {
name: "simple-mock-plugin",
configureServer(server) {
server.middlewares.use((req, res, next) => {
server.middlewares.use(async (req, res, next) => {
const pathname = getPathname(req);
// ========== GET仍然走你原来的静态文件 ==========
const sendJSON = (file) => {
const filePath = path.resolve(process.cwd(), `mock/${file}`);
if (!fs.existsSync(filePath)) {
res.statusCode = 404;
res.setHeader("Content-Type", "application/json");
return res.end(
JSON.stringify({
error: `Mock file not found: ${file}`,
}),
);
const p = filePath(file);
if (!fs.existsSync(p)) {
return send(res, { error: `Mock file not found: ${file}` }, 404);
}
const json = fs.readFileSync(filePath, "utf-8");
res.setHeader("Content-Type", "application/json");
res.end(json);
res.setHeader("Content-Type", "application/json; charset=utf-8");
res.end(fs.readFileSync(p, "utf-8"));
};
// 用户信息
if (req.url === "/api/userInfo" && req.method === "GET") {
if (pathname === "/api/userInfo" && req.method === "GET")
return sendJSON("userInfo.json");
}
// 提交用户信息
if (req.url === "/api/userInfo/submit" && req.method === "POST") {
return sendJSON("success.json");
}
// 活动列表
if (req.url.startsWith("/api/actList") && req.method === "GET") {
if (pathname.startsWith("/api/actList") && req.method === "GET")
return sendJSON("actList.json");
}
// 积分概览
if (
req.url.startsWith("/api/report/myOverview") &&
pathname.startsWith("/api/report/myOverview") &&
req.method === "GET"
) {
)
return sendJSON("scoreOverview.json");
}
// 排名列表
if (
req.url.startsWith("/api/report/rankList") &&
req.method === "GET"
) {
if (pathname.startsWith("/api/report/rankList") && req.method === "GET")
return sendJSON("rank.json");
}
// 活动详情
if (
req.url.startsWith("/api/actDetails/details") &&
pathname.startsWith("/api/actDetails/details") &&
req.method === "GET"
) {
)
return sendJSON("actDetails.json");
}
// 申请/撤销活动
if (
req.url.startsWith("/api/actDetails/apply") &&
req.method === "POST"
) {
return sendJSON("success.json");
}
// 我的报名列表
if (req.url.startsWith("/api/myApplyList") && req.method === "GET") {
if (pathname.startsWith("/api/myApplyList") && req.method === "GET")
return sendJSON("myApplyList.json");
}
// 活动来源列表
if (
req.url.startsWith("/api/act/publisherList") &&
pathname.startsWith("/api/act/publisherList") &&
req.method === "GET"
) {
)
return sendJSON("publishers.json");
}
// 服务时长列表
if (
req.url.startsWith("/api/act/durationsList") &&
pathname.startsWith("/api/act/durationsList") &&
req.method === "GET"
) {
)
return sendJSON("durationList.json");
if (
pathname.startsWith("/api/service/userScore") &&
req.method === "GET"
)
return sendJSON("userScore.json");
if (
pathname.startsWith("/api/service/yearList") &&
req.method === "GET"
)
return sendJSON("yearList.json");
if (
pathname.startsWith("/api/service/yearScore") &&
req.method === "GET"
)
return sendJSON("yearScore.json");
if (pathname.startsWith("/api/service/list") && req.method === "GET")
return sendJSON("serviceList.json");
if (pathname.startsWith("/api/service/details") && req.method === "GET")
return sendJSON("recordDetails.json");
// ========== POST全部改成“落盘” ==========
// 1) 用户信息保存
if (pathname === "/api/userInfo/submit" && req.method === "POST") {
try {
const incoming = await readBodyJson(req); // {name,code,gender,phoneNum,school,profession,userType...}
const old = readJson("userInfo.json", { error: 0, data: {} });
const next = {
error: 0,
data: { ...(old.data || {}), ...incoming },
};
writeJson("userInfo.json", next);
return ok(res);
} catch {
return send(res, { error: 1, msg: "Invalid JSON body" }, 400);
}
}
// 上传服务记录
// 2) 申请/撤销活动:更新 myApplyList + actDetails(可选 actList)
if (
req.url.startsWith("/api/act/uploadService") &&
pathname.startsWith("/api/actDetails/apply") &&
req.method === "POST"
) {
return sendJSON("success.json");
try {
const incoming = await readBodyJson(req);
// 约定:至少要有 id可选传 action: "apply" | "cancel"
const id = Number(incoming.id ?? incoming.actId);
const action = incoming.action || "apply";
if (!id) return send(res, { error: 1, msg: "missing id" }, 400);
// 读活动列表,用来补齐标题/时间/地点等字段
const actList = readJson("actList.json", {
error: 0,
data: { list: [] },
});
const act = (actList.data?.list || []).find(
(x) => Number(x.id) === id,
);
// myApplyList.json
const applyJson = readJson("myApplyList.json", {
error: 0,
data: { current: 1, pageSize: 10, pageCount: 1, list: [] },
});
const list = applyJson.data?.list || [];
const existsIdx = list.findIndex((x) => Number(x.id) === id);
if (action === "cancel") {
if (existsIdx >= 0) list.splice(existsIdx, 1);
} else {
// apply
if (existsIdx < 0) {
// 申请状态:你的 mock 里 1/2 出现过。这里用 1 表示已申请
list.unshift({ ...(act || { id }), applyStatus: 1 });
} else {
list[existsIdx].applyStatus = 1;
}
}
applyJson.data = applyJson.data || {};
applyJson.data.list = list;
applyJson.data.pageCount = 1;
writeJson("myApplyList.json", applyJson);
// actDetails.json让详情页刷新后看到申请状态变化
const detailsJson = readJson("actDetails.json", {
error: 0,
data: { details: {} },
});
if (
detailsJson.data?.details &&
Number(detailsJson.data.details.id) === id
) {
if (action === "cancel") {
detailsJson.data.details.applyStatus = 0;
detailsJson.data.details.canApply = true;
} else {
detailsJson.data.details.applyStatus = 1;
detailsJson.data.details.canApply = false;
}
writeJson("actDetails.json", detailsJson);
}
// actList.json可选列表 canApply 同步变化
if (act) {
const idx = (actList.data?.list || []).findIndex(
(x) => Number(x.id) === id,
);
if (idx >= 0) {
actList.data.list[idx].canApply = action === "cancel";
writeJson("actList.json", actList);
}
}
return ok(res);
} catch {
return send(res, { error: 1, msg: "Invalid JSON body" }, 400);
}
}
// 用户积分
// 3) 上传服务记录:写 serviceList + 联动积分文件
if (
req.url.startsWith("/api/service/userScore") &&
req.method === "GET"
pathname.startsWith("/api/act/uploadService") &&
req.method === "POST"
) {
return sendJSON("userScore.json");
}
try {
const incoming = await readBodyJson(req);
// 约定:时长字段可能叫 hour / duration / value
const hour =
Number(
incoming.hour ?? incoming.duration ?? incoming.value ?? 0,
) || 0;
// 年份列表
if (
req.url.startsWith("/api/service/yearList") &&
req.method === "GET"
) {
return sendJSON("yearList.json");
}
// serviceList.json 结构:{data:{list:[{id,pic,content,publisher,time,status}]}}
const sl = readJson("serviceList.json", {
error: 0,
data: { current: 1, pageSize: 10, pageCount: 1, list: [] },
});
const list = sl.data?.list || [];
// 年度积分
if (
req.url.startsWith("/api/service/yearScore") &&
req.method === "GET"
) {
return sendJSON("yearScore.json");
}
const nextId =
list.reduce((m, x) => Math.max(m, Number(x.id) || 0), 0) + 1;
// 服务记录列表
if (req.url.startsWith("/api/service/list") && req.method === "GET") {
return sendJSON("serviceList.json");
}
list.unshift({
id: nextId,
pic: incoming.pic || "./imgs/actImg.jpeg",
content: incoming.content || "新增服务记录",
publisher: incoming.publisher || "未知来源",
time: incoming.time || Date.now(),
status: 1, // 1=通过?你 recordDetails.status=1看起来是已审核/有效
// 额外字段可保留(不影响页面)
hour,
});
// 服务详情
if (
req.url.startsWith("/api/service/details") &&
req.method === "GET"
) {
return sendJSON("recordDetails.json");
sl.data = sl.data || {};
sl.data.list = list;
sl.data.pageCount = 1;
writeJson("serviceList.json", sl);
// 同步更新积分(按 1小时=2分
if (hour > 0) addScore(hour);
return ok(res);
} catch {
return send(res, { error: 1, msg: "Invalid JSON body" }, 400);
}
}
next();
@@ -145,10 +307,6 @@ function mockPlugin() {
}
export default defineConfig({
base: './',
plugins: [
vue(),
mockPlugin(),
VueDevTools(),
],
})
base: "./",
plugins: [vue(), mockPlugin(), VueDevTools()],
});