From 7dcc2997614f849258091f5d66e648317a40d323 Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期五, 14 八月 2026 10:12:42 +0800
Subject: [PATCH] add shop module

---
 src/modules/goods/service/comment.ts                |   62 
 src/modules/market/controller/app/coupon/user.ts    |   48 
 src/modules/count/service/order.ts                  |   94 
 src/modules/cs/service/msg.ts                       |  140 +
 src/configuration.ts                                |   15 
 src/modules/market/entity/coupon/info.ts            |   41 
 src/modules/cs/entity/conn.ts                       |   18 
 src/modules/count/service/goods.ts                  |   55 
 src/modules/info/controller/admin/banner.ts         |   15 
 src/modules/goods/entity/searchKeyword.ts           |   14 
 src/modules/goods/service/type.ts                   |   30 
 src/modules/app/controller/admin/goods.ts           |   15 
 src/modules/goods/config.ts                         |   19 
 typings/upload-oss.d.ts                             |   59 
 src/modules/goods/entity/spec.ts                    |   32 
 src/modules/order/service/pay.ts                    |  238 +
 src/modules/count/config.ts                         |   19 
 src/modules/info/entity/banner.ts                   |   23 
 src/modules/order/queue/order.ts                    |   33 
 src/modules/cs/config.ts                            |   19 
 src/modules/app/package.json                        |    5 
 src/modules/app/entity/complain.ts                  |   34 
 src/modules/goods/controller/admin/info.ts          |   29 
 src/modules/goods/controller/app/spec.ts            |   23 
 src/modules/base/entity/sys/log.ts                  |    9 
 src/modules/goods/controller/app/type.ts            |   29 
 src/modules/goods/service/info.ts                   |   56 
 src/modules/app/db.json                             |  124 +
 src/modules/cs/controller/app/session.ts            |   25 
 src/modules/app/controller/admin/complain.ts        |   32 
 src/modules/app/entity/version.ts                   |   32 
 src/modules/order/controller/app/pay.ts             |   64 
 src/modules/market/controller/admin/coupon/user.ts  |   26 
 src/modules/goods/controller/admin/searchKeyword.ts |   14 
 src/modules/base/db.json                            |   45 
 src/modules/cs/socket/middleware/token.ts           |   34 
 src/modules/app/service/feedback.ts                 |   36 
 src/modules/user/config.ts                          |    2 
 src/modules/goods/controller/admin/comment.ts       |   30 
 src/modules/goods/service/spec.ts                   |   71 
 src/modules/cs/controller/admin/msg.ts              |   58 
 src/modules/app/service/complain.ts                 |   36 
 src/modules/base/controller/admin/sys/param.ts      |    2 
 src/modules/app/menu.json                           |  270 ++
 src/modules/goods/controller/app/searchKeyword.ts   |   14 
 src/modules/user/controller/admin/info.ts           |    2 
 src/modules/count/service/comm.ts                   |   71 
 typings/sms-ali.d.ts                                |   28 
 src/modules/app/controller/app/version.ts           |   30 
 src/config/config.prod.ts                           |   15 
 src/modules/base/db/tenant.ts                       |    6 
 src/modules/cs/socket/io.ts                         |   46 
 src/modules/user/controller/app/login.ts            |   11 
 src/modules/cs/service/conn.ts                      |   57 
 src/modules/user/service/info.ts                    |    2 
 typings/plugin.d.ts                                 |   10 
 src/modules/order/config.ts                         |   19 
 src/modules/order/service/info.ts                   |  463 +++
 src/config/config.local.ts                          |    2 
 src/modules/app/service/version.ts                  |   45 
 src/modules/base/menu.json                          | 2500 ++++++++++++-------
 src/modules/market/controller/app/coupon/info.ts    |   51 
 src/modules/goods/entity/info.ts                    |   50 
 src/modules/cs/entity/msg.ts                        |   36 
 src/modules/app/controller/app/feedback.ts          |   38 
 src/modules/market/entity/coupon/user.ts            |   22 
 src/modules/app/entity/goods.ts                     |   48 
 src/modules/goods/controller/app/info.ts            |   45 
 src/modules/cs/controller/admin/session.ts          |   22 
 src/modules/base/middleware/authority.ts            |    4 
 src/modules/goods/controller/app/comment.ts         |   55 
 src/modules/order/service/goods.ts                  |   80 
 src/modules/market/config.ts                        |   19 
 src/modules/order/entity/goods.ts                   |   51 
 src/modules/order/controller/admin/info.ts          |   88 
 src/modules/market/controller/admin/coupon/info.ts  |   17 
 src/modules/base/config.ts                          |    6 
 src/modules/info/controller/app/banner.ts           |   27 
 src/modules/goods/entity/comment.ts                 |   29 
 src/modules/app/controller/admin/version.ts         |   17 
 src/modules/app/controller/app/complain.ts          |   38 
 src/modules/user/service/login.ts                   |   50 
 src/modules/count/controller/admin/home.ts          |   69 
 src/modules/app/controller/admin/feedback.ts        |   32 
 typings/pay-wx.d.ts                                 |   53 
 src/modules/app/entity/feedback.ts                  |   33 
 src/modules/market/service/coupon/info.ts           |  116 
 src/modules/market/service/coupon/user.ts           |   74 
 src/config/config.default.ts                        |   53 
 src/modules/app/controller/app/goods.ts             |   19 
 src/modules/cs/entity/session.ts                    |   19 
 src/modules/order/entity/info.ts                    |  126 +
 src/modules/app/config.ts                           |   19 
 src/modules/info/config.ts                          |   19 
 src/modules/goods/entity/type.ts                    |   24 
 src/comm/utils.ts                                   |   76 
 typings/wx.d.ts                                     |   58 
 src/modules/cs/controller/app/msg.ts                |   62 
 src/modules/cs/service/session.ts                   |   38 
 src/modules/order/controller/app/info.ts            |   86 
 typings/wuliu.d.ts                                  |   19 
 src/modules/goods/controller/admin/type.ts          |   20 
 src/modules/goods/controller/admin/spec.ts          |   14 
 src/modules/cs/menu.json                            |   27 
 package.json                                        |   56 
 src/modules/count/service/user.ts                   |   69 
 106 files changed, 6,268 insertions(+), 1,102 deletions(-)

diff --git a/package.json b/package.json
index 3a7cf85..bb1553d 100644
--- a/package.json
+++ b/package.json
@@ -4,49 +4,54 @@
   "description": "涓�涓緢閰风殑Ai蹇�熷紑鍙戞鏋�",
   "private": true,
   "dependencies": {
-    "@cool-midway/core": "^8.0.7",
-    "@cool-midway/rpc": "^8.0.1",
-    "@cool-midway/task": "^8.0.2",
-    "@midwayjs/bootstrap": "^3.20.3",
-    "@midwayjs/cache-manager": "^3.20.3",
-    "@midwayjs/core": "^3.20.3",
-    "@midwayjs/cron": "^3.20.3",
-    "@midwayjs/cross-domain": "^3.20.3",
-    "@midwayjs/info": "^3.20.3",
-    "@midwayjs/koa": "^3.20.3",
+    "@cool-midway/core": "8.0.1",
+    "@cool-midway/rpc": "8.0.1",
+    "@cool-midway/task": "8.0.1",
+    "@midwayjs/bootstrap": "^3.20.0",
+    "@midwayjs/cache-manager": "^3.20.0",
+    "@midwayjs/core": "^3.20.0",
+    "@midwayjs/cron": "^3.20.0",
+    "@midwayjs/cross-domain": "^3.20.0",
+    "@midwayjs/info": "^3.20.0",
+    "@midwayjs/koa": "^3.20.0",
     "@midwayjs/logger": "^3.4.2",
-    "@midwayjs/static-file": "^3.20.3",
-    "@midwayjs/typeorm": "^3.20.3",
-    "@midwayjs/upload": "^3.20.3",
-    "@midwayjs/validate": "^3.20.3",
+    "@midwayjs/static-file": "^3.20.0",
+    "@midwayjs/typeorm": "^3.20.0",
+    "@midwayjs/upload": "^3.20.0",
+    "@midwayjs/validate": "^3.20.0",
+    "@midwayjs/socketio": "^3.15.2",
+    "@socket.io/redis-adapter": "^8.3.0",
     "adm-zip": "^0.5.16",
-    "axios": "^1.8.4",
-    "cron": "^4.1.3",
-    "download": "^8.0.0",
+    "axios": "^1.7.9",
+    "bignumber.js": "^9.1.2",
+    "cache-manager-ioredis-yet": "^2.0.2",
+    "ioredis": "^5.3.2",
+    "cron": "^3.5.0",
     "jsonwebtoken": "^9.0.2",
     "lodash": "^4.17.21",
     "md5": "^2.3.0",
     "moment": "^2.30.1",
-    "mysql2": "^3.14.0",
+    "mysql2": "^3.12.0",
+    "semver": "^7.6.0",
     "svg-captcha": "^1.4.0",
     "tslib": "^2.8.1",
     "typeorm": "npm:@cool-midway/typeorm@0.3.20",
-    "uuid": "^11.1.0",
-    "ws": "^8.18.1"
+    "uuid": "^11.0.5",
+    "ws": "^8.18.0"
   },
   "devDependencies": {
     "@midwayjs/bundle-helper": "^1.3.0",
-    "@midwayjs/mock": "^3.20.3",
+    "@midwayjs/mock": "^3.20.0",
     "@types/jest": "^29.5.14",
     "@types/node": "22",
-    "@yao-pkg/pkg": "^6.3.2",
+    "@yao-pkg/pkg": "^6.2.0",
     "cross-env": "^7.0.3",
     "jest": "^29.7.0",
     "mwts": "^1.3.0",
     "mwtsc": "^1.15.1",
     "rimraf": "^6.0.1",
-    "ts-jest": "^29.3.0",
-    "typescript": "~5.8.2"
+    "ts-jest": "^29.2.5",
+    "typescript": "~5.7.3"
   },
   "engines": {
     "node": ">=18.0.0"
@@ -86,6 +91,5 @@
     "url": "https://cool-js.com"
   },
   "author": "COOL",
-  "license": "MIT",
-  "packageManager": "pnpm@11.12.0+sha512.820a6fbd0d9f04c226638002aead1e45340a9139dd5dc077c1d83ef44aa2481c8eb6637b4c9aa696a3c7e35ba818e49cf27213e5f2b91138d09b7a3e26e898ba"
+  "license": "MIT"
 }
diff --git a/src/comm/utils.ts b/src/comm/utils.ts
index e50b3b8..87b438d 100644
--- a/src/comm/utils.ts
+++ b/src/comm/utils.ts
@@ -192,80 +192,4 @@
     // 濡傛灉 pattern 鍜� url 鐨勯儴鍒嗘暟閲忎竴鑷达紝鍒欏尮閰嶆垚鍔�
     return patternParts.length === urlParts.length;
   }
-
-  /**
-   * 浠庢枃鏈腑鎻愬彇 JSON 瀛楃涓插苟杞崲涓哄璞�
-   * @param {string} text - 鍙兘鍖呭惈 JSON 鐨勬枃鏈�
-   * @returns {Object|Array|null} - 瑙f瀽鍑虹殑 JSON 瀵硅薄锛屽鏋滄病鏈夋壘鍒版湁鏁� JSON 鍒欒繑鍥� null
-   */
-  extractJSONFromText(text) {
-    if (!text || typeof text !== 'string') {
-      return null;
-    }
-
-    try {
-      // 灏濊瘯鐩存帴瑙f瀽鏁翠釜鏂囨湰
-      return JSON.parse(text);
-    } catch (e) {
-      // 鏁翠釜鏂囨湰涓嶆槸鏈夋晥鐨� JSON锛屽皾璇曟彁鍙� JSON 閮ㄥ垎
-    }
-
-    // 鏌ユ壘鍙兘鐨� JSON 寮�濮嬩綅缃紙{ 鎴� [锛�
-    const possibleStarts = [];
-    for (let i = 0; i < text.length; i++) {
-      if (text[i] === '{' || text[i] === '[') {
-        possibleStarts.push(i);
-      }
-    }
-
-    // 浠庢瘡涓彲鑳界殑璧峰浣嶇疆灏濊瘯鎻愬彇 JSON
-    for (const startIndex of possibleStarts) {
-      let openBraces = 0;
-      let openBrackets = 0;
-      let inString = false;
-      let escapeNext = false;
-
-      for (let i = startIndex; i < text.length; i++) {
-        const char = text[i];
-
-        // 澶勭悊杞箟瀛楃
-        if (inString && !escapeNext && char === '\\') {
-          escapeNext = true;
-          continue;
-        }
-
-        // 澶勭悊瀛楃涓茶竟鐣�
-        if (!escapeNext && char === '"') {
-          inString = !inString;
-        }
-
-        if (!inString) {
-          // 鍙湪涓嶅湪瀛楃涓插唴閮ㄦ椂鎵嶈绠楁嫭鍙�
-          if (char === '{') openBraces++;
-          else if (char === '}') openBraces--;
-          else if (char === '[') openBrackets++;
-          else if (char === ']') openBrackets--;
-        }
-
-        escapeNext = false;
-
-        // 妫�鏌ユ槸鍚︽壘鍒颁簡瀹屾暣鐨� JSON 缁撴瀯
-        if (
-          (openBraces === 0 && text[startIndex] === '{' && char === '}') ||
-          (openBrackets === 0 && text[startIndex] === '[' && char === ']')
-        ) {
-          const jsonStr = text.substring(startIndex, i + 1);
-          try {
-            const result = JSON.parse(jsonStr);
-            return result;
-          } catch (e) {
-            // 杩欎釜鍊欓�� JSON 鏃犳晥锛岀户缁皾璇曚笅涓�涓�
-            break;
-          }
-        }
-      }
-    }
-
-    return null; // 娌℃湁鎵惧埌鏈夋晥鐨� JSON
-  }
 }
diff --git a/src/config/config.default.ts b/src/config/config.default.ts
index 03a7323..1cc32d5 100644
--- a/src/config/config.default.ts
+++ b/src/config/config.default.ts
@@ -1,19 +1,23 @@
-import { CoolConfig } from '@cool-midway/core';
+import { CoolCacheStore, CoolConfig } from '@cool-midway/core';
 import { MidwayConfig } from '@midwayjs/core';
-import { CoolCacheStore } from '@cool-midway/core';
 import * as path from 'path';
 import { pCachePath, pUploadPath } from '../comm/path';
 import { availablePort } from '../comm/port';
 
+// redis缂撳瓨
+// import { redisStore } from 'cache-manager-ioredis-yet';
+
 export default {
-  keys: 'f65bcafd-b72c-4f01-a451-333155097148',
+  // 纭繚姣忎釜椤圭洰鍞竴锛岄」鐩娆″惎鍔ㄤ細鑷姩鐢熸垚
+  keys: '44ceca50-584c-44c4-8346-4b44471ea41f',
   koa: {
     port: availablePort(8001),
-    rawBody: true,    
   },
+  // 寮�鍚紓姝ヤ笂涓嬫枃绠$悊
   asyncContextManager: {
     enable: true,
   },
+  // 闈欐�佹枃浠堕厤缃�
   staticFile: {
     buffer: true,
     dirs: {
@@ -27,11 +31,12 @@
       },
     },
   },
+  // 鏂囦欢涓婁紶
   upload: {
     fileSize: '200mb',
     whitelist: null,
-    ignore: ['/open/push/yingshiyun', "/open/push/cameraEvent"],    
   },
+  // 缂撳瓨 鍙垏鎹㈡垚鍏朵粬缂撳瓨濡傦細redis http://www.midwayjs.org/docs/extensions/caching
   cacheManager: {
     clients: {
       default: {
@@ -43,19 +48,49 @@
       },
     },
   },
+  // cacheManager: {
+  //   clients: {
+  //     default: {
+  //       store: redisStore,
+  //       options: {
+  //         port: 6379,
+  //         host: '127.0.0.1',
+  //         password: '',
+  //         ttl: 0,
+  //         db: 0,
+  //       },
+  //     },
+  //   },
+  // },
   cool: {
+    redis: {
+      host: '127.0.0.1',
+      password: '',
+      port: 6379,
+      db: 10,
+    },
+    // 宸茬粡鎻掍欢鍖栵紝鏈湴鏂囦欢涓婁紶鏌ョ湅 plugin/config.ts锛屽叾浠栦簯瀛樺偍鏌ョ湅瀵瑰簲鎻掍欢鐨勪娇鐢�
     file: {},
+    // 鏄惁寮�鍚绉熸埛
     tenant: {
-      enable: true,
+      // 鏄惁寮�鍚绉熸埛
+      enable: false,
+      // 闇�瑕佽繃婊ゅ绉熸埛鐨剈rl, 鏀寔閫氶厤绗︼紝 濡�/admin/**/* 琛ㄧずadmin妯″潡涓嬬殑鎵�鏈夋帴鍙i兘杩涜澶氱鎴疯繃婊�
       urls: [],
     },
+    // 鍥介檯鍖栭厤缃�
     i18n: {
-      enable: true,
+      // 鏄惁寮�鍚�
+      enable: false,
+      // 璇█
       languages: ['zh-cn', 'zh-tw', 'en'],
     },
+    // crud閰嶇疆
     crud: {
+      // 鎻掑叆妯″紡锛宻ave涓嶄細鏍¢獙瀛楁(鍏佽浼犲叆涓嶅瓨鍦ㄧ殑瀛楁)锛宨nsert浼氭牎楠屽瓧娈�
       upsert: 'save',
+      // 杞垹闄�
       softDelete: true,
-    },  
+    },
   } as CoolConfig,
-} as MidwayConfig;
\ No newline at end of file
+} as MidwayConfig;
diff --git a/src/config/config.local.ts b/src/config/config.local.ts
index 3eabef6..80bbc57 100644
--- a/src/config/config.local.ts
+++ b/src/config/config.local.ts
@@ -14,7 +14,7 @@
         port: 8806,
         username: 'womp',
         password: 'Sening@2023',
-        database: 'womp',
+        database: 'womp-shop',
         // 鑷姩寤鸿〃 娉ㄦ剰锛氱嚎涓婇儴缃茬殑鏃跺�欎笉瑕佷娇鐢紝鏈夊彲鑳藉鑷存暟鎹涪澶�
         synchronize: true,
         // 鎵撳嵃鏃ュ織
diff --git a/src/config/config.prod.ts b/src/config/config.prod.ts
index df19add..e8f6b4c 100644
--- a/src/config/config.prod.ts
+++ b/src/config/config.prod.ts
@@ -2,11 +2,26 @@
 import { MidwayConfig } from '@midwayjs/core';
 import { entities } from '../entities';
 import { TenantSubscriber } from '../modules/base/db/tenant';
