li.shaoyi 2 年之前
父节点
当前提交
9c5b11045b
共有 86 个文件被更改,包括 3246 次插入640 次删除
  1. 145 155
      package-lock.json
  2. 1 1
      package.json
  3. 142 0
      public/proto/gz.proto
  4. 2 2
      src/business/account/index.ts
  5. 4 4
      src/business/bank/index.ts
  6. 5 3
      src/business/login/index.ts
  7. 0 12
      src/business/search/index.ts
  8. 2 2
      src/business/warehouse/index.ts
  9. 9 0
      src/constants/funcode.ts
  10. 70 0
      src/constants/presale.ts
  11. 23 8
      src/filters/index.ts
  12. 2 2
      src/hooks/echarts/candlestick/options.ts
  13. 2 2
      src/hooks/echarts/timeline/options.ts
  14. 36 36
      src/hooks/request/index.ts
  15. 148 0
      src/mock/router.ts
  16. 2 2
      src/packages/mobile/components/base/tabbar/index.vue
  17. 2 2
      src/packages/mobile/components/layouts/navbar/index.vue
  18. 3 3
      src/packages/mobile/main.ts
  19. 2 2
      src/packages/mobile/views/home/components/market/index.vue
  20. 2 4
      src/packages/mobile/views/home/components/order/index.vue
  21. 5 5
      src/packages/pc/assets/themes/default/default.less
  22. 1 1
      src/packages/pc/assets/themes/global/global.less
  23. 12 1
      src/packages/pc/components/base/table-details/index.less
  24. 43 26
      src/packages/pc/components/base/table-details/index.vue
  25. 3 0
      src/packages/pc/components/base/table/index.less
  26. 2 2
      src/packages/pc/components/base/upload/index.vue
  27. 7 11
      src/packages/pc/components/layouts/header/components/calculator/index.vue
  28. 6 10
      src/packages/pc/components/layouts/header/components/certificate/index.vue
  29. 4 5
      src/packages/pc/components/layouts/header/index.vue
  30. 2 2
      src/packages/pc/components/layouts/page/index.vue
  31. 2 2
      src/packages/pc/components/layouts/sidebar/index.vue
  32. 5 11
      src/packages/pc/components/modules/address/index.vue
  33. 5 11
      src/packages/pc/components/modules/invoice/index.vue
  34. 3 3
      src/packages/pc/main.ts
  35. 7 9
      src/packages/pc/views/bonded/expense/components/details/index.vue
  36. 1 1
      src/packages/pc/views/bonded/expense/components/payment/index.vue
  37. 2 2
      src/packages/pc/views/bonded/inbound/components/apply/index.vue
  38. 3 11
      src/packages/pc/views/bonded/inbound/components/details/index.vue
  39. 3 3
      src/packages/pc/views/bonded/outbound/components/apply/index.vue
  40. 5 12
      src/packages/pc/views/bonded/outbound/components/details/index.vue
  41. 89 0
      src/packages/pc/views/centralize/list/index.vue
  42. 264 0
      src/packages/pc/views/centralize/mine/components/add/index.vue
  43. 58 0
      src/packages/pc/views/centralize/mine/components/add/price-edit.vue
  44. 78 0
      src/packages/pc/views/centralize/mine/components/details/index.vue
  45. 94 0
      src/packages/pc/views/centralize/mine/index.vue
  46. 92 0
      src/packages/pc/views/centralize/partake/index.vue
  47. 84 0
      src/packages/pc/views/presale/list/components/buy/index.vue
  48. 70 0
      src/packages/pc/views/presale/list/components/details/index.vue
  49. 96 0
      src/packages/pc/views/presale/list/index.vue
  50. 196 0
      src/packages/pc/views/presale/mine/components/add/index.vue
  51. 99 0
      src/packages/pc/views/presale/mine/components/apply/details.vue
  52. 63 0
      src/packages/pc/views/presale/mine/components/apply/index.vue
  53. 78 0
      src/packages/pc/views/presale/mine/components/details/index.vue
  54. 95 0
      src/packages/pc/views/presale/mine/index.vue
  55. 46 0
      src/packages/pc/views/presale/partake/components/details/index.vue
  56. 92 0
      src/packages/pc/views/presale/partake/index.vue
  57. 2 4
      src/packages/pc/views/search/jewelry/components/compare/index.less
  58. 4 5
      src/packages/pc/views/search/jewelry/index.vue
  59. 4 6
      src/packages/pc/views/warehousing/goods/components/details/index.vue
  60. 19 6
      src/services/api/account/index.ts
  61. 15 5
      src/services/api/bank/index.ts
  62. 32 9
      src/services/api/bonded/index.ts
  63. 70 21
      src/services/api/common/index.ts
  64. 33 9
      src/services/api/customs/index.ts
  65. 5 2
      src/services/api/favorite/index.ts
  66. 12 4
      src/services/api/goods/index.ts
  67. 16 5
      src/services/api/performance/index.ts
  68. 113 0
      src/services/api/presale/index.ts
  69. 9 3
      src/services/api/quote/index.ts
  70. 13 4
      src/services/api/report/index.ts
  71. 35 10
      src/services/api/trade/index.ts
  72. 20 5
      src/services/api/user/index.ts
  73. 5 2
      src/services/api/warehouse/index.ts
  74. 117 102
      src/services/http/index.ts
  75. 15 8
      src/services/index.ts
  76. 4 1
      src/services/socket/trade/index.ts
  77. 1 2
      src/stores/index.ts
  78. 1 1
      src/stores/modules/enum.ts
  79. 8 6
      src/stores/modules/exrate.ts
  80. 0 1
      src/stores/modules/futures.ts
  81. 3 3
      src/stores/modules/global.ts
  82. 30 0
      src/stores/modules/login.ts
  83. 0 46
      src/stores/modules/user.ts
  84. 193 0
      src/types/ermcp/presale.d.ts
  85. 2 2
      src/types/ermcp/user.d.ts
  86. 148 0
      src/types/proto/presale.d.ts

+ 145 - 155
package-lock.json

@@ -14,7 +14,7 @@
         "crypto-js": "^4.1.1",
         "default-passive-events": "^2.0.0",
         "echarts": "^5.3.2",
-        "element-plus": "^2.2.8",
+        "element-plus": "^2.3.1",
         "long": "^5.2.0",
         "moment": "^2.29.3",
         "protobufjs": "^6.11.2",
@@ -1692,17 +1692,17 @@
       }
     },
     "node_modules/@ctrl/tinycolor": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
-      "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==",
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz",
+      "integrity": "sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==",
       "engines": {
         "node": ">=10"
       }
     },
     "node_modules/@element-plus/icons-vue": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
-      "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.1.0.tgz",
+      "integrity": "sha512-PSBn3elNoanENc1vnCfh+3WA9fimRC7n+fWkf3rE5jvv+aBohNHABC/KAR5KWPecxWxDTVT1ERpRbOMRcOV/vA==",
       "peerDependencies": {
         "vue": "^3.2.0"
       }
@@ -1764,16 +1764,16 @@
       }
     },
     "node_modules/@floating-ui/core": {
-      "version": "0.7.3",
-      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
-      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+      "version": "1.2.4",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.2.4.tgz",
+      "integrity": "sha512-SQOeVbMwb1di+mVWWJLpsUTToKfqVNioXys011beCAhyOIFtS+GQoW4EQSneuxzmQKddExDwQ+X0hLl4lJJaSQ=="
     },
     "node_modules/@floating-ui/dom": {
-      "version": "0.5.4",
-      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
-      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "version": "1.2.5",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.2.5.tgz",
+      "integrity": "sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ==",
       "dependencies": {
-        "@floating-ui/core": "^0.7.3"
+        "@floating-ui/core": "^1.2.4"
       }
     },
     "node_modules/@hapi/hoek": {
@@ -2270,14 +2270,14 @@
       "dev": true
     },
     "node_modules/@types/lodash": {
-      "version": "4.14.182",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
-      "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
+      "version": "4.14.191",
+      "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
     },
     "node_modules/@types/lodash-es": {
-      "version": "4.17.6",
-      "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
-      "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
+      "version": "4.17.7",
+      "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.7.tgz",
+      "integrity": "sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==",
       "dependencies": {
         "@types/lodash": "*"
       }
@@ -2375,9 +2375,9 @@
       "dev": true
     },
     "node_modules/@types/web-bluetooth": {
-      "version": "0.0.14",
-      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
-      "integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
+      "version": "0.0.16",
+      "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
+      "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
     },
     "node_modules/@types/webpack-env": {
       "version": "1.16.4",
@@ -3409,58 +3409,55 @@
       "dev": true
     },
     "node_modules/@vueuse/core": {
-      "version": "8.7.5",
-      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.7.5.tgz",
-      "integrity": "sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==",
+      "version": "9.13.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz",
+      "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
       "dependencies": {
-        "@types/web-bluetooth": "^0.0.14",
-        "@vueuse/metadata": "8.7.5",
-        "@vueuse/shared": "8.7.5",
+        "@types/web-bluetooth": "^0.0.16",
+        "@vueuse/metadata": "9.13.0",
+        "@vueuse/shared": "9.13.0",
         "vue-demi": "*"
+      }
+    },
+    "node_modules/@vueuse/core/node_modules/vue-demi": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
+      "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+      "hasInstallScript": true,
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
+      "engines": {
+        "node": ">=12"
       },
       "peerDependencies": {
-        "@vue/composition-api": "^1.1.0",
-        "vue": "^2.6.0 || ^3.2.0"
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
       },
       "peerDependenciesMeta": {
         "@vue/composition-api": {
           "optional": true
-        },
-        "vue": {
-          "optional": true
         }
       }
     },
-    "node_modules/@vueuse/core/node_modules/@vueuse/shared": {
-      "version": "8.7.5",
-      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.7.5.tgz",
-      "integrity": "sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==",
+    "node_modules/@vueuse/metadata": {
+      "version": "9.13.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz",
+      "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
+    },
+    "node_modules/@vueuse/shared": {
+      "version": "9.13.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz",
+      "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
       "dependencies": {
         "vue-demi": "*"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      },
-      "peerDependencies": {
-        "@vue/composition-api": "^1.1.0",
-        "vue": "^2.6.0 || ^3.2.0"
-      },
-      "peerDependenciesMeta": {
-        "@vue/composition-api": {
-          "optional": true
-        },
-        "vue": {
-          "optional": true
-        }
       }
     },
-    "node_modules/@vueuse/core/node_modules/vue-demi": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.2.tgz",
-      "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
+    "node_modules/@vueuse/shared/node_modules/vue-demi": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
+      "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
       "hasInstallScript": true,
       "bin": {
         "vue-demi-fix": "bin/vue-demi-fix.js",
@@ -3469,9 +3466,6 @@
       "engines": {
         "node": ">=12"
       },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      },
       "peerDependencies": {
         "@vue/composition-api": "^1.0.0-rc.1",
         "vue": "^3.0.0-0 || ^2.6.0"
@@ -3482,14 +3476,6 @@
         }
       }
     },
-    "node_modules/@vueuse/metadata": {
-      "version": "8.7.5",
-      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.7.5.tgz",
-      "integrity": "sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg==",
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      }
-    },
     "node_modules/@webassemblyjs/ast": {
       "version": "1.11.1",
       "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@@ -3915,7 +3901,7 @@
     },
     "node_modules/async-validator": {
       "version": "4.2.5",
-      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
       "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
     },
     "node_modules/at-least-node": {
@@ -5342,9 +5328,9 @@
       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
     },
     "node_modules/dayjs": {
-      "version": "1.11.3",
-      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
-      "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
+      "version": "1.11.7",
+      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz",
+      "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
     },
     "node_modules/debug": {
       "version": "4.3.4",
@@ -5741,17 +5727,17 @@
       "dev": true
     },
     "node_modules/element-plus": {
-      "version": "2.2.8",
-      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.8.tgz",
-      "integrity": "sha512-+cubFh1rgeGcc2LeBm7hv/1BKFJre/LIIdRntm9OLaIhysCxigjEwcxk9gbVT4KsbcjmoqZUr4/mwhIhQV6mvw==",
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.3.1.tgz",
+      "integrity": "sha512-IBS7ic1mRyDXpOreRkredV4ByZSuax5HPb0zNOHm4qwKC4wm927yQv+Is0JbzxPzCW5zWaV4PLy9/Gl3E3v59w==",
       "dependencies": {
         "@ctrl/tinycolor": "^3.4.1",
         "@element-plus/icons-vue": "^2.0.6",
-        "@floating-ui/dom": "^0.5.4",
+        "@floating-ui/dom": "^1.0.1",
         "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
         "@types/lodash": "^4.14.182",
         "@types/lodash-es": "^4.17.6",
-        "@vueuse/core": "^8.7.5",
+        "@vueuse/core": "^9.1.0",
         "async-validator": "^4.2.5",
         "dayjs": "^1.11.3",
         "escape-html": "^1.0.3",
@@ -5759,7 +5745,7 @@
         "lodash-es": "^4.17.21",
         "lodash-unified": "^1.0.2",
         "memoize-one": "^6.0.0",
-        "normalize-wheel-es": "^1.1.2"
+        "normalize-wheel-es": "^1.2.0"
       },
       "peerDependencies": {
         "vue": "^3.2.0"
@@ -5768,12 +5754,8 @@
     "node_modules/element-plus/node_modules/@popperjs/core": {
       "name": "@sxzz/popperjs-es",
       "version": "2.11.7",
-      "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
-      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/popperjs"
-      }
+      "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
     },
     "node_modules/emoji-regex": {
       "version": "8.0.0",
@@ -8094,13 +8076,13 @@
     },
     "node_modules/lodash-es": {
       "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
       "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
     },
     "node_modules/lodash-unified": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.2.tgz",
-      "integrity": "sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz",
+      "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
       "peerDependencies": {
         "@types/lodash-es": "*",
         "lodash": "*",
@@ -8435,7 +8417,7 @@
     },
     "node_modules/memoize-one": {
       "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+      "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
       "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
     },
     "node_modules/merge-descriptors": {
@@ -8895,9 +8877,9 @@
       }
     },
     "node_modules/normalize-wheel-es": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.1.2.tgz",
-      "integrity": "sha512-scX83plWJXYH1J4+BhAuIHadROzxX0UBF3+HuZNY2Ks8BciE7tSTQ+5JhTsvzjaO0/EJdm4JBGrfObKxFf3Png=="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
+      "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
     },
     "node_modules/npm-run-path": {
       "version": "2.0.2",
@@ -14007,14 +13989,14 @@
       }
     },
     "@ctrl/tinycolor": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
-      "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz",
+      "integrity": "sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ=="
     },
     "@element-plus/icons-vue": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.6.tgz",
-      "integrity": "sha512-lPpG8hYkjL/Z97DH5Ei6w6o22Z4YdNglWCNYOPcB33JCF2A4wye6HFgSI7hEt9zdLyxlSpiqtgf9XcYU+m5mew==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.1.0.tgz",
+      "integrity": "sha512-PSBn3elNoanENc1vnCfh+3WA9fimRC7n+fWkf3rE5jvv+aBohNHABC/KAR5KWPecxWxDTVT1ERpRbOMRcOV/vA==",
       "requires": {}
     },
     "@eslint/eslintrc": {
@@ -14058,16 +14040,16 @@
       }
     },
     "@floating-ui/core": {
-      "version": "0.7.3",
-      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
-      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+      "version": "1.2.4",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.2.4.tgz",
+      "integrity": "sha512-SQOeVbMwb1di+mVWWJLpsUTToKfqVNioXys011beCAhyOIFtS+GQoW4EQSneuxzmQKddExDwQ+X0hLl4lJJaSQ=="
     },
     "@floating-ui/dom": {
-      "version": "0.5.4",
-      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
-      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "version": "1.2.5",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.2.5.tgz",
+      "integrity": "sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ==",
       "requires": {
-        "@floating-ui/core": "^0.7.3"
+        "@floating-ui/core": "^1.2.4"
       }
     },
     "@hapi/hoek": {
@@ -14498,14 +14480,14 @@
       "dev": true
     },
     "@types/lodash": {
-      "version": "4.14.182",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
-      "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
+      "version": "4.14.191",
+      "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz",
+      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
     },
     "@types/lodash-es": {
-      "version": "4.17.6",
-      "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz",
-      "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
+      "version": "4.17.7",
+      "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.7.tgz",
+      "integrity": "sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==",
       "requires": {
         "@types/lodash": "*"
       }
@@ -14603,9 +14585,9 @@
       "dev": true
     },
     "@types/web-bluetooth": {
-      "version": "0.0.14",
-      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
-      "integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
+      "version": "0.0.16",
+      "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
+      "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
     },
     "@types/webpack-env": {
       "version": "1.16.4",
@@ -15370,36 +15352,44 @@
       "dev": true
     },
     "@vueuse/core": {
-      "version": "8.7.5",
-      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.7.5.tgz",
-      "integrity": "sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==",
+      "version": "9.13.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz",
+      "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
       "requires": {
-        "@types/web-bluetooth": "^0.0.14",
-        "@vueuse/metadata": "8.7.5",
-        "@vueuse/shared": "8.7.5",
+        "@types/web-bluetooth": "^0.0.16",
+        "@vueuse/metadata": "9.13.0",
+        "@vueuse/shared": "9.13.0",
         "vue-demi": "*"
       },
       "dependencies": {
-        "@vueuse/shared": {
-          "version": "8.7.5",
-          "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.7.5.tgz",
-          "integrity": "sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==",
-          "requires": {
-            "vue-demi": "*"
-          }
-        },
         "vue-demi": {
-          "version": "0.13.2",
-          "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.2.tgz",
-          "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
+          "version": "0.13.11",
+          "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
+          "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
           "requires": {}
         }
       }
     },
     "@vueuse/metadata": {
-      "version": "8.7.5",
-      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.7.5.tgz",
-      "integrity": "sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg=="
+      "version": "9.13.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz",
+      "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
+    },
+    "@vueuse/shared": {
+      "version": "9.13.0",
+      "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz",
+      "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
+      "requires": {
+        "vue-demi": "*"
+      },
+      "dependencies": {
+        "vue-demi": {
+          "version": "0.13.11",
+          "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
+          "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+          "requires": {}
+        }
+      }
     },
     "@webassemblyjs/ast": {
       "version": "1.11.1",
@@ -15747,7 +15737,7 @@
     },
     "async-validator": {
       "version": "4.2.5",
-      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
       "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
     },
     "at-least-node": {
@@ -16783,9 +16773,9 @@
       "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
     },
     "dayjs": {
-      "version": "1.11.3",
-      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
-      "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
+      "version": "1.11.7",
+      "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz",
+      "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
     },
     "debug": {
       "version": "4.3.4",
@@ -17088,17 +17078,17 @@
       "dev": true
     },
     "element-plus": {
-      "version": "2.2.8",
-      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.2.8.tgz",
-      "integrity": "sha512-+cubFh1rgeGcc2LeBm7hv/1BKFJre/LIIdRntm9OLaIhysCxigjEwcxk9gbVT4KsbcjmoqZUr4/mwhIhQV6mvw==",
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.3.1.tgz",
+      "integrity": "sha512-IBS7ic1mRyDXpOreRkredV4ByZSuax5HPb0zNOHm4qwKC4wm927yQv+Is0JbzxPzCW5zWaV4PLy9/Gl3E3v59w==",
       "requires": {
         "@ctrl/tinycolor": "^3.4.1",
         "@element-plus/icons-vue": "^2.0.6",
-        "@floating-ui/dom": "^0.5.4",
+        "@floating-ui/dom": "^1.0.1",
         "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
         "@types/lodash": "^4.14.182",
         "@types/lodash-es": "^4.17.6",
-        "@vueuse/core": "^8.7.5",
+        "@vueuse/core": "^9.1.0",
         "async-validator": "^4.2.5",
         "dayjs": "^1.11.3",
         "escape-html": "^1.0.3",
@@ -17106,12 +17096,12 @@
         "lodash-es": "^4.17.21",
         "lodash-unified": "^1.0.2",
         "memoize-one": "^6.0.0",
-        "normalize-wheel-es": "^1.1.2"
+        "normalize-wheel-es": "^1.2.0"
       },
       "dependencies": {
         "@popperjs/core": {
           "version": "npm:@sxzz/popperjs-es@2.11.7",
-          "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+          "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
           "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
         }
       }
@@ -18822,13 +18812,13 @@
     },
     "lodash-es": {
       "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
       "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
     },
     "lodash-unified": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.2.tgz",
-      "integrity": "sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz",
+      "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
       "requires": {}
     },
     "lodash.debounce": {
@@ -19091,7 +19081,7 @@
     },
     "memoize-one": {
       "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+      "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
       "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
     },
     "merge-descriptors": {
@@ -19443,9 +19433,9 @@
       "dev": true
     },
     "normalize-wheel-es": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.1.2.tgz",
-      "integrity": "sha512-scX83plWJXYH1J4+BhAuIHadROzxX0UBF3+HuZNY2Ks8BciE7tSTQ+5JhTsvzjaO0/EJdm4JBGrfObKxFf3Png=="
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
+      "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
     },
     "npm-run-path": {
       "version": "2.0.2",

+ 1 - 1
package.json

@@ -16,7 +16,7 @@
     "crypto-js": "^4.1.1",
     "default-passive-events": "^2.0.0",
     "echarts": "^5.3.2",
-    "element-plus": "^2.2.8",
+    "element-plus": "^2.3.1",
     "long": "^5.2.0",
     "moment": "^2.29.3",
     "protobufjs": "^6.11.2",

+ 142 - 0
public/proto/gz.proto

@@ -1160,4 +1160,146 @@ message BSCConfirmPayRsp {
 	optional string RetDesc = 3; // 描述信息
 		optional uint32 UserID = 4; // 用户ID,必填
 			optional string ClientSerialNo = 5; // 客户端流水号
+}
+
+// 广钻预售申请请求
+message GZPresaleApplyReq {
+	optional MessageHead Header = 1;
+		optional uint32 SellUserID = 2; // 发行方用户,必填
+		optional uint64 SellAccountID = 3; // 发行方资金账户ID,必填
+		optional string WRStandardName = 4; // 现货商品名称,必填
+		optional uint64 PresaleQty = 5; // 预售总量,必填
+		optional uint64 MinBuyQty = 6; // 单人最小申购量,必填
+		optional uint64 MaxBuyQty = 7; // 单人最大申购量,必填
+		optional uint64 MinSuccessQty = 8; // 最低成团量,必填
+		optional double UnitPrice = 9; // 预售价格,小数,两位,必填
+		optional string StartDate = 10; // 预售开始日期,必填
+		optional string EndDate = 11; // 预售结束日期,必填
+		optional uint32 BuyMarginAlgorithm = 12; // 买方保证金方式,必填
+		optional double BuyMarginValue = 13; // 买方保证金设置值,小数,四位,必填
+		optional int64 PerformanceTemplateID = 14; // 履约计划模板ID,必填
+		optional uint32 MarketID = 15; // 市场ID,必填
+		optional uint32 YSZSCategory = 16; // 预售钻石分类
+		optional string ZSColorTypeStr = 17; // 颜色,最大允许64个字符
+		optional string ZSClarityTypeStr = 18; // 净度,最大允许64个字符
+		optional string SizeStr = 19; // 尺寸,最大允许64个字符
+		optional string YieldRate = 20; // 成品率,最大允许64个字符
+		optional string QtyDesc = 21; // 数量描述,最大允许64个字符
+		optional string WeightDesc = 22; // 重量描述,最大允许64个字符
+		optional uint32 YSProductionMode = 23; // 生产方式
+		optional string PictureUrls = 24; // 图片,CLOB,多张逗号分隔
+		optional string Remark = 25; // 备注,最大允许256个字符
+		optional uint32 ClientType = 26; // 终端类型
+		optional string ClientSerialNo = 27; // 客户端流水号
+}
+
+// 广钻预售申请响应
+message GZPresaleApplyRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint32 SellUserID = 4; // 发行方用户
+		optional uint64 PresaleApplyID = 5; // 预售申请ID
+		optional string ClientSerialNo = 6; // 客户端流水号
+}
+
+// 广钻预售认购下单请求
+message GZPresaleOrderReq {
+	optional MessageHead Header = 1;
+	optional uint32 UserID = 2; // 用户ID,必填
+	optional uint64 AccountID = 3; // 资金账户ID,必填
+	optional uint64 WRTradeOrderID = 4; // 仓单贸易委托单ID,必填
+	optional uint64 OrderQty = 5; // 认购数量,必填
+	optional uint32 MarketID = 6; // 市场ID,必填
+	optional string ClientOrderTime = 7; // 委托时间,必填
+	optional uint32 ClientType = 8; // 终端类型
+	optional string ClientSerialNo = 9; // 客户端流水号
+}
+
+// 广钻预售认购下单响应
+message GZPresaleOrderRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint32 UserID = 4; // 用户ID
+		optional uint64 AccountID = 5; // 资金账户ID
+		optional uint64 WRTradeOrderID = 6; // 仓单贸易委托单ID
+		optional string ClientSerialNo = 7; // 客户端流水号
+}
+
+// 广钻集采申请请求
+message GZCenterPurchaseApplyReq {
+	optional MessageHead Header = 1;
+		optional uint32 SellUserID = 2; // 发行方用户,必填
+		optional uint64 SellAccountID = 3; // 发行方资金账户ID,必填
+		optional string WRStandardName = 4; // 现货商品名称,必填
+		optional uint64 PresaleQty = 5; // 预售总量,必填
+		optional uint64 MinBuyQty = 6; // 单人最小申购量,必填
+		optional uint64 MaxBuyQty = 7; // 单人最大申购量,必填
+		optional uint64 MinSuccessQty = 8; // 最低成团量,必填
+		optional string StartDate = 9; // 预售开始日期,必填
+		optional string EndDate = 10; // 预售结束日期,必填
+		optional uint32 BuyMarginAlgorithm = 11; // 买方保证金方式,必填
+		optional double BuyMarginValue = 12; // 买方保证金设置值,小数,四位,必填
+		optional int64 PerformanceTemplateID = 13; // 履约计划模板ID,必填
+		repeated GZCenterPurchasePriceList GZCenterPurchasePriceLists = 14; // 价格列表,必填
+		optional uint32 MarketID = 15; // 市场ID,必填
+		optional uint32 YSZSCategory = 16; // 预售钻石分类
+		optional string ZSShapeTypeStr = 17; // 形状,最大允许64个字符
+		optional string ZSColorTypeStr = 18; // 颜色,最大允许64个字符
+		optional string ZSClarityTypeStr = 19; // 净度,最大允许64个字符
+		optional string ZSCutTypeStr = 20; // 切工,最大允许64个字符
+		optional string ZSSymmetryTypeStr = 21; // 对称,最大允许64个字符
+		optional string ZSPolishTypeStr = 22; // 抛光,最大允许64个字符
+		optional string ZSFluorescenceTypeStr = 23; // 荧光,最大允许64个字符
+		optional string SizeStr = 24; // 尺寸,最大允许64个字符
+		optional string YieldRate = 25; // 成品率,最大允许64个字符
+		optional string QtyDesc = 26; // 数量描述,最大允许64个字符
+		optional string WeightDesc = 27; // 重量描述,最大允许64个字符
+		optional uint32 YSProductionMode = 28; // 生产方式
+		optional string PictureUrls = 29; // 图片,CLOB,多张逗号分隔
+		optional string Remark = 30; // 备注,最大允许256个字符
+		optional uint32 ClientType = 31; // 终端类型
+		optional string ClientSerialNo = 32; // 客户端流水号
+}
+
+// 广钻集采价格列表
+message GZCenterPurchasePriceList {
+	optional uint32 StepIndex = 1; // 档位序号,必填
+	optional uint64 Qty = 2; // 档位数量,必填
+	optional double Price = 3; // 档位价格,小数,两位,必填
+}
+
+// 广钻集采申请响应
+message GZCenterPurchaseApplyRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint32 SellUserID = 4; // 发行方用户
+		optional uint64 PresaleApplyID = 5; // 预售申请ID
+		optional string ClientSerialNo = 6; // 客户端流水号
+}
+
+// 广钻集采认购下单请求
+message GZCenterPurchaseOrderReq {
+	optional MessageHead Header = 1;
+	optional uint32 UserID = 2; // 用户ID,必填
+	optional uint64 AccountID = 3; // 资金账户ID,必填
+	optional uint64 WRTradeOrderID = 4; // 仓单贸易委托单ID,必填
+	optional uint64 OrderQty = 5; // 认购数量,必填
+	optional uint32 MarketID = 6; // 市场ID,必填
+		optional string ClientOrderTime = 7; // 委托时间,必填
+	optional uint32 ClientType = 8; // 终端类型
+	optional string ClientSerialNo = 9; // 客户端流水号
+}
+
+// 广钻集采认购下单响应
+message GZCenterPurchaseOrderRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint32 UserID = 4; // 用户ID
+		optional uint64 AccountID = 5; // 资金账户ID
+		optional uint64 WRTradeOrderID = 6; // 仓单贸易委托单ID
+		optional string ClientSerialNo = 7; // 客户端流水号
 }

+ 2 - 2
src/business/account/index.ts

@@ -1,11 +1,11 @@
 import { shallowRef, reactive } from 'vue'
-import { userStore, loginStore } from '@/stores'
+import { loginStore } from '@/stores'
 import { modifyPassword } from '@/services/api/account'
 import { queryBankAccountSign } from '@/services/api/bank'
 import cryptojs from 'crypto-js'
 
 export function useAccount() {
-    const { getUserDataInfo } = userStore.actions
+    const { getUserDataInfo } = loginStore.actions
     const loginInfo = getUserDataInfo('loginAccount')
     const userInfo = getUserDataInfo('userInfo')
     const bankInfo = shallowRef<Ermcp.BankAccountSignRsp>()

+ 4 - 4
src/business/bank/index.ts

@@ -1,7 +1,7 @@
 import { shallowRef, reactive } from 'vue'
 import { decryptAES } from '@/utils/websocket/crypto'
 import { useDataTable } from '@/hooks/datatable'
-import { userStore, accountStore, loginStore } from '@/stores'
+import { accountStore, loginStore } from '@/stores'
 import { queryCusBankSignBank, queryAccountInOutApply, t2bBankSign, t2bBankCancelSign, queryBankAccountSign, t2bBankDeposit, t2bBankWithdraw } from '@/services/api/bank'
 import { SignStatus } from '@/constants/bank'
 
@@ -9,7 +9,7 @@ const { userId, firstAccountId } = loginStore.$mapGetters()
 
 // 银行签约相关
 export function useBankSign() {
-    const userInfo = userStore.actions.getUserDataInfo('userInfo')
+    const userInfo = loginStore.actions.getUserDataInfo('userInfo')
     const loading = shallowRef(false)
     const custodianBanks = shallowRef<Ermcp.CusBankSignBankRsp[]>([]) // 托管银行列表
     const selectedCustodianBank = shallowRef<Ermcp.CusBankSignBankRsp>() // 已选中的托管银行
@@ -136,7 +136,7 @@ export function useAccountInOut() {
 // 入金
 export function useDeposit() {
     const { accountInfo } = accountStore.$mapGetters()
-    const userInfo = userStore.actions.getUserDataInfo('userInfo')
+    const userInfo = loginStore.actions.getUserDataInfo('userInfo')
     const loading = shallowRef(false)
 
     const formData = reactive<Partial<Proto.t2bBankDepositReq>>({
@@ -201,7 +201,7 @@ export function useDeposit() {
 // 出金
 export function useWithdraw() {
     const { accountInfo } = accountStore.$mapGetters()
-    const userInfo = userStore.actions.getUserDataInfo('userInfo')
+    const userInfo = loginStore.actions.getUserDataInfo('userInfo')
     const loading = shallowRef(false)
 
     const formData = reactive<Partial<Proto.t2bBankDepositReq>>({

+ 5 - 3
src/business/login/index.ts

@@ -4,7 +4,7 @@ import { encryptAES, decryptAES } from '@/utils/crypto'
 import { timerTask } from '@/utils/timer'
 import { queryLoginId, login } from '@/services/api/account'
 import { sessionData, localData } from '@/stores/storage'
-import { loginStore, enumStore, errorInfoStore, userStore, futuresStore, accountStore } from '@/stores'
+import { loginStore, enumStore, errorInfoStore, futuresStore, favoriteStore, accountStore, performanceStore } from '@/stores'
 import { checkToken, checkTokenLoop } from '@/business/common'
 import service from '@/services'
 import socket from '@/services/socket'
@@ -35,9 +35,11 @@ export function useLogin() {
 
     const loadUserData = async () => {
         await checkToken() // 令牌校验
-        await userStore.actions.getUserData()
-        futuresStore.actions.getGoodsList()
+        await loginStore.actions.getUserData()
+        performanceStore.actions.getPerformanceTemplateList()
+        performanceStore.actions.getPerformanceStepTypeList()
         accountStore.actions.getAccountList()
+        favoriteStore.actions.getFavoriteList()
         checkTokenLoop()
     }
 

+ 0 - 12
src/business/search/index.ts

@@ -101,18 +101,6 @@ export function useSearch(category: Category) {
         getSellOrderList()
     }
 
-    // 获取仓库列表
-    // queryWarehouseInfo({
-    //     data: {
-    //         userid: getUserId(),
-    //         status: 1,
-    //         isincludeexchange: true,
-    //     },
-    //     success: (res) => {
-    //         warehouseList.value = res.data
-    //     }
-    // })
-
     return {
         loading,
         warehouseList,

+ 2 - 2
src/business/warehouse/index.ts

@@ -1,7 +1,7 @@
 import { shallowRef, reactive } from 'vue'
 import { useDataTable } from '@/hooks/datatable'
 import { queryWarehouseInfo, warehouseApply } from '@/services/api/warehouse'
-import { userStore, loginStore } from '@/stores'
+import { loginStore } from '@/stores'
 
 const { userId } = loginStore.$mapGetters()
 
@@ -72,7 +72,7 @@ export function useWarehouseForm(selectedRow?: Ermcp.WarehouseInfoRsp) {
 
     return {
         loading,
-        accountName: userStore.getters.accountName,
+        accountName: loginStore.getters.accountName,
         formData,
         addOrUpdate,
     }

+ 9 - 0
src/constants/funcode.ts

@@ -95,4 +95,13 @@ export enum FunCode {
     BSCUploadFileRsp = 1114128, // 保税仓上传文件接口响应
     BSCConfirmPayReq = 1114133, // 保税仓确认支付接口请求
     BSCConfirmPayRsp = 1114134, // 保税仓确认支付接口响应
+
+    GZPresaleApplyReq = 1441879, // 广钻预售申请请求
+    GZPresaleApplyRsp = 1441880, // 广钻预售申请响应
+    GZPresaleOrderReq = 1441883, // 广钻预售认购下单请求
+    GZPresaleOrderRsp = 1441884, // 广钻预售认购下单响应
+    GZCenterPurchaseApplyReq = 1441887, // 广钻集采申请请求
+    GZCenterPurchaseApplyRsp = 1441888, // 广钻集采申请响应
+    GZCenterPurchaseOrderReq = 1441891, // 广钻集采认购下单请求
+    GZCenterPurchaseOrderRsp = 1441892, // 广钻集采认购下单响应
 }

+ 70 - 0
src/constants/presale.ts

@@ -0,0 +1,70 @@
+import { enumStore } from '@/stores'
+
+const { getEnumTypeList, getEnumTypeName } = enumStore.actions
+
+/**
+ * 发票类型
+ */
+export enum YSZSCategory {
+    Diamonds = 1, // 成批裸钻
+    Rough = 2, // 毛坯钻石
+}
+
+/**
+ * 获取预售钻石分类列表
+ * @returns 
+ */
+export function getYSZSCategoryList() {
+    return getEnumTypeList('YSZSCategory')
+}
+
+/**
+ * 获取预售生产方式列表
+ * @returns 
+ */
+export function getYSProductionModeList() {
+    return getEnumTypeList('YSProductionMode')
+}
+
+/**
+ * 获取预售生产方式名称
+ * @returns 
+ */
+export function getYSProductionModeName(value?: number) {
+    const enums = getYSProductionModeList()
+    return getEnumTypeName(enums, value)
+}
+
+/**
+ * 获取预售状态列表
+ * @returns 
+ */
+export function getWRPresaleStatusList() {
+    return getEnumTypeList('WRPresaleStatus')
+}
+
+/**
+ * 获取预售状态名称
+ * @returns 
+ */
+export function getWRPresaleStatusName(value?: number) {
+    const enums = getWRPresaleStatusList()
+    return getEnumTypeName(enums, value)
+}
+
+/**
+ * 获取预售申请状态列表
+ * @returns 
+ */
+export function getInOutApplyStatusList() {
+    return getEnumTypeList('inoutapplystatus')
+}
+
+/**
+ * 获取预售申请状态名称
+ * @returns 
+ */
+export function getInOutApplyStatusName(value?: number) {
+    const enums = getInOutApplyStatusList()
+    return getEnumTypeName(enums, value)
+}

+ 23 - 8
src/filters/index.ts

@@ -14,12 +14,12 @@ export function getUrl(url: string, base?: string) {
 }
 
 /**
- * 获取图片地址
- * @param fileUrl 
+ * 获取文件链接地址
+ * @param filePath 
  */
-export function getImageUrl(fileUrl: string) {
-    if (fileUrl) {
-        const url = getUrl(fileUrl)
+export function getFileUrl(filePath?: string) {
+    if (filePath) {
+        const url = getUrl(filePath)
         return url.href
     }
     return ''
@@ -57,11 +57,26 @@ export function handleNoneValue<T>(value?: T, suffix = '') {
  * @param suffix 后缀名
  * @returns 
  */
-export function handleNumberValue(value: number, suffix = '') {
-    if (value === 0) {
+export function handleNumberValue(value: number | string, suffix = '') {
+    try {
+        if (Number(value) === 0) {
+            return '--'
+        }
+        return value + suffix
+    }
+    catch {
         return '--'
     }
-    return value + suffix
+}
+
+/**
+ * 数值转换百分比
+ * @param value 
+ * @param decimal 保留小数位
+ */
+export function parsePercent(value: number, decimal = 2) {
+    const val = formatDecimal(value * 100, decimal, false)
+    return handleNumberValue(val, '%')
 }
 
 /**

+ 2 - 2
src/hooks/echarts/candlestick/options.ts

@@ -1,11 +1,11 @@
 import { reactive, watch } from 'vue'
 import { ECOption } from '@/components/base/echarts/core'
 import { timerInterceptor } from '@/utils/timer'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 import { EchartsDataset, EchartsOptions, Colors } from './interface'
 import moment from 'moment'
 
-const { appTheme } = themeStore.$mapState();
+const { appTheme } = globalStore.$mapState();
 
 function getColors() {
     // 默认主题色配置

+ 2 - 2
src/hooks/echarts/timeline/options.ts

@@ -1,10 +1,10 @@
 import { reactive, watch } from 'vue'
 import { timerInterceptor } from '@/utils/timer'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 import { echarts } from '@/components/base/echarts/core'
 import { EchartsDataset, EchartsOptions, Colors } from './interface'
 
-const { appTheme } = themeStore.$mapState();
+const { appTheme } = globalStore.$mapState();
 
 function getColors() {
     // 默认主题色配置

+ 36 - 36
src/hooks/request/index.ts

@@ -8,73 +8,69 @@ interface RequestOptions<TParams, TResponse> {
         pagesize?: number; // 每页条数
     } & TParams;
     localPagination?: boolean;
-    delay?: number;
+    manual?: boolean; // 是否手动触发
+    onBefore?: () => unknown;
     onSuccess?: (res: TResponse) => void;
     onError?: (err: string) => void;
     onFinally?: () => void;
 }
 
+// 判断对象是否通用响应对象
+const isCommonResult = (obj: unknown): obj is CommonResult => {
+    if (obj instanceof Object) {
+        return 'code' in obj && 'data' in obj
+    }
+    return false
+}
+
 export function useRequest<TParams extends object, TResponse>(request: (params: TParams) => Promise<TResponse>, options?: RequestOptions<TParams, TResponse>) {
-    const { params, localPagination, onSuccess, onError, onFinally } = options ?? {}
+    const { params, localPagination, manual, onBefore, onSuccess, onError, onFinally } = options ?? {}
 
     type Result = TResponse extends CommonResult ? TResponse['data'] : TResponse // 获取返回值的类型
     type ResultType = Result extends (infer U)[] ? U : Result // 如果 U 是数组,取 U 的类型
 
     const { dataList, filters, total, pageIndex, pageSize, pageCount } = useDataTable<ResultType>({
         localPagination,
-        pageSize: params?.page,
-        pageIndex: params?.pagesize,
+        pageIndex: params?.page,
+        pageSize: params?.pagesize,
     })
     const data = ref<ResultType>()
     const loading = ref(false)
 
-    // 判断对象是否通用响应对象
-    const isCommonResult = (obj: unknown): obj is CommonResult => {
-        if (obj instanceof Object) {
-            return 'code' in obj && 'data' in obj
-        }
-        return false
-    }
-
     // 异步函数
     const runAsync = async (payload: Partial<TParams> = {}) => {
-        try {
-            loading.value = true
-            if (params && params.page && params.pagesize) {
-                params.page = pageIndex.value
-                params.pagesize = pageIndex.value
+        if (params && params.pagesize) {
+            params.page = pageIndex.value
+            params.pagesize = pageSize.value
+        }
+        onBefore && await onBefore()
+        const res = await request({ ...params, ...payload } as TParams)
+        if (isCommonResult(res)) {
+            total.value = res.total
+            if (Array.isArray(res.data)) {
+                dataList.value = res.data
+            } else {
+                data.value = res.data as ResultType
             }
-
-            const res = await request({ ...params, ...payload } as TParams)
-
-            if (isCommonResult(res)) {
-                total.value = res.total
-                if (Array.isArray(res.data)) {
-                    dataList.value = res.data
-                } else {
-                    data.value = res.data as ResultType
-                }
+        } else {
+            if (Array.isArray(res)) {
+                dataList.value = res
             } else {
-                if (Array.isArray(res)) {
-                    dataList.value = res
-                } else {
-                    data.value = res as ResultType
-                }
+                data.value = res as ResultType
             }
-
-            return res
-        } finally {
-            loading.value = false
         }
+        return res
     }
 
     // 同步函数
     const run = (payload: Partial<TParams> = {}) => {
+        loading.value = true
         runAsync(payload).then((res) => {
             onSuccess && onSuccess(res)
         }).catch((err) => {
             onError && onError(err)
         }).finally(() => {
+            loading.value = false
             onFinally && onFinally()
         })
     }
@@ -83,6 +79,10 @@ export function useRequest<TParams extends object, TResponse>(request: (params:
         console.warn('取消请求')
     }
 
+    if (!manual) {
+        run() // 自动执行
+    }
+
     onUnmounted(() => {
         cancel()
     })

+ 148 - 0
src/mock/router.ts

@@ -248,6 +248,154 @@ const appmenu = {
             {
                 authType: 1,
                 sort: 5,
+                title: '竞价大厅',
+                code: 'bidding',
+                url: '/bidding',
+                urlType: 1,
+                component: 'Main',
+                icon: 'g-icon--listing-filled',
+            },
+            {
+                authType: 1,
+                sort: 4,
+                title: '预售大厅',
+                code: 'presale',
+                url: '/presale',
+                urlType: 1,
+                component: 'Main',
+                icon: 'g-icon--listing-filled',
+                children: [
+                    {
+                        authType: 1,
+                        sort: 1,
+                        title: '预售大厅',
+                        code: 'presale_list',
+                        url: '',
+                        urlType: 1,
+                        component: 'views/presale/list/index.vue',
+                        children: [
+                            {
+                                authType: 3,
+                                title: '认购下单',
+                                code: 'presale_list_details',
+                                component: 'views/presale/list/components/details/index.vue',
+                            },
+                        ]
+                    },
+                    {
+                        authType: 1,
+                        sort: 2,
+                        title: '我的预售',
+                        code: 'presale_mine',
+                        url: 'mine',
+                        urlType: 1,
+                        component: 'views/presale/mine/index.vue',
+                        children: [
+                            {
+                                authType: 3,
+                                title: '预售申请',
+                                code: 'presale_mine_add',
+                                component: 'views/presale/mine/components/add/index.vue',
+                                className: 'el-button--primary',
+                            },
+                            {
+                                authType: 3,
+                                title: '我的申请',
+                                code: 'presale_mine_apply',
+                                component: 'views/presale/mine/components/apply/index.vue',
+                                className: 'el-button--primary',
+                            },
+                            {
+                                authType: 3,
+                                title: '详情',
+                                code: 'presale_mine_details',
+                                component: 'views/presale/mine/components/details/index.vue',
+                            },
+                        ]
+                    },
+                    {
+                        authType: 1,
+                        sort: 3,
+                        title: '我参与的预售',
+                        code: 'presale_partake',
+                        url: 'partake',
+                        urlType: 1,
+                        component: 'views/presale/partake/index.vue',
+                        children: [
+                            {
+                                authType: 3,
+                                title: '详情',
+                                code: 'presale_partake_details',
+                                component: 'views/presale/partake/components/details/index.vue',
+                            },
+                        ]
+                    },
+                ]
+            },
+            {
+                authType: 1,
+                sort: 5,
+                title: '采集交易',
+                code: 'centralize',
+                url: '/centralize',
+                urlType: 1,
+                component: 'Main',
+                icon: 'g-icon--listing-filled',
+                children: [
+                    {
+                        authType: 1,
+                        sort: 1,
+                        title: '采集大厅',
+                        code: 'centralize_list',
+                        url: '',
+                        urlType: 1,
+                        component: 'views/centralize/list/index.vue',
+                    },
+                    {
+                        authType: 1,
+                        sort: 2,
+                        title: '我的采集',
+                        code: 'centralize_mine',
+                        url: 'mine',
+                        urlType: 1,
+                        component: 'views/centralize/mine/index.vue',
+                        children: [
+                            {
+                                authType: 3,
+                                title: '采集申请',
+                                code: 'centralize_mine_add',
+                                component: 'views/centralize/mine/components/add/index.vue',
+                                className: 'el-button--primary',
+                            },
+                            {
+                                authType: 3,
+                                title: '我的申请',
+                                code: 'centralize_mine_apply',
+                                component: 'views/centralize/mine/components/apply/index.vue',
+                                className: 'el-button--primary',
+                            },
+                            {
+                                authType: 3,
+                                title: '详情',
+                                code: 'centralize_mine_details',
+                                component: 'views/centralize/mine/components/details/index.vue',
+                            },
+                        ]
+                    },
+                    {
+                        authType: 1,
+                        sort: 3,
+                        title: '我参与的采集',
+                        code: 'centralize_partake',
+                        url: 'partake',
+                        urlType: 1,
+                        component: 'views/centralize/partake/index.vue',
+                    },
+                ]
+            },
+            {
+                authType: 1,
+                sort: 5,
                 title: '我的收藏',
                 code: 'favorite',
                 url: '/favorite',

+ 2 - 2
src/packages/mobile/components/base/tabbar/index.vue

@@ -27,7 +27,7 @@
 <script lang="ts" setup>
 import { PropType, ref, watch, computed } from 'vue'
 import { Tabbar } from './interface'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 
 const emit = defineEmits(['change', 'update:dataIndex'])
 
@@ -50,7 +50,7 @@ const props = defineProps({
 })
 
 const selectedIndex = ref(props.dataIndex);
-const { clientWidth } = themeStore.$mapState();
+const { clientWidth } = globalStore.$mapState();
 
 const styles = computed(() => ({
   position: props.fixed ? 'fixed' : 'static',

+ 2 - 2
src/packages/mobile/components/layouts/navbar/index.vue

@@ -36,7 +36,7 @@
 import { useAttrs, computed } from 'vue'
 import { useRouter } from 'vue-router'
 import { Icon } from 'vant'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 
 const emit = defineEmits<{ (event: string, ...args: unknown[]): void }>()
 
@@ -54,7 +54,7 @@ const props = defineProps({
 
 const router = useRouter();
 const attrs = useAttrs();
-const { clientWidth } = themeStore.$mapState();
+const { clientWidth } = globalStore.$mapState();
 
 const styles = computed(() => ({
   position: props.fixed ? 'fixed' : 'static',

+ 3 - 3
src/packages/mobile/main.ts

@@ -9,7 +9,7 @@ import '@/utils/h5plus' // 加载html5+
 import layouts from './components/layouts' // 全局布局组件
 import './assets/themes/style.less' // 主题样式
 import { timerInterceptor } from '@/utils/timer'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 // import Vconsole from 'vconsole'
 // new Vconsole();
 
@@ -22,7 +22,7 @@ app.mount('#app')
 // 等待 html 加载完成
 document.addEventListener('DOMContentLoaded', () => {
     // 适配客户端
-    themeStore.actions.screenAdapter(true)
+    globalStore.actions.screenAdapter(true)
     // 监听窗口大小变化
-    window.addEventListener('resize', timerInterceptor.setDebounce(() => themeStore.actions.screenAdapter(true)))
+    window.addEventListener('resize', timerInterceptor.setDebounce(() => globalStore.actions.screenAdapter(true)))
 }, false)

+ 2 - 2
src/packages/mobile/views/home/components/market/index.vue

@@ -36,13 +36,13 @@
 <script lang="ts" setup>
 import { ref, reactive, onActivated, onDeactivated } from 'vue'
 import { Grid, GridItem, Button, ActionSheet, ActionSheetAction } from 'vant'
-import { futuresStore, themeStore } from '@/stores'
+import { futuresStore, globalStore } from '@/stores'
 import { handlePriceColor, handleNoneValue } from '@/filters'
 import AppTable from '@mobile/components/base/table/index.vue'
 import { TableColumn } from '@mobile/components/base/table/interface'
 import subscribe from '@/services/subscribe'
 
-const { setTheme } = themeStore.actions;
+const { setTheme } = globalStore.actions;
 const { quoteDayList } = futuresStore.$mapState();
 const quoteSubscribe = subscribe.addQuoteSubscribe(['cu2206', 'cu2207', 'cu2208', 'cu2209', 'cu2301', 'cu2303', 'cu2304']);
 const showAction = ref(false);

+ 2 - 4
src/packages/mobile/views/home/components/order/index.vue

@@ -54,10 +54,8 @@ const columns = [
   }
 ]
 
-queryGoodsList({
-  success: (res) => {
-    tableList.value = res.data;
-  }
+queryGoodsList().then((res) => {
+  tableList.value = res.data;
 })
 
 onMounted(() => {

+ 5 - 5
src/packages/pc/assets/themes/default/default.less

@@ -39,6 +39,11 @@
             &:last-child {
                 margin-bottom: 18px;
             }
+
+            .el-select,
+            .el-input-number {
+                width: 100%;
+            }
         }
 
         &--horizontal {
@@ -61,11 +66,6 @@
                     width: 100%;
                 }
             }
-
-            .el-select,
-            .el-input-number {
-                width: 100%;
-            }
         }
     }
 

+ 1 - 1
src/packages/pc/assets/themes/global/global.less

@@ -16,7 +16,7 @@
 }
 
 .g-details {
-    &__header {
+    &__title {
         display: flex;
         align-items: center;
         gap: 10px;

+ 12 - 1
src/packages/pc/components/base/table-details/index.less

@@ -3,14 +3,25 @@
         margin-top: 20px;
     }
 
-    table {
+    >table {
         width: 100%;
         table-layout: fixed;
+        border-collapse: collapse;
+
+        th,
+        td {
+            border: 0 solid #ebeef5;
+            padding: 5px 10px;
+        }
 
         th {
             color: #666;
             font-weight: normal;
             vertical-align: top;
         }
+
+        td {
+            vertical-align: top;
+        }
     }
 }

+ 43 - 26
src/packages/pc/components/base/table-details/index.vue

@@ -1,18 +1,20 @@
 <template>
-    <div class="app-table-details">
-        <div class="app-table-details__header">
-            <slot name="header"></slot>
+    <div class="app-table-details g-details">
+        <div class="g-details__title">
+            <slot name="title">
+                {{ title }}
+            </slot>
         </div>
-        <table :cellspacing="cellSpacing" cellpadding="0">
+        <table cellspacing="0" cellpadding="0">
             <tbody>
                 <tr v-for="(items, i) in cellGroup" :key="i">
                     <template v-for="(item, n) in items" :key="n">
-                        <th :style="cellStyle">
+                        <th :style="labelStyle">
                             <slot :name="item.prop + 'Label'">
                                 {{ item.label }}
                             </slot>
                         </th>
-                        <td>
+                        <td :colspan="(column * 2 - items.length * 2) + 1" :style="valueStyle">
                             <slot :name="item.prop" :value="data[item.prop]">
                                 {{ handleValue(item) }}
                             </slot>
@@ -32,9 +34,11 @@ interface cellProp {
     prop: string;
     label: string;
     decimal?: number; // 保留小数点位数
+    entireRow?: boolean; // 是否整行显示
 }
 
 const props = defineProps({
+    title: String,
     data: {
         type: Object,
         required: true
@@ -47,41 +51,54 @@ const props = defineProps({
         type: Number,
         default: 1
     },
-    // 单元格间距
-    cellSpacing: {
-        type: Number,
-        default: 10
-    },
     // 标签宽度
     labelWidth: {
         type: Number,
         default: 0
     },
-    // 标签宽度
+    // 标签对齐方式
     labelAlign: {
         type: String as PropType<'left' | 'center' | 'right'>,
         default: 'right'
     },
-    border: {
-        type: Boolean,
-        default: false
-    }
+    // 边框大小
+    borderWidth: {
+        type: Number,
+        default: 0
+    },
 })
 
 const cellGroup = computed(() => {
-    const result = []
-    let index = 0
-    // 一维数组转换成二维数组
-    while (index < props.cellProps.length) {
-        const group = props.cellProps.slice(index, index += props.column)
-        result.push(group)
-    }
-    return result
+    // const result = []
+    // let index = 0
+    // // 一维数组转换成二维数组
+    // while (index < props.cellProps.length) {
+    //     const group = props.cellProps.slice(index, index += props.column)
+    //     result.push(group)
+    // }
+    return props.cellProps.reduce((pre, cur) => {
+        const last = pre[pre.length - 1]
+        if (last) {
+            if (cur.entireRow || last.length === props.column) {
+                pre[pre.length] = [cur]
+            } else {
+                last.push(cur)
+            }
+        } else {
+            pre[0] = [cur]
+        }
+        return pre
+    }, [] as cellProp[][])
 })
 
-const cellStyle = computed(() => ({
-    width: props.labelWidth ? props.labelWidth + 'px' : 'auto',
+const valueStyle = computed(() => ({
+    borderWidth: props.borderWidth + 'px',
+}))
+
+const labelStyle = computed(() => ({
+    width: props.labelWidth ? props.labelWidth + 'px' : 'fit-content',
     textAlign: props.labelAlign,
+    ...valueStyle.value,
 }))
 
 const handleValue = (cell: cellProp) => {

+ 3 - 0
src/packages/pc/components/base/table/index.less

@@ -1,4 +1,7 @@
 .app-table {
+    width: 100%;
+    line-height: normal;
+
     &:not(:first-child) {
         margin-top: 20px;
     }

+ 2 - 2
src/packages/pc/components/base/upload/index.vue

@@ -20,7 +20,7 @@
 <script lang="ts" setup>
 import { shallowRef, shallowReactive, computed, PropType, toRaw, onMounted } from 'vue'
 import { ElMessage, UploadProps, UploadUserFile, UploadRawFile, UploadFile, UploadFiles, UploadInstance, genFileId } from 'element-plus'
-import { getImageUrl } from '@/filters'
+import { getFileUrl } from '@/filters'
 import service from '@/services'
 
 const props = defineProps({
@@ -63,7 +63,7 @@ const imageList = computed(() => {
                 (response as { filePath: string }[]).forEach((e) => {
                     result.push({
                         uid,
-                        filePath: getImageUrl(e.filePath)
+                        filePath: getFileUrl(e.filePath)
                     })
                 })
             }

+ 7 - 11
src/packages/pc/components/layouts/header/components/calculator/index.vue

@@ -109,18 +109,14 @@ const formSubmit = () => {
                 discount = -discount
             }
             priceCalc({
-                data: {
-                    ...formData,
-                    discount
-                },
-                success: (res) => {
-                    if (res.data.length) {
-                        priceData.value = res.data[0]
-                    }
-                },
-                complete: () => {
-                    loading.value = false
+                ...formData,
+                discount
+            }).then((res) => {
+                if (res.data.length) {
+                    priceData.value = res.data[0]
                 }
+            }).finally(() => {
+                loading.value = false
             })
         }
     })

+ 6 - 10
src/packages/pc/components/layouts/header/components/certificate/index.vue

@@ -73,19 +73,15 @@ const formSubmit = () => {
     }
 }
 
-gzCertAddressParam({
-    success: (res) => {
-        urlParams.value = res.data
-    }
+gzCertAddressParam().then((res) => {
+    urlParams.value = res.data
 })
 
-gzCertAddressConfig({
-    success: (res) => {
-        if (res.data.length) {
-            formData.certtype = res.data[0].certtype
-        }
-        dataList.value = res.data
+gzCertAddressConfig().then((res) => {
+    if (res.data.length) {
+        formData.certtype = res.data[0].certtype
     }
+    dataList.value = res.data
 })
 </script>
 

+ 4 - 5
src/packages/pc/components/layouts/header/index.vue

@@ -39,15 +39,14 @@
                 </template>
             </el-dropdown>
         </div>
-        <component :is="componentMap.get(componentId)" v-bind="{ dataList }" @closed="closeComponent"
-            v-if="componentId" />
+        <component :is="componentMap.get(componentId)" v-bind="{ dataList }" @closed="closeComponent" v-if="componentId" />
     </div>
 </template>
 
 <script lang="ts" setup>
 import { ref, onMounted, defineAsyncComponent } from 'vue'
 import { useRouter } from 'vue-router'
-import { userStore, themeStore } from '@/stores'
+import { loginStore, globalStore } from '@/stores'
 import { useComponent } from '@/hooks/component'
 import { useNotice } from '@/business/notice'
 import eventBus from '@/services/bus'
@@ -61,8 +60,8 @@ const componentMap = new Map<string, unknown>([
 
 const { componentId, openComponent, closeComponent } = useComponent()
 const { dataList, unreadList, getNoticeList } = useNotice()
-const { isMobile } = themeStore.$mapState()
-const { accountName } = userStore.$mapGetters()
+const { isMobile } = globalStore.$mapState()
+const { accountName } = loginStore.$mapGetters()
 const router = useRouter()
 const fullScreen = ref(false)
 

+ 2 - 2
src/packages/pc/components/layouts/page/index.vue

@@ -30,14 +30,14 @@
 <script lang="ts" setup>
 import { shallowRef, watch } from 'vue'
 import { useMenu } from '@/hooks/menu'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 import AppTabs from '@/components/base/tabs/index.vue'
 import AppHeader from '../header/index.vue'
 import AppFooter from '../footer/index.vue'
 import AppSidebar from '../sidebar/index.vue'
 
 const { route, router, getChildrenMenus } = useMenu()
-const isCollapse = shallowRef(themeStore.state.isMobile)
+const isCollapse = shallowRef(globalStore.state.isMobile)
 const secondMenus = shallowRef<Ermcp.UserRoutes[]>([]) // 二级菜单
 const dataIndex = shallowRef(-1) // 选中的标签
 

+ 2 - 2
src/packages/pc/components/layouts/sidebar/index.vue

@@ -16,7 +16,7 @@
 <script lang="ts" setup>
 import { watch } from 'vue'
 import { useMenu } from '@/hooks/menu'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 import AppSidemenu from '../sidemenu/index.vue'
 
 const emit = defineEmits(['update:collapse'])
@@ -27,7 +27,7 @@ defineProps({
 })
 
 const { router, getChildrenMenus } = useMenu()
-const { isMobile } = themeStore.$mapState()
+const { isMobile } = globalStore.$mapState()
 const year = new Date().getFullYear()
 
 const hideSidebar = () => {

+ 5 - 11
src/packages/pc/components/modules/address/index.vue

@@ -1,6 +1,6 @@
 <template>
-    <el-select class="app-address" value-key="autoid" :placeholder="placeholder" v-model="selectedItem"
-        @change="onChange" @clear="onChange" clearable>
+    <el-select class="app-address" value-key="autoid" :placeholder="placeholder" v-model="selectedItem" @change="onChange"
+        @clear="onChange" clearable>
         <el-option class="app-address-item" v-for="(item, i) in dataList" :key="i"
             :label="[item.provincename, item.cityname, item.districtname, item.address].join(' ')" :value="item" />
     </el-select>
@@ -9,7 +9,6 @@
 <script lang="ts" setup>
 import { shallowRef } from 'vue'
 import { queryUserReceiveInfo } from '@/services/api/user'
-import { loginStore } from '@/stores'
 
 const props = defineProps({
     modelValue: Number,
@@ -28,14 +27,9 @@ const onChange = (item?: Ermcp.UserReceiveInfoRsp) => {
     emit('change', item)
 }
 
-queryUserReceiveInfo({
-    data: {
-        userid: loginStore.getters.userId
-    },
-    success: (res) => {
-        dataList.value = res.data
-        selectedItem.value = res.data.find((e) => e.autoid === props.modelValue)
-    }
+queryUserReceiveInfo().then((res) => {
+    dataList.value = res.data
+    selectedItem.value = res.data.find((e) => e.autoid === props.modelValue)
 })
 </script>
 

+ 5 - 11
src/packages/pc/components/modules/invoice/index.vue

@@ -1,6 +1,6 @@
 <template>
-    <el-select class="app-invoice" value-key="autoid" :placeholder="placeholder" v-model="selectedItem"
-        @change="onChange" @clear="onChange" clearable>
+    <el-select class="app-invoice" value-key="autoid" :placeholder="placeholder" v-model="selectedItem" @change="onChange"
+        @clear="onChange" clearable>
         <el-option class="app-invoice-item" v-for="(item, i) in dataList" :key="i"
             :label="[getReceiptTypeName(item.receipttype), item.username].join(' ')" :value="item" />
     </el-select>
@@ -10,7 +10,6 @@
 import { shallowRef } from 'vue'
 import { getReceiptTypeName } from '@/constants/receipt'
 import { queryWrUserReceiptInfo } from '@/services/api/user'
-import { loginStore } from '@/stores'
 
 const props = defineProps({
     modelValue: Number,
@@ -29,14 +28,9 @@ const onChange = (item?: Ermcp.WrUserReceiptInfoRsp) => {
     emit('change', item)
 }
 
-queryWrUserReceiptInfo({
-    data: {
-        userid: loginStore.getters.userId
-    },
-    success: (res) => {
-        dataList.value = res.data
-        selectedItem.value = res.data.find((e) => e.autoid === props.modelValue)
-    }
+queryWrUserReceiptInfo().then((res) => {
+    dataList.value = res.data
+    selectedItem.value = res.data.find((e) => e.autoid === props.modelValue)
 })
 </script>
 

+ 3 - 3
src/packages/pc/main.ts

@@ -11,7 +11,7 @@ import * as ElementIcons from '@element-plus/icons-vue'
 import 'element-plus/dist/index.css'
 import './assets/themes/style.less' // 主题样式
 import { timerInterceptor } from '@/utils/timer'
-import { themeStore } from '@/stores'
+import { globalStore } from '@/stores'
 
 const app = createApp(App)
 app.use(router)
@@ -24,9 +24,9 @@ app.mount('#app')
 // 等待 html 加载完成
 document.addEventListener('DOMContentLoaded', () => {
     // 适配客户端
-    themeStore.actions.screenAdapter()
+    globalStore.actions.screenAdapter()
     // 监听窗口大小变化
-    window.addEventListener('resize', timerInterceptor.setDebounce(() => themeStore.actions.screenAdapter()));
+    window.addEventListener('resize', timerInterceptor.setDebounce(() => globalStore.actions.screenAdapter()));
 }, false)
 
 // 注册全局图标

+ 7 - 9
src/packages/pc/views/bonded/expense/components/details/index.vue

@@ -1,10 +1,8 @@
 <!-- 保税仓业务-计费管理-详情 -->
 <template>
     <app-drawer class="g-details" title="详情" :width="960" v-model:show="show">
-        <app-table-details :label-width="100" :data="selectedRow" :cellProps="detailCells" :column="2">
-            <template #header>
-                <h3 class="g-details__header">款项明细【{{ selectedRow.trademonth }}】</h3>
-            </template>
+        <app-table-details :title="`款项明细【${selectedRow.trademonth}】`" :label-width="120" :data="selectedRow"
+            :cell-props="detailCells" :column="2">
             <!-- 支付状态 -->
             <template #paystatus="{ value }">
                 {{ getGZBSCPayStatusName(value) }}
@@ -14,24 +12,24 @@
                 {{ getGZBSCPayModeName(value) }}
             </template>
         </app-table-details>
-        <app-table :data="powerfeeList" :columns="powerfeeColumns" :show-toolbar="false" border>
+        <app-table title="电费明细" :data="powerfeeList" :columns="powerfeeColumns" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">电费明细</h3>
+                <h3 class="g-details__title">电费明细</h3>
             </template>
         </app-table>
         <app-table :data="importList" :columns="imporColumns" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">进口明细</h3>
+                <h3 class="g-details__title">进口明细</h3>
             </template>
         </app-table>
         <app-table :data="exportList" :columns="exportColumns" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">出境明细</h3>
+                <h3 class="g-details__title">出境明细</h3>
             </template>
         </app-table>
         <app-table :data="transferList" :columns="transferColumns" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">转厂明细</h3>
+                <h3 class="g-details__title">转厂明细</h3>
             </template>
         </app-table>
     </app-drawer>

+ 1 - 1
src/packages/pc/views/bonded/expense/components/payment/index.vue

@@ -2,7 +2,7 @@
 <template>
     <app-drawer :title="`款项明细【${selectedRow.trademonth}】`" :width="460" v-model:show="show" :loading="loading"
         :refresh="refresh">
-        <app-table-details :label-width="100" :data="selectedRow" :cellProps="detailCells">
+        <app-table-details :label-width="120" :data="selectedRow" :cell-props="detailCells">
             <!-- 账户可用余额 -->
             <template #balance>
                 <span :style="{ color: balanceIsInsufficient ? 'red' : '#409340' }">

+ 2 - 2
src/packages/pc/views/bonded/inbound/components/apply/index.vue

@@ -1,7 +1,7 @@
 <!-- 保税仓业务-进仓管理-提交申请 -->
 <template>
     <app-drawer class="g-details" title="提交申请" v-model:show="show" :width="960" :loading="loading" :refresh="refresh">
-        <h3 class="g-details__header">发货信息</h3>
+        <h3 class="g-details__title">发货信息</h3>
         <el-form ref="formRef" class="el-form--horizontal" label-width="100px" :model="formData" :rules="formRules">
             <el-form-item label="发货方" prop="UserName">
                 <el-input placeholder="请输入" v-model="formData.UserName" />
@@ -24,7 +24,7 @@
         </el-form>
         <app-table :data="orderDetailList" :columns="columns" :max-height="400" border>
             <template #header>
-                <h3 class="g-details__header">商品信息</h3>
+                <h3 class="g-details__title">商品信息</h3>
             </template>
             <template #toolbar>
                 <el-button-group>

+ 3 - 11
src/packages/pc/views/bonded/inbound/components/details/index.vue

@@ -1,19 +1,11 @@
 <!-- 保税仓业务-进仓管理-详情 -->
 <template>
     <app-drawer class="g-details" title="详情" :width="960" v-model:show="show">
-        <app-table-details :label-width="100" :data="selectedRow" :cellProps="deliveryCells" :column="2">
-            <template #header>
-                <h3 class="g-details__header">发货信息</h3>
-            </template>
-        </app-table-details>
-        <app-table-details :label-width="100" :data="selectedRow" :cellProps="receiveCells" :column="2">
-            <template #header>
-                <h3 class="g-details__header">签收信息</h3>
-            </template>
-        </app-table-details>
+        <app-table-details title="发货信息" :label-width="100" :data="selectedRow" :cell-props="deliveryCells" :column="2" />
+        <app-table-details title="签收信息" :label-width="100" :data="selectedRow" :cell-props="receiveCells" :column="2" />
         <app-table :data="orderDetailList" :columns="columns" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">
+                <h3 class="g-details__title">
                     商品信息
                     <el-button size="small" @click="showDownload = true">文件下载</el-button>
                 </h3>

+ 3 - 3
src/packages/pc/views/bonded/outbound/components/apply/index.vue

@@ -1,7 +1,7 @@
 <!-- 保税仓业务-出仓管理-提交申请 -->
 <template>
     <app-drawer class="g-details" title="提交申请" v-model:show="show" :width="960" :loading="loading" :refresh="refresh">
-        <h3 class="g-details__header">收货信息</h3>
+        <h3 class="g-details__title">收货信息</h3>
         <el-form ref="formRef" class="el-form--horizontal" label-width="100px" :model="formData" :rules="formRules">
             <el-form-item label="收货方" prop="UserName">
                 <el-input placeholder="请输入" v-model="formData.UserName" />
@@ -30,7 +30,7 @@
         </el-form>
         <app-table :data="orderDetailList" :columns="columns1" :max-height="400" border>
             <template #header>
-                <h3 class="g-details__header">商品信息</h3>
+                <h3 class="g-details__title">商品信息</h3>
             </template>
             <template #toolbar>
                 <el-button-group>
@@ -48,7 +48,7 @@
         </app-table>
         <app-table :data="orderDetailAttList" :columns="columns2" :max-height="400" border>
             <template #header>
-                <h3 class="g-details__header">附表信息</h3>
+                <h3 class="g-details__title">附表信息</h3>
             </template>
             <template #toolbar>
                 <el-button-group>

+ 5 - 12
src/packages/pc/views/bonded/outbound/components/details/index.vue

@@ -1,19 +1,12 @@
 <!-- 保税仓业务-出仓管理-详情 -->
 <template>
     <app-drawer class="g-details" title="详情" :width="960" v-model:show="show">
-        <app-table-details :label-width="100" :data="selectedRow" :cellProps="receiveCells" :column="2">
-            <template #header>
-                <h3 class="g-details__header">收货信息-{{ getGZBSCOutTypeName(selectedRow.outtype) }}</h3>
-            </template>
-        </app-table-details>
-        <app-table-details :label-width="100" :data="selectedRow" :cellProps="deliveryCells" :column="2">
-            <template #header>
-                <h3 class="g-details__header">发货信息</h3>
-            </template>
-        </app-table-details>
+        <app-table-details :title="`收货信息-${getGZBSCOutTypeName(selectedRow.outtype)}`" :label-width="110"
+            :data="selectedRow" :cell-props="receiveCells" :column="2" />
+        <app-table-details title="发货信息" :label-width="110" :data="selectedRow" :cell-props="deliveryCells" :column="2" />
         <app-table :data="orderDetailList" :columns="columns1" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">
+                <h3 class="g-details__title">
                     商品信息
                     <el-button size="small" @click="showDownload = true">文件下载</el-button>
                 </h3>
@@ -21,7 +14,7 @@
         </app-table>
         <app-table :data="orderDetailAttList" :columns="columns2" :show-toolbar="false" border>
             <template #header>
-                <h3 class="g-details__header">附表信息</h3>
+                <h3 class="g-details__title">附表信息</h3>
             </template>
         </app-table>
         <component :is="Download" v-bind="{ selectedRow }" @closed="showDownload = false" v-if="showDownload" />

+ 89 - 0
src/packages/pc/views/centralize/list/index.vue

@@ -0,0 +1,89 @@
+<!-- 集采大厅 -->
+<template>
+    <app-view>
+        <template #header>
+            <app-filter :options="filterOptons" />
+        </template>
+        <!-- 表格数据 -->
+        <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+            <!-- 最小 / 最大采购单位(克拉) -->
+            <template #buyqty="{ row }">
+                {{ row.minbuyqty }} / {{ row.maxbuyqty }}
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onRefresh" />
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryGZPreSell } from '@/services/api/presale'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+
+const { filterOptons, getQueryParams } = useDataFilter<Ermcp.GZPreSellReq>()
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZPreSell, {
+    params: {
+        pagesize: 20,
+        marketid: 62201,
+        presalestatus: 2,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Ermcp.TableColumn[]>([
+    { prop: 'customername', label: '卖方' },
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'presaleqty', label: '集采数量(克拉)' },
+    { prop: 'buyqty', label: '最小 / 最大采购单位(克拉)', width: 190 },
+    { prop: 'minsuccessqty', label: '最低成团量(克拉)', width: 140 },
+    { prop: 'buymarginvalue', label: '采购保证金(%)' },
+    { prop: 'startdate', label: '开始日期' },
+    { prop: 'enddate', label: '结束日期' },
+    { prop: 'tradeqty', label: '已认购数量(克拉)', width: 140 },
+    { prop: 'operate', label: '操作', fixed: 'right' },
+])
+
+filterOptons.selectList = [
+    {
+        label: '状态',
+        key: 'presalestatus',
+        locked: true,
+        selectedValue: 2,
+        options: [
+            { label: '未开始', value: 1 },
+            { label: '进行中', value: 2 },
+        ],
+    },
+]
+
+filterOptons.inputList = [
+    { label: '卖方', keys: ['customername'] },
+    { label: '商品', keys: ['wrstandardname'] },
+]
+
+filterOptons.buttonList = [
+    { lable: '重置', onClick: () => onSearch(true) },
+    { lable: '查询', className: 'el-button--primary', onClick: () => onSearch() }
+]
+
+const onSearch = (clear = false) => {
+    getQueryParams((qs) => {
+        pageIndex.value = 1
+        run(qs)
+    }, clear)
+}
+
+const onRefresh = () => {
+    getQueryParams((qs) => run(qs))
+}
+</script>

+ 264 - 0
src/packages/pc/views/centralize/mine/components/add/index.vue

@@ -0,0 +1,264 @@
+<!-- 预售大厅-我的集采-集采申请 -->
+<template>
+    <app-drawer class="g-details" title="集采申请" v-model:show="show" :width="960" :loading="loading" :refresh="refresh">
+        <h3 class="g-details__title">集采信息</h3>
+        <el-form ref="formRef" class="el-form--horizontal" label-width="140px" :model="formData" :rules="formRules">
+            <el-form-item label="商品名称" prop="WRStandardName">
+                <el-input placeholder="请输入" v-model="formData.WRStandardName" />
+            </el-form-item>
+            <el-form-item label="钻石分类" prop="YSZSCategory">
+                <el-radio-group v-model="formData.YSZSCategory">
+                    <el-radio :label="item.value" v-for="(item, index) in getYSZSCategoryList()" :key="index">
+                        {{ item.label }}
+                    </el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="集采数量" prop="PresaleQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.PresaleQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="履约方式" prop="PerformanceTemplateID">
+                <component :is="PerformanceTemplate" v-model="formData.PerformanceTemplateID" />
+            </el-form-item>
+            <el-form-item label="最小采购单位" prop="MinBuyQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.MinBuyQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="最低成团量" prop="MinSuccessQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.MinSuccessQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="最大采购单位" prop="MaxBuyQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.MaxBuyQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="采购保证金比例" prop="BuyMarginValue">
+                <el-input type="number" placeholder="请输入" v-model="formData.BuyMarginValue">
+                    <template #append>%</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="集采日期" prop="PreDate">
+                <el-date-picker type="daterange" placeholder="请选择" range-separator="至" start-placeholder="开始"
+                    end-placeholder="结束" v-model="datePickerValue" :disabled-date="disabledDate" />
+            </el-form-item>
+            <el-form-item class="el-form-item--row" label="集采价格" prop="GZCenterPurchasePriceLists">
+                <app-table :data="formData.GZCenterPurchasePriceLists" :columns="columns" :max-height="400" border>
+                    <template #toolbar>
+                        <el-button-group>
+                            <el-button size="small" @click="openEdit()">新增</el-button>
+                            <el-button size="small" @click="formData.GZCenterPurchasePriceLists = []">清空</el-button>
+                        </el-button-group>
+                    </template>
+                    <!-- 操作 -->
+                    <template #operate="{ row, index }">
+                        <el-button-group size="small">
+                            <el-button @click="openEdit(row)">修改</el-button>
+                            <el-button @click="deleteRecord(index)">删除</el-button>
+                        </el-button-group>
+                    </template>
+                </app-table>
+            </el-form-item>
+        </el-form>
+        <h3 class="g-details__title">钻石参考信息</h3>
+        <el-form class="el-form--horizontal" label-width="140px" :model="formData" :rules="formRules">
+            <el-form-item label="颜色" prop="ZSColorTypeStr">
+                <el-input placeholder="请输入" v-model="formData.ZSColorTypeStr" />
+            </el-form-item>
+            <el-form-item label="尺寸" prop="SizeStr">
+                <el-input placeholder="请输入" v-model="formData.SizeStr" />
+            </el-form-item>
+            <el-form-item label="净度" prop="ZSClarityTypeStr">
+                <el-input placeholder="请输入" v-model="formData.ZSClarityTypeStr" />
+            </el-form-item>
+            <el-form-item label="成品率" prop="YieldRate">
+                <el-input placeholder="请输入" v-model="formData.YieldRate" />
+            </el-form-item>
+            <el-form-item label="数量描述" prop="QtyDesc">
+                <el-input placeholder="请输入" v-model="formData.QtyDesc" />
+            </el-form-item>
+            <el-form-item label="重量描述" prop="WeightDesc">
+                <el-input placeholder="请输入" v-model="formData.WeightDesc" />
+            </el-form-item>
+            <el-form-item label="生产方式" prop="YSProductionMode">
+                <el-select v-model="formData.YSProductionMode">
+                    <el-option :label="item.label" :value="item.value" v-for="(item, index) in getYSProductionModeList()"
+                        :key="index" />
+                </el-select>
+            </el-form-item>
+            <el-form-item class="el-form-item--row" label="图片" prop="PictureUrls">
+                <app-upload :file-types="['image']" :limit="5" type-message="请选择正确的图片类型" @change="onUploadChange" />
+            </el-form-item>
+            <el-form-item class="el-form-item--row" label="备注" prop="Remark">
+                <el-input type="textarea" v-model="formData.Remark" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+        <component :is="PriceEdit" v-bind="{ selectedRow }" @update="onUpdate" @closed="showEdit = false" v-if="showEdit" />
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, defineAsyncComponent } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { formatDate } from '@/filters'
+import { getYSProductionModeList, getYSZSCategoryList } from '@/constants/presale'
+import { gzCenterPurchaseApply } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppUpload from '@pc/components/base/upload/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+
+// 履约模板
+const PerformanceTemplate = defineAsyncComponent(() => import('@pc/components/modules/performance/index.vue'))
+// 价格编辑
+const PriceEdit = defineAsyncComponent(() => import('./price-edit.vue'))
+
+const formRef = ref<FormInstance>()
+const show = ref(true)
+const refresh = ref(false)
+const loading = ref(false)
+const showEdit = ref(false)
+const datePickerValue = ref<string[]>([]) // 选中的日期
+const selectedRow = ref<Proto.GZCenterPurchasePrice>() // 当前选择的价格明细
+
+const formData = reactive<Partial<Proto.GZCenterPurchaseApplyReq>>({
+    BuyMarginAlgorithm: 1, // 买方保证金方式,必填
+    GZCenterPurchasePriceLists: [],
+})
+
+const columns: Ermcp.TableColumn[] = [
+    { prop: 'StepIndex', label: '序号' },
+    { prop: 'Qty', label: '数量' },
+    { prop: 'Price', label: '价格(元/克拉)' },
+    { prop: 'operate', label: '操作', width: 160, fixed: 'right' }
+]
+
+const formRules: FormRules = {
+    WRStandardName: [{
+        required: true,
+        message: '请输入商品名称'
+    }],
+    YSZSCategory: [{
+        required: true,
+        message: '请选择钻石分类'
+    }],
+    PerformanceTemplateID: [{
+        required: true,
+        message: '请选择履约方式'
+    }],
+    PresaleQty: [{
+        required: true,
+        message: '请输入集采数量'
+    }],
+    MinBuyQty: [{
+        required: true,
+        message: '请输入最小采购单位'
+    }],
+    MinSuccessQty: [{
+        required: true,
+        message: '请输入最低成团量'
+    }],
+    MaxBuyQty: [{
+        required: true,
+        message: '请输入最大采购单位'
+    }],
+    BuyMarginValue: [{
+        required: true,
+        message: '请输入采购保证金比例'
+    }],
+    PreDate: [{
+        required: true,
+        validator: (rule, value, callback) => {
+            if (datePickerValue.value && datePickerValue.value.length === 2) {
+                callback()
+            } else {
+                callback(new Error('请选择预售日期'))
+            }
+        }
+    }],
+    GZCenterPurchasePriceLists: [{
+        required: true,
+        validator: (rule, value, callback) => {
+            if (formData.GZCenterPurchasePriceLists?.length) {
+                callback()
+            } else {
+                callback(new Error('请添加集采价格'))
+            }
+        }
+    }],
+}
+
+// 只能选择今天开始日期
+const disabledDate = (date: Date) => {
+    return date.getTime() < Date.now() - 24 * 3600 * 1000
+}
+
+// 打开价格编辑
+const openEdit = (row?: Proto.GZCenterPurchasePrice) => {
+    selectedRow.value = row
+    showEdit.value = true
+}
+
+// 删除价格记录
+const deleteRecord = (index: number) => {
+    formData.GZCenterPurchasePriceLists?.splice(index, 1)
+    formData.GZCenterPurchasePriceLists?.forEach((e, i) => e.StepIndex = i + 1) // 重置序列
+}
+
+// 更新价格数据
+const onUpdate = (item: Proto.GZCenterPurchasePrice) => {
+    const list = formData.GZCenterPurchasePriceLists ?? []
+    const index = list.findIndex((e) => e.StepIndex === item.StepIndex)
+    if (index > -1) {
+        list[index] = item
+    } else {
+        const n = list.length
+        item.StepIndex = n + 1
+        list[n] = item
+    }
+    formRef.value?.validateField('GZCenterPurchasePriceLists')
+}
+
+const onUploadChange = (files: { filePath: string }[]) => {
+    formData.PictureUrls = files.map((e) => e.filePath).join(',')
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            const [startDate, endDate] = datePickerValue.value
+            formData.StartDate = formatDate(startDate, 'YYYY-MM-DD')
+            formData.EndDate = formatDate(endDate, 'YYYY-MM-DD')
+
+            loading.value = true
+            gzCenterPurchaseApply({
+                data: {
+                    ...formData,
+                    BuyMarginValue: (formData.BuyMarginValue ?? 0) / 100
+                },
+                success: () => {
+                    ElMessage.success('提交成功')
+                    onCancel(true)
+                },
+                fail: (err) => {
+                    ElMessage.error('提交失败:' + err)
+                },
+                complete: () => {
+                    loading.value = false
+                }
+            })
+        }
+    })
+}
+</script>

+ 58 - 0
src/packages/pc/views/centralize/mine/components/add/price-edit.vue

@@ -0,0 +1,58 @@
+<!-- 预售大厅-我的集采-集采申请-价格编辑 -->
+<template>
+    <app-drawer title="编辑" :width="400" v-model:show="show">
+        <el-form ref="formRef" label-width="60px" :model="formItem" :rules="formRules">
+            <el-form-item label="数量" prop="Qty">
+                <el-input-number placeholder="请输入" v-model="formItem.Qty" />
+            </el-form-item>
+            <el-form-item label="价格" prop="Price">
+                <el-input-number placeholder="请输入" v-model="formItem.Price" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">保存</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType } from 'vue'
+import type { FormInstance, FormRules } from 'element-plus'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Proto.GZCenterPurchasePrice>
+    }
+})
+
+const emit = defineEmits(['update'])
+const show = ref(true)
+const formRef = ref<FormInstance>()
+const formItem = ref<Partial<Proto.GZCenterPurchasePrice>>({ StepIndex: 0, ...props.selectedRow })
+
+const formRules: FormRules = {
+    Qty: [{
+        required: true,
+        message: '请输入数量'
+    }],
+    Price: [{
+        required: true,
+        message: '请输入价格'
+    }],
+}
+
+const onCancel = () => {
+    show.value = false
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            emit('update', formItem.value)
+            onCancel()
+        }
+    })
+}
+</script>

+ 78 - 0
src/packages/pc/views/centralize/mine/components/details/index.vue

@@ -0,0 +1,78 @@
+<!-- 预售大厅-我的预售-详情 -->
+<template>
+    <app-drawer class="g-details" title="详情" :width="960" v-model:show="show">
+        <app-table-details title="预售信息" :label-width="100" :data="selectedRow" :cell-props="details1" :column="2" />
+        <app-table-details title="钻石参考信息" :label-width="100" :data="selectedRow" :cell-props="details2" :column="2" />
+        <app-table :data="dataList" :columns="columns" :show-toolbar="false" :loading="loading" border>
+            <template #header>
+                <h3 class="g-details__title">认购信息</h3>
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex" @change="run" />
+            </template>
+        </app-table>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useRequest } from '@/hooks/request'
+import { queryGZMyPresell } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZPreSellRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZMyPresell, {
+    params: {
+        pagesize: 10,
+        presaleapplyid: props.selectedRow.presaleapplyid,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const details1 = [
+    { prop: 'wrstandardname', label: '商品名称:' },
+    { prop: 'createtime', label: '申请日期:' },
+    { prop: 'presaleqty', label: '预售总量:' },
+    { prop: 'unitprice', label: '预售价格:' },
+    { prop: 'minbuyqty', label: '最小采购单位:' },
+    { prop: 'minsuccessqty', label: '最低成团量:' },
+    { prop: 'maxbuyqty', label: '最大采购单位:' },
+    { prop: 'buymarginvalue', label: '采购保证金比例:' },
+    { prop: 'startdate', label: '开始日期:' },
+    { prop: 'enddate', label: '结束日期:' },
+    { prop: 'presalestatus', label: '状态:' },
+    { prop: 'tradeqty', label: '已认购数量:' },
+    { prop: 'performancetemplateid', label: '履约方式:' },
+]
+
+const details2 = [
+    { prop: 'zscolortypestr', label: '颜色:' },
+    { prop: 'sizestr', label: '尺寸:' },
+    { prop: 'zsclaritytypestr', label: '净度:' },
+    { prop: 'yieldrate', label: '成品率:' },
+    { prop: 'qtydesc', label: '数量描述:' },
+    { prop: 'weightdesc', label: '重量描述:' },
+    { prop: 'ysproductionmode', label: '生产方式:' },
+    { prop: 'pictureurls', label: '图片:' },
+    { prop: 'remark', label: '备注:' },
+]
+
+const columns: Ermcp.TableColumn[] = [
+    { prop: 'customername', label: '认购方' },
+    { prop: 'orderqty', label: '认购数量(ct)' },
+    { prop: 'ordertime', label: '认购时间' },
+]
+</script>

+ 94 - 0
src/packages/pc/views/centralize/mine/index.vue

@@ -0,0 +1,94 @@
+<!-- 集采大厅-我的集采 -->
+<template>
+    <app-view>
+        <template #header>
+            <app-filter :options="filterOptons" />
+        </template>
+        <!-- 表格数据 -->
+        <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+            <template #header>
+                <app-auth-operation :menus="['centralize_mine_add', 'centralize_mine_apply']" @closed="onRefresh" />
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-auth-operation type="dropdown" :menus="['centralize_mine_details']" :options="{ selectedRow: row }"
+                    @closed="onRefresh" />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onRefresh" />
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryGZPreSell } from '@/services/api/presale'
+import { loginStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+import AppAuthOperation from '@pc/components/modules/auth-operation/index.vue'
+
+const { userId } = loginStore.$mapGetters()
+const { filterOptons, getQueryParams } = useDataFilter<Ermcp.GZPreSellReq>()
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZPreSell, {
+    params: {
+        pagesize: 20,
+        marketid: 62201,
+        presalestatus: 2,
+        selluserid: userId.value
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Ermcp.TableColumn[]>([
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'presaleqty', label: '集采数量(克拉)' },
+    { prop: 'startdate', label: '开始日期' },
+    { prop: 'enddate', label: '结束日期' },
+    { prop: 'tradeqty', label: '已采购数量(克拉)', width: 140 },
+    { prop: 'createtime', label: '申请时间' },
+    { prop: 'operate', label: '操作', fixed: 'right' },
+])
+
+filterOptons.selectList = [
+    {
+        label: '状态',
+        key: 'presalestatus',
+        locked: true,
+        selectedValue: 2,
+        options: [
+            { label: '未开始', value: 1 },
+            { label: '进行中', value: 2 },
+            { label: '已结束', value: 3 }
+        ],
+    },
+]
+
+filterOptons.inputList = [
+    { label: '商品', keys: ['wrstandardname'] },
+]
+
+filterOptons.buttonList = [
+    { lable: '重置', onClick: () => onSearch(true) },
+    { lable: '查询', className: 'el-button--primary', onClick: () => onSearch() }
+]
+
+const onSearch = (clear = false) => {
+    getQueryParams((qs) => {
+        pageIndex.value = 1
+        run(qs)
+    }, clear)
+}
+
+const onRefresh = () => {
+    getQueryParams((qs) => run(qs))
+}
+</script>

+ 92 - 0
src/packages/pc/views/centralize/partake/index.vue

@@ -0,0 +1,92 @@
+<!-- 集采大厅-我参与的集采 -->
+<template>
+    <app-view>
+        <template #header>
+            <app-filter :options="filterOptons" />
+        </template>
+        <!-- 表格数据 -->
+        <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-auth-operation type="dropdown" :menus="['presale_partake_details']" :options="{ selectedRow: row }"
+                    @closed="onRefresh" />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onRefresh" />
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryGZMyTradingPreSell } from '@/services/api/presale'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+import AppAuthOperation from '@pc/components/modules/auth-operation/index.vue'
+
+const { filterOptons, getQueryParams } = useDataFilter<Ermcp.GZMyTradingPreSellReq>()
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZMyTradingPreSell, {
+    params: {
+        pagesize: 20,
+        marketid: 62201,
+        status: 1,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Ermcp.TableColumn[]>([
+    { prop: 'customername', label: '卖方' },
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'orderqty', label: '采购数量(克拉)' },
+    { prop: 'tradeprice', label: '采购价格(元/克拉)', width: 140 },
+    { prop: 'tradeamount', label: '货款' },
+    { prop: 'marginvalue', label: '保证金比例(%)' },
+    { prop: 'freezemargin', label: '已付保证金' },
+    { prop: 'status', label: '状态' },
+    { prop: 'createtime', label: '认购时间' },
+    { prop: 'operate', label: '操作', fixed: 'right' },
+])
+
+filterOptons.selectList = [
+    {
+        label: '状态',
+        key: 'status',
+        locked: true,
+        selectedValue: 1,
+        options: [
+            { label: '集采中', value: 1 },
+            { label: '执行中', value: 2 },
+            { label: '已完成', value: 3 }
+        ],
+    },
+]
+
+filterOptons.inputList = [
+    { label: '卖方', keys: ['customername'] },
+    { label: '商品', keys: ['wrstandardname'] },
+]
+
+filterOptons.buttonList = [
+    { lable: '重置', onClick: () => onSearch(true) },
+    { lable: '查询', className: 'el-button--primary', onClick: () => onSearch() }
+]
+
+const onSearch = (clear = false) => {
+    getQueryParams((qs) => {
+        pageIndex.value = 1
+        run(qs)
+    }, clear)
+}
+
+const onRefresh = () => {
+    getQueryParams((qs) => run(qs))
+}
+</script>

+ 84 - 0
src/packages/pc/views/presale/list/components/buy/index.vue

@@ -0,0 +1,84 @@
+<!-- 预售大厅-预售大厅-认购 -->
+<template>
+    <app-drawer title="认购" v-model:show="show" :loading="loading" :refresh="refresh">
+        <el-form ref="formRef" label-width="140px" :model="formData" :rules="formRules">
+            <el-form-item label="商品名称">
+                {{ selectedRow.wrstandardname }}
+            </el-form-item>
+            <el-form-item label="最小采购单位">
+                {{ selectedRow.minbuyqty }}
+            </el-form-item>
+            <el-form-item label="最大采购单位">
+                {{ selectedRow.maxbuyqty }}
+            </el-form-item>
+            <el-form-item label="剩余预售量">
+                {{ selectedRow.presaleqty }}
+            </el-form-item>
+            <el-form-item label="认购数量" prop="OrderQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.OrderQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, reactive, PropType } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { gzPresaleOrder } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZPreSellRsp>,
+        required: true
+    },
+})
+
+const formRef = shallowRef<FormInstance>()
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const formData = reactive<Partial<Proto.GZPresaleOrderReq>>({
+    WRTradeOrderID: props.selectedRow.sellwrtradeorderid, // 仓单贸易委托单ID,必填
+})
+
+const formRules: FormRules = {
+    OrderQty: [{
+        required: true,
+        message: '请输入认购数量'
+    }],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            loading.value = true
+            gzPresaleOrder({
+                data: formData,
+                success: () => {
+                    ElMessage.success('提交成功')
+                    onCancel(true)
+                },
+                fail: (err) => {
+                    ElMessage.error('提交失败:' + err)
+                },
+                complete: () => {
+                    loading.value = false
+                }
+            })
+        }
+    })
+}
+</script>

+ 70 - 0
src/packages/pc/views/presale/list/components/details/index.vue

@@ -0,0 +1,70 @@
+<!-- 预售大厅-预售大厅-详情 -->
+<template>
+    <app-drawer title="详情" :width="960" v-model:show="show" :loading="loading" :refresh="refresh">
+        <app-table-details title="预售信息" :label-width="100" :data="selectedRow" :cell-props="details1" :column="2" />
+        <app-table-details title="钻石参考信息" :label-width="100" :data="selectedRow" :cell-props="details2" :column="2" />
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="showBuy = true">认购</el-button>
+        </template>
+        <component :is="Buy" v-bind="{ selectedRow }" @closed="onBuyClosed" v-if="showBuy" />
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, defineAsyncComponent } from 'vue'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+
+defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZPreSellRsp>,
+        required: true
+    },
+})
+
+// 认购
+const Buy = defineAsyncComponent(() => import('../buy/index.vue'))
+
+const show = shallowRef(true)
+const showBuy = shallowRef(false)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const details1 = [
+    { prop: 'wrstandardname', label: '商品名称:' },
+    { prop: 'createtime', label: '申请日期:' },
+    { prop: 'presaleqty', label: '预售总量:' },
+    { prop: 'unitprice', label: '预售价格:' },
+    { prop: 'minbuyqty', label: '最小采购单位:' },
+    { prop: 'minsuccessqty', label: '最低成团量:' },
+    { prop: 'maxbuyqty', label: '最大采购单位:' },
+    { prop: 'buymarginvalue', label: '采购保证金比例:' },
+    { prop: 'startdate', label: '开始日期:' },
+    { prop: 'enddate', label: '结束日期:' },
+    { prop: 'presalestatus', label: '状态:' },
+    { prop: 'tradeqty', label: '已认购数量:' },
+    { prop: 'performancetemplateid', label: '履约方式:' },
+]
+
+const details2 = [
+    { prop: 'zscolortypestr', label: '颜色:' },
+    { prop: 'sizestr', label: '尺寸:' },
+    { prop: 'zsclaritytypestr', label: '净度:' },
+    { prop: 'yieldrate', label: '成品率:' },
+    { prop: 'qtydesc', label: '数量描述:' },
+    { prop: 'weightdesc', label: '重量描述:' },
+    { prop: 'ysproductionmode', label: '生产方式:' },
+    { prop: 'pictureurls', label: '图片:' },
+    { prop: 'remark', label: '备注:' },
+]
+
+const onBuyClosed = () => {
+    showBuy.value = false
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+</script>

+ 96 - 0
src/packages/pc/views/presale/list/index.vue

@@ -0,0 +1,96 @@
+<!-- 预售大厅 -->
+<template>
+    <app-view>
+        <template #header>
+            <app-filter :options="filterOptons" />
+        </template>
+        <!-- 表格数据 -->
+        <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+            <!-- 最小 / 最大采购单位(克拉) -->
+            <template #buyqty="{ row }">
+                {{ row.minbuyqty }} / {{ row.maxbuyqty }}
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-auth-operation type="dropdown" :menus="['presale_list_details']" :options="{ selectedRow: row }"
+                    @closed="onRefresh" />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onRefresh" />
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryGZPreSell } from '@/services/api/presale'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+import AppAuthOperation from '@pc/components/modules/auth-operation/index.vue'
+
+const { filterOptons, getQueryParams } = useDataFilter<Ermcp.GZPreSellReq>()
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZPreSell, {
+    params: {
+        pagesize: 20,
+        marketid: 63201,
+        presalestatus: 2,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Ermcp.TableColumn[]>([
+    { prop: 'customername', label: '卖方' },
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'presaleqty', label: '预售数量(克拉)' },
+    { prop: 'unitprice', label: '预售单价(元/克拉)', width: 140 },
+    { prop: 'buyqty', label: '最小 / 最大采购单位(克拉)', width: 190 },
+    { prop: 'minsuccessqty', label: '最低成团量(克拉)', width: 140 },
+    { prop: 'buymarginvalue', label: '采购保证金(%)' },
+    { prop: 'startdate', label: '开始日期' },
+    { prop: 'enddate', label: '结束日期' },
+    { prop: 'tradeqty', label: '已认购数量(克拉)', width: 140 },
+    { prop: 'operate', label: '操作', fixed: 'right' },
+])
+
+filterOptons.selectList = [
+    {
+        label: '状态',
+        key: 'presalestatus',
+        locked: true,
+        selectedValue: 2,
+        options: [
+            { label: '未开始', value: 1 },
+            { label: '进行中', value: 2 },
+        ],
+    },
+]
+
+filterOptons.inputList = [
+    { label: '卖方', keys: ['customername'] },
+    { label: '商品', keys: ['wrstandardname'] },
+]
+
+filterOptons.buttonList = [
+    { lable: '重置', onClick: () => onSearch(true) },
+    { lable: '查询', className: 'el-button--primary', onClick: () => onSearch() }
+]
+
+const onSearch = (clear = false) => {
+    getQueryParams((qs) => {
+        pageIndex.value = 1
+        run(qs)
+    }, clear)
+}
+
+const onRefresh = () => {
+    getQueryParams((qs) => run(qs))
+}
+</script>

+ 196 - 0
src/packages/pc/views/presale/mine/components/add/index.vue

@@ -0,0 +1,196 @@
+<!-- 预售大厅-我的预售-预售申请 -->
+<template>
+    <app-drawer class="g-details" title="预售申请" v-model:show="show" :width="960" :loading="loading" :refresh="refresh">
+        <h3 class="g-details__title">预售信息</h3>
+        <el-form ref="formRef" class="el-form--horizontal" label-width="140px" :model="formData" :rules="formRules">
+            <el-form-item label="商品名称" prop="WRStandardName">
+                <el-input placeholder="请输入" v-model="formData.WRStandardName" />
+            </el-form-item>
+            <el-form-item label="履约方式" prop="PerformanceTemplateID">
+                <component :is="PerformanceTemplate" v-model="formData.PerformanceTemplateID" />
+            </el-form-item>
+            <el-form-item label="预售总量" prop="PresaleQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.PresaleQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="预售价格" prop="UnitPrice">
+                <el-input type="number" placeholder="请输入" v-model="formData.UnitPrice">
+                    <template #append>(元/克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="最小采购单位" prop="MinBuyQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.MinBuyQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="最低成团量" prop="MinSuccessQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.MinSuccessQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="最大采购单位" prop="MaxBuyQty">
+                <el-input type="number" placeholder="请输入" v-model="formData.MaxBuyQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="采购保证金比例" prop="BuyMarginValue">
+                <el-input type="number" placeholder="请输入" v-model="formData.BuyMarginValue">
+                    <template #append>%</template>
+                </el-input>
+            </el-form-item>
+            <el-form-item label="预售日期" prop="PreDate">
+                <el-date-picker type="daterange" placeholder="请选择" range-separator="至" start-placeholder="开始"
+                    end-placeholder="结束" v-model="datePickerValue" :disabled-date="disabledDate" />
+            </el-form-item>
+        </el-form>
+        <h3 class="g-details__title">钻石参考信息</h3>
+        <el-form class="el-form--horizontal" label-width="140px" :model="formData" :rules="formRules">
+            <el-form-item label="颜色" prop="ZSColorTypeStr">
+                <el-input placeholder="请输入" v-model="formData.ZSColorTypeStr" />
+            </el-form-item>
+            <el-form-item label="尺寸" prop="SizeStr">
+                <el-input placeholder="请输入" v-model="formData.SizeStr" />
+            </el-form-item>
+            <el-form-item label="净度" prop="ZSClarityTypeStr">
+                <el-input placeholder="请输入" v-model="formData.ZSClarityTypeStr" />
+            </el-form-item>
+            <el-form-item label="成品率" prop="YieldRate">
+                <el-input placeholder="请输入" v-model="formData.YieldRate" />
+            </el-form-item>
+            <el-form-item label="数量描述" prop="QtyDesc">
+                <el-input placeholder="请输入" v-model="formData.QtyDesc" />
+            </el-form-item>
+            <el-form-item label="重量描述" prop="WeightDesc">
+                <el-input placeholder="请输入" v-model="formData.WeightDesc" />
+            </el-form-item>
+            <el-form-item label="生产方式" prop="YSProductionMode">
+                <el-select v-model="formData.YSProductionMode">
+                    <el-option :label="item.label" :value="item.value" v-for="(item, index) in getYSProductionModeList()"
+                        :key="index" />
+                </el-select>
+            </el-form-item>
+            <el-form-item class="el-form-item--row" label="图片" prop="PictureUrls">
+                <app-upload :file-types="['image']" :limit="5" type-message="请选择正确的图片类型" @change="onUploadChange" />
+            </el-form-item>
+            <el-form-item class="el-form-item--row" label="备注" prop="Remark">
+                <el-input type="textarea" v-model="formData.Remark" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, reactive, defineAsyncComponent } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { formatDate } from '@/filters'
+import { getYSProductionModeList, YSZSCategory } from '@/constants/presale'
+import { gzPresaleApply } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppUpload from '@pc/components/base/upload/index.vue'
+
+// 履约模板
+const PerformanceTemplate = defineAsyncComponent(() => import('@pc/components/modules/performance/index.vue'))
+
+const formRef = shallowRef<FormInstance>()
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+const datePickerValue = shallowRef<string[]>([]) // 选中的日期
+
+const formData = reactive<Partial<Proto.GZPresaleApplyReq>>({
+    YSZSCategory: YSZSCategory.Rough,
+    BuyMarginAlgorithm: 1, // 买方保证金方式,必填
+})
+
+const formRules: FormRules = {
+    WRStandardName: [{
+        required: true,
+        message: '请输入商品名称'
+    }],
+    PerformanceTemplateID: [{
+        required: true,
+        message: '请选择履约方式'
+    }],
+    PresaleQty: [{
+        required: true,
+        message: '请输入预售总量'
+    }],
+    UnitPrice: [{
+        required: true,
+        message: '请输入预售价格'
+    }],
+    MinBuyQty: [{
+        required: true,
+        message: '请输入最小采购单位'
+    }],
+    MinSuccessQty: [{
+        required: true,
+        message: '请输入最低成团量'
+    }],
+    MaxBuyQty: [{
+        required: true,
+        message: '请输入最大采购单位'
+    }],
+    BuyMarginValue: [{
+        required: true,
+        message: '请输入采购保证金比例'
+    }],
+    PreDate: [{
+        required: true,
+        validator: (rule, value, callback) => {
+            if (datePickerValue.value && datePickerValue.value.length === 2) {
+                callback()
+            } else {
+                callback(new Error('请选择预售日期'))
+            }
+        }
+    }],
+}
+
+// 只能选择今天开始日期
+const disabledDate = (date: Date) => {
+    return date.getTime() < Date.now() - 24 * 3600 * 1000
+}
+
+const onUploadChange = (files: { filePath: string }[]) => {
+    formData.PictureUrls = files.map((e) => e.filePath).join(',')
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            const [startDate, endDate] = datePickerValue.value
+            formData.StartDate = formatDate(startDate, 'YYYY-MM-DD')
+            formData.EndDate = formatDate(endDate, 'YYYY-MM-DD')
+
+            loading.value = true
+            gzPresaleApply({
+                data: {
+                    ...formData,
+                    BuyMarginValue: (formData.BuyMarginValue ?? 0) / 100
+                },
+                success: () => {
+                    ElMessage.success('提交成功')
+                    onCancel(true)
+                },
+                fail: (err) => {
+                    ElMessage.error('提交失败:' + err)
+                },
+                complete: () => {
+                    loading.value = false
+                }
+            })
+        }
+    })
+}
+</script>

+ 99 - 0
src/packages/pc/views/presale/mine/components/apply/details.vue

@@ -0,0 +1,99 @@
+<!-- 预售大厅-我的预售-我的申请-详情 -->
+<template>
+    <app-drawer title="详情" :width="800" v-model:show="show">
+        <app-table-details title="预售信息" :label-width="140" :data="selectedRow" :cell-props="details1" :column="2">
+            <!-- 采购保证金比例 -->
+            <template #buymarginvalue="{ value }">
+                {{ parsePercent(value) }}
+            </template>
+            <!-- 状态 -->
+            <template #applystatus="{ value }">
+                {{ getInOutApplyStatusName(value) }}
+            </template>
+            <!-- 履约方式 -->
+            <template #performancetemplateid="{ value }">
+                <app-performance-rule :item="getPerformanceTemplateById(value)" />
+            </template>
+        </app-table-details>
+        <app-table-details title="钻石参考信息" :label-width="140" :data="selectedRow" :cell-props="details2" :column="2">
+            <!-- 生产方式 -->
+            <template #ysproductionmode="{ value }">
+                {{ getYSProductionModeName(value) }}
+            </template>
+            <!-- 图片 -->
+            <template #pictureurls>
+                <template v-for="(url, index) in imageUrl" :key="index">
+                    <el-image :src="url" :preview-src-list="imageUrl" fit="cover" />
+                </template>
+            </template>
+        </app-table-details>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, reactive, PropType, onMounted } from 'vue'
+import { getFileUrl, parsePercent } from '@/filters'
+import { getInOutApplyStatusName, getYSProductionModeName } from '@/constants/presale'
+import { performanceStore } from '@/stores'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+import AppPerformanceRule from '@pc/components/modules/performance-rule/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZWrPreSaleApplyRsp>,
+        required: true
+    },
+})
+
+const { getPerformanceTemplateById } = performanceStore.actions
+const show = shallowRef(true)
+const imageUrl = reactive<string[]>([])
+
+const details1 = [
+    { prop: 'wrstandardname', label: '商品名称:' },
+    { prop: 'applytime', label: '申请日期:' },
+    { prop: 'presaleqty', label: '预售总量:' },
+    { prop: 'unitprice', label: '预售价格:' },
+    { prop: 'minbuyqty', label: '最小采购单位:' },
+    { prop: 'minsuccessqty', label: '最低成团量:' },
+    { prop: 'maxbuyqty', label: '最大采购单位:' },
+    { prop: 'buymarginvalue', label: '采购保证金比例:' },
+    { prop: 'startdate', label: '开始日期:' },
+    { prop: 'enddate', label: '结束日期:' },
+    { prop: 'applystatus', label: '状态:' },
+    { prop: 'auditremark', label: '审核备注:' },
+    { prop: 'performancetemplateid', label: '履约方式:', entireRow: true },
+]
+
+const details2 = [
+    { prop: 'zscolortypestr', label: '颜色:' },
+    { prop: 'sizestr', label: '尺寸:' },
+    { prop: 'zsclaritytypestr', label: '净度:' },
+    { prop: 'yieldrate', label: '成品率:' },
+    { prop: 'qtydesc', label: '数量描述:' },
+    { prop: 'weightdesc', label: '重量描述:' },
+    { prop: 'ysproductionmode', label: '生产方式:' },
+    { prop: 'pictureurls', label: '图片:', entireRow: true },
+    { prop: 'remark', label: '备注:', entireRow: true },
+]
+
+onMounted(() => {
+    const images = props.selectedRow.pictureurls.split(',')
+    images.forEach((url) => {
+        imageUrl.push(getFileUrl(url))
+    })
+})
+</script>
+
+<style lang="less" scoped>
+.el-image {
+    width: 64px;
+    height: 64px;
+    border: 1px solid #ccc;
+
+    +.el-image {
+        margin-left: 10px;
+    }
+}
+</style>

+ 63 - 0
src/packages/pc/views/presale/mine/components/apply/index.vue

@@ -0,0 +1,63 @@
+<!-- 预售大厅-我的预售-我的申请 -->
+<template>
+    <app-drawer title="我的申请" :width="960" v-model:show="show">
+        <app-table :data="dataList" :columns="columns" :show-toolbar="false" :loading="loading" border>
+            <!-- 状态 -->
+            <template #applystatus="{ value }">
+                {{ getInOutApplyStatusName(value) }}
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <el-button size="small" @click="openDetails(row)">查看</el-button>
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex" @change="run" />
+            </template>
+        </app-table>
+        <component :is="Details" v-bind="{ selectedRow }" @closed="showDetails = false" v-if="showDetails" />
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { getInOutApplyStatusName } from '@/constants/presale'
+import { useRequest } from '@/hooks/request'
+import { queryGZWrPreSaleApply } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+
+// 申请详情
+const Details = defineAsyncComponent(() => import('./details.vue'))
+
+const show = shallowRef(true)
+const showDetails = shallowRef(false)
+const selectedRow = shallowRef<Ermcp.GZWrPreSaleApplyRsp>() // 当前选择的申请明细
+
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZWrPreSaleApply, {
+    params: {
+        pagesize: 10,
+        marketid: 63201,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const columns: Ermcp.TableColumn[] = [
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'presaleqty', label: '预售数量(克拉)' },
+    { prop: 'unitprice', label: '预售单价(元/克拉)', width: 140 },
+    { prop: 'startdate', label: '开始日期' },
+    { prop: 'enddate', label: '结束日期' },
+    { prop: 'applystatus', label: '状态' },
+    { prop: 'applytime', label: '申请时间' },
+    { prop: 'operate', label: '详情', fixed: 'right' },
+]
+
+const openDetails = (item: Ermcp.GZWrPreSaleApplyRsp) => {
+    selectedRow.value = item
+    showDetails.value = true
+}
+</script>

+ 78 - 0
src/packages/pc/views/presale/mine/components/details/index.vue

@@ -0,0 +1,78 @@
+<!-- 预售大厅-我的预售-详情 -->
+<template>
+    <app-drawer class="g-details" title="详情" :width="960" v-model:show="show">
+        <app-table-details title="预售信息" :label-width="100" :data="selectedRow" :cell-props="details1" :column="2" />
+        <app-table-details title="钻石参考信息" :label-width="100" :data="selectedRow" :cell-props="details2" :column="2" />
+        <app-table :data="dataList" :columns="columns" :show-toolbar="false" :loading="loading" border>
+            <template #header>
+                <h3 class="g-details__title">认购信息</h3>
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex" @change="run" />
+            </template>
+        </app-table>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useRequest } from '@/hooks/request'
+import { queryGZMyPresell } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZPreSellRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZMyPresell, {
+    params: {
+        pagesize: 10,
+        presaleapplyid: props.selectedRow.presaleapplyid,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const details1 = [
+    { prop: 'wrstandardname', label: '商品名称:' },
+    { prop: 'createtime', label: '申请日期:' },
+    { prop: 'presaleqty', label: '预售总量:' },
+    { prop: 'unitprice', label: '预售价格:' },
+    { prop: 'minbuyqty', label: '最小采购单位:' },
+    { prop: 'minsuccessqty', label: '最低成团量:' },
+    { prop: 'maxbuyqty', label: '最大采购单位:' },
+    { prop: 'buymarginvalue', label: '采购保证金比例:' },
+    { prop: 'startdate', label: '开始日期:' },
+    { prop: 'enddate', label: '结束日期:' },
+    { prop: 'presalestatus', label: '状态:' },
+    { prop: 'tradeqty', label: '已认购数量:' },
+    { prop: 'performancetemplateid', label: '履约方式:' },
+]
+
+const details2 = [
+    { prop: 'zscolortypestr', label: '颜色:' },
+    { prop: 'sizestr', label: '尺寸:' },
+    { prop: 'zsclaritytypestr', label: '净度:' },
+    { prop: 'yieldrate', label: '成品率:' },
+    { prop: 'qtydesc', label: '数量描述:' },
+    { prop: 'weightdesc', label: '重量描述:' },
+    { prop: 'ysproductionmode', label: '生产方式:' },
+    { prop: 'pictureurls', label: '图片:' },
+    { prop: 'remark', label: '备注:' },
+]
+
+const columns: Ermcp.TableColumn[] = [
+    { prop: 'customername', label: '认购方' },
+    { prop: 'orderqty', label: '认购数量(ct)' },
+    { prop: 'ordertime', label: '认购时间' },
+]
+</script>

+ 95 - 0
src/packages/pc/views/presale/mine/index.vue

@@ -0,0 +1,95 @@
+<!-- 预售大厅-我的预售 -->
+<template>
+    <app-view>
+        <template #header>
+            <app-filter :options="filterOptons" />
+        </template>
+        <!-- 表格数据 -->
+        <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+            <template #header>
+                <app-auth-operation :menus="['presale_mine_add', 'presale_mine_apply']" @closed="onRefresh" />
+            </template>
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-auth-operation type="dropdown" :menus="['presale_mine_details']" :options="{ selectedRow: row }"
+                    @closed="onRefresh" />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onRefresh" />
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryGZPreSell } from '@/services/api/presale'
+import { loginStore } from '@/stores'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+import AppAuthOperation from '@pc/components/modules/auth-operation/index.vue'
+
+const { userId } = loginStore.$mapGetters()
+const { filterOptons, getQueryParams } = useDataFilter<Ermcp.GZPreSellReq>()
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZPreSell, {
+    params: {
+        pagesize: 20,
+        marketid: 63201,
+        presalestatus: 2,
+        selluserid: userId.value
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Ermcp.TableColumn[]>([
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'presaleqty', label: '预售数量(克拉)' },
+    { prop: 'unitprice', label: '预售单价(元/克拉)', width: 140 },
+    { prop: 'startdate', label: '开始日期' },
+    { prop: 'enddate', label: '结束日期' },
+    { prop: 'tradeqty', label: '已认购数量(克拉)', width: 140 },
+    { prop: 'createtime', label: '申请时间' },
+    { prop: 'operate', label: '操作', fixed: 'right' },
+])
+
+filterOptons.selectList = [
+    {
+        label: '状态',
+        key: 'presalestatus',
+        locked: true,
+        selectedValue: 2,
+        options: [
+            { label: '未开始', value: 1 },
+            { label: '进行中', value: 2 },
+            { label: '已结束', value: 3 }
+        ],
+    },
+]
+
+filterOptons.inputList = [
+    { label: '商品', keys: ['wrstandardname'] },
+]
+
+filterOptons.buttonList = [
+    { lable: '重置', onClick: () => onSearch(true) },
+    { lable: '查询', className: 'el-button--primary', onClick: () => onSearch() }
+]
+
+const onSearch = (clear = false) => {
+    getQueryParams((qs) => {
+        pageIndex.value = 1
+        run(qs)
+    }, clear)
+}
+
+const onRefresh = () => {
+    getQueryParams((qs) => run(qs))
+}
+</script>

+ 46 - 0
src/packages/pc/views/presale/partake/components/details/index.vue

@@ -0,0 +1,46 @@
+<!-- 预售大厅-我参与的预售-详情 -->
+<template>
+    <app-drawer title="详情" :width="960" v-model:show="show">
+        <app-table-details title="预售信息" :label-width="100" :data="selectedRow" :cell-props="details1" :column="2" />
+        <app-table-details title="钻石参考信息" :label-width="100" :data="selectedRow" :cell-props="details2" :column="2" />
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+
+defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZMyTradingPreSellRsp>,
+        required: true
+    },
+})
+
+const show = shallowRef(true)
+
+const details1 = [
+    { prop: 'wrstandardname', label: '商品名称:' },
+    { prop: 'customername', label: '发售方:' },
+    { prop: 'orderqty', label: '认购数量:' },
+    { prop: 'tradeprice', label: '预售价格:' },
+    { prop: 'tradeamount', label: '认购货款:' },
+    { prop: 'marginvalue', label: '保证金比例:' },
+    { prop: 'freezemargin', label: '保证金:' },
+    { prop: 'ordertime', label: '认购时间:' },
+    { prop: 'performancetemplateid', label: '履约方式:' },
+]
+
+const details2 = [
+    { prop: 'zscolortypestr', label: '颜色:' },
+    { prop: 'sizestr', label: '尺寸:' },
+    { prop: 'zsclaritytypestr', label: '净度:' },
+    { prop: 'yieldrate', label: '成品率:' },
+    { prop: 'qtydesc', label: '数量描述:' },
+    { prop: 'weightdesc', label: '重量描述:' },
+    { prop: 'ysproductionmode', label: '生产方式:' },
+    { prop: 'pictureurls', label: '图片:' },
+    { prop: 'remark', label: '备注:' },
+]
+</script>

+ 92 - 0
src/packages/pc/views/presale/partake/index.vue

@@ -0,0 +1,92 @@
+<!-- 预售大厅-我参与的预售 -->
+<template>
+    <app-view>
+        <template #header>
+            <app-filter :options="filterOptons" />
+        </template>
+        <!-- 表格数据 -->
+        <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading">
+            <!-- 操作 -->
+            <template #operate="{ row }">
+                <app-auth-operation type="dropdown" :menus="['presale_partake_details']" :options="{ selectedRow: row }"
+                    @closed="onRefresh" />
+            </template>
+            <template #footer>
+                <app-pagination :total="total" v-model:page-size="pageSize" v-model:page-index="pageIndex"
+                    @change="onRefresh" />
+            </template>
+        </app-table>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useDataFilter } from '@/hooks/datatable'
+import { useRequest } from '@/hooks/request'
+import { queryGZMyTradingPreSell } from '@/services/api/presale'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppPagination from '@pc/components/base/pagination/index.vue'
+import AppFilter from '@pc/components/base/table-filter/index.vue'
+import AppAuthOperation from '@pc/components/modules/auth-operation/index.vue'
+
+const { filterOptons, getQueryParams } = useDataFilter<Ermcp.GZMyTradingPreSellReq>()
+const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZMyTradingPreSell, {
+    params: {
+        pagesize: 20,
+        marketid: 63201,
+        status: 1,
+    },
+    onError: (err) => {
+        ElMessage.error(err)
+    }
+})
+
+const tableColumns = shallowRef<Ermcp.TableColumn[]>([
+    { prop: 'customername', label: '卖方' },
+    { prop: 'wrstandardname', label: '商品' },
+    { prop: 'orderqty', label: '认购数量(克拉)' },
+    { prop: 'tradeprice', label: '认购价格(元/克拉)', width: 140 },
+    { prop: 'tradeamount', label: '货款' },
+    { prop: 'marginvalue', label: '保证金比例(%)' },
+    { prop: 'freezemargin', label: '已付保证金' },
+    { prop: 'status', label: '状态' },
+    { prop: 'createtime', label: '认购时间' },
+    { prop: 'operate', label: '操作', fixed: 'right' },
+])
+
+filterOptons.selectList = [
+    {
+        label: '状态',
+        key: 'status',
+        locked: true,
+        selectedValue: 1,
+        options: [
+            { label: '预售中', value: 1 },
+            { label: '执行中', value: 2 },
+            { label: '已完成', value: 3 }
+        ],
+    },
+]
+
+filterOptons.inputList = [
+    { label: '发售方', keys: ['customername'] },
+    { label: '商品', keys: ['wrstandardname'] },
+]
+
+filterOptons.buttonList = [
+    { lable: '重置', onClick: () => onSearch(true) },
+    { lable: '查询', className: 'el-button--primary', onClick: () => onSearch() }
+]
+
+const onSearch = (clear = false) => {
+    getQueryParams((qs) => {
+        pageIndex.value = 1
+        run(qs)
+    }, clear)
+}
+
+const onRefresh = () => {
+    getQueryParams((qs) => run(qs))
+}
+</script>

+ 2 - 4
src/packages/pc/views/search/jewelry/components/compare/index.less

@@ -1,6 +1,5 @@
 .search-compare {
-    border: solid #eee;
-    border-width: 0 0 1px 1px;
+    border-collapse: collapse;
 
     tr {
         &:hover {
@@ -10,8 +9,7 @@
 
     th,
     td {
-        border: solid #eee;
-        border-width: 1px 1px 0 0;
+        border: 1px solid #eee;
         padding: 8px 20px;
     }
 

+ 4 - 5
src/packages/pc/views/search/jewelry/index.vue

@@ -25,8 +25,7 @@
                     <app-multiple :data-list="enums.polishTypeList" v-model="formData.zspolishtype" checkbox />
                 </el-form-item>
                 <el-form-item label="荧光">
-                    <app-multiple :data-list="enums.fluorescenceTypeList" v-model="formData.zsfluorescencetype"
-                        checkbox />
+                    <app-multiple :data-list="enums.fluorescenceTypeList" v-model="formData.zsfluorescencetype" checkbox />
                 </el-form-item>
                 <el-form-item>
                     <el-button type="primary" :loading="loading" @click="onSearch">搜索</el-button>
@@ -39,7 +38,7 @@
                 <template v-for="(item, index) in dataList" :key="index">
                     <li class="list-item">
                         <div class="list-item__header" @click="openDetails(item)">
-                            <app-image :width="200" :height="200" :src="getImageUrl(item.imagepath)" />
+                            <app-image :width="200" :height="200" :src="getFileUrl(item.imagepath)" />
                         </div>
                         <div class="list-item__body" @click="openDetails(item)">
                             <div class="block block--price">
@@ -67,7 +66,7 @@
                         <span>{{ index + 1 }}</span>
                     </div>
                     <div class="list-item__image">
-                        <app-image :width="48" :height="48" :src="getImageUrl(item.imagepath)" />
+                        <app-image :width="48" :height="48" :src="getFileUrl(item.imagepath)" />
                     </div>
                     <div class="list-item__info">
                         <span>{{ item.zsstyletypedisplay }}</span>
@@ -89,7 +88,7 @@
 import { ref, defineAsyncComponent } from 'vue'
 import { ElMessage } from 'element-plus'
 import type { FormInstance, FormRules } from 'element-plus'
-import { getImageUrl, formatDecimal } from '@/filters'
+import { getFileUrl, formatDecimal } from '@/filters'
 import { useSearch } from '@/business/search'
 import { Category } from '@/constants/diamond'
 import { useComponent } from '@/hooks/component'

+ 4 - 6
src/packages/pc/views/warehousing/goods/components/details/index.vue

@@ -5,7 +5,7 @@
             <div class="goods-details__wrapper">
                 <div class="goods-details__aside">
                     <div class="sku-gallery">
-                        <app-image :width="300" :height="300" :src="getImageUrl(details.imagepath)" />
+                        <app-image :width="300" :height="300" :src="getFileUrl(details.imagepath)" />
                     </div>
                     <div class="sku-address">
                         <ul>
@@ -21,7 +21,7 @@
                                 <span>仓库地址</span>
                                 <span>{{
                                     [details.provincename, details.cityname, details.districtname,
-                                        details.address].join(' ')
+                                    details.address].join(' ')
                                 }}</span>
                             </li>
                         </ul>
@@ -51,9 +51,7 @@
                             </li>
                             <li>
                                 <span>市场价:</span>
-                                <span>{{
-                                    details.zscurrencytypedisplayunit + formatDecimal(details.marketprice)
-                                }}</span>
+                                <span>{{ details.zscurrencytypedisplayunit + formatDecimal(details.marketprice) }}</span>
                             </li>
                         </ul>
                     </div>
@@ -135,7 +133,7 @@ export default defineComponent({
 
 <script lang="ts" setup>
 import { computed, PropType, defineAsyncComponent } from 'vue'
-import { getImageUrl, formatDecimal, handleNoneValue } from '@/filters'
+import { getFileUrl, formatDecimal, handleNoneValue } from '@/filters'
 import { CurrencyType } from '@/constants/diamond'
 import { loginStore, favoriteStore, exrateStore, performanceStore } from '@/stores'
 import { useComponent } from '@/hooks/component'

+ 19 - 6
src/services/api/account/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 
@@ -27,33 +27,46 @@ export function modifyPassword(params: TradeParams<Proto.ModifyPwdReq, Proto.Mod
  * 查询用户菜单
  */
 export function queryAccountMenu() {
-    return httpRequest<Ermcp.UserRoutes[]>('/account/menu', 'get');
+    return http.commonRequest<Ermcp.UserRoutes[]>({
+        url: '/account/menu',
+    })
 }
 
 /**
  * 查询登录ID
  */
 export function queryLoginId(params: { username: string }) {
-    return httpRequest<string>('/User/GetLoginID', 'get', params);
+    return http.commonRequest<string>({
+        url: '/User/GetLoginID',
+        params,
+    })
 }
 
 /**
  * 查询登录账户配置信息
  */
 export function queryLoginData(params: Ermcp.LoginQueryReq) {
-    return httpRequest<Ermcp.LoginQueryRsp>('/User/LoginQuery', 'get', params);
+    return http.commonRequest<Ermcp.LoginQueryRsp>({
+        url: '/User/LoginQuery',
+        params,
+    })
 }
 
 /**
  * 查询资金账户信息
  */
 export function queryTaAccounts(params: Ermcp.TaAccountsReq) {
-    return httpRequest<Ermcp.TaAccountsRsp[]>('/TaAccount/GetTaAccounts', 'get', params);
+    return http.commonRequest<Ermcp.TaAccountsRsp[]>({
+        url: '/TaAccount/GetTaAccounts',
+        params,
+    })
 }
 
 /**
  * 查询账户角色
  */
 export function queryAccountRole() {
-    return httpRequest<Ermcp.UserRole[]>('/account/role', 'get');
+    return http.commonRequest<Ermcp.UserRole[]>({
+        url: '/account/role',
+    })
 }

+ 15 - 5
src/services/api/bank/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 
@@ -34,26 +34,36 @@ export function t2bBankDeposit(params: TradeParams<Partial<Proto.t2bBankDepositR
  * 查询托管银行
  */
 export function queryCusBankSignBank() {
-    return httpRequest<Ermcp.CusBankSignBankRsp[]>('/Qhj/QueryCusBankSignBank', 'get');
+    return http.commonRequest<Ermcp.CusBankSignBankRsp[]>({
+        url: '/Qhj/QueryCusBankSignBank',
+    })
 }
 
 /**
  * 查询开户行
  */
 export function queryBankInfo() {
-    return httpRequest<Ermcp.BankInfoRsp[]>('/Qhj/QueryBankInfo', 'get');
+    return http.commonRequest<Ermcp.BankInfoRsp[]>({
+        url: '/Qhj/QueryBankInfo',
+    })
 }
 
 /**
  * 查询签约银行信息(提现账户管理)
  */
 export function queryBankAccountSign(params: Ermcp.BankAccountSignReq) {
-    return httpRequest<Ermcp.BankAccountSignRsp[]>('/Qhj/QueryBankAccountSign', 'get', params);
+    return http.commonRequest<Ermcp.BankAccountSignRsp[]>({
+        url: '/Qhj/QueryBankAccountSign',
+        params,
+    })
 }
 
 /**
  * 查询充值提现
  */
 export function queryAccountInOutApply(params: Ermcp.AccountInOutApplyReq) {
-    return httpRequest<Ermcp.AccountOutInApplyRsp[]>('/Qhj/QueryAccountInOutApply', 'get', params);
+    return http.commonRequest<Ermcp.AccountOutInApplyRsp[]>({
+        url: '/Qhj/QueryAccountInOutApply',
+        params,
+    })
 }

+ 32 - 9
src/services/api/bonded/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 
@@ -6,56 +6,79 @@ import { TradeParams } from '@/services/socket/trade/interface'
  * 获取保税商品表
  */
 export function queryGZBSCGoods() {
-    return httpRequest<Ermcp.GZBSCGoodsRsp[]>('/Guangzuan/GetGZBSCGoods', 'get');
+    return http.commonRequest<Ermcp.GZBSCGoodsRsp[]>({
+        url: '/Guangzuan/GetGZBSCGoods',
+    })
 }
 
 /**
  * 保税仓出入库申请表查询
  */
 export function queryGzbscinOutOrder(params: Ermcp.GzbscinOutOrderReq) {
-    return httpRequest<Ermcp.GzbscinOutOrderRsp[]>('/Guangzuan/QueryGzbscinOutOrder', 'get', params);
+    return http.commonRequest<Ermcp.GzbscinOutOrderRsp[]>({
+        url: '/Guangzuan/QueryGzbscinOutOrder',
+        params,
+    })
 }
 
 /**
  * 保税仓出库申请明细附表查询
  */
 export function queryBScinOutOrderDetail(params: Ermcp.BScinOutOrderDetailReq) {
-    return httpRequest<Ermcp.BScinOutOrderDetailRsp[]>('/Guangzuan/QueryBScinOutOrderDetail', 'get', params);
+    return http.commonRequest<Ermcp.BScinOutOrderDetailRsp[]>({
+        url: '/Guangzuan/QueryBScinOutOrderDetail',
+        params,
+    })
 }
 
 /**
  * 保税商品报关头寸表查询
  */
 export function queryGzbscPosition(params: Ermcp.GzbscPositionReq) {
-    return httpRequest<Ermcp.GzbscPositionRsp[]>('/Guangzuan/QueryGzbscPosition', 'get', params);
+    return http.commonRequest<Ermcp.GzbscPositionRsp[]>({
+        url: '/Guangzuan/QueryGzbscPosition',
+        params,
+    })
 }
 
 /**
  * 保税仓出库申请明细附表查询
  */
 export function queryBScOutOrderDetailatt(params: Ermcp.BScOutOrderDetailattReq) {
-    return httpRequest<Ermcp.BScOutOrderDetailattRsp[]>('/Guangzuan/QueryBScOutOrderDetailatt', 'get', params);
+    return http.commonRequest<Ermcp.BScOutOrderDetailattRsp[]>({
+        url: '/Guangzuan/QueryBScOutOrderDetailatt',
+        params,
+    })
 }
 
 /**
  * 保税仓用户月付款通知书表查询(计费管理)
  */
 export function queryGzbscusermonthpay(params: Ermcp.GzbscusermonthpayReq) {
-    return httpRequest<Ermcp.GzbscusermonthpayRsp[]>('/Guangzuan/QueryGzbscusermonthpay', 'get', params);
+    return http.commonRequest<Ermcp.GzbscusermonthpayRsp[]>({
+        url: '/Guangzuan/QueryGzbscusermonthpay',
+        params,
+    })
 }
 
 /**
  * 保税仓月电费登记表查询
  */
 export function queryGzbscuserpowerfee(params: Ermcp.GzbscuserpowerfeeReq) {
-    return httpRequest<Ermcp.GzbscuserpowerfeeRsp[]>('/Guangzuan/QueryGzbscuserpowerfee', 'get', params);
+    return http.commonRequest<Ermcp.GzbscuserpowerfeeRsp[]>({
+        url: '/Guangzuan/QueryGzbscuserpowerfee',
+        params,
+    })
 }
 
 /**
  * 保税仓本月进口明细/本月出境明细/本月转厂明细查询
  */
 export function queryBscinoutorder(params: Ermcp.BscinoutorderReq) {
-    return httpRequest<Ermcp.BscinoutorderRsp[]>('/Guangzuan/QueryBscinoutorder', 'get', params);
+    return http.commonRequest<Ermcp.BscinoutorderRsp[]>({
+        url: '/Guangzuan/QueryBscinoutorder',
+        params,
+    })
 }
 
 /**

+ 70 - 21
src/services/api/common/index.ts

@@ -1,113 +1,162 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 
 /**
  * 查询市场运行信息
  */
 export function queryMarketRun(params: Ermcp.MarketRunReq) {
-    return httpRequest<Ermcp.MarketRunRsp[]>('/Market/QueryMarketRun', 'get', params);
+    return http.commonRequest<Ermcp.MarketRunRsp[]>({
+        url: '/Market/QueryMarketRun',
+        params,
+    })
 }
 
 /**
  * 首页统计数据
  */
 export function homeData(params: Ermcp.HomeDataReq) {
-    return httpRequest<Ermcp.HomeDataRsp>('/Guangzuan/HomeData', 'get', params);
+    return http.commonRequest<Ermcp.HomeDataRsp>({
+        url: '/Guangzuan/HomeData',
+        params,
+    })
 }
 
 /**
  * 获取服务器时间
  */
 export function getServerTime() {
-    return httpRequest<string>('/Common/GetServerTime', 'get');
+    return http.commonRequest<string>({
+        url: '/Common/GetServerTime',
+    })
 }
 
 /**
  * 查询交易端列表头信息
  */
 export function queryTableDefine(params: Ermcp.TableDefineReq) {
-    return httpRequest<Ermcp.TableDefineRsp[]>('/Common/QueryTableDefine', 'get', params);
+    return http.commonRequest<Ermcp.TableDefineRsp[]>({
+        url: '/Common/QueryTableDefine',
+        params,
+    })
 }
 
 /**
  * 查询所有枚举信息
  */
 export function queryAllEnums(params?: Ermcp.EnumReq) {
-    return httpRequest<Ermcp.EnumRsp[]>('/Common/GetAllEnums', 'get', params);
+    return http.commonRequest<Ermcp.EnumRsp[]>({
+        url: '/Common/GetAllEnums',
+        params,
+    })
 }
 
 /**
  * 获取菜单表数据
  */
 export function queryNewFuncmenu(params: Ermcp.NewFuncmenuReq) {
-    return httpRequest<Ermcp.NewFuncmenuRsp[]>('/Common/FindNewFuncmenu', 'get', params);
+    return http.commonRequest<Ermcp.NewFuncmenuRsp[]>({
+        url: '/Common/FindNewFuncmenu',
+        params,
+    })
 }
 
 /**
  * 插入菜单表数据
  */
-export function insertNewFuncmenu(params: Partial<Ermcp.NewFuncmenuRsp>) {
-    return httpRequest('/Common/InsertNewFuncmenu', 'post', params);
+export function insertNewFuncmenu(data: Partial<Ermcp.NewFuncmenuRsp>) {
+    return http.commonRequest({
+        method: 'post',
+        url: '/Common/InsertNewFuncmenu',
+        data,
+    })
 }
 
 /**
  * 更新菜单表数据
  */
-export function updateNewFuncmenu(params: Partial<Ermcp.NewFuncmenuRsp>) {
-    return httpRequest('/Common/UpdateNewFuncmenu', 'put', params);
+export function updateNewFuncmenu(data: Partial<Ermcp.NewFuncmenuRsp>) {
+    return http.commonRequest({
+        method: 'put',
+        url: '/Common/UpdateNewFuncmenu',
+        data,
+    })
 }
 
 /**
  * 删除菜单表数据
  */
-export function deleteNewFuncmenu(params: Partial<Ermcp.NewFuncmenuRsp>) {
-    return httpRequest('/Common/DeleteNewFuncmenu', 'delete', params);
+export function deleteNewFuncmenu(data: Partial<Ermcp.NewFuncmenuRsp>) {
+    return http.commonRequest({
+        method: 'delete',
+        url: '/Common/DeleteNewFuncmenu',
+        data,
+    })
 }
 
 /**
  * 查询汇率信息
  */
 export function queryRates(params?: Ermcp.RatesReq) {
-    return httpRequest<Ermcp.RatesRsp[]>('/Common/QueryRates', 'get', params);
+    return http.commonRequest<Ermcp.RatesRsp[]>({
+        url: '/Common/QueryRates',
+        params,
+    })
 }
 
 /**
  * 通知公告系统消息查询
  */
 export function queryNotice(params: Ermcp.NoticeReq) {
-    return httpRequest<Ermcp.NoticeRsp[]>('/Common/QueryNotice', 'get', params);
+    return http.commonRequest<Ermcp.NoticeRsp[]>({
+        url: '/Common/QueryNotice',
+        params,
+    })
 }
 
 /**
  * 通知公告设置已读
  */
-export function postNoticeReaded(params: Ermcp.NoticeReadedReq) {
-    return httpRequest('/Common/NoticeReaded', 'post', params);
+export function postNoticeReaded(data: Ermcp.NoticeReadedReq) {
+    return http.commonRequest({
+        method: 'post',
+        url: '/Common/NoticeReaded',
+        data,
+    })
 }
 
 /**
  * 获取数据库错误信息
  */
 export function queryErrorInfos(params?: Ermcp.ErrorInfosReq) {
-    return httpRequest<Ermcp.ErrorInfosRsp[]>('/Common/QueryErrorInfos', 'get', params);
+    return http.commonRequest<Ermcp.ErrorInfosRsp[]>({
+        url: '/Common/QueryErrorInfos',
+        params,
+    })
 }
 
 /**
  * 钻石价格计算器
  */
 export function priceCalc(params: Partial<Ermcp.PriceCalcReq>) {
-    return httpRequest<Ermcp.PriceCalcRsp[]>('/Guangzuan/PriceCalc', 'get', params);
+    return http.commonRequest<Ermcp.PriceCalcRsp[]>({
+        url: '/Guangzuan/PriceCalc',
+        params,
+    })
 }
 
 /**
  * Rapaport最新报价表(广钻)
  */
 export function gzCertAddressConfig() {
-    return httpRequest<Ermcp.GzCertAddressConfigRsp[]>('/Guangzuan/GzCertAddressConfig', 'get');
+    return http.commonRequest<Ermcp.GzCertAddressConfigRsp[]>({
+        url: '/Guangzuan/GzCertAddressConfig',
+    })
 }
 
 /**
  * 钻石证书地址参数
  */
 export function gzCertAddressParam() {
-    return httpRequest<Ermcp.GzCertAddressParamRsp[]>('/Guangzuan/GzCertAddressParam', 'get');
+    return http.commonRequest<Ermcp.GzCertAddressParamRsp[]>({
+        url: '/Guangzuan/GzCertAddressParam',
+    })
 }

+ 33 - 9
src/services/api/customs/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 
@@ -6,56 +6,80 @@ import { TradeParams } from '@/services/socket/trade/interface'
  * 查询出境检测单据
  */
 export function queryGZCJJCOrder(params: Ermcp.GZCJJCOrderReq) {
-    return httpRequest<Ermcp.GZCJJCOrderRsp[]>('/Guangzuan/QueryGZCJJCOrder', 'get', params);
+    return http.commonRequest<Ermcp.GZCJJCOrderRsp[]>({
+        url: '/Guangzuan/QueryGZCJJCOrder',
+        params,
+    })
 }
 
 /**
  * 查询出境检测单据明细(批次信息)
  */
 export function queryGZCJJCOrderDetail(params: Ermcp.GZCJJCOrderDetailReq) {
-    return httpRequest<Ermcp.GZCJJCOrderDetailRsp[]>('/Guangzuan/QueryGZCJJCOrderDetail', 'get', params);
+    return http.commonRequest<Ermcp.GZCJJCOrderDetailRsp[]>({
+        url: '/Guangzuan/QueryGZCJJCOrderDetail',
+        params,
+    })
 }
 
 /**
  * 查询出境检测单据操作
  */
 export function queryGzcjjcorderoperate(params: Ermcp.GzcjjcorderoperateReq) {
-    return httpRequest<Ermcp.GzcjjcorderoperateRsp[]>('/Guangzuan/QueryGzcjjcorderoperate', 'get', params);
+    return http.commonRequest<Ermcp.GzcjjcorderoperateRsp[]>({
+        url: '/Guangzuan/QueryGzcjjcorderoperate',
+        params,
+    })
 }
 
 /**
  * 查询保税服务单据
  */
 export function queryGZBSFWOrder(params: Ermcp.GZBSFWOrderReq) {
-    return httpRequest<Ermcp.GZBSFWOrderRsp[]>('/Guangzuan/QueryGZBSFWOrder', 'get', params);
+    return http.commonRequest<Ermcp.GZBSFWOrderRsp[]>({
+        url: '/Guangzuan/QueryGZBSFWOrder',
+        params,
+    })
 }
 
 /**
  * 保税服务单据操作信息
  */
 export function gzBSFWOrderOperate(params: Ermcp.GZBSFWOrderOperateReq) {
-    return httpRequest<Ermcp.GZBSFWOrderOperateRsp[]>('/Guangzuan/GZBSFWOrderOperate', 'get', params);
+    return http.commonRequest<Ermcp.GZBSFWOrderOperateRsp[]>({
+        url: '/Guangzuan/GZBSFWOrderOperate',
+        params,
+    })
 }
 
 /**
  * 查询保税服务单据明细
  */
 export function queryGZBSFWOrderDetail(params: Ermcp.GZBSFWOrderDetailReq) {
-    return httpRequest<Ermcp.GZBSFWOrderDetailRsp[]>('/Guangzuan/QueryGZBSFWOrderDetail', 'get', params);
+    return http.commonRequest<Ermcp.GZBSFWOrderDetailRsp[]>({
+        url: '/Guangzuan/QueryGZBSFWOrderDetail',
+        params,
+    })
 }
 
 /**
  * 出境保税单据文件
  */
 export function queryGZCJBSOrderFile(params: Ermcp.GZCJBSOrderFileReq) {
-    return httpRequest<Ermcp.GZCJBSOrderFileRsp[]>('/Guangzuan/QueryGZCJBSOrderFile', 'get', params);
+    return http.commonRequest<Ermcp.GZCJBSOrderFileRsp[]>({
+        url: '/Guangzuan/QueryGZCJBSOrderFile',
+        params,
+    })
 }
 
 /**
  * 查询保税服务单据操作
  */
 export function queryFworderoperate(params: Ermcp.FworderoperateReq) {
-    return httpRequest<Ermcp.FworderoperateRsp[]>('/Guangzuan/QueryFworderoperate', 'get', params);
+    return http.commonRequest<Ermcp.FworderoperateRsp[]>({
+        url: '/Guangzuan/QueryFworderoperate',
+        params,
+    })
 }
 
 /**

+ 5 - 2
src/services/api/favorite/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 import { Market } from '@/constants/market'
@@ -7,7 +7,10 @@ import { Market } from '@/constants/market'
  * 查询我的收藏
  */
 export function queryMyFavorite(params: Ermcp.MyFavoriteReq) {
-    return httpRequest<Ermcp.MyFavoriteRsp[]>('/Guangzuan/QueryMyFavorite', 'get', params);
+    return http.commonRequest<Ermcp.MyFavoriteRsp[]>({
+        url: '/Guangzuan/QueryMyFavorite',
+        params,
+    })
 }
 
 /**

+ 12 - 4
src/services/api/goods/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 import { Market } from '@/constants/market'
@@ -7,21 +7,29 @@ import { Market } from '@/constants/market'
  * 查询商品列表
  */
 export function queryGoodsList() {
-    return httpRequest<Ermcp.GoodsRsp[]>('/goods', 'get');
+    return http.commonRequest<Ermcp.GoodsRsp[]>({
+        url: '/goods',
+    })
 }
 
 /**
  * 查询钻石列表
  */
 export function queryDiamondList(params: Ermcp.MyWRPositionReq) {
-    return httpRequest<Ermcp.MyWRPositionRsp[]>('/Guangzuan/QueryMyWRPosition', 'get', params);
+    return http.commonRequest<Ermcp.MyWRPositionRsp[]>({
+        url: '/Guangzuan/QueryMyWRPosition',
+        params,
+    })
 }
 
 /**
  * 获取钻石详情
  */
 export function queryDiamondDetails(params: Ermcp.DiamondDetailsReq) {
-    return httpRequest<Ermcp.DiamondDetailsRsp>('/Guangzuan/GetGoods', 'get', params);
+    return http.commonRequest<Ermcp.DiamondDetailsRsp>({
+        url: '/Guangzuan/GetGoods',
+        params,
+    })
 }
 
 /**

+ 16 - 5
src/services/api/performance/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 
@@ -34,26 +34,37 @@ export function performanceModifyContact(params: TradeParams<Proto.PerformanceMo
  * 查询我的履约
  */
 export function queryMyPerformance(params: Ermcp.MyPerformancReq) {
-    return httpRequest<Ermcp.MyPerformancRsp[]>('/Guangzuan/QueryMyPerformanc', 'get', params);
+    return http.commonRequest<Ermcp.MyPerformancRsp[]>({
+        url: '/Guangzuan/QueryMyPerformanc',
+        params,
+    })
 }
 
 /**
  * 查询履约模板
  */
 export function queryPermancePlanTmp(params?: Ermcp.PermancePlanTmpReq) {
-    return httpRequest<Ermcp.PermancePlanTmpRsp[]>('/WrTrade2/QueryPermancePlanTmp', 'get', params);
+    return http.commonRequest<Ermcp.PermancePlanTmpRsp[]>({
+        url: '/WrTrade2/QueryPermancePlanTmp',
+        params,
+    })
 }
 
 /**
  * 查询履约步骤枚举
  */
 export function queryWrPerformanceStepType() {
-    return httpRequest<Ermcp.WrPerformanceStepTypeRsp[]>('/WrTrade2/QueryWrPerformanceStepType', 'get');
+    return http.commonRequest<Ermcp.WrPerformanceStepTypeRsp[]>({
+        url: '/WrTrade2/QueryWrPerformanceStepType',
+    })
 }
 
 /**
  * 查询履约信息详情
  */
 export function queryWrPerformancePlanStep(params: Ermcp.WrPerformancePlanStepReq) {
-    return httpRequest<Ermcp.WrPerformancePlanStepRsp[]>('/WrTrade2/QueryWrPerformancePlanStep', 'get', params);
+    return http.commonRequest<Ermcp.WrPerformancePlanStepRsp[]>({
+        url: '/WrTrade2/QueryWrPerformancePlanStep',
+        params,
+    })
 }

+ 113 - 0
src/services/api/presale/index.ts

@@ -0,0 +1,113 @@
+import { v4 } from 'uuid'
+import { loginStore } from '@/stores'
+import { ClientType } from '@/constants/client'
+import { tradeServerRequest } from '@/services/socket/trade'
+import { TradeParams } from '@/services/socket/trade/interface'
+import http from '@/services/http'
+import moment from 'moment'
+
+const { userId, firstAccountId } = loginStore.$mapGetters()
+
+/**
+ * 预售大厅/我的预售/集采大厅/我的集采 列表查询
+ */
+export function queryGZPreSell(params: Ermcp.GZPreSellReq) {
+    return http.commonRequest<Ermcp.GZPreSellRsp[]>({
+        url: '/Guangzuan/QueryGZPreSell',
+        params,
+    })
+}
+
+/**
+ * 我的预售申请列表查询
+ */
+export function queryGZWrPreSaleApply(params: Ermcp.GZWrPreSaleApplyReq) {
+    params.userid = userId.value
+    return http.commonRequest<Ermcp.GZWrPreSaleApplyRsp[]>({
+        url: '/Guangzuan/QueryGZWrPreSaleApply',
+        params,
+    })
+}
+
+/**
+ * 我的预售认购列表查询
+ */
+export function queryGZMyPresell(params: Ermcp.GZMyPresellReq) {
+    return http.commonRequest<Ermcp.GZMyPresellRsp[]>({
+        url: '/Guangzuan/QueryGZMyPresell',
+        params,
+    })
+}
+
+/**
+ * 我参与的预售(预售中\执行中)\我参与的集采(集采中\执行中) 列表查询
+ */
+export function queryGZMyTradingPreSell(params: Ermcp.GZMyTradingPreSellReq) {
+    params.userid = userId.value
+    return http.commonRequest<Ermcp.GZMyTradingPreSellRsp[]>({
+        url: '/Guangzuan/QueryGZMyTradingPreSell',
+        params,
+    })
+}
+
+/**
+ * 广钻预售申请
+ */
+export function gzPresaleApply(params: TradeParams<Partial<Proto.GZPresaleApplyReq>, Proto.GZPresaleApplyRsp>) {
+    params.data = {
+        SellUserID: userId.value,
+        SellAccountID: firstAccountId.value,
+        MarketID: 63201,
+        ClientType: ClientType.Web,
+        ClientSerialNo: v4(),
+        ...params.data
+    }
+    return tradeServerRequest('GZPresaleApplyReq', 'GZPresaleApplyRsp', params, 63201);
+}
+
+/**
+ * 广钻预售认购下单
+ */
+export function gzPresaleOrder(params: TradeParams<Partial<Proto.GZPresaleOrderReq>, Proto.GZPresaleOrderRsp>) {
+    params.data = {
+        UserID: userId.value,
+        AccountID: firstAccountId.value,
+        MarketID: 63201,
+        ClientOrderTime: moment().format('YYYY-MM-DD HH:mm:ss'),
+        ClientType: ClientType.Web,
+        ClientSerialNo: v4(),
+        ...params.data
+    }
+    return tradeServerRequest('GZPresaleOrderReq', 'GZPresaleOrderRsp', params, 63201);
+}
+
+/**
+ * 广钻集采申请
+ */
+export function gzCenterPurchaseApply(params: TradeParams<Partial<Proto.GZCenterPurchaseApplyReq>, Proto.GZCenterPurchaseApplyRsp>) {
+    params.data = {
+        SellUserID: userId.value,
+        SellAccountID: firstAccountId.value,
+        MarketID: 62201,
+        ClientType: ClientType.Web,
+        ClientSerialNo: v4(),
+        ...params.data
+    }
+    return tradeServerRequest('GZCenterPurchaseApplyReq', 'GZCenterPurchaseApplyRsp', params, 62201);
+}
+
+/**
+ * 广钻集采认购下单
+ */
+export function gzCenterPurchaseOrder(params: TradeParams<Partial<Proto.GZCenterPurchaseOrderReq>, Proto.GZCenterPurchaseOrderRsp>) {
+    params.data = {
+        UserID: userId.value,
+        AccountID: firstAccountId.value,
+        MarketID: 62201,
+        ClientOrderTime: moment().format('YYYY-MM-DD HH:mm:ss'),
+        ClientType: ClientType.Web,
+        ClientSerialNo: v4(),
+        ...params.data
+    }
+    return tradeServerRequest('GZCenterPurchaseOrderReq', 'GZCenterPurchaseOrderRsp', params, 62201);
+}

+ 9 - 3
src/services/api/quote/index.ts

@@ -1,15 +1,21 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 
 /**
  * 历史行情
  */
 export function queryHistoryDatas(params: { goodscode?: string }) {
-    return httpRequest<Ermcp.QueryHistoryDatasRsp[]>('/Quote/QueryHistoryDatas', 'get', params);
+    return http.commonRequest<Ermcp.QueryHistoryDatasRsp[]>({
+        url: '/Quote/QueryHistoryDatas',
+        params,
+    })
 }
 
 /**
  * 历史行情
  */
 export function queryTSData(params: { goodscode?: string }) {
-    return httpRequest<Ermcp.QueryTSDataRsp>('/Quote/QueryTSData', 'get', params);
+    return http.commonRequest<Ermcp.QueryTSDataRsp>({
+        url: '/Quote/QueryTSData',
+        params,
+    })
 }

+ 13 - 4
src/services/api/report/index.ts

@@ -1,22 +1,31 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 
 /**
  * 查询会员报表
  */
 export function queryMemberReport(params: Ermcp.MemberReportReq) {
-    return httpRequest<Ermcp.MemberReportRsp[]>('/Guangzuan/QueryMemberReport', 'get', params);
+    return http.commonRequest<Ermcp.MemberReportRsp[]>({
+        url: '/Guangzuan/QueryMemberReport',
+        params,
+    })
 }
 
 /**
  * 查询仓储报表
  */
 export function queryWRPositionReport(params: Ermcp.WRPositionReportReq) {
-    return httpRequest<Ermcp.WRPositionReportRsp[]>('/Guangzuan/QueryWRPositionReport', 'get', params);
+    return http.commonRequest<Ermcp.WRPositionReportRsp[]>({
+        url: '/Guangzuan/QueryWRPositionReport',
+        params,
+    })
 }
 
 /**
  * 查询交易报表
  */
 export function queryTradeReport(params: Ermcp.TradeReportReq) {
-    return httpRequest<Ermcp.TradeReportRsp[]>('/Guangzuan/QueryTradeReport', 'get', params);
+    return http.commonRequest<Ermcp.TradeReportRsp[]>({
+        url: '/Guangzuan/QueryTradeReport',
+        params,
+    })
 }

+ 35 - 10
src/services/api/trade/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 import { Market } from '@/constants/market'
@@ -63,54 +63,79 @@ export function wrListingCancelOrder(params: TradeParams<Proto.WRListingCancelOr
  * 查询求购大厅委托单
  */
 export function queryBuyOrder(params: Ermcp.BuyOrderReq) {
-    return httpRequest<Ermcp.BuyOrderRsp[]>('/Guangzuan/QueryBuyOrder', 'get', params);
+    return http.commonRequest<Ermcp.BuyOrderRsp[]>({
+        url: '/Guangzuan/QueryBuyOrder',
+        params,
+    })
 }
 
 /**
  * 查询我的求购
  */
 export function queryMyBuyOrder(params: Ermcp.MyBuyOrderReq) {
-    return httpRequest<Ermcp.MyBuyOrderRsp[]>('/Guangzuan/QueryMyBuyOrder', 'get', params);
+    return http.commonRequest<Ermcp.MyBuyOrderRsp[]>({
+        url: '/Guangzuan/QueryMyBuyOrder',
+        params,
+    })
 }
 
 /**
  * 搜索出售大厅委托单
  */
-export function searchSellOrder(params: Ermcp.SellOrderSearchReq) {
-    return httpRequest<Ermcp.SellOrderSearchRsp[]>('/Guangzuan/QueryDiamond', 'post', params);
+export function searchSellOrder(data: Ermcp.SellOrderSearchReq) {
+    return http.commonRequest<Ermcp.SellOrderSearchRsp[]>({
+        method: 'post',
+        url: '/Guangzuan/QueryDiamond',
+        data,
+    })
 }
 
 /**
  * 查询出售大厅委托单
  */
 export function querySellOrder(params: Ermcp.SellOrderReq) {
-    return httpRequest<Ermcp.SellOrderRsp[]>('/Guangzuan/QuerySellOrder', 'get', params);
+    return http.commonRequest<Ermcp.SellOrderRsp[]>({
+        url: '/Guangzuan/QuerySellOrder',
+        params,
+    })
 }
 
 /**
  * 查询我的出售
  */
 export function queryMySellOrder(params: Ermcp.MySellOrderReq) {
-    return httpRequest<Ermcp.MySellOrderRsp[]>('/Guangzuan/QueryMySellOrder', 'get', params);
+    return http.commonRequest<Ermcp.MySellOrderRsp[]>({
+        url: '/Guangzuan/QueryMySellOrder',
+        params,
+    })
 }
 
 /**
  * 查询我的摘牌
  */
 export function queryMyDeListing(params: Ermcp.MyDeListingReq) {
-    return httpRequest<Ermcp.MyDeListingRsp[]>('/Guangzuan/QueryMyDeListing', 'get', params);
+    return http.commonRequest<Ermcp.MyDeListingRsp[]>({
+        url: '/Guangzuan/QueryMyDeListing',
+        params,
+    })
 }
 
 /**
  * 查询询价-求购
  */
 export function queryMyBargainApply(params: Ermcp.MyBargainApplyReq) {
-    return httpRequest<Ermcp.MyBargainApplyRsp[]>('/Guangzuan/QueryMyBargainApply', 'get', params);
+    return http.commonRequest<Ermcp.MyBargainApplyRsp[]>({
+        url: '/Guangzuan/QueryMyBargainApply',
+        params,
+    })
 }
 
 /**
  * 查询询价-出售
  */
 export function queryMyDelistingApply(params: Ermcp.MyDelistingApplyReq) {
-    return httpRequest<Ermcp.MyDelistingApplyRsp[]>('/Guangzuan/QueryMyDelistingApply', 'get', params);
+    return http.commonRequest<Ermcp.MyDelistingApplyRsp[]>({
+        url: '/Guangzuan/QueryMyDelistingApply',
+        params,
+    })
 }

+ 20 - 5
src/services/api/user/index.ts

@@ -1,19 +1,34 @@
-import { httpRequest } from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
+import { loginStore } from '@/stores'
+import http from '@/services/http'
+
+const { userId } = loginStore.$mapGetters()
 
 /**
  * 查询收货地址信息
  */
-export function queryUserReceiveInfo(params: Ermcp.UserReceiveInfoReq) {
-    return httpRequest<Ermcp.UserReceiveInfoRsp[]>('/Qhj/QueryUserReceiveInfo', 'get', params);
+export function queryUserReceiveInfo(params?: Ermcp.UserReceiveInfoReq) {
+    return http.commonRequest<Ermcp.UserReceiveInfoRsp[]>({
+        url: '/Qhj/QueryUserReceiveInfo',
+        params: {
+            userid: userId.value,
+            ...params
+        },
+    })
 }
 
 /**
  * 查询发票信息
  */
-export function queryWrUserReceiptInfo(params: Ermcp.WrUserReceiptInfoReq) {
-    return httpRequest<Ermcp.WrUserReceiptInfoRsp[]>('/WrTrade2/QueryWrUserReceiptInfo', 'get', params);
+export function queryWrUserReceiptInfo(params?: Ermcp.WrUserReceiptInfoReq) {
+    return http.commonRequest<Ermcp.WrUserReceiptInfoRsp[]>({
+        url: '/WrTrade2/QueryWrUserReceiptInfo',
+        params: {
+            userid: userId.value,
+            ...params
+        },
+    })
 }
 
 /**

+ 5 - 2
src/services/api/warehouse/index.ts

@@ -1,4 +1,4 @@
-import { httpRequest } from '@/services/http'
+import http from '@/services/http'
 import { tradeServerRequest } from '@/services/socket/trade'
 import { TradeParams } from '@/services/socket/trade/interface'
 
@@ -6,7 +6,10 @@ import { TradeParams } from '@/services/socket/trade/interface'
  * 查询仓库信息
  */
 export function queryWarehouseInfo(params: Ermcp.WarehouseInfoReq) {
-    return httpRequest<Ermcp.WarehouseInfoRsp[]>('/Guangzuan/QueryWarehouseInfo', 'get', params);
+    return http.commonRequest<Ermcp.WarehouseInfoRsp[]>({
+        url: '/Guangzuan/QueryWarehouseInfo',
+        params,
+    })
 }
 
 /**

+ 117 - 102
src/services/http/index.ts

@@ -1,121 +1,136 @@
-import axios, { AxiosRequestConfig, Method } from 'axios'
+import axios, { AxiosRequestConfig } from 'axios'
 //import qs from 'qs'
 //import cryptojs from 'crypto-js'
 //import { addPending, removePending } from './pending'
-import service from '@/services'
 import { loginStore } from '@/stores'
 import { CommonResult, ResultCode } from './interface'
+import service from '@/services'
 
-const axiosInstance = axios.create({
-    timeout: 30000,
-})
+export default new (class {
+    private readonly axiosInstance = axios.create({
+        timeout: 30000,
+    })
 
-// 请求拦截器
-axiosInstance.interceptors.request.use(
-    (config) => {
-        //addPending(config) //将当前请求添加到列表中
-        //请求头签名
-        const sign = {
-            token: loginStore.getters.token,
-            signsecret: 'qz7qWOMXKTMT5JlDs5w4NTPwWeR3xhF1v6wqbZ9cExmP6cc3spvNAp1wJJ1SqRI5',
-            timestamp: new Date().getTime(),
-        }
-        //设置请求头
-        config.headers = {
-            Authorization: sign.token,
-            //Signid: 'eecd3f37625f4501b88e9f0fa14b4b51',
-            //Sign: cryptojs.SHA256(qs.stringify(sign)).toString(),
-            //Timestamp: sign.timestamp.toString(),
-        }
-        return config
-    },
-    (err) => {
-        console.error(err)
-        return Promise.reject('出现错误,请稍后再试')
-    }
-)
+    constructor() {
+        // 请求拦截器
+        this.axiosInstance.interceptors.request.use(
+            (config) => {
+                //addPending(config) //将当前请求添加到列表中
+                //请求头签名
+                const sign = {
+                    token: loginStore.getters.token,
+                    signsecret: 'qz7qWOMXKTMT5JlDs5w4NTPwWeR3xhF1v6wqbZ9cExmP6cc3spvNAp1wJJ1SqRI5',
+                    timestamp: new Date().getTime(),
+                }
+                //设置请求头
+                config.headers = {
+                    Authorization: sign.token,
+                    //Signid: 'eecd3f37625f4501b88e9f0fa14b4b51',
+                    //Sign: cryptojs.SHA256(qs.stringify(sign)).toString(),
+                    //Timestamp: sign.timestamp.toString(),
+                }
+                return config
+            },
+            (err) => {
+                console.error(err)
+                return Promise.reject('出现错误,请稍后再试')
+            }
+        )
 
-// 响应拦截器
-axiosInstance.interceptors.response.use(
-    (res) => {
-        //removePending(res) //在请求结束后,移除本次请求
-        return res
-    },
-    (err) => {
-        if (err.message === 'Network Error') {
-            return Promise.reject('无网络连接,请检查网络')
-        }
-        if (err.response) {
-            const { msg, message } = err.response.data ?? {}
-            switch (err.response.status) {
-                case 408: {
-                    return Promise.reject('请求超时,请稍后再试')
+        // 响应拦截器
+        this.axiosInstance.interceptors.response.use(
+            (res) => {
+                //removePending(res) //在请求结束后,移除本次请求
+                return res
+            },
+            (err) => {
+                if (err.message === 'Network Error') {
+                    return Promise.reject('无网络连接,请检查网络')
                 }
-                default: {
-                    return Promise.reject(msg || message)
+                if (err.response) {
+                    const { msg, message } = err.response.data ?? {}
+                    switch (err.response.status) {
+                        case 408: {
+                            return Promise.reject('请求超时,请稍后再试')
+                        }
+                        default: {
+                            return Promise.reject(msg || message)
+                        }
+                    }
                 }
+                return Promise.reject('出现错误,请稍后再试')
             }
-        }
-        return Promise.reject('出现错误,请稍后再试')
+        )
     }
-)
 
-/**
- * Http 通用请求
- * @param url 
- * @param method 
- * @param payload 
- * @param errMsg 
- * @returns 
- */
-export async function commonRequest<T>(url: string, method: Method, payload?: unknown, errMsg?: string) {
-    await service.onReady().then((config) => {
-        axiosInstance.defaults.baseURL = config.goCommonSearchUrl
-    })
-    const config: AxiosRequestConfig = {
-        url,
-        method,
+    /** 
+     * 是否启用响应延时
+     * 可防止在动画过程中同时请求数据,数据请求先于动画完成,双绑数据的页面会重新渲染,导致动画卡顿的问题
+     */
+    private delay = false
+
+    /** 如果启用响应延时,将响应回调添加到该集合中 */
+    private resultMap = new Set<() => void>()
+
+    /** 请求时的 loading 状态 */
+    get loading() {
+        return this.delay
     }
-    if (payload instanceof Object) {
-        if (['post', 'POST', 'put', 'PUT', 'patch', 'PATCH'].includes(method)) {
-            config.data = payload
-        } else {
-            config.params = payload
+
+    /** 在动画开始时设置一个 loading 状态,在动画结束后取消 loading 状态,后返回请求结果 */
+    set loading(status: boolean) {
+        this.delay = status
+        if (!status) {
+            // 当 loading 状态为 false 时返回所有延时请求的回调
+            this.resultMap.forEach((fn) => {
+                fn()
+                this.resultMap.delete(fn)
+            })
         }
     }
-    return await axiosInstance(config).then((res) => {
-        return res.data as T
-    }).catch((err) => {
-        const msg = err ?? (errMsg ? '请求失败: ' + errMsg : '请求失败,请稍后重试')
-        return Promise.reject(msg)
-    })
-}
 
-/**
- * Http 请求
- * @param url 
- * @param method 
- * @param payload 
- * @param errMsg 
- * @returns 
- */
-export async function httpRequest<T>(url: string, method: Method, payload?: unknown, errMsg?: string) {
-    const res = await commonRequest<CommonResult<T>>(url, method, payload, errMsg)
-    switch (res.code) {
-        case ResultCode.InvalidToken:
-            return Promise.reject('令牌无效')
-        case ResultCode.Success:
-            return res
-        default:
-            return Promise.reject(res.msg)
+    /**
+     * Http 请求
+     * @param url 
+     * @param method 
+     * @param payload 
+     * @param errMsg 
+     * @returns 
+     */
+    request<T>(config: AxiosRequestConfig, errMsg?: string) {
+        return new Promise<T>((resolve, reject) => {
+            this.axiosInstance(config).then((res) => {
+                if (this.delay) {
+                    this.resultMap.add(() => resolve(res.data))
+                } else {
+                    resolve(res.data)
+                }
+            }).catch((err) => {
+                const msg = err ?? (errMsg ? '请求失败: ' + errMsg : '请求失败,请稍后重试')
+                reject(msg)
+            })
+        })
     }
-}
 
-/**
- * 获取服务配置地址
- * @param key 
- * @returns 
- */
-export function getServiceUrl(key: keyof typeof service.config) {
-    return service.config[key]
-}
+    /**
+     * Http 通用请求
+     * @param url 
+     * @param method 
+     * @param payload 
+     * @param errMsg 
+     * @returns 
+     */
+    async commonRequest<T>(config: AxiosRequestConfig, errMsg?: string) {
+        const baseUrl = service.getConfig('goCommonSearchUrl')
+        config.url = baseUrl + config.url
+        const res = await this.request<CommonResult<T>>(config, errMsg)
+        switch (res.code) {
+            case ResultCode.InvalidToken:
+                return Promise.reject('令牌无效')
+            case ResultCode.Success:
+                return res
+            default:
+                return Promise.reject(res.msg)
+        }
+    }
+})

+ 15 - 8
src/services/index.ts

@@ -47,18 +47,17 @@ export default new (class {
 
     /**
      * 失败时重新尝试初始化,直到成功为止
-     * @param msg 
      */
-    private tryinit = (msg: string) => {
+    private tryinit = () => {
         return new Promise<typeof this.config>((resolve, reject) => {
             if (this.retryCount >= 5) {
                 this.retryCount = 0
                 this.isPending = false
-                reject(msg)
+                reject('服务加载失败,请稍后再试')
             } else {
                 this.retryCount++
                 // 自动计算每次重试的延时,重试次数越多,延时越大
-                const delay = this.retryCount * 5000
+                const delay = this.retryCount * 3000
                 setTimeout(() => {
                     resolve(this.init())
                 }, delay)
@@ -72,7 +71,7 @@ export default new (class {
      */
     private init(): Promise<typeof this.config> {
         this.isPending = true
-        return new Promise((resolve) => {
+        return new Promise((resolve, reject) => {
             const filePath = './config/appconfig.json'
             const getAppConfig = async () => {
                 if (plus.hasPlus()) {
@@ -90,12 +89,11 @@ export default new (class {
                     this.isReady = true
                     resolve(this.config)
                 }).catch(() => {
-                    const result = this.tryinit('服务地址加载失败')
+                    const result = this.tryinit()
                     resolve(result)
                 })
             }).catch(() => {
-                const result = this.tryinit('配置文件加载失败')
-                resolve(result)
+                reject('配置文件加载失败,请稍后再试')
             })
         })
     }
@@ -110,4 +108,13 @@ export default new (class {
         // 确保当前只有一个初始化实例
         return this.onload
     }
+
+    /**
+     * 获取服务配置地址
+     * @param key 
+     * @returns 
+     */
+    getConfig<K extends keyof typeof this.config>(key: K) {
+        return this.config[key]
+    }
 })

+ 4 - 1
src/services/socket/trade/index.ts

@@ -4,6 +4,7 @@ import { FunCode } from '@/constants/funcode'
 import { loginStore, errorInfoStore } from '@/stores'
 import { IMessageHead } from './protobuf/proto'
 import { TradeParams, TradeResponse } from './interface'
+import cryptojs from 'crypto-js'
 import Protobuf from './protobuf'
 import socket from '../index'
 
@@ -89,8 +90,10 @@ export async function tradeServerRequest<Req, Rsp>(reqKey: keyof typeof FunCode,
             }
             case 12018: {
                 if (RetDesc) {
+                    const { Utf8, Base64 } = cryptojs.enc
+                    const word = Base64.parse(RetDesc)
                     // 解析base64
-                    res.RetDesc = Buffer.from(RetDesc, 'base64').toString();
+                    res.RetDesc = Utf8.stringify(word)
                 }
                 return Promise.reject(res.RetDesc);
             }

+ 1 - 2
src/stores/index.ts

@@ -1,6 +1,5 @@
 export { loginStore } from './modules/login'
-export { userStore } from './modules/user'
-export { themeStore } from './modules/theme'
+export { globalStore } from './modules/global'
 export { menuStore } from './modules/menu'
 export { accountStore } from './modules/account'
 export { futuresStore } from './modules/futures'

+ 1 - 1
src/stores/modules/enum.ts

@@ -12,7 +12,7 @@ export interface EnumType {
     disabled?: boolean;
 }
 
-const enumKeys = ['ZSCategory', 'ZSCurrencyType', 'ZSCurrencyType', 'ZSColorType', 'ZSClarityType', 'ZSCutType', 'ZSShapeType', 'ZSSymmetryType', 'ZSPolishType', 'ZSFluorescenceType', 'ZSCertType', 'ZSCrystalType', 'ZSCZColor1Type', 'ZSCZColor2Type', 'ZSCZColor3Type', 'ZSStyleType', 'signstatus', 'applystatus', 'executetype', 'certificatetype', 'clientType', 'wrApplyStatus', 'performanceStatus', 'stepStatus', 'GZCJAccountType', 'GZCJCategoryType', 'GZCJDeliveryType', 'GZCJShapeType', 'GZCJMarkType', 'GZCJPublishType', 'GZCJServiceType', 'GZCJStatus', 'GZBSStatus', 'GZBSDeliveryType', 'GZBSCOrderType', 'GZBSCOrderStatus', 'GZBSCOutType', 'GZBSCPayStatus', 'GZBSCPayMode'] as const
+const enumKeys = ['ZSCategory', 'ZSCurrencyType', 'ZSCurrencyType', 'ZSColorType', 'ZSClarityType', 'ZSCutType', 'ZSShapeType', 'ZSSymmetryType', 'ZSPolishType', 'ZSFluorescenceType', 'ZSCertType', 'ZSCrystalType', 'ZSCZColor1Type', 'ZSCZColor2Type', 'ZSCZColor3Type', 'ZSStyleType', 'signstatus', 'applystatus', 'executetype', 'certificatetype', 'clientType', 'wrApplyStatus', 'performanceStatus', 'stepStatus', 'GZCJAccountType', 'GZCJCategoryType', 'GZCJDeliveryType', 'GZCJShapeType', 'GZCJMarkType', 'GZCJPublishType', 'GZCJServiceType', 'GZCJStatus', 'GZBSStatus', 'GZBSDeliveryType', 'GZBSCOrderType', 'GZBSCOrderStatus', 'GZBSCOutType', 'GZBSCPayStatus', 'GZBSCPayMode', 'YSZSCategory', 'YSProductionMode', 'WRPresaleStatus', 'inoutapplystatus'] as const
 
 export const enumMap = new Map<typeof enumKeys[number], ShallowRef<Ermcp.EnumRsp[]>>()
 

+ 8 - 6
src/stores/modules/exrate.ts

@@ -30,12 +30,14 @@ export const exrateStore = createStore({
         },
         // 汇率转换
         exchangeRate(currencyId: number, currencyValue: number, prefix = true) {
-            const exrate = this.actions.getExrate(currencyId)
-            const currency = getCurrencyTypeInfo(currencyId)
-            const cny = getCurrencyTypeInfo(CurrencyType.CNY) // 人民币
-            const unit = prefix && exrate ? cny?.param2 : currency?.param2 // 币种单位符号
-
-            return unit + (exrate ? currencyValue * exrate : currencyValue).toFixed(2)
+            if (currencyValue) {
+                const exrate = this.actions.getExrate(currencyId)
+                const currency = getCurrencyTypeInfo(currencyId)
+                const cny = getCurrencyTypeInfo(CurrencyType.CNY) // 人民币
+                const unit = prefix && exrate ? cny?.param2 : currency?.param2 // 币种单位符号
+                return unit + (exrate ? currencyValue * exrate : currencyValue).toFixed(2)
+            }
+            return '0.00'
         }
     }
 })

+ 0 - 1
src/stores/modules/futures.ts

@@ -1,7 +1,6 @@
 import { computed } from 'vue'
 import { timerInterceptor } from '@/utils/timer'
 import { queryGoodsList } from '@/services/api/goods'
-import { loginStore } from './login'
 import { createStore } from '../base'
 import eventBus from '@/services/bus'
 import moment from 'moment'

+ 3 - 3
src/stores/modules/theme.ts → src/stores/modules/global.ts

@@ -3,7 +3,7 @@ import { createStore } from '../base'
 import { localData } from '../storage'
 import plus from '@/utils/h5plus'
 
-export const themeStore = createStore({
+export const globalStore = createStore({
     state() {
         return {
             appTheme: localData.getRef('appTheme'),
@@ -92,8 +92,8 @@ export const themeStore = createStore({
 
 // 加载主题
 const loadTheme = () => {
-    const theme = themeStore.state.appTheme
-    themeStore.actions.setStatusBarTheme(theme)
+    const theme = globalStore.state.appTheme
+    globalStore.actions.setStatusBarTheme(theme)
     document.documentElement.setAttribute('theme', theme)
     document.removeEventListener('DOMContentLoaded', loadTheme)
 }

+ 30 - 0
src/stores/modules/login.ts

@@ -1,3 +1,4 @@
+import { queryLoginData } from '@/services/api/account'
 import { createStore } from '../base'
 import { sessionData } from '../storage'
 
@@ -8,7 +9,15 @@ export const loginStore = createStore({
     state() {
         return {
             logining: false,
+            loading: false,
             loginInfo: sessionData.getRef('loginInfo'),
+            userData: <Ermcp.LoginQueryRsp>{
+                arearole: [],
+                externalExchanges: [],
+                goodsgroups: [],
+                markets: [],
+                systemParams: []
+            },
         }
     },
     getters: {
@@ -29,11 +38,32 @@ export const loginStore = createStore({
             const accounts = this.state.loginInfo.AccountIDs
             return accounts[0] ?? 0
         },
+        // 登录机构名称
+        accountName() {
+            const { userAccount } = this.state.userData
+            return userAccount?.accountname
+        },
     },
     actions: {
+        // 获取用户数据
+        async getUserData() {
+            try {
+                this.state.loading = true
+                const res = await queryLoginData({
+                    loginID: loginStore.getters.loginId
+                })
+                this.state.userData = res.data
+            } finally {
+                this.state.loading = false
+            }
+        },
         // 获取用户登录信息
         getLoginInfo<K extends keyof Proto.LoginRsp>(key: K) {
             return this.state.loginInfo[key]
         },
+        // 获取用户数据
+        getUserDataInfo<K extends keyof Ermcp.LoginQueryRsp>(key: K) {
+            return this.state.userData[key]!
+        },
     }
 })

+ 0 - 46
src/stores/modules/user.ts

@@ -1,46 +0,0 @@
-import { queryLoginData } from '@/services/api/account'
-import { loginStore } from './login'
-import { createStore } from '../base'
-
-/**
- * 用户存储对象
- */
-export const userStore = createStore({
-    state() {
-        return {
-            loading: false,
-            userData: <Ermcp.LoginQueryRsp>{
-                arearole: [],
-                externalExchanges: [],
-                goodsgroups: [],
-                markets: [],
-                systemParams: []
-            },
-        }
-    },
-    getters: {
-        // 登录机构名称
-        accountName() {
-            const { userAccount } = this.state.userData
-            return userAccount?.accountname
-        }
-    },
-    actions: {
-        // 获取用户数据
-        async getUserData() {
-            try {
-                this.state.loading = true
-                const res = await queryLoginData({
-                    loginID: loginStore.getters.loginId
-                })
-                this.state.userData = res.data
-            } finally {
-                this.state.loading = false
-            }
-        },
-        // 获取用户数据
-        getUserDataInfo<K extends keyof Ermcp.LoginQueryRsp>(key: K) {
-            return this.state.userData[key]!
-        },
-    }
-})

+ 193 - 0
src/types/ermcp/presale.d.ts

@@ -0,0 +1,193 @@
+declare namespace Ermcp {
+    /** 预售大厅/我的预售/集采大厅/我的集采 列表查询 请求 */
+    interface GZPreSellReq {
+        presalestatus: number; // 预售状态 - 1:未开始 2:进行中 3:已结束 4:已关闭 5:处理中 6::处理失败 7:已完成
+        marketid: number;// 市场ID
+        wrstandardname?: string; // 现货商品名称
+        customername?: string; // 预售方
+        selluserid?: number; // 发行方用户ID
+        page?: number; // 页码
+        pagesize?: number; // 每页大小
+    }
+
+    /** 预售大厅/我的预售/集采大厅/我的集采 列表查询 响应 */
+    interface GZPreSellRsp {
+        bannerpicurl: string; // Banner图(逗号分隔)
+        baseqty: number; // 中签基数
+        buymarginalgorithm: number; // 采购保证金方式
+        buymarginvalue: number; // 采购保证金值
+        createtime: string; // 创建时间\申请时间
+        customername: string; // 企业名称(预售方)
+        deliverygoodsid: number; // 现货品种ID
+        enddate: string; // 预售结束日期
+        endhandletime: string; // 到期处理时间
+        lastprice: number; // 实际价格(64)
+        lotteryflag: number; // 摇号标识 - 0:未摇号 1:已摇号 2:摇号中 3:摇号失败
+        lotteryqty: number; // 摇号总量
+        luckynums: string; // 中签号码(按顺序逗号分隔)
+        luckyqty: number; // 已中签量\成交量
+        marketid: number; // 市场ID
+        maxbuyqty: number; // 单人最大申购量
+        maxluckyqty: number; // 单人最大中签量 - 作废
+        minbuyqty: number; // 最小采购单位
+        minsuccessqty: number; // 最低成团量
+        performancetemplateid: number; // 履约模板ID
+        pictureurls: string; // 详情图片(逗号分隔)
+        placeqty: number; // 已配售量
+        presaleapplyid: string; // 预售申请ID(184+Unix秒时间戳(10位)+xxxxxx)
+        presaleqty: number; // 预售总量
+        presalestatus: number; // 预售状态 - 1:未开始 2:进行中 3:已结束 4:已关闭 5:处理中 6::处理失败 7:已完成
+        qtydesc: string; // 数量描述 [2:毛坯钻石]
+        remark: string; // 备注
+        sellaccountid: number; // 发行方资金账户ID
+        sellmarginalgorithm: number; // 卖方保证金方式
+        sellmarginvalue: number; // 卖方保证金值
+        selluserid: number; // 发行方用户ID
+        sellwrtradeorderid: number; // 发行方卖委托单ID
+        sizestr: string; // 尺寸 [1:成品裸钻 \ 2:毛坯钻石]
+        startdate: string; // 预售开始日期
+        takestartdate: string; // 提货开始日期
+        thumurls: string; // 缩略图片(1:1)(逗号分隔)
+        tradedate: string; // 交易日
+        unitid: number; // 单位ID
+        unitprice: number; // 商品单价
+        warehouseid: number; // 仓库ID
+        weightdesc: string; // 重量描述 [2:毛坯钻石]
+        wrfactortypeid: number; // 仓单要素类型ID - 根据现货商品\仓库生成
+        wrstandardid: number; // 现货商品ID
+        wrstandardname: string; // 现货商品名称
+        yieldrate: string; // 成品率[2:毛坯钻石]
+        ysproductionmode: number; // 生产方式 - 枚举”YSProductionMode“[2: 毛坯钻石] 1:HPHT 2: CVD
+        yszscategory: number; // 钻石分类 - 枚举”YSZSCategory“ 1:成品裸钻 2: 毛坯钻石
+        zsclaritytypestr: string; // 净度[1: 成品裸钻 \ 2:毛坯钻石]
+        zscolortypestr: string; // 颜色[1: 成品裸钻 \ 2:毛坯钻石]
+        zscuttypestr: string; // 切工[1:成品裸钻]
+        zsfluorescencetypestr: string; // 荧光[1:成品裸钻]
+        zspolishtypestr: string; // 抛光[1:成品裸钻]
+        zsshapetypestr: string; // 形状[1:成品裸钻]
+        zssymmetrytypestr: string; // 对称[1:成品裸钻]
+    }
+
+    /** 我的预售申请列表查询 请求 */
+    interface GZWrPreSaleApplyReq {
+        userid?: number; // 用户ID
+        marketid: number; // 市场ID
+        page?: number; // 页码
+        pagesize?: number; // 每页大小
+    }
+
+    /** 我的预售申请列表查询 响应 */
+    interface GZWrPreSaleApplyRsp {
+        applyid: number; // 申请人
+        applyremark: string; // 备注
+        applysrc: number; // 申请来源 - 1:管理端 2:终端
+        applystatus: number; // 申请状态(inoutapplystatus) - 1:待审核 2:审核通过 3:审核拒绝 4:处理失败 5:已撤回
+        applytime: string; // 申请时间
+        auditid: number; // 审核人
+        auditremark: string; // 审核备注
+        auditsrc: number; // 审核来源 - 1:管理端 2:终端
+        audittime: string; // 审核时间
+        audittradedate: string; // 审核交易日(yyyyMMdd)
+        bannerpicurl: string; // Banner图(逗号分隔)
+        baseqty: number; // 中签基数
+        buymarginalgorithm: number; // 买方保证金方式 - 1:比率 2:固定
+        buymarginvalue: number; // 买方保证金设置值
+        clientticket: string; // 客户端流水号
+        deliverygoodsid: number; // 现货品种ID
+        enddate: string; // 预售结束日期
+        handlestatus: number; // 处理状态
+        marketid: number; // 市场ID
+        maxbuyqty: number; // 单人最大申购量
+        maxluckyqty: number; // 单人最大中签量 - 作废
+        minbuyqty: number; // 单人最小申购量
+        minsuccessqty: number; // 最低成团量
+        performancetemplateid: number; // 履约计划模板ID(方式为1时填-1, 为2时选择模板)
+        pictureurls: string; // 详情图片(逗号分隔)
+        presaleapplyid: string; // 预售申请ID(184+Unix秒时间戳(10位)+xxxxxx)
+        presaleqty: number; // 预售总量
+        qtydesc: string; // 数量描述 [2:毛坯钻石]
+        remark: string; // 备注
+        sellaccountid: number; // 发行方资金账户ID
+        selluserid: number; // 发行方用户ID
+        sizestr: string; // 尺寸 [1:成品裸钻 \ 2:毛坯钻石]
+        startdate: string; // 预售开始日期
+        takestartdate: string; // 提货开始日期
+        thumurls: string; // 缩略图片(1:1)(逗号分隔)
+        unitid: number; // 单位ID
+        unitprice: number; // 商品单价
+        warehouseid: number; // 仓库ID
+        weightdesc: string; // 重量描述 [2:毛坯钻石]
+        wrfactortypeid: number; // 仓单要素类型ID - 根据现货商品\仓库生成
+        wrstandardid: number; // 现货商品ID
+        wrstandardname: string; // 现货商品名称
+        yieldrate: string; // 成品率 [2:毛坯钻石]
+        ysproductionmode: number; // 生产方式 - 枚举”YSProductionMode“ [2:毛坯钻石] 1:HPHT 2:CVD
+        yszscategory: number; // 钻石分类 - 枚举”YSZSCategory“ 1:成品裸钻 2:毛坯钻石
+        zsclaritytypestr: string; // 净度 [1:成品裸钻 \ 2:毛坯钻石]
+        zscolortypestr: string; // 颜色 [1:成品裸钻 \ 2:毛坯钻石]
+        zscuttypestr: string; // 切工 [1:成品裸钻]
+        zsfluorescencetypestr: string; // 荧光 [1:成品裸钻]
+        zspolishtypestr: string; // 抛光 [1:成品裸钻]
+        zsshapetypestr: string; // 形状 [1:成品裸钻]
+        zssymmetrytypestr: string; // 对称 [1:成品裸钻]
+    }
+
+    /** 我的预售认购列表查询 请求 */
+    interface GZMyPresellReq {
+        presaleapplyid: string; // 预售申请ID
+        page?: number; // 页码
+        pagesize?: number; // 每页大小
+    }
+
+    /** 我的预售认购列表查询 响应 */
+    interface GZMyPresellRsp {
+        customername: string; // 企业名称(认购方)
+        freezemargin: number; // 冻结保证金
+        orderqty: number; // 委托数量
+        ordertime: string; // 委托时间(认购时间)
+        tradeprice: number; // 成交价格 - [摘牌] (浮动价 ((商品1价格商品1价格系数+升贴水) 商品1重量系数 + 商品2价格商品2价格系数+商品2升贴水) 商品2重量系数 …)* 委托单价格系数 + 委托单升贴水)
+    }
+
+    /** 我参与的预售(预售中\执行中)\我参与的集采(集采中\执行中) 列表查询 请求 */
+    interface GZMyTradingPreSellReq {
+        userid?: number; // 用户ID
+        marketid: number; // 市场ID
+        wrstandardname?: string; // 现货商品名称
+        customername?: string; // 预售方
+        status?: number; // 状态 1:预售中\集采中 2:执行中 3:已完成
+        page?: number; // 页码
+        pagesize?: number; // 每页大小
+    }
+
+    /** 我参与的预售(预售中\执行中)\我参与的集采(集采中\执行中) 列表查询 响应 */
+    interface GZMyTradingPreSellRsp {
+        customername: string; // 企业名称(预售方、卖方)
+        freezemargin: number; // 冻结保证金\已付保证金
+        marginalgorithm: number; // 保证金方式 - 1:比率 2:固定
+        marginvalue: number; // 保证金设置值
+        orderqty: number; // 委托数量\认购数量
+        ordertime: string; // 委托时间(认购时间)
+        performanceplanid: number; // 履约计划ID/合同ID
+        performancetemplateid: number; // 履约计划模板ID
+        presaleapplyid: string; // 预售申请ID(184+Unix秒时间戳(10位)+xxxxxx)
+        qtydesc: string; // 数量描述 [2:毛坯钻石]
+        remark: string; // 备注
+        sizestr: string; // 尺寸 [1:成品裸钻 \ 2:毛坯钻石]
+        status: number; // 状态 1:预售中\集采中 2:执行中 3:已完成
+        tradeamount: number; // 货款
+        tradeprice: number; // 成交价格\认购价格 - [摘牌] (浮动价 ((商品1价格商品1价格系数+升贴水) 商品1重量系数 + 商品2价格商品2价格系数+商品2升贴水) 商品2重量系数 …)* 委托单价格系数 + 委托单升贴水)
+        weightdesc: string; // 重量描述 [2:毛坯钻石]
+        wrstandardname: string; // 商品
+        wrtradeorderid: number; // 仓单贸易委托单ID(320+Unix秒时间戳(10位)+xxxxxx)
+        yieldrate: string; // 成品率 [2:毛坯钻石]
+        ysproductionmode: number; // 生产方式 - 枚举”YSProductionMode“ [2:毛坯钻石] 1:HPHT 2:CVD
+        yszscategory: number; // 钻石分类 - 枚举”YSZSCategory“ 1:成品裸钻 2:毛坯钻石
+        zsclaritytypestr: string; // 净度 [1:成品裸钻 \ 2:毛坯钻石]
+        zscolortypestr: string; // 颜色 [1:成品裸钻 \ 2:毛坯钻石]
+        zscuttypestr: string; // 切工 [1:成品裸钻]
+        zsfluorescencetypestr: string; // 荧光 [1:成品裸钻]
+        zspolishtypestr: string; // 抛光 [1:成品裸钻]
+        zsshapetypestr: string; // 形状 [1:成品裸钻]
+        zssymmetrytypestr: string; // 对称 [1:成品裸钻]
+    }
+}

+ 2 - 2
src/types/ermcp/user.d.ts

@@ -1,7 +1,7 @@
 declare namespace Ermcp {
     /** 查询收货地址信息 请求 */
     interface UserReceiveInfoReq {
-        userid: number; // 用户ID
+        userid?: number; // 用户ID
     }
 
     /** 查询收货地址信息 响应 */
@@ -28,7 +28,7 @@ declare namespace Ermcp {
 
     /** 查询发票信息 请求 */
     interface WrUserReceiptInfoReq {
-        userid: number; // 用户ID
+        userid?: number; // 用户ID
         receipttype?: number; // 发票类型 - 1:个人 2:企业
     }
 

+ 148 - 0
src/types/proto/presale.d.ts

@@ -0,0 +1,148 @@
+import { IMessageHead } from '@/services/socket/trade/protobuf/proto'
+import Long from 'long'
+
+declare global {
+    namespace Proto {
+        /** 广钻预售申请请求 */
+        interface GZPresaleApplyReq {
+            Header?: IMessageHead;
+            SellUserID: number; // 发行方用户,必填
+            SellAccountID: number; // 发行方资金账户ID,必填
+            WRStandardName: string; // 现货商品名称,必填
+            PresaleQty: number; // 预售总量,必填
+            MinBuyQty: number; // 单人最小申购量,必填
+            MaxBuyQty: number; // 单人最大申购量,必填
+            MinSuccessQty: number; // 最低成团量,必填
+            UnitPrice: number; // 预售价格,小数,两位,必填
+            StartDate: string; // 预售开始日期,必填
+            EndDate: string; // 预售结束日期,必填
+            BuyMarginAlgorithm: number; // 买方保证金方式,必填
+            BuyMarginValue: number; // 买方保证金设置值,小数,四位,必填
+            PerformanceTemplateID: number; // 履约计划模板ID,必填
+            MarketID: number; // 市场ID,必填
+            YSZSCategory: number; // 预售钻石分类
+            ZSColorTypeStr: string; // 颜色,最大允许64个字符
+            ZSClarityTypeStr: string; // 净度,最大允许64个字符
+            SizeStr: string; // 尺寸,最大允许64个字符
+            YieldRate: string; // 成品率,最大允许64个字符
+            QtyDesc: string; // 数量描述,最大允许64个字符
+            WeightDesc: string; // 重量描述,最大允许64个字符
+            YSProductionMode: number; // 生产方式
+            PictureUrls: string; // 图片,CLOB,多张逗号分隔
+            Remark: string; // 备注,最大允许256个字符
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻预售申请响应 */
+        interface GZPresaleApplyRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            SellUserID: number; // 发行方用户
+            PresaleApplyID: number; // 预售申请ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻预售认购下单请求 */
+        interface GZPresaleOrderReq {
+            Header?: IMessageHead;
+            UserID: number; // 用户ID,必填
+            AccountID: number; // 资金账户ID,必填
+            WRTradeOrderID: number; // 仓单贸易委托单ID,必填
+            OrderQty: number; // 认购数量,必填
+            MarketID: number; // 市场ID,必填
+            ClientOrderTime: string; // 委托时间,必填
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻预售认购下单响应 */
+        interface GZPresaleOrderRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            UserID: number; // 用户ID
+            AccountID: number; // 资金账户ID
+            WRTradeOrderID: number; // 仓单贸易委托单ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻集采申请请求 */
+        interface GZCenterPurchaseApplyReq {
+            Header?: IMessageHead;
+            SellUserID: number; // 发行方用户,必填
+            SellAccountID: number; // 发行方资金账户ID,必填
+            WRStandardName: string; // 现货商品名称,必填
+            PresaleQty: number; // 预售总量,必填
+            MinBuyQty: number; // 单人最小申购量,必填
+            MaxBuyQty: number; // 单人最大申购量,必填
+            MinSuccessQty: number; // 最低成团量,必填
+            StartDate: string; // 预售开始日期,必填
+            EndDate: string; // 预售结束日期,必填
+            BuyMarginAlgorithm: number; // 买方保证金方式,必填
+            BuyMarginValue: number; // 买方保证金设置值,小数,四位,必填
+            PerformanceTemplateID: number; // 履约计划模板ID,必填
+            GZCenterPurchasePriceLists: GZCenterPurchasePrice[]; // 价格列表,必填
+            MarketID: number; // 市场ID,必填
+            YSZSCategory: number; // 预售钻石分类
+            ZSShapeTypeStr: string; // 形状,最大允许64个字符
+            ZSColorTypeStr: string; // 颜色,最大允许64个字符
+            ZSClarityTypeStr: string; // 净度,最大允许64个字符
+            ZSCutTypeStr: string; // 切工,最大允许64个字符
+            ZSSymmetryTypeStr: string; // 对称,最大允许64个字符
+            ZSPolishTypeStr: string; // 抛光,最大允许64个字符
+            ZSFluorescenceTypeStr: string; // 荧光,最大允许64个字符
+            SizeStr: string; // 尺寸,最大允许64个字符
+            YieldRate: string; // 成品率,最大允许64个字符
+            QtyDesc: string; // 数量描述,最大允许64个字符
+            WeightDesc: string; // 重量描述,最大允许64个字符
+            YSProductionMode: number; // 生产方式
+            PictureUrls: string; // 图片,CLOB,多张逗号分隔
+            Remark: string; // 备注,最大允许256个字符
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻集采价格列表 */
+        interface GZCenterPurchasePrice {
+            StepIndex: number; // 档位序号,必填
+            Qty: number; // 档位数量,必填
+            Price: number; // 档位价格,小数,两位,必填
+        }
+
+        /** 广钻集采申请响应 */
+        interface GZCenterPurchaseApplyRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            SellUserID: number; // 发行方用户
+            PresaleApplyID: number; // 预售申请ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻集采认购下单请求 */
+        interface GZCenterPurchaseOrderReq {
+            Header?: IMessageHead;
+            UserID: number; // 用户ID,必填
+            AccountID: number; // 资金账户ID,必填
+            WRTradeOrderID: number; // 仓单贸易委托单ID,必填
+            OrderQty: number; // 认购数量,必填
+            MarketID: number; // 市场ID,必填
+            ClientOrderTime: string; // 委托时间,必填
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 广钻集采认购下单响应 */
+        interface GZCenterPurchaseOrderRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            UserID: number; // 用户ID
+            AccountID: number; // 资金账户ID
+            WRTradeOrderID: number; // 仓单贸易委托单ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+    }
+}