forked from admin/deShanXiao
初始版本,目前线上可用
This commit is contained in:
101
backEnd/src/lib/curd/curd.ts
Normal file
101
backEnd/src/lib/curd/curd.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Request } from "express";
|
||||
import { Repository, getConnection } from "typeorm";
|
||||
import { filterObjEmptyVal } from "@/util/globalMethods";
|
||||
import dayjs from "dayjs";
|
||||
import pagination from "../pagination/pagination";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import getBuilderPagination from "../pagination/builderPagination";
|
||||
|
||||
interface CurdOptions<T> {
|
||||
entity: { new (): T } & typeof BaseEntity; // 确保实体继承 BaseEntity
|
||||
req: Request;
|
||||
params?: Partial<T>;
|
||||
}
|
||||
class Curd<T extends BaseEntity> {
|
||||
private entity: { new (): T };
|
||||
private req: Request;
|
||||
private queryParams?: { [key: string]: any };
|
||||
private repositrory: Repository<unknown>;
|
||||
private params?: Partial<T>;
|
||||
|
||||
constructor(options: CurdOptions<T> & { repository?: Repository<T> }) {
|
||||
if (!options.entity) throw Error("请传入实体类");
|
||||
if (!options.req)
|
||||
throw Error("请传express的Request参数,一般在中间件回调中的第一个参数");
|
||||
// if (!options.params) throw Error("请传入需要操作的条件对象,用于sql查询");
|
||||
this.req = options.req;
|
||||
this.entity = options.entity;
|
||||
|
||||
this.repositrory =
|
||||
options.repository || getConnection().getRepository(options.entity);
|
||||
this.queryParams =
|
||||
this.req.method === "GET" ? this.req.query : this.req.body;
|
||||
|
||||
this.params = options.params;
|
||||
}
|
||||
|
||||
async add() {
|
||||
let addData = { ...new this.entity(), ...this.queryParams };
|
||||
|
||||
addData.updateDate = new Date();
|
||||
addData.createDate = new Date();
|
||||
|
||||
return await this.repositrory.save(addData);
|
||||
}
|
||||
|
||||
async delete() {
|
||||
if (!this.queryParams?.id)
|
||||
return {
|
||||
code: 500,
|
||||
msg: "没有传入需要删除数据的ID",
|
||||
};
|
||||
let queryData = await this.repositrory.findOne({
|
||||
where: { id: this.queryParams.id },
|
||||
});
|
||||
if (!queryData) return { code: 500, msg: "删除的数据不存在" };
|
||||
await this.repositrory.remove(queryData);
|
||||
return {
|
||||
code: 200,
|
||||
msg: "删除成功",
|
||||
};
|
||||
}
|
||||
|
||||
async update() {
|
||||
let body = this.queryParams;
|
||||
await this.repositrory.update(
|
||||
{ id: body.id },
|
||||
{ ...this.queryParams, updateDate: new Date() }
|
||||
);
|
||||
|
||||
return await this.repositrory.findOne(this.queryParams.id);
|
||||
}
|
||||
|
||||
async query() {
|
||||
return await this.repositrory.find({
|
||||
where: filterObjEmptyVal({ ...this.queryParams, ...this.params }),
|
||||
order: {
|
||||
createDate: "DESC",
|
||||
},
|
||||
});
|
||||
}
|
||||
async queryList() {
|
||||
return await pagination(
|
||||
this.entity,
|
||||
this.req,
|
||||
filterObjEmptyVal({ ...this.queryParams, ...this.params })
|
||||
);
|
||||
}
|
||||
async queryBuilderList() {
|
||||
return await getBuilderPagination(
|
||||
this.entity,
|
||||
this.req,
|
||||
filterObjEmptyVal({ ...this.queryParams, ...this.params })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function curd<T extends BaseEntity>(
|
||||
options: CurdOptions<T>
|
||||
): Curd<T> {
|
||||
return new Curd(options);
|
||||
}
|
||||
32
backEnd/src/lib/menueToTree.ts
Normal file
32
backEnd/src/lib/menueToTree.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { SystemMenue } from "../entity/SystemMenue";
|
||||
interface routerTree extends SystemMenue {
|
||||
children?: SystemMenue[];
|
||||
}
|
||||
let filterKey = (obj: SystemMenue) => {
|
||||
delete obj.id;
|
||||
delete obj.updateDate;
|
||||
delete obj.createDate;
|
||||
delete obj.parentId;
|
||||
return obj;
|
||||
};
|
||||
export default function menueToTree(data: SystemMenue[]): routerTree[] {
|
||||
let dataList = [];
|
||||
if (!data.some((item) => item.parentId === 0)) {
|
||||
return data.map((item) => filterKey(item));
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let item: routerTree = data[i];
|
||||
|
||||
item.children = [];
|
||||
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
let childrenItem = data[j];
|
||||
if (childrenItem.parentId === item.id) {
|
||||
item.children.push(filterKey({ ...childrenItem }));
|
||||
}
|
||||
}
|
||||
// 只添加父级
|
||||
if (!item.parentId) dataList.push(filterKey({ ...item }));
|
||||
}
|
||||
return dataList;
|
||||
}
|
||||
113
backEnd/src/lib/pagination/builderPagination.ts
Normal file
113
backEnd/src/lib/pagination/builderPagination.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { getConnection, Between, Brackets } from "typeorm";
|
||||
import { Request } from "express";
|
||||
|
||||
type paginationType<T> = {
|
||||
list: T[];
|
||||
total: number;
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
};
|
||||
|
||||
const filterKeys = ["pwd"];
|
||||
const DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
export default async function getBuilderPagination<T>(
|
||||
entity: Function,
|
||||
req: Request,
|
||||
queryParams?: { [key: string]: any }
|
||||
): Promise<paginationType<T>> {
|
||||
try {
|
||||
// 获取分页参数
|
||||
const { pageSize, pageNumber } = getPaginationParams(req);
|
||||
const repository = getConnection().manager.getRepository(entity);
|
||||
const alias = "entity";
|
||||
|
||||
// 创建 QueryBuilder
|
||||
const queryBuilder = repository.createQueryBuilder(alias);
|
||||
// 处理查询参数
|
||||
if (queryParams) {
|
||||
Object.entries(queryParams).forEach(([key, value]) => {
|
||||
if (!["pageSize", "pageNumber"].includes(key)) {
|
||||
// 新增非空条件处理
|
||||
if (value === "NOT_EMPTY") {
|
||||
queryBuilder.andWhere(
|
||||
new Brackets((qb) => {
|
||||
qb.where(`${alias}.${key} IS NOT NULL`).andWhere(
|
||||
`${alias}.${key} != ''`
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
// 处理日期范围
|
||||
else if (typeof value === "string" && DATE_REGEX.test(value)) {
|
||||
const start = new Date(`${value}T00:00:00`);
|
||||
const end = new Date(`${value}T23:59:59`);
|
||||
queryBuilder.andWhere(
|
||||
new Brackets((qb) =>
|
||||
qb
|
||||
.where(`${alias}.${key} >= :start`, { start })
|
||||
.andWhere(`${alias}.${key} <= :end`, { end })
|
||||
)
|
||||
);
|
||||
}
|
||||
// 处理普通参数
|
||||
else if (value !== undefined) {
|
||||
// 处理数组参数(如?status=1,2,3)
|
||||
if (typeof value === "string" && value.includes(",")) {
|
||||
queryBuilder.andWhere(`${alias}.${key} IN (:...${key})`, {
|
||||
[key]: value.split(","),
|
||||
});
|
||||
}
|
||||
// 处理普通值
|
||||
else {
|
||||
queryBuilder.andWhere(`${alias}.${key} = :${key}`, {
|
||||
[key]: value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加排序
|
||||
queryBuilder.orderBy(`${alias}.createDate`, "DESC");
|
||||
|
||||
// 执行分页查询
|
||||
const [list, total] = await queryBuilder
|
||||
.skip((pageNumber - 1) * pageSize)
|
||||
.take(pageSize)
|
||||
.getManyAndCount();
|
||||
|
||||
// 过滤敏感字段
|
||||
const filteredList = list.map((item: any) => {
|
||||
const filtered = { ...item };
|
||||
filterKeys.forEach((key) => delete filtered[key]);
|
||||
return filtered;
|
||||
});
|
||||
|
||||
return {
|
||||
list: filteredList,
|
||||
total,
|
||||
pageSize,
|
||||
pageNumber,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new Error(`分页查询出错: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分页参数
|
||||
*/
|
||||
function getPaginationParams(req: Request): {
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
} {
|
||||
const { pageSize = 10, pageNumber = 1 } =
|
||||
req.method === "GET" ? req.query : req.body;
|
||||
|
||||
return {
|
||||
pageSize: Math.max(1, parseInt(pageSize as string, 10)),
|
||||
pageNumber: Math.max(1, parseInt(pageNumber as string, 10)),
|
||||
};
|
||||
}
|
||||
97
backEnd/src/lib/pagination/multPagination.ts
Normal file
97
backEnd/src/lib/pagination/multPagination.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { getConnection } from "typeorm";
|
||||
import { Request } from "express";
|
||||
|
||||
type paginationType<T> = {
|
||||
list: T[] | any[];
|
||||
total: number;
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
};
|
||||
|
||||
const filterKeys = ["pwd"];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param entites 传入实体类数组以供查询(支持多表)
|
||||
* @param req express的Request请求体
|
||||
* @param queryParams 查询参数
|
||||
* @param aliasMap 表别名映射,键为实体类名,值为别名
|
||||
* @returns
|
||||
*/
|
||||
export default async function MultPagination<T>(
|
||||
entites: Function[],
|
||||
req: Request,
|
||||
queryParams?: { [key: string]: any },
|
||||
aliasMap: { [key: string]: string } = {}
|
||||
): Promise<paginationType<T>> {
|
||||
const { pageSize, pageNumber } = getPaginationParams(req);
|
||||
|
||||
// 获取 QueryBuilder
|
||||
const queryBuilder = getConnection().createQueryBuilder();
|
||||
|
||||
// 构造 FROM 部分,支持多表
|
||||
entites.forEach((entite, index) => {
|
||||
const alias = aliasMap[entite.name] || `alias${index}`;
|
||||
if (index === 0) {
|
||||
queryBuilder.from(entite, alias); // 主表
|
||||
} else {
|
||||
queryBuilder.leftJoinAndSelect(entite, alias); // 关联表
|
||||
}
|
||||
});
|
||||
|
||||
// 构造 WHERE 条件
|
||||
if (queryParams) {
|
||||
Object.entries(queryParams).forEach(([key, value]) => {
|
||||
queryBuilder.andWhere(`${getWhereKey(key, aliasMap)} = :${key}`, {
|
||||
[key]: value,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 构造排序
|
||||
queryBuilder.orderBy("alias0.createDate", "ASC");
|
||||
|
||||
// 分页处理
|
||||
queryBuilder.skip((pageNumber - 1) * pageSize).take(pageSize);
|
||||
|
||||
try {
|
||||
const [list, total] = await queryBuilder.getManyAndCount();
|
||||
|
||||
// 过滤敏感数据
|
||||
list.forEach((item) => {
|
||||
filterKeys.forEach((key) => {
|
||||
delete item[key];
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
list,
|
||||
total,
|
||||
pageSize,
|
||||
pageNumber,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new Error("分页查询出错:" + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
function getPaginationParams(req: Request): {
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
} {
|
||||
const { pageSize = 10, pageNumber = 1 } =
|
||||
req.method === "GET" ? req.query : req.body;
|
||||
const realPageSize = Math.max(1, parseInt(pageSize as string, 10));
|
||||
const realPageNumber = Math.max(1, parseInt(pageNumber as string, 10));
|
||||
return { pageSize: realPageSize, pageNumber: realPageNumber };
|
||||
}
|
||||
|
||||
// 获取WHERE条件时自动识别别名
|
||||
function getWhereKey(key: string, aliasMap: { [key: string]: string }) {
|
||||
for (const alias in aliasMap) {
|
||||
if (key.startsWith(alias + ".")) {
|
||||
return key; // 已包含别名
|
||||
}
|
||||
}
|
||||
return `alias0.${key}`; // 默认主表
|
||||
}
|
||||
83
backEnd/src/lib/pagination/pagination.ts
Normal file
83
backEnd/src/lib/pagination/pagination.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { getConnection, Between } from "typeorm";
|
||||
import { Request } from "express";
|
||||
|
||||
type paginationType<T> = {
|
||||
list: T[] | any[];
|
||||
total: number;
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
};
|
||||
|
||||
const filterKeys = ["pwd"];
|
||||
const DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
/**
|
||||
* 处理日期查询参数
|
||||
*/
|
||||
function processDateParams(params: { [key: string]: any }): {
|
||||
[key: string]: any;
|
||||
} {
|
||||
const processed = {} as Record<string, any>;
|
||||
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (typeof value === "string" && DATE_REGEX.test(value)) {
|
||||
// 处理日期范围
|
||||
const start = new Date(`${value}T00:00:00`);
|
||||
const end = new Date(`${value}T23:59:59`);
|
||||
processed[key] = Between(start, end);
|
||||
} else {
|
||||
processed[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分页参数
|
||||
*/
|
||||
function getPaginationParams(req: Request): {
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
} {
|
||||
const { pageSize = 10, pageNumber = 1 } =
|
||||
req.method === "GET" ? req.query : req.body;
|
||||
|
||||
return {
|
||||
pageSize: Math.max(1, parseInt(pageSize as string, 10)),
|
||||
pageNumber: Math.max(1, parseInt(pageNumber as string, 10)),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询封装
|
||||
*/
|
||||
export default async function getPagination<T>(
|
||||
entity: Function,
|
||||
req: Request,
|
||||
queryParams?: { [key: string]: any }
|
||||
): Promise<paginationType<T>> {
|
||||
try {
|
||||
const { pageSize, pageNumber } = getPaginationParams(req);
|
||||
const repository = getConnection().manager.getRepository(entity);
|
||||
|
||||
// 处理日期查询参数
|
||||
const processedWhere = queryParams ? processDateParams(queryParams) : {};
|
||||
|
||||
const [list, total] = await repository.findAndCount({
|
||||
where: processedWhere,
|
||||
order: { createDate: "DESC" },
|
||||
skip: (pageNumber - 1) * pageSize,
|
||||
take: pageSize,
|
||||
});
|
||||
|
||||
// 过滤敏感字段
|
||||
list.forEach((item) => {
|
||||
filterKeys.forEach((key) => delete item[key]);
|
||||
});
|
||||
|
||||
return { list, total, pageSize, pageNumber };
|
||||
} catch (err) {
|
||||
throw new Error(`分页查询出错: ${err.message}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user