/** * 订阅模块通用 CRUD(与 admin 约定 POST /{model}/page|add|edit|del ,GET /{model}/detail|all) */ const baseModel = require("../../middleware/baseModel"); const { op } = baseModel; 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}%` } }; } /** 模型未声明但表中存在的列(列表/导出需要带出) */ function extraListAttributes(modelName, model) { if (modelName === "biz_audit_log") { const tn = model.tableName; return { attributes: { include: [[model.sequelize.col(`${tn}.created_at`), "created_at"]], }, }; } return {}; } 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"]], ...extraListAttributes(modelName, model), }); 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, extraListAttributes(modelName, model)); return row; } async function all(modelName) { const model = getModel(modelName); const rows = await model.findAll({ limit: 2000, order: [["id", "DESC"]], ...extraListAttributes(modelName, model), }); 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"]], ...extraListAttributes(modelName, model), }); return { rows }; } module.exports = { page, add, edit, del, detail, all, exportCsv, getRequestBody, buildSearchWhere, };