+import { createAdapter } from '@socket.io/redis-adapter';
+import Redis from 'ioredis';
+
+const redis = {
+  host: '127.0.0.1',
+  port: 6379,
+  password: '',
+  db: 0,
+};
+const pubClient = new Redis(redis);
+const subClient = pubClient.duplicate();
 
 /**
  * 鏈湴寮�鍙� npm run prod 璇诲彇鐨勯厤缃枃浠�
  */
 export default {
+  socketIO: {
+    upgrades: ['websocket'], // 鍙崌绾х殑鍗忚
+    adapter: createAdapter(pubClient, subClient),
+  },
   typeorm: {
     dataSource: {
       default: {
diff --git a/src/configuration.ts b/src/configuration.ts
index 0ba1d73..d367d50 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -8,7 +8,7 @@
   MidwayWebRouterService,
 } from '@midwayjs/core';
 import * as koa from '@midwayjs/koa';
-import * as crossDomain from '@midwayjs/cross-domain';
+// import * as crossDomain from '@midwayjs/cross-domain';
 import * as validate from '@midwayjs/validate';
 import * as info from '@midwayjs/info';
 import * as staticFile from '@midwayjs/static-file';
@@ -18,15 +18,16 @@
 import * as ProdConfig from './config/config.prod';
 import * as cool from '@cool-midway/core';
 import * as upload from '@midwayjs/upload';
-//import * as task from '@cool-midway/task';
-//import * as rpc from '@cool-midway/rpc';
+import * as socketio from '@midwayjs/socketio';
+import * as task from '@cool-midway/task';
+// import * as rpc from '@cool-midway/rpc';
 
 @Configuration({
   imports: [
     // https://koajs.com/
     koa,
     // 鏄惁寮�鍚法鍩�(娉細椤哄簭涓嶈兘涔辨斁锛侊紒锛�) http://www.midwayjs.org/docs/extensions/cross_domain
-    crossDomain,
+    // crossDomain,
     // 闈欐�佹枃浠舵墭绠� https://midwayjs.org/docs/extensions/static_file
     staticFile,
     // orm https://midwayjs.org/docs/extensions/orm
@@ -40,9 +41,11 @@
     // cool-admin 瀹樻柟缁勪欢 https://cool-js.com
     cool,
     // rpc 寰湇鍔� 杩滅▼璋冪敤
-    //rpc,
+    // rpc,
     // 浠诲姟涓庨槦鍒�
-    //task,
+    task,
+    // 鍗虫椂閫氳
+    socketio,
     {
       component: info,
       enabledEnvironment: ['local', 'prod'],
diff --git a/src/modules/app/config.ts b/src/modules/app/config.ts
new file mode 100644
index 0000000..d0eda0e
--- /dev/null
+++ b/src/modules/app/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '搴旂敤绠$悊',
+    // 妯″潡鎻忚堪
+    description: '鎶曡瘔涓炬姤銆佹剰瑙佸弽棣堛�佹洿鏂板崌绾с�佸椁愯缃瓑',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/app/controller/admin/complain.ts b/src/modules/app/controller/admin/complain.ts
new file mode 100644
index 0000000..7098936
--- /dev/null
+++ b/src/modules/app/controller/admin/complain.ts
@@ -0,0 +1,32 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { AppComplainEntity } from '../../entity/complain';
+import { BaseSysUserEntity } from '../../../base/entity/sys/user';
+import { AppComplainService } from '../../service/complain';
+import { UserInfoEntity } from '../../../user/entity/info';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: AppComplainEntity,
+  service: AppComplainService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.contact', 'b.nickName', 'c.name'],
+    select: ['a.*', 'b.nickName', 'b.avatarUrl', 'c.name as handlerName'],
+    fieldEq: ['a.status', 'a.type'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+      {
+        entity: BaseSysUserEntity,
+        alias: 'c',
+        condition: 'a.handlerId = c.id',
+      },
+    ],
+  },
+})
+export class AdminAppComplainController extends BaseController {}
diff --git a/src/modules/app/controller/admin/feedback.ts b/src/modules/app/controller/admin/feedback.ts
new file mode 100644
index 0000000..f15af95
--- /dev/null
+++ b/src/modules/app/controller/admin/feedback.ts
@@ -0,0 +1,32 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { AppFeedbackEntity } from '../../entity/feedback';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { BaseSysUserEntity } from '../../../base/entity/sys/user';
+import { AppFeedbackService } from '../../service/feedback';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: AppFeedbackEntity,
+  service: AppFeedbackService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.contact', 'b.nickName', 'c.name'],
+    select: ['a.*', 'b.nickName', 'b.avatarUrl', 'c.name as handlerName'],
+    fieldEq: ['a.status'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+      {
+        entity: BaseSysUserEntity,
+        alias: 'c',
+        condition: 'a.handlerId = c.id',
+      },
+    ],
+  },
+})
+export class AdminAppFeedbackController extends BaseController {}
diff --git a/src/modules/app/controller/admin/goods.ts b/src/modules/app/controller/admin/goods.ts
new file mode 100644
index 0000000..f147b42
--- /dev/null
+++ b/src/modules/app/controller/admin/goods.ts
@@ -0,0 +1,15 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { AppGoodsEntity } from '../../entity/goods';
+
+/**
+ * 濂楅
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: AppGoodsEntity,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title'],
+    fieldEq: ['a.status', 'a.type'],
+  },
+})
+export class AdminAppGoodsController extends BaseController {}
diff --git a/src/modules/app/controller/admin/version.ts b/src/modules/app/controller/admin/version.ts
new file mode 100644
index 0000000..9799680
--- /dev/null
+++ b/src/modules/app/controller/admin/version.ts
@@ -0,0 +1,17 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { AppVersionEntity } from '../../entity/version';
+import { AppVersionService } from '../../service/version';
+
+/**
+ * 鐗堟湰
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: AppVersionEntity,
+  service: AppVersionService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.name', 'a.version'],
+    fieldEq: ['a.status', 'a.type'],
+  },
+})
+export class AdminAppVersionController extends BaseController {}
diff --git a/src/modules/app/controller/app/complain.ts b/src/modules/app/controller/app/complain.ts
new file mode 100644
index 0000000..aeaaa33
--- /dev/null
+++ b/src/modules/app/controller/app/complain.ts
@@ -0,0 +1,38 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { Body, Inject, Post } from '@midwayjs/core';
+import { AppComplainService } from '../../service/complain';
+import { AppComplainEntity } from '../../entity/complain';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@CoolController({
+  api: ['page', 'info'],
+  entity: AppComplainEntity,
+  insertParam: ctx => {
+    return {
+      userId: ctx.user.id,
+    };
+  },
+  pageQueryOp: {
+    fieldEq: ['a.type'],
+    where: ctx => {
+      const userId = ctx.user.id;
+      return [['a.userId = :userId', { userId }]];
+    },
+  },
+})
+export class AppAppComplainController extends BaseController {
+  @Inject()
+  appComplainService: AppComplainService;
+
+  @Inject()
+  ctx;
+
+  @Post('/submit', { summary: '鎻愪氦鎶曡瘔涓炬姤' })
+  async submit(@Body() info) {
+    info.userId = this.ctx.user.id;
+    await this.appComplainService.submit(info);
+    return this.ok();
+  }
+}
diff --git a/src/modules/app/controller/app/feedback.ts b/src/modules/app/controller/app/feedback.ts
new file mode 100644
index 0000000..17f4805
--- /dev/null
+++ b/src/modules/app/controller/app/feedback.ts
@@ -0,0 +1,38 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { Body, Inject, Post } from '@midwayjs/core';
+import { AppFeedbackService } from '../../service/feedback';
+import { AppFeedbackEntity } from '../../entity/feedback';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@CoolController({
+  api: ['page', 'info'],
+  entity: AppFeedbackEntity,
+  insertParam: ctx => {
+    return {
+      userId: ctx.user.id,
+    };
+  },
+  pageQueryOp: {
+    fieldEq: ['a.type'],
+    where: ctx => {
+      const userId = ctx.user.id;
+      return [['a.userId = :userId', { userId }]];
+    },
+  },
+})
+export class AppAppFeedbackController extends BaseController {
+  @Inject()
+  appFeedbackService: AppFeedbackService;
+
+  @Inject()
+  ctx;
+
+  @Post('/submit', { summary: '鎻愪氦鎰忚鍙嶉' })
+  async submit(@Body() info) {
+    info.userId = this.ctx.user.id;
+    await this.appFeedbackService.submit(info);
+    return this.ok();
+  }
+}
diff --git a/src/modules/app/controller/app/goods.ts b/src/modules/app/controller/app/goods.ts
new file mode 100644
index 0000000..d0dd0fb
--- /dev/null
+++ b/src/modules/app/controller/app/goods.ts
@@ -0,0 +1,19 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { AppGoodsEntity } from '../../entity/goods';
+
+/**
+ * 濂楅
+ */
+@CoolController({
+  api: ['list'],
+  entity: AppGoodsEntity,
+  listQueryOp: {
+    addOrderBy: {
+      sort: 'ASC',
+    },
+    where: () => {
+      return [['a.status = :status', { status: 1 }]];
+    },
+  },
+})
+export class AppAppGoodsController extends BaseController {}
diff --git a/src/modules/app/controller/app/version.ts b/src/modules/app/controller/app/version.ts
new file mode 100644
index 0000000..119476c
--- /dev/null
+++ b/src/modules/app/controller/app/version.ts
@@ -0,0 +1,30 @@
+import {
+  CoolController,
+  BaseController,
+  CoolUrlTag,
+  CoolTag,
+  TagTypes,
+} from '@cool-midway/core';
+import { Get, Inject, Query } from '@midwayjs/core';
+import { AppVersionService } from '../../service/version';
+import { AppVersionEntity } from '../../entity/version';
+
+/**
+ * 鐗堟湰
+ */
+@CoolUrlTag()
+@CoolController({
+  api: [],
+  entity: AppVersionEntity,
+})
+export class AppAppVersionController extends BaseController {
+  @Inject()
+  appVersionService: AppVersionService;
+
+  @CoolTag(TagTypes.IGNORE_TOKEN)
+  @Get('/check', { summary: '妫�鏌ョ増鏈�' })
+  async check(@Query('version') version: string, @Query('type') type = 0) {
+    const result = await this.appVersionService.check(version, type);
+    return this.ok(result);
+  }
+}
diff --git a/src/modules/app/db.json b/src/modules/app/db.json
new file mode 100644
index 0000000..53fde8a
--- /dev/null
+++ b/src/modules/app/db.json
@@ -0,0 +1,124 @@
+{
+    "dict_type": [
+        {
+            "name": "鍗囩骇绫诲瀷",
+            "key": "upgradeType",
+            "@childDatas": {
+                "dict_info": [
+                    {
+                        "typeId": "@id",
+                        "name": "瀹夊崜",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "0"
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "IOS",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "1"
+                    }
+                ]
+            }
+        },
+        {
+            "name": "鎶曡瘔绫诲瀷",
+            "key": "complainType",
+            "@childDatas": {
+                "dict_info": [
+                    {
+                        "typeId": "@id",
+                        "name": "宕╂簝涓庨敊璇�",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "0"
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "鏀粯闂",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "1"
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "浣撻獙涓嶄匠",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "2"
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "鍔熻兘缂哄け",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "3"
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "鍏朵粬",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null,
+                        "value": "4"
+                    }
+                ]
+            }
+        },
+        {
+            "name": "鍙嶉绫诲瀷",
+            "key": "feedbackType",
+            "@childDatas": {
+                "dict_info": [
+                    {
+                        "typeId": "@id",
+                        "name": "宕╂簝涓庨敊璇�",
+                        "value": "0",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "鏀粯闂",
+                        "value": "1",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "浣撻獙涓嶄匠",
+                        "value": "2",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "鍔熻兘缂哄け",
+                        "value": "3",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null
+                    },
+                    {
+                        "typeId": "@id",
+                        "name": "鍏朵粬",
+                        "value": "-1",
+                        "orderNum": 1,
+                        "remark": null,
+                        "parentId": null
+                    }
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/modules/app/entity/complain.ts b/src/modules/app/entity/complain.ts
new file mode 100644
index 0000000..bfb52c6
--- /dev/null
+++ b/src/modules/app/entity/complain.ts
@@ -0,0 +1,34 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+
+/**
+ * 涓炬姤鎶曡瘔
+ */
+@Entity('app_complain')
+export class AppComplainEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Column({ comment: '绫诲瀷' })
+  type: number;
+
+  @Column({ comment: '鑱旂郴鏂瑰紡' })
+  contact: string;
+
+  @Column({ comment: '鍐呭' })
+  content: string;
+
+  @Column({ comment: '鍥剧墖', type: 'json', nullable: true })
+  images: string[];
+
+  @Column({ comment: '鐘舵�� 0-鏈鐞� 1-宸插鐞�', default: 0 })
+  status: number;
+
+  @Column({ comment: '澶勭悊浜篒D', nullable: true })
+  handlerId: number;
+
+  @Column({ comment: '澶囨敞', type: 'text', nullable: true })
+  remark: string;
+}
diff --git a/src/modules/app/entity/feedback.ts b/src/modules/app/entity/feedback.ts
new file mode 100644
index 0000000..5c5be76
--- /dev/null
+++ b/src/modules/app/entity/feedback.ts
@@ -0,0 +1,33 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@Entity('app_feedback')
+export class AppFeedbackEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Column({ comment: '鑱旂郴鏂瑰紡' })
+  contact: string;
+
+  @Column({ comment: '绫诲瀷' })
+  type: number;
+
+  @Column({ comment: '鍐呭' })
+  content: string;
+
+  @Column({ comment: '鍥剧墖', type: 'json', nullable: true })
+  images: string[];
+
+  @Column({ comment: '鐘舵�� 0-鏈鐞� 1-宸插鐞�', default: 0 })
+  status: number;
+
+  @Column({ comment: '澶勭悊浜篒D', nullable: true })
+  handlerId: number;
+
+  @Column({ comment: '澶囨敞', type: 'text', nullable: true })
+  remark: string;
+}
diff --git a/src/modules/app/entity/goods.ts b/src/modules/app/entity/goods.ts
new file mode 100644
index 0000000..1ad6287
--- /dev/null
+++ b/src/modules/app/entity/goods.ts
@@ -0,0 +1,48 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity } from 'typeorm';
+
+/**
+ * 濂楅
+ */
+@Entity('app_goods')
+export class AppGoodsEntity extends BaseEntity {
+  @Column({ comment: '鏍囬' })
+  title: string;
+
+  @Column({
+    comment: '浠锋牸',
+    type: 'decimal',
+    precision: 12,
+    scale: 2,
+  })
+  price: number;
+
+  @Column({
+    comment: '鍘熶环',
+    type: 'decimal',
+    precision: 12,
+    scale: 2,
+  })
+  originalPrice: number;
+
+  @Column({ comment: '鎻忚堪', type: 'text', nullable: true })
+  description: string;
+
+  @Column({ comment: '鐘舵�� 0-绂佺敤 1-鍚敤', default: 1 })
+  status: number;
+
+  @Column({ comment: '鎺掑簭', default: 0 })
+  sort: number;
+
+  @Column({ comment: '绫诲瀷 0-澶� 1-鏈� 2-骞� 3-姘镐箙', default: 0 })
+  type: number;
+
+  @Column({ comment: '鏃堕暱', default: 1 })
+  duration: number;
+
+  @Column({ comment: '鏍囩', nullable: true })
+  tag: string;
+
+  @Column({ comment: '鏍囩棰滆壊', default: '#26A7FD' })
+  tagColor: string;
+}
diff --git a/src/modules/app/entity/version.ts b/src/modules/app/entity/version.ts
new file mode 100644
index 0000000..fa8c39a
--- /dev/null
+++ b/src/modules/app/entity/version.ts
@@ -0,0 +1,32 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity } from 'typeorm';
+
+/**
+ * 搴旂敤鐗堟湰
+ */
+@Entity('app_version')
+export class AppVersionEntity extends BaseEntity {
+  @Column({ comment: '鍚嶇О' })
+  name: string;
+
+  @Column({ comment: '鐗堟湰鍙�' })
+  version: string;
+
+  @Column({ comment: '绫诲瀷', default: 0 })
+  type: number;
+
+  @Column({ comment: '涓嬭浇鍦板潃' })
+  url: string;
+
+  @Column({ comment: '寮哄埗鏇存柊 0-鍚� 1-鏄�', default: 0 })
+  forceUpdate: number;
+
+  @Column({ comment: '鐘舵�� 0-绂佺敤 1-鍚敤', default: 1 })
+  status: number;
+
+  @Column({ comment: '鐑洿鏂� 0-鍚� 1-鏄�', default: 0 })
+  hotUpdate: number;
+
+  @Column({ comment: '鎻忚堪', type: 'text' })
+  description: string;
+}
diff --git a/src/modules/app/menu.json b/src/modules/app/menu.json
new file mode 100644
index 0000000..2906595
--- /dev/null
+++ b/src/modules/app/menu.json
@@ -0,0 +1,270 @@
+[
+    {
+        "name": "搴旂敤绠$悊",
+        "router": null,
+        "perms": null,
+        "type": 0,
+        "icon": "icon-app",
+        "orderNum": 4,
+        "viewPath": null,
+        "keepAlive": true,
+        "isShow": true,
+        "childMenus": [
+            {
+                "name": "鐗堟湰绠$悊",
+                "router": "/app/version",
+                "perms": null,
+                "type": 1,
+                "icon": "icon-tag",
+                "orderNum": 0,
+                "viewPath": "modules/app/views/version.vue",
+                "keepAlive": true,
+                "isShow": true,
+                "childMenus": [
+                    {
+                        "name": "鍒犻櫎",
+                        "router": null,
+                        "perms": "app:version:delete",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "淇敼",
+                        "router": null,
+                        "perms": "app:version:update,app:version:info",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍗曚釜淇℃伅",
+                        "router": null,
+                        "perms": "app:version:info",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍒楄〃鏌ヨ",
+                        "router": null,
+                        "perms": "app:version:list",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍒嗛〉鏌ヨ",
+                        "router": null,
+                        "perms": "app:version:page",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鏂板",
+                        "router": null,
+                        "perms": "app:version:add",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    }
+                ]
+            },
+            {
+                "name": "鎰忚鍙嶉",
+                "router": "/app/feedback",
+                "perms": null,
+                "type": 1,
+                "icon": "icon-info",
+                "orderNum": 0,
+                "viewPath": "modules/app/views/feedback.vue",
+                "keepAlive": true,
+                "isShow": true,
+                "childMenus": [
+                    {
+                        "name": "鍒犻櫎",
+                        "router": null,
+                        "perms": "app:feedback:delete",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "淇敼",
+                        "router": null,
+                        "perms": "app:feedback:update,app:feedback:info",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍗曚釜淇℃伅",
+                        "router": null,
+                        "perms": "app:feedback:info",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍒楄〃鏌ヨ",
+                        "router": null,
+                        "perms": "app:feedback:list",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍒嗛〉鏌ヨ",
+                        "router": null,
+                        "perms": "app:feedback:page",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鏂板",
+                        "router": null,
+                        "perms": "app:feedback:add",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    }
+                ]
+            },
+            {
+                "name": "鎶曡瘔涓炬姤",
+                "router": "/app/complain",
+                "perms": null,
+                "type": 1,
+                "icon": "icon-new",
+                "orderNum": 0,
+                "viewPath": "modules/app/views/complain.vue",
+                "keepAlive": true,
+                "isShow": true,
+                "childMenus": [
+                    {
+                        "name": "鍒犻櫎",
+                        "router": null,
+                        "perms": "app:complain:delete",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "淇敼",
+                        "router": null,
+                        "perms": "app:complain:update,app:complain:info",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍗曚釜淇℃伅",
+                        "router": null,
+                        "perms": "app:complain:info",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍒楄〃鏌ヨ",
+                        "router": null,
+                        "perms": "app:complain:list",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鍒嗛〉鏌ヨ",
+                        "router": null,
+                        "perms": "app:complain:page",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    },
+                    {
+                        "name": "鏂板",
+                        "router": null,
+                        "perms": "app:complain:add",
+                        "type": 2,
+                        "icon": null,
+                        "orderNum": 0,
+                        "viewPath": null,
+                        "keepAlive": true,
+                        "isShow": true,
+                        "childMenus": []
+                    }
+                ]
+            }
+        ]
+    }
+]
\ No newline at end of file
diff --git a/src/modules/app/package.json b/src/modules/app/package.json
new file mode 100644
index 0000000..726d311
--- /dev/null
+++ b/src/modules/app/package.json
@@ -0,0 +1,5 @@
+{
+    "dependencies": {
+        "semver": "^7.5.4"
+    }
+}
\ No newline at end of file
diff --git a/src/modules/app/service/complain.ts b/src/modules/app/service/complain.ts
new file mode 100644
index 0000000..e92c46e
--- /dev/null
+++ b/src/modules/app/service/complain.ts
@@ -0,0 +1,36 @@
+import { Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { AppComplainEntity } from '../entity/complain';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@Provide()
+export class AppComplainService extends BaseService {
+  @InjectEntityModel(AppComplainEntity)
+  appComplainEntity: Repository<AppComplainEntity>;
+
+  @Inject()
+  ctx;
+
+  /**
+   * 鎻愪氦
+   * @param info
+   */
+  async submit(info: AppComplainEntity) {
+    await this.appComplainEntity.insert(info);
+  }
+
+  /**
+   * 鏇存柊
+   * @param param
+   */
+  async update(param: AppComplainEntity) {
+    if (param.status == 1) {
+      param.handlerId = this.ctx.admin.userId;
+    }
+    await super.update(param);
+  }
+}
diff --git a/src/modules/app/service/feedback.ts b/src/modules/app/service/feedback.ts
new file mode 100644
index 0000000..09f3d10
--- /dev/null
+++ b/src/modules/app/service/feedback.ts
@@ -0,0 +1,36 @@
+import { Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { AppFeedbackEntity } from '../entity/feedback';
+
+/**
+ * 鎰忚鍙嶉
+ */
+@Provide()
+export class AppFeedbackService extends BaseService {
+  @InjectEntityModel(AppFeedbackEntity)
+  appFeedbackEntity: Repository<AppFeedbackEntity>;
+
+  @Inject()
+  ctx;
+
+  /**
+   * 鎻愪氦
+   * @param info
+   */
+  async submit(info: AppFeedbackEntity) {
+    await this.appFeedbackEntity.insert(info);
+  }
+
+  /**
+   * 鏇存柊
+   * @param param
+   */
+  async update(param: AppFeedbackEntity) {
+    if (param.status == 1) {
+      param.handlerId = this.ctx.admin.userId;
+    }
+    await super.update(param);
+  }
+}
diff --git a/src/modules/app/service/version.ts b/src/modules/app/service/version.ts
new file mode 100644
index 0000000..349ab31
--- /dev/null
+++ b/src/modules/app/service/version.ts
@@ -0,0 +1,45 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Not, Repository } from 'typeorm';
+import { AppVersionEntity } from '../entity/version';
+import * as semver from 'semver';
+
+/**
+ * 搴旂敤鐗堟湰
+ */
+@Provide()
+export class AppVersionService extends BaseService {
+  @InjectEntityModel(AppVersionEntity)
+  appVersionEntity: Repository<AppVersionEntity>;
+
+  /**
+   * 妫�鏌ユ洿鏂�
+   * @param version
+   */
+  async check(version: string, type = 0) {
+    const info = await this.appVersionEntity.findOneBy({ type, status: 1 });
+    if (info && semver.gt(info.version, version)) {
+      return info;
+    }
+    return;
+  }
+
+  /**
+   * 淇敼涔嬪悗
+   * @param data
+   * @param type
+   */
+  async modifyAfter(data: any, type: 'add' | 'update' | 'delete') {
+    if (type == 'add' || type == 'update') {
+      const info = await this.appVersionEntity.findOneBy({ id: data.id });
+      if (info.status == 1) {
+        // 灏嗗叾浠栫殑鐗堟湰璁剧疆涓虹鐢�
+        await this.appVersionEntity.update(
+          { type: info.type, id: Not(info.id) },
+          { status: 0 }
+        );
+      }
+    }
+  }
+}
diff --git a/src/modules/base/config.ts b/src/modules/base/config.ts
index 0218350..a419211 100644
--- a/src/modules/base/config.ts
+++ b/src/modules/base/config.ts
@@ -21,17 +21,17 @@
     // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
     order: 10,
     // app鍙傛暟閰嶇疆鍏佽璇诲彇鐨刱ey
-    allowKeys: [],
+    allowKeys: ['privacyPolicy', 'userAgreement'],
     // jwt 鐢熸垚瑙e瘑token鐨�
     jwt: {
       // 鍗曠偣鐧诲綍
       sso: false,
       // 娉ㄦ剰锛� 鏈�濂介噸鏂颁慨鏀癸紝闃叉鐮磋В
-      secret: '9184c592-96a8-4db5-b722-65df1e892c83',
+      secret: '83cd61e9-8e10-4efb-8c48-af22d773d774',
       // token
       token: {
         // 2灏忔椂杩囨湡锛岄渶瑕佺敤鍒锋柊token
-        expire: 7 * 24 * 3600,
+        expire: 2 * 24 * 3600,
         // 15澶╁唴锛屽鏋滄病鎿嶄綔杩囧氨闇�瑕侀噸鏂扮櫥褰�
         refreshExpire: 24 * 3600 * 15,
       },
diff --git a/src/modules/base/controller/admin/sys/param.ts b/src/modules/base/controller/admin/sys/param.ts
index 6c3ac88..70da1d4 100644
--- a/src/modules/base/controller/admin/sys/param.ts
+++ b/src/modules/base/controller/admin/sys/param.ts
@@ -32,7 +32,7 @@
     this.ctx.body = await this.baseSysParamService.htmlByKey(key);
   }
 
-  @Get('/stringbykey', { summary: '鑾峰緱缃戦〉鍐呭鐨勫弬鏁板��' })
+   @Get('/stringbykey', { summary: '鑾峰緱缃戦〉鍐呭鐨勫弬鏁板��' })
   async stringByKey(@Query('key') key: string) {
     this.ctx.body = await this.baseSysParamService.getByKey(key);
   }
diff --git a/src/modules/base/db.json b/src/modules/base/db.json
index 285598a..f5c591c 100644
--- a/src/modules/base/db.json
+++ b/src/modules/base/db.json
@@ -1,31 +1,31 @@
 {
   "base_sys_param": [
       {
-          "keyName": "rich",
-          "name": "瀵屾枃鏈弬鏁�",
-          "data": "<h3><strong>杩欐槸涓�涓瘜鏂囨湰</strong></h3><p>xxx</p><p>xxxxxxxxxx</p><p><br></p>",
+          "keyName": "orderTimeout",
+          "name": "璁㈠崟瓒呮椂鏃堕棿",
+          "data": "120",
+          "dataType": 0,
+          "remark": "璁㈠崟瓒呮椂鏈敮浠橈紝鑷姩鍏抽棴銆傚崟浣嶏細鍒嗛挓"
+      },
+      {
+          "keyName": "orderConfirm",
+          "name": "鑷姩纭鏀惰揣",
+          "data": "15",
+          "dataType": 0,
+          "remark": "鑷姩纭鏀惰揣鏃堕棿锛屼粠鏀粯鎴愬姛璧风畻锛屽崟浣嶏細澶�"
+      },
+      {
+          "keyName": "userAgreement",
+          "name": "鐢ㄦ埛鍗忚",
+          "data": "<h3 style=\"text-align: center;\"><strong>鐢ㄦ埛鍗忚</strong></h3><p><br></p><p>xxxxxx</p>",
           "dataType": 1,
           "remark": null
       },
       {
-          "keyName": "json",
-          "name": "JSON鍙傛暟",
-          "data": "{\n  \"code\": 111233\n}",
-          "dataType": 0,
-          "remark": null
-      },
-      {
-          "keyName": "file",
-          "name": "鏂囦欢",
-          "data": "",
-          "dataType": 2,
-          "remark": null
-      },
-      {
-          "keyName": "text",
-          "name": "娴嬭瘯",
-          "data": "杩欐槸涓�娈靛瓧绗︿覆",
-          "dataType": 0,
+          "keyName": "privacyPolicy",
+          "name": "闅愮鏀跨瓥",
+          "data": "<h3 style=\"text-align: center;\"><strong>闅愮鏀跨瓥</strong></h3><p><br></p><p>xxxxxx</p>",
+          "dataType": 1,
           "remark": null
       }
   ],
@@ -86,6 +86,7 @@
           "password": "e10adc3949ba59abbe56e057f20f883e",
           "passwordV": 7,
           "nickName": "绠$悊鍛�",
+          "headImg": "https://cool-js.com/admin/headimg.jpg",
           "phone": "18000000000",
           "email": "team@cool-js.com",
           "status": 1,
@@ -99,4 +100,4 @@
           "roleId": 1
       }
   ]
-}
\ No newline at end of file
+}
diff --git a/src/modules/base/db/tenant.ts b/src/modules/base/db/tenant.ts
index 5b121c5..9683b85 100644
--- a/src/modules/base/db/tenant.ts
+++ b/src/modules/base/db/tenant.ts
@@ -163,9 +163,8 @@
     const tenantId = this.getTenantId();
     if (tenantId) {
       queryBuilder.andWhere(
-        `${
-          queryBuilder.alias ? queryBuilder.alias + '.' : ''
-        }tenantId = '${tenantId}'`
+        `${queryBuilder.alias ? queryBuilder.alias + '.' : ''
+        }tenantId = ${tenantId}`
       );
     }
   }
@@ -195,6 +194,7 @@
     if (!this.tenant?.enable) return;
     const tenantId = this.getTenantId();
     if (tenantId) {
+      //queryBuilder.set({ tenantId });
       queryBuilder.andWhere(`tenantId = '${tenantId}'`);
     }
   }
