mm_os
Version:
MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。
1,465 lines (1,343 loc) • 37.5 kB
JavaScript
const Excel = require('mm_excel');
if (!global.$) {
global.$ = {};
}
if (!$.dict) {
$.dict = {};
}
$.dict.user_id = 'user_id';
$.dict.player_id = 'player_id';
$.dict.role_id = 'role_id';
/**
* Sql操作驱动类
* @class
*/
class Drive {
static config = {
// 表名 {0} 代表可前端传参自定义查询的表
table: '{0}',
// ID 用于查询时的主键 例如:id
id: 'id',
// 主键 用于水平连表查询时 例如:id
key: '',
// 排序 {0} 代表可前台传参自定义排序规则 格式: `name` asc, `id` desc
orderby: '{0}',
// 默认排序 `id` desc
orderby_default: '',
// 显示的字段 {0} 代表可前台传参自定义查询的字段, 例如: `id`,`username`,`name`,`email`
field: '{0}',
// 默认显示字段 例如: `id`,`username`,`name`
field_default: '*',
// 隐藏字段 有些字段即使前端请求也不能返回,这是通过隐藏字段将其过滤掉, 例如:password *表示包含匹配
field_hide: ['*password*', '*token*', 'salt'],
// 分页大小,默认一页显示条数
page_size: 30,
/* 过滤参数 */
filter: {
/**
* 表名
*/
table: 'table',
/**
* 查询的页码
*/
page: 'page',
/**
* 查询每页条数
*/
size: 'size',
/**
* 操作方式: 传入参数method=add, 支持参数 add增、del删、set改、get查,为空则为get
*/
method: 'method',
/**
* 排序
*/
orderby: 'orderby',
/**
* 查询显示的字段
*/
field: 'field',
/**
* 统计结果: 统计符合条件的结果数,只有当page等于1或0时才会统计
*/
count_ret: 'count_ret',
},
// 分隔符 用于查询时的多条件处理
sep: '|',
// 支持的方法 add增、del删、set改、get查, 只填get表示只支持查询 // import export del_repeat",
method:
'add del set get get_obj import export del_repeat avg sum count update',
// sql查询语句
query: {},
// 默认查询, 当查询条件中不包含该项时,默认添加该项。 例如: { 'age': '`age` < 20' } , 当查询参含有age,不调用该项,不存在时,sql会增加该项
query_default: {},
// sql更改语句
update: {},
// 默认添加条件,当不包含该项时,默认添加该项。 例如: { 'age': '`age` += 1' } , 当查询参含有age,不调用该项,不存在时,sql会增加该项
body_default: {},
// 文件路径, 当调用函数不存在时,会先从文件中加载
main: '',
// 回调函数名 用于决定调用脚本的哪个函数
func_name: '',
// 参数 []
params: null,
// 格式
format: [
/* {
// 表名,当选择转换方式 表转换时需填写
'table': 'mm_web_region',
// 查询条件,用于加速转换
'query': {
'group': '市'
},
// 表标题名
'title': '所属省份',
// 转换ID
'id': 'province_id',
// 转换主键
'key': 'province',
// 取名
'name': 'name',
// 列表
'list': [{
'province_id': 1,
'name': '广东省'
},
{
'province_id': 2,
'name': '广西省'
},
{
'province_id': 3,
'name': '湖南省'
}
]
},
{
'title': '是否可见',
'key': 'show',
'list': ['否', '是']
} */
],
/* 去重 */
del_repeat: {
// 判断重复的字段,例如字段名 number
group_by: '',
// 排序方式 例如: `diJia` ASC
order_by: '',
},
/* 逻辑符 */
logic: {},
// 输出sql语句
log: false,
};
/**
* 构造函数
* @param {object} config 配置参数
* @class
*/
constructor(config) {
// 配置参数
this.config = { ...Drive.config };
/* 通用项 */
this.params = null;
this.setConfig(config);
}
}
/**
* 日志
* @param {string} level 日志级别
* @param {string} msg 日志消息
* @param {...any} args 日志参数
*/
Drive.prototype.log = function (level, msg, ...args) {
this.getLogger()[level](`[${this.constructor.name}] ${msg}`, ...args);
};
/**
* 设置配置参数
* @param {object} config 配置参数
*/
Drive.prototype.setConfig = function (config) {
$.push(this.config, config, true);
};
/**
* 执行前, 可用于过滤参数
* @param {object} db 数据库管理器
* @param {object} query 查询url参数
* @param {object} body 修改时置入body的参数
* @returns {object} 过滤后的参数
*/
Drive.prototype.before = async function (db, query, body) {
this.log('info', 'before', query, body, db);
return {
query,
body,
};
};
/**
* 验证, 用于判断是否执行
* @param {object} db 数据管理器
* @param {object} query 查询url参数
* @param {object} body 修改时置入body的参数
* @returns {boolean} 验证通过返回true, 失败返回false
*/
Drive.prototype.check = async function (db, query, body) {
this.log('info', 'check', query, body, db);
return true;
};
/**
* 执行后操作,可用于附加执行
* @param {object} db 数据管理器
* @returns {object} 最终执行结果
*/
Drive.prototype.after = async function (db) {
return db.ret;
};
/**
* 执行修改
* @param {object} db 数据库管理器
* @param {object} query 查询url参数
* @param {object} body 修改时置入body的参数
* @returns {object} 执行结果
*/
Drive.prototype.run = async function (db, query, body) {
await this.before(db, query, body);
if (this.check(db, query, body)) {
var ret = await this.main(db, query, body);
if (!ret.error) {
db.ret = ret;
return await this.after(db);
}
return ret;
}
return null;
};
/**
* SQL操作准备
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @returns {object} 返回准备参数
*/
Drive.prototype.ready = function (db, query) {
var cg = this.config;
var qy = { ...query };
$.push(db.config.filter, cg.filter, true);
db.filter(qy);
return {
cg,
qy,
};
};
/**
* 获取查询字段设置
* @param {object} cg 配置
* @param {string} field 字段值
* @param {string} method 查询方法
* @returns {string} 字段设置
*/
Drive.prototype._getFieldSet = function (cg, field, method) {
if (cg.field.has('*{0}*')) {
if (field) {
return cg.field.replace('{0}', field);
} else if (method === 'get_obj' && cg.field_obj) {
return cg.field_obj + '';
} else if (cg.field_default) {
return cg.field_default + '';
}
}
return cg.field + '';
};
/**
* 获取排序方式设置
* @param {object} cg 配置
* @param {string} orderby 排序字段
* @returns {string} 排序设置
*/
Drive.prototype._getOrderbySet = function (cg, orderby) {
if (cg.orderby.has('*{0}*')) {
if (orderby) {
return cg.orderby.replace('{0}', orderby);
} else if (cg.orderby_default) {
return cg.orderby_default + '';
}
}
return cg.orderby + '';
};
/**
* 处理默认查询条件
* @param {string} query_str 查询字符串
* @param {object} query_default 默认查询条件
* @param {object} query 查询参数
* @param {object} db 数据库副本
* @returns {string} 处理后的查询字符串
*/
Drive.prototype._runDefaultGet = function (query_str, query_default, query, db) {
var ret_str = query_str;
if (Object.keys(query_default).length > 0) {
var qt_str = db.tplQuery(query, query_default);
if (qt_str) {
ret_str = query_str + ' AND ' + qt_str;
}
}
return ret_str;
};
/**
* 生成查询条件
* @param {object} db 数据库管理器
* @param {object} query 查询参数
* @param {string} method 查询方法
* @returns {string} 返回查询条件
*/
Drive.prototype.toWhere = function (db, query, method) {
var ready = this.ready(db, query, {});
var cg = ready.cg;
var qy = $.clone(ready.qy);
if (!query.size && cg.page_size) {
db.size = cg.page_size + 0;
}
if (db.size > 0 && db.page === 0) {
db.page = 1;
}
var f = db.config.filter;
// 获取查询字段设置
var field = query[f.field];
var fld = this._getFieldSetting(cg, field, method);
// 获取排序方式设置
var orderby = query[f.orderby];
var ord = this._getOrderbySetting(cg, orderby);
// 处理查询参数
if (!cg.field.has('*{0}*') && field) {
qy[f.field] = field;
}
if (!cg.orderby.has('*{0}*') && orderby) {
qy[f.orderby] = orderby;
}
// 应用字段和排序设置到数据库副本
db.field = fld;
db.orderby = ord;
var query_str = db.tplQuery(qy, cg.query);
var qt = cg.query_default;
// 处理默认查询条件
var final_query_str = this._handleDefaultQuery(query_str, qt, qy, db);
return final_query_str;
};
/**
* 查询(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} method 方法
* @returns {object} 返回查询结果
*/
Drive.prototype.getMain = async function (db, query, method) {
var ret;
var query_str = this.toWhere(db, query, method);
// 查询
try {
if (db.count_ret === 'true') {
ret = await db.getCountSql(query_str, db.orderby, db.field);
} else {
ret = await db.getSql(query_str, db.orderby, db.field);
}
// 对查询结果进行脱敏处理
if (
ret &&
ret.list &&
this.config.field_hide &&
this.config.field_hide.length > 0
) {
ret.list = this._filterFields(ret.list);
}
return ret;
} catch {
return $.ret.error(10000, '查询错误');
}
};
/**
* 查询
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @returns {object} 返回查询结果
*/
Drive.prototype.get = async function (db, query) {
var ret = await this.getMain(db, query);
if (ret && ret.list) {
return $.ret.list(ret.list);
}
return $.ret.list([]);
};
/**
* 查询单条数据
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @returns {object} 返回查询结果
*/
Drive.prototype.getObj = async function (db, query) {
var qy = $.clone(query);
qy.page = 1;
qy.size = 1;
var ret = await this.getMain(db, qy, 'get_obj');
var result;
if (ret && ret.list) {
if (ret.list.length > 0) {
result = $.ret.obj(ret.list[0]);
} else {
// 查询不到数据时返回空对象,而不是null
result = $.ret.obj({});
}
} else {
// 查询不到数据时返回空对象,而不是null
result = $.ret.obj({});
}
return result;
};
/**
* 修改(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回修改结果
*/
Drive.prototype.setMain = async function (db, query, body) {
var ret;
var ready = this.ready(db, query, body);
var cg = ready.cg;
var qy = ready.qy;
var key = cg.key;
if (body[key]) {
qy[key] = body[key];
}
var query_str = db.tplQuery(qy, cg.query);
var qt = cg.query_default;
if (Object.keys(qt).length > 0) {
var id = $.dict.user_id;
var user_id = '0';
var user = db.user;
if (user && user[id]) {
user_id = user[id];
}
for (var k in qt) {
if (!qy[k]) {
query_str += ' && ' + qt[k].replace('{' + id + '}', user_id);
}
}
if (query_str.startsWith(' && ')) {
query_str = query_str.replace(' && ', '');
}
}
var sql = db.tplBody(body, cg.update);
var n = await db.setSql(query_str, sql);
if (n < 1) {
ret = $.ret.error(500, '修改失败!\n' + db.error.message);
$.log.error('修改SQL', db.sql, db.error);
} else {
ret = $.ret.bl(true, '修改成功!');
}
return ret;
};
/**
* 修改
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回查询结果
*/
Drive.prototype.set = async function (db, query, body) {
return await this.setMain(db, query, body);
};
/**
* 添加(主要)
* @param {object} db 数据库操作类
* @param {object} body 添加项
* @returns {object} 返回查询结果
*/
/**
* 处理默认参数值
* @param {object} body 参数对象
* @param {object} bt 默认参数配置
* @param {object} db 数据库操作类
* @returns {object} 处理后的参数对象
*/
Drive.prototype._runDefaults = function (body, bt, db) {
var id = $.dict.user_id;
var user_id = '0';
var user = db.user;
var result = $.clone(body);
if (user && user[id]) {
user_id = user[id];
}
for (var k in bt) {
if (!result[k]) {
result[
bt[k]
.replace('{' + id + '}', user_id)
.left('=')
.trim('`')
] = bt[k]
.replace('{' + id + '}', user_id)
.right('=')
.trim('\'');
}
}
return result;
};
/**
* 添加(主要)
* @param {object} db 数据库操作类
* @param {object} body 添加项
* @returns {object} 返回查询结果
*/
Drive.prototype.addMain = async function (db, body) {
var ready = this.ready(db, {});
var cg = ready.cg;
var result;
var bd = $.clone(body);
if (Object.keys(bd).length > 0) {
var bt = cg.body_default;
if (Object.keys(bt).length > 0) {
bd = this._processDefaults(bd, bt, db);
}
var n = await db.add(bd);
if (n < 1) {
result = $.ret.error(500, '添加失败!\n' + db.error.message);
$.log.error('添加SQL', db.sql, db.error);
} else {
result = $.ret.bl(true, '添加成功!');
}
} else {
result = $.ret.error(30001, '参数不能为空');
}
if (cg.log) {
$.log.debug('添加SQL语句', db.sql);
}
return result;
};
/**
* 添加
* @param {object} db 数据库操作类
* @param {object} body 修改项
* @returns {object} 返回添加结果
*/
Drive.prototype.add = async function (db, body) {
return await this.addMain(db, body);
};
/**
* 删除(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @returns {object} 返回查询结果
*/
Drive.prototype.delMain = async function (db, query) {
var ret;
var { cg, qy } = this.ready(db, query, {});
var query_str = db.tplQuery(qy, cg.query);
var bl = await db.run(query_str);
if (bl < 1) {
ret = $.ret.error(500, '删除失败!\n' + db.error.message);
$.log.error('删除SQL', db.sql, db.error);
} else {
ret = $.ret.bl(true, '删除成功!');
}
if (cg.log) {
$.log.debug('删除SQL语句', db.sql);
}
return ret;
};
/**
* 删除
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @returns {object} 返回删除结果
*/
Drive.prototype.del = async function (db, query) {
return await this.delMain(db, query);
};
/**
* 批量添加(主要)
* @param {object} db 数据库操作类
* @param {Array} list 添加项列表
* @returns {object} 返回批量添加结果
*/
Drive.prototype.addListMain = async function (db, list) {
if (Array.isArray(list) && list.length > 0) {
var success_num = 0,
error_num = 0,
errors = [],
list_error = [];
for (var i = 0; i < list.length; i++) {
var result = await this.addMain(db, list[i]);
if (result.error) {
error_num++;
errors.push(result.message);
list_error.push(list[i]);
} else {
success_num++;
}
}
var ret = $.ret.bl(
success_num > 0,
success_num > 0 ? '批量添加成功!' : '批量添加失败!',
);
ret.result = {
total: list.length,
success: success_num,
error: error_num,
list_error: list_error,
errors: errors,
};
return ret;
}
return $.ret.error(30001, '参数不能为空');
};
/**
* 批量添加
* @param {object} db 数据库操作类
* @param {Array} list 添加项列表
* @returns {object} 返回批量添加结果
*/
Drive.prototype.addList = async function (db, list) {
return await this.addListMain(db, list);
};
/**
* 添加或修改(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回修改结果
*/
Drive.prototype.addOrSetMain = async function (db, query, body) {
var ret;
var { cg, qy } = this.ready(db, query, body);
if (Object.keys(body).length > 0 && Object.keys(qy).length > 0) {
var n = await db.addOrSet(qy, body);
if (n < 1) {
ret = $.ret.error(500, '操作失败!\n' + db.error.message);
$.log.error('添加或修改SQL', db.sql, db.error);
} else {
ret = $.ret.bl(true, '操作成功!');
}
} else {
ret = $.ret.error(30001, '参数不能为空');
}
if (cg.log) {
$.log.debug('添加或修改SQL语句', db.sql);
}
return ret;
};
/**
* 添加或修改
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 修改项
* @returns {object} 返回查询结果
*/
Drive.prototype.addOrSet = async function (db, query, body) {
return await this.addOrSetMain(db, query, body);
};
/**
* 获取数据类型
* @param {string} type 数据库数据类型
* @returns {string} 返回数据类型
*/
Drive.prototype.getType = function (type) {
if (type.indexOf('int') !== -1) {
return 'number';
} else {
return 'string';
}
};
/**
* 从配置获取参数
* @param {object} cg 配置
* @returns {Array|null} 参数列表或null
*/
Drive.prototype._getArgsFromConfig = function (cg) {
if (cg.params) {
return cg.params;
}
if (this.params) {
return this.params;
}
return null;
};
/**
* 从池获取字段列表
* @param {object} cg 配置
* @returns {Array} 字段列表
*/
Drive.prototype._getFieldsFromPool = function (cg) {
var lt = [];
if ($.pool.sql) {
var pool = $.pool.sql['sys'];
if (pool) {
var dt = pool.get(cg.table);
if (dt && dt.config) {
var list = dt.config.fields;
for (var i = 0; i < list.length; i++) {
var name = list[i].replace(/`/g, '');
lt.push({
name,
title: name,
});
}
}
}
}
return lt;
};
/**
* 从数据库获取字段列表
* @param {object} db 数据库操作类
* @param {object} cg 配置
* @returns {Array} 字段列表
*/
Drive.prototype._getFieldsFromDb = async function (db, cg) {
var lt = [];
db.table = cg.table;
var list = await db.fields();
for (var i = 0; i < list.length; i++) {
var o = list[i];
var note = o.note ? o.note.replace(':', ':') : o.name;
lt.push({
name: o.name,
title: note.left(':', true),
type: this.getType(o.type),
});
}
return lt;
};
/**
* 过滤参数
* @param {Array} lt 字段列表
* @param {string} fields 字段字符串
* @param {object} cg 配置
* @returns {Array} 过滤后的参数列表
*/
Drive.prototype._filterArgs = function (lt, fields, cg) {
var field = fields;
if (!field) {
field = cg.field_default;
}
if (field && field !== '*') {
var arr = field.replace(/`/g, '').split(',');
var params = [];
arr.map((name) => {
var obj = lt.getObj({
name,
});
if (obj) {
params.push(obj);
}
});
return params;
}
return lt;
};
/**
* 获取数据
* @param {object} db 数据库操作类
* @param {Array} fields 要获取的字段数组
* @returns {Array} 返回参数信息列表
*/
Drive.prototype.getFields = async function (db, fields) {
var cg = this.config;
// 从配置获取参数
var params_from_config = this._getFromConfig(cg);
if (params_from_config) {
return params_from_config;
}
// 从池获取字段列表
var lt = this._getFieldsFromPool(cg);
// 如果池中没有,从数据库获取
if (!lt.length) {
lt = await this._getFieldsFromDb(db, cg);
}
// 根据字段过滤参数
return this._filter(lt, fields, cg);
};
/**
* 获取导入导出格式
* @param {object} db 数据库操作类
* @returns {Array} 格式列表
*/
Drive.prototype.getFormat = async function (db) {
var dbs = { ...db };
dbs.size = 0;
var fmt = this.config.format;
for (var i = 0; i < fmt.length; i++) {
var o = fmt[i];
if (o.table) {
if (!o.list || o.list.length == 0) {
dbs.table = o.table;
if (!o.id) {
o.id = o.key;
}
o.list = await dbs.getSql(o.where, null, o.id + ',' + o.name);
if (o.id !== o.key) {
o.list.map((m) => {
var m_clone = $.clone(m);
m_clone[o.key] = m_clone[o.name];
return m_clone;
});
}
}
}
}
return fmt;
};
/**
* 处理文件路径
* @param {string} file 文件名
* @returns {string} 处理后的文件路径
*/
Drive.prototype._runFilePath = function (file) {
var file_copy = file;
if (file_copy.indexOf($.run_path) !== 0) {
file_copy = file_copy.replace(this.url_path, this.save_dir);
var path = $.config.get('static_path') || '/static/';
file_copy = file_copy.fullname(path);
}
return file_copy;
};
/**
* 加载文件数据
* @param {string} file 文件名
* @param {Array} fields 字段列表
* @param {Array} format 格式列表
* @returns {Array} 数据数组
*/
Drive.prototype._loadFileInfo = async function (file, fields, format) {
var jarr = [];
if (file.endsWith('.json')) {
jarr = file.loadJson();
} else if (file.endsWith('.xml')) {
jarr = file.loadXml();
} else {
var excel = new Excel({
file,
fields,
format,
});
try {
jarr = await excel.load();
} catch (e) {
$.log.error('导入文件', e);
} finally {
excel.clear();
excel = null;
}
}
return jarr;
};
/**
* 导入有主键的数据
* @param {object} db 数据库操作类
* @param {Array} jarr 数据数组
* @param {string} key 主键字段
* @returns {object} 导入结果
*/
Drive.prototype._importKey = async function (db, jarr, key) {
var list = [];
var errors = [];
var list_error = [];
for (var i = 0; i < jarr.length; i++) {
var o = jarr[i];
var qy = {};
qy[key] = o[key];
var n = await db.addOrSet(qy, o);
if (n < 1) {
errors.push(db.error);
list_error.push(o);
} else {
list.push(o);
}
}
return { list, errors, list_error };
};
/**
* 导入无主键的数据
* @param {object} db 数据库操作类
* @param {Array} jarr 数据数组
* @returns {object} 导入结果
*/
Drive.prototype._importWithoutKey = async function (db, jarr) {
var list = [];
var errors = [];
var list_error = [];
for (var i = 0; i < jarr.length; i++) {
var o = jarr[i];
var n = await db.add(o);
if (n < 1) {
errors.push(db.error);
list_error.push(o);
} else {
list.push(o);
}
}
return { list, errors, list_error };
};
/**
* 构建导入结果
* @param {Array} list 成功列表
* @param {Array} jarr 原始数据
* @param {Array} list_error 失败列表
* @param {Array} errors 错误列表
* @returns {object} 结果对象
*/
Drive.prototype._buildImportRet = function (list, jarr, list_error, errors) {
var bl = list.length === jarr.length;
var body = $.ret.bl(bl, bl ? '导入成功!' : '导入失败!');
body.result.list = list;
if (errors.length) {
body.result.list_error = list_error;
body.result.errors = errors;
}
return body;
};
/**
* 导入数据(主要)
* @param {object} db 数据库操作类
* @param {string} file 文件名
* @returns {object} 返回导入结果
*/
Drive.prototype.importMain = async function (db, file) {
var fields = await this.getFields(db);
var format = await this.getFormat(db);
// 处理文件路径
var file_copy = this._processFilePath(file);
if (!file_copy.hasFile()) {
return $.ret.error(30001, file_copy + '文件不存在!');
}
// 加载文件数据
var jarr = await this._loadFile(file, fields, format);
if (!jarr.length) {
return $.ret.error(10000, '要导入的数据不能为空!');
}
db.table = db.table || this.config.table;
var key = this.config.key;
// 导入数据
var imp;
if (jarr[0][key]) {
imp = await this._importKey(db, jarr, key);
} else {
imp = await this._importWithoutKey(db, jarr);
}
// 构建结果
return this._buildImport(
imp.list,
jarr,
imp.list_error,
imp.errors,
);
};
/**
* 导入数据
* @param {object} db 数据库操作类
* @param {string} file 文件名
* @returns {object} 返回执行结果
*/
Drive.prototype.import = async function (db, file) {
return await this.importMain(db, file);
};
/**
* 导出数据(主要)
* @param {object} db 数据库操作类
* @param {object} query 查询参数
* @param {object} body 正文参数(导出设置)
* @property {string} body.fields 需要导出的字段 例如: `username`,`gm`,`vip`
* @property {string} body.file 文件名 例如: 用户名.xlsx 、用户信息.csv 、用户账户.xls
* @property {string} body.path 文件路径 例如: /static/download, 可不填写
* @returns {object} 返回执行结果
*/
Drive.prototype.exportMain = async function (db, query, body) {
var by = await this.getMain(db, query);
var message = '';
if (db.error) {
message = db.error.message;
return $.ret.error(10000, message);
}
var config = this._getExportConfig(db, query, body);
var fields = await this.getFields(db, config.fields);
var format = await this.getFormat(db);
var file = await this._processExcelExport(
config,
fields,
format,
by.result.list,
);
return this._buildExport(file, config.name, message);
};
/**
* 获取导出配置
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 导出设置
* @returns {object} 导出配置对象
*/
Drive.prototype._getExportConfig = function (db, query, body) {
var { path, file, fields } = body;
var table = db.table || this.config.table;
var date = new Date();
var name = table + '_' + date.stamp() + '.xlsx';
path = this._getExportPath(path);
file = this._getExportFile(file, name);
fields = this._getExportFields(fields, query);
return {
path,
file,
fields,
name,
};
};
/**
* 获取导出路径
* @param {string} path 路径参数
* @returns {string} 导出路径
*/
Drive.prototype._getExportPath = function (path) {
if (!path) {
return $.config.get('static_path') || '/static/';
}
return path;
};
/**
* 获取导出文件
* @param {string} file 文件参数
* @param {string} name 文件名
* @returns {string} 导出文件路径
*/
Drive.prototype._getExportFile = function (file, name) {
if (!file) {
return this.save_dir + name;
}
return file;
};
/**
* 获取导出字段
* @param {string} fields 字段参数
* @param {object} query 查询条件
* @returns {string} 导出字段
*/
Drive.prototype._getExportFields = function (fields, query) {
if (!fields) {
if (query.field) {
return query.field;
} else {
var f = this.config.field_default;
if (f.length !== '*') {
return f;
}
}
}
return fields;
};
/**
* 处理Excel导出
* @param {object} config 导出配置
* @param {Array} fields 字段列表
* @param {object} format 格式设置
* @param {Array} list 数据列表
* @returns {string} 导出的文件路径
*/
Drive.prototype._runExcelExport = async function (
config,
fields,
format,
list,
) {
var file = config.file.fullname(config.path);
file.addDir();
var excel = new Excel({
file,
params: fields,
format,
});
try {
file = await excel.save(list);
} catch (e) {
$.log.error('导出保存文件失败!', e);
} finally {
excel.clear();
excel = null;
}
return file;
};
/**
* 构建导出结果
* @param {string} file 文件路径
* @param {string} name 文件名
* @param {string} message 消息
* @returns {object} 导出结果
*/
Drive.prototype._buildExportRet = function (file, name, message) {
var body = $.ret.bl(!!file, file ? '导出成功!' : '导出失败!');
body.result.file = file;
body.result.url = this.url_path + name;
if (message) {
body.result.message = message;
}
return body;
};
/**
* 导出数据
* @param {object} db 数据库操作类
* @param {object} query 查询条件
* @param {object} body 导出设置
* @returns {object} 返回执行结果
*/
Drive.prototype.export = async function (db, query, body) {
return await this.exportMain(db, query, body);
};
/**
* 删除重复项(主要)
* @param {object} db 数据库管理器
* @param {object} params 查询参数
* @returns {object} 返回执行结果
*/
Drive.prototype.delRepeatMain = async function (db, params) {
var msg = '';
var cg = this.config.del_repeat;
var pm = $.clone(params);
var order = pm.orderby || cg.orderBy;
delete pm.orderby;
var group = pm.groupby || cg.groupBy;
delete pm.groupby;
var f = db.config.filter;
// 设置查询字段
var field = pm[f.field] || group;
delete pm[f.field];
db.field = field;
var sql = db
.toGetSql(pm)
.replace(' * ', ' `' + field + '`, count(*) as len ');
sql += ` GROUP BY ${group}`;
sql = 'SELECT * FROM (' + sql + ') a WHERE len > 1';
var list = await db.run(sql);
if (list.length) {
db.page = 1;
db.size = 1;
var key = this.config.key;
for (var i = 0; i < list.length; i++) {
var o = list[i];
var len = o.len - 1;
delete o.len;
for (var n = 0; n < len; n++) {
var obj = await db.getObj(o, order, key);
if (obj) {
await db.del(obj);
}
}
}
} else {
msg = '没有重复项。';
}
return $.ret.bl(!msg, msg ? '去重失败!原因:' + msg : '去重成功!');
};
/**
* 删除重复项
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.delRepeat = async function (db, query) {
return await this.delRepeatMain(db, query);
};
/**
* 执行模板操作
* @param {object} db 数据管理器
* @param {object} query 查询参数
* @param {object} body 正文参数
* @returns {object} 返回执行结果
*/
Drive.prototype.main = async function (db, query, body) {
var cg = this.config;
var method = query.method;
if (!method) {
method = 'get';
}
if (!cg.method.has('*' + method + '*')) {
return $.ret.error(50001, '不支持的操作方式');
}
var qy = { ...query };
delete qy.method;
if (this[method]) {
db.method = method;
// 过滤查询参数
var f = cg.filter;
var table = query[f.table];
// 设置操作的数据表
if (cg.table.has('*{0}*')) {
if (table) {
db.table = cg.table.replace('{0}', table);
} else {
return $.ret.error(30001, '表名不能为空');
}
} else {
db.table = cg.table + '';
}
// 根据方法类型传递不同参数
if (method === 'add' || method === 'addList') {
return await this[method](db, { ...body });
} else {
return await this[method](db, qy, { ...body });
}
} else {
return $.ret.error(50001, '不支持的操作方式');
}
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} pm 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.sumMain = async function (db, pm) {
var ret;
var pm_clone = $.clone(pm);
var orderby = pm_clone.orderby || '';
delete pm_clone.orderby;
var groupby = pm_clone.groupby;
delete pm_clone.groupby;
var f = db.config.filter;
var field = pm_clone[f.field];
delete pm_clone[f.field];
var query_str = this.toWhere(db, pm_clone, 'get_list');
if (!groupby || !field) {
ret = $.ret.error(30000, '参数groupby、field是必须的,且值不能为空!');
} else {
var list = await db.groupSumSql(query_str, groupby, field, orderby);
if (!list.length && db.error) {
// $.log.error('SUM查询SQL', db.sql, db.error);
ret = $.ret.body(db.error);
} else {
ret = $.ret.list(list);
}
}
return ret;
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.sum = async function (db, query) {
return await this.sumMain(db, query);
};
/**
* 平均值
* @param {object} db 数据库管理器
* @param {object} pm 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.avgMain = async function (db, pm) {
var ret;
var pm_clone = $.clone(pm);
var orderby = pm_clone.orderby || '';
delete pm_clone.orderby;
var groupby = pm_clone.groupby;
delete pm_clone.groupby;
var f = db.config.filter;
var field = pm_clone[f.field];
delete pm_clone[f.field];
var query_str = this.toWhere(db, pm_clone, 'get_list');
if (!groupby || !field) {
ret = $.ret.error(30000, '参数groupby、field是必须的,且值不能为空!');
} else {
var list = await db.groupAvgSql(query_str, groupby, field, orderby);
if (!list.length && db.error) {
// $.log.error('AVG查询SQL', db.sql, db.error);
ret = $.ret.body(db.error);
} else {
ret = $.ret.list(list);
}
}
return ret;
};
/**
* 平均值
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.avg = async function (db, query) {
return await this.avgMain(db, query);
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} params 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.countMain = async function (db, params) {
var ret;
var pm_clone = $.clone(params);
var orderby = pm_clone.orderby || '';
delete pm_clone.orderby;
var groupby = pm_clone.groupby;
delete pm_clone.groupby;
var f = db.config.filter;
var field = pm_clone[f.field];
delete pm_clone[f.field];
var query_str = this.toWhere(db, pm_clone, 'get_list');
if (!groupby || !field) {
ret = $.ret.error(30000, '参数groupby、field是必须的,且值不能为空!');
} else {
var list = await db.groupCountSql(query_str, groupby, field, orderby);
if (!list.length && db.error) {
// $.log.error('COUNT查询SQL', db.sql, db.error);
ret = $.ret.body(db.error);
} else {
ret = $.ret.list(list);
}
}
return ret;
};
/**
* 总计
* @param {object} db 数据库管理器
* @param {object} query 查询条件
* @returns {object} 返回执行结果
*/
Drive.prototype.count = async function (db, query) {
return await this.countMain(db, query);
};
/**
* 过滤敏感字段
* @param {Array} list 数据列表
* @returns {Array} 过滤后的数据列表
*/
Drive.prototype._filterSens = function (list) {
if (!list || !Array.isArray(list) || list.length === 0) {
return list;
}
var lt = [];
for (var i = 0; i < list.length; i++) {
var item = this._filter(list[i]);
lt.push(item);
}
return lt;
};
/**
* 过滤单个对象的敏感字段
* @param {object} item 数据对象
* @returns {object} 过滤后的数据对象
*/
Drive.prototype._filterObj = function (item) {
if (!item || typeof item !== 'object') {
return item;
}
var obj = { ...item };
// 敏感字段集合
var arr = this.config.field_hide;
for (var i = 0; i < arr.length; i++) {
var word = arr[i];
for (var key in item) {
if (key.has(word)) {
delete obj[key];
}
}
}
return obj;
};
module.exports = { Drive };