初始版本,目前线上可用
This commit is contained in:
1
backEnd/.gitignore
vendored
Normal file
1
backEnd/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
0
backEnd/README.md
Normal file
0
backEnd/README.md
Normal file
24
backEnd/index.ts
Normal file
24
backEnd/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
require("module-alias/register"); // 别名加载
|
||||
|
||||
import express from "express";
|
||||
import bodyParser from "body-parser";
|
||||
import routerIndex from "./src/router/index";
|
||||
import { createConnection } from "typeorm";
|
||||
import cors from "cors";
|
||||
|
||||
const app = express();
|
||||
const port = 8101;
|
||||
createConnection().then(() => {
|
||||
console.log("数据库连接成功!");
|
||||
app.listen(port, () => {
|
||||
console.log(`开始监听${port}了`);
|
||||
});
|
||||
});
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: true })); // 进行url解码
|
||||
app.use(bodyParser.json());
|
||||
|
||||
app.use(cors());
|
||||
|
||||
// 匹配接口路由
|
||||
app.use("/", routerIndex);
|
||||
17
backEnd/ormconfig.js
Normal file
17
backEnd/ormconfig.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const env = process.env.NODE_ENV;
|
||||
module.exports = {
|
||||
"type": "mysql",
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"username": "root",
|
||||
"password": "123456",
|
||||
"database": "binyi",
|
||||
"entities": ["./src/entity/*.ts"],
|
||||
"migrations": ["src/migration/*.ts"],
|
||||
"synchronize": true,
|
||||
"logging": false,
|
||||
"cli": {
|
||||
"entitiesDir": "src/entity",
|
||||
"migrationsDir": "src/migration"
|
||||
}
|
||||
}
|
||||
7472
backEnd/package-lock.json
generated
Normal file
7472
backEnd/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
49
backEnd/package.json
Normal file
49
backEnd/package.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "interface",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "commonjs",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"db": "rd ./src/entity & typeorm-model-generator -h localhost -d baseSystem -p 3306 -u root -x 123456 -e mysql -o ./src/entity --noConfig true --ce pascal --cp camel",
|
||||
"dev": "nodemon --watch 'src/**/*.ts' --exec ts-node ./index.ts --development",
|
||||
"build": "webpack "
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/body-parser": "^1.19.2",
|
||||
"@types/jsonwebtoken": "^9.0.9",
|
||||
"axios": "^1.3.4",
|
||||
"bcrypt": "^5.1.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.20.2",
|
||||
"dayjs": "^1.11.10",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"module-alias": "^2.2.3",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"mysql": "^2.18.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"ts-loader": "^9.5.1",
|
||||
"typeorm": "^0.2.9",
|
||||
"webpack": "^5.95.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/module-alias": "^2.0.4",
|
||||
"@types/mysql": "^2.15.21",
|
||||
"cors": "^2.8.5",
|
||||
"ts-node": "^10.9.1",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"_moduleAliases": {
|
||||
"@": "./src",
|
||||
"@router": "./src/router",
|
||||
"@entity": "./src/entity"
|
||||
}
|
||||
}
|
||||
34
backEnd/src/abstrClass/BaseEntity.ts
Normal file
34
backEnd/src/abstrClass/BaseEntity.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
import dayjs from "dayjs";
|
||||
export abstract class BaseEntity {
|
||||
@PrimaryGeneratedColumn({ type: "int", name: "id" })
|
||||
id: number;
|
||||
@Column({
|
||||
type: "datetime",
|
||||
comment: "创建时间",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
createDate: Date;
|
||||
@Column({
|
||||
type: "datetime",
|
||||
comment: "更新时间",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
updateDate: Date;
|
||||
}
|
||||
79
backEnd/src/entity/CancelPayment.ts
Normal file
79
backEnd/src/entity/CancelPayment.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import { Entity, Column } from "typeorm";
|
||||
|
||||
@Entity("cacnle_payment")
|
||||
export class CancelPayment extends BaseEntity {
|
||||
@Column({
|
||||
type: "datetime",
|
||||
name: "checkout_date",
|
||||
comment: "结账日期",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
checkoutDate: Date;
|
||||
|
||||
@Column({ type: "varchar", length: 50, comment: "经办人" })
|
||||
handler: string;
|
||||
|
||||
@Column({
|
||||
type: "datetime",
|
||||
name: "settlement_date",
|
||||
comment: "结算日期",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
settlementDate: Date;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
name: "cash_amount",
|
||||
comment: "现金金额",
|
||||
})
|
||||
cashAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
comment: "银联支付金额",
|
||||
scale: 2,
|
||||
name: "union_pay_amount",
|
||||
})
|
||||
unionPayAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
comment: "刷卡金额",
|
||||
scale: 2,
|
||||
name: "card_amount",
|
||||
})
|
||||
cardAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
comment: "对公转账金额",
|
||||
name: "public_transfer_amount",
|
||||
})
|
||||
publicTransferAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
comment: "车间支付",
|
||||
name: "workshop_payment",
|
||||
})
|
||||
workshopPayment: number;
|
||||
|
||||
@Column({
|
||||
type: "int",
|
||||
comment: "单子ID",
|
||||
name: "retail_id",
|
||||
default: 0,
|
||||
})
|
||||
retailId: number;
|
||||
}
|
||||
|
||||
export default CancelPayment;
|
||||
89
backEnd/src/entity/CancelRetail.ts
Normal file
89
backEnd/src/entity/CancelRetail.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Entity, Column, OneToOne, JoinColumn } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import DeceasedRetail from "./DeceasedRetail";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@Entity("cancel_retail")
|
||||
export class CancelRetail extends BaseEntity {
|
||||
@Column("int", {
|
||||
name: "deceasedRetail_id",
|
||||
comment: "销售单ID",
|
||||
default: 0,
|
||||
})
|
||||
deceasedRetailId: number;
|
||||
|
||||
@Column("int", {
|
||||
name: "checkoutRetail_id",
|
||||
comment: "服务销售单ID",
|
||||
default: 0,
|
||||
})
|
||||
checkoutRetailId: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "cancel_person",
|
||||
length: 100,
|
||||
comment: "作废申请人",
|
||||
default: "",
|
||||
})
|
||||
cancelPerson: string;
|
||||
|
||||
@Column("datetime", {
|
||||
name: "cancel_date",
|
||||
comment: "作废日期",
|
||||
default: () => "CURRENT_TIMESTAMP", // 默认值为当前时间
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
cancelDate: Date;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "cancel_reason",
|
||||
comment: "作废原因",
|
||||
default: "",
|
||||
})
|
||||
cancelReason: string;
|
||||
|
||||
@Column("int", {
|
||||
name: "examine_state",
|
||||
comment: "审核状态 (0: 未审核, 1: 已审核, 2: 拒绝)",
|
||||
default: 0,
|
||||
})
|
||||
examineState: number;
|
||||
|
||||
@Column("int", {
|
||||
name: "cancel_type",
|
||||
comment: "作废类型,0结账处理、1零售结算",
|
||||
default: 0,
|
||||
})
|
||||
cancelType: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "examine_pserson",
|
||||
comment: "审核人",
|
||||
default: "",
|
||||
})
|
||||
examinePserson: string;
|
||||
|
||||
@Column("datetime", {
|
||||
name: "examine_date",
|
||||
comment: "审核时间",
|
||||
nullable: true, // 允许为空
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
examineDate: Date;
|
||||
}
|
||||
|
||||
export default CancelRetail;
|
||||
78
backEnd/src/entity/CheckoutPayment.ts
Normal file
78
backEnd/src/entity/CheckoutPayment.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import { Entity, Column } from "typeorm";
|
||||
|
||||
@Entity("checkout_payment_records")
|
||||
export class CheckoutPaymentRecords extends BaseEntity {
|
||||
@Column({
|
||||
type: "datetime",
|
||||
name: "checkout_date",
|
||||
comment: "结账日期",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
checkoutDate: Date;
|
||||
|
||||
@Column({ type: "varchar", length: 50, comment: "经办人" })
|
||||
handler: string;
|
||||
|
||||
@Column({
|
||||
type: "datetime",
|
||||
name: "settlement_date",
|
||||
comment: "结算日期",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
settlementDate: Date;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
name: "cash_amount",
|
||||
comment: "现金金额",
|
||||
})
|
||||
cashAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
comment: "银联支付金额",
|
||||
scale: 2,
|
||||
name: "union_pay_amount",
|
||||
})
|
||||
unionPayAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
comment: "刷卡金额",
|
||||
scale: 2,
|
||||
name: "card_amount",
|
||||
})
|
||||
cardAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
comment: "对公转账金额",
|
||||
name: "public_transfer_amount",
|
||||
})
|
||||
publicTransferAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
comment: "车间支付",
|
||||
name: "workshop_payment",
|
||||
})
|
||||
workshopPayment: number;
|
||||
|
||||
@Column({
|
||||
type: "int",
|
||||
comment: "单子ID",
|
||||
name: "checkout_retail_id",
|
||||
})
|
||||
checkoutRetailId: number;
|
||||
}
|
||||
|
||||
export default CheckoutPaymentRecords;
|
||||
85
backEnd/src/entity/CheckoutRetail.ts
Normal file
85
backEnd/src/entity/CheckoutRetail.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Entity, Column } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@Entity("checkout_retail")
|
||||
export class CheckoutRetail extends BaseEntity {
|
||||
@Column("int", {
|
||||
name: "deceased_id",
|
||||
comment: "逝者ID",
|
||||
default: 0,
|
||||
})
|
||||
deceasedId: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "buyer",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
buyer: string;
|
||||
|
||||
@Column("datetime", {
|
||||
name: "purchase_date",
|
||||
comment: "购买日期",
|
||||
default: () => "CURRENT_TIMESTAMP", // 默认值为当前时间
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
purchaseDate: Date;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "handler",
|
||||
comment: "经办人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
handler: string;
|
||||
|
||||
@Column("decimal", {
|
||||
name: "sales_amount",
|
||||
comment: "销售金额",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
default: 0.0,
|
||||
})
|
||||
salesAmount: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "guide",
|
||||
comment: "引导员",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
guide: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "service_items",
|
||||
comment: "服务项目列表",
|
||||
})
|
||||
serviceItems: string;
|
||||
|
||||
// 0未结账、1已结账
|
||||
@Column("int", {
|
||||
name: "retail_state",
|
||||
comment: "结账状态",
|
||||
default: 0,
|
||||
})
|
||||
retailState: number;
|
||||
|
||||
// 0正常、1已作废
|
||||
@Column("int", {
|
||||
name: "cancel_state",
|
||||
comment: "作废状态",
|
||||
default: 0,
|
||||
})
|
||||
cancelState: number;
|
||||
}
|
||||
|
||||
export default CheckoutRetail;
|
||||
117
backEnd/src/entity/Deceased.ts
Normal file
117
backEnd/src/entity/Deceased.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { Entity, Column } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@Entity("deceased")
|
||||
export class Deceased extends BaseEntity {
|
||||
@Column("varchar", {
|
||||
name: "name",
|
||||
comment: "逝者姓名",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "id_number",
|
||||
comment: "证件号码",
|
||||
length: 50,
|
||||
default: "",
|
||||
})
|
||||
idNumber: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "gender",
|
||||
comment: "性别",
|
||||
length: 10,
|
||||
default: "男",
|
||||
})
|
||||
gender: string;
|
||||
|
||||
@Column("int", {
|
||||
comment: "年龄",
|
||||
default: 0,
|
||||
})
|
||||
age: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "buyer",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
buyer: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "family_name",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
familyName: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "family_phone",
|
||||
comment: "购买人电话",
|
||||
length: 255,
|
||||
default: 0,
|
||||
})
|
||||
familyPhone: string;
|
||||
|
||||
@Column({ comment: "所在省", default: "" })
|
||||
province: string; // 所在省
|
||||
@Column({ comment: "所在市", default: "" })
|
||||
city: string; // 所在市
|
||||
@Column({ comment: "所在区域", default: "" })
|
||||
area: string; // 所在区域
|
||||
@Column({ comment: "详细地址", default: "" })
|
||||
address: string; // 详细地址
|
||||
|
||||
@Column("datetime", {
|
||||
name: "purchase_date",
|
||||
comment: "购买日期",
|
||||
default: () => "CURRENT_TIMESTAMP", // 默认值为当前时间
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
purchaseDate: Date;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "handler",
|
||||
comment: "经办人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
handler: string;
|
||||
|
||||
@Column("decimal", {
|
||||
name: "sales_amount",
|
||||
comment: "销售金额",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
default: 0.0,
|
||||
})
|
||||
salesAmount: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "guide",
|
||||
comment: "引导员",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
guide: string;
|
||||
|
||||
@Column("simple-array", {
|
||||
name: "service_items",
|
||||
comment: "服务项目列表",
|
||||
})
|
||||
serviceItems: number[];
|
||||
}
|
||||
|
||||
export default Deceased;
|
||||
143
backEnd/src/entity/DeceasedRetail.ts
Normal file
143
backEnd/src/entity/DeceasedRetail.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { Entity, Column, Index } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@Entity("deceased_retail")
|
||||
export class DeceasedRetail extends BaseEntity {
|
||||
@Index()
|
||||
@Column("int", {
|
||||
name: "deceased_id",
|
||||
comment: "逝者ID",
|
||||
default: 0,
|
||||
})
|
||||
deceasedId: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "deceased_name",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
deceasedName: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "buyer",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
buyer: string;
|
||||
|
||||
@Column("datetime", {
|
||||
name: "purchase_date",
|
||||
comment: "录单日期",
|
||||
default: () => "CURRENT_TIMESTAMP", // 默认值为当前时间
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
purchaseDate: Date;
|
||||
|
||||
@Column("datetime", {
|
||||
name: "checkout_date",
|
||||
comment: "录单日期",
|
||||
default: () => "CURRENT_TIMESTAMP", // 默认值为当前时间
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
checkoutDate: Date;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "handler",
|
||||
comment: "经办人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
handler: string;
|
||||
|
||||
@Column("decimal", {
|
||||
name: "sales_amount",
|
||||
comment: "销售金额",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
default: 0.0,
|
||||
})
|
||||
salesAmount: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "guide",
|
||||
comment: "引导员",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
guide: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "service_items",
|
||||
comment: "服务项目列表",
|
||||
})
|
||||
serviceItems: string;
|
||||
|
||||
// 0未结账、1已结账
|
||||
@Column("int", {
|
||||
name: "retail_state",
|
||||
comment: "结账状态",
|
||||
default: 0,
|
||||
})
|
||||
retailState: number;
|
||||
|
||||
// 0正常、1已作废
|
||||
@Column("int", {
|
||||
name: "cancel_state",
|
||||
comment: "作废状态",
|
||||
default: 0,
|
||||
})
|
||||
cancelState: number;
|
||||
|
||||
// 0服务单、1有逝者零售单, 2 无逝者零售单
|
||||
@Column("int", {
|
||||
name: "retail_type",
|
||||
comment: "单子类型",
|
||||
default: 0,
|
||||
})
|
||||
retailType: number;
|
||||
|
||||
//无逝者零售单
|
||||
@Column("varchar", {
|
||||
name: "family_name",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
familyName: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "family_phone",
|
||||
comment: "购买人电话",
|
||||
length: 255,
|
||||
default: 0,
|
||||
})
|
||||
familyPhone: string;
|
||||
|
||||
@Column({ comment: "所在省", default: "" })
|
||||
province: string; // 所在省
|
||||
@Column({ comment: "所在市", default: "" })
|
||||
city: string; // 所在市
|
||||
@Column({ comment: "所在区域", default: "" })
|
||||
area: string; // 所在区域
|
||||
@Column({ comment: "详细地址", default: "" })
|
||||
address: string; // 详细地址
|
||||
}
|
||||
|
||||
export default DeceasedRetail;
|
||||
102
backEnd/src/entity/Payment.ts
Normal file
102
backEnd/src/entity/Payment.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
OneToOne,
|
||||
JoinColumn,
|
||||
} from "typeorm";
|
||||
import DeceasedRetail from "./DeceasedRetail";
|
||||
|
||||
@Entity("payment_records")
|
||||
export class PaymentRecord extends BaseEntity {
|
||||
@Column({
|
||||
type: "datetime",
|
||||
name: "checkout_date",
|
||||
comment: "结账日期",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
checkoutDate: Date;
|
||||
|
||||
@Column({ type: "varchar", length: 50, comment: "经办人" })
|
||||
handler: string;
|
||||
|
||||
@Column({
|
||||
type: "datetime",
|
||||
name: "settlement_date",
|
||||
comment: "结算日期",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
settlementDate: Date;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
name: "cash_amount",
|
||||
comment: "现金金额",
|
||||
})
|
||||
cashAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
comment: "银联支付金额",
|
||||
scale: 2,
|
||||
name: "union_pay_amount",
|
||||
})
|
||||
unionPayAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
comment: "刷卡金额",
|
||||
scale: 2,
|
||||
name: "card_amount",
|
||||
})
|
||||
cardAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
comment: "对公转账金额",
|
||||
name: "public_transfer_amount",
|
||||
})
|
||||
publicTransferAmount: number;
|
||||
|
||||
@Column({
|
||||
type: "decimal",
|
||||
precision: 12,
|
||||
scale: 2,
|
||||
comment: "车间支付",
|
||||
name: "workshop_payment",
|
||||
})
|
||||
workshopPayment: number;
|
||||
|
||||
@Column({
|
||||
type: "int",
|
||||
comment: "零售单子ID",
|
||||
default: 0,
|
||||
name: "deceased_retail_id",
|
||||
})
|
||||
deceasedRetailId: number;
|
||||
|
||||
@Column({
|
||||
type: "int",
|
||||
comment: "无零售单子ID",
|
||||
name: "no_deceased_retail_id",
|
||||
default: 0,
|
||||
})
|
||||
noDeceasedRetailId: number;
|
||||
|
||||
@Column({
|
||||
type: "int",
|
||||
comment: "单子ID",
|
||||
name: "retail_id",
|
||||
default: 0,
|
||||
})
|
||||
retailId: number;
|
||||
}
|
||||
|
||||
export default PaymentRecord;
|
||||
12
backEnd/src/entity/Role.ts
Normal file
12
backEnd/src/entity/Role.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Column, Entity } from "typeorm";
|
||||
import { BaseEntity } from "../abstrClass/BaseEntity";
|
||||
|
||||
@Entity("role")
|
||||
export class Role extends BaseEntity {
|
||||
@Column({ type: "varchar", comment: "角色值", default: "" })
|
||||
values: string;
|
||||
@Column({ type: "int", comment: "角色状态", default: 1 })
|
||||
roleState: number;
|
||||
@Column({ type: "varchar", comment: "角色名", default: "" })
|
||||
name: string;
|
||||
}
|
||||
53
backEnd/src/entity/SeletedServiceList.ts
Normal file
53
backEnd/src/entity/SeletedServiceList.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Entity, Column } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
|
||||
@Entity("seleted_service_list")
|
||||
export class SeletedServiceList extends BaseEntity {
|
||||
@Column("varchar", {
|
||||
name: "name",
|
||||
comment: "服务项目名称",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column("int", {
|
||||
comment: "数量",
|
||||
default: 0,
|
||||
})
|
||||
quantity: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "unit",
|
||||
comment: "单位",
|
||||
length: 50,
|
||||
default: "",
|
||||
})
|
||||
unit: string;
|
||||
|
||||
@Column("decimal", {
|
||||
name: "price",
|
||||
comment: "售价",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
default: 0.0,
|
||||
})
|
||||
price: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "remark",
|
||||
comment: "备注",
|
||||
length: 500,
|
||||
default: "",
|
||||
})
|
||||
remark: string;
|
||||
|
||||
@Column("int", {
|
||||
name: "retail_id",
|
||||
comment: "所属零售ID",
|
||||
default: 0,
|
||||
})
|
||||
retailId: number;
|
||||
}
|
||||
|
||||
export default SeletedServiceList;
|
||||
30
backEnd/src/entity/ServiceCategory.ts
Normal file
30
backEnd/src/entity/ServiceCategory.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Entity, Column } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
|
||||
@Entity("service_category")
|
||||
export class ServiceCategory extends BaseEntity {
|
||||
@Column("varchar", {
|
||||
name: "name",
|
||||
comment: "商品分类名称",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
name: string; // 商品分类名称
|
||||
|
||||
@Column("varchar", {
|
||||
name: "remark",
|
||||
comment: "备注",
|
||||
length: 500,
|
||||
default: "",
|
||||
})
|
||||
remark: string;
|
||||
|
||||
@Column("int", {
|
||||
name: "parentId",
|
||||
comment: "分类ID",
|
||||
default: 0,
|
||||
})
|
||||
parentId: number; // 关联分类
|
||||
}
|
||||
|
||||
export default ServiceCategory;
|
||||
60
backEnd/src/entity/ServiceItem.ts
Normal file
60
backEnd/src/entity/ServiceItem.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Entity, Column } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
|
||||
@Entity("service_item")
|
||||
export class ServiceItem extends BaseEntity {
|
||||
@Column("varchar", {
|
||||
name: "name",
|
||||
comment: "服务项目名称",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column("int", {
|
||||
comment: "数量",
|
||||
default: 0,
|
||||
})
|
||||
quantity: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "unit",
|
||||
comment: "单位",
|
||||
length: 50,
|
||||
default: "",
|
||||
})
|
||||
unit: string;
|
||||
|
||||
@Column("decimal", {
|
||||
name: "price",
|
||||
comment: "售价",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
default: 0.0,
|
||||
})
|
||||
price: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "remark",
|
||||
comment: "备注",
|
||||
length: 500,
|
||||
default: "",
|
||||
})
|
||||
remark: string;
|
||||
|
||||
@Column("int", {
|
||||
name: "parentId",
|
||||
comment: "分类ID",
|
||||
default: 0,
|
||||
})
|
||||
parentId: number; // 关联分类
|
||||
|
||||
@Column("int", {
|
||||
name: "hasDeceased",
|
||||
comment: "是否有逝者",
|
||||
default: 1,
|
||||
})
|
||||
hasDeceased: number; // 关联分类
|
||||
}
|
||||
|
||||
export default ServiceItem;
|
||||
28
backEnd/src/entity/SystemMenue.ts
Normal file
28
backEnd/src/entity/SystemMenue.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
|
||||
@Entity("system_menue")
|
||||
export class SystemMenue {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ comment: "菜单名", default: "" })
|
||||
name: string;
|
||||
|
||||
@Column({ comment: "创建时间", default: "" })
|
||||
createDate: string;
|
||||
|
||||
@Column({ comment: "更新时间", default: "" })
|
||||
updateDate: string;
|
||||
|
||||
@Column({ comment: "路径名", default: "" })
|
||||
path: string;
|
||||
|
||||
@Column({ comment: "父级ID", default: 0 })
|
||||
parentId: number;
|
||||
|
||||
@Column({ comment: "图标", default: "" })
|
||||
icon: string;
|
||||
|
||||
@Column({ comment: "是否显示", default: true })
|
||||
show: boolean;
|
||||
}
|
||||
45
backEnd/src/entity/User.ts
Normal file
45
backEnd/src/entity/User.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
import dayjs from "dayjs";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
|
||||
@Entity("user")
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn({ type: "int", name: "id" })
|
||||
id: number;
|
||||
@Column("varchar", { name: "name", comment: "姓名\r\n", length: 255 })
|
||||
name: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "phone",
|
||||
nullable: true,
|
||||
comment: "电话",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
phone: string;
|
||||
@Column({ comment: "性别", default: "男" })
|
||||
sex: string;
|
||||
@Column("varchar", { name: "pwd", nullable: true, length: 255 })
|
||||
pwd: string;
|
||||
@Column({
|
||||
comment: "创建时间",
|
||||
default: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
})
|
||||
@Column({ comment: "用户状态", default: 1 })
|
||||
userState: number; // 账户状态
|
||||
@Column({ comment: "角色", default: "" })
|
||||
role: string; // 角色
|
||||
@Column({ comment: "生日", default: "" })
|
||||
birthday: string; // 生日
|
||||
@Column({ comment: "年龄", default: "" })
|
||||
age: string; // 年龄
|
||||
@Column({ comment: "所在省", default: "" })
|
||||
province: string; // 所在省
|
||||
@Column({ comment: "所在市", default: "" })
|
||||
city: string; // 所在市
|
||||
@Column({ comment: "所在区域", default: "" })
|
||||
area: string; // 所在区域
|
||||
@Column({ comment: "详细地址", default: "" })
|
||||
address: string; // 详细地址
|
||||
}
|
||||
export default User;
|
||||
94
backEnd/src/entity/noDeceasedRetail.ts
Normal file
94
backEnd/src/entity/noDeceasedRetail.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Entity, Column } from "typeorm";
|
||||
import { BaseEntity } from "@/abstrClass/BaseEntity";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@Entity("nodeceased_retail")
|
||||
export class noDeceasedRetail extends BaseEntity {
|
||||
@Column("varchar", {
|
||||
name: "buyer",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
buyer: string;
|
||||
|
||||
@Column("datetime", {
|
||||
name: "purchase_date",
|
||||
comment: "购买日期",
|
||||
default: () => "CURRENT_TIMESTAMP", // 默认值为当前时间
|
||||
transformer: {
|
||||
to(value: Date) {
|
||||
return value;
|
||||
},
|
||||
from(value) {
|
||||
return dayjs(new Date(value)).format("YYYY-MM-DD HH:mm:ss");
|
||||
},
|
||||
},
|
||||
})
|
||||
purchaseDate: Date;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "handler",
|
||||
comment: "经办人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
handler: string;
|
||||
|
||||
@Column("decimal", {
|
||||
name: "sales_amount",
|
||||
comment: "销售金额",
|
||||
precision: 10,
|
||||
scale: 2,
|
||||
default: 0.0,
|
||||
})
|
||||
salesAmount: number;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "guide",
|
||||
comment: "引导员",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
guide: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "family_name",
|
||||
comment: "购买人",
|
||||
length: 255,
|
||||
default: "",
|
||||
})
|
||||
familyName: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "family_phone",
|
||||
comment: "购买人电话",
|
||||
length: 255,
|
||||
default: 0,
|
||||
})
|
||||
familyPhone: string;
|
||||
|
||||
@Column("varchar", {
|
||||
name: "service_items",
|
||||
comment: "服务项目列表",
|
||||
})
|
||||
serviceItems: string;
|
||||
|
||||
// 0未结账、1已结账
|
||||
@Column("int", {
|
||||
name: "retail_state",
|
||||
comment: "结账状态",
|
||||
default: 0,
|
||||
})
|
||||
retailState: number;
|
||||
|
||||
// 0正常、1已作废
|
||||
@Column("int", {
|
||||
name: "cancel_state",
|
||||
comment: "作废状态",
|
||||
default: 0,
|
||||
})
|
||||
cancelState: number;
|
||||
}
|
||||
|
||||
export default noDeceasedRetail;
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
220
backEnd/src/router/CheckoutRetail/CheckoutRetail.ts
Normal file
220
backEnd/src/router/CheckoutRetail/CheckoutRetail.ts
Normal file
@@ -0,0 +1,220 @@
|
||||
import * as express from "express";
|
||||
import { Brackets, getConnection } from "typeorm";
|
||||
|
||||
import Deceased from "@/entity/Deceased";
|
||||
import CheckoutPayment from "@/entity/CheckoutPayment";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
import parseRangDate, {
|
||||
filterObjEmptyVal,
|
||||
getPaginationParams,
|
||||
} from "@/util/globalMethods";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 统一查询方法
|
||||
async function queryRetailRecords(params: {
|
||||
req: Request;
|
||||
retailState?: number;
|
||||
isQuery?: boolean;
|
||||
}): Promise<{
|
||||
list: any[];
|
||||
total: number;
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
}> {
|
||||
const { req, retailState } = params;
|
||||
const { pageSize, pageNumber } = getPaginationParams(req);
|
||||
const alias = "r";
|
||||
const paymentAlias = "p";
|
||||
const deceasedAlias = "d";
|
||||
|
||||
let { startDate, endDate } = parseRangDate(req);
|
||||
// 初始化查询构造器
|
||||
const queryBuilder = getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.createQueryBuilder(alias)
|
||||
.leftJoinAndMapOne(
|
||||
`${alias}.paymentRecord`,
|
||||
CheckoutPayment,
|
||||
paymentAlias,
|
||||
`${paymentAlias}.checkout_retail_id = ${alias}.id`
|
||||
)
|
||||
.leftJoinAndMapOne(
|
||||
`${alias}.deceased`,
|
||||
Deceased,
|
||||
deceasedAlias,
|
||||
`${deceasedAlias}.id = ${alias}.deceasedId`
|
||||
)
|
||||
.where(`${alias}.retailType = 0`)
|
||||
.andWhere(`${alias}.cancelState = 0`);
|
||||
|
||||
// 零售状态筛选
|
||||
if (typeof retailState === "number") {
|
||||
queryBuilder.andWhere(`${alias}.retailState = :retailState`, {
|
||||
retailState,
|
||||
});
|
||||
}
|
||||
|
||||
queryBuilder.andWhere(
|
||||
new Brackets((qb) =>
|
||||
qb
|
||||
.where(`${alias}.serviceItems IS NOT NULL`)
|
||||
.andWhere(`${alias}.serviceItems != ''`)
|
||||
)
|
||||
);
|
||||
|
||||
if (startDate && endDate) {
|
||||
queryBuilder
|
||||
.andWhere(`p.checkoutDate BETWEEN :start AND :end`)
|
||||
.setParameters({ start: startDate, end: endDate });
|
||||
}
|
||||
|
||||
// 动态处理查询参数
|
||||
const queryParams: any = filterObjEmptyVal(
|
||||
req.method === "GET" ? req.query : req.body
|
||||
);
|
||||
Object.entries(queryParams).forEach(([key, value]) => {
|
||||
if (["pageSize", "pageNumber"].includes(key)) return;
|
||||
if (value === undefined || value === "") return;
|
||||
|
||||
switch (key) {
|
||||
// case "checkoutDate":
|
||||
// queryBuilder.andWhere(`${paymentAlias}.checkoutDate = :checkoutDate`, {
|
||||
// checkoutDate: value,
|
||||
// });
|
||||
// break;
|
||||
case "gender":
|
||||
queryBuilder.andWhere(`${deceasedAlias}.gender = :gender`, {
|
||||
gender: value,
|
||||
});
|
||||
break;
|
||||
case "name":
|
||||
queryBuilder.andWhere(`${deceasedAlias}.name LIKE :name`, {
|
||||
name: `%${value}%`,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
if (key.startsWith("deceased.")) {
|
||||
const field = key.split(".")[1];
|
||||
queryBuilder.andWhere(`${deceasedAlias}.${field} = :${field}`, {
|
||||
[field]: value,
|
||||
});
|
||||
} else if (
|
||||
Object.keys(queryBuilder.expressionMap.parameters).includes(key)
|
||||
) {
|
||||
// 处理重复参数名
|
||||
const uniqueKey = `${key}_${Date.now()}`;
|
||||
queryBuilder.andWhere(`${alias}.${key} = :${uniqueKey}`, {
|
||||
[uniqueKey]: value,
|
||||
});
|
||||
} else {
|
||||
if (!["purchaseDate", "startDate", "endDate"].includes(key)) {
|
||||
queryBuilder.andWhere(`${alias}.${key} = :${key}`, {
|
||||
[key]: value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 执行分页查询
|
||||
const [list, total] = await queryBuilder
|
||||
.orderBy(`${alias}.createDate`, "DESC")
|
||||
.skip((pageNumber - 1) * pageSize)
|
||||
.take(pageSize)
|
||||
.getManyAndCount();
|
||||
|
||||
return { list, total, pageSize, pageNumber };
|
||||
}
|
||||
|
||||
// 列表接口
|
||||
router.get("/list", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const result = await queryRetailRecords({
|
||||
req,
|
||||
retailState: Number(req.query.retailState),
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
data: {
|
||||
list: result.list,
|
||||
pageNumber: result.pageNumber,
|
||||
pageSize: result.pageSize,
|
||||
total: result.total,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
msg: err.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 查询接口
|
||||
router.post("/query", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const result = await queryRetailRecords({
|
||||
req,
|
||||
isQuery: true,
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
data: {
|
||||
list: result.list,
|
||||
pageNumber: result.pageNumber,
|
||||
pageSize: result.pageSize,
|
||||
total: result.total,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
msg: err.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/confirmCheckout", async (req, res) => {
|
||||
let id = Number(req.body.id);
|
||||
if (!id) {
|
||||
return res.status(500).send({ code: 500, msg: "未传入结账id" });
|
||||
}
|
||||
|
||||
try {
|
||||
let connection = getConnection();
|
||||
|
||||
let deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
let paymentRecordRep = connection.getRepository(CheckoutPayment);
|
||||
|
||||
let deceasedRetail = await deceasedRetailRep.findOne(id);
|
||||
if (!deceasedRetail) {
|
||||
return res.status(500).send({ code: 500, msg: "该记录不存在" });
|
||||
}
|
||||
|
||||
let newPaymentRecord = new CheckoutPayment();
|
||||
|
||||
deceasedRetail.retailState = 1;
|
||||
deceasedRetail.checkoutDate = new Date();
|
||||
|
||||
newPaymentRecord = Object.assign({}, req.body.currentPayment);
|
||||
newPaymentRecord.checkoutRetailId = deceasedRetail.id;
|
||||
|
||||
await deceasedRetailRep.save(deceasedRetail);
|
||||
// await cancelRecordRep.save(newCancleRetail);
|
||||
await paymentRecordRep.save(newPaymentRecord);
|
||||
|
||||
res
|
||||
.status(200)
|
||||
.send({ code: 200, data: deceasedRetail, msg: "结账成功!" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
328
backEnd/src/router/cancle/cancleExamine.ts
Normal file
328
backEnd/src/router/cancle/cancleExamine.ts
Normal file
@@ -0,0 +1,328 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
|
||||
import curd from "@/lib/curd/curd";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import CancelRetail from "@/entity/CancelRetail";
|
||||
import Deceased from "@/entity/Deceased";
|
||||
import PaymentRecord from "@/entity/Payment";
|
||||
import CheckoutRetail from "@/entity/CheckoutRetail";
|
||||
import CheckoutPaymentRecords from "@/entity/CheckoutPayment";
|
||||
import CancelPayment from "@/entity/CancelPayment";
|
||||
|
||||
const router = express.Router();
|
||||
async function getMoreInfor(result, type = 0) {
|
||||
const deceasedRetailIds = result.list
|
||||
.filter((item) => item.deceasedRetailId)
|
||||
.map((item) => Number(item.deceasedRetailId));
|
||||
|
||||
const checkoutRetailIds = result.list
|
||||
.filter((item) => item.checkoutRetailId)
|
||||
.map((item) => Number(item.checkoutRetailId));
|
||||
|
||||
if (deceasedRetailIds.length) {
|
||||
const deceasedRetails = await getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.createQueryBuilder("deceased_retail")
|
||||
.where("deceased_retail.id IN (:...ids)", {
|
||||
ids: deceasedRetailIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
const deceasedIds = Array.from(
|
||||
new Set(deceasedRetails.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
let deceaseds = [];
|
||||
|
||||
if (deceasedIds.length) {
|
||||
deceaseds = await getConnection()
|
||||
.getRepository(Deceased)
|
||||
.createQueryBuilder("deceased")
|
||||
.where("deceased.id IN (:...ids)", {
|
||||
ids: deceasedIds,
|
||||
})
|
||||
.getMany();
|
||||
}
|
||||
|
||||
let paymentRecords = [];
|
||||
|
||||
if (type === 0) {
|
||||
paymentRecords = await getConnection()
|
||||
.getRepository(CheckoutPaymentRecords)
|
||||
.createQueryBuilder("paymentRecord")
|
||||
.where("paymentRecord.checkout_retail_id IN (:...ids)", {
|
||||
ids: deceasedRetailIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
let tempRec = await getConnection()
|
||||
.getRepository(PaymentRecord)
|
||||
.createQueryBuilder("paymentRecord")
|
||||
.where("paymentRecord.deceased_retail_id IN (:...ids)", {
|
||||
ids: deceasedRetailIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
paymentRecords = [...paymentRecords, ...tempRec];
|
||||
} else {
|
||||
let retailIds = result.list.map((item) => Number(item.id));
|
||||
|
||||
paymentRecords = await getConnection()
|
||||
.getRepository(CancelPayment)
|
||||
.createQueryBuilder("paymentRecord")
|
||||
.where("paymentRecord.retail_id IN (:...ids)", {
|
||||
ids: retailIds,
|
||||
})
|
||||
.getMany();
|
||||
}
|
||||
result.list = result.list.map((item: any) => {
|
||||
let retail = deceasedRetails.find(
|
||||
(fitem: any) => fitem.id === item.deceasedRetailId
|
||||
);
|
||||
|
||||
let deceased = {};
|
||||
if (retail) {
|
||||
deceased = deceaseds.find((fitem) => fitem.id === retail.deceasedId);
|
||||
}
|
||||
let payment =
|
||||
paymentRecords.find(
|
||||
(fitem) => fitem.checkoutRetailId === item.deceasedRetailId
|
||||
) ||
|
||||
paymentRecords.find((fitem) => fitem.retailId === item.id) ||
|
||||
paymentRecords.find(
|
||||
(fitem) => fitem.deceasedRetailId === item.deceasedRetailId
|
||||
);
|
||||
|
||||
return {
|
||||
retail,
|
||||
deceased,
|
||||
payment,
|
||||
...item,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (checkoutRetailIds.length) {
|
||||
const checkouitRetails = await getConnection()
|
||||
.getRepository(CheckoutRetail)
|
||||
.createQueryBuilder("checkout_retail")
|
||||
.where("checkout_retail.id IN (:...ids)", {
|
||||
ids: checkoutRetailIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
let deceaseds = [];
|
||||
|
||||
if (checkouitRetails.length) {
|
||||
const checkoutRetailsIds = Array.from(
|
||||
new Set(checkouitRetails.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
|
||||
if (checkoutRetailsIds.length) {
|
||||
deceaseds = await getConnection()
|
||||
.getRepository(Deceased)
|
||||
.createQueryBuilder("deceased")
|
||||
.where("deceased.id IN (:...ids)", {
|
||||
ids: checkoutRetailsIds,
|
||||
})
|
||||
.getMany();
|
||||
}
|
||||
|
||||
const paymentRecords = await getConnection()
|
||||
.getRepository(CheckoutPaymentRecords)
|
||||
.createQueryBuilder("paymentRecord")
|
||||
.where("paymentRecord.checkoutRetailId IN (:...ids)", {
|
||||
ids: checkoutRetailIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
let retail = checkouitRetails.find(
|
||||
(fitem: any) => fitem.id === item.checkoutRetailId
|
||||
);
|
||||
|
||||
let deceased = deceaseds.find(
|
||||
(fitem) => fitem.id === retail.deceasedId
|
||||
);
|
||||
|
||||
let payment = paymentRecords.find(
|
||||
(fitem) => fitem.checkoutRetailId === item.checkoutRetailId
|
||||
);
|
||||
|
||||
return {
|
||||
...item,
|
||||
retail,
|
||||
deceased,
|
||||
payment,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
try {
|
||||
const result: any = await curd({
|
||||
entity: CancelRetail,
|
||||
req,
|
||||
params: {
|
||||
examineState: 0,
|
||||
},
|
||||
}).queryList();
|
||||
|
||||
// console.log(result);
|
||||
|
||||
await getMoreInfor(result);
|
||||
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 查询逝者列表(支持分页)
|
||||
router.post("/query", async (req, res) => {
|
||||
try {
|
||||
const result = await curd({
|
||||
entity: CancelRetail,
|
||||
req,
|
||||
params: {
|
||||
...req.body,
|
||||
},
|
||||
}).queryList();
|
||||
|
||||
await getMoreInfor(result, 1);
|
||||
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/cancel", async (req, res) => {
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceaseRetailRep = connection.getRepository(DeceasedRetail);
|
||||
const cancelRetailRep = connection.getRepository(CancelRetail);
|
||||
|
||||
let findDeceaseRetail = await deceaseRetailRep.findOne(
|
||||
Number(req.body.deceasedRetailId)
|
||||
);
|
||||
let cancelRetail = new CancelRetail();
|
||||
|
||||
findDeceaseRetail.cancelState = 1;
|
||||
|
||||
cancelRetail = {
|
||||
...cancelRetail,
|
||||
...req.body.cancelForm,
|
||||
};
|
||||
|
||||
// 结账处理
|
||||
cancelRetail.deceasedRetailId = findDeceaseRetail.id;
|
||||
cancelRetail.cancelDate = new Date();
|
||||
|
||||
await deceaseRetailRep.save(findDeceaseRetail);
|
||||
await cancelRetailRep.save(cancelRetail);
|
||||
|
||||
res.send({ code: 200, data: cancelRetail });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/examine", async (req, res) => {
|
||||
let examineState = req.body.examineState;
|
||||
let id = req.body.id;
|
||||
let connection = getConnection();
|
||||
|
||||
if (examineState === 1) {
|
||||
try {
|
||||
let cancleRetailRep = connection.getRepository(CancelRetail);
|
||||
let cancleRetail = await cancleRetailRep.findOne(id);
|
||||
|
||||
let cancelPaymentRep = connection.getRepository(CancelPayment);
|
||||
let cancelPayment = new CancelPayment();
|
||||
|
||||
cancelPayment = { ...req.body.payment };
|
||||
delete cancelPayment.id;
|
||||
cancelPayment.retailId = cancleRetail.id;
|
||||
|
||||
await cancelPaymentRep.save(cancelPayment);
|
||||
|
||||
cancleRetail.examineState = 1;
|
||||
cancleRetail.examineDate = new Date();
|
||||
|
||||
if (req.body.checkoutRetailId) {
|
||||
let checkoutRetailRep = connection.getRepository(CheckoutRetail);
|
||||
let checkoutRetail = await checkoutRetailRep.findOne(
|
||||
req.body.checkoutRetailId
|
||||
);
|
||||
checkoutRetail.cancelState = 1;
|
||||
|
||||
await checkoutRetailRep.save(checkoutRetail);
|
||||
}
|
||||
|
||||
if (req.body.deceasedRetailId) {
|
||||
let deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
let deceasedRetail = await deceasedRetailRep.findOne(
|
||||
req.body.deceasedRetailId
|
||||
);
|
||||
deceasedRetail.cancelState = 0;
|
||||
deceasedRetail.retailState = 0;
|
||||
|
||||
await deceasedRetailRep.save(deceasedRetail);
|
||||
}
|
||||
await cancleRetailRep.save(cancleRetail);
|
||||
|
||||
let paymentRep = connection.getRepository(PaymentRecord);
|
||||
let findPaymeny = await paymentRep.findOne(req.body.payment.id);
|
||||
|
||||
if (findPaymeny) {
|
||||
findPaymeny.cashAmount = 0;
|
||||
findPaymeny.unionPayAmount = 0;
|
||||
findPaymeny.cardAmount = 0;
|
||||
findPaymeny.publicTransferAmount = 0;
|
||||
findPaymeny.workshopPayment = 0;
|
||||
await paymentRep.save(findPaymeny);
|
||||
}
|
||||
|
||||
res.send({ code: 200, data: cancleRetail });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
}
|
||||
if (examineState === 2) {
|
||||
try {
|
||||
let cancleRetailRep = getConnection().getRepository(CancelRetail);
|
||||
let cancleRetail = await cancleRetailRep.findOne(id);
|
||||
|
||||
if (req.body.checkoutRetailId) {
|
||||
let checkoutRetailRep = getConnection().getRepository(CheckoutRetail);
|
||||
let checkoutRetail = await checkoutRetailRep.findOne(
|
||||
req.body.checkoutRetailId
|
||||
);
|
||||
checkoutRetail.cancelState = 1;
|
||||
|
||||
await checkoutRetailRep.save(checkoutRetail);
|
||||
}
|
||||
|
||||
if (req.body.deceasedRetailId) {
|
||||
let deceasedRetailRep = getConnection().getRepository(DeceasedRetail);
|
||||
let deceasedRetail = await deceasedRetailRep.findOne(
|
||||
req.body.deceasedRetailId
|
||||
);
|
||||
deceasedRetail.cancelState = 0;
|
||||
deceasedRetail.retailState = 1;
|
||||
|
||||
await deceasedRetailRep.save(deceasedRetail);
|
||||
}
|
||||
|
||||
await cancleRetailRep.remove(cancleRetail);
|
||||
|
||||
res.send({ code: 200, data: cancleRetail });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
50
backEnd/src/router/checkout/checkout.ts
Normal file
50
backEnd/src/router/checkout/checkout.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import PaymentRecord from "@/entity/Payment";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post("/deceasedCheckout", async (req, res) => {
|
||||
let id = Number(req.body.id);
|
||||
if (!id) {
|
||||
return res.status(500).send({ code: 500, msg: "未传入结账id" });
|
||||
}
|
||||
|
||||
try {
|
||||
let connection = getConnection();
|
||||
|
||||
let deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
let paymentRecordRep = connection.getRepository(PaymentRecord);
|
||||
|
||||
let deceasedRetail = await deceasedRetailRep.findOne(id);
|
||||
|
||||
if (!deceasedRetail)
|
||||
return res.status(500).send({ code: 500, msg: "该记录不存在" });
|
||||
|
||||
let newPaymentRecord = await paymentRecordRep.findOne({
|
||||
deceasedRetailId: deceasedRetail.id,
|
||||
});
|
||||
|
||||
if (!newPaymentRecord) {
|
||||
newPaymentRecord = new PaymentRecord();
|
||||
}
|
||||
|
||||
deceasedRetail.retailState = 1;
|
||||
deceasedRetail.checkoutDate = new Date();
|
||||
|
||||
newPaymentRecord = Object.assign(newPaymentRecord, req.body.currentPayment);
|
||||
newPaymentRecord.deceasedRetailId = deceasedRetail.id;
|
||||
|
||||
await deceasedRetailRep.save(deceasedRetail);
|
||||
await paymentRecordRep.save(newPaymentRecord);
|
||||
|
||||
res
|
||||
.status(200)
|
||||
.send({ code: 200, data: deceasedRetail, msg: "结账成功!" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
201
backEnd/src/router/deceased/deceased.ts
Normal file
201
backEnd/src/router/deceased/deceased.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import Deceased from "@/entity/Deceased";
|
||||
import curd from "@/lib/curd/curd";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import { SeletedServiceList } from "@/entity/SeletedServiceList";
|
||||
import { Request } from "express-serve-static-core";
|
||||
import PaymentRecord from "@/entity/Payment";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 查询逝者列表(支持分页)
|
||||
router.post("/query", async (req, res) => {
|
||||
try {
|
||||
const result = await curd({ entity: Deceased, req }).queryList();
|
||||
await getData(result, req);
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
try {
|
||||
const result = await curd({ entity: Deceased, req }).queryList();
|
||||
await getData(result, req);
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 添加逝者
|
||||
router.post("/add", async (req, res) => {
|
||||
const { name, idNumber } = req.body;
|
||||
|
||||
if (!name || !idNumber) {
|
||||
return res.send({ code: 400, msg: "逝者姓名和证件号码不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceasedRepository = connection.getRepository(Deceased);
|
||||
const deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
|
||||
const tempServiceItems = req.body.services.map((item) => {
|
||||
delete item.id;
|
||||
return {
|
||||
...item,
|
||||
};
|
||||
});
|
||||
req.body.serviceItems = "";
|
||||
|
||||
// 校验是否已存在相同证件号码的逝者
|
||||
const existingDeceased = await deceasedRepository.findOne({
|
||||
where: { idNumber },
|
||||
});
|
||||
|
||||
if (existingDeceased) {
|
||||
return res.send({ code: 400, msg: "证件号码已存在,请勿重复添加!" });
|
||||
}
|
||||
|
||||
const newDeceased = await curd({ entity: Deceased, req }).add();
|
||||
let newDeceasedRetail = await curd({ entity: DeceasedRetail, req }).add();
|
||||
|
||||
if (tempServiceItems.length) {
|
||||
tempServiceItems.forEach((item) => {
|
||||
item.retailId = newDeceasedRetail.id;
|
||||
|
||||
delete item.id;
|
||||
});
|
||||
|
||||
const data = await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.save(tempServiceItems);
|
||||
|
||||
newDeceasedRetail.serviceItems = data.map((item) => item.id).join(",");
|
||||
}
|
||||
newDeceasedRetail.deceasedId = newDeceased.id;
|
||||
|
||||
await deceasedRetailRep.save(newDeceasedRetail);
|
||||
|
||||
res.send({ code: 200, msg: "逝者信息添加成功", data: newDeceased });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新逝者信息
|
||||
router.post("/update", async (req, res) => {
|
||||
const { id, idNumber } = req.body;
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "逝者ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceasedRepository = connection.getRepository(Deceased);
|
||||
|
||||
// 校验是否已存在相同证件号码的逝者(排除当前记录)
|
||||
if (idNumber) {
|
||||
const existingDeceased = await deceasedRepository.findOne({
|
||||
where: { idNumber },
|
||||
});
|
||||
|
||||
if (existingDeceased && existingDeceased.id !== id) {
|
||||
return res.send({ code: 400, msg: "证件号码已存在,请勿重复使用!" });
|
||||
}
|
||||
}
|
||||
|
||||
const updatedDeceased = await curd({ entity: Deceased, req }).update();
|
||||
res.send({ code: 200, msg: "逝者信息更新成功", data: updatedDeceased });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除逝者信息
|
||||
router.get("/delete", async (req, res) => {
|
||||
const { id } = req.query;
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "逝者ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
await curd({ entity: Deceased, req }).delete();
|
||||
res.send({ code: 200, msg: "逝者信息删除成功" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
async function getData(result, req: Request) {
|
||||
let type = req.query.type ?? req.body.type;
|
||||
if (!type && type !== 0) type = 0;
|
||||
|
||||
const deceasedId = Array.from(
|
||||
new Set(result.list.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
|
||||
const deceasedIds = Array.from(
|
||||
new Set(result.list.map((item) => Number(item.id)))
|
||||
);
|
||||
|
||||
if (deceasedId.length) {
|
||||
const reatialList = await getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.createQueryBuilder("DeceasedRetail")
|
||||
.where("DeceasedRetail.deceased_id IN (:...ids)", {
|
||||
ids: deceasedIds,
|
||||
})
|
||||
.andWhere("DeceasedRetail.retail_type = :retailType", {
|
||||
retailType: type,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
if (reatialList.length) {
|
||||
result.list = result.list.map((item: any) => {
|
||||
return {
|
||||
...item,
|
||||
deceased: { ...item },
|
||||
retail: reatialList.find(
|
||||
(fitem: any) => fitem.deceasedId === item.id
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
let retailIds = reatialList.map((item) => item.id);
|
||||
|
||||
if (retailIds.length) {
|
||||
const serviceList = await getConnection()
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("SeletedServiceList")
|
||||
.where("SeletedServiceList.retail_id IN (:...retailIds)", {
|
||||
retailIds: retailIds,
|
||||
})
|
||||
.getMany();
|
||||
if (serviceList.length) {
|
||||
result.list = result.list.map((item: any) => {
|
||||
let retailId = reatialList.find(
|
||||
(fitem) => fitem.deceasedId === item.id
|
||||
)?.id;
|
||||
|
||||
let services = serviceList.filter(
|
||||
(fitem) => fitem.retailId === retailId
|
||||
);
|
||||
return {
|
||||
...item,
|
||||
serviceItems: services.map((mitem) => mitem.id.toString()),
|
||||
services: services,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default router;
|
||||
484
backEnd/src/router/deceasedRetail/deceasedRetail.ts
Normal file
484
backEnd/src/router/deceasedRetail/deceasedRetail.ts
Normal file
@@ -0,0 +1,484 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import DeceasedRetail from "../../entity/DeceasedRetail";
|
||||
import curd from "@/lib/curd/curd";
|
||||
import SeletedServiceList from "@/entity/SeletedServiceList";
|
||||
import Deceased from "@/entity/Deceased";
|
||||
import PaymentRecord from "@/entity/Payment";
|
||||
import parseRangDate, { getPaginationParams } from "@/util/globalMethods";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
async function GetData(result) {
|
||||
const ids = Array.from(
|
||||
new Set(result.list.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
|
||||
if (ids.length) {
|
||||
const manyResult = await getConnection()
|
||||
.getRepository(Deceased)
|
||||
.createQueryBuilder("deceased")
|
||||
.where("deceased.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
let findData = manyResult.find(
|
||||
(fitem: any) => fitem.id === item.deceasedId
|
||||
);
|
||||
|
||||
return {
|
||||
...item,
|
||||
deceased: findData,
|
||||
};
|
||||
});
|
||||
}
|
||||
let paymentIds = result.list
|
||||
.filter((item) => item.retailState === 1)
|
||||
.map((item) => item.id);
|
||||
if (paymentIds.length) {
|
||||
let manyResult = await getConnection()
|
||||
.getRepository(PaymentRecord)
|
||||
.createQueryBuilder("PaymentRecord")
|
||||
.where("PaymentRecord.deceased_retail_id IN (:...ids)", {
|
||||
ids: paymentIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
return {
|
||||
...item,
|
||||
payment: manyResult.find((fitem) => fitem.deceasedRetailId === item.id),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
router.post("/query", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const {
|
||||
pageNumber = 1,
|
||||
pageSize = 10,
|
||||
deceased = {},
|
||||
retail = {},
|
||||
} = req.body;
|
||||
|
||||
// 参数校验
|
||||
const connection = getConnection();
|
||||
const queryBuilder = connection
|
||||
.getRepository(DeceasedRetail)
|
||||
.createQueryBuilder("retail")
|
||||
.leftJoinAndMapOne(
|
||||
"retail.deceased",
|
||||
Deceased,
|
||||
"deceased",
|
||||
"deceased.id = retail.deceased_id"
|
||||
)
|
||||
.leftJoinAndMapOne(
|
||||
"retail.payment",
|
||||
PaymentRecord,
|
||||
"payment",
|
||||
"payment.deceased_retail_id = retail.id"
|
||||
)
|
||||
.where(`retail.cancel_state = 0`)
|
||||
.andWhere("retail.retail_type = :retailType", {
|
||||
retailType: retail.retailType ?? 0,
|
||||
});
|
||||
|
||||
req.body.startDate = retail.startDate;
|
||||
req.body.endDate = retail.endDate;
|
||||
let { startDate, endDate } = parseRangDate(req);
|
||||
if (retail.retailType === 2) {
|
||||
if (retail.familyName) {
|
||||
queryBuilder.andWhere("retail.familyName LIKE :familyName", {
|
||||
familyName: `%${retail.familyName}%`,
|
||||
});
|
||||
}
|
||||
if (deceased.name) {
|
||||
queryBuilder.andWhere("retail.deceased_Name LIKE :name", {
|
||||
name: `%${deceased.name}%`,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (retail.retailType === 1) {
|
||||
if (deceased.name) {
|
||||
queryBuilder.andWhere("deceased.name LIKE :name", {
|
||||
name: `%${deceased.name}%`,
|
||||
});
|
||||
}
|
||||
if (retail.familyName) {
|
||||
queryBuilder.andWhere("retail.familyName LIKE :familyName", {
|
||||
familyName: `%${retail.familyName}%`,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (startDate && endDate) {
|
||||
queryBuilder
|
||||
.andWhere(`retail.purchaseDate BETWEEN :start AND :end`)
|
||||
.setParameters({ start: startDate, end: endDate });
|
||||
}
|
||||
|
||||
if (retail.guide) {
|
||||
queryBuilder.andWhere(`retail.guide LIKE :guide`, {
|
||||
guide: retail.guide,
|
||||
});
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
const [list, total] = await queryBuilder
|
||||
.orderBy("retail.createDate", "DESC")
|
||||
.skip((pageNumber - 1) * pageSize)
|
||||
.take(pageSize)
|
||||
.getManyAndCount();
|
||||
|
||||
let result = {
|
||||
list,
|
||||
total,
|
||||
pageSize,
|
||||
pageNumber,
|
||||
};
|
||||
await GetData(result);
|
||||
|
||||
res.json({
|
||||
code: 200,
|
||||
data: result,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("查询失败:", err);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
msg: process.env.NODE_ENV === "production" ? "服务器错误" : err.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
try {
|
||||
let { retailType } = req.method === "GET" ? req.query : req.body;
|
||||
let queryBuilder = getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.createQueryBuilder("dr")
|
||||
.where(`dr.retailType=${retailType}`)
|
||||
.andWhere(`dr.cancelState = 0`);
|
||||
|
||||
const { pageSize, pageNumber } = getPaginationParams(req);
|
||||
|
||||
let [list, total] = await queryBuilder
|
||||
.orderBy("dr.createDate", "DESC")
|
||||
.skip((pageNumber - 1) * pageSize)
|
||||
.take(pageSize)
|
||||
.getManyAndCount();
|
||||
let result = {
|
||||
list,
|
||||
pageNumber,
|
||||
pageSize,
|
||||
total,
|
||||
};
|
||||
|
||||
await GetData(result);
|
||||
res.status(200).send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* retailId: 销售单ID
|
||||
* deceasedId: 人的ID,且必须传retailType
|
||||
*/
|
||||
router.get("/selected-service", async (req, res) => {
|
||||
let retailId = req.query.retailId;
|
||||
let deceasedId = req.query.deceasedId;
|
||||
let retailType = req.query.retailType;
|
||||
try {
|
||||
let retail;
|
||||
if (retailId) {
|
||||
if (retailType && Number(retailType) === 2) {
|
||||
retail = await getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.findOne({
|
||||
where: {
|
||||
id: Number(retailId),
|
||||
retailType,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
retail = await getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.findOne(Number(retailId));
|
||||
}
|
||||
}
|
||||
if (deceasedId) {
|
||||
retail = await getConnection()
|
||||
.getRepository(DeceasedRetail)
|
||||
.createQueryBuilder("deceasedRetail")
|
||||
.where("deceasedRetail.retail_type = :retailType", {
|
||||
retailType,
|
||||
})
|
||||
.andWhere("deceasedRetail.deceased_id = :deceasedId", {
|
||||
deceasedId,
|
||||
})
|
||||
.getOne();
|
||||
}
|
||||
if (!retail) return res.status(200).send({ code: 200, data: { list: [] } });
|
||||
|
||||
const ids = retail.serviceItems
|
||||
? retail.serviceItems.split(",").map((id) => Number(id))
|
||||
: [];
|
||||
|
||||
if (!ids.length)
|
||||
return res.status(200).send({ code: 200, data: { list: [] } });
|
||||
const result = await getConnection()
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
res.status(200).send({ code: 200, data: { list: result } });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/checkout", async (req, res) => {
|
||||
let { id } = req.query;
|
||||
if (!id) {
|
||||
return res.status(500).send({ code: 500, msg: "未传入结账id" });
|
||||
}
|
||||
|
||||
let deceasedRetailRep = getConnection().getRepository(DeceasedRetail);
|
||||
let deceasedRetail = await deceasedRetailRep.findOne(Number(id));
|
||||
|
||||
if (!deceasedRetail)
|
||||
return res.status(500).send({ code: 500, msg: "该记录不存在" });
|
||||
|
||||
deceasedRetail.retailState = 1;
|
||||
|
||||
await deceasedRetailRep.save(deceasedRetail);
|
||||
|
||||
res.status(200).send({ code: 200, data: deceasedRetail, msg: "结账成功!" });
|
||||
});
|
||||
|
||||
// 添加逝者零售
|
||||
router.post("/add", async (req, res) => {
|
||||
delete req.body.id;
|
||||
const connection = getConnection();
|
||||
try {
|
||||
const tempServiceItems = req.body.services.map((item) => {
|
||||
delete item.id;
|
||||
|
||||
return item;
|
||||
});
|
||||
req.body.serviceItems = "";
|
||||
|
||||
const deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
const newDeceasedRetail = await curd({ entity: DeceasedRetail, req }).add();
|
||||
|
||||
if (tempServiceItems.length) {
|
||||
tempServiceItems.forEach((item) => {
|
||||
item.retailId = newDeceasedRetail.id;
|
||||
});
|
||||
let executeData = await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.save(tempServiceItems);
|
||||
|
||||
newDeceasedRetail.serviceItems = executeData
|
||||
.map((item) => item.id)
|
||||
.join(",");
|
||||
|
||||
await deceasedRetailRep.save(newDeceasedRetail);
|
||||
}
|
||||
|
||||
res.send({ code: 200, msg: "逝者零售添加成功", data: newDeceasedRetail });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/updateRetail", async (req, res) => {
|
||||
const connection = getConnection();
|
||||
try {
|
||||
const tempServiceItems = req.body.services.map((item) => {
|
||||
return item;
|
||||
});
|
||||
req.body.serviceItems = "";
|
||||
|
||||
const deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
let newDeceasedRetail = await deceasedRetailRep.findOne({
|
||||
id: req.body?.retail?.id,
|
||||
});
|
||||
|
||||
if (!newDeceasedRetail) {
|
||||
newDeceasedRetail = await deceasedRetailRep.findOne({
|
||||
where: { deceasedId: req.body.deceasedId, retailType: 0 },
|
||||
});
|
||||
}
|
||||
|
||||
if (tempServiceItems.length) {
|
||||
tempServiceItems.forEach((item) => {
|
||||
item.retailId = newDeceasedRetail.id;
|
||||
item.updateDate = new Date();
|
||||
item.createDate = new Date();
|
||||
});
|
||||
|
||||
const ids = newDeceasedRetail.serviceItems
|
||||
.split(",")
|
||||
.map((id) => Number(id));
|
||||
if (ids.length) {
|
||||
await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.delete()
|
||||
.execute();
|
||||
}
|
||||
|
||||
let executeData = await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.save(tempServiceItems);
|
||||
|
||||
newDeceasedRetail.salesAmount = req.body.salesAmount;
|
||||
|
||||
newDeceasedRetail.serviceItems = executeData
|
||||
.map((item) => item.id)
|
||||
.join(",");
|
||||
|
||||
// 保存人
|
||||
let deceased = await connection
|
||||
.getRepository(Deceased)
|
||||
.findOne(req.body.id);
|
||||
if (deceased) {
|
||||
deceased = { ...deceased, ...req.body.deceased };
|
||||
deceased.salesAmount = newDeceasedRetail.salesAmount;
|
||||
|
||||
await connection.getRepository(Deceased).save(deceased);
|
||||
}
|
||||
} else {
|
||||
const ids = newDeceasedRetail.serviceItems
|
||||
.split(",")
|
||||
.map((id) => Number(id));
|
||||
if (ids.length) {
|
||||
await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.delete()
|
||||
.execute();
|
||||
}
|
||||
newDeceasedRetail.serviceItems = "";
|
||||
}
|
||||
|
||||
await deceasedRetailRep.save(newDeceasedRetail);
|
||||
|
||||
res.send({ code: 200, msg: "逝者服务单修改成功", data: newDeceasedRetail });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新逝者信息
|
||||
router.post("/update", async (req, res) => {
|
||||
const id = Number(req.body.id);
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "逝者ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceasedRepository = connection.getRepository(DeceasedRetail);
|
||||
const deceasedRep = connection.getRepository(Deceased);
|
||||
|
||||
let services = req.body.retail?.services || req.body.services;
|
||||
const tempServiceItems = services.map((item) => {
|
||||
delete item.id;
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
let findData = await deceasedRepository.findOne(id);
|
||||
|
||||
let decease = await deceasedRep.findOne(Number(findData.deceasedId));
|
||||
|
||||
const ids = findData.serviceItems.split(",").map((id) => Number(id));
|
||||
if (ids.length) {
|
||||
await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.delete()
|
||||
.execute();
|
||||
}
|
||||
|
||||
findData = { ...findData, ...req.body };
|
||||
if (tempServiceItems.length) {
|
||||
tempServiceItems.forEach((item) => {
|
||||
item.retailId = id;
|
||||
item.hasDeceased = 0;
|
||||
item.updateDate = new Date();
|
||||
item.createDate = new Date();
|
||||
});
|
||||
let executeData = await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.save(tempServiceItems);
|
||||
|
||||
findData.serviceItems = executeData.map((item) => item.id).join(",");
|
||||
}
|
||||
let newDeceased: Deceased = { ...req.body };
|
||||
delete newDeceased.id;
|
||||
|
||||
decease = { ...decease, ...newDeceased };
|
||||
|
||||
await deceasedRep.save(decease);
|
||||
await deceasedRepository.save(findData);
|
||||
|
||||
res.send({ code: 200, msg: "更新成功", data: findData });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除逝者信息
|
||||
router.get("/delete", async (req, res) => {
|
||||
const id = Number(req.query.id);
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "数据ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceasedRepository = connection.getRepository(DeceasedRetail);
|
||||
|
||||
const findData = await deceasedRepository.findOne(id);
|
||||
|
||||
const ids = findData.serviceItems.split(",").map((id) => Number(id));
|
||||
if (ids.length) {
|
||||
await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.delete()
|
||||
.execute();
|
||||
}
|
||||
await deceasedRepository.remove(findData);
|
||||
|
||||
res.send({ code: 200, msg: "删除成功!" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
75
backEnd/src/router/index.ts
Normal file
75
backEnd/src/router/index.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import * as express from "express";
|
||||
import login from "./login/login";
|
||||
import user from "./user/user";
|
||||
import systemMenue from "./system-menue/system-menue";
|
||||
import role from "./role/role";
|
||||
import deceased from "./deceased/deceased";
|
||||
import serviceItem from "./serviceList/serviceItem";
|
||||
import serviceCategory from "./serviceList/serviceCategory";
|
||||
import deceasedRetail from "./deceasedRetail/deceasedRetail";
|
||||
import checkout from "./checkout/checkout";
|
||||
import retailCheckout from "./retailCheckout/retailCheckout";
|
||||
import noDeceasedRetail from "./noDeceasedRetail/noDeceasedRetail";
|
||||
import cancleExamine from "./cancle/cancleExamine";
|
||||
import CheckoutRetail from "./CheckoutRetail/CheckoutRetail";
|
||||
import publicList from "./public/public";
|
||||
import Stats from "./stats/stats";
|
||||
|
||||
let jwt = require("jsonwebtoken");
|
||||
|
||||
let router = express.Router();
|
||||
const secretKey = "myNameIsLiJiaTu";
|
||||
|
||||
// 统一请求入口
|
||||
router.use("/", (req, res, next) => {
|
||||
const token = req.headers.authorization;
|
||||
const refreshToken = req.headers.refreshtoken;
|
||||
// 非登录并且无token证明用户未登录,禁止操作,不需要这个,注释即可
|
||||
if (!token && !refreshToken && req.path !== "/login")
|
||||
return res.send({ code: 401, msg: "未登录,禁止操作访问!" });
|
||||
|
||||
if (token) {
|
||||
jwt.verify(token, secretKey, (err, decoded) => {
|
||||
if (err) {
|
||||
if (!refreshToken) {
|
||||
return res.status(401).send({ code: 401, msg: "请重新登录" });
|
||||
}
|
||||
jwt.verify(refreshToken, secretKey, (refErr, refDecoded) => {
|
||||
if (refErr) {
|
||||
return res
|
||||
.status(401)
|
||||
.send({ code: 401, msg: "登录已失效,请重新登录。" });
|
||||
} else {
|
||||
let userId = refDecoded.userId;
|
||||
const newToken = jwt.sign({ userId }, secretKey, {
|
||||
expiresIn: "1h",
|
||||
});
|
||||
res.setHeader("refreshToken", newToken);
|
||||
next();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
router.use("/login", login);
|
||||
router.use("/user", user);
|
||||
router.use("/system-menue", systemMenue);
|
||||
router.use("/role", role);
|
||||
router.use("/public/", publicList);
|
||||
router.use("/deceased", deceased);
|
||||
router.use("/deceased-retail", deceasedRetail);
|
||||
router.use("/service-item", serviceItem);
|
||||
router.use("/service-category", serviceCategory);
|
||||
router.use("/checkout", checkout);
|
||||
router.use("/retail-checkout", retailCheckout);
|
||||
router.use("/no-deceased-retail", noDeceasedRetail);
|
||||
router.use("/cancel", cancleExamine);
|
||||
router.use("/checkout-retail", CheckoutRetail);
|
||||
router.use("/stats", Stats);
|
||||
|
||||
export default router;
|
||||
117
backEnd/src/router/login/login.ts
Normal file
117
backEnd/src/router/login/login.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import * as express from "express";
|
||||
import { Request, Response } from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import User from "../../entity/User";
|
||||
import { Role } from "../../entity/Role";
|
||||
import { SystemMenue } from "../../entity/SystemMenue";
|
||||
import menueToTree from "../../lib/menueToTree";
|
||||
|
||||
const router = express.Router();
|
||||
let jwt = require("jsonwebtoken");
|
||||
|
||||
const secretKey = "myNameIsLiJiaTu";
|
||||
|
||||
// 递归获取所有父级菜单的ID
|
||||
async function getAllParentIds(menuIds: number[]): Promise<number[]> {
|
||||
const parentIds = new Set<number>();
|
||||
|
||||
const getParents = async (id: number) => {
|
||||
let menueRep = getConnection().getRepository(SystemMenue);
|
||||
const menu = await menueRep.findOne({ where: { id } });
|
||||
if (menu && menu.parentId !== 0) {
|
||||
parentIds.add(menu.parentId);
|
||||
await getParents(menu.parentId);
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all(menuIds.map((id) => getParents(id)));
|
||||
return Array.from(parentIds);
|
||||
}
|
||||
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
const { name, pwd } = req.body;
|
||||
|
||||
const connection = getConnection();
|
||||
const user = connection.getRepository(User);
|
||||
if (!(await user.findAndCount())[0].length && name === "admin") {
|
||||
let userInstance = new User();
|
||||
userInstance = {
|
||||
...userInstance,
|
||||
name: "admin",
|
||||
pwd: "E10ADC3949BA59ABBE56E057F20F883E",
|
||||
role: "1",
|
||||
userState: 1,
|
||||
};
|
||||
userInstance.createDate = userInstance.createDate || new Date();
|
||||
userInstance.updateDate = userInstance.updateDate || new Date();
|
||||
|
||||
await connection.getRepository(User).save(userInstance);
|
||||
}
|
||||
|
||||
const findUser = await user.findOne({ name });
|
||||
if (!findUser) return res.send("该用户不存在,请检查!");
|
||||
|
||||
if (findUser && findUser.pwd !== pwd) return res.send("密码错误,请检查!");
|
||||
if (findUser.userState === 0 && findUser.name !== "admin")
|
||||
return res.send({ code: 500, msg: "该账号被禁止使用,请联系管理员!" });
|
||||
|
||||
let userRole = findUser.role;
|
||||
let roleRep = connection.getRepository(Role);
|
||||
|
||||
if (findUser.name === "admin") {
|
||||
let role = await roleRep.findOne({ where: { id: Number(userRole) } });
|
||||
role.values = (
|
||||
await connection.getRepository(SystemMenue).findAndCount()
|
||||
)[0]
|
||||
.map((item) => item.id.toString())
|
||||
.join(",");
|
||||
if (role.values.length !== findUser.role.length) {
|
||||
await roleRep.save(role);
|
||||
}
|
||||
}
|
||||
let roleRes = await roleRep
|
||||
.createQueryBuilder("role")
|
||||
.where("role.id IN (:...userRole)", { userRole: userRole.split(",") })
|
||||
.getOne();
|
||||
if (roleRes) {
|
||||
let menueRep = connection.getRepository(SystemMenue);
|
||||
// 在原有查询中增加父级查询
|
||||
const selectedMenuIds = roleRes.values.split(",").map(Number); // [34,33,24]
|
||||
const parentIds = await getAllParentIds(selectedMenuIds); // 获取所有父级ID(如26)
|
||||
|
||||
const finalMenuIds = Array.from(
|
||||
new Set([...selectedMenuIds, ...parentIds])
|
||||
); // 合并选中的ID和父级ID
|
||||
|
||||
let menueList = await menueRep
|
||||
.createQueryBuilder("system_menue")
|
||||
.where("system_menue.id IN (:...menue)", { menue: finalMenuIds })
|
||||
.getMany();
|
||||
|
||||
findUser["routerMenue"] = menueToTree(menueList);
|
||||
} else {
|
||||
findUser["routerMenue"] = [];
|
||||
}
|
||||
|
||||
// 登录成功,生成 JWT
|
||||
const token = jwt.sign({ userId: findUser.id }, secretKey, {
|
||||
expiresIn: "1h",
|
||||
});
|
||||
const refreshToken = jwt.sign({ userId: findUser.id }, secretKey, {
|
||||
expiresIn: "1d",
|
||||
});
|
||||
|
||||
// 过滤密码
|
||||
delete findUser.pwd;
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "登录成功!",
|
||||
data: {
|
||||
token: "Bearer " + token,
|
||||
refreshToken,
|
||||
user: findUser,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
212
backEnd/src/router/noDeceasedRetail/noDeceasedRetail.ts
Normal file
212
backEnd/src/router/noDeceasedRetail/noDeceasedRetail.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import * as express from "express";
|
||||
import { getConnection, getRepository } from "typeorm";
|
||||
import DeceasedRetail from "../../entity/DeceasedRetail";
|
||||
import curd from "@/lib/curd/curd";
|
||||
import SeletedServiceList from "@/entity/SeletedServiceList";
|
||||
import Deceased from "@/entity/Deceased";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
async function GetData(result) {
|
||||
const ids = Array.from(
|
||||
new Set(result.list.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
|
||||
if (ids.length) {
|
||||
const manyResult = await getConnection()
|
||||
.getRepository(Deceased)
|
||||
.createQueryBuilder("deceased")
|
||||
.where("deceased.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
let findData = manyResult.find(
|
||||
(fitem: any) => fitem.id === item.deceasedId
|
||||
);
|
||||
return {
|
||||
...findData,
|
||||
...item,
|
||||
deceased: findData,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
try {
|
||||
const result = await curd({
|
||||
entity: DeceasedRetail,
|
||||
req,
|
||||
params: {
|
||||
retailType: 2,
|
||||
},
|
||||
}).queryList();
|
||||
await GetData(result);
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
try {
|
||||
const result: any = await curd({
|
||||
entity: DeceasedRetail,
|
||||
req,
|
||||
params: {
|
||||
retailType: 2,
|
||||
},
|
||||
}).queryList();
|
||||
await GetData(result);
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/checkout", async (req, res) => {
|
||||
let { id } = req.query;
|
||||
if (!id) {
|
||||
return res.status(500).send({ code: 500, msg: "未传入结账id" });
|
||||
}
|
||||
|
||||
let deceasedRetailRep = getConnection().getRepository(DeceasedRetail);
|
||||
let deceasedRetail = await deceasedRetailRep.findOne(Number(id));
|
||||
|
||||
if (!deceasedRetail)
|
||||
return res.status(500).send({ code: 500, msg: "该记录不存在" });
|
||||
|
||||
deceasedRetail.retailState = 1;
|
||||
|
||||
await deceasedRetailRep.save(deceasedRetail);
|
||||
|
||||
res.status(200).send({ code: 200, data: deceasedRetail, msg: "结账成功!" });
|
||||
});
|
||||
|
||||
router.post("/add", async (req, res) => {
|
||||
delete req.body.id;
|
||||
const connection = getConnection();
|
||||
try {
|
||||
const tempServiceItems = req.body.services.map((item) => {
|
||||
delete item.id;
|
||||
|
||||
return item;
|
||||
});
|
||||
req.body.serviceItems = "";
|
||||
|
||||
const deceasedRetailRep = connection.getRepository(DeceasedRetail);
|
||||
let newDeceasedRetail = new DeceasedRetail();
|
||||
|
||||
newDeceasedRetail = Object.assign(newDeceasedRetail, req.body);
|
||||
newDeceasedRetail.retailType = 2;
|
||||
|
||||
if (tempServiceItems.length) {
|
||||
tempServiceItems.forEach((item) => {
|
||||
item.retailId = newDeceasedRetail.id;
|
||||
item.hasDeceased = 0;
|
||||
});
|
||||
let executeData = await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.save(tempServiceItems);
|
||||
|
||||
newDeceasedRetail.serviceItems = executeData
|
||||
.map((item) => item.id)
|
||||
.join(",");
|
||||
|
||||
await deceasedRetailRep.save(newDeceasedRetail);
|
||||
}
|
||||
|
||||
res.send({ code: 200, msg: "添加成功", data: newDeceasedRetail });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/update", async (req, res) => {
|
||||
const id = Number(req.body.id);
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "逝者ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceasedRepository = connection.getRepository(DeceasedRetail);
|
||||
|
||||
const tempServiceItems = req.body.services.map((item) => {
|
||||
delete item.id;
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
let findData = await deceasedRepository.findOne(id);
|
||||
|
||||
const ids = findData.serviceItems.split(",").map((id) => Number(id));
|
||||
if (ids.length) {
|
||||
await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.delete()
|
||||
.execute();
|
||||
}
|
||||
findData = { ...findData, ...req.body };
|
||||
if (tempServiceItems.length) {
|
||||
tempServiceItems.forEach((item) => {
|
||||
item.retailId = id;
|
||||
item.hasDeceased = 0;
|
||||
item.updateDate = new Date();
|
||||
item.createDate = new Date();
|
||||
});
|
||||
let executeData = await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.save(tempServiceItems);
|
||||
|
||||
findData.serviceItems = executeData.map((item) => item.id).join(",");
|
||||
|
||||
await deceasedRepository.save(findData);
|
||||
}
|
||||
|
||||
res.send({ code: 200, msg: "更新成功", data: findData });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/delete", async (req, res) => {
|
||||
const id = Number(req.query.id);
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "数据ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const deceasedRepository = connection.getRepository(DeceasedRetail);
|
||||
|
||||
const findData = await deceasedRepository.findOne(id);
|
||||
|
||||
const ids = findData.serviceItems.split(",").map((id) => Number(id));
|
||||
if (ids.length) {
|
||||
await connection
|
||||
.getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("seleted_service_list")
|
||||
.where("seleted_service_list.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.delete()
|
||||
.execute();
|
||||
}
|
||||
await deceasedRepository.remove(findData);
|
||||
|
||||
res.send({ code: 200, msg: "删除成功!" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
65
backEnd/src/router/public/public.ts
Normal file
65
backEnd/src/router/public/public.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import User from "../../entity/User";
|
||||
import { Role } from "@/entity/Role";
|
||||
|
||||
import ServiceCategory from "@/entity/ServiceCategory"; // 请确保路径正确
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/guide", async (req, res) => {
|
||||
let roleRep = getConnection().getRepository(Role);
|
||||
let guide1ID = (await roleRep.findOne({ name: "服务部" })).id;
|
||||
|
||||
let guideIds = [guide1ID]
|
||||
.filter((item) => item)
|
||||
.map((item) => item.toString());
|
||||
let userList = await getConnection()
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.where("user.role IN (:...ids)", {
|
||||
ids: guideIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
data: userList.map((item) => {
|
||||
return {
|
||||
value: item.name,
|
||||
label: item.name,
|
||||
};
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/service-categories", async (req, res) => {
|
||||
try {
|
||||
// 获取服务分类Repository
|
||||
const categoryRepo = getConnection().getRepository(ServiceCategory);
|
||||
|
||||
// 查询所有分类(可按需要添加排序)
|
||||
const categories = await categoryRepo.find({
|
||||
order: { createDate: "DESC" }, // 按创建时间倒序
|
||||
});
|
||||
|
||||
// 格式化返回数据
|
||||
return res.status(200).json({
|
||||
code: 200,
|
||||
data: categories.map((item) => ({
|
||||
value: item.id, // 使用ID作为值
|
||||
label: item.name, // 显示分类名称
|
||||
// 可根据需要添加额外字段
|
||||
name: item.name,
|
||||
// parentId: item.parentId
|
||||
})),
|
||||
});
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
code: 500,
|
||||
msg: "获取服务分类失败,请稍后重试",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
130
backEnd/src/router/retailCheckout/retailCheckout.ts
Normal file
130
backEnd/src/router/retailCheckout/retailCheckout.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import ServiceItem from "../../entity/ServiceItem";
|
||||
import curd from "@/lib/curd/curd";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import Deceased from "@/entity/Deceased";
|
||||
import noDeceasedRetail from "@/entity/noDeceasedRetail";
|
||||
import PaymentRecord from "@/entity/Payment";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
async function GetData(result) {
|
||||
let paymentIds = result.list
|
||||
.filter((item) => item.retailState === 1)
|
||||
.map((item) => item.id);
|
||||
if (paymentIds.length) {
|
||||
let manyResult = await getConnection()
|
||||
.getRepository(PaymentRecord)
|
||||
.createQueryBuilder("PaymentRecord")
|
||||
.where("PaymentRecord.deceased_retail_id IN (:...ids)", {
|
||||
ids: paymentIds,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
return {
|
||||
...item,
|
||||
payment: manyResult.find((fitem) => fitem.deceasedRetailId === item.id),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
let retailType = Number(req.query.retailType || 0);
|
||||
|
||||
try {
|
||||
let result = await curd({
|
||||
entity: DeceasedRetail,
|
||||
params: {
|
||||
cancelState: 0,
|
||||
retailType,
|
||||
...req.body,
|
||||
},
|
||||
req,
|
||||
}).queryList();
|
||||
|
||||
if (retailType === 1) {
|
||||
const ids = Array.from(
|
||||
new Set(result.list.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
|
||||
if (ids.length) {
|
||||
const manyResult = await getConnection()
|
||||
.getRepository(Deceased)
|
||||
.createQueryBuilder("deceased")
|
||||
.where("deceased.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
let findData = manyResult.find(
|
||||
(fitem: any) => fitem.id === item.deceasedId
|
||||
);
|
||||
return {
|
||||
...findData,
|
||||
...item,
|
||||
deceased: findData,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await GetData(result);
|
||||
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
let retailType = Number(req.body.retailType);
|
||||
try {
|
||||
let result = await curd({
|
||||
entity: DeceasedRetail,
|
||||
params: {
|
||||
cancelState: 0,
|
||||
retailType,
|
||||
...req.body,
|
||||
},
|
||||
req,
|
||||
}).queryList();
|
||||
|
||||
if (retailType === 1) {
|
||||
const ids = Array.from(
|
||||
new Set(result.list.map((item) => Number(item.deceasedId)))
|
||||
);
|
||||
|
||||
if (ids.length) {
|
||||
const manyResult = await getConnection()
|
||||
.getRepository(Deceased)
|
||||
.createQueryBuilder("deceased")
|
||||
.where("deceased.id IN (:...ids)", {
|
||||
ids,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
result.list = result.list.map((item: any) => {
|
||||
let findData = manyResult.find(
|
||||
(fitem: any) => fitem.id === item.deceasedId
|
||||
);
|
||||
return {
|
||||
...findData,
|
||||
...item,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await GetData(result);
|
||||
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
70
backEnd/src/router/role/role.ts
Normal file
70
backEnd/src/router/role/role.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import pagination from "../../lib/pagination/pagination";
|
||||
import dayjs from "dayjs";
|
||||
import { Role } from "../../entity/Role";
|
||||
import curd from "@/lib/curd/curd";
|
||||
|
||||
let router = express.Router();
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
let data = await pagination(Role, req);
|
||||
return res.send({
|
||||
code: 200,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/add", async (req, res) => {
|
||||
let body = req.body;
|
||||
let roleRep = getConnection().manager.getRepository(Role);
|
||||
let findRole = await roleRep.findOne({ where: { name: body.name } });
|
||||
if (findRole) return res.send({ code: 500, msg: "角色名已存在!" });
|
||||
|
||||
await curd({ entity: Role, req }).add();
|
||||
|
||||
return res.send({ code: 200, msg: "角色添加成功!" });
|
||||
});
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
let data = await curd({ entity: Role, req }).queryList();
|
||||
return res.send({
|
||||
code: 200,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/delete", async (req, res) => {
|
||||
let roleRep = getConnection().manager.getRepository(Role);
|
||||
let { id } = req.query;
|
||||
let findMnue = await roleRep.find({ where: { id } });
|
||||
|
||||
if (!findMnue)
|
||||
return res.send({ code: 500, msg: "删除的角色不存在,请检查!" });
|
||||
|
||||
await roleRep.remove(findMnue);
|
||||
return res.send({ code: 200, msg: "删除成功!" });
|
||||
});
|
||||
|
||||
router.post("/update", async (req, res, next) => {
|
||||
if (!req.body.id)
|
||||
return res.send({ code: 502, msg: "未传入角色ID,请检查数据!" });
|
||||
|
||||
const bodyData = req.body;
|
||||
|
||||
const roleRep = getConnection().manager.getRepository(Role);
|
||||
let findRole = await roleRep.findOne({ where: { id: bodyData.id } });
|
||||
|
||||
findRole = { ...findRole, ...bodyData };
|
||||
findRole.updateDate = new Date();
|
||||
|
||||
await roleRep.save(findRole);
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "角色修改成功!",
|
||||
data: findRole,
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
155
backEnd/src/router/serviceList/serviceCategory.ts
Normal file
155
backEnd/src/router/serviceList/serviceCategory.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import ServiceCategory from "../../entity/ServiceCategory";
|
||||
import curd from "@/lib/curd/curd";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
req.body.pageSize = "1000";
|
||||
req.query.pageSize = "1000";
|
||||
|
||||
try {
|
||||
if (req.query.all) {
|
||||
req.body.pageSize = "1000";
|
||||
req.query.pageSize = "1000";
|
||||
const result = await curd({ entity: ServiceCategory, req }).queryList();
|
||||
return res.send({ code: 200, data: result });
|
||||
}
|
||||
// 查询数据库中的所有分类数据
|
||||
const result = await curd({ entity: ServiceCategory, req }).queryList();
|
||||
// 将数据转换为树形结构
|
||||
const buildTree = (items, parentId = 0) => {
|
||||
return items
|
||||
.filter((item) => item.parentId === parentId)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
children: buildTree(items, item.id), // 递归构建子节点
|
||||
}));
|
||||
};
|
||||
|
||||
const treeData = buildTree(result.list);
|
||||
|
||||
result.list = treeData;
|
||||
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
try {
|
||||
// 查询数据库中的所有分类数据
|
||||
const result = await curd({ entity: ServiceCategory, req }).queryList();
|
||||
|
||||
// 将数据转换为树形结构
|
||||
// const buildTree = (items, parentId = 0) => {
|
||||
// return items
|
||||
// .filter((item) => item.parentId === parentId)
|
||||
// .map((item) => ({
|
||||
// ...item,
|
||||
// children: buildTree(items, item.id), // 递归构建子节点
|
||||
// }));
|
||||
// };
|
||||
|
||||
// const treeData = buildTree(result.list);
|
||||
|
||||
// result.list = treeData;
|
||||
|
||||
res.send({ code: 200, data: result });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 添加商品分类
|
||||
router.post("/add", async (req, res) => {
|
||||
const { name } = req.body;
|
||||
|
||||
if (!name) {
|
||||
return res.send({ code: 400, msg: "商品分类名称不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const categoryRepository = connection.getRepository(ServiceCategory);
|
||||
|
||||
// 校验是否已存在相同名称的商品分类
|
||||
const existingCategory = await categoryRepository.findOne({
|
||||
where: { name },
|
||||
});
|
||||
|
||||
if (existingCategory) {
|
||||
return res.send({ code: 400, msg: "商品分类名称已存在,请勿重复添加!" });
|
||||
}
|
||||
|
||||
let newCategory = new ServiceCategory();
|
||||
newCategory = {
|
||||
...newCategory,
|
||||
...req.body,
|
||||
};
|
||||
|
||||
await categoryRepository.save(newCategory);
|
||||
res.send({ code: 200, msg: "商品分类添加成功", data: newCategory });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新商品分类
|
||||
router.post("/update", async (req, res) => {
|
||||
const { id } = req.body;
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "商品分类ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const categoryRepository = connection.getRepository(ServiceCategory);
|
||||
|
||||
// 查找商品分类
|
||||
let category = await categoryRepository.findOne(Number(id));
|
||||
if (!category) {
|
||||
return res.send({ code: 400, msg: "商品分类不存在!" });
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
category = {
|
||||
...category,
|
||||
...req.body,
|
||||
};
|
||||
|
||||
await categoryRepository.save(category);
|
||||
res.send({ code: 200, msg: "商品分类更新成功", data: category });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除商品分类
|
||||
router.get("/delete", async (req, res) => {
|
||||
const { id } = req.query;
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "商品分类ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const categoryRepository = connection.getRepository(ServiceCategory);
|
||||
|
||||
const category = await categoryRepository.findOne(Number(id));
|
||||
if (!category) {
|
||||
return res.send({ code: 400, msg: "商品分类不存在!" });
|
||||
}
|
||||
|
||||
await categoryRepository.remove(category);
|
||||
res.send({ code: 200, msg: "商品分类删除成功" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
112
backEnd/src/router/serviceList/serviceItem.ts
Normal file
112
backEnd/src/router/serviceList/serviceItem.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import ServiceItem from "../../entity/ServiceItem";
|
||||
import curd from "@/lib/curd/curd";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 查询服务项目列表(支持分页)
|
||||
// router.get("/list", async (req, res) => {
|
||||
// try {
|
||||
// const result = await curd({ entity: ServiceItem, req }).queryList();
|
||||
// res.send({ code: 200, data: result });
|
||||
// } catch (err) {
|
||||
// res.status(500).send({ code: 500, msg: err.message });
|
||||
// }
|
||||
// });
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
if (req.query.all) {
|
||||
req.body.pageSize = "1000";
|
||||
req.query.pageSize = "1000";
|
||||
}
|
||||
let data = await curd({ entity: ServiceItem, req }).queryList();
|
||||
return res.send({
|
||||
code: 200,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
let data = await curd({ entity: ServiceItem, req }).queryList();
|
||||
return res.send({
|
||||
code: 200,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
||||
// 添加服务项目
|
||||
router.post("/add", async (req, res) => {
|
||||
const { name } = req.body;
|
||||
if (!name) {
|
||||
return res.send({ code: 400, msg: "服务项目名称不能为空!" });
|
||||
}
|
||||
const connection = getConnection();
|
||||
const itemRepository = connection.getRepository(ServiceItem);
|
||||
if (await itemRepository.findOne({ name })) {
|
||||
return res.send({ code: 400, msg: "服务项目名称已存在!" });
|
||||
}
|
||||
try {
|
||||
const newDeceased = await curd({ entity: ServiceItem, req }).add();
|
||||
res.send({ code: 200, msg: "服务项目添加成功", data: newDeceased });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新服务项目
|
||||
router.post("/update", async (req, res) => {
|
||||
const { id, name } = req.body;
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "服务项目ID不能为空!" });
|
||||
}
|
||||
const connection = getConnection();
|
||||
const itemRepository = connection.getRepository(ServiceItem);
|
||||
try {
|
||||
// 查找服务项目
|
||||
let serviceItem = await itemRepository.findOne({ id });
|
||||
if (!serviceItem) {
|
||||
return res.send({ code: 400, msg: "服务项目不存在!" });
|
||||
}
|
||||
if (serviceItem.id !== id && serviceItem.name === name) {
|
||||
return res.send({ code: 400, msg: "服务项目名称已存在!" });
|
||||
}
|
||||
serviceItem = {
|
||||
...serviceItem,
|
||||
...req.body,
|
||||
parentId: req.body.parentId ?? 0,
|
||||
};
|
||||
|
||||
await itemRepository.save(serviceItem);
|
||||
res.send({ code: 200, msg: "服务项目更新成功", data: serviceItem });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除服务项目
|
||||
router.get("/delete", async (req, res) => {
|
||||
const { id } = req.query;
|
||||
|
||||
if (!id) {
|
||||
return res.send({ code: 400, msg: "服务项目ID不能为空!" });
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = getConnection();
|
||||
const itemRepository = connection.getRepository(ServiceItem);
|
||||
|
||||
const item = await itemRepository.findOne(Number(id));
|
||||
if (!item) {
|
||||
return res.send({ code: 400, msg: "服务项目不存在!" });
|
||||
}
|
||||
|
||||
await itemRepository.remove(item);
|
||||
res.send({ code: 200, msg: "服务项目删除成功" });
|
||||
} catch (err) {
|
||||
res.status(500).send({ code: 500, msg: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
121
backEnd/src/router/stats/controller/dayIncome.ts
Normal file
121
backEnd/src/router/stats/controller/dayIncome.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
// controllers/paymentStats.ts
|
||||
import { Request, Response } from "express";
|
||||
import { getRepository } from "typeorm";
|
||||
import dayjs from "dayjs";
|
||||
import CheckoutPaymentRecords from "@/entity/CheckoutPayment";
|
||||
import PaymentRecord from "@/entity/Payment";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import parseRangDate, { handleError } from "@/util/globalMethods";
|
||||
|
||||
// 类型定义
|
||||
type PaymentStats = {
|
||||
cashAmount: number;
|
||||
unionPayAmount: number;
|
||||
cardAmount: number;
|
||||
publicTransferAmount: number;
|
||||
workshopPayment: number;
|
||||
};
|
||||
|
||||
type StatsResponse = {
|
||||
retail: PaymentStats; // 零售单统计(来自PaymentRecord)
|
||||
service: PaymentStats; // 服务单统计(来自CheckoutPaymentRecords)
|
||||
total: PaymentStats; // 合并统计
|
||||
};
|
||||
|
||||
export const getPaymentStats = async (req: Request, res: Response) => {
|
||||
try {
|
||||
// 参数处理
|
||||
const { startDate, endDate } = parseRangDate(req);
|
||||
|
||||
// 并行获取统计结果
|
||||
const [retailStats, serviceStats] = await Promise.all([
|
||||
getRetailStats(startDate, endDate),
|
||||
getServiceStats(startDate, endDate),
|
||||
]);
|
||||
|
||||
// 构建响应
|
||||
const response: StatsResponse = {
|
||||
retail: retailStats,
|
||||
service: serviceStats,
|
||||
total: {
|
||||
cashAmount: retailStats.cashAmount + serviceStats.cashAmount,
|
||||
unionPayAmount:
|
||||
retailStats.unionPayAmount + serviceStats.unionPayAmount,
|
||||
cardAmount: retailStats.cardAmount + serviceStats.cardAmount,
|
||||
publicTransferAmount:
|
||||
retailStats.publicTransferAmount + serviceStats.publicTransferAmount,
|
||||
workshopPayment:
|
||||
retailStats.workshopPayment + serviceStats.workshopPayment,
|
||||
},
|
||||
};
|
||||
|
||||
res.json({ code: 200, data: response });
|
||||
} catch (error) {
|
||||
handleError(res, error);
|
||||
}
|
||||
};
|
||||
|
||||
// 修改后的获取零售单统计
|
||||
const getRetailStats = async (
|
||||
start: string,
|
||||
end: string
|
||||
): Promise<PaymentStats> => {
|
||||
const result = await getRepository(PaymentRecord)
|
||||
.createQueryBuilder("payment")
|
||||
.select([
|
||||
"SUM(payment.cash_amount) AS cashAmount",
|
||||
"SUM(payment.union_pay_amount) AS unionPayAmount",
|
||||
"SUM(payment.card_amount) AS cardAmount",
|
||||
"SUM(payment.public_transfer_amount) AS publicTransferAmount",
|
||||
"SUM(payment.workshop_payment) AS workshopPayment",
|
||||
])
|
||||
.where("payment.checkout_date BETWEEN :start AND :end", { start, end })
|
||||
.andWhere(
|
||||
`(payment.deceased_retail_id IN (
|
||||
SELECT id
|
||||
FROM deceased_retail
|
||||
WHERE retail_state = 1
|
||||
) OR payment.no_deceased_retail_id IN (
|
||||
SELECT id
|
||||
FROM deceased_retail
|
||||
WHERE retail_state = 1
|
||||
))`
|
||||
)
|
||||
.getRawOne();
|
||||
|
||||
return formatStats(result);
|
||||
};
|
||||
|
||||
// 修改后的获取服务单统计
|
||||
const getServiceStats = async (
|
||||
start: string,
|
||||
end: string
|
||||
): Promise<PaymentStats> => {
|
||||
const result = await getRepository(CheckoutPaymentRecords)
|
||||
.createQueryBuilder("cpr")
|
||||
.innerJoin(
|
||||
DeceasedRetail,
|
||||
"dr",
|
||||
"dr.id = cpr.checkout_retail_id AND dr.retail_state = 1"
|
||||
)
|
||||
.select([
|
||||
"SUM(cpr.cash_amount) AS cashAmount",
|
||||
"SUM(cpr.union_pay_amount) AS unionPayAmount",
|
||||
"SUM(cpr.card_amount) AS cardAmount",
|
||||
"SUM(cpr.public_transfer_amount) AS publicTransferAmount",
|
||||
"SUM(cpr.workshop_payment) AS workshopPayment",
|
||||
])
|
||||
.where("cpr.checkout_date BETWEEN :start AND :end", { start, end })
|
||||
.getRawOne();
|
||||
|
||||
return formatStats(result);
|
||||
};
|
||||
|
||||
/** 格式化统计结果 */
|
||||
const formatStats = (raw: any): PaymentStats => ({
|
||||
cashAmount: Number(raw?.cashAmount || 0),
|
||||
unionPayAmount: Number(raw?.unionPayAmount || 0),
|
||||
cardAmount: Number(raw?.cardAmount || 0),
|
||||
publicTransferAmount: Number(raw?.publicTransferAmount || 0),
|
||||
workshopPayment: Number(raw?.workshopPayment || 0),
|
||||
});
|
||||
199
backEnd/src/router/stats/controller/salesDetail.ts
Normal file
199
backEnd/src/router/stats/controller/salesDetail.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { Request, Response } from "express";
|
||||
import { getRepository } from "typeorm";
|
||||
import dayjs from "dayjs";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import SeletedServiceList from "@/entity/SeletedServiceList";
|
||||
import Deceased from "@/entity/Deceased";
|
||||
import { handleError } from "@/util/globalMethods";
|
||||
|
||||
interface QueryParams {
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
serviceName?: string;
|
||||
deceasedName?: string;
|
||||
pageSize?: number;
|
||||
pageNumber?: number;
|
||||
guide?: string;
|
||||
familyName: string;
|
||||
}
|
||||
|
||||
interface SalesDetailItem {
|
||||
id: string;
|
||||
checkoutDate: string;
|
||||
deceasedName: string;
|
||||
gender: string;
|
||||
age: number;
|
||||
idCard: string;
|
||||
contactPerson: string;
|
||||
contactPhone: string;
|
||||
serviceName: string;
|
||||
price: number;
|
||||
quantity: number;
|
||||
amount: number;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export const getSalesDetails = async (req: Request, res: Response) => {
|
||||
try {
|
||||
const params = parseQueryParams(
|
||||
req.method === "GET" ? req.query : req.body
|
||||
);
|
||||
const pageSize = Number(params.pageSize) || 10;
|
||||
const pageNumber = Number(params.pageNumber) || 1;
|
||||
|
||||
// 第一步:查询 SeletedServiceList 和 DeceasedRetail
|
||||
const initialQuery = getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("ssl")
|
||||
.innerJoinAndMapOne(
|
||||
"ssl.deceasedRetail",
|
||||
DeceasedRetail,
|
||||
"dr",
|
||||
"FIND_IN_SET(ssl.id, dr.serviceItems) AND dr.retailState = 1 AND dr.cancelState = 0 "
|
||||
);
|
||||
|
||||
if (pageSize !== 999999999) {
|
||||
// 如果还没有连接 Deceased 表,需要确保连接
|
||||
if (
|
||||
(params.deceasedName || params.familyName) &&
|
||||
!initialQuery.expressionMap.joinAttributes.some(
|
||||
(join) => join.alias.name === "d"
|
||||
)
|
||||
) {
|
||||
initialQuery.innerJoin(Deceased, "d", "d.id = dr.deceasedId");
|
||||
}
|
||||
if (params.startDate || params.endDate) {
|
||||
initialQuery.andWhere("dr.checkoutDate BETWEEN :start AND :end", {
|
||||
start:
|
||||
params.startDate ||
|
||||
dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
|
||||
end: params.endDate || dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
});
|
||||
}
|
||||
|
||||
// 服务名称条件
|
||||
if (params.serviceName) {
|
||||
initialQuery.andWhere("ssl.name LIKE :serviceName", {
|
||||
serviceName: `%${params.serviceName}%`,
|
||||
});
|
||||
}
|
||||
|
||||
if (params.guide) {
|
||||
initialQuery.andWhere("dr.guide LIKE :guide", {
|
||||
guide: `%${params.guide}%`,
|
||||
});
|
||||
}
|
||||
|
||||
// 逝者姓名条件
|
||||
if (params.deceasedName) {
|
||||
initialQuery.andWhere(
|
||||
"( d.name LIKE :deceasedName OR (dr.deceasedId = 0 AND dr.deceasedName LIKE :deceasedName))",
|
||||
{
|
||||
deceasedName: `%${params.deceasedName}%`,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// 逝者家属姓名条件
|
||||
if (params.familyName) {
|
||||
initialQuery.andWhere(
|
||||
"( d.familyName LIKE :familyName OR (dr.deceasedId = 0 AND dr.familyName LIKE :familyName) )",
|
||||
{
|
||||
familyName: `%${params.familyName}%`,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行初步查询
|
||||
const initialResult = await initialQuery
|
||||
.orderBy("dr.checkoutDate", "DESC")
|
||||
.skip((pageNumber - 1) * pageSize)
|
||||
.take(pageSize)
|
||||
.getMany();
|
||||
|
||||
// 第二步:根据初步查询结果查询绑定 Deceased
|
||||
|
||||
const deceasedIds = initialResult
|
||||
//@ts-ignore
|
||||
.map((item) => item.deceasedRetail?.deceasedId)
|
||||
.filter((id) => id !== undefined && id !== 0);
|
||||
|
||||
const deceasedMap = new Map();
|
||||
if (deceasedIds.length > 0) {
|
||||
const deceasedList = await getRepository(Deceased)
|
||||
.createQueryBuilder("d")
|
||||
.where("d.id IN (:...ids)", { ids: deceasedIds })
|
||||
.getMany();
|
||||
|
||||
deceasedList.forEach((deceased) => {
|
||||
deceasedMap.set(deceased.id, deceased);
|
||||
});
|
||||
}
|
||||
|
||||
// 合并结果
|
||||
const result = initialResult.map((item) => {
|
||||
//@ts-ignore
|
||||
if (item.deceasedRetail?.deceasedId !== 0) {
|
||||
//@ts-ignore
|
||||
item.deceased = deceasedMap.get(item.deceasedRetail.deceasedId) || {};
|
||||
} else {
|
||||
//@ts-ignore
|
||||
item.deceased = { ...item.deceasedRetail };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
// 获取总记录数
|
||||
const total = await initialQuery.getCount();
|
||||
res.json({
|
||||
code: 200,
|
||||
data: {
|
||||
list: result.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
// @ts-ignore
|
||||
sum: Number(item.price).toFixed(2) * Number(item.quantity),
|
||||
};
|
||||
}),
|
||||
pageSize,
|
||||
pageNumber,
|
||||
total,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
handleError(res, error);
|
||||
}
|
||||
};
|
||||
|
||||
const parseQueryParams = (query: any): QueryParams => {
|
||||
const {
|
||||
startDate,
|
||||
endDate,
|
||||
serviceName,
|
||||
deceasedName,
|
||||
guide,
|
||||
pageSize,
|
||||
pageNumber,
|
||||
familyName,
|
||||
} = query;
|
||||
|
||||
const validateDate = (date: string, field: string) => {
|
||||
if (date && !dayjs(date).isValid()) {
|
||||
throw new Error(`${field}格式错误,请使用YYYY-MM-DD格式`);
|
||||
}
|
||||
};
|
||||
|
||||
validateDate(startDate, "开始日期");
|
||||
validateDate(endDate, "结束日期");
|
||||
|
||||
return {
|
||||
startDate: startDate?.trim(),
|
||||
endDate: endDate?.trim(),
|
||||
serviceName: serviceName?.trim(),
|
||||
deceasedName: deceasedName?.trim(),
|
||||
guide: guide?.trim(),
|
||||
pageSize: pageSize ? parseInt(pageSize) : undefined,
|
||||
pageNumber: pageNumber ? parseInt(pageNumber) : undefined,
|
||||
familyName: familyName,
|
||||
};
|
||||
};
|
||||
272
backEnd/src/router/stats/controller/serviceStats.ts
Normal file
272
backEnd/src/router/stats/controller/serviceStats.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
// controllers/serviceStats.ts
|
||||
import { Request, Response } from "express";
|
||||
import { getRepository, In } from "typeorm";
|
||||
import dayjs from "dayjs";
|
||||
import DeceasedRetail from "@/entity/DeceasedRetail";
|
||||
import SeletedServiceList from "@/entity/SeletedServiceList";
|
||||
import ServiceItem from "@/entity/ServiceItem";
|
||||
import ServiceCategory from "@/entity/ServiceCategory";
|
||||
import { handleError } from "@/util/globalMethods";
|
||||
|
||||
// 类型定义
|
||||
interface ServiceStatsItem {
|
||||
serviceName: string;
|
||||
price: number;
|
||||
unit: string;
|
||||
quantity: number;
|
||||
subtotal: number;
|
||||
}
|
||||
|
||||
interface CategoryStats {
|
||||
categoryName: string;
|
||||
services: ServiceStatsItem[];
|
||||
totalQuantity: number;
|
||||
totalAmount: number;
|
||||
}
|
||||
|
||||
interface StatsResponse {
|
||||
categories: CategoryStats[];
|
||||
otherCategory: CategoryStats;
|
||||
grandTotalQuantity: number;
|
||||
grandTotalAmount: number;
|
||||
}
|
||||
|
||||
interface QueryParams {
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
serviceName?: string;
|
||||
categoryName?: string;
|
||||
}
|
||||
|
||||
export const getServiceStats = async (req: Request, res: Response) => {
|
||||
try {
|
||||
// 1. 参数解析和验证
|
||||
const params = parseQueryParams(
|
||||
req.method === "GET" ? req.query : req.body
|
||||
);
|
||||
// 2. 查询符合条件的零售单(按结账时间)
|
||||
const retailRecords = await getRepository(DeceasedRetail)
|
||||
.createQueryBuilder("dr")
|
||||
.where("dr.checkoutDate BETWEEN :start AND :end", {
|
||||
start:
|
||||
params.startDate ||
|
||||
dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
|
||||
end: params.endDate || dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss"),
|
||||
})
|
||||
.andWhere("dr.retailState = 1 AND dr.cancelState = 0") // 只统计已结账的
|
||||
.getMany();
|
||||
|
||||
// 3. 收集所有服务项目ID(从serviceItems字段)
|
||||
const allServiceItemIds = retailRecords
|
||||
.map((record) => {
|
||||
try {
|
||||
return record.serviceItems.split(",").map(Number);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.flat()
|
||||
.filter((id) => id > 0); // 过滤无效ID
|
||||
|
||||
if (allServiceItemIds.length === 0) {
|
||||
return res.json(emptyResponse());
|
||||
}
|
||||
|
||||
// 4. 查询这些服务项目在SeletedServiceList中的记录
|
||||
const selectedServices = await getRepository(SeletedServiceList)
|
||||
.createQueryBuilder("ssl")
|
||||
.where("ssl.id IN (:...ids)", { ids: allServiceItemIds })
|
||||
.getMany();
|
||||
|
||||
// 5. 收集所有不重复的服务名称
|
||||
const serviceNames = Array.from(
|
||||
new Set(selectedServices.map((s) => s.name))
|
||||
);
|
||||
if (serviceNames.length === 0) {
|
||||
return res.json(emptyResponse());
|
||||
}
|
||||
|
||||
// 6. 分步查询分类信息
|
||||
// 第一步:查询ServiceItem获取parentIds
|
||||
const serviceItems = await getRepository(ServiceItem)
|
||||
.createQueryBuilder("si")
|
||||
.select(["si.name", "si.parentId"])
|
||||
.where("si.name IN (:...names)", { names: serviceNames })
|
||||
.getMany();
|
||||
|
||||
// 第二步:收集所有parentIds
|
||||
const parentIds = Array.from(
|
||||
new Set(serviceItems.map((item) => item.parentId))
|
||||
);
|
||||
|
||||
// 第三步:批量查询分类名称
|
||||
const categories = await getRepository(ServiceCategory)
|
||||
.createQueryBuilder("sc")
|
||||
.select(["sc.id", "sc.name"])
|
||||
.where({ id: In(parentIds) })
|
||||
.getMany();
|
||||
|
||||
// 第四步:构建分类ID到名称的映射
|
||||
const categoryIdToName = new Map<number, string>();
|
||||
categories.forEach((cat) => categoryIdToName.set(cat.id, cat.name));
|
||||
|
||||
// 第五步:构建服务名称到分类的映射
|
||||
const nameToCategoryMap = new Map<string, string>();
|
||||
serviceItems.forEach((item) => {
|
||||
const categoryName = categoryIdToName.get(item.parentId) || "其他服务";
|
||||
nameToCategoryMap.set(item.name, categoryName);
|
||||
});
|
||||
|
||||
// 7. 初始化统计结构
|
||||
const categoryStats = new Map<string, ServiceStatsItem[]>();
|
||||
const otherServices: ServiceStatsItem[] = [];
|
||||
|
||||
// 8. 处理每个服务项的统计
|
||||
const serviceNameToStats = new Map<string, ServiceStatsItem>();
|
||||
|
||||
selectedServices.forEach((service) => {
|
||||
// 应用服务名称过滤条件
|
||||
if (params.serviceName && !service.name.includes(params.serviceName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existingItem = serviceNameToStats.get(service.name);
|
||||
if (existingItem) {
|
||||
// 如果已存在同名服务,则合并数量和金额
|
||||
existingItem.quantity += service.quantity;
|
||||
existingItem.subtotal += Number(service.price) * service.quantity;
|
||||
} else {
|
||||
// 否则创建新条目
|
||||
serviceNameToStats.set(service.name, {
|
||||
serviceName: service.name,
|
||||
price: Number(service.price),
|
||||
unit: service.unit,
|
||||
quantity: service.quantity,
|
||||
subtotal: Number(service.price) * service.quantity,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// // 9. 将合并后的服务项按分类分组
|
||||
// const categoryStats = new Map<string, ServiceStatsItem[]>();
|
||||
// const otherServices: ServiceStatsItem[] = [];
|
||||
|
||||
serviceNameToStats.forEach((statsItem, serviceName) => {
|
||||
// 获取分类名称,默认为"其他服务"
|
||||
const categoryName = nameToCategoryMap.get(serviceName) || "其他服务";
|
||||
|
||||
// 分类到对应分组
|
||||
if (categoryName === "其他服务") {
|
||||
otherServices.push(statsItem);
|
||||
} else {
|
||||
if (!categoryStats.has(categoryName)) {
|
||||
categoryStats.set(categoryName, []);
|
||||
}
|
||||
categoryStats.get(categoryName)?.push(statsItem);
|
||||
}
|
||||
});
|
||||
|
||||
// 9. 应用分类过滤条件
|
||||
if (params.categoryName) {
|
||||
if (params.categoryName !== "其他服务") {
|
||||
categoryStats.forEach((_, key) => {
|
||||
if (key !== params.categoryName) {
|
||||
categoryStats.delete(key);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
categoryStats.clear(); // 只保留其他服务
|
||||
}
|
||||
}
|
||||
|
||||
// 10. 构建最终响应
|
||||
const response = buildFinalResponse(categoryStats, otherServices);
|
||||
res.json({ code: 200, data: response });
|
||||
} catch (error) {
|
||||
handleError(res, error);
|
||||
}
|
||||
};
|
||||
|
||||
// 辅助函数
|
||||
const emptyResponse = (): StatsResponse => ({
|
||||
categories: [],
|
||||
otherCategory: {
|
||||
categoryName: "其他服务",
|
||||
services: [],
|
||||
totalQuantity: 0,
|
||||
totalAmount: 0,
|
||||
},
|
||||
grandTotalQuantity: 0,
|
||||
grandTotalAmount: 0,
|
||||
});
|
||||
|
||||
const buildFinalResponse = (
|
||||
categoryMap: Map<string, ServiceStatsItem[]>,
|
||||
otherItems: ServiceStatsItem[]
|
||||
): StatsResponse => {
|
||||
const categories: CategoryStats[] = [];
|
||||
let grandTotalQuantity = 0;
|
||||
let grandTotalAmount = 0;
|
||||
|
||||
// 处理分类数据
|
||||
categoryMap.forEach((items, categoryName) => {
|
||||
const totalQuantity = items.reduce((sum, item) => sum + item.quantity, 0);
|
||||
const totalAmount = items.reduce((sum, item) => sum + item.subtotal, 0);
|
||||
|
||||
categories.push({
|
||||
categoryName,
|
||||
services: items,
|
||||
totalQuantity,
|
||||
totalAmount,
|
||||
});
|
||||
|
||||
grandTotalQuantity += totalQuantity;
|
||||
grandTotalAmount += totalAmount;
|
||||
});
|
||||
|
||||
// 处理其他分类
|
||||
const otherTotalQuantity = otherItems.reduce(
|
||||
(sum, item) => sum + item.quantity,
|
||||
0
|
||||
);
|
||||
const otherTotalAmount = otherItems.reduce(
|
||||
(sum, item) => sum + item.subtotal,
|
||||
0
|
||||
);
|
||||
|
||||
grandTotalQuantity += otherTotalQuantity;
|
||||
grandTotalAmount += otherTotalAmount;
|
||||
|
||||
return {
|
||||
categories,
|
||||
otherCategory: {
|
||||
categoryName: "其他服务",
|
||||
services: otherItems,
|
||||
totalQuantity: otherTotalQuantity,
|
||||
totalAmount: otherTotalAmount,
|
||||
},
|
||||
grandTotalQuantity,
|
||||
grandTotalAmount,
|
||||
};
|
||||
};
|
||||
|
||||
const parseQueryParams = (query: any): QueryParams => {
|
||||
const { startDate, endDate, serviceName, categoryName } = query;
|
||||
|
||||
// 日期格式验证
|
||||
const validateDate = (date: string, field: string) => {
|
||||
if (date && !dayjs(date).isValid()) {
|
||||
throw new Error(`${field}格式错误,请使用YYYY-MM-DD格式`);
|
||||
}
|
||||
};
|
||||
|
||||
validateDate(startDate, "开始日期");
|
||||
validateDate(endDate, "结束日期");
|
||||
|
||||
return {
|
||||
startDate: startDate?.trim(),
|
||||
endDate: endDate?.trim(),
|
||||
serviceName: serviceName?.trim(),
|
||||
categoryName: categoryName?.trim(),
|
||||
};
|
||||
};
|
||||
13
backEnd/src/router/stats/stats.ts
Normal file
13
backEnd/src/router/stats/stats.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// controllers/paymentStats.ts
|
||||
import { Router } from "express";
|
||||
import { getPaymentStats } from "./controller/dayIncome";
|
||||
import { getServiceStats } from "./controller/serviceStats";
|
||||
import { getSalesDetails } from "./controller/salesDetail";
|
||||
|
||||
const router = Router();
|
||||
router.get("/dayIncome", getPaymentStats);
|
||||
router.get("/servicesStats", getServiceStats);
|
||||
router.get("/salesDetails", getSalesDetails);
|
||||
router.post("/salesDetails", getSalesDetails);
|
||||
|
||||
export default router;
|
||||
102
backEnd/src/router/system-menue/system-menue.ts
Normal file
102
backEnd/src/router/system-menue/system-menue.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import { SystemMenue } from "../../entity/SystemMenue";
|
||||
import pagination from "../../lib/pagination/pagination";
|
||||
import dayjs from "dayjs";
|
||||
import { filterObjEmptyVal } from "../../util/globalMethods";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
let isAll = req.query.all;
|
||||
req.query.pageSize = "1000";
|
||||
req.body.pageSize = "1000";
|
||||
let data = await pagination(SystemMenue, req);
|
||||
let dataList = [];
|
||||
for (let i = 0; i < data.list.length; i++) {
|
||||
let item = data.list[i];
|
||||
item.children = [];
|
||||
|
||||
for (let j = 0; j < data.list.length; j++) {
|
||||
let tempItem = data.list[j];
|
||||
if (tempItem.parentId === item.id) {
|
||||
item.children.push(tempItem);
|
||||
}
|
||||
}
|
||||
// 只添加父级
|
||||
if (!item.parentId || isAll) dataList.push(item);
|
||||
}
|
||||
data.list = dataList;
|
||||
data.total = dataList.length;
|
||||
return res.send({
|
||||
code: 200,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
let params = req.body;
|
||||
let data = await pagination(SystemMenue, req, filterObjEmptyVal(params));
|
||||
return res.send({
|
||||
code: 200,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/add", async (req, res) => {
|
||||
let menueRep = getConnection().manager.getRepository(SystemMenue);
|
||||
let body = req.body;
|
||||
let findMenue = await menueRep.findOne({ where: { name: body.name } });
|
||||
|
||||
if (findMenue) return res.send({ code: 403, msg: `${body.name}已经存在了` });
|
||||
|
||||
let menueInstance = new SystemMenue();
|
||||
menueInstance = body;
|
||||
menueInstance.createDate = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
await menueRep.save(menueInstance);
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "菜单增加成功!",
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/update", async (req, res) => {
|
||||
let menueRep = getConnection().manager.getRepository(SystemMenue);
|
||||
let body = req.body as SystemMenue;
|
||||
|
||||
let filterMenue = await menueRep.findOne({ where: { name: body.name } });
|
||||
if (
|
||||
filterMenue &&
|
||||
filterMenue.id !== body.id &&
|
||||
body.name === filterMenue.name
|
||||
) {
|
||||
return res.send({ code: 500, msg: "菜单名已经存在" });
|
||||
}
|
||||
|
||||
let findMenue = await menueRep.findOne({ where: { id: body.id } });
|
||||
|
||||
findMenue = { ...findMenue, ...body };
|
||||
findMenue.updateDate = dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
await menueRep.save(findMenue);
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "菜单修改成功!",
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/delete", async (req, res) => {
|
||||
let menueRep = getConnection().manager.getRepository(SystemMenue);
|
||||
let { id } = req.query;
|
||||
let findMnue = await menueRep.find({ where: { id } });
|
||||
|
||||
if (!findMnue)
|
||||
return res.send({ code: 500, msg: "删除菜单不存在,请检查!" });
|
||||
|
||||
await menueRep.remove(findMnue);
|
||||
return res.send({ code: 200, msg: "删除成功!" });
|
||||
});
|
||||
|
||||
export default router;
|
||||
116
backEnd/src/router/user/user.ts
Normal file
116
backEnd/src/router/user/user.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import * as express from "express";
|
||||
import { getConnection } from "typeorm";
|
||||
import User from "../../entity/User";
|
||||
import pagination from "../../lib/pagination/pagination";
|
||||
import dayjs from "dayjs";
|
||||
import curd from "@/lib/curd/curd";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post("/query", async (req, res) => {
|
||||
const findUsers = await curd({ entity: User, req }).query();
|
||||
if (!findUsers.length) return res.send({ code: 200, data: [] });
|
||||
// 过滤密码
|
||||
findUsers.map((item) => {
|
||||
// @ts-ignore
|
||||
delete item.pwd;
|
||||
return item;
|
||||
});
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
data: {
|
||||
list: findUsers,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/list", async (req, res) => {
|
||||
let data = await pagination(User, req);
|
||||
return res.send({
|
||||
code: 200,
|
||||
data: data,
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/add", async (req, res) => {
|
||||
const connection = getConnection();
|
||||
const bodyData = req.body;
|
||||
|
||||
if (!bodyData.name?.length)
|
||||
return res.send({ code: 502, msg: "用户名是必须的!" });
|
||||
|
||||
const userRep = connection.getRepository(User);
|
||||
const findUser = await userRep.findOne({ name: bodyData.name });
|
||||
|
||||
if (findUser)
|
||||
return res.send({ code: 403, msg: `${bodyData.name}已经存在了!` });
|
||||
|
||||
let userInstance = new User();
|
||||
userInstance = { ...userInstance, ...bodyData };
|
||||
userInstance.createDate = userInstance.createDate || new Date();
|
||||
userInstance.updateDate = userInstance.updateDate || new Date();
|
||||
userInstance.pwd = "E10ADC3949BA59ABBE56E057F20F883E"; // 默认用户密码123456
|
||||
userInstance.birthday = dayjs(userInstance.birthday).format(
|
||||
"YYYY-MM-DD HH:mm:ss"
|
||||
); // 用户默认生日
|
||||
|
||||
await userRep.save(userInstance);
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "用户注册成功!",
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/update", async (req, res, next) => {
|
||||
if (!req.body.id)
|
||||
return res.send({ code: 502, msg: "未传入用户ID,请检查数据!" });
|
||||
if (!req.body.pwd) delete req.body.pwd;
|
||||
const findUser = await curd({ entity: User, req }).update();
|
||||
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "用户修改成功!",
|
||||
data: {
|
||||
userInfo: findUser,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/delete", async (req, res) => {
|
||||
const connection = getConnection();
|
||||
const userRep = connection.getRepository(User);
|
||||
const { id } = req.query;
|
||||
|
||||
const findUser = await userRep.findOne(id as string);
|
||||
|
||||
if (findUser) {
|
||||
await userRep.remove(findUser);
|
||||
return res.send({
|
||||
code: 200,
|
||||
msg: "用户删除成功!",
|
||||
});
|
||||
} else {
|
||||
return res.send({
|
||||
code: 401,
|
||||
msg: "要删除的用户不存在!",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/resetPwd", async (req, res) => {
|
||||
let userRep = getConnection().getRepository(User);
|
||||
let { id } = req.query;
|
||||
let findUser = await userRep.findOne(id as string);
|
||||
|
||||
if (findUser) {
|
||||
findUser.pwd = "E10ADC3949BA59ABBE56E057F20F883E"; // 默认用户密码123456
|
||||
await userRep.save(findUser);
|
||||
return res.send({ code: 200, msg: "用户密码重置成功!" });
|
||||
} else {
|
||||
return res.send({ code: 500, msg: "用户不存在!" });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
81
backEnd/src/util/globalMethods.ts
Normal file
81
backEnd/src/util/globalMethods.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import dayjs from "dayjs";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export function filterObjEmptyVal(obj: { [key: string]: any }) {
|
||||
if (!obj) return {};
|
||||
if (Array.isArray(obj))
|
||||
throw Error("你传入了一个数组,需要的是一个Object对象");
|
||||
|
||||
let emptyObj = {};
|
||||
|
||||
for (let [key, value] of Object.entries(obj)) {
|
||||
if (value || value === 0) emptyObj[key] = value;
|
||||
}
|
||||
return emptyObj;
|
||||
}
|
||||
|
||||
export function getNowDateStr() {
|
||||
return dayjs().format("YYYY-MM-DD HH:mm:ss");
|
||||
}
|
||||
|
||||
export function buildTree(items, parentId = 0) {
|
||||
return items
|
||||
.filter((item) => item.parentId === parentId)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
children: buildTree(items, item.id),
|
||||
}));
|
||||
}
|
||||
|
||||
export 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 function handleError(res: Response, error: any) {
|
||||
const message = error instanceof Error ? error.message : "未知错误";
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
msg: message,
|
||||
});
|
||||
}
|
||||
|
||||
/** 处理日期参数 */
|
||||
export default function parseRangDate(req: Request) {
|
||||
let { startDate: reqStart, endDate: reqEnd } =
|
||||
req.method === "GET" ? req.query : req.body;
|
||||
const dateFormat = "YYYY-MM-DD HH:mm:ss";
|
||||
|
||||
if (!reqStart && !reqEnd) return {};
|
||||
|
||||
// 验证必填参数
|
||||
if (!reqStart) reqStart = dayjs().startOf("day").toDate();
|
||||
|
||||
// 处理起始日期
|
||||
const start = dayjs(reqStart as string, dateFormat);
|
||||
if (!start.isValid()) throw new Error("起始日期格式错误");
|
||||
|
||||
// 处理结束日期
|
||||
let end = start;
|
||||
if (reqEnd) {
|
||||
end = dayjs(reqEnd as string, dateFormat);
|
||||
if (!end.isValid()) throw new Error("结束日期格式错误");
|
||||
if (end.isBefore(start)) throw new Error("结束日期不能早于起始日期");
|
||||
}
|
||||
|
||||
// 生成时间范围
|
||||
|
||||
return {
|
||||
startDate: start.format("YYYY-MM-DD HH:mm:ss"),
|
||||
endDate: (reqEnd ? end : dayjs()).format("YYYY-MM-DD HH:mm:ss"),
|
||||
};
|
||||
}
|
||||
27
backEnd/tsconfig.json
Normal file
27
backEnd/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["es5", "es6", "ES2022"],
|
||||
"paths": {
|
||||
"router/*": ["./src/router/*"],
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"baseUrl": "./",
|
||||
"declaration": true, // 是否生成.d.ts文件
|
||||
"declarationDir": "./types", // .d.ts文件输出路径
|
||||
"target": "ES5", // 编译目标
|
||||
"module": "CommonJS",
|
||||
// "strict": true,
|
||||
"moduleResolution": "Node",
|
||||
"outDir": "./build",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true, // 用于指定是否启用实验性的装饰器特性
|
||||
"sourceMap": false,
|
||||
// "resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true, // 用于允许从没有默认导出的模块中默认导入
|
||||
"esModuleInterop": true, //是否允许export=导出,import from导入
|
||||
},
|
||||
// "ts-node": {
|
||||
// "esm": true
|
||||
// },
|
||||
"include": ["src/**/*", "index.ts"]
|
||||
}
|
||||
1
backEnd/types/index.d.ts
vendored
Normal file
1
backEnd/types/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import "./src/util/dotenvConfig";
|
||||
5
backEnd/types/src/abstrClass/baseEntity.d.ts
vendored
Normal file
5
backEnd/types/src/abstrClass/baseEntity.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export declare abstract class BaseEntity {
|
||||
id: number;
|
||||
createDate: string;
|
||||
updateDate: string;
|
||||
}
|
||||
6
backEnd/types/src/entity/Role.d.ts
vendored
Normal file
6
backEnd/types/src/entity/Role.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { BaseEntity } from "../abstrClass/BaseEntity";
|
||||
export declare class Role extends BaseEntity {
|
||||
values: string;
|
||||
roleState: number;
|
||||
name: string;
|
||||
}
|
||||
10
backEnd/types/src/entity/SystemMenu.d.ts
vendored
Normal file
10
backEnd/types/src/entity/SystemMenu.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
export declare class SystemMenu {
|
||||
id: number;
|
||||
name: string;
|
||||
createDate: string;
|
||||
updateDate: string;
|
||||
path: string;
|
||||
parentId: number;
|
||||
icon: string;
|
||||
show: boolean;
|
||||
}
|
||||
18
backEnd/types/src/entity/User.d.ts
vendored
Normal file
18
backEnd/types/src/entity/User.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export declare class User {
|
||||
id: number;
|
||||
name: string;
|
||||
phone: string;
|
||||
sex: string;
|
||||
pwd: string;
|
||||
createDate: string;
|
||||
updateDate: string;
|
||||
userState: number;
|
||||
role: string;
|
||||
birthday: string;
|
||||
age: string;
|
||||
province: string;
|
||||
city: string;
|
||||
area: string;
|
||||
address: string;
|
||||
}
|
||||
export default User;
|
||||
30
backEnd/types/src/lib/curd/curd.d.ts
vendored
Normal file
30
backEnd/types/src/lib/curd/curd.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Request } from "express";
|
||||
interface CurdOptions {
|
||||
entity: any;
|
||||
req: Request;
|
||||
params: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
declare class Curd {
|
||||
private entity;
|
||||
private req;
|
||||
private queryParams;
|
||||
private repositrory;
|
||||
constructor(options: CurdOptions);
|
||||
add(): Promise<{
|
||||
code: number;
|
||||
data: any;
|
||||
}>;
|
||||
delete(): Promise<{
|
||||
code: number;
|
||||
msg: string;
|
||||
}>;
|
||||
update(): Promise<{
|
||||
code: number;
|
||||
data: any;
|
||||
}>;
|
||||
query(): Promise<unknown[]>;
|
||||
}
|
||||
export default function (options: CurdOptions): Curd;
|
||||
export {};
|
||||
6
backEnd/types/src/lib/menueToTree.d.ts
vendored
Normal file
6
backEnd/types/src/lib/menueToTree.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { SystemMenu } from "../../src/entity/SystemMenu";
|
||||
interface routerTree extends SystemMenu {
|
||||
children?: SystemMenu[];
|
||||
}
|
||||
export default function menueToTree(data: SystemMenu[]): routerTree[];
|
||||
export {};
|
||||
17
backEnd/types/src/lib/pagination/pagination.d.ts
vendored
Normal file
17
backEnd/types/src/lib/pagination/pagination.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Request } from "express";
|
||||
interface paginationType {
|
||||
list: any[];
|
||||
total: number;
|
||||
pageSize: number;
|
||||
pageNumber: number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param entite 传入实体类以供查询
|
||||
* @param req express的Request请求体
|
||||
* @returns
|
||||
*/
|
||||
export default function getPagination(entite: any, req: Request, queryParams?: {
|
||||
[key: string]: any;
|
||||
}): Promise<paginationType>;
|
||||
export {};
|
||||
2
backEnd/types/src/router/index.d.ts
vendored
Normal file
2
backEnd/types/src/router/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare let router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
2
backEnd/types/src/router/login/login.d.ts
vendored
Normal file
2
backEnd/types/src/router/login/login.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
2
backEnd/types/src/router/role/role.d.ts
vendored
Normal file
2
backEnd/types/src/router/role/role.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare let router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
2
backEnd/types/src/router/system-menue/system-menue.d.ts
vendored
Normal file
2
backEnd/types/src/router/system-menue/system-menue.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
2
backEnd/types/src/router/user/user.d.ts
vendored
Normal file
2
backEnd/types/src/router/user/user.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export default router;
|
||||
5
backEnd/types/src/util/dotenvConfig.d.ts
vendored
Normal file
5
backEnd/types/src/util/dotenvConfig.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
declare const _default: {
|
||||
development: boolean;
|
||||
production: boolean;
|
||||
};
|
||||
export default _default;
|
||||
2
backEnd/types/src/util/globalMethods.d.ts
vendored
Normal file
2
backEnd/types/src/util/globalMethods.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare function filterObjEmptyVal(obj: { [key: string]: any }): {};
|
||||
export declare function getNowDateStr(): string;
|
||||
22
backEnd/webpack.config.ts
Normal file
22
backEnd/webpack.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import path from "path";
|
||||
|
||||
module.exports = {
|
||||
entry: "./index.ts",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: "ts-loader",
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
},
|
||||
output: {
|
||||
filename: "index.js",
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
},
|
||||
target: "node",
|
||||
};
|
||||
Reference in New Issue
Block a user