From 665ba0f9ae078c2859209451a163d10515171d11 Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期四, 13 八月 2026 12:05:48 +0800
Subject: [PATCH] add 预约和回收订单

---
 src/modules/shop/controller/app/recycleorderitem.ts        |   29 +
 src/modules/basicdata/entity/sorter.ts                     |   14 
 src/modules/shop/controller/admin/recycleorderitem.ts      |   20 
 src/modules/push/controller/admin/sortergps.ts             |   36 +
 src/modules/push/entity/sorterhealth.ts                    |   40 +
 src/modules/shop/entity/recycleappointmentlog.ts           |   39 +
 src/modules/push/entity/sorterattendance.ts                |   45 ++
 src/modules/shop/controller/app/recycleorder.ts            |   25 +
 src/modules/shop/entity/recycleorder.ts                    |   56 ++
 src/modules/basicdata/controller/admin/sorter.ts           |    3 
 src/modules/shop/entity/recycleorderitem.ts                |   34 +
 src/modules/push/entity/sorteralarm.ts                     |   43 +
 src/modules/push/controller/admin/sorterhealth.ts          |   36 +
 src/modules/shop/service/recycleappointment.ts             |   14 
 src/modules/shop/controller/admin/recycleitem.ts           |   41 +
 src/modules/shop/service/recycleitem.ts                    |   15 
 src/modules/shop/controller/admin/recycleappointment.ts    |   53 ++
 src/modules/user/controller/admin/info.ts                  |   19 
 src/modules/push/service/sorteralarm.ts                    |   14 
 src/modules/shop/entity/transaction.ts                     |   42 +
 src/modules/shop/config.ts                                 |   16 
 src/modules/base/config.ts                                 |    2 
 src/modules/shop/controller/admin/recycleappointmentlog.ts |   25 +
 src/modules/shop/service/transaction.ts                    |   15 
 src/modules/shop/controller/admin/transaction.ts           |   53 ++
 src/modules/push/service/sorterhealth.ts                   |   14 
 src/modules/push/service/sorterattendance.ts               |   14 
 src/modules/shop/service/recycleappointmentlog.ts          |   14 
 src/modules/shop/service/recycleorderitem.ts               |   14 
 src/modules/basicdata/service/sorter.ts                    |   10 
 src/modules/shop/service/recycleorder.ts                   |  143 ++++++
 src/modules/push/controller/admin/sorteralarm.ts           |   36 +
 src/modules/push/entity/sortergps.ts                       |   42 +
 src/modules/shop/entity/recycleitem.ts                     |   48 ++
 src/modules/push/service/sortergps.ts                      |   14 
 src/modules/user/service/info.ts                           |   24 
 src/modules/shop/controller/admin/recycleorder.ts          |   57 ++
 src/modules/shop/entity/recycleappointment.ts              |   66 +++
 src/modules/push/controller/admin/sorterattendance.ts      |   36 +
 src/modules/user/entity/info.ts                            |   43 +
 40 files changed, 1,288 insertions(+), 16 deletions(-)

diff --git a/src/modules/base/config.ts b/src/modules/base/config.ts
index 4819103..0218350 100644
--- a/src/modules/base/config.ts
+++ b/src/modules/base/config.ts
@@ -31,7 +31,7 @@
       // token
       token: {
         // 2灏忔椂杩囨湡锛岄渶瑕佺敤鍒锋柊token
-        expire: 2 * 3600,
+        expire: 7 * 24 * 3600,
         // 15澶╁唴锛屽鏋滄病鎿嶄綔杩囧氨闇�瑕侀噸鏂扮櫥褰�
         refreshExpire: 24 * 3600 * 15,
       },
diff --git a/src/modules/basicdata/controller/admin/sorter.ts b/src/modules/basicdata/controller/admin/sorter.ts
index f828211..12859fb 100644
--- a/src/modules/basicdata/controller/admin/sorter.ts
+++ b/src/modules/basicdata/controller/admin/sorter.ts
@@ -39,10 +39,7 @@
     where: async ctx => {
       const conditions: any[][] = [];
       conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
-
-      // 鍏朵粬鍏宠仈琛紙涓句緥锛�
       // conditions.push(...(await deptFilterWhere(ctx, 'd', 'id')));
-
       return conditions;
     },
   },
diff --git a/src/modules/basicdata/entity/sorter.ts b/src/modules/basicdata/entity/sorter.ts
index 74636e2..5f27442 100644
--- a/src/modules/basicdata/entity/sorter.ts
+++ b/src/modules/basicdata/entity/sorter.ts
@@ -13,12 +13,24 @@
   @Column({ comment: '濮撳悕', length: 64 })
   businessName: string;
 
-  @Column({ comment: '鎵嬫満鍙�', length: 32, nullable: true })
+  @Column({ comment: '鎵嬫満鍙�', length: 32 })
   phone: string;
+
+  @Column({ comment: '瀵嗙爜', length: 32, nullable: true })
+  password: string;
+
+  @Column({ comment: '鎬у埆', dict: ['鏈煡', '鐢�', '濂�'], default: '鐢�' })
+  sex: string;
+
+  @Column({ comment: '鐢熸棩', type: 'date', nullable: true })
+  birthday: Date;
 
   @Column({ comment: '鍏ヨ亴鏃ユ湡', type: 'date', nullable: true })
   hireDate: Date;
 
+  @Column({ comment: '绂昏亴鏃ユ湡', type: 'date', nullable: true })
+  leaveDate: Date;
+
   @Column({ comment: '鐘舵��', dict: ['鍦ㄨ亴', '绂昏亴', '绂佺敤'], default: 0 })
   status: number;
 
diff --git a/src/modules/basicdata/service/sorter.ts b/src/modules/basicdata/service/sorter.ts
index c929530..18d0a12 100644
--- a/src/modules/basicdata/service/sorter.ts
+++ b/src/modules/basicdata/service/sorter.ts
@@ -3,6 +3,7 @@
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Repository } from 'typeorm';
 import { BasicdataSorterEntity } from '../entity/sorter';
+import * as md5 from 'md5';
 
 /**
  * 鍒嗘嫞浜哄憳鏈嶅姟
@@ -11,4 +12,13 @@
 export class BasicdataSorterService extends BaseService {
   @InjectEntityModel(BasicdataSorterEntity)
   basicdataSorterEntity: Repository<BasicdataSorterEntity>;
+
+   /**
+     * 淇敼涔嬪墠澶勭悊瀵嗙爜鍔犲瘑
+     */
+    async modifyBefore(data: any, type: 'delete' | 'update' | 'add') {
+      if ((type === 'add' || type === 'update') && data.password) {
+        data.password = md5(data.password);
+      }
+    }
 }
