1
This commit is contained in:
@@ -1,196 +0,0 @@
|
||||
/**
|
||||
* 订阅模块通用 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,
|
||||
buildSearchWhere,
|
||||
};
|
||||
128
api/service/biz_query_helpers.js
Normal file
128
api/service/biz_query_helpers.js
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* 列表筛选、写入字段裁剪、审计日志列表补列(供 admin 控制器直接配合 baseModel 使用)
|
||||
*/
|
||||
const Sequelize = require("sequelize");
|
||||
const { Op } = Sequelize;
|
||||
|
||||
function build_search_where(model, seach_option) {
|
||||
const key = seach_option && seach_option.key;
|
||||
const raw = seach_option && seach_option.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 type_key = attr.type && attr.type.key;
|
||||
|
||||
if (type_key === "BOOLEAN") {
|
||||
if (str === "true" || str === "1" || str === "是") return { [key]: true };
|
||||
if (str === "false" || str === "0" || str === "否") return { [key]: false };
|
||||
return {};
|
||||
}
|
||||
|
||||
if (type_key === "ENUM") {
|
||||
return { [key]: str };
|
||||
}
|
||||
|
||||
if (
|
||||
type_key === "INTEGER" ||
|
||||
type_key === "BIGINT" ||
|
||||
type_key === "FLOAT" ||
|
||||
type_key === "DOUBLE" ||
|
||||
type_key === "DECIMAL"
|
||||
) {
|
||||
const n = Number(str);
|
||||
if (!Number.isNaN(n)) return { [key]: n };
|
||||
return {};
|
||||
}
|
||||
|
||||
if (type_key === "DATE" || type_key === "DATEONLY") {
|
||||
return { [key]: str };
|
||||
}
|
||||
|
||||
return { [key]: { [Op.like]: `%${str}%` } };
|
||||
}
|
||||
|
||||
function normalize_for_write(model, data, { for_create } = {}) {
|
||||
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" && for_create) 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) {
|
||||
/* 保持原字符串 */
|
||||
}
|
||||
}
|
||||
out[k] = v;
|
||||
}
|
||||
if (for_create && out.id !== undefined && (out.id === "" || out.id === null)) {
|
||||
delete out.id;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function list_query_extra(model_name, model) {
|
||||
if (model_name === "biz_audit_log") {
|
||||
const tn = model.tableName;
|
||||
return {
|
||||
attributes: {
|
||||
include: [[model.sequelize.col(`${tn}.created_at`), "created_at"]],
|
||||
},
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
async function find_page(model, model_name, body, extra_find_options = {}) {
|
||||
const param = body.param || body;
|
||||
const page_option = param.pageOption || {};
|
||||
const seach_option = param.seachOption || {};
|
||||
const page_num = parseInt(page_option.page, 10) || 1;
|
||||
const page_size = parseInt(page_option.pageSize, 10) || 20;
|
||||
const offset = (page_num - 1) * page_size;
|
||||
const where = build_search_where(model, seach_option);
|
||||
return model.findAndCountAll({
|
||||
where,
|
||||
offset,
|
||||
limit: page_size,
|
||||
order: [["id", "DESC"]],
|
||||
...list_query_extra(model_name, model),
|
||||
...extra_find_options,
|
||||
});
|
||||
}
|
||||
|
||||
async function find_for_export(model, model_name, body, extra_find_options = {}) {
|
||||
const param = body.param || body;
|
||||
const where = build_search_where(model, param.seachOption || {});
|
||||
const rows = await model.findAll({
|
||||
where,
|
||||
limit: 10000,
|
||||
order: [["id", "DESC"]],
|
||||
...list_query_extra(model_name, model),
|
||||
...extra_find_options,
|
||||
});
|
||||
return { rows };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
build_search_where,
|
||||
normalize_for_write,
|
||||
list_query_extra,
|
||||
find_page,
|
||||
find_for_export,
|
||||
};
|
||||
Reference in New Issue
Block a user