diff --git a/src/modules/base/entity/sys/log.ts b/src/modules/base/entity/sys/log.ts
index fd298a5..1581c42 100644
--- a/src/modules/base/entity/sys/log.ts
+++ b/src/modules/base/entity/sys/log.ts
@@ -1,4 +1,4 @@
-import { BaseEntity, transformerJson } from '../base';
+import { BaseEntity,transformerJson } from '../base';
 import { Column, Index, Entity } from 'typeorm';
 
 /**
@@ -18,11 +18,6 @@
   @Column({ comment: 'ip', nullable: true })
   ip: string;
 
-  @Column({
-    comment: '鍙傛暟',
-    nullable: true,
-    type: 'json',
-    transformer: transformerJson,
-  })
+  @Column({ comment: '鍙傛暟', nullable: true, type: 'json',transformer: transformerJson, })
   params: string;
 }
diff --git a/src/modules/base/menu.json b/src/modules/base/menu.json
index ac91af3..9fb7d42 100644
--- a/src/modules/base/menu.json
+++ b/src/modules/base/menu.json
@@ -1,943 +1,1559 @@
 [
-    {
-        "name": "绯荤粺绠$悊",
-        "router": "/sys",
-        "perms": null,
-        "type": 0,
-        "icon": "icon-set",
-        "orderNum": 2,
-        "viewPath": null,
-        "keepAlive": true,
-        "isShow": true,
-        "childMenus": [
-            {
-                "name": "鏉冮檺绠$悊",
-                "router": null,
-                "perms": null,
-                "type": 0,
-                "icon": "icon-auth",
-                "orderNum": 1,
-                "viewPath": null,
-                "keepAlive": false,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "鑿滃崟鍒楄〃",
-                        "router": "/sys/menu",
-                        "perms": null,
-                        "type": 1,
-                        "icon": "icon-menu",
-                        "orderNum": 2,
-                        "viewPath": "modules/base/views/menu/index.vue",
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": [
-                            {
-                                "name": "鏂板",
-                                "router": null,
-                                "perms": "base:sys:menu:add",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 1,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鍒犻櫎",
-                                "router": null,
-                                "perms": "base:sys:menu:delete",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 2,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏌ヨ",
-                                "router": null,
-                                "perms": "base:sys:menu:page,base:sys:menu:list,base:sys:menu:info",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 4,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鍙傛暟",
-                                "router": "/test/aa",
-                                "perms": null,
-                                "type": 1,
-                                "icon": "icon-goods",
-                                "orderNum": 0,
-                                "viewPath": "modules/base/views/info.vue",
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "缂栬緫",
-                                "router": null,
-                                "perms": "base:sys:menu:info,base:sys:menu:update",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            }
-                        ]
-                    },
-                    {
-                        "name": "瑙掕壊鍒楄〃",
-                        "router": "/sys/role",
-                        "perms": null,
-                        "type": 1,
-                        "icon": "icon-dept",
-                        "orderNum": 3,
-                        "viewPath": "cool/modules/base/views/role.vue",
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": [
-                            {
-                                "name": "鏂板",
-                                "router": null,
-                                "perms": "base:sys:role:add",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 1,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鍒犻櫎",
-                                "router": null,
-                                "perms": "base:sys:role:delete",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 2,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "淇敼",
-                                "router": null,
-                                "perms": "base:sys:role:update",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 3,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏌ヨ",
-                                "router": null,
-                                "perms": "base:sys:role:page,base:sys:role:list,base:sys:role:info",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 4,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            }
-                        ]
-                    },
-                    {
-                        "name": "鐢ㄦ埛鍒楄〃",
-                        "router": "/sys/user",
-                        "perms": null,
-                        "type": 1,
-                        "icon": "icon-user",
-                        "orderNum": 0,
-                        "viewPath": "modules/base/views/user/index.vue",
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": [
-                            {
-                                "name": "閮ㄩ棬鍒楄〃",
-                                "router": null,
-                                "perms": "base:sys:department:list",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏂板閮ㄩ棬",
-                                "router": null,
-                                "perms": "base:sys:department:add",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏇存柊閮ㄩ棬",
-                                "router": null,
-                                "perms": "base:sys:department:update",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鍒犻櫎閮ㄩ棬",
-                                "router": null,
-                                "perms": "base:sys:department:delete",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "閮ㄩ棬鎺掑簭",
-                                "router": null,
-                                "perms": "base:sys:department:order",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鐢ㄦ埛杞Щ",
-                                "router": null,
-                                "perms": "base:sys:user:move",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏂板",
-                                "router": null,
-                                "perms": "base:sys:user:add",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鍒犻櫎",
-                                "router": null,
-                                "perms": "base:sys:user:delete",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "淇敼",
-                                "router": null,
-                                "perms": "base:sys:user:delete,base:sys:user:update",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏌ヨ",
-                                "router": null,
-                                "perms": "base:sys:user:page,base:sys:user:list,base:sys:user:info",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            }
-                        ]
-                    }
-                ]
-            },
-            {
-                "name": "鍙傛暟閰嶇疆",
-                "router": null,
-                "perms": null,
-                "type": 0,
-                "icon": "icon-params",
-                "orderNum": 3,
-                "viewPath": null,
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "鍙傛暟鍒楄〃",
-                        "router": "/sys/param",
-                        "perms": null,
-                        "type": 1,
-                        "icon": "icon-menu",
-                        "orderNum": 0,
-                        "viewPath": "cool/modules/base/views/param.vue",
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": [
-                            {
-                                "name": "鏂板",
-                                "router": null,
-                                "perms": "base:sys:param:add",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "淇敼",
-                                "router": null,
-                                "perms": "base:sys:param:info,base:sys:param:update",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鍒犻櫎",
-                                "router": null,
-                                "perms": "base:sys:param:delete",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            },
-                            {
-                                "name": "鏌ョ湅",
-                                "router": null,
-                                "perms": "base:sys:param:page,base:sys:param:list,base:sys:param:info",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            }
-                        ]
-                    }
-                ]
-            },
-            {
-                "name": "鐩戞帶绠$悊",
-                "router": null,
-                "perms": null,
-                "type": 0,
-                "icon": "icon-monitor",
-                "orderNum": 9,
-                "viewPath": null,
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "璇锋眰鏃ュ織",
-                        "router": "/sys/log",
-                        "perms": null,
-                        "type": 1,
-                        "icon": "icon-log",
-                        "orderNum": 1,
-                        "viewPath": "cool/modules/base/views/log.vue",
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": [
-                            {
-                                "name": "鏉冮檺",
-                                "router": null,
-                                "perms": "base:sys:log:page,base:sys:log:clear,base:sys:log:getKeep,base:sys:log:setKeep",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 1,
-                                "viewPath": null,
-                                "keepAlive": false,
-                                "isShow": true,
-                                "childMenus": []
-                            }
-                        ]
-                    }
-                ]
-            },
-            {
-                "name": "浠诲姟绠$悊",
-                "router": null,
-                "perms": null,
-                "type": 0,
-                "icon": "icon-activity",
-                "orderNum": 9,
-                "viewPath": null,
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "浠诲姟鍒楄〃",
-                        "router": "/task/list",
-                        "perms": null,
-                        "type": 1,
-                        "icon": "icon-menu",
-                        "orderNum": 0,
-                        "viewPath": "modules/task/views/list.vue",
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": [
-                            {
-                                "name": "鏉冮檺",
-                                "router": null,
-                                "perms": "task:info:page,task:info:list,task:info:info,task:info:add,task:info:delete,task:info:update,task:info:stop,task:info:start,task:info:once,task:info:log",
-                                "type": 2,
-                                "icon": null,
-                                "orderNum": 0,
-                                "viewPath": null,
-                                "keepAlive": true,
-                                "isShow": true,
-                                "childMenus": []
-                            }
-                        ]
-                    }
-                ]
-            }
-        ]
-    },
-    {
-        "name": "妗嗘灦鏁欑▼",
-        "router": "/tutorial",
-        "perms": null,
-        "type": 0,
-        "icon": "icon-task",
-        "orderNum": 98,
-        "viewPath": null,
-        "keepAlive": true,
-        "isShow": true,
-        "childMenus": [
-            {
-                "name": "鏂囨。瀹樼綉",
-                "router": "/tutorial/doc",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-log",
-                "orderNum": 0,
-                "viewPath": "https://admin.cool-js.com",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": []
-            },
-            {
-                "name": "crud 绀轰緥",
-                "router": "/demo/crud",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-favor",
-                "orderNum": 1,
-                "viewPath": "modules/demo/views/crud/index.vue",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": []
-            }
-        ]
-    },
-    {
-        "name": "閫氱敤",
-        "router": null,
-        "perms": null,
-        "type": 0,
-        "icon": "icon-radioboxfill",
-        "orderNum": 99,
-        "viewPath": null,
-        "keepAlive": true,
-        "isShow": false,
-        "childMenus": [
-            {
-                "name": "鍥剧墖涓婁紶",
-                "router": null,
-                "perms": "space:info:page,space:info:list,space:info:info,space:info:add,space:info:delete,space:info:update,space:type:page,space:type:list,space:type:info,space:type:add,space:type:delete,space:type:update",
-                "type": 2,
-                "icon": null,
-                "orderNum": 1,
-                "viewPath": null,
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": []
-            }
-        ]
-    },
-    {
-        "name": "棣栭〉",
-        "router": "/",
-        "perms": null,
-        "type": 1,
-        "icon": null,
-        "orderNum": 0,
-        "viewPath": "modules/demo/views/home/index.vue",
-        "keepAlive": true,
-        "isShow": false,
-        "childMenus": []
-    },
-    {
-        "name": "鏁版嵁绠$悊",
-        "router": null,
-        "perms": null,
-        "type": 0,
-        "icon": "icon-data",
-        "orderNum": 7,
-        "viewPath": null,
-        "keepAlive": true,
-        "isShow": true,
-        "childMenus": [
-            {
-                "name": "瀛楀吀绠$悊",
-                "router": "/dict/list",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-dict",
-                "orderNum": 3,
-                "viewPath": "modules/dict/views/list.vue",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "鍒犻櫎",
-                        "router": null,
-                        "perms": "dict:info:delete",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "淇敼",
-                        "router": null,
-                        "perms": "dict:info:update,dict:info:info",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鑾峰緱瀛楀吀鏁版嵁",
-                        "router": null,
-                        "perms": "dict:info:data",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍗曚釜淇℃伅",
-                        "router": null,
-                        "perms": "dict:info:info",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍒楄〃鏌ヨ",
-                        "router": null,
-                        "perms": "dict:info:list",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍒嗛〉鏌ヨ",
-                        "router": null,
-                        "perms": "dict:info:page",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鏂板",
-                        "router": null,
-                        "perms": "dict:info:add",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "缁勬潈闄�",
-                        "router": null,
-                        "perms": "dict:type:list,dict:type:update,dict:type:delete,dict:type:add",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "瀛楀吀绫诲瀷",
-                        "router": null,
-                        "perms": "dict:type:delete,dict:type:update,dict:type:info,dict:type:list,dict:type:page,dict:type:add",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    }
-                ]
-            },
-            {
-                "name": "鏁版嵁鍥炴敹绔�",
-                "router": "/recycle/data",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-delete",
-                "orderNum": 6,
-                "viewPath": "modules/recycle/views/data.vue",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "鎭㈠鏁版嵁",
-                        "router": null,
-                        "perms": "recycle:data:restore",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍗曚釜淇℃伅",
-                        "router": null,
-                        "perms": "recycle:data:info",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍒嗛〉鏌ヨ",
-                        "router": null,
-                        "perms": "recycle:data:page",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    }
-                ]
-            },
-            {
-                "name": "鏂囦欢绠$悊",
-                "router": "/upload/list",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-log",
-                "orderNum": 5,
-                "viewPath": "modules/space/views/list.vue",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "鏉冮檺",
-                        "router": null,
-                        "perms": "space:type:delete,space:type:update,space:type:info,space:type:list,space:type:page,space:type:add,space:info:getConfig,space:info:delete,space:info:update,space:info:info,space:info:list,space:info:page,space:info:add",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    }
-                ]
-            }
-        ]
-    },
-    {
-        "name": "鐢ㄦ埛绠$悊",
-        "router": null,
-        "perms": null,
-        "type": 0,
-        "icon": "icon-user",
-        "orderNum": 11,
-        "viewPath": null,
-        "keepAlive": true,
-        "isShow": true,
-        "childMenus": [
-            {
-                "name": "鐢ㄦ埛鍒楄〃",
-                "router": "/user/list",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-menu",
-                "orderNum": 1,
-                "viewPath": "modules/user/views/list.vue",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "name": "鍒犻櫎",
-                        "router": null,
-                        "perms": "user:info:delete",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "淇敼",
-                        "router": null,
-                        "perms": "user:info:update,user:info:info",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍗曚釜淇℃伅",
-                        "router": null,
-                        "perms": "user:info:info",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍒楄〃鏌ヨ",
-                        "router": null,
-                        "perms": "user:info:list",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鍒嗛〉鏌ヨ",
-                        "router": null,
-                        "perms": "user:info:page",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "name": "鏂板",
-                        "router": null,
-                        "perms": "user:info:add",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    }
-                ]
-            }
-        ]
-    },
-    {
-        "name": "鎵╁睍绠$悊",
-        "router": null,
-        "perms": null,
-        "type": 0,
-        "icon": "icon-favor",
-        "orderNum": 8,
-        "viewPath": null,
-        "keepAlive": true,
-        "isShow": true,
-        "childMenus": [
-            {
-                "tenantId": null,
-                "name": "鎻掍欢鍒楄〃",
-                "router": "/helper/plugins",
-                "perms": null,
-                "type": 1,
-                "icon": "icon-list",
-                "orderNum": 1,
-                "viewPath": "modules/helper/views/plugins.vue",
-                "keepAlive": true,
-                "isShow": true,
-                "childMenus": [
-                    {
-                        "tenantId": null,
-                        "name": "鍒犻櫎",
-                        "router": null,
-                        "perms": "plugin:info:delete",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "tenantId": null,
-                        "name": "鍒嗛〉鏌ヨ",
-                        "router": null,
-                        "perms": "plugin:info:page",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "tenantId": null,
-                        "name": "鍗曚釜淇℃伅",
-                        "router": null,
-                        "perms": "plugin:info:info",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "tenantId": null,
-                        "name": "瀹夎鎻掍欢",
-                        "router": null,
-                        "perms": "plugin:info:install",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "tenantId": null,
-                        "name": "淇敼",
-                        "router": null,
-                        "perms": "plugin:info:update",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "tenantId": null,
-                        "name": "鍒楄〃鏌ヨ",
-                        "router": null,
-                        "perms": "plugin:info:list",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    },
-                    {
-                        "tenantId": null,
-                        "name": "鏂板",
-                        "router": null,
-                        "perms": "plugin:info:add",
-                        "type": 2,
-                        "icon": null,
-                        "orderNum": 0,
-                        "viewPath": null,
-                        "keepAlive": true,
-                        "isShow": true,
-                        "childMenus": []
-                    }
-                ]
-            }
-        ]
-    }
-]
\ No newline at end of file
+  {
+      "name": "绯荤粺绠$悊",
+      "router": "/sys",
+      "perms": null,
+      "type": 0,
+      "icon": "icon-system",
+      "orderNum": 9,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "鏉冮檺绠$悊",
+              "router": null,
+              "perms": null,
+              "type": 0,
+              "icon": "icon-auth",
+              "orderNum": 1,
+              "viewPath": null,
+              "keepAlive": false,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鑿滃崟鍒楄〃",
+                      "router": "/sys/menu",
+                      "perms": null,
+                      "type": 1,
+                      "icon": "icon-menu",
+                      "orderNum": 2,
+                      "viewPath": "modules/base/views/menu/index.vue",
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": [
+                          {
+                              "name": "鏂板",
+                              "router": null,
+                              "perms": "base:sys:menu:add",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 1,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鍒犻櫎",
+                              "router": null,
+                              "perms": "base:sys:menu:delete",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 2,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏌ヨ",
+                              "router": null,
+                              "perms": "base:sys:menu:page,base:sys:menu:list,base:sys:menu:info",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 4,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鍙傛暟",
+                              "router": "/test/aa",
+                              "perms": null,
+                              "type": 1,
+                              "icon": "icon-goods",
+                              "orderNum": 0,
+                              "viewPath": "modules/base/views/info.vue",
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "缂栬緫",
+                              "router": null,
+                              "perms": "base:sys:menu:info,base:sys:menu:update",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          }
+                      ]
+                  },
+                  {
+                      "name": "瑙掕壊鍒楄〃",
+                      "router": "/sys/role",
+                      "perms": null,
+                      "type": 1,
+                      "icon": "icon-dept",
+                      "orderNum": 3,
+                      "viewPath": "cool/modules/base/views/role.vue",
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": [
+                          {
+                              "name": "鏂板",
+                              "router": null,
+                              "perms": "base:sys:role:add",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 1,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鍒犻櫎",
+                              "router": null,
+                              "perms": "base:sys:role:delete",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 2,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "淇敼",
+                              "router": null,
+                              "perms": "base:sys:role:update",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 3,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏌ヨ",
+                              "router": null,
+                              "perms": "base:sys:role:page,base:sys:role:list,base:sys:role:info",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 4,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          }
+                      ]
+                  },
+                  {
+                      "name": "鐢ㄦ埛鍒楄〃",
+                      "router": "/sys/user",
+                      "perms": null,
+                      "type": 1,
+                      "icon": "icon-user",
+                      "orderNum": 0,
+                      "viewPath": "modules/base/views/user/index.vue",
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": [
+                          {
+                              "name": "閮ㄩ棬鍒楄〃",
+                              "router": null,
+                              "perms": "base:sys:department:list",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏂板閮ㄩ棬",
+                              "router": null,
+                              "perms": "base:sys:department:add",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏇存柊閮ㄩ棬",
+                              "router": null,
+                              "perms": "base:sys:department:update",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鍒犻櫎閮ㄩ棬",
+                              "router": null,
+                              "perms": "base:sys:department:delete",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "閮ㄩ棬鎺掑簭",
+                              "router": null,
+                              "perms": "base:sys:department:order",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鐢ㄦ埛杞Щ",
+                              "router": null,
+                              "perms": "base:sys:user:move",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏂板",
+                              "router": null,
+                              "perms": "base:sys:user:add",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鍒犻櫎",
+                              "router": null,
+                              "perms": "base:sys:user:delete",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "淇敼",
+                              "router": null,
+                              "perms": "base:sys:user:delete,base:sys:user:update",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏌ヨ",
+                              "router": null,
+                              "perms": "base:sys:user:page,base:sys:user:list,base:sys:user:info",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          }
+                      ]
+                  }
+              ]
+          },
+          {
+              "name": "鍙傛暟閰嶇疆",
+              "router": null,
+              "perms": null,
+              "type": 0,
+              "icon": "icon-params",
+              "orderNum": 3,
+              "viewPath": null,
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍙傛暟鍒楄〃",
+                      "router": "/sys/param",
+                      "perms": null,
+                      "type": 1,
+                      "icon": "icon-menu",
+                      "orderNum": 0,
+                      "viewPath": "cool/modules/base/views/param.vue",
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": [
+                          {
+                              "name": "鏂板",
+                              "router": null,
+                              "perms": "base:sys:param:add",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "淇敼",
+                              "router": null,
+                              "perms": "base:sys:param:info,base:sys:param:update",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鍒犻櫎",
+                              "router": null,
+                              "perms": "base:sys:param:delete",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          },
+                          {
+                              "name": "鏌ョ湅",
+                              "router": null,
+                              "perms": "base:sys:param:page,base:sys:param:list,base:sys:param:info",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          }
+                      ]
+                  }
+              ]
+          },
+          {
+              "name": "鐩戞帶绠$悊",
+              "router": null,
+              "perms": null,
+              "type": 0,
+              "icon": "icon-monitor",
+              "orderNum": 9,
+              "viewPath": null,
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "璇锋眰鏃ュ織",
+                      "router": "/sys/log",
+                      "perms": null,
+                      "type": 1,
+                      "icon": "icon-log",
+                      "orderNum": 1,
+                      "viewPath": "cool/modules/base/views/log.vue",
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": [
+                          {
+                              "name": "鏉冮檺",
+                              "router": null,
+                              "perms": "base:sys:log:page,base:sys:log:clear,base:sys:log:getKeep,base:sys:log:setKeep",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 1,
+                              "viewPath": null,
+                              "keepAlive": false,
+                              "isShow": true,
+                              "childMenus": []
+                          }
+                      ]
+                  }
+              ]
+          },
+          {
+              "name": "浠诲姟绠$悊",
+              "router": null,
+              "perms": null,
+              "type": 0,
+              "icon": "icon-activity",
+              "orderNum": 9,
+              "viewPath": null,
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "浠诲姟鍒楄〃",
+                      "router": "/task/list",
+                      "perms": null,
+                      "type": 1,
+                      "icon": "icon-menu",
+                      "orderNum": 0,
+                      "viewPath": "modules/task/views/list.vue",
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": [
+                          {
+                              "name": "鏉冮檺",
+                              "router": null,
+                              "perms": "task:info:page,task:info:list,task:info:info,task:info:add,task:info:delete,task:info:update,task:info:stop,task:info:start,task:info:once,task:info:log",
+                              "type": 2,
+                              "icon": null,
+                              "orderNum": 0,
+                              "viewPath": null,
+                              "keepAlive": true,
+                              "isShow": true,
+                              "childMenus": []
+                          }
+                      ]
+                  }
+              ]
+          }
+      ]
+  },
+  {
+      "name": "妗嗘灦鏁欑▼",
+      "router": "/tutorial",
+      "perms": null,
+      "type": 0,
+      "icon": "icon-task",
+      "orderNum": 98,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "鏂囨。瀹樼綉",
+              "router": "/tutorial/doc",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-log",
+              "orderNum": 0,
+              "viewPath": "https://admin.cool-js.com",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": []
+          },
+          {
+              "name": "crud 绀轰緥",
+              "router": "/demo/crud",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-favor",
+              "orderNum": 1,
+              "viewPath": "modules/demo/views/crud/index.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": []
+          }
+      ]
+  },
+  {
+      "name": "閫氱敤",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-radioboxfill",
+      "orderNum": 99,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": false,
+      "childMenus": [
+          {
+              "name": "鍥剧墖涓婁紶",
+              "router": null,
+              "perms": "space:info:page,space:info:list,space:info:info,space:info:add,space:info:delete,space:info:update,space:type:page,space:type:list,space:type:info,space:type:add,space:type:delete,space:type:update",
+              "type": 2,
+              "icon": null,
+              "orderNum": 1,
+              "viewPath": null,
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": []
+          }
+      ]
+  },
+  {
+      "name": "棣栭〉",
+      "router": "/",
+      "perms": null,
+      "type": 1,
+      "icon": null,
+      "orderNum": 0,
+      "viewPath": "modules/demo/views/home/index.vue",
+      "keepAlive": true,
+      "isShow": false,
+      "childMenus": []
+  },
+  {
+      "name": "鏁版嵁绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-data",
+      "orderNum": 7,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "瀛楀吀绠$悊",
+              "router": "/dict/list",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-dict",
+              "orderNum": 3,
+              "viewPath": "modules/dict/views/list.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "dict:info:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "dict:info:update,dict:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鑾峰緱瀛楀吀鏁版嵁",
+                      "router": null,
+                      "perms": "dict:info:data",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "dict:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "dict:info:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "dict:info:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "dict:info:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "缁勬潈闄�",
+                      "router": null,
+                      "perms": "dict:type:list,dict:type:update,dict:type:delete,dict:type:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "鏁版嵁鍥炴敹绔�",
+              "router": "/recycle/data",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-delete",
+              "orderNum": 6,
+              "viewPath": "modules/recycle/views/data.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鎭㈠鏁版嵁",
+                      "router": null,
+                      "perms": "recycle:data:restore",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "recycle:data:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "recycle:data:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "鏂囦欢绠$悊",
+              "router": "/upload/list",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-log",
+              "orderNum": 5,
+              "viewPath": "modules/space/views/list.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鏉冮檺",
+                      "router": null,
+                      "perms": "space:type:delete,space:type:update,space:type:info,space:type:list,space:type:page,space:type:add,space:info:getConfig,space:info:delete,space:info:update,space:info:info,space:info:list,space:info:page,space:info:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          }
+      ]
+  },
+  {
+      "name": "鐢ㄦ埛绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-user",
+      "orderNum": 11,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "鐢ㄦ埛鍒楄〃",
+              "router": "/user/list",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-menu",
+              "orderNum": 1,
+              "viewPath": "modules/user/views/list.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "user:info:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "user:info:update,user:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "user:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "user:info:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "user:info:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "user:info:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          }
+      ]
+  },
+  {
+      "name": "鎵╁睍绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-favor",
+      "orderNum": 8,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "鍚庣鎻掍欢",
+              "router": "/helper/plugins/serve",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-component",
+              "orderNum": 2,
+              "viewPath": "modules/helper/views/plugins.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鏉冮檺",
+                      "router": null,
+                      "perms": "plugin:info:install,plugin:info:delete,plugin:info:update,plugin:info:page,plugin:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          }
+      ]
+  },
+  {
+      "name": "鍟嗗搧绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-goods",
+      "orderNum": 1,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "鍟嗗搧鍒楄〃",
+              "router": "/goods/info",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-menu",
+              "orderNum": 1,
+              "viewPath": "modules/goods/views/info.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "goods:info:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "goods:info:update,goods:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "goods:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "goods:info:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "goods:info:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "goods:info:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "鍒嗙被鍒楄〃",
+              "router": "/goods/type",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-component",
+              "orderNum": 2,
+              "viewPath": "modules/goods/views/type.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "goods:type:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "goods:type:update,goods:type:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "goods:type:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "goods:type:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "goods:type:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "goods:type:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "璇勮鍒楄〃",
+              "router": "/goods/comment",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-message",
+              "orderNum": 3,
+              "viewPath": "modules/goods/views/comment.vue",
+              "keepAlive": false,
+              "isShow": false,
+              "childMenus": [
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "goods:comment:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "鎼滅储鍏抽敭璇�",
+              "router": "/goods/search-keyword",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-hot",
+              "orderNum": 4,
+              "viewPath": "modules/goods/views/search-keyword.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "goods:searchKeyword:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "goods:searchKeyword:update,goods:searchKeyword:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "goods:searchKeyword:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "goods:searchKeyword:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "goods:searchKeyword:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "goods:searchKeyword:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          }
+      ]
+  },
+  {
+      "name": "璁㈠崟绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-log",
+      "orderNum": 2,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "璁㈠崟鍒楄〃",
+              "router": "/order/info",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-menu",
+              "orderNum": 1,
+              "viewPath": "modules/order/views/info.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "閫�娆惧鐞�",
+                      "router": null,
+                      "perms": "order:info:refundHandle",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鐗╂祦淇℃伅",
+                      "router": null,
+                      "perms": "order:info:logistics",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍙戣揣",
+                      "router": null,
+                      "perms": "order:info:deliver",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "order:info:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "order:info:update,order:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "order:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "order:info:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "order:info:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "閫�娆惧垪琛�",
+              "router": "/order/refund",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-amount",
+              "orderNum": 2,
+              "viewPath": "modules/order/views/refund.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": []
+          }
+      ]
+  },
+  {
+      "name": "娲诲姩绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-activity",
+      "orderNum": 3,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "浼樻儬鍒稿垪琛�",
+              "router": "/market/coupon/info",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-activity",
+              "orderNum": 1,
+              "viewPath": "modules/market/views/coupon/info.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "market:coupon:info:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "market:coupon:info:update,market:coupon:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "market:coupon:info:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "market:coupon:info:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "market:coupon:info:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "market:coupon:info:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          },
+          {
+              "name": "棰嗗彇鍒楄〃",
+              "router": "/market/coupon/user",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-menu",
+              "orderNum": 2,
+              "viewPath": "modules/market/views/coupon/user.vue",
+              "keepAlive": false,
+              "isShow": false,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "market:coupon:user:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "market:coupon:user:update,market:coupon:user:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "market:coupon:user:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "market:coupon:user:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "market:coupon:user:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "market:coupon:user:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          }
+      ]
+  },
+  {
+      "name": "淇℃伅绠$悊",
+      "router": null,
+      "perms": null,
+      "type": 0,
+      "icon": "icon-dict",
+      "orderNum": 5,
+      "viewPath": null,
+      "keepAlive": true,
+      "isShow": true,
+      "childMenus": [
+          {
+              "name": "杞挱鍥惧垪琛�",
+              "router": "/info/banner",
+              "perms": null,
+              "type": 1,
+              "icon": "icon-pic",
+              "orderNum": 1,
+              "viewPath": "modules/info/views/banner.vue",
+              "keepAlive": true,
+              "isShow": true,
+              "childMenus": [
+                  {
+                      "name": "鍒犻櫎",
+                      "router": null,
+                      "perms": "info:banner:delete",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "淇敼",
+                      "router": null,
+                      "perms": "info:banner:update,info:banner:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍗曚釜淇℃伅",
+                      "router": null,
+                      "perms": "info:banner:info",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒楄〃鏌ヨ",
+                      "router": null,
+                      "perms": "info:banner:list",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鍒嗛〉鏌ヨ",
+                      "router": null,
+                      "perms": "info:banner:page",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  },
+                  {
+                      "name": "鏂板",
+                      "router": null,
+                      "perms": "info:banner:add",
+                      "type": 2,
+                      "icon": null,
+                      "orderNum": 0,
+                      "viewPath": null,
+                      "keepAlive": true,
+                      "isShow": true,
+                      "childMenus": []
+                  }
+              ]
+          }
+      ]
+  }
+]
diff --git a/src/modules/base/middleware/authority.ts b/src/modules/base/middleware/authority.ts
index 2515f94..d0fd5ed 100644
--- a/src/modules/base/middleware/authority.ts
+++ b/src/modules/base/middleware/authority.ts
@@ -17,8 +17,7 @@
  */
 @Middleware()
 export class BaseAuthorityMiddleware
