q-koa 13.8.57 → 13.8.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/app.js CHANGED
@@ -672,285 +672,265 @@ class APP {
672
672
  __dirname,
673
673
  `${rootDirectory}/${APP_DIR}/${appName}/${PLUGINS_DIR}`
674
674
  )
675
- const publicExist = fs.existsSync(pluginDir)
676
- if (!publicExist) await fsPromise.mkdir(pluginDir)
675
+ await fsPromise.mkdir(pluginDir, { recursive: true })
677
676
  const excludesModel = _.get(
678
677
  this.app[appName],
679
678
  'appConfig.excludesModel',
680
679
  []
681
680
  )
682
- const pluginDirList = await fsPromise.readdir(pluginDir)
683
- const pluginDirResult = pluginDirList.filter(
684
- (item) => !excludesModel.includes(item)
681
+ // withFileTypes 直接带出类型,省掉每个文件夹一次同步 lstatSync
682
+ const pluginEntries = await fsPromise.readdir(pluginDir, {
683
+ withFileTypes: true,
684
+ })
685
+ const folders = pluginEntries
686
+ .filter(
687
+ (item) => item.isDirectory() && !excludesModel.includes(item.name)
688
+ )
689
+ .map((item) => item.name)
690
+
691
+ // 各插件目录的 readdir 互相独立,并行读取
692
+ const folderFileList = await Promise.all(
693
+ folders.map(async (folder) => [
694
+ folder,
695
+ await fsPromise.readdir(path.resolve(pluginDir, folder)),
696
+ ])
685
697
  )
686
698
 
687
- for (const folder of pluginDirResult) {
688
- const isFolder = fs
689
- .lstatSync(path.resolve(pluginDir, folder))
690
- .isDirectory()
691
- if (isFolder) {
692
- const folderResult = await fsPromise.readdir(
693
- path.resolve(pluginDir, folder)
694
- )
695
- for (const filename of folderResult) {
696
- const extname = path.extname(filename)
697
- if (extname === '.js') {
698
- const n = path.basename(filename, extname)
699
- if (
700
- [
701
- 'model',
702
- 'controller',
703
- 'service',
704
- 'validate',
705
- 'config',
706
- 'beforeValidate',
707
- 'afterValidate',
708
- 'afterExecute',
709
- ].includes(n)
710
- ) {
711
- if (n === 'model') {
712
- const defaultModelPath = path.resolve(
713
- __dirname,
714
- `./file/${PLUGINS_DIR}/${folder}`,
715
- `${filename}`
716
- )
717
- const defaultModelExist = fs.existsSync(defaultModelPath)
718
- const currentAttributes = require(path.resolve(
719
- pluginDir,
720
- folder,
721
- filename
722
- ))
723
- const _attributes =
724
- Object.keys(currentAttributes).length === 0 &&
725
- defaultModelExist
726
- ? require(defaultModelPath)
727
- : currentAttributes
728
-
729
- const belongs = _.get(
730
- this.app[appName].config[folder],
731
- 'belongs',
732
- 'page'
733
- )
699
+ // O(1) 直接挂载,替代对整个 app 对象反复 defaultsDeep(O(n²))
700
+ const mount = (n, folder, value) => {
701
+ const target = this.app[appName]
702
+ target[n] = target[n] || {}
703
+ target[n][folder] = value
704
+ }
734
705
 
735
- const idType = _.get(
736
- this.app[appName].config[folder],
737
- 'idType',
738
- belongs === 'setting' ? 'TINYINT' : 'MEDIUMINT'
739
- )
706
+ for (const [folder, folderResult] of folderFileList) {
707
+ for (const filename of folderResult) {
708
+ const extname = path.extname(filename)
709
+ if (extname === '.js') {
710
+ const n = path.basename(filename, extname)
711
+ if (
712
+ [
713
+ 'model',
714
+ 'controller',
715
+ 'service',
716
+ 'validate',
717
+ 'config',
718
+ 'beforeValidate',
719
+ 'afterValidate',
720
+ 'afterExecute',
721
+ ].includes(n)
722
+ ) {
723
+ if (n === 'model') {
724
+ const defaultModelPath = path.resolve(
725
+ __dirname,
726
+ `./file/${PLUGINS_DIR}/${folder}`,
727
+ `${filename}`
728
+ )
729
+ const defaultModelExist = fs.existsSync(defaultModelPath)
730
+ const currentAttributes = require(path.resolve(
731
+ pluginDir,
732
+ folder,
733
+ filename
734
+ ))
735
+ const _attributes =
736
+ Object.keys(currentAttributes).length === 0 &&
737
+ defaultModelExist
738
+ ? require(defaultModelPath)
739
+ : currentAttributes
740
+
741
+ const belongs = _.get(
742
+ this.app[appName].config[folder],
743
+ 'belongs',
744
+ 'page'
745
+ )
740
746
 
741
- const _id = {
742
- id: {
743
- type: Sequelize[idType].UNSIGNED,
744
- allowNull: false,
745
- primaryKey: true,
746
- autoIncrement: true,
747
- },
748
- }
747
+ const idType = _.get(
748
+ this.app[appName].config[folder],
749
+ 'idType',
750
+ belongs === 'setting' ? 'TINYINT' : 'MEDIUMINT'
751
+ )
749
752
 
750
- const attributes = _.defaultsDeep(_.cloneDeep(_attributes), {
751
- ..._id,
752
- createdid: {
753
- type: Sequelize.MEDIUMINT.UNSIGNED,
754
- allowNull: false,
755
- defaultValue: 0,
756
- },
757
- created_at: {
758
- type: Sequelize.DATE,
759
- allowNull: false,
760
- // defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
761
- comment: '生成时间',
762
- },
763
- updated_at: {
764
- type: Sequelize.DATE,
765
- allowNull: false,
766
- // defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
767
- comment: '修改时间',
768
- },
769
- })
753
+ const _id = {
754
+ id: {
755
+ type: Sequelize[idType].UNSIGNED,
756
+ allowNull: false,
757
+ primaryKey: true,
758
+ autoIncrement: true,
759
+ },
760
+ }
770
761
 
771
- this.app[appName].attributes = {
772
- ...this.app[appName].attributes,
773
- [folder]: _attributes,
774
- }
775
- const indexes = _.cloneDeep(
776
- _.get(this.app[appName].config[folder], 'indexList', [])
777
- )
778
- let hookList = _.cloneDeep(
779
- _.get(this.app[appName].config[folder], 'hookList', [])
780
- )
781
- if (
782
- hookList.some((h) =>
783
- ['afterDestroy', 'beforeDestroy'].includes(h)
784
- ) &&
785
- !hookList.includes('beforeBulkDestroy')
786
- ) {
787
- hookList = [...hookList, 'beforeBulkDestroy']
762
+ const attributes = _.defaultsDeep(_.cloneDeep(_attributes), {
763
+ ..._id,
764
+ createdid: {
765
+ type: Sequelize.MEDIUMINT.UNSIGNED,
766
+ allowNull: false,
767
+ defaultValue: 0,
768
+ },
769
+ created_at: {
770
+ type: Sequelize.DATE,
771
+ allowNull: false,
772
+ // defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
773
+ comment: '生成时间',
774
+ },
775
+ updated_at: {
776
+ type: Sequelize.DATE,
777
+ allowNull: false,
778
+ // defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
779
+ comment: '修改时间',
780
+ },
781
+ })
782
+
783
+ this.app[appName].attributes = {
784
+ ...this.app[appName].attributes,
785
+ [folder]: _attributes,
786
+ }
787
+ const indexes = _.cloneDeep(
788
+ _.get(this.app[appName].config[folder], 'indexList', [])
789
+ )
790
+ let hookList = _.cloneDeep(
791
+ _.get(this.app[appName].config[folder], 'hookList', [])
792
+ )
793
+ if (
794
+ hookList.some((h) =>
795
+ ['afterDestroy', 'beforeDestroy'].includes(h)
796
+ ) &&
797
+ !hookList.includes('beforeBulkDestroy')
798
+ ) {
799
+ hookList = [...hookList, 'beforeBulkDestroy']
800
+ }
801
+ let reduceHook = {}
802
+ for (const hook of hookList) {
803
+ reduceHook = {
804
+ ...reduceHook,
805
+ [hook]: (target, t) => {
806
+ if (['beforeBulkDestroy'].includes(hook)) {
807
+ target.individualHooks = true
808
+ }
809
+ try {
810
+ this.app[appName].service &&
811
+ this.app[appName].service[folder] &&
812
+ this.app[appName].service[folder][hook] &&
813
+ this.app[appName].service[folder][hook]({
814
+ app: this.app[appName],
815
+ model: folder,
816
+ hook,
817
+ ...(target.toJSON
818
+ ? {
819
+ target: target.toJSON(),
820
+ }
821
+ : {
822
+ target,
823
+ }),
824
+ ...t,
825
+ })
826
+ } catch (e) {
827
+ console.log(e)
828
+ }
829
+
830
+ if (['beforeBulkDestroy'].includes(hook)) {
831
+ return target
832
+ }
833
+ },
788
834
  }
789
- let reduceHook = {}
790
- for (const hook of hookList) {
791
- reduceHook = {
835
+ }
836
+ const instance = this.app[appName].sequelize.define(
837
+ folder,
838
+ attributes,
839
+ {
840
+ freezeTableName: true,
841
+ comment: folder,
842
+ // timestamps: !modelConfig.belongs === 'setting',
843
+ createdAt: 'created_at',
844
+ updatedAt: 'updated_at',
845
+ name: {
846
+ singular: folder,
847
+ plural: `${folder}s`,
848
+ },
849
+ hooks: {
792
850
  ...reduceHook,
793
- [hook]: (target, t) => {
794
- if (['beforeBulkDestroy'].includes(hook)) {
795
- target.individualHooks = true
796
- }
851
+ beforeCreate: (res, t) => {
797
852
  try {
798
- this.app[appName].service &&
799
- this.app[appName].service[folder] &&
800
- this.app[appName].service[folder][hook] &&
801
- this.app[appName].service[folder][hook]({
802
- app: this.app[appName],
803
- model: folder,
804
- hook,
805
- ...(target.toJSON
806
- ? {
807
- target: target.toJSON(),
808
- }
809
- : {
810
- target,
811
- }),
812
- ...t,
813
- })
814
- } catch (e) {
815
- console.log(e)
816
- }
817
-
818
- if (['beforeBulkDestroy'].includes(hook)) {
819
- return target
820
- }
821
- },
822
- }
823
- }
824
- const instance = this.app[appName].sequelize.define(
825
- folder,
826
- attributes,
827
- {
828
- freezeTableName: true,
829
- comment: folder,
830
- // timestamps: !modelConfig.belongs === 'setting',
831
- createdAt: 'created_at',
832
- updatedAt: 'updated_at',
833
- name: {
834
- singular: folder,
835
- plural: `${folder}s`,
836
- },
837
- hooks: {
838
- ...reduceHook,
839
- beforeCreate: (res, t) => {
840
- try {
841
- if (folder === 'log') {
842
- if (this.is_dev && !this.app[appName].service.log) {
843
- console.error('缺少log/service.js,')
844
- }
845
- this.app[appName].service.log &&
846
- this.app[appName].service.log.push({
847
- app: this.app[appName],
848
- appName,
849
- message: res.toJSON().message,
850
- url: res.toJSON().url,
851
- })
853
+ if (folder === 'log') {
854
+ if (this.is_dev && !this.app[appName].service.log) {
855
+ console.error('缺少log/service.js,')
852
856
  }
853
- if (res.toJSON().user_id) {
854
- res.createdid = res.toJSON().user_id
855
- }
856
- } catch (e) {
857
- console.log(e)
857
+ this.app[appName].service.log &&
858
+ this.app[appName].service.log.push({
859
+ app: this.app[appName],
860
+ appName,
861
+ message: res.toJSON().message,
862
+ url: res.toJSON().url,
863
+ })
858
864
  }
859
- },
860
- },
861
- ...(indexes.length > 0
862
- ? {
863
- indexes,
865
+ if (res.toJSON().user_id) {
866
+ res.createdid = res.toJSON().user_id
864
867
  }
865
- : {}),
866
- }
867
- )
868
- instance.getName = function () {
869
- return folder
870
- }
871
- this.app[appName] = _.defaultsDeep(
872
- {
873
- [n]: {
874
- [folder]: instance,
868
+ } catch (e) {
869
+ console.log(e)
870
+ }
875
871
  },
876
872
  },
877
- this.app[appName]
878
- )
879
- if (is_dev) {
880
- const mockObj = _.pickBy(
881
- _attributes,
882
- (item) => item.mock && typeof item.mock === 'function'
883
- )
884
- this.app[appName] = _.defaultsDeep(
885
- {
886
- mock: {
887
- [folder]: () =>
888
- _.zipObject(
889
- Object.keys(mockObj),
890
- Object.keys(mockObj).map((key) =>
891
- _.result(mockObj, `${key}.mock`)
892
- )
893
- ),
894
- },
895
- },
896
- this.app[appName]
897
- )
873
+ ...(indexes.length > 0
874
+ ? {
875
+ indexes,
876
+ }
877
+ : {}),
898
878
  }
899
- } else if (
900
- [
901
- 'config',
902
- 'controller',
903
- 'validate',
904
- 'afterExecute',
905
- 'service',
906
- ].includes(n)
907
- ) {
908
- const defaultPath = path.resolve(
909
- __dirname,
910
- `./file/${PLUGINS_DIR}/${folder}`,
911
- `${filename}`
912
- )
913
- const defaultExist = fs.existsSync(defaultPath)
914
- const defaultN = !defaultExist
915
- ? Object.create(null)
916
- : {
917
- [n]: {
918
- [folder]: defaultExist
919
- ? require(path.resolve(
920
- __dirname,
921
- `./file/${PLUGINS_DIR}/${folder}`,
922
- `${filename}`
923
- ))
924
- : null,
925
- },
926
- }
927
- this.app[appName] = _.defaultsDeep(
928
- {
929
- [n]: {
930
- [folder]: require(path.resolve(
931
- pluginDir,
932
- `${folder}`,
933
- `${filename}`
934
- )),
935
- },
936
- },
937
- defaultN,
938
- this.app[appName]
879
+ )
880
+ instance.getName = function () {
881
+ return folder
882
+ }
883
+ mount(n, folder, instance)
884
+ if (is_dev) {
885
+ const mockObj = _.pickBy(
886
+ _attributes,
887
+ (item) => item.mock && typeof item.mock === 'function'
939
888
  )
940
- } else {
941
- this.app[appName] = _.defaultsDeep(
942
- {
943
- [n]: {
944
- [folder]: require(path.resolve(
945
- pluginDir,
946
- `${folder}`,
947
- `${filename}`
948
- )),
949
- },
950
- },
951
- this.app[appName]
889
+ mount(
890
+ 'mock',
891
+ folder,
892
+ () =>
893
+ _.zipObject(
894
+ Object.keys(mockObj),
895
+ Object.keys(mockObj).map((key) =>
896
+ _.result(mockObj, `${key}.mock`)
897
+ )
898
+ )
952
899
  )
953
900
  }
901
+ } else if (
902
+ [
903
+ 'config',
904
+ 'controller',
905
+ 'validate',
906
+ 'afterExecute',
907
+ 'service',
908
+ ].includes(n)
909
+ ) {
910
+ const defaultPath = path.resolve(
911
+ __dirname,
912
+ `./file/${PLUGINS_DIR}/${folder}`,
913
+ `${filename}`
914
+ )
915
+ const userModule = require(path.resolve(
916
+ pluginDir,
917
+ `${folder}`,
918
+ `${filename}`
919
+ ))
920
+ // 用户模块缺失的方法/配置由框架内置同名模块补齐(仅合并当前模块,不波及整个 app)
921
+ if (
922
+ fs.existsSync(defaultPath) &&
923
+ _.isPlainObject(userModule)
924
+ ) {
925
+ _.defaultsDeep(userModule, require(defaultPath))
926
+ }
927
+ mount(n, folder, userModule)
928
+ } else {
929
+ mount(
930
+ n,
931
+ folder,
932
+ require(path.resolve(pluginDir, `${folder}`, `${filename}`))
933
+ )
954
934
  }
955
935
  }
956
936
  }
@@ -1673,7 +1673,12 @@ exports.union_notify = async (ctx) => {
1673
1673
  }
1674
1674
 
1675
1675
  // 通联回调报文字段为全小写 signtype;兼容大小写两种 + 配置 union_signType;末位回退 RSA
1676
- const rawSignType = (notifyData.signtype || notifyData.signType || union_signType || 'RSA').toUpperCase()
1676
+ const rawSignType = (
1677
+ notifyData.signtype ||
1678
+ notifyData.signType ||
1679
+ union_signType ||
1680
+ 'RSA'
1681
+ ).toUpperCase()
1677
1682
  const hasSign = notifyData.sign !== undefined && notifyData.sign !== ''
1678
1683
  const trxstatus = notifyData.trxstatus
1679
1684
 
@@ -1698,22 +1703,17 @@ exports.union_notify = async (ctx) => {
1698
1703
  if (!signOk) {
1699
1704
  app.service.log.push({
1700
1705
  app,
1701
- message: `通联回调验签失败(type=${rawSignType}): ${JSON.stringify(notifyData)}`,
1706
+ message: `通联回调验签失败(type=${rawSignType}): ${JSON.stringify(
1707
+ notifyData
1708
+ )}`,
1702
1709
  })
1703
1710
  ctx.body = 'FAIL'
1704
1711
  return
1705
1712
  }
1706
1713
  }
1707
1714
 
1708
- const {
1709
- trxcode,
1710
- cusorderid,
1711
- acct,
1712
- trxid,
1713
- trxamt,
1714
- srctrxid,
1715
- trxreserved,
1716
- } = notifyData
1715
+ const { trxcode, cusorderid, acct, trxid, trxamt, srctrxid, trxreserved } =
1716
+ notifyData
1717
1717
 
1718
1718
  if (trxstatus === '0000') {
1719
1719
  if (['VSP501', 'VSP681'].includes(trxcode)) {
@@ -2439,6 +2439,7 @@ exports.union_checkPay = async (ctx) => {
2439
2439
  const payResult = await allinpay.checkOrder(out_trade_no)
2440
2440
 
2441
2441
  if (payResult) {
2442
+ console.log(payResult)
2442
2443
  if (payResult.trxstatus === '0000' && payResult.trxcode === 'VSP501') {
2443
2444
  const order_price = Number(payResult.trxamt) / 100
2444
2445
 
@@ -2477,12 +2478,8 @@ exports.union_check_balance = async (ctx) => {
2477
2478
  } = ctx.request.body
2478
2479
 
2479
2480
  const appConfig = getConfig(app)
2480
- const {
2481
- union_mchId,
2482
- union_appid,
2483
- union_privateKey,
2484
- union_publicKey,
2485
- } = await appConfig.getObject(pay_config)
2481
+ const { union_mchId, union_appid, union_privateKey, union_publicKey } =
2482
+ await appConfig.getObject(pay_config)
2486
2483
 
2487
2484
  const allinpay = new AllinPay({
2488
2485
  cusid: mch_id || union_mchId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q-koa",
3
- "version": "13.8.57",
3
+ "version": "13.8.58",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {