This commit is contained in:
张成
2026-03-24 16:07:02 +08:00
commit aa8eaa6ccd
121 changed files with 34042 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
/**
* 订阅模块通用 CRUD与 admin 约定 POST /{model}/page|add|edit|del GET /{model}/detail|all
*/
const baseModel = require("../../middleware/baseModel");
const { op } = baseModel;
function getRequestBody(ctx) {
if (ctx.request && ctx.request.body && Object.keys(ctx.request.body).length > 0) {
return ctx.request.body;
}
if (typeof ctx.getBody === "function") {
return ctx.getBody() || {};
}
return {};
}
function getModel(modelName) {
const m = baseModel[modelName];
if (!m) {
throw new Error(`模型不存在: ${modelName}`);
}
return m;
}
function normalizeForWrite(model, data, { forCreate } = {}) {
const attrs = model.rawAttributes;
const out = {};
for (const k of Object.keys(data || {})) {
if (!attrs[k]) continue;
let v = data[k];
if (v === "") {
if (k === "id" && forCreate) continue;
if (k.endsWith("_id") || k === "id") {
v = null;
} else if (attrs[k].allowNull) {
v = null;
}
}
if (k === "enabled_features" && typeof v === "string" && v.trim() !== "") {
try {
v = JSON.parse(v);
} catch (e) {
/* 保持原字符串,由 Sequelize 或 DB 报错 */
}
}
out[k] = v;
}
if (forCreate && out.id !== undefined && (out.id === "" || out.id === null)) {
delete out.id;
}
return out;
}
function buildSearchWhere(model, seachOption) {
const key = seachOption && seachOption.key;
const raw = seachOption && seachOption.value;
if (!key || raw === undefined || raw === null) return {};
const str = String(raw).trim();
if (str === "") return {};
const attr = model.rawAttributes[key];
if (!attr) {
return { [key]: { [op.like]: `%${str}%` } };
}
const typeKey = attr.type && attr.type.key;
if (typeKey === "BOOLEAN") {
if (str === "true" || str === "1" || str === "是") return { [key]: true };
if (str === "false" || str === "0" || str === "否") return { [key]: false };
return {};
}
if (typeKey === "ENUM") {
return { [key]: str };
}
if (
typeKey === "INTEGER" ||
typeKey === "BIGINT" ||
typeKey === "FLOAT" ||
typeKey === "DOUBLE" ||
typeKey === "DECIMAL"
) {
const n = Number(str);
if (!Number.isNaN(n)) return { [key]: n };
return {};
}
if (typeKey === "DATE" || typeKey === "DATEONLY") {
return { [key]: str };
}
return { [key]: { [op.like]: `%${str}%` } };
}
async function page(modelName, body) {
const model = getModel(modelName);
const param = body.param || body;
const pageOption = param.pageOption || {};
const seachOption = param.seachOption || {};
const pageNum = parseInt(pageOption.page, 10) || 1;
const pageSize = parseInt(pageOption.pageSize, 10) || 20;
const offset = (pageNum - 1) * pageSize;
const where = buildSearchWhere(model, seachOption);
const { count, rows } = await model.findAndCountAll({
where,
offset,
limit: pageSize,
order: [["id", "DESC"]],
});
return { rows, count };
}
async function add(modelName, body) {
const model = getModel(modelName);
const payload = normalizeForWrite(model, body, { forCreate: true });
const row = await model.create(payload);
return row;
}
async function edit(modelName, body) {
const model = getModel(modelName);
const id = body.id;
if (id === undefined || id === null || id === "") {
throw new Error("缺少 id");
}
const payload = normalizeForWrite(model, body, { forCreate: false });
delete payload.id;
await model.update(payload, { where: { id } });
return {};
}
async function del(modelName, body) {
const model = getModel(modelName);
const id = body.id !== undefined ? body.id : body;
if (id === undefined || id === null || id === "") {
throw new Error("缺少 id");
}
await model.destroy({ where: { id } });
return {};
}
async function detail(modelName, query) {
const model = getModel(modelName);
const id = query && (query.id || query.ID);
if (id === undefined || id === null || id === "") {
throw new Error("缺少 id");
}
const row = await model.findByPk(id);
return row;
}
async function all(modelName) {
const model = getModel(modelName);
const rows = await model.findAll({
limit: 2000,
order: [["id", "DESC"]],
});
return rows;
}
async function exportCsv(modelName, body) {
const model = getModel(modelName);
const param = body.param || body;
const where = buildSearchWhere(model, param.seachOption || {});
const rows = await model.findAll({
where,
limit: 10000,
order: [["id", "DESC"]],
});
return { rows };
}
module.exports = {
page,
add,
edit,
del,
detail,
all,
exportCsv,
getRequestBody,
buildSearchWhere,
};