-  implements IMiddleware<Context, NextFunction>
-{
+  implements IMiddleware<Context, NextFunction> {
   @Config('koa.globalPrefix')
   prefix;
 
@@ -68,7 +67,6 @@
               ? departmentIds
               : [];
           }
-
         } catch (error) { }
         // 浣跨敤matchUrl鏂规硶鏉ユ鏌RL鏄惁搴旇琚拷鐣�
         const isIgnored = this.ignoreUrls.some(pattern =>
diff --git a/src/modules/count/config.ts b/src/modules/count/config.ts
new file mode 100644
index 0000000..6412d7a
--- /dev/null
+++ b/src/modules/count/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '缁熻鍒嗘瀽',
+    // 妯″潡鎻忚堪
+    description: '璁㈠崟銆佸晢鍝併�佺敤鎴风瓑缁熻',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/count/controller/admin/home.ts b/src/modules/count/controller/admin/home.ts
new file mode 100644
index 0000000..f50bd08
--- /dev/null
+++ b/src/modules/count/controller/admin/home.ts
@@ -0,0 +1,69 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { Body, Inject, Post } from '@midwayjs/core';
+import { CountUserService } from '../../service/user';
+import { CountOrderService } from '../../service/order';
+import { CountGoodsService } from '../../service/goods';
+
+/**
+ * 棣栭〉缁熻
+ */
+@CoolController()
+export class AdminCountHomeController extends BaseController {
+  @Inject()
+  countUserService: CountUserService;
+
+  @Inject()
+  countOrderService: CountOrderService;
+
+  @Inject()
+  countGoodsService: CountGoodsService;
+
+  @Post('/userSummary', { summary: '鐢ㄦ埛姒傚喌' })
+  async userSummary() {
+    return this.ok(await this.countUserService.summary());
+  }
+
+  @Post('/userChart', { summary: '鐢ㄦ埛鍥捐〃' })
+  async userChart(
+    // 澶╂暟
+    @Body('dayCount') dayCount: number
+  ) {
+    return this.ok(await this.countUserService.chart(dayCount));
+  }
+
+  @Post('/orderSummary', { summary: '璁㈠崟姒傚喌' })
+  async orderSummary(
+    // 绫诲瀷 count-鏁伴噺 amount-閲戦
+    @Body('type') type: 'count' | 'amount'
+  ) {
+    return this.ok(await this.countOrderService.summary(type));
+  }
+
+  @Post('/orderChart', { summary: '璁㈠崟鍥捐〃' })
+  async orderChart(
+    // 澶╂暟
+    @Body('dayCount') dayCount: number,
+    // 绫诲瀷 count-鏁伴噺 amount-閲戦
+    @Body('type') type: 'count' | 'amount'
+  ) {
+    return this.ok(await this.countOrderService.chart(dayCount, type));
+  }
+
+  @Post('/goodsRank', { summary: '鍟嗗搧鎺掕' })
+  async goodsRank(
+    // 绫诲瀷 count-鏁伴噺 amount-閲戦
+    @Body('type') type: 'count' | 'amount',
+    // 鏉℃暟
+    @Body('limit') limit: number
+  ) {
+    return this.ok(await this.countGoodsService.rank(type, limit));
+  }
+
+  @Post('/goodsCategory', { summary: '鍟嗗搧鍒嗙被' })
+  async goodsCategory(
+    // 绫诲瀷 count-鏁伴噺 amount-閲戦
+    @Body('type') type: 'count' | 'amount'
+  ) {
+    return this.ok(await this.countGoodsService.category(type));
+  }
+}
diff --git a/src/modules/count/service/comm.ts b/src/modules/count/service/comm.ts
new file mode 100644
index 0000000..2de44fe
--- /dev/null
+++ b/src/modules/count/service/comm.ts
@@ -0,0 +1,71 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import * as moment from 'moment';
+import { Utils } from '../../../comm/utils';
+
+/**
+ * 閫氱敤
+ */
+@Provide()
+export class CountCommService extends BaseService {
+  @Inject()
+  utils: Utils;
+
+  /**
+   * 鑾峰緱鏃堕棿鑼冨洿
+   * @param unit
+   */
+  getTimeRange(unit: 'day' | 'week' | 'month' | 'year') {
+    let start, end;
+    if (unit === 'week') {
+      // 鍛ㄧ殑寮�濮嬫椂闂村姞涓�澶╋紝浠ュ尮閰嶆偍鐨勯渶姹�
+      start = moment()
+        .startOf(unit)
+        .add(1, 'days')
+        .format('YYYY-MM-DD HH:mm:ss');
+    } else {
+      start = moment().startOf(unit).format('YYYY-MM-DD HH:mm:ss');
+    }
+    end = moment().endOf(unit).format('YYYY-MM-DD HH:mm:ss');
+    return { start, end };
+  }
+
+  /**
+   * 鍥捐〃
+   * @param tableName
+   * @param dayCount
+   * @param column 缁熻鍒�
+   * @returns
+   */
+  async chart(tableName: string, dayCount: number, column = 'count(a.id)') {
+    const result = {
+      datas: [],
+      dates: [],
+    };
+    const dates = this.utils.getRecentlyDates(dayCount);
+    const count = await this.nativeQuery(
+      `SELECT
+              ${column} as total,
+              LEFT(a.createTime, 10) AS time
+         FROM
+          ${tableName} a
+         WHERE
+              DATE_SUB( CURDATE( ), INTERVAL ? DAY ) <= a.createTime
+         GROUP BY
+              LEFT(a.createTime, 10)`,
+      [dayCount]
+    );
+    dates.forEach(date => {
+      let data = 0;
+      for (const item of count) {
+        if (date == item.time) {
+          data = item.total;
+          break;
+        }
+      }
+      result.dates.push(date);
+      result.datas.push(data);
+    });
+    return result;
+  }
+}
diff --git a/src/modules/count/service/goods.ts b/src/modules/count/service/goods.ts
new file mode 100644
index 0000000..9636db8
--- /dev/null
+++ b/src/modules/count/service/goods.ts
@@ -0,0 +1,55 @@
+import { Init, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { OrderGoodsEntity } from '../../order/entity/goods';
+
+/**
+ * 鍟嗗搧缁熻
+ */
+@Provide()
+export class CountGoodsService extends BaseService {
+  @InjectEntityModel(OrderGoodsEntity)
+  orderGoodsEntity: Repository<OrderGoodsEntity>;
+
+  /**
+   * 閿�鍞帓琛�
+   * @param type 绫诲瀷 count-鏁伴噺 amount-閲戦
+   * @param limit 鏉℃暟
+   */
+  async rank(type: 'count' | 'amount', limit = 10) {
+    const sql = `SELECT * FROM (
+        SELECT
+        a.goodsId,
+        b.title,
+        b.mainPic,
+        ${type === 'count' ? 'SUM(a.count)' : 'SUM(a.price * a.count)'} AS total
+    FROM
+        order_goods a
+        LEFT JOIN goods_info b ON a.goodsId = b.id
+    GROUP BY
+        a.goodsId
+    ORDER BY
+        total DESC
+    ) a LIMIT ${parseInt(limit.toString())}`;
+    return this.nativeQuery(sql);
+  }
+
+  /**
+   * 鍒嗙被缁熻
+   * @param type 绫诲瀷 count-鏁伴噺 amount-閲戦
+   */
+  async category(type: 'count' | 'amount') {
+    const sql = `SELECT
+        b.typeId,
+        c.name AS typeName,
+        ${type === 'count' ? 'SUM(a.count)' : 'SUM(a.price * a.count)'} AS total
+    FROM
+        order_goods a
+        LEFT JOIN goods_info b ON a.goodsId = b.id
+        LEFT JOIN goods_type c ON b.typeId = c.id
+    GROUP BY
+        b.typeId`;
+    return this.nativeQuery(sql);
+  }
+}
diff --git a/src/modules/count/service/order.ts b/src/modules/count/service/order.ts
new file mode 100644
index 0000000..31e234c
--- /dev/null
+++ b/src/modules/count/service/order.ts
@@ -0,0 +1,94 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { OrderInfoEntity } from '../../order/entity/info';
+import { CountCommService } from './comm';
+
+/**
+ * 璁㈠崟缁熻
+ */
+@Provide()
+export class CountOrderService extends BaseService {
+  @InjectEntityModel(OrderInfoEntity)
+  orderInfoEntity: Repository<OrderInfoEntity>;
+
+  @Inject()
+  countCommService: CountCommService;
+
+  /**
+   * 姒傚喌
+   * @param type 绫诲瀷 count-鏁伴噺 amount-閲戦
+   * @returns
+   */
+  async summary(type: 'count' | 'amount' = 'count') {
+    // 瀹氫箟涓�涓嚱鏁版潵鍒涘缓鏌ヨ
+    const createQuery = async (start, end) => {
+      if (type === 'count') {
+        return await this.orderInfoEntity
+          .createQueryBuilder('a')
+          .where('a.createTime >= :start', { start })
+          .andWhere('a.createTime <= :end', { end })
+          .getCount();
+      }
+      if (type === 'amount') {
+        const result = await this.orderInfoEntity
+          .createQueryBuilder('a')
+          .select('SUM(a.price)', 'amount')
+          .where('a.createTime >= :start', { start })
+          .andWhere('a.createTime <= :end', { end })
+          .getRawOne();
+        return result.amount || 0;
+      }
+    };
+
+    // 鎬绘暟
+    const total = await (type == 'amount'
+      ? this.orderInfoEntity.sum('price')
+      : this.orderInfoEntity.count());
+
+    // 鑾峰彇浠婂ぉ鐨勬椂闂磋寖鍥�
+    const { start: todayStart, end: todayEnd } =
+      this.countCommService.getTimeRange('day');
+    // 浠婂ぉ
+    const today = await createQuery(todayStart, todayEnd);
+
+    // 鑾峰彇鏈懆鐨勬椂闂磋寖鍥�
+    const { start: weekStart, end: weekEnd } =
+      this.countCommService.getTimeRange('week');
+    // 鏈懆
+    const week = await createQuery(weekStart, weekEnd);
+
+    // 鑾峰彇鏈湀鐨勬椂闂磋寖鍥�
+    const { start: monthStart, end: monthEnd } =
+      this.countCommService.getTimeRange('month');
+    // 鏈湀
+    const month = await createQuery(monthStart, monthEnd);
+
+    // 鑾峰彇骞寸殑鏃堕棿鑼冨洿
+    const { start: yearStart, end: yearEnd } =
+      this.countCommService.getTimeRange('year');
+    // 浠婂勾
+    const year = await createQuery(yearStart, yearEnd);
+
+    return { total, today, week, month, year };
+  }
+
+  /**
+   * 鍥捐〃
+   * @param dayCount 鏈�杩戝灏戝ぉ
+   * @param type 绫诲瀷 count-鏁伴噺 amount-閲戦
+   */
+  async chart(dayCount = 30, type: 'count' | 'amount' = 'count') {
+    if (type == 'count') {
+      return await this.countCommService.chart('order_info', dayCount);
+    }
+    if (type == 'amount') {
+      return await this.countCommService.chart(
+        'order_info',
+        dayCount,
+        'SUM(a.price)'
+      );
+    }
+  }
+}
diff --git a/src/modules/count/service/user.ts b/src/modules/count/service/user.ts
new file mode 100644
index 0000000..50574d0
--- /dev/null
+++ b/src/modules/count/service/user.ts
@@ -0,0 +1,69 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { UserInfoEntity } from '../../user/entity/info';
+import { CountCommService } from './comm';
+
+/**
+ * 鐢ㄦ埛缁熻
+ */
+@Provide()
+export class CountUserService extends BaseService {
+  @InjectEntityModel(UserInfoEntity)
+  userInfoEntity: Repository<UserInfoEntity>;
+
+  @Inject()
+  countCommService: CountCommService;
+
+  /**
+   * 姒傚喌
+   */
+  async summary() {
+    // 瀹氫箟涓�涓嚱鏁版潵鍒涘缓鏌ヨ
+    const createQuery = async (start, end) => {
+      return await this.userInfoEntity
+        .createQueryBuilder('a')
+        .where('a.createTime >= :start', { start })
+        .andWhere('a.createTime <= :end', { end })
+        .getCount();
+    };
+
+    // 鎬绘暟
+    const total = await this.userInfoEntity.count();
+
+    // 鑾峰彇浠婂ぉ鐨勬椂闂磋寖鍥�
+    const { start: todayStart, end: todayEnd } =
+      this.countCommService.getTimeRange('day');
+    // 浠婂ぉ
+    const today = await createQuery(todayStart, todayEnd);
+
+    // 鑾峰彇鏈懆鐨勬椂闂磋寖鍥�
+    const { start: weekStart, end: weekEnd } =
+      this.countCommService.getTimeRange('week');
+    // 鏈懆
+    const week = await createQuery(weekStart, weekEnd);
+
+    // 鑾峰彇鏈湀鐨勬椂闂磋寖鍥�
+    const { start: monthStart, end: monthEnd } =
+      this.countCommService.getTimeRange('month');
+    // 鏈湀
+    const month = await createQuery(monthStart, monthEnd);
+
+    // 鑾峰彇骞寸殑鏃堕棿鑼冨洿
+    const { start: yearStart, end: yearEnd } =
+      this.countCommService.getTimeRange('year');
+    // 浠婂勾
+    const year = await createQuery(yearStart, yearEnd);
+
+    return { total, today, week, month, year };
+  }
+
+  /**
+   * 鍥捐〃
+   * @param dayCount 鏈�杩戝灏戝ぉ
+   */
+  async chart(dayCount = 30) {
+    return await this.countCommService.chart('user_info', dayCount);
+  }
+}
diff --git a/src/modules/cs/config.ts b/src/modules/cs/config.ts
new file mode 100644
index 0000000..78d2201
--- /dev/null
+++ b/src/modules/cs/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '瀹㈡湇妯″潡',
+    // 妯″潡鎻忚堪
+    description: '瀹㈡湇绯荤粺',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/cs/controller/admin/msg.ts b/src/modules/cs/controller/admin/msg.ts
new file mode 100644
index 0000000..19740c5
--- /dev/null
+++ b/src/modules/cs/controller/admin/msg.ts
@@ -0,0 +1,58 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { CsMsgEntity } from '../../entity/msg';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { BaseSysUserEntity } from '../../../base/entity/sys/user';
+import { CsMsgService } from '../../service/msg';
+import { Body, Get, Inject, Post } from '@midwayjs/core';
+
+/**
+ * 娑堟伅
+ */
+@CoolController({
+  api: ['page'],
+  entity: CsMsgEntity,
+  service: CsMsgService,
+  pageQueryOp: {
+    select: [
+      'a.*',
+      'b.nickName',
+      'b.avatarUrl',
+      'c.name as adminUserName',
+      'c.headImg as adminUserHeadImg',
+    ],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id and a.type = 0',
+      },
+      {
+        entity: BaseSysUserEntity,
+        alias: 'c',
+        condition: 'a.userId = c.id and a.type = 1',
+      },
+    ],
+    where: ctx => {
+      const { sessionId } = ctx.request.body;
+      return [['a.sessionId = :sessionId', { sessionId }]];
+    },
+  },
+})
+export class AdminCsMsgController extends BaseController {
+  @Inject()
+  ctx;
+
+  @Inject()
+  csMsgService: CsMsgService;
+
+  @Get('/unreadCount', { summary: '鏈娑堟伅鏁�' })
+  async unreadCount() {
+    return this.ok(await this.csMsgService.unreadCount(null, 0));
+  }
+
+  @Post('/read', { summary: '鏍囪宸茶' })
+  async read(@Body('msgIds') msgIds: number[]) {
+    this.csMsgService.read(msgIds);
+    return this.ok();
+  }
+}
diff --git a/src/modules/cs/controller/admin/session.ts b/src/modules/cs/controller/admin/session.ts
new file mode 100644
index 0000000..23817ca
--- /dev/null
+++ b/src/modules/cs/controller/admin/session.ts
@@ -0,0 +1,22 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { CsSessionEntity } from '../../entity/session';
+import { UserInfoEntity } from '../../../user/entity/info';
+
+/**
+ * 瀹㈡湇浼氳瘽
+ */
+@CoolController({
+  api: ['page'],
+  entity: CsSessionEntity,
+  pageQueryOp: {
+    select: ['a.*', 'b.nickName', 'b.avatarUrl'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+    ],
+  },
+})
+export class Controller extends BaseController {}
diff --git a/src/modules/cs/controller/app/msg.ts b/src/modules/cs/controller/app/msg.ts
new file mode 100644
index 0000000..9aea144
--- /dev/null
+++ b/src/modules/cs/controller/app/msg.ts
@@ -0,0 +1,62 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { CsMsgEntity } from '../../entity/msg';
+import { CsSessionEntity } from '../../entity/session';
+import { BaseSysUserEntity } from '../../../base/entity/sys/user';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { Body, Get, Inject, Post } from '@midwayjs/core';
+import { CsMsgService } from '../../service/msg';
+
+/**
+ * 娑堟伅
+ */
+@CoolController({
+  api: ['page'],
+  entity: CsMsgEntity,
+  pageQueryOp: {
+    select: [
+      'a.*',
+      'b.nickName',
+      'b.avatarUrl',
+      'c.name as adminUserName',
+      'c.headImg as adminUserHeadImg',
+    ],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id and a.type = 0',
+      },
+      {
+        entity: BaseSysUserEntity,
+        alias: 'c',
+        condition: 'a.userId = c.id and a.type = 1',
+      },
+      {
+        entity: CsSessionEntity,
+        alias: 'd',
+        condition: 'a.sessionId = d.id',
+      },
+    ],
+    where: ctx => {
+      return [['d.userId = :userId', { userId: ctx.user?.id }]];
+    },
+  },
+})
+export class AppCsMsgController extends BaseController {
+  @Inject()
+  ctx;
+
+  @Inject()
+  csMsgService: CsMsgService;
+
+  @Get('/unreadCount', { summary: '鏈娑堟伅鏁�' })
+  async unreadCount() {
+    return this.ok(await this.csMsgService.unreadCount(this.ctx.user?.id, 1));
+  }
+
+  @Post('/read', { summary: '鏍囪宸茶' })
+  async read(@Body('msgIds') msgIds: number[]) {
+    this.csMsgService.read(msgIds);
+    return this.ok();
+  }
+}
diff --git a/src/modules/cs/controller/app/session.ts b/src/modules/cs/controller/app/session.ts
new file mode 100644
index 0000000..fe73446
--- /dev/null
+++ b/src/modules/cs/controller/app/session.ts
@@ -0,0 +1,25 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { Get, Inject, Post } from '@midwayjs/core';
+import { CsSessionService } from '../../service/session';
+
+/**
+ * 瀹㈡湇浼氳瘽
+ */
+@CoolController()
+export class AppCsSessionController extends BaseController {
+  @Inject()
+  csSessionService: CsSessionService;
+
+  @Inject()
+  ctx;
+
+  @Get('/detail', { summary: '浼氳瘽璇︽儏' })
+  async detail() {
+    return this.ok(await this.csSessionService.detail(this.ctx.user?.id));
+  }
+
+  @Post('/create', { summary: '鍒涘缓浼氳瘽' })
+  async create() {
+    return this.ok(await this.csSessionService.create(this.ctx.user?.id));
+  }
+}
diff --git a/src/modules/cs/entity/conn.ts b/src/modules/cs/entity/conn.ts
new file mode 100644
index 0000000..7577b57
--- /dev/null
+++ b/src/modules/cs/entity/conn.ts
@@ -0,0 +1,18 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 瀹㈡湇杩炴帴
+ */
+@Entity('cs_conn')
+export class CsConnEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Column({ comment: '杩炴帴ID' })
+  connId: string;
+
+  @Column({ comment: '绫诲瀷 0-瀹㈡埛 1-鍚庡彴', default: 0 })
+  type: number;
+}
diff --git a/src/modules/cs/entity/msg.ts b/src/modules/cs/entity/msg.ts
new file mode 100644
index 0000000..c879769
--- /dev/null
+++ b/src/modules/cs/entity/msg.ts
@@ -0,0 +1,36 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 瀹㈡湇娑堟伅
+ */
+@Entity('cs_msg')
+export class CsMsgEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Index()
+  @Column({ comment: '浼氳瘽ID' })
+  sessionId: number;
+
+  @Column({ comment: '娑堟伅鍐呭', type: 'json' })
+  content: {
+    type:
+      | 'text'
+      | 'image'
+      | 'voice'
+      | 'video'
+      | 'file'
+      | 'link'
+      | 'location'
+      | 'emoji';
+    data: string;
+  };
+
+  @Column({ comment: '绫诲瀷 0-鍙嶉 1-鍥炲', default: 0 })
+  type: number;
+
+  @Column({ comment: '鐘舵�� 0-鏈 1-宸茶', default: 0 })
+  status: number;
+}
diff --git a/src/modules/cs/entity/session.ts b/src/modules/cs/entity/session.ts
new file mode 100644
index 0000000..8a83685
--- /dev/null
+++ b/src/modules/cs/entity/session.ts
@@ -0,0 +1,19 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+import { CsMsgEntity } from './msg';
+
+/**
+ * 瀹㈡湇浼氳瘽
+ */
+@Entity('cs_session')
+export class CsSessionEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Column({ comment: '鏈�鍚庝竴鏉℃秷鎭�', nullable: true, type: 'json' })
+  lastMsg: CsMsgEntity;
+
+  @Column({ comment: '瀹㈡湇鏈娑堟伅鏁�', default: 0 })
+  adminUnreadCount: number;
+}
diff --git a/src/modules/cs/menu.json b/src/modules/cs/menu.json
new file mode 100644
index 0000000..d2828cd
--- /dev/null
+++ b/src/modules/cs/menu.json
@@ -0,0 +1,27 @@
+[
+    {
+        "name": "瀹㈡湇妯″潡",
+        "router": null,
+        "perms": null,
+        "type": 0,
+        "icon": null,
+        "orderNum": 0,
+        "viewPath": null,
+        "keepAlive": true,
+        "isShow": false,
+        "childMenus": [
+            {
+                "name": "閫氱敤",
+                "router": null,
+                "perms": "cs:session:page,cs:session:update,cs:session:info,cs:session:list,cs:session:add,cs:msg:unreadCount,cs:msg:page,cs:msg:update,cs:msg:info,cs:msg:list,cs:msg:add",
+                "type": 2,
+                "icon": null,
+                "orderNum": 0,
+                "viewPath": null,
+                "keepAlive": true,
+                "isShow": true,
+                "childMenus": []
+            }
+        ]
+    }
+]
\ No newline at end of file
diff --git a/src/modules/cs/service/conn.ts b/src/modules/cs/service/conn.ts
new file mode 100644
index 0000000..8910e23
--- /dev/null
+++ b/src/modules/cs/service/conn.ts
@@ -0,0 +1,57 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { CsConnEntity } from '../entity/conn';
+import { CsSessionEntity } from '../entity/session';
+
+/**
+ * 杩炴帴
+ */
+@Provide()
+export class CsConnService extends BaseService {
+  @InjectEntityModel(CsConnEntity)
+  csConnEntity: Repository<CsConnEntity>;
+
+  @InjectEntityModel(CsSessionEntity)
+  csSessionEntity: Repository<CsSessionEntity>;
+
+  /**
+   * 缁戝畾
+   * @param isAdmin
+   * @param userId
+   * @param connId
+   */
+  async binding(isAdmin: boolean, userId: number, connId: string) {
+    const info = await this.csConnEntity.findOneBy({
+      userId,
+      type: isAdmin ? 1 : 0,
+    });
+    if (info) {
+      info.connId = connId;
+      info.type = isAdmin ? 1 : 0;
+      await this.csConnEntity.update(info.id, { connId: connId });
+    } else {
+      const entity = new CsConnEntity();
+      entity.userId = userId;
+      entity.connId = connId;
+      entity.type = isAdmin ? 1 : 0;
+      await this.csConnEntity.insert(entity);
+    }
+  }
+
+  /**
+   * 鑾峰緱杩炴帴ID
+   * @param isAdmin
+   * @param sessionId
+   */
+  async getConnId(isAdmin: boolean, sessionId: number) {
+    const session = await this.csSessionEntity.findOneBy({ id: sessionId });
+    if (!session) return;
+    const info = await this.csConnEntity.findOneBy({
+      userId: session.userId,
+      type: isAdmin ? 1 : 0,
+    });
+    return info ? info.connId : null;
+  }
+}
diff --git a/src/modules/cs/service/msg.ts b/src/modules/cs/service/msg.ts
new file mode 100644
index 0000000..5d68aca
--- /dev/null
+++ b/src/modules/cs/service/msg.ts
@@ -0,0 +1,140 @@
+import { App, Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { In, Repository } from 'typeorm';
+import { CsMsgEntity } from '../entity/msg';
+import { CsSessionEntity } from '../entity/session';
+import { CsConnService } from './conn';
+import { Application as SocketApplication } from '@midwayjs/socketio';
+import * as _ from 'lodash';
+import { UserInfoEntity } from '../../user/entity/info';
+import { BaseSysUserEntity } from '../../base/entity/sys/user';
+
+/**
+ * 娑堟伅
+ */
+@Provide()
+export class CsMsgService extends BaseService {
+  @InjectEntityModel(CsMsgEntity)
+  csMsgEntity: Repository<CsMsgEntity>;
+
+  @InjectEntityModel(CsSessionEntity)
+  csSessionEntity: Repository<CsSessionEntity>;
+
+  @InjectEntityModel(UserInfoEntity)
+  userInfoEntity: Repository<UserInfoEntity>;
+
+  @InjectEntityModel(BaseSysUserEntity)
+  baseSysUserEntity: Repository<BaseSysUserEntity>;
+
+  @Inject()
+  csConnService: CsConnService;
+
+  @App('socketIO')
+  socketApp: SocketApplication;
+
+  @Inject()
+  ctx;
+
+  /**
+   * 娑堟伅鏍囪涓哄凡璇�
+   * @param msgIds
+   */
+  async read(msgIds: number[]) {
+    await this.csMsgEntity.update({ id: In(msgIds) }, { status: 1 });
+  }
+
+  /**
+   * 鏈娑堟伅鏁�
+   * @param userId
+   * @param type
+   */
+  async unreadCount(userId: number, type: number) {
+    if (userId) {
+      return this.csMsgEntity.countBy({ userId, type, status: 0 });
+    }
+    return this.csMsgEntity.countBy({ type, status: 0 });
+  }
+
+  /**
+   * 鏇存柊瀹㈡埛鏈娑堟伅鏁�
+   * @param sessionId
+   */
+  async updateAdminUnreadCount(sessionId: number) {
+    const count = await this.csMsgEntity.countBy({
+      sessionId,
+      type: 0,
+      status: 0,
+    });
+    await this.csSessionEntity.update(sessionId, { adminUnreadCount: count });
+  }
+
+  /**
+   * 鍒嗛〉鏌ヨ
+   * @param query
+   * @param option
+   * @param connectionName
+   */
+  async page(query: any, option: any, connectionName?: any) {
+    const { sessionId } = query;
+    const result = await super.page(query, option, connectionName);
+    // 娑堟伅缃负宸茶
+    const type = this.ctx.user?.id ? 1 : 0;
+    await this.csMsgEntity.update({ sessionId, type }, { status: 1 });
+    // 鏇存柊鏈娑堟伅鏁�
+    await this.updateAdminUnreadCount(sessionId);
+
+    return result;
+  }
+
+  /**
+   * 娑堟伅鍙戦��
+   * @param msg
+   */
+  async send(msg: any, isAdmin: boolean) {
+    let session = await this.csSessionEntity.findOneBy({ id: msg.sessionId });
+    if (isAdmin) {
+      msg.type = 1;
+    } else {
+      msg.type = 0;
+      if (!session) {
+        session = new CsSessionEntity();
+        session.userId = msg.userId;
+        await this.csSessionEntity.insert(session);
+      }
+    }
+    await this.csMsgEntity.insert(msg);
+    // 鏇存柊鏈娑堟伅鏁�
+    await this.updateAdminUnreadCount(msg.sessionId);
+    // 鏇存柊鏈�鍚庝竴鏉℃秷鎭�
+    await this.csSessionEntity.update(session.id, { lastMsg: msg });
+
+    // 瀹屽杽娑堟伅鍐呭
+    if (msg.type == 0) {
+      const user = await this.userInfoEntity.findOneBy({ id: msg.userId });
+      msg.user = {
+        userId: user.id,
+        nickName: user.nickName,
+        avatarUrl: user.avatarUrl,
+      };
+    }
+    if (msg.type == 1) {
+      const user = await this.baseSysUserEntity.findOneBy({ id: msg.userId });
+      msg.user = {
+        userId: user.id,
+        nickName: user.name,
+        avatarUrl: user.headImg,
+      };
+    }
+    // 鍙戦�佺粰瀹㈡埛绔�
+    if (isAdmin) {
+      // 鑾峰緱杩炴帴ID
+      const connId = await this.csConnService.getConnId(false, msg.sessionId);
+      // 鍙戦�佹秷鎭�
+      this.socketApp.of('/cs').to(connId).emit('msg', msg);
+    } else {
+      // 骞挎挱缁欐墍鏈夌殑鍚庣瀹㈡湇
+      this.socketApp.of('/cs').emit('msg', msg);
+    }
+  }
+}
diff --git a/src/modules/cs/service/session.ts b/src/modules/cs/service/session.ts
new file mode 100644
index 0000000..3994ad7
--- /dev/null
+++ b/src/modules/cs/service/session.ts
@@ -0,0 +1,38 @@
+import { Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { CsSessionEntity } from '../entity/session';
+
+/**
+ * 瀹㈡湇浼氳瘽
+ */
+@Provide()
+export class CsSessionService extends BaseService {
+  @InjectEntityModel(CsSessionEntity)
+  csSessionEntity: Repository<CsSessionEntity>;
+
+  /**
+   * 浼氳瘽璇︽儏
+   * @param userId
+   */
+  async detail(userId: number) {
+    return await this.csSessionEntity.findOneBy({ userId });
+  }
+
+  /**
+   * 鍒涘缓浼氳瘽
+   * @param userId
+   * @returns
+   */
+  async create(userId: number) {
+    const check = await this.detail(userId);
+    if (check) {
+      return check;
+    }
+    const session = new CsSessionEntity();
+    session.userId = userId;
+    await this.csSessionEntity.insert(session);
+    return session;
+  }
+}
diff --git a/src/modules/cs/socket/io.ts b/src/modules/cs/socket/io.ts
new file mode 100644
index 0000000..4986c52
--- /dev/null
+++ b/src/modules/cs/socket/io.ts
@@ -0,0 +1,46 @@
+import {
+  WSController,
+  OnWSConnection,
+  Inject,
+  OnWSMessage,
+} from '@midwayjs/core';
+import { CsConnService } from '../service/conn';
+import { CsSocketTokenMiddleware } from './middleware/token';
+import { CsMsgService } from '../service/msg';
+/**
+ * code-socket
+ */
+@WSController('/cs')
+export class CsSocketIoController {
+  @Inject()
+  ctx;
+
+  @Inject()
+  csConnService: CsConnService;
+
+  @Inject()
+  csMsgService: CsMsgService;
+
+  // 瀹㈡埛绔繛鎺�
+  @OnWSConnection({ middleware: [CsSocketTokenMiddleware] })
+  async onConnectionMethod() {
+    const { isAdmin, userId } = this.ctx.connData;
+    await this.csConnService.binding(isAdmin, userId, this.ctx.id);
+    this.ctx.emit('message', '杩炴帴鎴愬姛');
+  }
+
+  // 鍙戦�佹秷鎭�
+  @OnWSMessage('send', { middleware: [CsSocketTokenMiddleware] })
+  async send(data) {
+    const { isAdmin, userId } = this.ctx.connData;
+    const { sessionId, content } = data;
+    await this.csMsgService.send(
+      {
+        userId,
+        sessionId,
+        content,
+      },
+      isAdmin
+    );
+  }
+}
diff --git a/src/modules/cs/socket/middleware/token.ts b/src/modules/cs/socket/middleware/token.ts
new file mode 100644
index 0000000..42ac237
--- /dev/null
+++ b/src/modules/cs/socket/middleware/token.ts
@@ -0,0 +1,34 @@
+import { Config, Middleware } from '@midwayjs/core';
+import { NextFunction } from '@midwayjs/socketio';
+import * as jwt from 'jsonwebtoken';
+
+@Middleware()
+export class CsSocketTokenMiddleware {
+  @Config('module.user.jwt')
+  appJwtConfig;
+
+  @Config('module.base.jwt')
+  adminJwtConfig;
+
+  resolve() {
+    return async (ctx, next: NextFunction) => {
+      try {
+        // 鑾峰緱杩炴帴鍙傛暟
+        const isAdmin = ctx.handshake.auth.isAdmin;
+        const token = ctx.handshake.auth.token;
+        const data = jwt.verify(
+          token,
+          isAdmin ? this.adminJwtConfig.secret : this.appJwtConfig.secret
+        );
+        ctx.connData = {
+          userId: isAdmin ? data.userId : data.id,
+          isAdmin,
+        };
+      } catch (error) {
+        ctx.emit('sys', '杩炴帴澶辫触');
+        return;
+      }
+      return await next();
+    };
+  }
+}
diff --git a/src/modules/goods/config.ts b/src/modules/goods/config.ts
new file mode 100644
index 0000000..5e280ed
--- /dev/null
+++ b/src/modules/goods/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '鍟嗗搧妯″潡',
+    // 妯″潡鎻忚堪
+    description: '鍟嗗搧銆佸垎绫荤鐞�',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/goods/controller/admin/comment.ts b/src/modules/goods/controller/admin/comment.ts
new file mode 100644
index 0000000..7b59f14
--- /dev/null
+++ b/src/modules/goods/controller/admin/comment.ts
@@ -0,0 +1,30 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { GoodsCommentEntity } from '../../entity/comment';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { GoodsInfoEntity } from '../../entity/info';
+
+/**
+ * 鍟嗗搧璇勮
+ */
+@CoolController({
+  api: ['page'],
+  entity: GoodsCommentEntity,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.content', 'b.nickName'],
+    fieldEq: ['a.goodsId'],
+    select: ['a.*', 'b.nickName', 'b.avatarUrl', 'c.title', 'c.mainPic'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+      {
+        entity: GoodsInfoEntity,
+        alias: 'c',
+        condition: 'a.goodsId = c.id',
+      },
+    ],
+  },
+})
+export class AdminGoodsCommentController extends BaseController {}
diff --git a/src/modules/goods/controller/admin/info.ts b/src/modules/goods/controller/admin/info.ts
new file mode 100644
index 0000000..70829d8
--- /dev/null
+++ b/src/modules/goods/controller/admin/info.ts
@@ -0,0 +1,29 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { GoodsInfoEntity } from '../../entity/info';
+import { GoodsInfoService } from '../../service/info';
+import { GoodsTypeEntity } from '../../entity/type';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: GoodsInfoEntity,
+  service: GoodsInfoService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title', 'a.subTitle'],
+    select: ['a.*', 'b.name as typeName'],
+    fieldEq: ['a.status', 'a.typeId'],
+    addOrderBy: {
+      sortNum: 'desc',
+    },
+    join: [
+      {
+        entity: GoodsTypeEntity,
+        alias: 'b',
+        condition: 'a.typeId = b.id',
+      },
+    ],
+  },
+})
+export class AdminGoodsInfoController extends BaseController {}
diff --git a/src/modules/goods/controller/admin/searchKeyword.ts b/src/modules/goods/controller/admin/searchKeyword.ts
new file mode 100644
index 0000000..4f9882f
--- /dev/null
+++ b/src/modules/goods/controller/admin/searchKeyword.ts
@@ -0,0 +1,14 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { GoodsSearchKeywordEntity } from '../../entity/searchKeyword';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: GoodsSearchKeywordEntity,
+  pageQueryOp: {
+    keyWordLikeFields: ['name'],
+  },
+})
+export class AdminGoodsSearchKeywordController extends BaseController {}
diff --git a/src/modules/goods/controller/admin/spec.ts b/src/modules/goods/controller/admin/spec.ts
new file mode 100644
index 0000000..ca9b1d5
--- /dev/null
+++ b/src/modules/goods/controller/admin/spec.ts
@@ -0,0 +1,14 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { GoodsSpecEntity } from '../../entity/spec';
+
+/**
+ * 鍒嗙被
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: GoodsSpecEntity,
+  listQueryOp: {
+    fieldEq: ['goodsId'],
+  },
+})
+export class AdminGoodsSpecController extends BaseController {}
diff --git a/src/modules/goods/controller/admin/type.ts b/src/modules/goods/controller/admin/type.ts
new file mode 100644
index 0000000..0801b46
--- /dev/null
+++ b/src/modules/goods/controller/admin/type.ts
@@ -0,0 +1,20 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { GoodsTypeEntity } from '../../entity/type';
+import { GoodsTypeService } from '../../service/type';
+
+/**
+ * 鍒嗙被
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: GoodsTypeEntity,
+  service: GoodsTypeService,
+  listQueryOp: {
+    keyWordLikeFields: ['name'],
+  },
+  pageQueryOp: {
+    keyWordLikeFields: ['name'],
+    fieldEq: ['parentId'],
+  },
+})
+export class AdminGoodsTypeController extends BaseController {}
diff --git a/src/modules/goods/controller/app/comment.ts b/src/modules/goods/controller/app/comment.ts
new file mode 100644
index 0000000..521c871
--- /dev/null
+++ b/src/modules/goods/controller/app/comment.ts
@@ -0,0 +1,55 @@
+import {
+  CoolController,
+  BaseController,
+  TagTypes,
+  CoolUrlTag,
+} from '@cool-midway/core';
+import { GoodsCommentEntity } from '../../entity/comment';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { Body, Inject, Post } from '@midwayjs/core';
+import { GoodsCommentService } from '../../service/comment';
+
+/**
+ * 鍟嗗搧璇勮
+ */
+@CoolUrlTag({
+  key: TagTypes.IGNORE_TOKEN,
+  value: ['page'],
+})
+@CoolController({
+  api: ['page'],
+  entity: GoodsCommentEntity,
+  insertParam: ctx => {
+    return {
+      userId: ctx.user.id,
+    };
+  },
+  pageQueryOp: {
+    fieldEq: ['a.goodsId', 'a.orderId'],
+    select: ['a.*', 'b.nickName', 'b.avatarUrl'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+    ],
+  },
+})
+export class AppGoodsCommentController extends BaseController {
+  @Inject()
+  ctx;
+
+  @Inject()
+  goodsCommentService: GoodsCommentService;
+
+  @Post('/submit', { summary: '鎻愪氦璇勮' })
+  async submit(
+    @Body('data') data: GoodsCommentEntity,
+    @Body('orderId') orderId: number
+  ) {
+    return this.ok(
+      await this.goodsCommentService.submit(this.ctx.user.id, orderId, data)
+    );
+  }
+}
diff --git a/src/modules/goods/controller/app/info.ts b/src/modules/goods/controller/app/info.ts
new file mode 100644
index 0000000..430ff6b
--- /dev/null
+++ b/src/modules/goods/controller/app/info.ts
@@ -0,0 +1,45 @@
+import {
+  CoolController,
+  BaseController,
+  CoolUrlTag,
+  TagTypes,
+} from '@cool-midway/core';
+import { GoodsInfoEntity } from '../../entity/info';
+import { GoodsInfoService } from '../../service/info';
+import { GoodsTypeEntity } from '../../entity/type';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@CoolUrlTag({
+  key: TagTypes.IGNORE_TOKEN,
+  value: ['page', 'info'],
+})
+@CoolController({
+  api: ['page', 'info'],
+  entity: GoodsInfoEntity,
+  service: GoodsInfoService,
+  pageQueryOp: {
+    keyWordLikeFields: ['title'],
+    fieldEq: ['a.typeId'],
+    select: ['a.*', 'b.name as typeName'],
+    where: ctx => {
+      const { minPrice, maxPrice } = ctx.request.body;
+      return [
+        // 杩囨护鎺夊凡涓嬫灦鍟嗗搧
+        ['a.status = :status', { status: 1 }],
+        // 浠锋牸鍖洪棿
+        ['a.price >= :minPrice', { minPrice }, minPrice],
+        ['a.price <= :maxPrice', { maxPrice }, maxPrice],
+      ];
+    },
+    join: [
+      {
+        entity: GoodsTypeEntity,
+        alias: 'b',
+        condition: 'a.typeId = b.id',
+      },
+    ],
+  },
+})
+export class AppGoodsInfoController extends BaseController {}
diff --git a/src/modules/goods/controller/app/searchKeyword.ts b/src/modules/goods/controller/app/searchKeyword.ts
new file mode 100644
index 0000000..dbbdced
--- /dev/null
+++ b/src/modules/goods/controller/app/searchKeyword.ts
@@ -0,0 +1,14 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { GoodsSearchKeywordEntity } from '../../entity/searchKeyword';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: GoodsSearchKeywordEntity,
+  pageQueryOp: {
+    keyWordLikeFields: ['name'],
+  },
+})
+export class AppGoodsSearchKeywordController extends BaseController {}
diff --git a/src/modules/goods/controller/app/spec.ts b/src/modules/goods/controller/app/spec.ts
new file mode 100644
index 0000000..5b0829f
--- /dev/null
+++ b/src/modules/goods/controller/app/spec.ts
@@ -0,0 +1,23 @@
+import {
+  CoolController,
+  BaseController,
+  TagTypes,
+  CoolUrlTag,
+} from '@cool-midway/core';
+import { GoodsSpecEntity } from '../../entity/spec';
+
+/**
+ * 鍒嗙被
+ */
+@CoolUrlTag({
+  key: TagTypes.IGNORE_TOKEN,
+  value: ['list'],
+})
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: GoodsSpecEntity,
+  listQueryOp: {
+    fieldEq: ['goodsId'],
+  },
+})
+export class AppGoodsSpecController extends BaseController {}
diff --git a/src/modules/goods/controller/app/type.ts b/src/modules/goods/controller/app/type.ts
new file mode 100644
index 0000000..a6b35ae
--- /dev/null
+++ b/src/modules/goods/controller/app/type.ts
@@ -0,0 +1,29 @@
+import {
+  CoolController,
+  BaseController,
+  TagTypes,
+  CoolUrlTag,
+} from '@cool-midway/core';
+import { GoodsTypeEntity } from '../../entity/type';
+
+/**
+ * 鍒嗙被
+ */
+@CoolUrlTag({
+  key: TagTypes.IGNORE_TOKEN,
+  value: ['list'],
+})
+@CoolController({
+  api: ['list'],
+  entity: GoodsTypeEntity,
+  listQueryOp: {
+    keyWordLikeFields: ['a.name'],
+    addOrderBy: {
+      sortNum: 'desc',
+    },
+    where: () => {
+      return [['a.status =:status', { status: 1 }]];
+    },
+  },
+})
+export class AppGoodsTypeController extends BaseController {}
diff --git a/src/modules/goods/entity/comment.ts b/src/modules/goods/entity/comment.ts
new file mode 100644
index 0000000..1f3c76a
--- /dev/null
+++ b/src/modules/goods/entity/comment.ts
@@ -0,0 +1,29 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@Entity('goods_comment')
+export class GoodsCommentEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Index()
+  @Column({ comment: '鍟嗗搧ID' })
+  goodsId: number;
+
+  @Index()
+  @Column({ comment: '璁㈠崟ID' })
+  orderId: number;
+
+  @Column({ comment: '鍐呭' })
+  content: string;
+
+  @Column({ comment: '鏄熸暟', default: 5 })
+  starCount: number;
+
+  @Column({ comment: '鍥剧墖', type: 'json', nullable: true })
+  pics: string[];
+}
diff --git a/src/modules/goods/entity/info.ts b/src/modules/goods/entity/info.ts
new file mode 100644
index 0000000..d25d8f0
--- /dev/null
+++ b/src/modules/goods/entity/info.ts
@@ -0,0 +1,50 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+import { GoodsSpecEntity } from './spec';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@Entity('goods_info')
+export class GoodsInfoEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '绫诲瀷ID' })
+  typeId: number;
+
+  @Index()
+  @Column({ comment: '鏍囬' })
+  title: string;
+
+  @Column({ comment: '鍓爣棰�', nullable: true })
+  subTitle: string;
+
+  @Column({ comment: '涓诲浘' })
+  mainPic: string;
+
+  @Column({ comment: '鍥剧墖', type: 'json', nullable: true })
+  pics: string[];
+
+  @Column({
+    comment: '浠锋牸',
+    type: 'decimal',
+    precision: 12,
+    scale: 2,
+  })
+  price: number;
+
+  @Column({ comment: '宸插敭', default: 0 })
+  sold: number;
+
+  @Column({ comment: '璇︽儏', type: 'text', nullable: true })
+  content: string;
+
+  @Index()
+  @Column({ comment: '鐘舵�� 0-涓嬫灦 1-涓婃灦', default: 0 })
+  status: number;
+
+  @Column({ comment: '鎺掑簭', default: 0, nullable: true })
+  sortNum: number;
+
+  // 瑙勬牸锛岄潪琛ㄥ瓧娈�
+  specs: GoodsSpecEntity[];
+}
diff --git a/src/modules/goods/entity/searchKeyword.ts b/src/modules/goods/entity/searchKeyword.ts
new file mode 100644
index 0000000..4ea4faa
--- /dev/null
+++ b/src/modules/goods/entity/searchKeyword.ts
@@ -0,0 +1,14 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 鎼滅储鍏抽敭璇�
+ */
+@Entity('goods_search_keyword')
+export class GoodsSearchKeywordEntity extends BaseEntity {
+  @Column({ comment: '鍚嶇О' })
+  name: string;
+
+  @Column({ comment: '鎺掑簭', default: 0, nullable: true })
+  sortNum: number;
+}
diff --git a/src/modules/goods/entity/spec.ts b/src/modules/goods/entity/spec.ts
new file mode 100644
index 0000000..bc29125
--- /dev/null
+++ b/src/modules/goods/entity/spec.ts
@@ -0,0 +1,32 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 瑙勬牸
+ */
+@Entity('goods_spec')
+export class GoodsSpecEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鍟嗗搧ID' })
+  goodsId: number;
+
+  @Column({ comment: '鍚嶇О' })
+  name: string;
+
+  @Column({
+    comment: '浠锋牸',
+    type: 'decimal',
+    precision: 12,
+    scale: 2,
+  })
+  price: number;
+
+  @Column({ comment: '搴撳瓨', default: 0 })
+  stock: number;
+
+  @Column({ comment: '鎺掑簭', default: 0, nullable: true })
+  sortNum: number;
+
+  @Column({ comment: '鍥剧墖', type: 'json', nullable: true })
+  images: string[];
+}
diff --git a/src/modules/goods/entity/type.ts b/src/modules/goods/entity/type.ts
new file mode 100644
index 0000000..8c12dda
--- /dev/null
+++ b/src/modules/goods/entity/type.ts
@@ -0,0 +1,24 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 瑙勬牸
+ */
+@Entity('goods_type')
+export class GoodsTypeEntity extends BaseEntity {
+  @Column({ comment: '鍚嶇О' })
+  name: string;
+
+  @Index()
+  @Column({ comment: '鐖禝D', nullable: true })
+  parentId: number;
+
+  @Column({ comment: '鎺掑簭', default: 0, nullable: true })
+  sortNum: number;
+
+  @Column({ comment: '鍥剧墖', nullable: true })
+  pic: string;
+
+  @Column({ comment: '鐘舵��  0-绂佺敤 1-鍚敤', nullable: true, default: 1 })
+  status: number;
+}
diff --git a/src/modules/goods/service/comment.ts b/src/modules/goods/service/comment.ts
new file mode 100644
index 0000000..46c51cc
--- /dev/null
+++ b/src/modules/goods/service/comment.ts
@@ -0,0 +1,62 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService, CoolCommException } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Equal, Repository } from 'typeorm';
+import { GoodsCommentEntity } from '../entity/comment';
+import { OrderInfoService } from '../../order/service/info';
+import { OrderGoodsEntity } from '../../order/entity/goods';
+
+/**
+ * 鍟嗗搧璇勮
+ */
+@Provide()
+export class GoodsCommentService extends BaseService {
+  @InjectEntityModel(GoodsCommentEntity)
+  goodsCommentEntity: Repository<GoodsCommentEntity>;
+
+  @InjectEntityModel(OrderGoodsEntity)
+  orderGoodsEntity: Repository<OrderGoodsEntity>;
+
+  @Inject()
+  orderInfoService: OrderInfoService;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.goodsCommentEntity);
+  }
+
+  /**
+   * 鎻愪氦璇勮
+   * @param userId
+   * @param orderId
+   * @param comment
+   */
+  async submit(userId: number, orderId: number, comment: GoodsCommentEntity) {
+    const order = await this.orderInfoService.info(orderId);
+    if (order && order.userId != userId) {
+      throw new CoolCommException('鏃犳潈闄�');
+    }
+    if (![3, 4].includes(order.status)) {
+      throw new CoolCommException('涓嶆槸鍙瘎浠风殑璁㈠崟鐘舵��');
+    }
+    const goods = await this.orderGoodsEntity.findOneBy({
+      goodsId: Equal(comment.goodsId),
+      orderId: Equal(orderId),
+    });
+    if (!goods) {
+      throw new CoolCommException('鍟嗗搧涓嶅瓨鍦�');
+    }
+    if (goods.isComment) {
+      throw new CoolCommException('宸茶瘎浠疯繃锛屼笉鑳介噸澶嶈瘎浠�');
+    }
+    // 鏇存柊璁㈠崟鍟嗗搧鐘舵��
+    await this.orderGoodsEntity.update(goods.id, { isComment: 1 });
+    // 璁㈠崟鐘舵�佹敼涓轰氦鏄撳畬鎴�
+    if (order.status == 3) {
+      await this.orderInfoService.changeStatus(orderId, 4);
+    }
+    comment.userId = userId;
+    await this.add(comment);
+  }
+}
diff --git a/src/modules/goods/service/info.ts b/src/modules/goods/service/info.ts
new file mode 100644
index 0000000..7979d5c
--- /dev/null
+++ b/src/modules/goods/service/info.ts
@@ -0,0 +1,56 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { GoodsInfoEntity } from '../entity/info';
+import { GoodsSpecService } from './spec';
+
+/**
+ * 鍟嗗搧淇℃伅
+ */
+@Provide()
+export class GoodsInfoService extends BaseService {
+  @InjectEntityModel(GoodsInfoEntity)
+  goodsInfoEntity: Repository<GoodsInfoEntity>;
+
+  @Inject()
+  goodsSpecService: GoodsSpecService;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.goodsInfoEntity);
+  }
+
+  /**
+   * 淇敼涔嬪悗
+   * @param data
+   * @param type
+   */
+  async modifyAfter(data: any, type: 'add' | 'update' | 'delete') {
+    if ((type == 'add' || type == 'update') && data.specs) {
+      // 淇濆瓨瑙勬牸
+      await this.goodsSpecService.save(data.id, data.specs);
+    }
+    if (type == 'delete') {
+      // 鍒犻櫎瑙勬牸
+      await this.goodsSpecService.removeByGoodsId([data.id]);
+    }
+  }
+
+  /**
+   * 璇︽儏
+   * @param id
+   * @param infoIgnoreProperty
+   * @returns
+   */
+  async info(id: any, infoIgnoreProperty?: string[]) {
+    if (!id) return;
+    const info = await super.info(id, infoIgnoreProperty);
+    if (info) {
+      // 鑾峰彇瑙勬牸
+      info.specs = await this.goodsSpecService.getByGoodsId(info.id);
+    }
+    return info;
+  }
+}
diff --git a/src/modules/goods/service/spec.ts b/src/modules/goods/service/spec.ts
new file mode 100644
index 0000000..efa0ac6
--- /dev/null
+++ b/src/modules/goods/service/spec.ts
@@ -0,0 +1,71 @@
+import { Init, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Equal, In, Repository } from 'typeorm';
+import { GoodsSpecEntity } from '../entity/spec';
+
+/**
+ * 瑙勬牸
+ */
+@Provide()
+export class GoodsSpecService extends BaseService {
+  @InjectEntityModel(GoodsSpecEntity)
+  goodsSpecEntity: Repository<GoodsSpecEntity>;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.goodsSpecEntity);
+  }
+
+  /**
+   * 淇濇寔瑙勬牸
+   * @param goodsId
+   * @param specs
+   */
+  async save(goodsId: number, specs: GoodsSpecEntity[]) {
+    // 鍏堝垹闄ゅ師鏉ョ殑瑙勬牸
+    await this.goodsSpecEntity.delete({ goodsId });
+    // 淇濆瓨鏂扮殑瑙勬牸
+    await this.goodsSpecEntity.save(
+      specs.map(item => {
+        item.goodsId = goodsId;
+        return item;
+      })
+    );
+  }
+
+  /**
+   * 閫氳繃鍟嗗搧ID鑾峰彇瑙勬牸
+   * @param goodsId
+   */
+  async removeByGoodsId(goodsIds: number[]) {
+    await this.goodsSpecEntity.delete({ goodsId: In(goodsIds) });
+  }
+
+  /**
+   * 閫氳繃鍟嗗搧ID鑾峰彇瑙勬牸
+   * @param goodsId
+   * @returns
+   */
+  async getByGoodsId(goodsId: number) {
+    return await this.goodsSpecEntity.findBy({ goodsId: Equal(goodsId) });
+  }
+
+  /**
+   * 鏇存柊搴撳瓨
+   * @param specId 瑙勬牸ID
+   * @param count 鏁伴噺
+   */
+  async updateStock(specId: number, count: number) {
+    await this.goodsSpecEntity.increment({ id: specId }, 'stock', count);
+
+    // 鏇存柊鍚庢鏌ュ簱瀛橈紝濡傛灉灏忎簬0鍒欒缃负0
+    const spec = await this.goodsSpecEntity.findOneBy({ id: Equal(specId) });
+    if (spec && spec.stock < 0) {
+      await this.goodsSpecEntity.update(spec.id, {
+        stock: 0,
+      });
+    }
+  }
+}
diff --git a/src/modules/goods/service/type.ts b/src/modules/goods/service/type.ts
new file mode 100644
index 0000000..8120209
--- /dev/null
+++ b/src/modules/goods/service/type.ts
@@ -0,0 +1,30 @@
+import { Init, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { In, Repository } from 'typeorm';
+import { GoodsTypeEntity } from '../entity/type';
+
+/**
+ * 鍟嗗搧绫诲瀷
+ */
+@Provide()
+export class GoodsTypeService extends BaseService {
+  @InjectEntityModel(GoodsTypeEntity)
+  goodsTypeEntity: Repository<GoodsTypeEntity>;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.goodsTypeEntity);
+  }
+
+  /**
+   * 鍒犻櫎
+   * @param ids
+   */
+  async delete(ids: any) {
+    await super.delete(ids);
+    // 鍒犻櫎瀛愰泦
+    await this.goodsTypeEntity.delete({ parentId: In(ids) });
+  }
+}
diff --git a/src/modules/info/config.ts b/src/modules/info/config.ts
new file mode 100644
index 0000000..00fdcaa
--- /dev/null
+++ b/src/modules/info/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '淇℃伅妯″潡',
+    // 妯″潡鎻忚堪
+    description: '杞挱鍥剧瓑',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/info/controller/admin/banner.ts b/src/modules/info/controller/admin/banner.ts
new file mode 100644
index 0000000..e1d08de
--- /dev/null
+++ b/src/modules/info/controller/admin/banner.ts
@@ -0,0 +1,15 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { InfoBannerEntity } from '../../entity/banner';
+
+/**
+ * 杞挱鍥�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: InfoBannerEntity,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title'],
+    fieldEq: ['a.status'],
+  },
+})
+export class AdminInfoBannerController extends BaseController {}
diff --git a/src/modules/info/controller/app/banner.ts b/src/modules/info/controller/app/banner.ts
new file mode 100644
index 0000000..3f5926d
--- /dev/null
+++ b/src/modules/info/controller/app/banner.ts
@@ -0,0 +1,27 @@
+import {
+  CoolController,
+  BaseController,
+  CoolUrlTag,
+  TagTypes,
+} from '@cool-midway/core';
+import { InfoBannerEntity } from '../../entity/banner';
+
+/**
+ * 杞挱鍥�
+ */
+@CoolUrlTag({
+  key: TagTypes.IGNORE_TOKEN,
+  value: ['list'],
+})
+@CoolController({
+  api: ['list'],
+  entity: InfoBannerEntity,
+  listQueryOp: {
+    keyWordLikeFields: ['a.title'],
+    fieldEq: ['a.status'],
+    where: () => {
+      return [['a.status =:status', { status: 1 }]];
+    },
+  },
+})
+export class AppInfoBannerController extends BaseController {}
diff --git a/src/modules/info/entity/banner.ts b/src/modules/info/entity/banner.ts
new file mode 100644
index 0000000..d22e1b2
--- /dev/null
+++ b/src/modules/info/entity/banner.ts
@@ -0,0 +1,23 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity } from 'typeorm';
+
+/**
+ * 杞挱鍥�
+ */
+@Entity('info_banner')
+export class InfoBannerEntity extends BaseEntity {
+  @Column({ comment: '鎻忚堪', nullable: true })
+  description: string;
+
+  @Column({ comment: '璺宠浆璺緞', nullable: true })
+  path: string;
+
+  @Column({ comment: '鍥剧墖' })
+  pic: string;
+
+  @Column({ comment: '鎺掑簭', default: 0, nullable: true })
+  sortNum: number;
+
+  @Column({ comment: '鐘舵�� 1:鍚敤 2:绂佺敤', default: 1 })
+  status: number;
+}
diff --git a/src/modules/market/config.ts b/src/modules/market/config.ts
new file mode 100644
index 0000000..a622185
--- /dev/null
+++ b/src/modules/market/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '钀ラ攢妯″潡',
+    // 妯″潡鎻忚堪
+    description: '浼樻儬鍒�',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/market/controller/admin/coupon/info.ts b/src/modules/market/controller/admin/coupon/info.ts
new file mode 100644
index 0000000..68ffe09
--- /dev/null
+++ b/src/modules/market/controller/admin/coupon/info.ts
@@ -0,0 +1,17 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { MarketCouponInfoEntity } from '../../../entity/coupon/info';
+import { MarketCouponInfoService } from '../../../service/coupon/info';
+
+/**
+ * 浼樻儬鍒镐俊鎭�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: MarketCouponInfoEntity,
+  service: MarketCouponInfoService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title'],
+    fieldEq: ['a.status'],
+  },
+})
+export class AdminMarketCouponInfoController extends BaseController {}
diff --git a/src/modules/market/controller/admin/coupon/user.ts b/src/modules/market/controller/admin/coupon/user.ts
new file mode 100644
index 0000000..0ed0ce1
--- /dev/null
+++ b/src/modules/market/controller/admin/coupon/user.ts
@@ -0,0 +1,26 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { MarketCouponUserEntity } from '../../../entity/coupon/user';
+import { MarketCouponUserService } from '../../../service/coupon/user';
+import { UserInfoEntity } from '../../../../user/entity/info';
+
+/**
+ * 浼樻儬鍒哥敤鎴�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: MarketCouponUserEntity,
+  service: MarketCouponUserService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title', 'b.nickName'],
+    fieldEq: ['a.status', 'a.couponId', 'a.userId'],
+    select: ['a.*', 'b.nickName', 'b.avatarUrl'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+    ],
+  },
+})
+export class AdminMarketCouponUserController extends BaseController {}
diff --git a/src/modules/market/controller/app/coupon/info.ts b/src/modules/market/controller/app/coupon/info.ts
new file mode 100644
index 0000000..bd996af
--- /dev/null
+++ b/src/modules/market/controller/app/coupon/info.ts
@@ -0,0 +1,51 @@
+import {
+  CoolController,
+  BaseController,
+  QueryOp,
+  CoolUrlTag,
+  TagTypes,
+} from '@cool-midway/core';
+import { MarketCouponInfoEntity } from '../../../entity/coupon/info';
+import { MarketCouponInfoService } from '../../../service/coupon/info';
+import * as moment from 'moment';
+import { MarketCouponUserEntity } from '../../../entity/coupon/user';
+
+/**
+ * 浼樻儬鍒镐俊鎭�
+ */
+@CoolUrlTag({
+  key: TagTypes.IGNORE_TOKEN,
+  value: ['page'],
+})
+@CoolController({
+  api: ['page'],
+  entity: MarketCouponInfoEntity,
+  service: MarketCouponInfoService,
+  // 鑾峰緱ctx瀵硅薄
+  pageQueryOp: ctx => {
+    return new Promise<QueryOp>(res => {
+      res({
+        keyWordLikeFields: ['a.title'],
+        fieldEq: ['a.status'],
+        select: ['a.*', 'b.userId'],
+        where: () => {
+          return [
+            // 鍙繑鍥炲惎鐢ㄧ殑浼樻儬鍒�
+            ['a.status =:status', { status: 1 }],
+            // 鍙繑鍥炲凡寮�濮嬪拰鏈粨鏉熺殑浼樻儬鍒�
+            ['a.startTime <=:startTime', { startTime: moment().toDate() }],
+            ['a.endTime >=:endTime', { endTime: moment().toDate() }],
+          ];
+        },
+        join: [
+          {
+            entity: MarketCouponUserEntity,
+            alias: 'b',
+            condition: 'a.id = b.couponId and b.userId =' + (ctx?.user?.id ?? 0),
+          },
+        ],
+      });
+    });
+  },
+})
+export class AppMarketCouponInfoController extends BaseController {}
diff --git a/src/modules/market/controller/app/coupon/user.ts b/src/modules/market/controller/app/coupon/user.ts
new file mode 100644
index 0000000..a0e6acd
--- /dev/null
+++ b/src/modules/market/controller/app/coupon/user.ts
@@ -0,0 +1,48 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { MarketCouponUserEntity } from '../../../entity/coupon/user';
+import { MarketCouponUserService } from '../../../service/coupon/user';
+import { MarketCouponInfoService } from '../../../service/coupon/info';
+import { Inject, Post, Body } from '@midwayjs/core';
+import { MarketCouponInfoEntity } from '../../../entity/coupon/info';
+
+/**
+ * 浼樻儬鍒哥敤鎴�
+ */
+@CoolController({
+  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
+  entity: MarketCouponUserEntity,
+  service: MarketCouponUserService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title'],
+    fieldEq: ['a.status'],
+    select: ['b.*', 'a.status as useStatus'],
+    where: ctx => {
+      const userId = ctx.user.id;
+      return [
+        // 鍙繑鍥炲綋鍓嶇敤鎴风殑浼樻儬鍒�
+        ['a.userId =:userId', { userId }],
+      ];
+    },
+    join: [
+      {
+        entity: MarketCouponInfoEntity,
+        alias: 'b',
+        condition: 'a.couponId = b.id',
+      },
+    ],
+  },
+})
+export class AppMarketCouponUserController extends BaseController {
+  @Inject()
+  marketCouponInfoService: MarketCouponInfoService;
+
+  @Inject()
+  ctx;
+
+  @Post('/receive', { summary: '棰嗗彇浼樻儬鍒�' })
+  async receive(@Body('couponId') couponId: number) {
+    return this.ok(
+      await this.marketCouponInfoService.receive(couponId, this.ctx.user.id)
+    );
+  }
+}
diff --git a/src/modules/market/entity/coupon/info.ts b/src/modules/market/entity/coupon/info.ts
new file mode 100644
index 0000000..96adc00
--- /dev/null
+++ b/src/modules/market/entity/coupon/info.ts
@@ -0,0 +1,41 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity } from 'typeorm';
+
+/**
+ * 浼樻儬鍒镐俊鎭�
+ */
+@Entity('market_coupon_info')
+export class MarketCouponInfoEntity extends BaseEntity {
+  @Column({ comment: '鏍囬' })
+  title: string;
+
+  @Column({ comment: '鎻忚堪' })
+  description: string;
+
+  @Column({ comment: '绫诲瀷 0-婊″噺', default: 0 })
+  type: number;
+
+  @Column({ comment: '閲戦', type: 'decimal', precision: 12, scale: 2 })
+  amount: number;
+
+  @Column({ comment: '鏁伴噺' })
+  num: number;
+
+  @Column({ comment: '宸查鍙�' })
+  receivedNum: number;
+
+  @Column({ comment: '寮�濮嬫椂闂�' })
+  startTime: Date;
+
+  @Column({ comment: '缁撴潫鏃堕棿' })
+  endTime: Date;
+
+  @Column({ comment: '鐘舵�� 0-绂佺敤 1-鍚敤', default: 0 })
+  status: number;
+
+  @Column({ comment: '鏉′欢', type: 'json' })
+  condition: {
+    // 婊″灏戦噾棰�
+    fullAmount: number;
+  };
+}
diff --git a/src/modules/market/entity/coupon/user.ts b/src/modules/market/entity/coupon/user.ts
new file mode 100644
index 0000000..e32f162
--- /dev/null
+++ b/src/modules/market/entity/coupon/user.ts
@@ -0,0 +1,22 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+
+/**
+ * 浼樻儬鍒哥敤鎴�
+ */
+@Entity('market_coupon_user')
+export class MarketCouponUserEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Index()
+  @Column({ comment: '浼樻儬鍒窱D' })
+  couponId: number;
+
+  @Column({ comment: '鐘舵�� 0-鏈娇鐢� 1-宸蹭娇鐢�', default: 0 })
+  status: number;
+
+  @Column({ comment: '浣跨敤鏃堕棿', type: 'datetime', nullable: true })
+  useTime: Date;
+}
diff --git a/src/modules/market/service/coupon/info.ts b/src/modules/market/service/coupon/info.ts
new file mode 100644
index 0000000..b163a7e
--- /dev/null
+++ b/src/modules/market/service/coupon/info.ts
@@ -0,0 +1,116 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService, CoolCommException } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { MarketCouponInfoEntity } from '../../entity/coupon/info';
+import { MarketCouponUserService } from './user';
+import { OrderInfoEntity } from '../../../order/entity/info';
+import * as moment from 'moment';
+
+/**
+ * 浼樻儬鍒镐俊鎭�
+ */
+@Provide()
+export class MarketCouponInfoService extends BaseService {
+  @InjectEntityModel(MarketCouponInfoEntity)
+  marketCouponInfoEntity: Repository<MarketCouponInfoEntity>;
+
+  @Inject()
+  marketCouponUserService: MarketCouponUserService;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.marketCouponInfoEntity);
+  }
+
+  /**
+   * 妫�鏌ヤ紭鎯犲埜鐘舵��
+   * @param couponId
+   */
+  async check(couponId: number) {
+    const couponInfo: MarketCouponInfoEntity = await super.info(couponId);
+    if (!couponInfo) {
+      throw new CoolCommException('浼樻儬鍒镐笉瀛樺湪');
+    }
+    // 鍒ゆ柇鏁伴噺
+    if (couponInfo.receivedNum >= couponInfo.num) {
+      throw new CoolCommException('浼樻儬鍒稿凡棰嗗畬');
+    }
+    // 鍒ゆ柇鏃堕棿
+    if (
+      moment().isBefore(couponInfo.startTime) ||
+      moment().isAfter(couponInfo.endTime)
+    ) {
+      throw new CoolCommException('浼樻儬鍒告湭寮�濮嬫垨宸茬粨鏉�');
+    }
+    // 鍒ゆ柇鐘舵��
+    if (couponInfo.status !== 1) {
+      throw new CoolCommException('浼樻儬鍒告湭鍚敤');
+    }
+    return couponInfo;
+  }
+
+  /**
+   * 棰嗗彇浼樻儬鍒�
+   * @param couponId
+   * @param userId
+   */
+  async receive(couponId: number, userId: number) {
+    // 妫�鏌ヤ紭鎯犲埜
+    await this.check(couponId);
+    // 妫�鏌ョ敤鎴锋槸鍚﹀凡棰嗗彇
+    if (await this.marketCouponUserService.checkExist(couponId, userId)) {
+      throw new CoolCommException('宸查鍙栬繃璇ヤ紭鎯犲埜');
+    }
+    // 淇濆瓨
+    await this.marketCouponUserService.save(couponId, userId);
+    // 澧炲姞棰嗗彇鏁伴噺
+    await this.marketCouponInfoEntity.increment(
+      { id: couponId },
+      'receivedNum',
+      1
+    );
+  }
+
+  /**
+   * 妫�鏌ヤ紭鎯犲埜鏄惁婊¤冻鏉′欢锛屾弧瓒崇殑璇濅娇鐢ㄥ苟璁剧疆鍜岃繑鍥炶鍗曚紭鎯犻噾棰�
+   * @param couponId
+   * @param userId
+   * @param order
+   */
+  async checkAndUse(couponId: number, userId: number, order: OrderInfoEntity) {
+    // 鍒ゆ柇浼樻儬鍒�
+    const couponInfo = await this.check(couponId);
+    // 鍒ゆ柇鐢ㄦ埛
+    await this.marketCouponUserService.check(couponId, userId);
+    // 鍒ゆ柇鏉′欢
+    if (couponInfo.type == 0) {
+      // 婊″噺
+      if (order.price < couponInfo.condition.fullAmount) {
+        throw new CoolCommException('鏈弧瓒充紭鎯犲埜浣跨敤鏉′欢');
+      }
+      // 璁剧疆璁㈠崟鐨勪紭鎯犻噾棰�
+      order.discountPrice = couponInfo.amount;
+      // 璁剧疆浼樻儬鏉ユ簮
+      order.discountSource = {
+        type: 0,
+        objectId: couponId,
+        info: couponInfo,
+      };
+      // 璁剧疆鍟嗗搧鐨勪紭鎯犻噾棰�
+      if (order.price > 0) {
+        order.goodsList.forEach(goods => {
+          // 浼樻儬閲戦 = 鍟嗗搧浠锋牸 / 璁㈠崟鎬讳环 * 浼樻儬閲戦 淇濈暀涓や綅灏忔暟
+          goods.discountPrice = Number(
+            ((goods.price / order.price) * couponInfo.amount).toFixed(2)
+          );
+        });
+      }
+      // 浣跨敤浼樻儬鍒�
+      await this.marketCouponUserService.use(couponId, userId);
+      return couponInfo.amount;
+    }
+    return 0;
+  }
+}
diff --git a/src/modules/market/service/coupon/user.ts b/src/modules/market/service/coupon/user.ts
new file mode 100644
index 0000000..566a4da
--- /dev/null
+++ b/src/modules/market/service/coupon/user.ts
@@ -0,0 +1,74 @@
+import { Init, Provide } from '@midwayjs/core';
+import { BaseService, CoolCommException } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Equal, Repository } from 'typeorm';
+import { MarketCouponUserEntity } from '../../entity/coupon/user';
+
+/**
+ * 浼樻儬鍒哥敤鎴�
+ */
+@Provide()
+export class MarketCouponUserService extends BaseService {
+  @InjectEntityModel(MarketCouponUserEntity)
+  marketCouponUserEntity: Repository<MarketCouponUserEntity>;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.marketCouponUserEntity);
+  }
+
+  /**
+   * 淇濆瓨
+   * @param idcouponId
+   * @param userId
+   */
+  async save(couponId: number, userId: number) {
+    const couponUser = new MarketCouponUserEntity();
+    couponUser.userId = userId;
+    couponUser.couponId = couponId;
+    await this.marketCouponUserEntity.save(couponUser);
+  }
+
+  /**
+   * 妫�鏌ヤ紭鎯犲埜鏄惁鍙敤
+   * @param couponId
+   * @param userId
+   */
+  async check(couponId: number, userId: number) {
+    const info = await this.marketCouponUserEntity.findOneBy({
+      couponId: Equal(couponId),
+      userId: Equal(userId),
+      status: 0,
+    });
+    if (!info) {
+      throw new CoolCommException('浼樻儬鍒告湭棰嗗彇鎴栧凡浣跨敤');
+    }
+    return info;
+  }
+
+  /**
+   * 妫�鏌ヤ紭鎯犲埜鏄惁瀛樺湪
+   * @param couponId
+   * @param userId
+   */
+  async checkExist(couponId: number, userId: number) {
+    const info = await this.marketCouponUserEntity.findOneBy({
+      couponId: Equal(couponId),
+      userId: Equal(userId),
+    });
+    return !!info;
+  }
+
+  /**
+   * 浣跨敤浼樻儬鍒�
+   * @param couponId
+   * @param userId
+   */
+  async use(couponId: number, userId: number) {
+    await this.marketCouponUserEntity.update(
+      { couponId: Equal(couponId), userId: Equal(userId) },
+      { status: 1, useTime: new Date() }
+    );
+  }
+}
diff --git a/src/modules/order/config.ts b/src/modules/order/config.ts
new file mode 100644
index 0000000..5e11cc4
--- /dev/null
+++ b/src/modules/order/config.ts
@@ -0,0 +1,19 @@
+import { ModuleConfig } from '@cool-midway/core';
+
+/**
+ * 妯″潡閰嶇疆
+ */
+export default () => {
+  return {
+    // 妯″潡鍚嶇О
+    name: '璁㈠崟绠$悊妯″潡',
+    // 妯″潡鎻忚堪
+    description: '璁㈠崟銆侀��娆俱�佹敮浠樼瓑',
+    // 涓棿浠讹紝鍙鏈ā鍧楁湁鏁�
+    middlewares: [],
+    // 涓棿浠讹紝鍏ㄥ眬鏈夋晥
+    globalMiddlewares: [],
+    // 妯″潡鍔犺浇椤哄簭锛岄粯璁や负0锛屽�艰秺澶ц秺浼樺厛鍔犺浇
+    order: 0,
+  } as ModuleConfig;
+};
diff --git a/src/modules/order/controller/admin/info.ts b/src/modules/order/controller/admin/info.ts
new file mode 100644
index 0000000..21b0c05
--- /dev/null
+++ b/src/modules/order/controller/admin/info.ts
@@ -0,0 +1,88 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { OrderInfoEntity } from '../../entity/info';
+import { OrderInfoService } from '../../service/info';
+import { UserInfoEntity } from '../../../user/entity/info';
+import { Body, Get, Inject, Post, Query } from '@midwayjs/core';
+
+/**
+ * 璁㈠崟淇℃伅
+ */
+@CoolController({
+  api: ['delete', 'update', 'info', 'list', 'page'],
+  entity: OrderInfoEntity,
+  service: OrderInfoService,
+  pageQueryOp: {
+    keyWordLikeFields: ['a.title', 'a.orderNum', 'b.nickName'],
+    select: ['a.*', 'b.nickName', 'b.avatarUrl'],
+    fieldEq: ['a.status', 'a.payType'],
+    join: [
+      {
+        entity: UserInfoEntity,
+        alias: 'b',
+        condition: 'a.userId = b.id',
+      },
+    ],
+    where: ctx => {
+      const { startTime, endTime, refundApplyStartTime, refundApplyEndTime } =
+        ctx.request.body;
+      return [
+        // 杩囨护鍒涘缓鏃堕棿
+        ['a.createTime >= :startTime', { startTime }, startTime],
+        ['a.createTime <= :endTime', { endTime }, endTime],
+        // 杩囨护閫�娆炬椂闂�
+        [
+          'a.refundApplyTime >= :refundApplyStartTime',
+          { refundApplyStartTime },
+          refundApplyStartTime,
+        ],
+        [
+          'a.refundApplyTime <= :refundApplyEndTime',
+          { refundApplyEndTime },
+          refundApplyEndTime,
+        ],
+      ];
+    },
+  },
+})
+export class AdminOrderInfoController extends BaseController {
+  @Inject()
+  orderInfoService: OrderInfoService;
+
+  @Post('/refundHandle', { summary: '閫�娆惧鐞�' })
+  async refundHandle(
+    @Body('orderId') orderId: number,
+    // 0-鎷掔粷 1-鍚屾剰
+    @Body('action') action: number,
+    // 鎷掔粷鍘熷洜
+    @Body('refuseReason') refuseReason: string,
+    // 閫�娆鹃噾棰�
+    @Body('amount') amount: number
+  ) {
+    await this.orderInfoService.refundHandle(
+      orderId,
+      action,
+      refuseReason,
+      amount
+    );
+    return this.ok();
+  }
+
+  @Get('/logistics', { summary: '鐗╂祦淇℃伅' })
+  async logistics(@Query('orderId') orderId: number) {
+    return this.ok(await this.orderInfoService.logistics(orderId));
+  }
+
+  @Post('/deliver', { summary: '鍙戣揣' })
+  async deliver(
+    @Body('orderId') orderId: number,
+    @Body('logistics')
+    logistics: {
+      // 鐗╂祦鍏徃
+      company: string;
+      // 鐗╂祦鍗曞彿
+      num: string;
+    }
+  ) {
+    return this.ok(await this.orderInfoService.deliver(orderId, logistics));
+  }
+}
diff --git a/src/modules/order/controller/app/info.ts b/src/modules/order/controller/app/info.ts
new file mode 100644
index 0000000..0018a8b
--- /dev/null
+++ b/src/modules/order/controller/app/info.ts
@@ -0,0 +1,86 @@
+import { CoolController, BaseController } from '@cool-midway/core';
+import { OrderInfoEntity } from '../../entity/info';
+import { OrderInfoService } from '../../service/info';
+import { Body, Get, Inject, Post, Query } from '@midwayjs/core';
+import { OrderGoodsEntity } from '../../entity/goods';
+
+/**
+ * 璁㈠崟淇℃伅
+ */
+@CoolController({
+  api: ['info', 'page', 'update'],
+  entity: OrderInfoEntity,
+  service: OrderInfoService,
+  pageQueryOp: {
+    fieldEq: ['status'],
+    where: ctx => {
+      return [
+        // 杩囨护鐢ㄦ埛ID
+        ['a.userId = :userId', { userId: ctx.user.id }],
+      ];
+    },
+  },
+})
+export class AppOrderInfoController extends BaseController {
+  @Inject()
+  orderInfoService: OrderInfoService;
+
+  @Inject()
+  ctx;
+
+  @Post('/create', { summary: '鍒涘缓璁㈠崟' })
+  async create(
+    @Body('data')
+    data: {
+      goodsList: OrderGoodsEntity[];
+      addressId: number;
+      remark: string;
+      title: string;
+      couponId: number;
+    }
+  ) {
+    return this.ok(
+      await this.orderInfoService.create({
+        ...data,
+        userId: this.ctx.user.id,
+      })
+    );
+  }
+
+  @Post('/cancel', { summary: '鍙栨秷璁㈠崟' })
+  async cancel(
+    @Body('orderId') orderId: number,
+    @Body('remark') remark: string
+  ) {
+    return this.ok(await this.orderInfoService.close(orderId, remark));
+  }
+
+  @Post('/refund', { summary: '閫�娆�' })
+  async refund(
+    @Body('orderId') orderId: number,
+    @Body('reason') reason: string
+  ) {
+    return this.ok(
+      await this.orderInfoService.refund(this.ctx.user.id, orderId, reason)
+    );
+  }
+
+  @Get('/confirm', { summary: '纭鏀惰揣' })
+  async confirm(@Query('orderId') orderId: number) {
+    return this.ok(
+      await this.orderInfoService.confirm(orderId, this.ctx.user.id)
+    );
+  }
+
+  @Get('/logistics', { summary: '鐗╂祦淇℃伅' })
+  async logistics(@Query('orderId') orderId: number) {
+    return this.ok(
+      await this.orderInfoService.logistics(orderId, this.ctx.user.id)
+    );
+  }
+
+  @Get('/userCount', { summary: '鐢ㄦ埛璁㈠崟缁熻' })
+  async userCount() {
+    return this.ok(await this.orderInfoService.userCount(this.ctx.user.id));
+  }
+}
diff --git a/src/modules/order/controller/app/pay.ts b/src/modules/order/controller/app/pay.ts
new file mode 100644
index 0000000..ffa1b39
--- /dev/null
+++ b/src/modules/order/controller/app/pay.ts
@@ -0,0 +1,64 @@
+import {
+  CoolController,
+  BaseController,
+  CoolUrlTag,
+  CoolTag,
+  TagTypes,
+} from '@cool-midway/core';
+import { Body, Inject, Post } from '@midwayjs/core';
+import { PluginService } from '../../../plugin/service/info';
+import { OrderPayService } from '../../service/pay';
+
+/**
+ * 鏀粯
+ */
+@CoolUrlTag()
+@CoolController()
+export class OrderPayController extends BaseController {
+  @Inject()
+  pluginService: PluginService;
+
+  @Inject()
+  orderPayService: OrderPayService;
+
+  @Inject()
+  ctx;
+
+  @CoolTag(TagTypes.IGNORE_TOKEN)
+  @Post('/wxNotify', { summary: '寰俊鏀粯鍥炶皟' })
+  async wxNotify(@Body() body) {
+    // 鑾峰緱鎻掍欢瀹炰緥
+    const plugin: any = await this.pluginService.getInstance('pay-wx');
+    // 鑾峰緱寰俊鏀粯 SDK 瀹炰緥
+    const instance = await plugin.getInstance();
+    const { ciphertext, associated_data, nonce } = body.resource;
+    const data: any = instance.decipher_gcm(ciphertext, associated_data, nonce);
+    const check = await plugin.signVerify(this.ctx);
+    // 楠岀閫氳繃锛屽鐞嗕笟鍔¢�昏緫
+    if (check && data.trade_state == 'SUCCESS') {
+      return await this.orderPayService.paySuccess(data.out_trade_no, 1);
+    }
+    return 'fail';
+  }
+
+  @Post('/wxMiniPay', { summary: '寰俊灏忕▼搴忔敮浠�' })
+  async wxMiniPay(@Body('orderId') orderId) {
+    return this.ok(
+      await this.orderPayService.wxMiniPay(orderId, this.ctx.user.id)
+    );
+  }
+
+  @Post('/wxMpPay', { summary: '寰俊鍏紬鍙锋敮浠�' })
+  async wxMpPay(@Body('orderId') orderId) {
+    return this.ok(
+      await this.orderPayService.wxMpPay(orderId, this.ctx.user.id)
+    );
+  }
+
+  @Post('/wxAppPay', { summary: '寰俊APP鏀粯' })
+  async wxAppPay(@Body('orderId') orderId) {
+    return this.ok(
+      await this.orderPayService.wxAppPay(orderId, this.ctx.user.id)
+    );
+  }
+}
diff --git a/src/modules/order/entity/goods.ts b/src/modules/order/entity/goods.ts
new file mode 100644
index 0000000..0aa1212
--- /dev/null
+++ b/src/modules/order/entity/goods.ts
@@ -0,0 +1,51 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+import { GoodsInfoEntity } from '../../goods/entity/info';
+import { GoodsSpecEntity } from '../../goods/entity/spec';
+
+/**
+ * 璁㈠崟鍟嗗搧
+ */
+@Entity('order_goods')
+export class OrderGoodsEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '璁㈠崟ID' })
+  orderId: number;
+
+  @Index()
+  @Column({ comment: '鍟嗗搧ID' })
+  goodsId: number;
+
+  @Column({
+    comment: '浠锋牸',
+    type: 'decimal',
+    precision: 12,
+    scale: 2,
+  })
+  price: number;
+
+  @Column({
+    comment: '浼樻儬閲戦',
+    type: 'decimal',
+    scale: 2,
+    precision: 12,
+    default: 0,
+  })
+  discountPrice: number;
+
+  @Column({ comment: '鏁伴噺' })
+  count: number;
+
+  @Column({ comment: '鍏朵粬淇℃伅', nullable: true })
+  remark: string;
+
+  // 闅忕潃鏃堕棿鐨勬帹绉伙紝鍟嗗搧淇℃伅浼氬彉锛岃繖杈瑰繀椤昏褰曡喘涔版椂鐨勫晢鍝佷俊鎭�
+  @Column({ comment: '鍟嗗搧淇℃伅', type: 'json' })
+  goodsInfo: GoodsInfoEntity;
+
+  @Column({ comment: '瑙勬牸', type: 'json', nullable: true })
+  spec: GoodsSpecEntity;
+
+  @Column({ comment: '鏄惁璇勪环 0-鍚� 1-鏄�', default: 0 })
+  isComment: number;
+}
diff --git a/src/modules/order/entity/info.ts b/src/modules/order/entity/info.ts
new file mode 100644
index 0000000..ee48bb0
--- /dev/null
+++ b/src/modules/order/entity/info.ts
@@ -0,0 +1,126 @@
+import { BaseEntity } from '@cool-midway/core';
+import { Column, Entity, Index } from 'typeorm';
+import { UserAddressEntity } from '../../user/entity/address';
+import { OrderGoodsEntity } from './goods';
+
+/**
+ * 璁㈠崟淇℃伅
+ */
+@Entity('order_info')
+export class OrderInfoEntity extends BaseEntity {
+  @Index()
+  @Column({ comment: '鐢ㄦ埛ID' })
+  userId: number;
+
+  @Column({ comment: '鏍囬', nullable: true })
+  title: string;
+
+  @Column({ comment: '鏀粯鏂瑰紡 0-寰呮敮浠� 1-寰俊 2-鏀粯瀹�', default: 0 })
+  payType: number;
+
+  @Column({ comment: '鏀粯鏃堕棿', type: 'datetime', nullable: true })
+  payTime: Date;
+
+  @Index()
+  @Column({ comment: '璁㈠崟鍙�', nullable: true })
+  orderNum: string;
+
+  @Column({
+    comment:
+      '鐘舵�� 0-寰呬粯娆� 1-寰呭彂璐� 2-寰呮敹璐� 3-寰呰瘎浠� 4-浜ゆ槗瀹屾垚 5-閫�娆句腑 6-宸查��娆� 7-宸插叧闂�',
+    type: 'tinyint',
+    default: 0,
+  })
+  status: number;
+
+  @Column({
+    comment: '浠锋牸',
+    type: 'decimal',
+    precision: 12,
+    scale: 2,
+  })
+  price: number;
+
+  @Column({
+    comment: '浼樻儬閲戦',
+    type: 'decimal',
+    scale: 2,
+    precision: 12,
+    default: 0,
+  })
+  discountPrice: number;
+
+  @Column({ comment: '浼樻儬鏉ユ簮', type: 'json', nullable: true })
+  discountSource: {
+    // 0-浼樻儬鍒�
+    type: number;
+    // 瀵硅薄ID
+    objectId: number;
+    // 淇℃伅
+    info: any;
+  };
+
+  @Column({ comment: '鍦板潃', type: 'json', nullable: true })
+  address: UserAddressEntity;
+
+  @Column({ comment: '鐗╂祦淇℃伅', type: 'json', nullable: true })
+  logistics: {
+    // 鐗╂祦鍏徃
+    company: string;
+    // 鐗╂祦鍗曞彿
+    num: string;
+  };
+
+  @Column({ comment: '閫�娆�', type: 'json', nullable: true })
+  refund: {
+    // 閫�娆惧崟鍙�
+    orderNum: string;
+    // 閲戦
+    amount: number;
+    // 瀹為檯閫�娆鹃噾棰�
+    realAmount: number;
+    // 鐘舵�� 0-鐢宠涓� 1-宸查��娆� 2-鎷掔粷
+    status: number;
+    // 鐢宠鏃堕棿
+    applyTime: Date;
+    // 閫�娆炬椂闂�
+    time: Date;
+    // 閫�娆惧師鍥�
+    reason: string;
+    // 鎷掔粷鍘熷洜
+    refuseReason: string;
+  };
+
+  @Index()
+  @Column({
+    asExpression: "JSON_EXTRACT(refund, '$.status')",
+    generatedType: 'VIRTUAL',
+    comment: '閫�娆剧姸鎬�',
+    nullable: true,
+  })
+  refundStatus: number;
+
+  @Index()
+  @Column({
+    asExpression: "JSON_EXTRACT(refund, '$.applyTime')",
+    generatedType: 'VIRTUAL',
+    comment: '閫�娆剧敵璇锋椂闂�',
+    nullable: true,
+  })
+  refundApplyTime: Date;
+
+  @Column({ comment: '澶囨敞', nullable: true })
+  remark: string;
+
+  @Column({ comment: '鍏抽棴澶囨敞', nullable: true })
+  closeRemark: string;
+
+  @Column({ comment: '宸插紑绁�: 0-鏈紑绁� 1-宸插紑绁�', default: 0 })
+  invoice: number;
+
+  @Column({ comment: '寰俊绫诲瀷 0-灏忕▼搴� 1-鍏紬鍙� 2-App', default: 0 })
+  wxType: number;
+
+  // 璁㈠崟鍟嗗搧
+  goodsList: OrderGoodsEntity[];
+}
diff --git a/src/modules/order/queue/order.ts b/src/modules/order/queue/order.ts
new file mode 100644
index 0000000..8e5058c
--- /dev/null
+++ b/src/modules/order/queue/order.ts
@@ -0,0 +1,33 @@
+import { BaseCoolQueue, CoolQueue } from '@cool-midway/task';
+import { Inject } from '@midwayjs/core';
+import { OrderInfoService } from '../service/info';
+
+// 琛屼负
+export enum Action {
+  // 瓒呮椂鏈敮浠�
+  TIMEOUT = 0,
+  // 鑷姩纭鏀惰揣
+  CONFIRM = 1,
+}
+
+/**
+ * 闃熷垪
+ */
+@CoolQueue()
+export abstract class OrderQueue extends BaseCoolQueue {
+  @Inject()
+  orderInfoService: OrderInfoService;
+
+  async data(job: any, done: any) {
+    const action = job.data.action;
+    if (action == Action.TIMEOUT) {
+      // 鍏抽棴璁㈠崟
+      await this.orderInfoService.close(job.data.orderId, '瓒呮椂鏈敮浠�');
+    }
+    if (action == Action.CONFIRM) {
+      // 鑷姩纭鏀惰揣
+      await this.orderInfoService.autoConfirm(job.data.orderId);
+    }
+    done();
+  }
+}
diff --git a/src/modules/order/service/goods.ts b/src/modules/order/service/goods.ts
new file mode 100644
index 0000000..1b50be6
--- /dev/null
+++ b/src/modules/order/service/goods.ts
@@ -0,0 +1,80 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Equal, In, Repository } from 'typeorm';
+import { OrderGoodsEntity } from '../entity/goods';
+import BigNumber from 'bignumber.js';
+import { GoodsSpecService } from '../../goods/service/spec';
+
+/**
+ * 璁㈠崟鍟嗗搧
+ */
+@Provide()
+export class OrderGoodsService extends BaseService {
+  @InjectEntityModel(OrderGoodsEntity)
+  orderGoodsEntity: Repository<OrderGoodsEntity>;
+
+  @Inject()
+  goodsSpecService: GoodsSpecService;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.orderGoodsEntity);
+  }
+
+  /**
+   * 淇濆瓨
+   * @param orderId
+   * @param goodsList
+   */
+  async save(orderId: number, goodsList: OrderGoodsEntity[]) {
+    await this.orderGoodsEntity.save(
+      goodsList.map(item => {
+        item.orderId = orderId;
+        return item;
+      })
+    );
+  }
+
+  /**
+   * 鑾峰緱鎬讳环
+   * @param goodsList
+   */
+  async getTotalPrice(goodsList: OrderGoodsEntity[]) {
+    let totalPrice = new BigNumber(0);
+    for (const goods of goodsList) {
+      totalPrice = totalPrice.plus(goods.price * goods.count);
+    }
+    return totalPrice.toNumber();
+  }
+
+  /**
+   * 閫氳繃璁㈠崟ID鑾峰彇鍟嗗搧
+   * @param orderId
+   */
+  async getByOrderId(orderId: number) {
+    return await this.orderGoodsEntity.findBy({ orderId: Equal(orderId) });
+  }
+
+  /**
+   * 閫氳繃璁㈠崟ID鑾峰彇鍟嗗搧
+   * @param orderId
+   */
+  async getByOrderIds(orderIds: number[]) {
+    return await this.orderGoodsEntity.findBy({ orderId: In(orderIds) });
+  }
+
+  // 鏇存柊搴撳瓨
+  async updateStock(
+    goodsList: OrderGoodsEntity[],
+    type: 'add' | 'sub' = 'sub'
+  ) {
+    for (const goods of goodsList) {
+      await this.goodsSpecService.updateStock(
+        goods.spec.id,
+        type == 'add' ? goods.count : -goods.count
+      );
+    }
+  }
+}
diff --git a/src/modules/order/service/info.ts b/src/modules/order/service/info.ts
new file mode 100644
index 0000000..ed47d6b
--- /dev/null
+++ b/src/modules/order/service/info.ts
@@ -0,0 +1,463 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService, CoolCommException } from '@cool-midway/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Equal, In, Repository } from 'typeorm';
+import { OrderInfoEntity } from '../entity/info';
+import { OrderGoodsService } from './goods';
+import { OrderGoodsEntity } from '../entity/goods';
+import * as moment from 'moment';
+import { UserAddressService } from '../../user/service/address';
+import { Action, OrderQueue } from '../queue/order';
+import { OrderPayService } from './pay';
+import { PluginService } from '../../plugin/service/info';
+import { GoodsSpecEntity } from '../../goods/entity/spec';
+import { MarketCouponInfoService } from '../../market/service/coupon/info';
+import { MarketCouponUserEntity } from '../../market/entity/coupon/user';
+import { BaseSysParamService } from '../../base/service/sys/param';
+import BigNumber from 'bignumber.js';
+
+/**
+ * 璁㈠崟淇℃伅
+ */
+@Provide()
+export class OrderInfoService extends BaseService {
+  @InjectEntityModel(OrderInfoEntity)
+  orderInfoEntity: Repository<OrderInfoEntity>;
+
+  @InjectEntityModel(GoodsSpecEntity)
+  goodsSpecEntity: Repository<GoodsSpecEntity>;
+
+  @InjectEntityModel(MarketCouponUserEntity)
+  marketCouponUserEntity: Repository<MarketCouponUserEntity>;
+
+  @Inject()
+  orderGoodsService: OrderGoodsService;
+
+  @Inject()
+  userAddressService: UserAddressService;
+
+  @Inject()
+  orderPayService: OrderPayService;
+
+  @Inject()
+  orderQueue: OrderQueue;
+
+  @Inject()
+  pluginService: PluginService;
+
+  @Inject()
+  marketCouponInfoService: MarketCouponInfoService;
+
+  @Inject()
+  baseSysParamService: BaseSysParamService;
+
+  @Init()
+  async init() {
+    await super.init();
+    this.setEntity(this.orderInfoEntity);
+  }
+
+  /**
+   * 淇敼鍓�
+   * @param data
+   * @param type
+   */
+  async modifyBefore(data: any, type: 'add' | 'update' | 'delete') {
+    if (type == 'add' || type == 'update') {
+      delete data.refundStatus;
+      delete data.refundApplyTime;
+    }
+  }
+
+  /**
+   * 鍒嗛〉鏌ヨ
+   * @param query
+   * @param option
+   * @param connectionName
+   */
+  async page(query: any, option: any, connectionName?: any) {
+    const result = await super.page(query, option, connectionName);
+    // 绛涢�夋潯浠剁殑闈炲垎椤祍ql
+    const countSql = await super.getOptionFind(query, option);
+
+    const countResult = await this.nativeQuery(
+      `SELECT COUNT(a.id) as totalCount, SUM(a.price) as totalPrice FROM ${
+        countSql.split('FROM')[1].split('ORDER BY')[0]
+      }`
+    );
+
+    result['subData'] = {
+      totalCount: countResult[0].totalCount,
+      totalPrice: countResult[0].totalPrice,
+    };
+
+    const goodsList = await this.orderGoodsService.getByOrderIds(
+      result.list.map(e => e.id)
+    );
+    for (const item of result.list) {
+      item.goodsList = goodsList.filter(e => e.orderId == item.id);
+    }
+    return result;
+  }
+
+  /**
+   * 鏍规嵁璁㈠崟鍙疯幏鍙栬鍗�
+   * @param orderNum
+   * @returns
+   */
+  async getByOrderNum(orderNum: string) {
+    return this.orderInfoEntity.findOneBy({
+      orderNum: Equal(orderNum),
+    });
+  }
+
+  /**
+   * 淇敼璁㈠崟鐘舵��
+   * @param id
+   * @param status
+   */
+  async changeStatus(id: number, status: number) {
+    await this.orderInfoEntity.update({ id }, { status });
+  }
+
+  /**
+   * 鍏抽棴璁㈠崟
+   * @param orderId
+   * @param remark
+   */
+  async close(orderId: number, remark: string) {
+    const order = await this.info(orderId);
+    if (!order || !remark)
+      throw new CoolCommException('璁㈠崟涓嶅瓨鍦ㄦ垨澶囨敞涓嶈兘涓虹┖');
+    if (order.status != 0) {
+      throw new CoolCommException('璁㈠崟鐘舵�佷笉鍏佽鍏抽棴');
+    }
+
+    // 閫�鍥炰紭鎯犲埜
+    if (order.discountSource && order.discountPrice > 0) {
+      if (order.discountSource.type == 0) {
+        this.marketCouponUserEntity.update(
+          {
+            id: order.discountSource.objectId,
+          },
+          {
+            status: 0,
+          }
+        );
+      }
+    }
+
+    await this.orderInfoEntity.update(
+      { id: orderId },
+      { status: 7, closeRemark: remark }
+    );
+
+    // 閲婃斁搴撳瓨
+    await this.orderGoodsService.updateStock(order.goodsList, 'add');
+  }
+
+  /**
+   * 璁㈠崟璇︽儏
+   * @param id
+   * @param infoIgnoreProperty
+   */
+  async info(id: any, infoIgnoreProperty?: string[]) {
+    const info = await super.info(id, infoIgnoreProperty);
+    if (!info) {
+      throw new CoolCommException('璁㈠崟涓嶅瓨鍦�');
+    }
+    if (info) {
+      // 鑾峰彇鍟嗗搧
+      info.goodsList = await this.orderGoodsService.getByOrderId(info.id);
+    }
+    return info;
+  }
+
+  /**
+   * 鍒涘缓璁㈠崟
+   * @param data
+   */
+  async create(data: {
+    userId: number;
+    goodsList: OrderGoodsEntity[];
+    addressId: number;
+    remark: string;
+    title: string;
+    couponId?: number;
+  }) {
+    const address = await this.userAddressService.info(data.addressId);
+    const order = {
+      userId: data.userId,
+      address,
+      remark: data.remark,
+      title: data.title,
+      goodsList: data.goodsList,
+    } as OrderInfoEntity;
+    // 妫�鏌ュ簱瀛�
+    await this.checkStock(data.goodsList);
+    order.price = await this.orderGoodsService.getTotalPrice(data.goodsList);
+    order.goodsList = data.goodsList;
+
+    // 浣跨敤浼樻儬鍒�
+    if (data.couponId) {
+      await this.marketCouponInfoService.checkAndUse(
+        data.couponId,
+        data.userId,
+        order
+      );
+    }
+    await this.orderInfoEntity.insert(order);
+
+    // 鐢熸垚璁㈠崟鍙�
+    const orderNum = await this.generateOrderNum(order.id);
+
+    // 鏇存柊璁㈠崟
+    await this.orderInfoEntity.update(order.id, {
+      orderNum,
+    });
+
+    // 淇濆瓨璁㈠崟鍟嗗搧
+    await this.orderGoodsService.save(order.id, data.goodsList);
+
+    // 鏇存柊鍟嗗搧搴撳瓨
+    await this.orderGoodsService.updateStock(data.goodsList);
+
+    const orderTimeout = await this.baseSysParamService.dataByKey(
+      'orderTimeout'
+    );
+    // 鍙戦�佽鍗曞垱寤烘秷鎭�
+    this.orderQueue.add(
+      { orderId: order.id, action: Action.TIMEOUT },
+      {
+        // 瓒呮椂鍏抽棴璁㈠崟
+        delay: orderTimeout * 60 * 1000,
+      }
+    );
+    return order;
+  }
+
+  /**
+   * 鐢熸垚璁㈠崟鍙�
+   * @param orderId
+   */
+  async generateOrderNum(orderId: number, label = 'U') {
+    const orderNum =
+      moment().format('YYYYMMDDHHmmss') +
+      Math.floor(Math.random() * 10000).toString() +
+      orderId.toString();
+    return label + orderNum;
+  }
+
+  /**
+   * 閫�娆�
+   * @param userId
+   * @param orderId
+   * @param goodsId
+   * @param reason
+   */
+  async refund(userId: number, orderId: number, reason: string) {
+    const order = await this.info(orderId);
+    if (order && order.userId != userId) {
+      throw new CoolCommException('闈炴硶鎿嶄綔');
+    }
+    if (![1, 2].includes(order.status)) {
+      throw new CoolCommException('璁㈠崟鐘舵�佷笉鍏佽閫�娆�');
+    }
+
+    await this.orderInfoEntity.update(
+      { id: Equal(orderId) },
+      {
+        status: 5,
+        refund: {
+          amount: new BigNumber(order.price)
+            .minus(order.discountPrice)
+            .toNumber(),
+          status: 0,
+          applyTime: new Date(),
+          reason,
+          orderNum: 'R' + order.orderNum.slice(1),
+        },
+      }
+    );
+  }
+
+  /**
+   * 閫�娆惧鐞�
+   * @param orderId
+   * @param action 0-鎷掔粷 1-鍚屾剰
+   * @param refuseReason 0-鎷掔粷 1-鍚屾剰
+   * @param amount
+   */
+  async refundHandle(
+    orderId: number,
+    action: number,
+    refuseReason: string,
+    amount: number
+  ) {
+    const order = await this.info(orderId);
+    if (order.status != 5 || !order.refund) {
+      throw new CoolCommException('璁㈠崟鐘舵�佷笉鍏佽閫�娆惧鐞�');
+    }
+    // 鎷掔粷閫�娆�
+    if (action == 0) {
+      await this.orderInfoEntity.update(
+        { id: Equal(orderId) },
+        {
+          status: 4,
+          refund: {
+            ...order.refund,
+            status: 2,
+            refuseReason: refuseReason,
+          },
+        }
+      );
+    }
+    // 鍚屾剰閫�娆�
+    if (action == 1) {
+      if (amount > order.price) {
+        throw new CoolCommException('閫�娆鹃噾棰濅笉鑳藉ぇ浜庤鍗曢噾棰�');
+      }
+      // 鎵ц閫�娆炬搷浣�
+      const result = await this.orderPayService.wxRefund(order, amount);
+
+      if (result) {
+        await this.orderInfoEntity.update(
+          { id: Equal(orderId) },
+          {
+            status: 6,
+            refund: {
+              ...order.refund,
+              status: 1,
+              realAmount: amount,
+              time: new Date(),
+            },
+          }
+        );
+      }
+    }
+  }
+
+  /**
+   * 纭鏀惰揣
+   * @param userId
+   * @param orderId
+   */
+  async confirm(orderId: number, userId: number) {
+    const order = await this.info(orderId);
+    if (order && order.userId != userId) {
+      throw new CoolCommException('闈炴硶鎿嶄綔');
+    }
+    if (![2].includes(order.status)) {
+      throw new CoolCommException('璁㈠崟鐘舵�佷笉鍏佽閫�娆�');
+    }
+    await this.orderInfoEntity.update(
+      { id: Equal(orderId) },
+      {
+        status: 3,
+      }
+    );
+  }
+
+  /**
+   * 鑷姩纭鏀惰揣
+   * @param orderId
+   * @returns
+   */
+  async autoConfirm(orderId: number) {
+    const info = await this.orderInfoEntity.findOneBy({ id: Equal(orderId) });
+    if (info.status != 2) {
+      return;
+    }
+    await this.orderInfoEntity.update({ id: Equal(orderId) }, { status: 3 });
+  }
+
+  /**
+   * 鐗╂祦淇℃伅
+   * @param orderId
+   */
+  async logistics(orderId: number, userId?: number) {
+    const order: OrderInfoEntity = await this.info(orderId);
+    if (userId && order.userId != userId) {
+      throw new CoolCommException('闈炴硶鎿嶄綔');
+    }
+    const no = order.logistics?.num;
+
+    if (!no) {
+      return null;
+    }
+
+    const instance: any = await this.pluginService.getInstance('wuliu');
+    return await instance.query(no);
+  }
+
+  /**
+   * 鍙戣揣
+   * @param orderId
+   * @param logistics
+   */
+  async deliver(
+    orderId: number,
+    logistics: {
+      // 鐗╂祦鍏徃
+      company: string;
+      // 鐗╂祦鍗曞彿
+      num: string;
+    }
+  ) {
+    const order: OrderInfoEntity = await this.info(orderId);
+    if (order.status != 1) {
+      throw new CoolCommException('璁㈠崟鐘舵�佷笉鍏佽鍙戣揣');
+    }
+    await this.orderInfoEntity.update(orderId, {
+      status: 2,
+      logistics,
+    });
+  }
+
+  /**
+   * 妫�鏌ュ簱瀛�
+   * @param goodsList
+   */
+  async checkStock(goodsList: OrderGoodsEntity[]) {
+    const specs = goodsList.map(item => item.spec);
+    const specList = await this.goodsSpecEntity.findBy({
+      id: In(specs.map(e => e.id)),
+    });
+    for (const spec of specList) {
+      const goods = goodsList.find(e => e.spec.id == spec.id);
+      // 璁剧疆鍟嗗搧浠锋牸
+      goods.price = spec.price;
+      if (goods.count > spec.stock) {
+        throw new CoolCommException(`鍟嗗搧[${goods.goodsInfo.title}]锛屽簱瀛樹笉瓒砢);
+      }
+    }
+  }
+
+  /**
+   * 鐢ㄦ埛璁㈠崟鏁伴噺
+   * @param userId
+   */
+  async userCount(userId: number) {
+    const statusLabels = [
+      '寰呬粯娆�',
+      '寰呭彂璐�',
+      '寰呮敹璐�',
+      '寰呰瘎浠�',
+      '浜ゆ槗瀹屾垚',
+      '閫�娆句腑',
+      '宸查��娆�',
+      '宸插叧闂�',
+    ];
+    // 鐢熸垚鏌ヨ瀛楃涓�
+    const selectQueries = statusLabels.map(
+      (label, index) =>
+        `SUM(CASE WHEN status = ${index} THEN 1 ELSE 0 END) AS '${label}'`
+    );
+    const list = await this.orderInfoEntity
+      .createQueryBuilder('a')
+      .select(selectQueries)
+      .where('a.userId = :userId', { userId })
+      .getRawMany();
+    return list[0];
+  }
+}
diff --git a/src/modules/order/service/pay.ts b/src/modules/order/service/pay.ts
new file mode 100644
index 0000000..9f5d9f4
--- /dev/null
+++ b/src/modules/order/service/pay.ts
@@ -0,0 +1,238 @@
+import { Init, Inject, Provide } from '@midwayjs/core';
+import { BaseService, CoolCommException } from '@cool-midway/core';
+import { PluginService } from '../../plugin/service/info';
+import { OrderInfoService } from './info';
+import { UserWxService } from '../../user/service/wx';
+import BigNumber from 'bignumber.js';
+import { OrderInfoEntity } from '../entity/info';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+import { Action, OrderQueue } from '../queue/order';
+import { BaseSysParamService } from '../../base/service/sys/param';
+
+/**
+ * 鏀粯
+ */
+@Provide()
+export class OrderPayService extends BaseService {
+  @InjectEntityModel(OrderInfoEntity)
+  orderInfoEntity: Repository<OrderInfoEntity>;
+
+  @Inject()
+  pluginService: PluginService;
+
+  @Inject()
+  orderInfoService: OrderInfoService;
+
+  @Inject()
+  userWxService: UserWxService;
+
+  @Inject()
+  orderQueue: OrderQueue;
+
+  @Inject()
+  baseSysParamService: BaseSysParamService;
+
+  @Init()
+  async init() {
+    await super.init();
+  }
+
+  /**
+   * 鏀粯鎴愬姛
+   * @param orderNum 璁㈠崟鍙�
+   * @param payType 鏀粯鏂瑰紡 0-寰呮敮浠� 1-寰俊 2-鏀粯瀹�
+   */
+  async paySuccess(orderNum: string, payType: number) {
+    const order = await this.orderInfoService.getByOrderNum(orderNum);
+    if (order && order.status == 0) {
+      await this.orderInfoEntity.update(order.id, {
+        payType,
+        status: 1,
+        payTime: order.payTime,
+      });
+      // 鍙戦�佽嚜鍔ㄧ‘璁ゆ敹璐ч槦鍒�
+      const orderConfirm = await this.baseSysParamService.dataByKey(
+        'orderConfirm'
+      );
+      this.orderQueue.add(
+        { orderId: order.id, action: Action.CONFIRM },
+        {
+          // 鑷姩纭鏀惰揣鏃堕棿
+          delay: orderConfirm * 60 * 60 * 1000,
+        }
+      );
+    }
+    return 'success';
+  }
+
+  /**
+   * 寰俊灏忕▼搴忔敮浠�
+   * @param userId
+   * @param orderId
+   */
+  async wxMiniPay(orderId: number, userId: number) {
+    await this.orderInfoEntity.update(orderId, { wxType: 0 });
+    return await this.wxJSAPI(orderId, userId, 0);
+  }
+
+  /**
+   * 寰俊鍏紬鍙锋敮浠�
+   * @param userId
+   * @param orderId
+   */
+  async wxMpPay(orderId: number, userId: number) {
+    await this.orderInfoEntity.update(orderId, { wxType: 1 });
+    return await this.wxJSAPI(orderId, userId, 1);
+  }
+
+  /**
+   * 鑾峰緱appid
+   * @param type 0-灏忕▼搴� 1-鍏紬鍙� 2-App
+   */
+  async getAppidByType(type: number) {
+    let account;
+    const plugin: any = await this.pluginService.getInstance('wx');
+    // 灏忕▼搴�
+    if (type == 0) {
+      account = (await plugin.MiniApp()).getAccount();
+    }
+    // 鍏紬鍙�
+    if (type == 1) {
+      account = (await plugin.OfficialAccount()).getAccount();
+    }
+    // App
+    if (type == 2) {
+      account = (await plugin.OpenPlatform()).getAccount();
+    }
+    // 鑾峰緱appid
+    const appid = account.getAppId();
+    return appid;
+  }
+
+  /**
+   * 鑾峰緱寰俊鏀粯 SDK 瀹炰緥
+   * @param type 0-灏忕▼搴� 1-鍏紬鍙� 2-App
+   * @returns
+   */
+  async wxPayInstance(appid: string) {
+    // 鑾峰緱鎻掍欢瀹炰緥
+    const plugin: any = await this.pluginService.getInstance('pay-wx');
+    // 鑾峰緱鎻掍欢閰嶇疆
+    const config = await plugin.getConfig();
+    // 鑾峰緱寰俊鏀粯 SDK 瀹炰緥
+    const instance = await plugin.getInstance({
+      ...config,
+      appid,
+    });
+    return { config, instance };
+  }
+
+  /**
+   * 寰俊APP鏀粯
+   * @param orderId
+   * @param userId
+   * @returns
+   */
+  async wxAppPay(orderId: number, userId: number) {
+    const appid = await this.getAppidByType(2);
+
+    const { config, instance } = await this.wxPayInstance(appid);
+
+    const order = await this.getOrder(orderId, userId);
+    const params = {
+      description: '鍟嗗搧閲囪喘',
+      out_trade_no: order?.orderNum,
+      notify_url: config.notify_url,
+      amount: {
+        total: new BigNumber(order.price)
+          .minus(order.discountPrice || 0)
+          .multipliedBy(100)
+          .toNumber(),
+      },
+    };
+
+    const result = await instance.transactions_app(params);
+    return result;
+  }
+
+  /**
+   * 鑾峰緱璁㈠崟
+   * @param orderId
+   * @param userId
+   * @returns
+   */
+  async getOrder(orderId: number, userId: number) {
+    const order: OrderInfoEntity = await this.orderInfoService.info(orderId);
+    if (!order || order.status != 0 || order.userId != userId) {
+      throw new CoolCommException('璁㈠崟涓嶅瓨鍦ㄦ垨涓嶆槸鍙互鏀粯鐨勭姸鎬�');
+    }
+    return order;
+  }
+
+  /**
+   * 寰俊JSAPI
+   * @param orderId
+   * @param userId
+   * @param type 0-灏忕▼搴� 1-鍏紬鍙� 2-App
+   * @returns
+   */
+  async wxJSAPI(orderId: number, userId: number, type = 0) {
+    const order = await this.getOrder(orderId, userId);
+    const openid = await this.userWxService.getOpenid(userId, type);
+
+    const appid = await this.getAppidByType(type);
+
+    const { config, instance } = await this.wxPayInstance(appid);
+
+    const params = {
+      description: '鍟嗗搧閲囪喘',
+      out_trade_no: order.orderNum,
+      notify_url: config.notify_url,
+      amount: {
+        total: new BigNumber(order.price)
+          .minus(order.discountPrice || 0)
+          .multipliedBy(100)
+          .toNumber(),
+      },
+      payer: {
+        openid,
+      },
+      scene_info: {
+        payer_client_ip: '127.0.0.1',
+      },
+    };
+    const result = await instance.transactions_jsapi(params);
+    return result;
+  }
+
+  /**
+   * 寰俊閫�娆�
+   * @param order
+   * @param amount
+   * @returns
+   */
+  async wxRefund(order: OrderInfoEntity, amount: number) {
+    const appid = await this.getAppidByType(order.wxType);
+    const { config, instance } = await this.wxPayInstance(appid);
+    const params = {
+      out_trade_no: order.orderNum,
+      out_refund_no: order.refund.orderNum,
+      notify_url: config.notify_url,
+      amount: {
+        refund: new BigNumber(amount).multipliedBy(100).toNumber(),
+        total: new BigNumber(order.price).multipliedBy(100).toNumber(),
+        currency: 'CNY',
+      },
+    };
+    const result = await instance.refunds(params);
+    if (
+      result.status == 200 ||
+      result.status == 'SUCCESS' ||
+      result.status == 'PROCESSING'
+    ) {
+      return true;
+    }
+    throw new CoolCommException(result.message);
+  }
+}
diff --git a/src/modules/user/config.ts b/src/modules/user/config.ts
index 6c8cf60..b14f922 100644
--- a/src/modules/user/config.ts
+++ b/src/modules/user/config.ts
@@ -28,7 +28,7 @@
       // 鍒锋柊token 杩囨湡鏃堕棿锛屽崟浣嶇
       refreshExpire: 60 * 60 * 24 * 30,
       // jwt 绉橀挜
-      secret: 'b4652251-d174-4e8e-9c61-25a091afb328x',
+      secret: '5b81d7bc-11cc-485d-8d6b-39d3e7c48f74x',
     },
   } as ModuleConfig;
 };
diff --git a/src/modules/user/controller/admin/info.ts b/src/modules/user/controller/admin/info.ts
index 19ef3f3..addf3c4 100644
--- a/src/modules/user/controller/admin/info.ts
+++ b/src/modules/user/controller/admin/info.ts
@@ -29,4 +29,4 @@
 
   },
 })
-export class AdminUserInfoController extends BaseController { }
+export class AdminUserInfoController extends BaseController {}
diff --git a/src/modules/user/controller/app/login.ts b/src/modules/user/controller/app/login.ts
index e089df4..3f76431 100644
--- a/src/modules/user/controller/app/login.ts
+++ b/src/modules/user/controller/app/login.ts
@@ -103,4 +103,15 @@
   ) {
     return this.ok(await this.userLoginService.password(phone, password));
   }
+
+  @CoolTag(TagTypes.IGNORE_TOKEN)
+  @Post('/sorterPassword', { summary: '瀵嗙爜鐧诲綍' })
+  async sorterPassword(
+    @Body('phone') phone: string,
+    @Body('password') password: string
+  ) {
+    return this.ok(await this.userLoginService.sorterPassword(phone, password));
+  }
+
+
 }
diff --git a/src/modules/user/service/info.ts b/src/modules/user/service/info.ts
index 58dd8fd..1331c45 100644
--- a/src/modules/user/service/info.ts
+++ b/src/modules/user/service/info.ts
@@ -85,7 +85,7 @@
           uuid() + '.png'
         );
       }
-    } catch (err) { }
+    } catch (err) {}
     try {
       return await this.userInfoEntity.update({ id }, param);
     } catch (err) {
diff --git a/src/modules/user/service/login.ts b/src/modules/user/service/login.ts
index 440e5a9..0b8d2f2 100644
--- a/src/modules/user/service/login.ts
+++ b/src/modules/user/service/login.ts
@@ -3,6 +3,7 @@
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Equal, Repository } from 'typeorm';
 import { UserInfoEntity } from '../entity/info';
+import { BasicdataSorterEntity } from '../../basicdata/entity/sorter';
 import { UserWxService } from './wx';
 import * as jwt from 'jsonwebtoken';
 import { UserWxEntity } from '../entity/wx';
@@ -19,6 +20,9 @@
 export class UserLoginService extends BaseService {
   @InjectEntityModel(UserInfoEntity)
   userInfoEntity: Repository<UserInfoEntity>;
+
+  @InjectEntityModel(BasicdataSorterEntity)
+  basicdataSorterEntity: Repository<BasicdataSorterEntity>;
 
   @InjectEntityModel(UserWxEntity)
   userWxEntity: Repository<UserWxEntity>;
@@ -275,6 +279,34 @@
   }
 
   /**
+   * 鍒嗘嫞浜哄憳-瀵嗙爜鐧诲綍
+   * @param phone
+   * @param password
+   */
+  async sorterPassword(phone, password) {
+    const user = await this.basicdataSorterEntity.findOneBy({ phone });
+
+    if (user && user.password == md5(password)) {
+
+      const info = {
+        id: user.businessId,
+      }
+      const { expire, refreshExpire } = this.jwtConfig;
+      return {
+        expire,
+        token: await this.generateSorterToken(info),
+        refreshExpire,
+        refreshToken: await this.generateSorterToken(info, true),
+      };
+
+    } else {
+      throw new CoolCommException('璐﹀彿鎴栧瘑鐮侀敊璇�');
+    }
+  }
+
+
+
+  /**
    * 鑾峰緱token
    * @param info
    * @returns
@@ -306,4 +338,22 @@
       expiresIn: isRefresh ? refreshExpire : expire,
     });
   }
+
+  /**
+   * 鐢熸垚token
+   * @param tokenInfo 淇℃伅
+   * @param roleIds 瑙掕壊闆嗗悎
+   */
+  async generateSorterToken(info, isRefresh = false) {
+    const { expire, refreshExpire, secret } = this.jwtConfig;
+    const user = await this.basicdataSorterEntity.findOneBy({ businessId: Equal(info.id) });
+    const tokenInfo = {
+      isRefresh,
+      ...info,
+      tenantId: user?.tenantId,
+    };
+    return jwt.sign(tokenInfo, secret, {
+      expiresIn: isRefresh ? refreshExpire : expire,
+    });
+  }
 }
diff --git a/typings/pay-wx.d.ts b/typings/pay-wx.d.ts
new file mode 100644
index 0000000..035a8fc
--- /dev/null
+++ b/typings/pay-wx.d.ts
@@ -0,0 +1,53 @@
+import { BasePlugin } from '@cool-midway/plugin-cli';
+/**
+ * 寰俊鏀粯
+ */
+export declare class CoolPlugin extends BasePlugin {
+  /**
+   * 鐢熸垚璁㈠崟鍙凤紝鍩轰簬鏃堕棿鎴�+鍞竴瀛楃涓�+闅忔満鏁�+鍙�夌殑瀛怚D
+   * @param subId 鍙�夛紝濡備綘鐨勮鍗旾D, 鎴栬�呯敤鎴稩D鐨勪竴浜涚粍鍚�
+   * @returns 璁㈠崟鍙�
+   */
+  createOrderNum(subId?: string): string;
+  /**
+   * 鑾峰緱閰嶇疆
+   */
+  getConfig(): Promise<any>;
+  /**
+   * 鑾峰緱寰俊鏀粯SDK瀹炰緥
+   * @param config 鍔ㄦ�侀厤缃�
+   * @returns
+   */
+  getInstance(config?: {
+    appid: string;
+    mchid: string;
+    key: string;
+    notify_url: string;
+    publicKey: Buffer;
+    privateKey: Buffer;
+  }): Promise<any>;
+  /**
+   * 鏍规嵁缁欏畾鐨� URL 涓嬭浇鏂囦欢骞惰繑鍥炰竴涓� Buffer銆�
+   * @param {string} url 鏂囦欢鐨� URL
+   * @return {Promise<Buffer>} 杩斿洖涓�涓� Promise锛岃В鏋愪负鏂囦欢鍐呭鐨� Buffer
+   */
+  downloadFileAsBuffer(url: any): Promise<Buffer<any>>;
+  /**
+   * 绛惧悕
+   * @param ctx 璇锋眰涓婁笅鏂�
+   * @param config 鍔ㄦ�侀厤缃�
+   * @returns
+   */
+  signVerify(
+    ctx: any,
+    config?: {
+      appid: string;
+      mchid: string;
+      key: string;
+      notify_url: string;
+      publicKey: Buffer;
+      privateKey: Buffer;
+    },
+  ): Promise<any>;
+}
+export declare const Plugin: typeof CoolPlugin;
diff --git a/typings/plugin.d.ts b/typings/plugin.d.ts
index e2ae5a0..14b5d95 100644
--- a/typings/plugin.d.ts
+++ b/typings/plugin.d.ts
@@ -1,3 +1,8 @@
+import * as wuliu from './wuliu';
+import * as pay_wx from './pay-wx';
+import * as wx from './wx';
+import * as upload_oss from './upload-oss';
+import * as sms_ali from './sms-ali';
 import { BaseUpload, MODETYPE } from './upload';
 type AnyString = string & {};
 /**
@@ -5,4 +10,9 @@
  */
 interface PluginMap {
   upload: BaseUpload;
+  'sms-ali': sms_ali.CoolPlugin;
+  'upload-oss': upload_oss.CoolPlugin;
+  wx: wx.CoolPlugin;
+  'pay-wx': pay_wx.CoolPlugin;
+  wuliu: wuliu.CoolPlugin;
 }
diff --git a/typings/sms-ali.d.ts b/typings/sms-ali.d.ts
new file mode 100644
index 0000000..13e9b8f
--- /dev/null
+++ b/typings/sms-ali.d.ts
@@ -0,0 +1,28 @@
+import { BasePlugin } from '@cool-midway/plugin-cli';
+/**
+ * 闃块噷浜戠煭淇�
+ */
+export declare class CoolPlugin extends BasePlugin {
+  /**
+   * 鍙戦��
+   * @param phone 鎵嬫満鍙锋暟缁� 鏈�澶氫笉瑕佽秴杩�200涓墜鏈哄彿
+   * @param params 鍙傛暟鏁扮粍 鐭俊妯℃澘鍙傛暟, 渚嬪: {code: '1234', product: 'yours'}
+   * @param config 閰嶇疆 signName 绛惧悕 template 妯℃澘 options 鍏朵粬閰嶇疆 countryCode 鍥藉鍖哄彿 榛樿 +86
+   * @returns 杩斿洖缁撴灉
+   */
+  send(
+    phone: string[],
+    params: {
+      [key: string]: any;
+    },
+    config?: {
+      signName: string;
+      template: string;
+      countryCode?: string;
+      options?: {
+        [key: string]: any;
+      };
+    },
+  ): Promise<any>;
+}
+export declare const Plugin: typeof CoolPlugin;
diff --git a/typings/upload-oss.d.ts b/typings/upload-oss.d.ts
new file mode 100644
index 0000000..3adbe06
--- /dev/null
+++ b/typings/upload-oss.d.ts
@@ -0,0 +1,59 @@
+import {
+  BasePlugin,
+  BaseUpload,
+  Mode,
+  PluginInfo,
+} from '@cool-midway/plugin-cli';
+import OSS from 'ali-oss';
+/**
+ * 鎻忚堪
+ */
+export declare class CoolPlugin extends BasePlugin implements BaseUpload {
+  client: OSS;
+  /**
+   * 鍒濆鍖�
+   * @param pluginInfo
+   */
+  init(pluginInfo: PluginInfo): Promise<void>;
+  /**
+   * 鑾峰緱涓婁紶妯″紡
+   */
+  getMode(): Promise<Mode>;
+  /**
+   * 鑾峰緱鍘熷鎿嶄綔瀵硅薄
+   * @returns
+   */
+  getMetaFileObj(): OSS;
+  /**
+   * 鏍规嵁缁欏畾鐨� URL 涓嬭浇鏂囦欢骞惰繑鍥炰竴涓� Buffer銆�
+   * @param {string} url 鏂囦欢鐨� URL
+   * @return {Promise<Buffer>} 杩斿洖涓�涓� Promise锛岃В鏋愪负鏂囦欢鍐呭鐨� Buffer
+   */
+  downloadFileAsBuffer(url: any): Promise<Buffer<any>>;
+  /**
+   * 涓嬭浇骞朵笂浼�
+   * @param url
+   * @param fileName 鏂囦欢鍚�
+   */
+  downAndUpload(url: string, fileName?: string): Promise<string>;
+  /**
+   * 鎸囧畾Key(璺緞)涓婁紶
+   * @param filePath 鏂囦欢璺緞
+   * @param key 璺緞涓�鑷翠細瑕嗙洊婧愭枃浠�
+   */
+  uploadWithKey(filePath: any, key: any): Promise<string>;
+  /**
+   * 鑾峰緱绛惧悕
+   * @param ctx
+   * @returns
+   */
+  upload(ctx?: any): Promise<{
+    signature: string;
+    policy: string;
+    host: any;
+    publicDomain: any;
+    OSSAccessKeyId: any;
+    success_action_status: number;
+  }>;
+}
+export declare const Plugin: typeof CoolPlugin;
diff --git a/typings/wuliu.d.ts b/typings/wuliu.d.ts
new file mode 100644
index 0000000..188b77d
--- /dev/null
+++ b/typings/wuliu.d.ts
@@ -0,0 +1,19 @@
+import { BasePlugin } from '@cool-midway/plugin-cli';
+/**
+ * 鐗╂枡鏌ヨ
+ */
+export declare class CoolPlugin extends BasePlugin {
+  host: string;
+  /**
+   * 闃块噷浜戝競鍦虹墿娴佹煡璇�  https://market.aliyun.com/products/56928004/cmapi021863.html
+   * @param no 蹇�掑崟鍙�
+   * @param type 蹇�掑叕鍙哥紪鐮侊紝涓嶄紶鍒欒嚜鍔ㄨ瘑鍒�(鍑嗙‘鐜�95%)
+   */
+  query(no: string, type?: string): Promise<any>;
+  /**
+   * 鑾峰緱鎵�鏈夊揩閫掑叕鍙�
+   * @returns
+   */
+  companyList(): Promise<any>;
+}
+export declare const Plugin: typeof CoolPlugin;
diff --git a/typings/wx.d.ts b/typings/wx.d.ts
new file mode 100644
index 0000000..a1f8c73
--- /dev/null
+++ b/typings/wx.d.ts
@@ -0,0 +1,58 @@
+import { BasePlugin } from '@cool-midway/plugin-cli';
+import {
+  OfficialAccount,
+  MiniApp,
+  Pay,
+  OpenPlatform,
+  Work,
+  OpenWork,
+} from 'node-easywechat';
+/**
+ * 寰俊
+ */
+export declare class CoolPlugin extends BasePlugin {
+  /**
+   * 鍏紬鍙�
+   * @param config
+   * @returns
+   */
+  OfficialAccount(config?: any): Promise<any>;
+  /**
+   * 灏忕▼搴�
+   * @param config
+   * @returns
+   */
+  MiniApp(config?: any): Promise<any>;
+  /**
+   * 鏀粯
+   * @param config
+   * @returns
+   */
+  Pay(config?: any): Promise<any>;
+  /**
+   * 寮�鏀惧钩鍙�
+   * @param config
+   * @returns
+   */
+  OpenPlatform(config?: any): Promise<any>;
+  /**
+   * 浼佷笟寰俊
+   * @param config
+   * @returns
+   */
+  Work(config?: any): Promise<any>;
+  /**
+   * 浼佷笟寰俊寮�鏀惧钩鍙�
+   * @param config
+   * @returns
+   */
+  OpenWork(config?: any): Promise<any>;
+  /**
+   * 璁剧疆缂撳瓨
+   * @param app
+   */
+  setCache(
+    app: OfficialAccount | MiniApp | Pay | OpenPlatform | Work | OpenWork,
+  ): Promise<void>;
+}
+export declare const Plugin: typeof CoolPlugin;

--
Gitblit v1.9.1