diff --git a/src/modules/push/controller/admin/sorteralarm.ts b/src/modules/push/controller/admin/sorteralarm.ts
new file mode 100644
index 0000000..c658a7a
--- /dev/null
+++ b/src/modules/push/controller/admin/sorteralarm.ts
@@ -0,0 +1,36 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { PushSorterAlarmEntity } from '../../entity/sorteralarm';
+import { PushSorterAlarmService } from '../../service/sorteralarm';
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department'
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 鍒嗘嫞鍛樿建杩圭鐞�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: PushSorterAlarmEntity,
+  service: PushSorterAlarmService,
+  pageQueryOp: {
+    select: ['a.*', 'b.name as departmentName'],
+    join: [
+      {
+        entity: BaseSysDepartmentEntity,
+        alias: 'b',
+        condition: 'a.departmentId = b.id',
+        type: 'leftJoin',
+      },
+    ],
+    fieldEq: ['a.sorterId', 'a.departmentId'],
+    where: async ctx => {
+      const { startTime, endTime } = ctx.request.body;
+      const conditions:any[][] = [];
+      if (startTime && endTime) {
+        conditions.push(['a.uploadTime BETWEEN :startTime AND :endTime', { startTime, endTime }]);
+      }
+      conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+      return conditions;
+    },
+  },
+})
+export class PushSorterAlarmController extends BaseController {}
\ No newline at end of file
diff --git a/src/modules/push/controller/admin/sorterattendance.ts b/src/modules/push/controller/admin/sorterattendance.ts
new file mode 100644
index 0000000..c39ff3d
--- /dev/null
+++ b/src/modules/push/controller/admin/sorterattendance.ts
@@ -0,0 +1,36 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { PushSorterAttendanceEntity } from '../../entity/sorterattendance';
+import { PushSorterAttendanceService } from '../../service/sorterattendance';
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department'
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 鍒嗘嫞鍛樿建杩圭鐞�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: PushSorterAttendanceEntity,
+  service: PushSorterAttendanceService,
+  pageQueryOp: {
+    select: ['a.*', 'b.name as departmentName'],
+    join: [
+      {
+        entity: BaseSysDepartmentEntity,
+        alias: 'b',
+        condition: 'a.departmentId = b.id',
+        type: 'leftJoin',
+      },
+    ],
+    fieldEq: ['a.sorterId', 'a.departmentId'],
+    where: async ctx => {
+      const { startTime, endTime } = ctx.request.body;
+      const conditions:any[][] = [];
+      if (startTime && endTime) {
+        conditions.push(['a.uploadTime BETWEEN :startTime AND :endTime', { startTime, endTime }]);
+      }
+      conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+      return conditions;
+    },
+  },
+})
+export class PushSorterAttendanceController extends BaseController {}
\ No newline at end of file
diff --git a/src/modules/push/controller/admin/sortergps.ts b/src/modules/push/controller/admin/sortergps.ts
new file mode 100644
index 0000000..55ed4e1
--- /dev/null
+++ b/src/modules/push/controller/admin/sortergps.ts
@@ -0,0 +1,36 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { PushSorterGpsEntity } from '../../entity/sortergps';
+import { PushSorterGpsService } from '../../service/sortergps';
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department'
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 鍒嗘嫞鍛樿建杩圭鐞�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: PushSorterGpsEntity,
+  service: PushSorterGpsService,
+  pageQueryOp: {
+    select: ['a.*', 'b.name as departmentName'],
+    join: [
+      {
+        entity: BaseSysDepartmentEntity,
+        alias: 'b',
+        condition: 'a.departmentId = b.id',
+        type: 'leftJoin',
+      },
+    ],
+    fieldEq: ['a.sorterId', 'a.departmentId'],
+    where: async ctx => {
+      const { startTime, endTime } = ctx.request.body;
+      const conditions:any[][] = [];
+      if (startTime && endTime) {
+        conditions.push(['a.uploadTime BETWEEN :startTime AND :endTime', { startTime, endTime }]);
+      }
+      conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+      return conditions;
+    },
+  },
+})
+export class PushSorterGpsController extends BaseController {}
\ No newline at end of file
diff --git a/src/modules/push/controller/admin/sorterhealth.ts b/src/modules/push/controller/admin/sorterhealth.ts
new file mode 100644
index 0000000..056d14c
--- /dev/null
+++ b/src/modules/push/controller/admin/sorterhealth.ts
@@ -0,0 +1,36 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { PushSorterHealthEntity } from '../../entity/sorterhealth';
+import { PushSorterHealthService } from '../../service/sorterhealth';
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department'
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 鍒嗘嫞鍛樿建杩圭鐞�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: PushSorterHealthEntity,
+  service: PushSorterHealthService,
+  pageQueryOp: {
+    select: ['a.*', 'b.name as departmentName'],
+    join: [
+      {
+        entity: BaseSysDepartmentEntity,
+        alias: 'b',
+        condition: 'a.departmentId = b.id',
+        type: 'leftJoin',
+      },
+    ],
+    fieldEq: ['a.sorterId', 'a.departmentId'],
+    where: async ctx => {
+      const { startTime, endTime } = ctx.request.body;
+      const conditions:any[][] = [];
+      if (startTime && endTime) {
+        conditions.push(['a.uploadTime BETWEEN :startTime AND :endTime', { startTime, endTime }]);
+      }
+      conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+      return conditions;
+    },
+  },
+})
+export class PushSorterHealthController extends BaseController {}
\ No newline at end of file
diff --git a/src/modules/push/entity/sorteralarm.ts b/src/modules/push/entity/sorteralarm.ts
new file mode 100644
index 0000000..cf3e78a
--- /dev/null
+++ b/src/modules/push/entity/sorteralarm.ts
@@ -0,0 +1,43 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍒嗘嫞鍛樺仴搴峰憡璀︿俊鎭�
+ */
+@Entity('t_push_sorter_alarm')
+export class PushSorterAlarmEntity extends BaseEntity {
+    @Index()
+    @Column({ comment: '韬唤璇佸彿', length: 18 })
+    idCard: string;
+
+    @Column({ comment: '鎵�灞炲崟浣�' })
+    departmentId: number;
+
+    departmentName: string;
+
+    @Index()
+    @Column({ comment: '鏁版嵁鏃堕棿' })
+    uploadTime: Date;
+
+
+    @Column({ comment: '鎶ヨ绫诲瀷' })
+    alarmType: string;
+
+    @Column({ comment: '鎶ヨ鍐呭', type: 'text', nullable: true })
+    content: string;
+
+    @Column({ comment: '鎶ヨ绾у埆', dict: ['涓�鑸�', '涓瓑', '涓ラ噸'], default: '涓�鑸�' })
+    alarmLevel: string;
+
+    @Column({ comment: '澶勭悊鐘舵��', dict: ['鏈鐞�', '宸插鐞�'], default: 0 })
+    status: number;
+
+
+    @Column({ comment: '澶勭悊浜篒D', nullable: true })
+    handleUser: number;
+
+    @Column({ comment: '澶勭悊鏃堕棿', nullable: true })
+    handleTime: Date;
+
+
+}
\ No newline at end of file
diff --git a/src/modules/push/entity/sorterattendance.ts b/src/modules/push/entity/sorterattendance.ts
new file mode 100644
index 0000000..27faaed
--- /dev/null
+++ b/src/modules/push/entity/sorterattendance.ts
@@ -0,0 +1,45 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍒嗘嫞鍛樼鍒帮紝绛鹃��淇℃伅
+ */
+@Entity('t_push_sorter_attendance')
+export class PushSorterAttendanceEntity extends BaseEntity {
+    @Index()
+    @Column({ comment: '韬唤璇佸彿', length: 18 })
+    idCard: string;
+
+    @Column({ comment: '鎵�灞炲崟浣�' })
+    departmentId: number;
+
+    departmentName: string;
+
+    @Index()
+    @Column({ comment: '鏁版嵁鏃堕棿' })
+    uploadTime: Date;
+
+    @Index()
+    @Column({ comment: '宸ヤ綔鏃ユ湡', type: 'date' })
+    workDate: Date;
+
+    @Column({ comment: '绛惧埌鏃堕棿', nullable: true })
+    checkInTime: Date;
+
+    @Column({ comment: '绛鹃��鏃堕棿', nullable: true })
+    checkOutTime: Date;
+
+    @Column({ comment: '绛惧埌鍦扮偣', nullable: true })  // lon,lat
+    checkInLocation: string;
+
+    @Column({ comment: '绛鹃��鍦扮偣', nullable: true }) // lon,lat
+    checkOutLocation: string;
+
+    @Column({ comment: '宸ヤ綔鏃堕暱', type: 'decimal', precision: 4, scale: 2, default: 0.00 })
+    workHours: number;
+
+    @Column({ comment: '鑰冨嫟鐘舵��', dict: ['姝e父', '杩熷埌', '鏃╅��', '缂哄崱', '鏃峰伐'], default: '缂哄崱' })
+    status: string;
+
+
+}
\ No newline at end of file
diff --git a/src/modules/push/entity/sortergps.ts b/src/modules/push/entity/sortergps.ts
new file mode 100644
index 0000000..e0e49aa
--- /dev/null
+++ b/src/modules/push/entity/sortergps.ts
@@ -0,0 +1,42 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍒嗘嫞鍛樿建杩逛俊鎭�
+ */
+@Entity('t_push_sorter_gps')
+export class PushSorterGpsEntity extends BaseEntity {
+    @Index()
+    @Column({ comment: '韬唤璇佸彿', length: 18 })
+    idCard: string;
+
+    @Column({ comment: '濮撳悕', length: 18 })
+    name: string;
+
+
+    @Column({ comment: '鎵�灞炲崟浣�' })
+    departmentId: number;
+
+    departmentName: string;
+
+    @Index()
+    @Column({ comment: '鏁版嵁鏃堕棿' })
+    uploadTime: Date;
+
+    @Column({ comment: '缁忓害', type: 'decimal', precision: 10, scale: 7 })
+    longitude: number;
+    
+    @Column({ comment: '绾害', type: 'decimal', precision: 10, scale: 7 })
+    latitude: number;
+
+    @Column({ comment: '楂樼▼', type: 'decimal', precision: 10, scale: 7 })
+    height: number;
+
+    @Column({ comment: '閫熷害', type: 'decimal', precision: 5, scale: 2 })
+    speed: number;
+
+    @Column({ comment: '绮惧害', type: 'decimal', precision: 5, scale: 2 })
+    accuracy: number;
+
+
+}
\ No newline at end of file
diff --git a/src/modules/push/entity/sorterhealth.ts b/src/modules/push/entity/sorterhealth.ts
new file mode 100644
index 0000000..c09edd6
--- /dev/null
+++ b/src/modules/push/entity/sorterhealth.ts
@@ -0,0 +1,40 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍒嗘嫞鍛樺仴搴风洃娴嬩俊鎭�
+ */
+@Entity('t_push_sorter_health')
+export class PushSorterHealthEntity extends BaseEntity {
+    @Index()
+    @Column({ comment: '韬唤璇佸彿', length: 18 })
+    idCard: string;
+
+    @Column({ comment: '鎵�灞炲崟浣�' })
+    departmentId: number;
+
+    departmentName: string;
+
+    @Index()
+    @Column({ comment: '鏁版嵁鏃堕棿' })
+    uploadTime: Date;
+
+    @Column({ comment: '浣撴俯', type: 'decimal', precision: 3, scale: 1 })
+    temperature: number;
+
+    @Column({ comment: '蹇冪巼' })
+    heartRate: number;
+
+    @Column({ comment: '鏀剁缉鍘�' })
+    bloodPressureHigh: number;
+
+    @Column({ comment: '鑸掑紶鍘�' })
+    bloodPressureLow: number;
+
+    @Column({ comment: '琛�姘чケ鍜屽害', type: 'decimal', precision: 4, scale: 1 })
+    bloodOxygen: number;
+    
+    // add more if needed
+
+
+}
\ No newline at end of file
diff --git a/src/modules/push/service/sorteralarm.ts b/src/modules/push/service/sorteralarm.ts
new file mode 100644
index 0000000..a3923e7
--- /dev/null
+++ b/src/modules/push/service/sorteralarm.ts
@@ -0,0 +1,14 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { PushSorterAlarmEntity } from '../entity/sorteralarm';
+
+/**
+ * 鍒嗘嫞鍛樺仴搴峰憡璀︽湇鍔�
+ */
+@Provide()
+export class PushSorterAlarmService extends BaseService {
+  @InjectEntityModel(PushSorterAlarmEntity)
+  pushSorterAlarmEntity: Repository<PushSorterAlarmEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/push/service/sorterattendance.ts b/src/modules/push/service/sorterattendance.ts
new file mode 100644
index 0000000..1546c35
--- /dev/null
+++ b/src/modules/push/service/sorterattendance.ts
@@ -0,0 +1,14 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { PushSorterAttendanceEntity } from '../entity/sorterattendance';
+
+/**
+ * 鍒嗘嫞鍛樺仴搴峰憡璀︽湇鍔�
+ */
+@Provide()
+export class PushSorterAttendanceService extends BaseService {
+  @InjectEntityModel(PushSorterAttendanceEntity)
+  pushSorterAttendanceEntity: Repository<PushSorterAttendanceEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/push/service/sortergps.ts b/src/modules/push/service/sortergps.ts
new file mode 100644
index 0000000..134fe0a
--- /dev/null
+++ b/src/modules/push/service/sortergps.ts
@@ -0,0 +1,14 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { PushSorterGpsEntity } from '../entity/sortergps';
+
+/**
+ * 鍒嗘嫞鍛樿建杩规湇鍔�
+ */
+@Provide()
+export class PushSorterGpsService extends BaseService {
+  @InjectEntityModel(PushSorterGpsEntity)
+  pushSorterGpsEntity: Repository<PushSorterGpsEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/push/service/sorterhealth.ts b/src/modules/push/service/sorterhealth.ts
new file mode 100644
index 0000000..1603a6b
--- /dev/null
+++ b/src/modules/push/service/sorterhealth.ts
@@ -0,0 +1,14 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { PushSorterHealthEntity } from '../entity/sorterhealth';
+
+/**
+ * 鍒嗘嫞鍛樺仴搴风洃娴嬫湇鍔�
+ */
+@Provide()
+export class PushSorterHealthService extends BaseService {
+  @InjectEntityModel(PushSorterHealthEntity)
+  pushSorterHealthEntity: Repository<PushSorterHealthEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/shop/config.ts b/src/modules/shop/config.ts
new file mode 100644
index 0000000..64f6171
--- /dev/null
+++ b/src/modules/shop/config.ts
@@ -0,0 +1,16 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 鍟嗗煄妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    name: '鍟嗗煄妯″潡',
+    description: 'user绠$悊锛屽瀮鍦剧绫伙紝鍙洖鏀剁墿锛岄绾﹁鍗曪紝鍟嗗煄鍟嗗搧锛岃皥绉垎璐︽埛',
+    middlewares: [],
+    globalMiddlewares: [],
+    router: {
+      admin: ['/saveWithSummary'],
+    },
+  } as ModuleConfig;
+};
diff --git a/src/modules/shop/controller/admin/recycleappointment.ts b/src/modules/shop/controller/admin/recycleappointment.ts
new file mode 100644
index 0000000..09a6623
--- /dev/null
+++ b/src/modules/shop/controller/admin/recycleappointment.ts
@@ -0,0 +1,53 @@
+import { Inject } from "@midwayjs/core";
+import { CoolController, BaseController } from "@cool-midway/core";
+import { RecycleAppointmentEntity } from "../../entity/recycleappointment";
+import { RecycleAppointmentService } from "../../service/recycleappointment";
+import { BaseSysDepartmentEntity } from "../../../base/entity/sys/department";
+import { BasicdataSorterEntity } from "../../../basicdata/entity/sorter";
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+
+/**
+ * 棰勭害绠$悊
+ */
+@CoolController({
+    api: ["add", "delete", "update", "info", "list", "page"],
+    entity: RecycleAppointmentEntity,
+    service: RecycleAppointmentService,
+    pageQueryOp: {
+        keyWordLikeFields: ["a.appointmentNo", "a.contactName", "a.contactPhone"],
+        fieldEq: ["a.status", "a.departmentId", "a.sorterId"],
+        select: [
+            "a.*",
+            "b.name AS departmentName",
+            "c.businessName AS sorterName"
+        ],
+        join: [
+            {
+                entity: BaseSysDepartmentEntity,
+                alias: "b",
+                condition: "a.departmentId = b.id",
+                type: "leftJoin"
+            },
+            {
+                entity: BasicdataSorterEntity,
+                alias: "c",
+                condition: "a.sorterId = c.businessId",
+                type: "leftJoin"
+            }
+        ],
+        where: async (ctx) => {
+            const { startDate, endDate } = ctx.request.body;
+            const conditions: any[][] = [];
+            if (startDate && endDate) {
+                conditions.push(["a.appointmentDate BETWEEN :startDate AND :endDate", { startDate, endDate }]);
+            }
+            conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+            return conditions;
+        }
+    }
+})
+export class AdminRecycleAppointmentController extends BaseController {
+    @Inject()
+    recycleAppointmentService: RecycleAppointmentService;
+}
\ No newline at end of file
diff --git a/src/modules/shop/controller/admin/recycleappointmentlog.ts b/src/modules/shop/controller/admin/recycleappointmentlog.ts
new file mode 100644
index 0000000..ddcdf4d
--- /dev/null
+++ b/src/modules/shop/controller/admin/recycleappointmentlog.ts
@@ -0,0 +1,25 @@
+import { Inject } from '@midwayjs/core';
+import { CoolController, BaseController } from '@cool-midway/core';
+import { RecycleAppointmentLogEntity } from '../../entity/recycleappointmentlog';
+import { RecycleAppointmentLogService } from '../../service/recycleappointmentlog';
+
+/**
+ * 鍥炴敹鐗╁搧棰勭害淇℃伅璇︾粏鏃ュ織鎺у埗鍣�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: RecycleAppointmentLogEntity,
+  service: RecycleAppointmentLogService,
+  pageQueryOp: {
+    fieldEq: [
+      'a.appointmentId',
+      'a.action',
+      'a.operatorType',
+      'a.operatorId',
+    ],
+  },
+})
+export class AdminRecycleAppointmentLogController extends BaseController {
+  @Inject()
+  recycleAppointmentLogService: RecycleAppointmentLogService;
+}
\ No newline at end of file
diff --git a/src/modules/shop/controller/admin/recycleitem.ts b/src/modules/shop/controller/admin/recycleitem.ts
new file mode 100644
index 0000000..566f798
--- /dev/null
+++ b/src/modules/shop/controller/admin/recycleitem.ts
@@ -0,0 +1,41 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { Inject } from '@midwayjs/core';
+import { RecycleItemEntity } from '../../entity/recycleitem';
+import { RecycleItemService } from '../../service/recycleitem';
+import { BaseSysDepartmentEntity } from "../../../base/entity/sys/department";
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 鍥炴敹鐗╁搧
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: RecycleItemEntity,
+  service: RecycleItemService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.name'],
+    fieldEq: ['a.itemId', 'a.category', 'a.status'],
+    select: [
+      "a.*",
+      "b.name AS departmentName"
+    ],
+    join: [
+      {
+        entity: BaseSysDepartmentEntity,
+        alias: "b",
+        condition: "a.departmentId = b.id",
+        type: "leftJoin"
+      }
+
+    ],
+    where: async (ctx) => {
+      const conditions: any[][] = [];
+      conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+      return conditions;
+    }
+  },
+})
+export class RecycleItemController extends BaseController {
+  @Inject()
+  recycleItemService: RecycleItemService;
+}
\ No newline at end of file
diff --git a/src/modules/shop/controller/admin/recycleorder.ts b/src/modules/shop/controller/admin/recycleorder.ts
new file mode 100644
index 0000000..44f5dba
--- /dev/null
+++ b/src/modules/shop/controller/admin/recycleorder.ts
@@ -0,0 +1,57 @@
+import { Inject,Body,Post } from "@midwayjs/core";
+
+import { CoolController, BaseController } from "@cool-midway/core";
+import { RecycleOrderEntity } from "../../entity/recycleorder";
+import { RecycleOrderService } from "../../service/recycleorder";
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department';
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 鍥炴敹璁㈠崟鍚庡彴绠$悊
+ */
+@CoolController({
+    api: ["add", "delete", "update", "info", "list", "page"],
+    entity: RecycleOrderEntity,
+    service: RecycleOrderService,
+    pageQueryOp: {
+        keyWordLikeFields: ["a.orderNo"],
+        fieldEq: ["a.orderType", "a.status"],
+        select: ["a.*", "c.name AS departmentName"],
+        join: [
+            {
+                entity: BaseSysDepartmentEntity,
+                alias: "c",
+                condition: 'a.departmentId = c.id',
+                type: "leftJoin"
+            }
+        ],
+        where: async (ctx) => {
+            const { startTime, endTime } = ctx.request.body;
+            const conditions: any[][] = [];
+            if (startTime && endTime) {
+                conditions.push(["a.finishTime BETWEEN :startTime AND :endTime", { startTime, endTime }]);
+            }
+            conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+            return conditions;
+        },
+        addOrderBy: {
+            createTime: 'desc',
+        },
+    }
+})
+export class AdminRecycleOrderController extends BaseController {
+    @Inject()
+    recycleOrderService: RecycleOrderService;
+
+    @Post("/saveWithSummary")
+    async saveWithSummary(
+        @Body()
+        body: {
+            orderNo: string;
+            items: any[];
+        }
+    ) {
+        await this.recycleOrderService.saveWithSummary(body.orderNo, body.items);
+        return this.ok();
+    }
+}
\ No newline at end of file
diff --git a/src/modules/shop/controller/admin/recycleorderitem.ts b/src/modules/shop/controller/admin/recycleorderitem.ts
new file mode 100644
index 0000000..237facb
--- /dev/null
+++ b/src/modules/shop/controller/admin/recycleorderitem.ts
@@ -0,0 +1,20 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { RecycleOrderItemEntity } from '../../entity/recycleorderitem';
+import { RecycleOrderItemService } from '../../service/recycleorderitem';
+
+/**
+ * 璁㈠崟璇︽儏绠$悊
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: RecycleOrderItemEntity,
+  service: RecycleOrderItemService,
+  pageQueryOp: {
+    fieldEq: ['a.orderNo', 'a.itemId', 'a.categoryId'],
+    fieldLike: ['a.itemName'],  
+  },
+  listQueryOp: {
+    fieldEq: ['a.orderNo', 'a.itemId', 'a.categoryId'],
+  },
+})
+export class AdminRecycleOrderItemController extends BaseController {}
\ No newline at end of file
diff --git a/src/modules/shop/controller/admin/transaction.ts b/src/modules/shop/controller/admin/transaction.ts
new file mode 100644
index 0000000..f0481d9
--- /dev/null
+++ b/src/modules/shop/controller/admin/transaction.ts
@@ -0,0 +1,53 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { RecycleTransactionEntity } from '../../entity/transaction';
+import { RecycleTransactionService } from '../../service/transaction';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department';
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
+
+/**
+ * 娴佹按璁板綍绠$悊
+ */
+@CoolController({
+    api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+    entity: RecycleTransactionEntity,
+    service: RecycleTransactionService,
+    pageQueryOp: {
+        select: ['a.*', 'b.userName as userName', 'c.name as departmentName'],
+        keyWordLikeFields: ['a.remark'],
+        fieldEq: [
+            { column: 'a.userId', requestParam: 'userId' },
+            { column: 'a.orderId', requestParam: 'orderId' },
+            { column: 'a.departmentId', requestParam: 'departmentId' },
+            { column: 'a.type', requestParam: 'type' },
+            { column: 'a.sourceType', requestParam: 'sourceType' }
+        ],
+        join: [
+            {
+                entity: UserInfoEntity,
+                alias: 'b',
+                condition: 'a.userId = b.unionid',
+                type: 'leftJoin'
+            },
+            {
+                entity: BaseSysDepartmentEntity,
+                alias: 'c',
+                condition: 'a.departmentId = c.id',
+                type: 'leftJoin'
+            }
+        ],
+        where: async (ctx) => {
+            const { startTime, endTime } = ctx.request.body;
+            const conditions: any[][] = [];
+            if (startTime && endTime) {
+                conditions.push(['a.createTime BETWEEN :startTime AND :endTime', { startTime, endTime }]);
+            }
+            conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+            return conditions;
+        },
+        addOrderBy: {
+            createTime: 'desc'
+        }
+    }
+})
+export class AdminFinanceTransactionController extends BaseController { }
\ No newline at end of file
diff --git a/src/modules/shop/controller/app/recycleorder.ts b/src/modules/shop/controller/app/recycleorder.ts
new file mode 100644
index 0000000..9761a25
--- /dev/null
+++ b/src/modules/shop/controller/app/recycleorder.ts
@@ -0,0 +1,25 @@
+import { Inject } from "@midwayjs/core";
+import { CoolController, BaseController } from "@cool-midway/core";
+import { RecycleOrderEntity } from "../../entity/recycleorder";
+import { RecycleOrderService } from "../../service/recycleorder";
+
+/**
+ * 鍥炴敹璁㈠崟App瀹㈡埛绔�
+ */
+@CoolController({
+  api: ["add", "info", "page"],
+  entity: RecycleOrderEntity,
+  service: RecycleOrderService,
+  pageQueryOp: {
+    fieldEq: ["a.status"],
+    where: async (ctx) => {
+      return [
+        ["a.campusUserId = :userId", { userId: ctx.user.id }]
+      ];
+    }
+  }
+})
+export class AppRecycleOrderController extends BaseController {
+  @Inject()
+  recycleOrderService: RecycleOrderService;
+}
\ No newline at end of file
diff --git a/src/modules/shop/controller/app/recycleorderitem.ts b/src/modules/shop/controller/app/recycleorderitem.ts
new file mode 100644
index 0000000..b1a5fd9
--- /dev/null
+++ b/src/modules/shop/controller/app/recycleorderitem.ts
@@ -0,0 +1,29 @@
+import { Inject } from "@midwayjs/core";
+import { CoolController, BaseController } from "@cool-midway/core";
+import { RecycleOrderItemEntity } from "../../entity/recycleorderitem";
+import { RecycleOrderItemService } from "../../service/recycleorderitem";
+import { RecycleItemEntity } from "../../entity/recycleitem";
+
+/**
+ * 鍥炴敹璁㈠崟鏉$洰-搴旂敤绔�
+ */
+@CoolController({
+  api: ["info", "page"],
+  entity: RecycleOrderItemEntity,
+  service: RecycleOrderItemService,
+  pageQueryOp: {
+    select: ["a.*", "b.mainPic"],
+    fieldEq: ["a.orderId"],
+    join: [
+      {
+        entity: RecycleItemEntity,
+        alias: "b",
+        condition: "a.itemId = b.id",
+      },
+    ],
+  },
+})
+export class AppRecycleOrderitemController extends BaseController {
+  @Inject()
+  recycleOrderItemService: RecycleOrderItemService;
+}
\ No newline at end of file
diff --git a/src/modules/shop/entity/recycleappointment.ts b/src/modules/shop/entity/recycleappointment.ts
new file mode 100644
index 0000000..62c5de5
--- /dev/null
+++ b/src/modules/shop/entity/recycleappointment.ts
@@ -0,0 +1,66 @@
+import { StringLiteralType } from 'typescript';
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from "typeorm";
+
+/**
+ * 鍥炴敹鐗╁搧棰勭害淇℃伅
+ */
+@Entity("t_recycle_appointment")
+export class RecycleAppointmentEntity extends BaseEntity {
+    @Index({ unique: true })
+    @Column({ comment: "棰勭害缂栧彿" })
+    appointmentNo: string;
+
+    @Index()
+    @Column({ comment: '瀛︽牎ID', nullable: true })   // 浣跨敤褰掑睘閮ㄩ棬锛岃繖閲屽缓璁�夐《灞傚鏍�
+    departmentId: number;
+
+    departmentName: string;
+
+    @Index()
+    @Column({ comment: "鐢ㄦ埛ID" })
+    campusUserId: string;
+
+    campusUserName: string;
+
+    @Column({ comment: "鑱旂郴浜�" })
+    contactName: string;
+
+    @Column({ comment: "鑱旂郴鐢佃瘽" })
+    contactPhone: string;
+
+    @Column({ comment: "璇︾粏鍦板潃" })
+    address: string;
+
+
+    @Column({ comment: "缁忓害", nullable: true })
+    longitude: number;
+
+
+    @Column({ comment: "绾害",nullable: true })
+    latitude: number;
+
+    @Column({ comment:"棰勭害鏃ユ湡"})
+    appointmentDate:string;
+
+     @Column({comment:"棰勭害鏃堕棿娈�", default:"鍌嶆櫄 18:00-20:00"})
+    appointmentSlot:string;
+
+
+    @Column({ comment:"棰勮閲嶉噺",default: 0 })
+    expectedWeight:number;
+
+    @Column({ comment: "鐘舵��", dict: ['寰呭鏍�', '寰呮帴鍗�', '宸叉帴鍗�', '涓婇棬涓�', '宸插畬鎴�','宸插彇娑�', '鏈煡'], default: '鏈煡' })
+    status: string;
+    
+    @Index()
+    @Column({ comment: "鍒嗘嫞鍛業D", nullable: true, default: 0 })
+    sorterId: string;
+
+    sorterName: string;
+
+    @Column({ comment:"鍥炴敹璁㈠崟ID", nullable:true})
+    recycleOrderId:string;
+
+
+}
\ No newline at end of file
diff --git a/src/modules/shop/entity/recycleappointmentlog.ts b/src/modules/shop/entity/recycleappointmentlog.ts
new file mode 100644
index 0000000..1c544a1
--- /dev/null
+++ b/src/modules/shop/entity/recycleappointmentlog.ts
@@ -0,0 +1,39 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from "typeorm";
+
+/**
+ * 鍥炴敹鐗╁搧棰勭害淇℃伅-璇︾粏log
+ */
+@Entity("t_recycle_appointment_log")
+export class RecycleAppointmentLogEntity extends BaseEntity {
+    @Index()
+    @Column({ comment: "棰勭害ID" })
+    appointmentId: number;
+
+    @Column({
+        comment: "鎿嶄綔绫诲瀷",
+        dict: [
+            "鍒涘缓棰勭害",
+            "瀹℃牳閫氳繃",
+            "鍒嗛厤浜哄憳",
+            "鎺ュ崟",
+            "鍒拌揪",
+            "寮�濮嬪洖鏀�",
+            "瀹屾垚",
+            "鍙栨秷",
+            "鏀规湡"
+        ]
+    })
+    action: string;
+
+    @Column({ comment: "鎿嶄綔浜虹被鍨�" })   // 鐢ㄦ埛/鍒嗘嫞鍛�/绠$悊鍛�
+    operatorType: string;
+
+    @Column({ comment: "鎿嶄綔浜篒D" })
+    operatorId: number;
+
+    @Column({ comment: "鎻忚堪" })
+    remark: string;
+
+
+}
\ No newline at end of file
diff --git a/src/modules/shop/entity/recycleitem.ts b/src/modules/shop/entity/recycleitem.ts
new file mode 100644
index 0000000..a9a9be1
--- /dev/null
+++ b/src/modules/shop/entity/recycleitem.ts
@@ -0,0 +1,48 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍥炴敹鐗╁搧淇℃伅
+ */
+@Entity('t_recycle_item')
+export class RecycleItemEntity extends BaseEntity {
+
+  @Index()
+  @Column({ comment: '鎵�灞炲崟浣�' })
+  departmentId: string;
+
+  departmentName: string;
+
+  @Column({ comment: '鍒嗙被ID' })
+  itemId: string;
+
+  @Index()
+  @Column({ comment: '鍚嶇О' })
+  itemName: string;
+
+  @Index()
+  @Column({ comment: '鍖呭惈鍝佺被' })
+  including: string;
+
+  @Column({ comment: '鍗曚綅' })
+  unit: string;
+
+  @Column({
+    comment: '浠锋牸',
+    type: 'decimal',
+    precision: 10,
+    scale: 2,
+  })
+  price: number;
+
+  @Column({ comment: '纰崇Н鍒�' })
+  carbonPoint: number;
+
+  @Index()
+  @Column({ comment: '搴熷搧绫诲埆缂栫爜' })
+  category: string;
+
+  @Column({ comment: '鐘舵��', dict: ['鍚敤', '绂佺敤'], default: 0 })
+  status: number;
+  
+}
\ No newline at end of file
diff --git a/src/modules/shop/entity/recycleorder.ts b/src/modules/shop/entity/recycleorder.ts
new file mode 100644
index 0000000..6abfb50
--- /dev/null
+++ b/src/modules/shop/entity/recycleorder.ts
@@ -0,0 +1,56 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from "typeorm";
+
+/**
+ * 鍥炴敹鐗╁搧璁㈠崟
+ */
+@Entity("t_recycle_order")
+export class RecycleOrderEntity extends BaseEntity {
+    @Index({ unique: true })
+    @Column({ comment: "璁㈠崟缂栧彿" })
+    orderNo: string;
+
+    @Column({ comment: "璁㈠崟绫诲瀷", dict: ['鐜板満', '棰勭害', '澶у睆', '娲诲姩'], default: '鐜板満' })
+    orderType: string;
+
+    @Index()
+    @Column({ comment: "鐢ㄦ埛ID" })
+    campusUserId: string;
+
+    campusUserName: string;
+
+    @Index()
+    @Column({ comment: '瀛︽牎ID', nullable: true })   // 浣跨敤褰掑睘閮ㄩ棬锛岃繖閲屽缓璁�夐《灞傚鏍�
+    departmentId: number;
+
+    departmentName: string;
+
+    @Index()
+    @Column({ comment: "绔欑偣ID", nullable: true})
+    siteId: string;
+
+    @Index()
+    @Column({ comment: "鍒嗘嫞鍛業D", nullable: true, default: 0 })
+    sorterId: string;
+
+    @Index()
+    @Column({ comment: "棰勭害ID", nullable: true})
+    appointmentId: number;
+
+    @Column({ comment: '鐘舵��', dict: ['寰呭鐞�', '杩涜涓�', '宸插畬鎴�', '宸插彇娑�'], default: '宸插畬鎴�', })
+    status: string;
+
+    @Column({ comment: '鎬婚噸閲�', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    totalWeight: number;
+
+    @Column({ comment: '鎬婚噾棰�', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    totalAmount: number;
+
+    @Column({ comment: '鎬荤⒊绉垎', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    totalCarbonPoint: number;
+
+    @Column({ comment: '瀹屾垚鏃堕棿', nullable: true })
+    finishTime: Date;
+
+
+}
\ No newline at end of file
diff --git a/src/modules/shop/entity/recycleorderitem.ts b/src/modules/shop/entity/recycleorderitem.ts
new file mode 100644
index 0000000..e149dad
--- /dev/null
+++ b/src/modules/shop/entity/recycleorderitem.ts
@@ -0,0 +1,34 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍨冨溇鍥炴敹璁㈠崟璇︽儏淇℃伅
+ */
+@Entity('t_recycle_order_item')
+export class RecycleOrderItemEntity extends BaseEntity {
+    @Index()
+    @Column({ comment: '璁㈠崟NO' })
+    orderNo: string;
+
+    @Index()
+    @Column({ comment: '鍨冨溇鍒嗙被ID' })
+    itemId: string;
+
+    @Column({ comment: '鍨冨溇鍒嗙被鍚嶇О' })
+    itemName: string;
+
+    @Column({ comment: '鍥哄簾鍥芥爣鍒嗙被' })
+    category: string;
+
+    @Column({ comment: '閲嶉噺', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    weight: number;
+
+    @Column({ comment: '鍗曚环', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    unitPrice: number;
+
+    @Column({ comment: '閲戦', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    amount: number;
+
+    @Column({ comment: '纰崇Н鍒�', type: 'decimal', precision: 10, scale: 2, default: 0, })
+    carbonPoint: number;
+}
\ No newline at end of file
diff --git a/src/modules/shop/entity/transaction.ts b/src/modules/shop/entity/transaction.ts
new file mode 100644
index 0000000..53bc7ca
--- /dev/null
+++ b/src/modules/shop/entity/transaction.ts
@@ -0,0 +1,42 @@
+import { BaseEntity } from '../../base/entity/base';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 娴佹按璁板綍
+ */
+@Entity('t_recycle_transaction')
+export class RecycleTransactionEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: string;
+
+  @Index()
+  @Column({ comment: '鏈烘瀯ID', nullable: true })
+  departmentId: number;
+
+  @Column({ comment: '娴佹按绫诲瀷', dict: ['鏀跺叆', '鏀嚭'], default: '鏀跺叆' })
+  type: string;
+
+  @Column({
+    comment: '閲戦',
+    type: 'decimal',
+    precision: 15,
+    scale: 2,
+  })
+  amount: number;
+
+  @Column({
+    comment: '鏉ユ簮绫诲瀷',
+    dict: ['鍥炴敹', '鍟嗗煄', '璧犻��', '鎺ュ彈', '鎹愯禒', '绛惧埌'],
+    default: '鍥炴敹',
+  })
+  sourceType: string;
+
+  @Column({ comment: '澶囨敞', nullable: true })
+  remark: string;
+
+  @Index()
+  @Column({ comment: '璁㈠崟ID', nullable: true })
+  orderId: string;
+  
+}
\ No newline at end of file
diff --git a/src/modules/shop/service/recycleappointment.ts b/src/modules/shop/service/recycleappointment.ts
new file mode 100644
index 0000000..a715550
--- /dev/null
+++ b/src/modules/shop/service/recycleappointment.ts
@@ -0,0 +1,14 @@
+import { Provide } from "@midwayjs/core";
+import { BaseService } from "@cool-midway/core";
+import { InjectEntityModel } from "@midwayjs/typeorm";
+import { Repository } from "typeorm";
+import { RecycleAppointmentEntity } from "../entity/recycleappointment";
+
+/**
+ * 鍥炴敹鐗╁搧璁㈠崟-棰勭害鏈嶅姟
+ */
+@Provide()
+export class RecycleAppointmentService extends BaseService {
+  @InjectEntityModel(RecycleAppointmentEntity)
+  recycleAppointmentEntity: Repository<RecycleAppointmentEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/shop/service/recycleappointmentlog.ts b/src/modules/shop/service/recycleappointmentlog.ts
new file mode 100644
index 0000000..581fac4
--- /dev/null
+++ b/src/modules/shop/service/recycleappointmentlog.ts
@@ -0,0 +1,14 @@
+import { Provide } from "@midwayjs/core";
+import { BaseService } from "@cool-midway/core";
+import { InjectEntityModel } from "@midwayjs/typeorm";
+import { Repository } from "typeorm";
+import { RecycleAppointmentLogEntity } from "../entity/recycleappointmentlog";
+
+/**
+ * 鍥炴敹鐗╁搧璁㈠崟-棰勭害鐨勫彉鍔�
+ */
+@Provide()
+export class RecycleAppointmentLogService extends BaseService {
+  @InjectEntityModel(RecycleAppointmentLogEntity)
+  recycleAppointmentLogEntity: Repository<RecycleAppointmentLogEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/shop/service/recycleitem.ts b/src/modules/shop/service/recycleitem.ts
new file mode 100644
index 0000000..ce201a0
--- /dev/null
+++ b/src/modules/shop/service/recycleitem.ts
@@ -0,0 +1,15 @@
+import { Provide, Inject } from '@midwayjs/core';
+import { BaseService, CoolTransaction } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository, QueryRunner } from 'typeorm';
+import { RecycleItemEntity } from '../entity/recycleitem';
+
+/**
+ * 纰崇Н鍒嗘祦杞褰�
+ */
+@Provide()
+export class RecycleItemService extends BaseService {
+  @InjectEntityModel(RecycleItemEntity)
+  recycleItemEntity: Repository<RecycleItemEntity>;
+
+}
\ No newline at end of file
diff --git a/src/modules/shop/service/recycleorder.ts b/src/modules/shop/service/recycleorder.ts
new file mode 100644
index 0000000..1bd5240
--- /dev/null
+++ b/src/modules/shop/service/recycleorder.ts
@@ -0,0 +1,143 @@
+import { Provide } from "@midwayjs/core";
+import { BaseService, CoolTransaction } from "@cool-midway/core";
+import { InjectEntityModel } from "@midwayjs/typeorm";
+import { Repository, QueryRunner, EntityManager } from "typeorm";
+import { RecycleItemEntity } from "../entity/recycleitem";
+import { RecycleOrderEntity } from "../entity/recycleorder";
+import { RecycleOrderItemEntity } from '../entity/recycleorderitem';
+import { UserInfoEntity } from '../../user/entity/info';
+import { RecycleTransactionEntity } from '../entity/transaction';
+
+
+/**
+ * 鍥炴敹鐗╁搧璁㈠崟鏈嶅姟
+ */
+@Provide()
+export class RecycleOrderService extends BaseService {
+  @InjectEntityModel(RecycleOrderEntity)
+  recycleOrderEntity: Repository<RecycleOrderEntity>;
+
+  @InjectEntityModel(RecycleItemEntity)
+  recycleItemEntity: Repository<RecycleItemEntity>;
+
+  @InjectEntityModel(RecycleOrderItemEntity)
+  recycleOrderItemEntity: Repository<RecycleOrderItemEntity>;
+
+  @InjectEntityModel(RecycleTransactionEntity)
+  recycleTransactionEntity: Repository<RecycleTransactionEntity>;
+
+  /**
+   * 閲嶅啓鏂板锛屽鐞嗚鍗曞強璇︽儏
+   */
+  @CoolTransaction()
+  async add(param: any, queryRunner?: QueryRunner) {
+    const { items, ...orderData } = param;
+    // 淇濆瓨璁㈠崟
+    const order = await queryRunner?.manager.save(RecycleOrderEntity, orderData);
+    // 淇濆瓨璇︽儏
+    if (items && items.length > 0) {
+      const itemEntities = items.map(e => {
+        return {
+          ...e,
+          orderId: order.id,
+        };
+      });
+      await queryRunner?.manager.save(RecycleItemEntity, itemEntities);
+    }
+    return order;
+  }
+
+  /**
+   * 閲嶅啓鏇存柊
+   */
+  @CoolTransaction()
+  async update(param: any, queryRunner?: QueryRunner) {
+    const { items, id, ...orderData } = param;
+    await queryRunner?.manager.update(RecycleOrderEntity, id, orderData);
+    if (items) {
+      // 鍏堝垹闄ゆ棫璇︽儏鍐嶆彃鍏ユ柊璇︽儏锛堢畝鍗曞鐞嗭級
+      await queryRunner?.manager.delete(RecycleItemEntity, { orderId: id });
+      const itemEntities = items.map(e => {
+        return {
+          ...e,
+          orderId: id,
+        };
+      });
+      await queryRunner?.manager.save(RecycleItemEntity, itemEntities);
+    }
+  }
+
+  /**
+ * 閲嶅啓鍒犻櫎閫昏緫锛屽悓姝ュ垹闄よ鍗曢」
+ */
+  @CoolTransaction()
+  async delete(ids: number[], queryRunner?: QueryRunner) {
+    for (const id of ids) {
+      const order = await this.recycleOrderEntity.findOneBy({ id });
+      if (order) {
+        await queryRunner?.manager.delete(RecycleOrderItemEntity, {
+          orderNo: order.orderNo,
+        });
+      }
+    }
+    await queryRunner?.manager.delete(RecycleOrderEntity, ids);
+  }
+
+  @CoolTransaction()
+  async saveWithSummary(orderNo: string, items: any[]) {
+
+
+    // 1锔忊儯 鍏堝垹鎺夋棫鏄庣粏
+    await RecycleOrderItemEntity.delete({ orderNo });
+
+    // 2锔忊儯 閲嶆柊鎻掑叆
+    const newItems = items.map(i => ({
+      ...i,
+      orderNo
+    }));
+    console.log(newItems)
+    await RecycleOrderItemEntity.save(newItems);
+
+    // 3锔忊儯 姹囨��
+    const all = await RecycleOrderItemEntity.find({
+      where: { orderNo }
+    });
+
+    const totalWeight = all.reduce((s, i) => s + Number(i.weight), 0);
+    const totalCarbonPoint = all.reduce((s, i) => s + Number(i.carbonPoint), 0);
+    const totalAmount = all.reduce((s, i) => s + Number(i.amount), 0);
+
+    await RecycleOrderEntity.update(
+      { orderNo },
+      { totalWeight, totalCarbonPoint, totalAmount }
+    );
+
+    // 5锔忊儯 鏇存柊鐢ㄦ埛纰充綑棰�
+    const order = await RecycleOrderEntity.findOne({
+      where: { orderNo },
+      select: ['campusUserId']
+    });
+
+    if (order?.campusUserId) {
+      await UserInfoEntity.update(
+        { unionid: order.campusUserId },
+        {
+          carbonBalance: () => `carbonBalance + ${totalCarbonPoint}`
+        }
+      );
+    }
+
+    // 7锔忊儯 鉁� 鐢� add() 鍐欐祦姘达紙閲嶇偣锛�
+    await RecycleTransactionEntity.save({
+      userId: order?.campusUserId,
+      departmentId: order?.departmentId,
+      type: '鏀跺叆',
+      amount: totalCarbonPoint,
+      sourceType: '鍥炴敹',
+      remark: `鍥炴敹璁㈠崟 ${orderNo} 鑾峰緱纰崇Н鍒哷,
+      orderId: orderNo
+    });
+
+  };
+
+}
\ No newline at end of file
diff --git a/src/modules/shop/service/recycleorderitem.ts b/src/modules/shop/service/recycleorderitem.ts
new file mode 100644
index 0000000..b7eb210
--- /dev/null
+++ b/src/modules/shop/service/recycleorderitem.ts
@@ -0,0 +1,14 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { RecycleOrderItemEntity } from '../entity/recycleorderitem';
+
+/**
+ * 璁㈠崟璇︽儏鏈嶅姟
+ */
+@Provide()
+export class RecycleOrderItemService extends BaseService {
+  @InjectEntityModel(RecycleOrderItemEntity)
+  recycleOrderItemEntity: Repository<RecycleOrderItemEntity>;
+}
\ No newline at end of file
diff --git a/src/modules/shop/service/transaction.ts b/src/modules/shop/service/transaction.ts
new file mode 100644
index 0000000..e8304cd
--- /dev/null
+++ b/src/modules/shop/service/transaction.ts
@@ -0,0 +1,15 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { RecycleTransactionEntity } from '../entity/transaction';
+
+/**
+ * 纰崇Н鍒嗘祦杞褰�
+ */
+@Provide()
+export class RecycleTransactionService extends BaseService {
+  @InjectEntityModel(RecycleTransactionEntity)
+  recycleTransactionEntity: Repository<RecycleTransactionEntity>;
+
+}
\ No newline at end of file
diff --git a/src/modules/user/controller/admin/info.ts b/src/modules/user/controller/admin/info.ts
index deeec01..19ef3f3 100644
--- a/src/modules/user/controller/admin/info.ts
+++ b/src/modules/user/controller/admin/info.ts
@@ -1,5 +1,7 @@
 import { CoolController, BaseController } from '@cool-midway/core';
 import { UserInfoEntity } from '../../entity/info';
+import { BaseSysDepartmentEntity } from '../../../base/entity/sys/department';
+import { WithDeptFilterWhere } from '../../../base/middleware/with-dept-filter-where'
 
 /**
  * 鐢ㄦ埛淇℃伅
@@ -10,6 +12,21 @@
   pageQueryOp: {
     fieldEq: ['a.status', 'a.gender', 'a.loginType'],
     keyWordLikeFields: ['a.nickName', 'a.phone'],
+    select: ["a.*", "c.name AS departmentName"],
+    join: [
+      {
+        entity: BaseSysDepartmentEntity,
+        alias: "c",
+        condition: 'a.departmentId = c.id',
+        type: "leftJoin"
+      }
+    ],
+    where: async (ctx) => {
+      const conditions: any[][] = [];
+      conditions.push(...(await WithDeptFilterWhere(ctx, { alias: 'a', field: 'departmentId' })));
+      return conditions;
+    }
+
   },
 })
-export class AdminUserInfoController extends BaseController {}
+export class AdminUserInfoController extends BaseController { }
diff --git a/src/modules/user/entity/info.ts b/src/modules/user/entity/info.ts
index 7f0e127..3e0a40e 100644
--- a/src/modules/user/entity/info.ts
+++ b/src/modules/user/entity/info.ts
@@ -1,10 +1,10 @@
 import { BaseEntity } from '../../base/entity/base';
-import { Column, Entity, Index } from 'typeorm';
+import { Column, Entity, Index,BeforeInsert } from 'typeorm';
 
 /**
  * 鐢ㄦ埛淇℃伅
  */
-@Entity('user_info')
+@Entity('t_school_user_info')
 export class UserInfoEntity extends BaseEntity {
   @Index({ unique: true })
   @Column({ comment: '鐧诲綍鍞竴ID', nullable: true })
@@ -20,8 +20,46 @@
   @Column({ comment: '鎵嬫満鍙�', nullable: true })
   phone: string;
 
+  @Column({ comment: '鐢熸棩', type: 'date', nullable: true })
+  birthday: Date;
+
   @Column({ comment: '鎬у埆', dict: ['鏈煡', '鐢�', '濂�'], default: 0 })
   gender: number;
+
+  @Index()
+  @Column({ comment: '瑙掕壊', dict: ['鑰佸笀', '瀛︾敓', '鍏朵粬'], default: '瀛︾敓' })
+  role: string;
+
+  @Index()
+  @Column({ comment: '瀛︽牎ID' })   // 浣跨敤褰掑睘閮ㄩ棬锛岃繖閲屽缓璁�夐《灞傚鏍�
+  departmentId: number;
+
+  departmentName: string;
+
+  @Index()
+  @Column({ comment: '纰崇Н鍒�', default: 0 })
+  carbonBalance: number;
+
+  @Index()
+  @Column({ comment: '瀛﹂櫌ID', nullable: true })
+  collegeId: number;
+
+  @Column({ comment: '瀛﹂櫌鍚嶇О', nullable: true })
+  collegeName: string;
+
+  @Index()
+  @Column({ comment: '涓撲笟ID', nullable: true })
+  majorId: number;
+
+  @Column({ comment: '涓撲笟鍚嶇О', nullable: true })
+  majorName: string;
+
+  @Index()
+  @Column({ comment: '鐝骇ID', nullable: true })
+  classId: number;
+
+  @Column({ comment: '鐝骇鍚嶇О', nullable: true })
+  className: string;
 
   @Column({ comment: '鐘舵��', dict: ['绂佺敤', '姝e父', '宸叉敞閿�'], default: 1 })
   status: number;
@@ -34,4 +72,5 @@
 
   @Column({ comment: '浠嬬粛', type: 'text', nullable: true })
   description: string;
+
 }
diff --git a/src/modules/user/service/info.ts b/src/modules/user/service/info.ts
index 62f2017..58dd8fd 100644
--- a/src/modules/user/service/info.ts
+++ b/src/modules/user/service/info.ts
@@ -46,7 +46,7 @@
    */
   async person(id) {
     const info = await this.userInfoEntity.findOneBy({ id: Equal(id) });
-    delete info.password;
+    //delete info.password;
     return info;
   }
 
@@ -59,10 +59,10 @@
       { id: userId },
       {
         status: 2,
-        phone: null,
-        unionid: null,
+        phone: "",
+        unionid: "",
         nickName: `宸叉敞閿�-00${userId}`,
-        avatarUrl: null,
+        avatarUrl: "",
       }
     );
   }
@@ -85,7 +85,7 @@
           uuid() + '.png'
         );
       }
-    } catch (err) {}
+    } catch (err) { }
     try {
       return await this.userInfoEntity.update({ id }, param);
     } catch (err) {
@@ -99,13 +99,21 @@
    * @param password
    * @param 楠岃瘉鐮�
    */
-  async updatePassword(userId, password, code) {
-    const user = await this.userInfoEntity.findOneBy({ id: userId });
+  async updatePassword(userId: string, password: string, code: string) {
+    const user = await this.userInfoEntity.findOneBy({ unionid: userId });
+
+    if (!user) {
+      throw new CoolCommException('鐢ㄦ埛涓嶅瓨鍦�');
+    }
+
     const check = await this.userSmsService.checkCode(user.phone, code);
     if (!check) {
       throw new CoolCommException('楠岃瘉鐮侀敊璇�');
     }
-    await this.userInfoEntity.update(user.id, { password: md5(password) });
+
+    await this.userInfoEntity.update(user.unionid, {
+      password: md5(password),
+    });
   }
 
   /**

--
Gitblit v1.9.1