244 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ModuleConfig } from './../interface';
import {
Scope,
ScopeEnum,
saveClassMetadata,
saveModule,
CONTROLLER_KEY,
MiddlewareParamArray,
WEB_ROUTER_KEY,
attachClassMetadata,
} from '@midwayjs/core';
import * as fs from 'fs';
import * as _ from 'lodash';
import location from '../util/location';
export type ApiTypes = 'add' | 'delete' | 'update' | 'page' | 'info' | 'list';
/** 服务映射接口 */
export type ServiceApis = {
/** 方法 */
method: string;
/** 描述 */
summary: string;
};
// Crud配置
export interface CurdOption {
// 路由前缀不配置默认是按Controller下的文件夹路径
prefix?: string;
// curd api接口
api?: ApiTypes[];
// 服务映射接口
serviceApis?: (ServiceApis | string)[];
// 分页查询配置
pageQueryOp?: QueryOp | Function;
// 非分页查询配置
listQueryOp?: QueryOp | Function;
// 插入参数
insertParam?: Function;
// 操作之前
before?: Function;
// info 忽略返回属性
infoIgnoreProperty?: string[];
// 实体
entity?: any;
// 服务
service?: any;
// api标签
urlTag?: {
name: 'ignoreToken' | string;
url: ApiTypes[];
};
}
export interface JoinOp {
// 实体
entity: any;
// 别名
alias: string;
// 关联条件
condition: string;
// 关联类型
type?: 'innerJoin' | 'leftJoin';
}
// 字段匹配
export interface FieldEq {
// 字段
column: string;
// 请求参数
requestParam: string;
}
// 查询配置
export interface QueryOp {
// 需要模糊查询的字段
keyWordLikeFields?: string[];
// 查询条件
where?: Function;
// 查询字段
select?: string[];
// 字段模糊查询
fieldLike?: string[] | FieldEq[] | (string | FieldEq)[];
// 字段相等
fieldEq?: string[] | FieldEq[] | (string | FieldEq)[];
// 添加排序条件
addOrderBy?: {};
// 关联配置
join?: JoinOp[];
// 其他条件
extend?: Function;
}
// Controller 配置
export interface ControllerOption {
// crud配置 如果是字符串则为路由前缀不配置默认是按Controller下的文件夹路径
curdOption?: CurdOption & string;
// 路由配置
routerOptions?: {
// 是否敏感
sensitive?: boolean;
// 路由中间件
middleware?: MiddlewareParamArray;
// 别名
alias?: string[];
// 描述
description?: string;
// 标签名称
tagName?: string;
};
}
// 路由配置
export interface RouterOptions {
sensitive?: boolean;
middleware?: MiddlewareParamArray;
description?: string;
tagName?: string;
ignoreGlobalPrefix?: boolean;
}
// COOL的装饰器
export function CoolController(
curdOption?: CurdOption | string | RouterOptions,
routerOptions: RouterOptions = { middleware: [], sensitive: true }
): ClassDecorator {
return (target: any) => {
// 将装饰的类,绑定到该装饰器,用于后续能获取到 class
saveModule(CONTROLLER_KEY, target);
let prefix;
if (curdOption) {
// 判断 curdOption 的类型
if (typeof curdOption === 'string') {
prefix = curdOption;
} else if (curdOption && 'api' in curdOption) {
// curdOption 是 CurdOption 类型
prefix = curdOption.prefix || '';
} else {
// curdOption 是 RouterOptions 类型 合并到 routerOptions
routerOptions = { ...curdOption, ...routerOptions };
}
}
// 如果不存在路由前缀,那么自动根据当前文件夹路径
location.scriptPath(target).then(async (res: any) => {
if (!res?.path) return;
const pathSps = res.path.split('.');
const paths = pathSps[pathSps.length - 2].split(/[/\\]/);
const pathArr = [];
let module = null;
for (const path of paths.reverse()) {
if (path != 'controller' && !module) {
pathArr.push(path);
}
if (path == 'controller' && !paths.includes('modules')) {
break;
}
if (path == 'controller' && paths.includes('modules')) {
module = 'ready';
}
if (module && path != 'controller') {
module = `${path}`;
break;
}
}
if (module) {
pathArr.reverse();
pathArr.splice(1, 0, module);
// 追加模块中间件
const path = `${
res.path.split(new RegExp(`modules[/\\\\]${module}`))[0]
}modules/${module}/config.${_.endsWith(res.path, 'ts') ? 'ts' : 'js'}`;
if (fs.existsSync(path)) {
const config: ModuleConfig = require(path).default();
routerOptions.middleware = (config.middlewares || []).concat(
routerOptions.middleware || []
);
}
}
if (!prefix) {
prefix = `/${pathArr.join('/')}`;
}
saveMetadata(prefix, routerOptions, target, curdOption, module);
});
};
}
export const apiDesc = {
add: '新增',
delete: '删除',
update: '修改',
page: '分页查询',
list: '列表查询',
info: '单个信息',
};
// 保存一些元数据信息,任意你希望存的东西
function saveMetadata(prefix, routerOptions, target, curdOption, module) {
if (module && !routerOptions.tagName) {
routerOptions = routerOptions || {};
routerOptions.tagName = module;
}
saveClassMetadata(
CONTROLLER_KEY,
{
prefix,
routerOptions,
curdOption,
module,
} as ControllerOption,
target
);
// 追加CRUD路由
if (!_.isEmpty(curdOption?.api)) {
curdOption?.api.forEach(path => {
attachClassMetadata(
WEB_ROUTER_KEY,
{
path: `/${path}`,
requestMethod: path == 'info' ? 'get' : 'post',
method: path,
summary: apiDesc[path] || path,
description: '',
},
target
);
});
}
if (!_.isEmpty(curdOption?.serviceApis)) {
curdOption.serviceApis.forEach(api => {
const methodName = typeof api === 'string' ? api : api.method;
attachClassMetadata(
WEB_ROUTER_KEY,
{
path: `/${methodName}`,
requestMethod: 'post',
method: methodName,
summary: typeof api === 'string' ? api : api.summary,
description: '',
},
target
);
});
}
Scope(ScopeEnum.Request)(target);
}