li.shaoyi 1 год назад
Родитель
Сommit
7169355694
75 измененных файлов с 2965 добавлено и 37 удалено
  1. 5 0
      .env.thj
  2. 5 0
      .env.thj@pc
  3. 1 1
      app/package.json
  4. 7 1
      file/android/fxgl.txt
  5. 34 0
      file/南海国际.ai
  6. 33 0
      file/铁合金掌上行 LOGO 定稿 源文件.ai
  7. 2 2
      oem/gstj/config/appconfig.json
  8. 0 18
      oem/gzcj/config/router.json
  9. 2 2
      oem/qdhs/config/appconfig.json
  10. 27 0
      oem/thj/androidPrivacy.json
  11. BIN
      oem/thj/app/icons/1024x1024.png
  12. BIN
      oem/thj/app/icons/120x120.png
  13. BIN
      oem/thj/app/icons/144x144.png
  14. BIN
      oem/thj/app/icons/152x152.png
  15. BIN
      oem/thj/app/icons/167x167.png
  16. BIN
      oem/thj/app/icons/180x180.png
  17. BIN
      oem/thj/app/icons/192x192.png
  18. BIN
      oem/thj/app/icons/20x20.png
  19. BIN
      oem/thj/app/icons/29x29.png
  20. BIN
      oem/thj/app/icons/40x40.png
  21. BIN
      oem/thj/app/icons/58x58.png
  22. BIN
      oem/thj/app/icons/60x60.png
  23. BIN
      oem/thj/app/icons/72x72.png
  24. BIN
      oem/thj/app/icons/76x76.png
  25. BIN
      oem/thj/app/icons/80x80.png
  26. BIN
      oem/thj/app/icons/87x87.png
  27. BIN
      oem/thj/app/icons/96x96.png
  28. BIN
      oem/thj/app/splashscreen/1080x1920.png
  29. BIN
      oem/thj/app/splashscreen/480x853.png
  30. BIN
      oem/thj/app/splashscreen/720x1280.png
  31. 15 0
      oem/thj/config/appconfig.json
  32. 410 0
      oem/thj/config/router.json
  33. BIN
      oem/thj/favicon.ico
  34. BIN
      oem/thj/logo/logo-horizontal.png
  35. 303 0
      oem/thj/manifest.json
  36. BIN
      src/packages/gzcj/assets/images/login-logo.png
  37. 2 2
      src/packages/mobile/views/bank/wallet/components/deposit/Index.vue
  38. 2 2
      src/packages/mobile/views/bank/wallet/components/withdraw/Index.vue
  39. 2 2
      src/packages/pc/views/footer/swap/position/close/index.vue
  40. 5 1
      src/packages/sbyj/views/home/main/index.less
  41. 5 1
      src/packages/sbyj/views/home/main/index.vue
  42. 37 0
      src/packages/sbyj/views/market/detail/index.less
  43. 34 2
      src/packages/sbyj/views/market/detail/index.vue
  44. 3 1
      src/packages/sbyj/views/order/list/components/close-holder/index.vue
  45. 3 1
      src/packages/sbyj/views/order/list/components/market-order-delivery/index.vue
  46. 54 0
      src/packages/thj/App.vue
  47. BIN
      src/packages/thj/assets/images/avatar.jpg
  48. BIN
      src/packages/thj/assets/images/avatar.png
  49. BIN
      src/packages/thj/assets/images/block-bg.png
  50. BIN
      src/packages/thj/assets/images/certification.png
  51. BIN
      src/packages/thj/assets/images/guide-1.png
  52. BIN
      src/packages/thj/assets/images/guide-2.png
  53. BIN
      src/packages/thj/assets/images/login-logo.png
  54. 10 0
      src/packages/thj/assets/themes/dark/dark.less
  55. 70 0
      src/packages/thj/assets/themes/default/default.less
  56. 562 0
      src/packages/thj/assets/themes/global/global.less
  57. 6 0
      src/packages/thj/assets/themes/light/light.less
  58. 5 0
      src/packages/thj/assets/themes/style.less
  59. 71 0
      src/packages/thj/index.html
  60. 34 0
      src/packages/thj/main.ts
  61. 10 0
      src/packages/thj/postcss.config.js
  62. 314 0
      src/packages/thj/router/index.ts
  63. 99 0
      src/packages/thj/views/boot/Index.vue
  64. 19 0
      src/packages/thj/views/boot/index.less
  65. 131 0
      src/packages/thj/views/home/main/Index.vue
  66. 125 0
      src/packages/thj/views/home/main/index.less
  67. 216 0
      src/packages/thj/views/mine/Index.vue
  68. 167 0
      src/packages/thj/views/mine/index.less
  69. 20 0
      src/packages/thj/views/order/delivery/Index.vue
  70. 59 0
      src/packages/thj/views/order/list/Index.vue
  71. 34 0
      src/packages/thj/views/order/position/Index.vue
  72. 13 0
      src/packages/thj/views/user/login/Index.vue
  73. 2 0
      src/stores/modules/futures.ts
  74. 6 1
      src/stores/modules/position.ts
  75. 1 0
      src/types/model/market.d.ts

+ 5 - 0
.env.thj

@@ -0,0 +1,5 @@
+VUE_APP_ENV = 'thj'
+VUE_APP_NAME = 铁合金掌上行
+VUE_APP_ROOT = src/packages/thj/
+VUE_APP_OEM = oem/thj/
+VUE_APP_TRADE_CHANNEL = ws

+ 5 - 0
.env.thj@pc

@@ -0,0 +1,5 @@
+VUE_APP_ENV = 'pc'
+VUE_APP_NAME = 铁合金掌上行
+VUE_APP_ROOT = src/packages/pc/
+VUE_APP_OEM = oem/thj/
+VUE_APP_TRADE_CHANNEL = ws

+ 1 - 1
app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "trading",
-  "version": "1.0.13",
+  "version": "1.0.25",
   "main": "main.js",
   "dependencies": {
     "electron-updater": "^6.1.4",

+ 7 - 1
file/android/fxgl.txt

@@ -80,4 +80,10 @@ cn.muchinfo.gcszt_demo_v1.0.0.apk
 http://47.104.153.69:8280/cfg?key=gc_mnp
 实盘
 cn.muchinfo.gcszt_release_v1.0.0.apk
-http://118.190.217.127:8280/cfg?key=szt_sp
+http://118.190.217.127:8280/cfg?key=szt_sp
+
+
+贵州茶交
+模拟盘
+cn.muchinfo.gzcj_demo_v1.0.0.apk
+http://140.210.215.73:8280/cfg?key=gzcj_demo

Разница между файлами не показана из-за своего большого размера
+ 34 - 0
file/南海国际.ai


Разница между файлами не показана из-за своего большого размера
+ 33 - 0
file/铁合金掌上行 LOGO 定稿 源文件.ai


+ 2 - 2
oem/gstj/config/appconfig.json

@@ -1,8 +1,8 @@
 {
   "appId": "com.muchinfo.gstj",
   "appName": "甘肃碳交",
-  "version": "1.0.24",
-  "versionCode": "100024",
+  "version": "1.0.25",
+  "versionCode": "100025",
   "apiUrl": "http://192.168.31.205:8080/cfg?key=test_205",
   "tradeChannel": "ws",
   "modules": [

+ 0 - 18
oem/gzcj/config/router.json

@@ -505,24 +505,6 @@
             },
             {
                 "authType": 1,
-                "sort": 2,
-                "title": "入金代扣签约",
-                "code": "account_holdsign",
-                "url": "address",
-                "urlType": 1,
-                "component": "views/account/holdsign/index.vue"
-            },
-            {
-                "authType": 1,
-                "sort": 3,
-                "title": "入金代扣申请",
-                "code": "account_holddeposit",
-                "url": "address",
-                "urlType": 1,
-                "component": "views/account/holddeposit/index.vue"
-            },
-            {
-                "authType": 1,
                 "sort": 4,
                 "title": "收货地址管理",
                 "code": "account_address",

+ 2 - 2
oem/qdhs/config/appconfig.json

@@ -1,8 +1,8 @@
 {
   "appId": "com.muchinfo.qdhs",
   "appName": "青岛海商",
-  "version": "1.0.13",
-  "versionCode": "100013",
+  "version": "1.0.14",
+  "versionCode": "100014",
   "apiUrl": "http://192.168.31.204:8080/cfg?key=test_204",
   "tradeChannel": "ws",
   "modules": [

+ 27 - 0
oem/thj/androidPrivacy.json

@@ -0,0 +1,27 @@
+{
+    "version": "1",
+    "prompt": "template",
+    "title": "隐私政策",
+    "message": "  请你务必审慎阅读、充分理解“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/>  你可阅读<a href=\"html/yszc.htm\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
+    "buttonAccept": "同意并接受",
+    "buttonRefuse": "拒绝",
+    "hrefLoader": "system|default",
+    "second": {
+        "title": "确认提示",
+        "message": "  进入应用前,你需先同意<a href=\"html/yszc.htm\">《隐私政策》</a>,否则将退出应用。",
+        "buttonAccept": "同意并继续",
+        "buttonRefuse": "退出应用"
+    },
+    "disagreeMode": {
+        "support": false,
+        "loadNativePlugins": false,
+        "visitorEntry": true,
+        "showAlways": true
+    },
+    "styles": {
+        "borderRadius": "5px",
+        "buttonAccept": {
+            "color": "#ee0a24"
+        }
+    }
+}

BIN
oem/thj/app/icons/1024x1024.png


BIN
oem/thj/app/icons/120x120.png


BIN
oem/thj/app/icons/144x144.png


BIN
oem/thj/app/icons/152x152.png


BIN
oem/thj/app/icons/167x167.png


BIN
oem/thj/app/icons/180x180.png


BIN
oem/thj/app/icons/192x192.png


BIN
oem/thj/app/icons/20x20.png


BIN
oem/thj/app/icons/29x29.png


BIN
oem/thj/app/icons/40x40.png


BIN
oem/thj/app/icons/58x58.png


BIN
oem/thj/app/icons/60x60.png


BIN
oem/thj/app/icons/72x72.png


BIN
oem/thj/app/icons/76x76.png


BIN
oem/thj/app/icons/80x80.png


BIN
oem/thj/app/icons/87x87.png


BIN
oem/thj/app/icons/96x96.png


BIN
oem/thj/app/splashscreen/1080x1920.png


BIN
oem/thj/app/splashscreen/480x853.png


BIN
oem/thj/app/splashscreen/720x1280.png


+ 15 - 0
oem/thj/config/appconfig.json

@@ -0,0 +1,15 @@
+{
+  "appId": "com.muchinfo.thj",
+  "appName": "铁合金掌上行",
+  "version": "1.0.0",
+  "versionCode": "100000",
+  "apiUrl": "http://192.168.31.132:8080/cfg?key=test_132",
+  "tradeChannel": "ws",
+  "modules": [
+    "register",
+    "delivery"
+  ],
+  "quotationPropertys": [
+    "totalvolume"
+  ]
+}

+ 410 - 0
oem/thj/config/router.json

@@ -0,0 +1,410 @@
+[
+    {
+        "authType": 2,
+        "sort": 0,
+        "title": "底部单据菜单",
+        "code": "bottom",
+        "children": [
+            {
+                "authType": 2,
+                "sort": 4,
+                "title": "掉期市场",
+                "code": "bottom_swap",
+                "component": "views/footer/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "持仓汇总",
+                        "code": "bottom_swap_position",
+                        "component": "views/footer/swap/position/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "委托",
+                        "code": "bottom_swap_order",
+                        "component": "views/footer/swap/order/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 3,
+                        "title": "成交",
+                        "code": "bottom_swap_trade",
+                        "component": "views/footer/swap/trade/index.vue"
+                    }
+                ]
+            },
+            {
+                "authType": 2,
+                "sort": 3,
+                "title": "现货仓单",
+                "code": "bottom_spot",
+                "component": "views/footer/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "现货明细",
+                        "code": "bottom_spot_position",
+                        "component": "views/footer/spot/position/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "挂单",
+                        "code": "bottom_spot_order",
+                        "component": "views/footer/spot/order/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 3,
+                        "title": "成交",
+                        "code": "bottom_spot_trade",
+                        "component": "views/footer/spot/trade/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 4,
+                        "title": "提货",
+                        "code": "bottom_spot_pickup",
+                        "component": "views/footer/spot/pickup/index.vue"
+                    }
+                ]
+            },
+            {
+                "authType": 2,
+                "sort": 4,
+                "title": "履约信息",
+                "code": "bottom_performance",
+                "component": "views/footer/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "买履约",
+                        "code": "bottom_performance_buy",
+                        "component": "views/footer/performance/buy/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "卖履约",
+                        "code": "bottom_performance_sell",
+                        "component": "views/footer/performance/sell/index.vue"
+                    }
+                ]
+            },
+            {
+                "authType": 2,
+                "sort": 5,
+                "title": "资金信息",
+                "code": "bottom_capital",
+                "component": "views/footer/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "资金汇总",
+                        "code": "bottom_capital_summary",
+                        "component": "views/footer/capital/summary/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "资金流水",
+                        "code": "bottom_capital_statement",
+                        "component": "views/footer/capital/statement/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 3,
+                        "title": "出入金明细",
+                        "code": "bottom_capital_inoutapply",
+                        "component": "views/footer/capital/inoutapply/index.vue"
+                    }
+                ]
+            }
+        ]
+    },
+    {
+        "authType": 1,
+        "sort": 1,
+        "title": "掉期市场",
+        "code": "market",
+        "url": "/market",
+        "urlType": 1,
+        "component": "Page",
+        "icon": "TrendCharts",
+        "children": [
+            {
+                "authType": 1,
+                "sort": 1,
+                "title": "掉期市场",
+                "code": "market_trade",
+                "url": "trade",
+                "urlType": 1,
+                "component": "views/market/trade/index.vue"
+            }
+        ]
+    },
+    {
+        "authType": 1,
+        "sort": 2,
+        "title": "查询",
+        "code": "query",
+        "url": "/query",
+        "urlType": 1,
+        "component": "Page",
+        "icon": "TrendCharts",
+        "children": [
+            {
+                "authType": 1,
+                "sort": 1,
+                "title": "委托记录",
+                "code": "query_order",
+                "url": "order",
+                "urlType": 1,
+                "component": "Main",
+                "children": [
+                    {
+                        "authType": 1,
+                        "sort": 1,
+                        "title": "掉期市场",
+                        "code": "query_order_swap",
+                        "url": "swap",
+                        "urlType": 1,
+                        "component": "views/query/order/swap/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_order_swap_list",
+                                "component": "views/query/order/swap/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_order_swap_history",
+                                "component": "views/query/order/swap/history/index.vue"
+                            }
+                        ]
+                    },
+                    {
+                        "authType": 1,
+                        "sort": 2,
+                        "title": "现货仓单",
+                        "code": "query_order_spot",
+                        "url": "spot",
+                        "urlType": 1,
+                        "component": "views/query/order/spot/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_order_spot_list",
+                                "component": "views/query/order/spot/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_order_spot_history",
+                                "component": "views/query/order/spot/history/index.vue"
+                            }
+                        ]
+                    }
+                ]
+            },
+            {
+                "authType": 1,
+                "sort": 2,
+                "title": "成交记录",
+                "code": "query_trade",
+                "url": "trade",
+                "urlType": 1,
+                "component": "Main",
+                "children": [
+                    {
+                        "authType": 1,
+                        "sort": 1,
+                        "title": "掉期市场",
+                        "code": "query_trade_swap",
+                        "url": "swap",
+                        "urlType": 1,
+                        "component": "views/query/trade/swap/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_trade_swap_list",
+                                "component": "views/query/trade/swap/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_trade_swap_history",
+                                "component": "views/query/trade/swap/history/index.vue"
+                            }
+                        ]
+                    },
+                    {
+                        "authType": 1,
+                        "sort": 2,
+                        "title": "现货仓单",
+                        "code": "query_trade_spot",
+                        "url": "spot",
+                        "urlType": 1,
+                        "component": "views/query/trade/spot/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_trade_spot_list",
+                                "component": "views/query/trade/spot/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_trade_spot_history",
+                                "component": "views/query/trade/spot/history/index.vue"
+                            }
+                        ]
+                    }
+                ]
+            },
+            {
+                "authType": 1,
+                "sort": 3,
+                "title": "资金流水",
+                "code": "query_capital",
+                "url": "capital",
+                "urlType": 1,
+                "component": "views/query/capital/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "当前记录",
+                        "code": "query_capital_list",
+                        "component": "views/query/capital/list/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "历史记录",
+                        "code": "query_capital_history",
+                        "component": "views/query/capital/history/index.vue"
+                    }
+                ]
+            },
+            {
+                "authType": 1,
+                "sort": 4,
+                "title": "履约查询",
+                "code": "query_performance",
+                "url": "performance",
+                "urlType": 1,
+                "component": "Main",
+                "children": [
+                    {
+                        "authType": 1,
+                        "sort": 1,
+                        "title": "买履约",
+                        "code": "query_performance_buy",
+                        "url": "buy",
+                        "urlType": 1,
+                        "component": "views/query/performance/buy/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "执行中",
+                                "code": "query_performance_buy_running",
+                                "component": "views/query/performance/buy/running/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "全部",
+                                "code": "query_performance_buy_all",
+                                "component": "views/query/performance/buy/all/index.vue"
+                            }
+                        ]
+                    },
+                    {
+                        "authType": 1,
+                        "sort": 2,
+                        "title": "卖履约",
+                        "code": "query_performance_sell",
+                        "url": "sell",
+                        "urlType": 1,
+                        "component": "views/query/performance/sell/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "执行中",
+                                "code": "query_performance_sell_running",
+                                "component": "views/query/performance/sell/running/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "全部",
+                                "code": "query_performance_sell_all",
+                                "component": "views/query/performance/sell/all/index.vue"
+                            }
+                        ]
+                    }
+                ]
+            }
+        ]
+    },
+    {
+        "authType": 1,
+        "sort": 3,
+        "title": "账户管理",
+        "code": "account",
+        "url": "/account",
+        "urlType": 1,
+        "component": "Page",
+        "icon": "TrendCharts",
+        "children": [
+            {
+                "authType": 1,
+                "sort": 1,
+                "title": "签约账号管理",
+                "code": "account_sign",
+                "url": "sign",
+                "urlType": 1,
+                "component": "views/account/sign/index.vue"
+            },
+            {
+                "authType": 1,
+                "sort": 2,
+                "title": "收货地址管理",
+                "code": "account_address",
+                "url": "address",
+                "urlType": 1,
+                "component": "views/account/address/index.vue"
+            },
+            {
+                "authType": 1,
+                "sort": 3,
+                "title": "发票信息管理",
+                "code": "account_receipt",
+                "url": "receipt",
+                "urlType": 1,
+                "component": "views/account/receipt/index.vue"
+            }
+        ]
+    }
+]

BIN
oem/thj/favicon.ico


BIN
oem/thj/logo/logo-horizontal.png


+ 303 - 0
oem/thj/manifest.json

@@ -0,0 +1,303 @@
+{
+    "@platforms" : [ "android", "iPhone", "iPad" ],
+    "id" : "H5E4A9458",
+    /*应用的标识*/
+    "name" : "海南掉期市场",
+    /*应用名称,程序桌面图标名称*/
+    "version" : {
+        "name" : "1.0.13",
+        /*应用版本名称*/
+        "code" : 100013
+    },
+    "description" : "",
+    /*应用描述信息*/
+    "icons" : {
+        "72" : "icon.png"
+    },
+    "launch_path" : "index.html",
+    /*应用的入口页面,默认为根目录下的index.html;支持网络地址,必须以http://或https://开头*/
+    "developer" : {
+        "name" : "",
+        /*开发者名称*/
+        "email" : "",
+        /*开发者邮箱地址*/
+        "url" : "" /*开发者个人主页地址*/
+    },
+    "permissions" : {
+        "Accelerometer" : {
+            "description" : "访问加速度感应器"
+        },
+        "Audio" : {
+            "description" : "访问麦克风"
+        },
+        "Cache" : {
+            "description" : "管理应用缓存"
+        },
+        "Camera" : {
+            "description" : "访问摄像头"
+        },
+        "Console" : {
+            "description" : "跟踪调试输出日志"
+        },
+        "Device" : {
+            "description" : "访问设备信息"
+        },
+        "Downloader" : {
+            "description" : "文件下载管理"
+        },
+        "Events" : {
+            "description" : "应用扩展事件"
+        },
+        "File" : {
+            "description" : "访问本地文件系统"
+        },
+        "Gallery" : {
+            "description" : "访问系统相册"
+        },
+        "Invocation" : {
+            "description" : "使用Native.js能力"
+        },
+        "Orientation" : {
+            "description" : "访问方向感应器"
+        },
+        "Proximity" : {
+            "description" : "访问距离感应器"
+        },
+        "Storage" : {
+            "description" : "管理应用本地数据"
+        },
+        "Uploader" : {
+            "description" : "管理文件上传任务"
+        },
+        "Runtime" : {
+            "description" : "访问运行期环境"
+        },
+        "XMLHttpRequest" : {
+            "description" : "跨域网络访问"
+        },
+        "Zip" : {
+            "description" : "文件压缩与解压缩"
+        },
+        "Barcode" : {
+            "description" : "管理二维码扫描插件"
+        },
+        "Webview" : {
+            "description" : "窗口管理"
+        },
+        "NativeUI" : {
+            "description" : "原生UI控件"
+        },
+        "Navigator" : {
+            "description" : "浏览器信息"
+        },
+        "NativeObj" : {
+            "description" : "原生对象"
+        },
+        "Share" : {}
+    },
+    "plus" : {
+        "modules" : {
+            "Barcode" : {},
+            "Camera" : {},
+            "Gallery" : {},
+            "Share" : {}
+        },
+        "statusbar" : {
+            "immersed" : true /*沉浸式状态栏。*/
+        },
+        "splashscreen" : {
+            "autoclose" : true,
+            /*是否自动关闭程序启动界面,true表示应用加载应用入口页面后自动关闭;false则需调plus.navigator.closeSplashscreen()关闭*/
+            "waiting" : true /*是否在程序启动界面显示等待雪花,true表示显示,false表示不显示。*/
+        },
+        "popGesture" : "close",
+        /*设置应用默认侧滑返回关闭Webview窗口,"none"为无侧滑返回功能,"hide"为侧滑隐藏Webview窗口。参考http://ask.dcloud.net.cn/article/102*/
+        "runmode" : "liberate",
+        /*应用的首次启动运行模式,可取liberate或normal,liberate模式在第一次启动时将解压应用资源(Android平台File API才可正常访问_www目录)*/
+        "signature" : "Sk9JTiBVUyBtYWlsdG86aHIyMDEzQGRjbG91ZC5pbw==",
+        /*可选,保留给应用签名,暂不使用*/
+        "distribute" : {
+            "apple" : {
+                "appid" : "",
+                /*iOS应用标识,苹果开发网站申请的appid,如io.dcloud.HelloH5*/
+                "mobileprovision" : "",
+                /*iOS应用打包配置文件*/
+                "password" : "",
+                /*iOS应用打包个人证书导入密码*/
+                "p12" : "",
+                /*iOS应用打包个人证书,打包配置文件关联的个人证书*/
+                "devices" : "universal",
+                /*iOS应用支持的设备类型,可取值iphone/ipad/universal*/
+                "frameworks" : [], /*调用Native.js调用原生Objective-c API需要引用的FrameWork,如需调用GameCenter,则添加"GameKit.framework"*/
+                "idfa" : false,
+                "privacyDescription" : {
+                    "NSCameraUsageDescription" : "访问您的相册用来上传您的图像用来设置头像!",
+                    "NSPhotoLibraryAddUsageDescription" : "访问您的相册保存图像用来设置头像!",
+                    "NSPhotoLibraryUsageDescription" : "访问您的摄像头用来拍照上传您的图像用来设置头像!"
+                }
+            },
+            "google" : {
+                "packagename" : "",
+                /*Android应用包名,如io.dcloud.HelloH5*/
+                "keystore" : "",
+                /*Android应用打包使用的密钥库文件*/
+                "password" : "",
+                /*Android应用打包使用密钥库中证书的密码*/
+                "aliasname" : "",
+                /*Android应用打包使用密钥库中证书的别名*/
+                "permissions" : [
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.BIND_INPUT_METHOD\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>"
+                ],
+                "abiFilters" : [ "armeabi-v7a", "arm64-v8a" ],
+                "autoSdkPermissions" : false,
+                "minSdkVersion" : 26
+            },
+            /*使用Native.js调用原生安卓API需要使用到的系统权限*/
+            "orientation" : [ "portrait-primary" ],
+            /*应用支持的方向,portrait-primary:竖屏正方向;portrait-secondary:竖屏反方向;landscape-primary:横屏正方向;landscape-secondary:横屏反方向*/
+            "icons" : {
+                "ios" : {
+                    "prerendered" : true,
+                    /*应用图标是否已经高亮处理,在iOS6及以下设备上有效*/
+                    "auto" : "",
+                    /*应用图标,分辨率:512x512,用于自动生成各种尺寸程序图标*/
+                    "iphone" : {
+                        "normal" : "",
+                        /*iPhone3/3GS程序图标,分辨率:57x57*/
+                        "retina" : "",
+                        /*iPhone4程序图标,分辨率:114x114*/
+                        "retina7" : "",
+                        /*iPhone4S/5/6程序图标,分辨率:120x120*/
+                        "retina8" : "",
+                        /*iPhone6 Plus程序图标,分辨率:180x180*/
+                        "spotlight-normal" : "",
+                        /*iPhone3/3GS Spotlight搜索程序图标,分辨率:29x29*/
+                        "spotlight-retina" : "",
+                        /*iPhone4 Spotlight搜索程序图标,分辨率:58x58*/
+                        "spotlight-retina7" : "",
+                        /*iPhone4S/5/6 Spotlight搜索程序图标,分辨率:80x80*/
+                        "settings-normal" : "",
+                        /*iPhone4设置页面程序图标,分辨率:29x29*/
+                        "settings-retina" : "",
+                        /*iPhone4S/5/6设置页面程序图标,分辨率:58x58*/
+                        "settings-retina8" : "", /*iPhone6Plus设置页面程序图标,分辨率:87x87*/
+                        "app@2x" : "app/icons/120x120.png",
+                        "app@3x" : "app/icons/180x180.png",
+                        "notification@2x" : "app/icons/40x40.png",
+                        "notification@3x" : "app/icons/60x60.png",
+                        "settings@2x" : "app/icons/58x58.png",
+                        "settings@3x" : "app/icons/87x87.png",
+                        "spotlight@2x" : "app/icons/80x80.png",
+                        "spotlight@3x" : "app/icons/120x120.png"
+                    },
+                    "ipad" : {
+                        "normal" : "",
+                        /*iPad普通屏幕程序图标,分辨率:72x72*/
+                        "retina" : "",
+                        /*iPad高分屏程序图标,分辨率:144x144*/
+                        "normal7" : "",
+                        /*iPad iOS7程序图标,分辨率:76x76*/
+                        "retina7" : "",
+                        /*iPad iOS7高分屏程序图标,分辨率:152x152*/
+                        "spotlight-normal" : "",
+                        /*iPad Spotlight搜索程序图标,分辨率:50x50*/
+                        "spotlight-retina" : "",
+                        /*iPad高分屏Spotlight搜索程序图标,分辨率:100x100*/
+                        "spotlight-normal7" : "",
+                        /*iPad iOS7 Spotlight搜索程序图标,分辨率:40x40*/
+                        "spotlight-retina7" : "",
+                        /*iPad iOS7高分屏Spotlight搜索程序图标,分辨率:80x80*/
+                        "settings-normal" : "",
+                        /*iPad设置页面程序图标,分辨率:29x29*/
+                        "settings-retina" : "", /*iPad高分屏设置页面程序图标,分辨率:58x58*/
+                        "app" : "app/icons/76x76.png",
+                        "app@2x" : "app/icons/152x152.png",
+                        "notification" : "app/icons/20x20.png",
+                        "notification@2x" : "app/icons/40x40.png",
+                        "proapp@2x" : "app/icons/167x167.png",
+                        "settings" : "app/icons/29x29.png",
+                        "settings@2x" : "app/icons/58x58.png",
+                        "spotlight" : "app/icons/40x40.png",
+                        "spotlight@2x" : "app/icons/80x80.png"
+                    },
+                    "appstore" : "app/icons/1024x1024.png"
+                },
+                "android" : {
+                    "mdpi" : "",
+                    /*普通屏程序图标,分辨率:48x48*/
+                    "ldpi" : "",
+                    /*大屏程序图标,分辨率:48x48*/
+                    "hdpi" : "app/icons/72x72.png",
+                    /*高分屏程序图标,分辨率:72x72*/
+                    "xhdpi" : "app/icons/96x96.png",
+                    /*720P高分屏程序图标,分辨率:96x96*/
+                    "xxhdpi" : "app/icons/144x144.png", /*1080P 高分屏程序图标,分辨率:144x144*/
+                    "xxxhdpi" : "app/icons/192x192.png"
+                }
+            },
+            "splashscreen" : {
+                "ios" : {
+                    "iphone" : {
+                        "default" : "",
+                        /*iPhone3启动图片选,分辨率:320x480*/
+                        "retina35" : "",
+                        /*3.5英寸设备(iPhone4)启动图片,分辨率:640x960*/
+                        "retina40" : "",
+                        /*4.0 英寸设备(iPhone5/iPhone5s)启动图片,分辨率:640x1136*/
+                        "retina47" : "",
+                        /*4.7 英寸设备(iPhone6)启动图片,分辨率:750x1334*/
+                        "retina55" : "",
+                        /*5.5 英寸设备(iPhone6 Plus)启动图片,分辨率:1242x2208*/
+                        "retina55l" : "" /*5.5 英寸设备(iPhone6 Plus)横屏启动图片,分辨率:2208x1242*/
+                    },
+                    "ipad" : {
+                        "portrait" : "",
+                        /*iPad竖屏启动图片,分辨率:768x1004*/
+                        "portrait-retina" : "",
+                        /*iPad高分屏竖屏图片,分辨率:1536x2008*/
+                        "landscape" : "",
+                        /*iPad横屏启动图片,分辨率:1024x748*/
+                        "landscape-retina" : "",
+                        /*iPad高分屏横屏启动图片,分辨率:2048x1496*/
+                        "portrait7" : "",
+                        /*iPad iOS7竖屏启动图片,分辨率:768x1024*/
+                        "portrait-retina7" : "",
+                        /*iPad iOS7高分屏竖屏图片,分辨率:1536x2048*/
+                        "landscape7" : "",
+                        /*iPad iOS7横屏启动图片,分辨率:1024x768*/
+                        "landscape-retina7" : "" /*iPad iOS7高分屏横屏启动图片,分辨率:2048x1536*/
+                    },
+                    "storyboard" : "../ios/CustomStoryborad.zip"
+                },
+                "android" : {
+                    "mdpi" : "",
+                    /*普通屏启动图片,分辨率:240x282*/
+                    "ldpi" : "",
+                    /*大屏启动图片,分辨率:320x442*/
+                    "hdpi" : "app/splashscreen/480x853.png",
+                    /*高分屏启动图片,分辨率:480x762*/
+                    "xhdpi" : "app/splashscreen/720x1280.png",
+                    /*720P高分屏启动图片,分辨率:720x1242*/
+                    "xxhdpi" : "app/splashscreen/1080x1920.png" /*1080P高分屏启动图片,分辨率:1080x1882*/
+                },
+                "androidStyle" : "default",
+                "iosStyle" : "common",
+                "useOriginalMsgbox" : true
+            },
+            "plugins" : {
+                "ad" : {},
+                "geolocation" : {},
+                "share" : {}
+            },
+            "ios" : {
+                "dSYMs" : false
+            }
+        }
+    },
+    "screenOrientation" : [ "portrait-primary" ]
+}

BIN
src/packages/gzcj/assets/images/login-logo.png


+ 2 - 2
src/packages/mobile/views/bank/wallet/components/deposit/Index.vue

@@ -38,8 +38,8 @@
                 </div>
             </div>
             <CellGroup inset v-if="msg_324">
-                <Cell title="提示" icon="info-o">
-                    <template #label><p class="tips" v-html="msg_324" /></template>
+                <Cell title="提示">
+                    <template #label><p v-html="msg_324" /></template>
                 </Cell>
             </CellGroup>
         </Form>

+ 2 - 2
src/packages/mobile/views/bank/wallet/components/withdraw/Index.vue

@@ -34,8 +34,8 @@
                 <span class="msg_tips"><br>节假日以通知、公告为准;非交易日请勿操作!</span>
             </div>
             <CellGroup inset v-if="msg_317">
-                <Cell title="提示" icon="info-o">
-                    <template #label><p class="tips" v-html="msg_317" /></template>
+                <Cell title="提示">
+                    <template #label><p v-html="msg_317" /></template>
                 </Cell>
             </CellGroup>
             <CellGroup inset v-if="cusBank.canoutamount === 0">

+ 2 - 2
src/packages/pc/views/footer/swap/position/close/index.vue

@@ -1,6 +1,6 @@
 <!-- 掉期市场-持仓汇总-平仓 -->
 <template>
-    <app-drawer :title="`${position.goodscode}/${position.goodsname}`" v-model:show="show" :width="1200" :loading="loading"
+    <app-drawer :title="`${position.goodscode}/${position.goodsname}`" v-model:show="show" :width="1100" :loading="loading"
         :refresh="refresh">
         <app-table :data="computedList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey"
             :expand-row-keys="expandKeys" @row-click="rowClick">
@@ -26,7 +26,7 @@
             </template>
             <!-- 操作 -->
             <template #operate="{ row }">
-                <div class="buttonbar" v-if="useStore.userType === 5">
+                <div class="buttonbar" v-if="useStore.userType === 5 && [1, 3].includes(quote?.goodstradetype ?? 0)">
                     <el-button type="danger" size="small" @click="onCloseSubmit(row)">平仓</el-button>
                 </div>
                 <span v-else>--</span>

+ 5 - 1
src/packages/sbyj/views/home/main/index.less

@@ -40,7 +40,7 @@
                 display: flex;
                 flex-direction: column;
                 align-items: center;
-                width: calc(~'100% / 3');
+                width: calc(~'100% / 4');
                 text-align: center;
 
                 .g-icon {
@@ -62,6 +62,10 @@
                     &-delivery--line {
                         background-color: #9d6969;
                     }
+
+                    &-pickup--line {
+                        background-color: #69869d;
+                    }
                 }
             }
         }

+ 5 - 1
src/packages/sbyj/views/home/main/index.vue

@@ -21,11 +21,15 @@
           <li @click="routerTo('delivery-list')">
             <Iconfont label-direction="bottom" icon="g-icon-delivery--line">交料订单</Iconfont>
           </li>
+          <li @click="routerTo('pickup-list')">
+            <Iconfont label-direction="bottom" icon="g-icon-pickup--line">提料订单</Iconfont>
+          </li>
         </ul>
       </app-block>
       <app-block class="home-main__news">
         <CellGroup class="article">
-          <Cell class="home-main__titlebar" title="市场资讯" value="更多" icon="fire" @click="routerTo('home-news', true)" is-link />
+          <Cell class="home-main__titlebar" title="市场资讯" value="更多" icon="fire" @click="routerTo('home-news', true)"
+            is-link />
           <template v-for="(item, index) in newsList" :key="index">
             <Cell class="article-item" :title="item.data.content" :value="formatDate(item.time, 'MM/DD')"
               @click="routerTo('home-news', true)" />

+ 37 - 0
src/packages/sbyj/views/market/detail/index.less

@@ -56,8 +56,45 @@
     }
 
     &__list {
+        padding: 10px;
+
         .g-order-list {
             padding: 10px;
         }
+
+        table {
+            width: 100%;
+            text-align: center;
+            border-radius: 10px;
+            overflow: hidden;
+
+            tr {
+                td {
+                    padding-bottom: 1px;
+
+                    >span {
+                        display: block;
+                        background-color: #fff;
+                        padding: 14px 0;
+                    }
+                }
+            }
+        }
+    }
+
+    &__ul {
+        text-align: center;
+        padding: 10px;
+
+        li {
+            display: flex;
+            background-color: #fff;
+            padding: 10px 0;
+            margin-bottom: 10px;
+
+            span {
+                flex: 1;
+            }
+        }
     }
 }

+ 34 - 2
src/packages/sbyj/views/market/detail/index.vue

@@ -36,7 +36,37 @@
                 <Button type="danger" @click="commit(BuyOrSell.Buy)" block square>我要买料</Button>
             </div>
         </div>
+        <!-- <ul class="market-detail__ul">
+            <li v-for="(item, index) in orderList" :key="index">
+                <span>{{ item.tHDetailEx.buyOrSell === BuyOrSell.Buy ? '买料:' : '卖料:' }}</span>
+                <span>{{ item.tHDetailEx.openQty * item.agreeUnit }}{{ getGoodsUnitName(item.goodsUnitID) }}</span>
+                <span>{{ formatDecimal(item.tHDetailEx.holderPrice) }}</span>
+                <span>{{ parsePercent(item.tHDetailEx.depositRate) }}</span>
+            </li>
+        </ul> -->
         <div class="market-detail__list">
+            <table cellspacing="0" cellpadding="0">
+                <tr v-for="(item, index) in orderList" :key="index">
+                    <td>
+                        <span :class="item.tHDetailEx.buyOrSell === BuyOrSell.Buy ? 'g-price-up' : 'g-price-down'">
+                            {{ item.tHDetailEx.buyOrSell === BuyOrSell.Buy ? '买料' : '卖料' }}
+                        </span>
+                    </td>
+                    <td>
+                        <span>{{ item.tHDetailEx.openQty * item.agreeUnit }}{{ getGoodsUnitName(item.goodsUnitID) }}</span>
+                    </td>
+                    <td>
+                        <span>{{ formatDecimal(item.tHDetailEx.holderPrice) }}</span>
+                    </td>
+                    <td>
+                        <span :class="item.tHDetailEx.depositRate <= item.tHDetailEx.promptDepositRate ? 'g-price-up' : ''">
+                            {{ parsePercent(item.tHDetailEx.depositRate) }}
+                        </span>
+                    </td>
+                </tr>
+            </table>
+        </div>
+        <div class="market-detail__list" v-if="false">
             <div class="g-order-list">
                 <div class="g-order-list__box" v-for="(item, index) in orderList" :key="index">
                     <div class="g-order-list__titlebar">
@@ -237,7 +267,9 @@ const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
 }
 
 const onRadioChange = (value: number) => {
-    orderQty.value = value
+    if (orderQty.value % agreeunit.value > 0) {
+        orderQty.value = value
+    }
 }
 
 const showComponent = (componentName: string, row: Model.SBYJMyOrderRsp) => {
@@ -258,7 +290,7 @@ onActivated(() => {
 
 onMounted(() => {
     subscribe.start(goodscode)
-    orderQty.value = agreeunit.value
+    orderQty.value = qtyStepList.value[0]
     qtyStep.value = qtyStepList.value[0]
     getSBYJMyOrders()
 })

+ 3 - 1
src/packages/sbyj/views/order/list/components/close-holder/index.vue

@@ -106,7 +106,9 @@ const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
 }
 
 const onRadioChange = (value: number) => {
-    orderQty.value = Math.min(enableqty.value, value)
+    if (orderQty.value % agreeunit.value > 0) {
+        orderQty.value = Math.min(enableqty.value, value)
+    }
 }
 
 // 下单

+ 3 - 1
src/packages/sbyj/views/order/list/components/market-order-delivery/index.vue

@@ -95,7 +95,9 @@ const getTagName = () => {
 }
 
 const onRadioChange = (value: number) => {
-    orderQty.value = Math.min(enableqty.value, value)
+    if (orderQty.value % agreeunit.value > 0) {
+        orderQty.value = Math.min(enableqty.value, value)
+    }
 }
 
 const onSubmit = () => {

+ 54 - 0
src/packages/thj/App.vue

@@ -0,0 +1,54 @@
+<template>
+  <router-view />
+  <Notify v-model:show="notify.show" :title="notify.title" :content="notify.content" />
+</template>
+
+<script lang="ts" setup>
+import { reactive } from 'vue'
+import { useNavigation } from '@mobile/router/navigation'
+import { dialog } from '@/utils/vant'
+import { useLogin } from '@/business/login'
+import eventBus from '@/services/bus'
+import Notify from '@mobile/components/base/notify/index.vue'
+
+const { userLogout } = useLogin()
+const { backHome } = useNavigation()
+
+const notify = reactive({
+  show: false,
+  title: '',
+  content: ''
+})
+
+// 接收用户登出通知
+eventBus.$on('LogoutNotify', (msg) => {
+  userLogout(() => {
+    if (msg) {
+      dialog({
+        message: msg as string,
+        confirmButtonText: '确定'
+      }).then(() => {
+        backHome()
+      })
+    } else {
+      backHome()
+    }
+  })
+})
+
+// 接收风控通知
+eventBus.$on('RiskToWebNtf', (msg, type) => {
+  const res = msg as { title: string, content: string }
+  if (type === 1) {
+    notify.title = res.title
+    notify.content = res.content
+    notify.show = true
+  } else {
+    dialog({
+      title: res.title,
+      message: res.content,
+      confirmButtonText: '确定'
+    })
+  }
+})
+</script>

BIN
src/packages/thj/assets/images/avatar.jpg


BIN
src/packages/thj/assets/images/avatar.png


BIN
src/packages/thj/assets/images/block-bg.png


BIN
src/packages/thj/assets/images/certification.png


BIN
src/packages/thj/assets/images/guide-1.png


BIN
src/packages/thj/assets/images/guide-2.png


BIN
src/packages/thj/assets/images/login-logo.png


+ 10 - 0
src/packages/thj/assets/themes/dark/dark.less

@@ -0,0 +1,10 @@
+[theme='dark'] {
+    /* 导航栏 */
+    --navbar-color     : #fff;
+    --navbar-background: #333;
+
+    /* 标签栏 */
+    --tabbar-background : #333;
+    --tabbar-icon       : #fff;
+    --tabbar-icon-active: #dc143c;
+}

+ 70 - 0
src/packages/thj/assets/themes/default/default.less

@@ -0,0 +1,70 @@
+:root {
+    /* 字体大小规范 */
+    --font-x-large: 18px;
+    --font-large: 16px;
+    --font-medium: 14px;
+    --font-small: 12px;
+    --font-x-small: 10px;
+
+    /* 颜色规范 */
+    --color-default: #384048;
+    --color-primary: #409EFF;
+    --color-secondary: #04c786;
+    --color-info: #999;
+    --color-border: #eee;
+    --color-up: #ff2b2b;
+    --color-down: #04c786;
+
+    /* 导航栏 */
+    --navbar-height: 44px;
+    --navbar-color: #fff;
+    --navbar-background: #C30D23;
+    --navbar-backbutton-color: #fff;
+
+    /* 标签栏 */
+    --tabbar-background: #fff;
+    --tabbar-icon: #999;
+    --tabbar-icon-active: #c30d23;
+
+    /* 内容边距 */
+    --content-inset: 12px;
+
+    /* Vant-Button */
+    --van-button-border-width: 0;
+    --van-button-primary-background: #1e78b9;
+    --van-button-danger-background: #d82d42;
+
+    /* Vant-Checkbox */
+    --van-checkbox-checked-icon-color: #DD364A !important;
+
+    /* Vant-Tabs */
+    --van-tabs-bottom-bar-color: #DD364A;
+
+    --van-dialog-confirm-button-text-color: #DD364A;
+
+    .app-tabs {
+        .tabs {
+            flex-wrap: wrap;
+
+            &-item {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                color: #626675;
+                cursor: pointer;
+                border-radius: 2px;
+                background-color: #f0f0f1;
+                padding: 4px 8px;
+
+                &:not(:first-child) {
+                    margin-left: 5px;
+                }
+
+                &.is-active {
+                    color: #222;
+                    font-weight: bold;
+                }
+            }
+        }
+    }
+}

+ 562 - 0
src/packages/thj/assets/themes/global/global.less

@@ -0,0 +1,562 @@
+[class*='g-image'] {
+    position: relative;
+    object-fit: cover;
+    overflow: hidden;
+
+    &:before {
+        content: '';
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 100%;
+        height: 100%;
+        background: #fff url("../../images/avatar.png") no-repeat center;
+        background-size: cover;
+    }
+}
+
+.g-price {
+    &-normal {
+        color: #333333;
+    }
+
+    &-up {
+        color: #ff3333;
+    }
+
+    &-down {
+        color: #0baf1f;
+    }
+}
+
+.g-risk {
+    &-green {
+        color: #0baf1f;
+    }
+
+    &-red {
+        color: #ff3333;
+    }
+
+    &-orange {
+        color: orange;
+    }
+
+    &-yellow {
+        color: #ebce12;
+    }
+}
+
+.g-form {
+    &__container {
+        display: flex;
+        flex-direction: column;
+        padding-bottom: 16px;
+
+        /* 父元素的第一个子元素 */
+        .van-cell-group--inset:first-of-type {
+            margin-top: 16px;
+        }
+
+        /* 相邻兄弟元素 */
+        .van-cell-group--inset+.van-cell-group--inset {
+            margin-top: 12px;
+        }
+
+        .van-field {
+            &__right-icon {
+                align-self: normal;
+            }
+
+            .van-stepper {
+                display: flex;
+                align-items: center;
+                width: 100%;
+
+                &__input {
+                    flex: 1;
+                }
+            }
+        }
+    }
+
+    &__footer {
+        display: flex;
+        align-items: center;
+
+        &:empty {
+            display: none;
+        }
+
+        &.inset {
+            gap: 10px;
+            padding: 10px 16px;
+        }
+    }
+}
+
+.g-flex {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+
+    &--row {
+        flex-direction: row;
+    }
+
+    &__body {
+        flex: 1;
+        overflow-y: auto;
+        -webkit-overflow-scrolling: touch;
+    }
+
+    &__footer {
+        margin-top: auto;
+    }
+}
+
+.g-color {
+    &--up {
+        color: var(--color-up);
+    }
+
+    &--down {
+        color: var(--color-down);
+    }
+}
+
+.g-block {
+    &--bg {
+        background: #fff url('../../images/block-bg.png') no-repeat center bottom;
+        background-size: 100%;
+    }
+}
+
+/* 导航列表 */
+.g-navmenu {
+    .app-iconfont {
+        height: 100%;
+
+        .g-icon {
+            width: 18px;
+            height: 18px;
+            font-size: 18px;
+        }
+
+        &__label {
+            font-size: 13px;
+            margin-left: 12px
+        }
+    }
+}
+
+/* 商品列表 */
+.g-goods-list {
+    padding: 10px;
+
+    .list {
+        padding: 10px 10px 0 10px;
+
+        &-item {
+            display: flex;
+            align-items: center;
+            border-radius: 5px;
+            overflow: hidden;
+            padding: 10px;
+
+            &:not(:last-child) {
+                margin-bottom: 10px;
+            }
+
+            .img {
+                &:first-child {
+                    display: flex;
+                    align-items: center;
+
+                    img {
+                        width: 90px;
+                        height: 90px;
+                        object-fit: cover;
+                        border-radius: 8px;
+                        margin-right: 15px;
+                    }
+                }
+
+                &:last-child {
+                    .van-button {
+                        width: 65px;
+                        height: 25px;
+                    }
+                }
+            }
+
+            .info {
+                flex: 1;
+
+                .title {
+                    color: #333;
+                    font-size: 15px;
+                }
+
+                .desc {
+                    color: #666;
+                    font-size: 12px;
+                    padding: 5px 0;
+                }
+
+                .price {
+
+                    .buyprice,
+                    .sellprice {
+                        padding-bottom: 1px;
+                    }
+                }
+            }
+        }
+    }
+}
+
+.g-goods-waterfall {
+    padding: 10px;
+
+    .goods {
+        background-color: #fff;
+        border-radius: 6px;
+        overflow: hidden;
+
+        &-image {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            min-height: 120px;
+            font-size: 0;
+        }
+
+        &-info {
+            padding: 10px;
+
+            &__title {
+                font-size: 13px;
+                margin-bottom: 5px;
+            }
+
+            &__desc {
+                font-size: 12px;
+                color: #999;
+                margin-bottom: 5px;
+            }
+
+            &__price {
+                color: #f2270c;
+
+                .unit {
+                    font-size: 12px;
+                }
+
+                .integer {
+                    font-size: 15px;
+                }
+            }
+        }
+    }
+}
+
+/* 订单列表 */
+.g-order-list {
+    padding: 10px;
+    padding-bottom: 0;
+
+    &__box {
+        &:not(:first-child) {
+            margin-top: 10px;
+        }
+
+        background-color: #fff;
+        border-radius: 8px;
+        padding: 12px;
+
+    }
+
+    &__titlebar {
+        display: flex;
+        justify-content: space-between;
+        margin-bottom: 10px;
+
+        .left {
+            h4 {
+                font-weight: bold;
+            }
+
+            span {
+                font-size: 12px;
+                color: #999;
+            }
+        }
+
+        .right {
+            font-size: 12px;
+            color: #999;
+        }
+    }
+
+    &__content {
+        font-size: 12px;
+
+        ul {
+            display: flex;
+            flex-wrap: wrap;
+            justify-content: space-between;
+
+            li {
+                display: flex;
+                justify-content: space-between;
+                line-height: 24px;
+                width: calc(~"50% - 12px");
+
+                span {
+                    &:first-child {
+                        color: #999;
+                        white-space: nowrap;
+                        padding-right: 12px;
+                    }
+                }
+            }
+        }
+    }
+
+    &__btnbar {
+        display: flex;
+        justify-content: flex-end;
+        gap: 8px;
+        margin-top: 10px;
+
+        .van-button {
+            width: 80px;
+            border-width: 1px;
+        }
+    }
+}
+
+.g-detail {
+    &__buy {
+        background-color: #fff;
+
+        .topic {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            color: #fff;
+            background-image: linear-gradient(to right, #ee0a24, #ff6034);
+            padding: 10px 12px;
+
+            &-left {
+                .price-text {
+                    font-size: 12px;
+                }
+
+                .price-integer {
+                    font-size: 22px;
+                }
+            }
+
+            &-right {
+                display: flex;
+                flex-direction: column;
+                font-size: 12px;
+            }
+        }
+
+        .title {
+            font-size: 15px;
+            font-weight: bold;
+            line-height: 24px;
+            padding: 12px;
+            padding-bottom: 0;
+
+            .van-tag {
+                font-weight: normal;
+            }
+
+            span {
+                margin-right: 5px;
+            }
+        }
+
+        .desc {
+            padding: 0 12px;
+        }
+
+        .qty {
+            font-size: 12px;
+            color: #999;
+            padding: 5px 12px 0 12px;
+        }
+
+        .info {
+            background-color: #fff;
+            padding: 10px;
+
+            ul {
+                display: flex;
+                flex-wrap: wrap;
+                font-size: 13px;
+
+                li {
+                    display: flex;
+                    justify-content: space-between;
+                    width: 50%;
+                    padding: 4px 12px;
+
+                    span {
+                        &:first-child {
+                            color: #999;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    &__desc {
+        background-color: #fff;
+        margin-top: 12px;
+    }
+
+    &__footer {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        height: 44px;
+        background-color: #fff;
+
+        .price {
+            padding-left: 16px;
+
+            &-text,
+            &-unit {
+                font-size: 12px;
+            }
+
+            &-unit {
+                color: #f2270c;
+            }
+
+            &-integer {
+                font-size: 16px;
+                color: #f2270c;
+            }
+        }
+
+        .submit {
+            align-self: stretch;
+            display: flex;
+            margin-left: auto;
+
+            &-button {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                height: 100%;
+                min-width: 100px;
+                font-weight: bold;
+                color: #fff;
+                padding: 0 24px;
+
+                &.warning {
+                    background-image: linear-gradient(to right, #ffd01e, #ff8917);
+                    background-color: #ff8a17;
+                }
+
+                &.danger {
+                    background-image: linear-gradient(to right, #ff6034, #ee0a24);
+                    background-color: #ee270a;
+                }
+            }
+        }
+    }
+}
+
+.g-qty-group {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+
+    &__stepper {
+        display: flex;
+        align-items: center;
+        gap: 5px;
+        width: 100%;
+
+        .van-stepper {
+            flex: 1;
+            display: flex;
+
+            &__input {
+                flex: 1;
+            }
+        }
+    }
+
+    .van-radio-group {
+        display: flex;
+        flex-wrap: wrap;
+        width: 100%;
+        margin-top: 10px;
+    }
+
+    .van-radio {
+        width: calc(~'100% / 3');
+        padding: 2px;
+        margin-right: 0;
+
+        .van-radio__icon {
+            display: none;
+        }
+
+        &__label {
+            display: block;
+            width: 100%;
+            font-size: 12px;
+            text-align: center;
+            color: #666;
+            border: 1px solid #e5e5e5;
+            border-radius: 4px;
+            padding: 2px;
+            margin-left: 0;
+        }
+
+        &[aria-checked="true"] {
+            .van-radio__label {
+                color: var(--van-radio-checked-icon-color);
+                border-color: var(--van-radio-checked-icon-color);
+            }
+        }
+    }
+}
+
+.van {
+    &-dialog {
+        &__message {
+            font-size: 14px;
+            line-height: 22px;
+        }
+    }
+
+    &-tabs {
+        &--list {
+            display: flex;
+            flex-direction: column;
+            height: 100%;
+        }
+
+        &--list &__content {
+            flex: 1;
+            overflow-y: auto;
+
+            .van-tab__panel {
+                height: 100%;
+            }
+        }
+    }
+}

+ 6 - 0
src/packages/thj/assets/themes/light/light.less

@@ -0,0 +1,6 @@
+[theme='light'] {
+    /* 导航栏 */
+    --navbar-color           : #333;
+    --navbar-background      : #fff;
+    --navbar-backbutton-color: #666;
+}

+ 5 - 0
src/packages/thj/assets/themes/style.less

@@ -0,0 +1,5 @@
+@import '@mobile/assets/themes/base/reset.less';
+@import './global/global.less';
+@import './default/default.less';
+@import './light/light.less';
+@import './dark/dark.less';

+ 71 - 0
src/packages/thj/index.html

@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html lang="zh-cn">
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport"
+    content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no,viewport-fit=cover">
+  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+  <title>
+    <%= htmlWebpackPlugin.options.title %>
+  </title>
+  <style>
+    @keyframes app-load {
+      0% {
+        opacity: 1;
+      }
+
+      100% {
+        opacity: 0;
+      }
+    }
+
+    .app-load {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      gap: 5px;
+      height: 100vh;
+    }
+
+    .app-load span {
+      display: inline-block;
+      width: 8px;
+      height: 8px;
+      border-radius: 50%;
+      background: #ccc;
+      opacity: 0;
+      animation: app-load 600ms ease infinite;
+    }
+
+    .app-load span:nth-child(1) {
+      animation-delay: 100ms;
+    }
+
+    .app-load span:nth-child(2) {
+      animation-delay: 200ms;
+    }
+
+    .app-load span:nth-child(3) {
+      animation-delay: 300ms;
+    }
+  </style>
+</head>
+
+<body>
+  <noscript>
+    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
+        Please enable it to continue.</strong>
+  </noscript>
+  <div id="app" class="app">
+    <div class="app-load">
+      <span></span>
+      <span></span>
+      <span></span>
+    </div>
+  </div>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>

+ 34 - 0
src/packages/thj/main.ts

@@ -0,0 +1,34 @@
+import 'core-js'
+import 'regenerator-runtime/runtime'
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+import directives from '@/directives' // 自定义指令集
+//import 'default-passive-events'
+import '@/utils/h5plus' // 加载html5+
+import 'hqchart/src/jscommon/umychart.resource/font/iconfont.css'
+import layouts from '@mobile/components/layouts' // 全局布局组件
+import 'vant/lib/index.css'
+import VXETable from 'vxe-table'
+import 'vxe-table/lib/style.css'
+import './assets/themes/style.less' // 主题样式
+// import { timerInterceptor } from '@/utils/timer'
+// import { useGlobalStore } from '@/stores'
+// import Vconsole from 'vconsole'
+// new Vconsole()
+
+const app = createApp(App)
+app.use(router)
+app.use(directives)
+app.use(VXETable)
+app.use(layouts)
+app.mount('#app')
+
+// 等待 html 加载完成
+// document.addEventListener('DOMContentLoaded', () => {
+//     const { screenAdapter } = useGlobalStore()
+//     // 适配客户端
+//     screenAdapter(true)
+//     // 监听窗口大小变化
+//     window.addEventListener('resize', timerInterceptor.setDebounce(() => screenAdapter(true)))
+// }, false)

+ 10 - 0
src/packages/thj/postcss.config.js

@@ -0,0 +1,10 @@
+module.exports = {
+    plugins: {
+        'postcss-px-to-viewport': {
+            viewportWidth: 375,
+            landscape: true, // 是否处理横屏情况
+            landscapeUnit: 'vw', // 横屏时使用的单位
+            landscapeWidth: 844, // 横屏时使用的视口宽度
+        },
+    },
+}

+ 314 - 0
src/packages/thj/router/index.ts

@@ -0,0 +1,314 @@
+import { createWebHashHistory, RouteRecordRaw } from 'vue-router'
+import { useLoginStore } from '@/stores'
+import { clearPending } from '@/services/http/pending'
+import { homeRoutes, pageRoutes } from '@mobile/router/section'
+import service from '@/services'
+import Page from '@mobile/components/layouts/page/index.vue'
+import animateRouter from '@mobile/router/animateRouter'
+
+const loginStore = useLoginStore()
+
+const routes: Array<RouteRecordRaw> = [
+  {
+    path: '/:pathMatch(.*)*',
+    name: 'error',
+    component: () => import('@mobile/views/error/404.vue'),
+    meta: {
+      ignoreAuth: true,
+    },
+  },
+  {
+    path: '/boot',
+    name: 'boot',
+    component: () => import('../views/boot/Index.vue'),
+    meta: {
+      ignoreAuth: true,
+    },
+  },
+  {
+    path: '/',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'home',
+        component: () => import('@mobile/views/home/Index.vue'),
+        children: [
+          {
+            path: '',
+            name: 'home-index',
+            component: () => import('../views/home/main/Index.vue'),
+            meta: {
+              ignoreAuth: true,
+            },
+          },
+          {
+            path: 'mine',
+            name: 'home-mine',
+            component: () => import('../views/mine/Index.vue'),
+          },
+          ...homeRoutes
+        ]
+      }
+    ]
+  },
+  {
+    path: '/user',
+    component: Page,
+    children: [
+      {
+        path: 'login',
+        name: 'user-login',
+        component: () => import('../views/user/login/Index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: 'register',
+        name: 'user-register',
+        component: () => import('@mobile/views/user/register/Index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: 'forget',
+        name: 'user-forget',
+        component: () => import('@mobile/views/user/forget/Index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: 'cancel',
+        name: 'user-cancel',
+        component: () => import('@mobile/views/user/cancel/Index.vue'),
+      },
+      {
+        path: 'password',
+        name: 'user-password',
+        component: () => import('@mobile/views/user/password/Index.vue'),
+      },
+      {
+        path: 'avatar',
+        name: 'user-avatar',
+        component: () => import('@mobile/views/user/avatar/Index.vue'),
+      },
+    ],
+  },
+  {
+    path: '/report',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'report',
+        component: () => import('@mobile//views/report/index.vue'),
+      }
+    ]
+  },
+  {
+    path: '/news',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'news-list',
+        component: () => import('@mobile/views/news/list/Index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: 'detail',
+        name: 'news-detail',
+        component: () => import('@mobile/views/news/detail/Index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+    ],
+  },
+  {
+    path: '/bank',
+    component: Page,
+    children: [
+      {
+        path: 'wallet',
+        name: 'bank-wallet',
+        component: () => import('@mobile/views/bank/wallet/Index.vue'),
+      },
+      {
+        path: 'sign',
+        name: 'bank-sign',
+        component: () => import('@mobile/views/bank/sign/Index.vue'),
+      },
+      {
+        path: 'capital',
+        name: 'bank-capital',
+        component: () => import('@mobile/views/bank/capital/index.vue'),
+      }
+    ]
+  },
+  {
+    path: '/order',
+    component: Page,
+    children: [
+      {
+        path: 'list',
+        name: 'order-list',
+        component: () => import('../views/order/list/Index.vue'),
+      },
+      {
+        path: 'position',
+        name: 'order-position',
+        component: () => import('../views/order/position/Index.vue'),
+      },
+      {
+        path: 'delivery',
+        name: 'order-delivery',
+        component: () => import('../views/order/delivery/Index.vue'),
+      },
+      {
+        path: 'performance',
+        name: 'order-performance',
+        component: () => import('@mobile/views/order/performance/Index.vue'),
+      },
+    ],
+  },
+  {
+    path: '/mine',
+    component: Page,
+    children: [
+      {
+        path: 'address',
+        name: 'mine-address',
+        component: () => import('@mobile/views/mine/address/Index.vue'),
+      },
+      {
+        path: 'invoice',
+        name: 'mine-invoice',
+        component: () => import('@mobile/views/mine/invoice/Index.vue'),
+      },
+      {
+        path: 'profile',
+        name: 'mine-profile',
+        component: () => import('@mobile/views/mine/profile/Index.vue'),
+      },
+      {
+        path: 'setting',
+        name: 'mine-setting',
+        component: () => import('@mobile/views/mine/setting/Index.vue'),
+      },
+      {
+        path: 'wechat',
+        name: 'mine-wechat',
+        component: () => import('@mobile/views/mine/wechat/Index.vue'),
+      },
+      {
+        path: 'email',
+        name: 'mine-email',
+        component: () => import('@mobile/views/mine/email/Index.vue'),
+      }
+    ],
+  },
+  {
+    path: '/notice',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'notice-list',
+        component: () => import('@mobile/views/notice/list/index.vue'),
+      }
+    ]
+  },
+  {
+    path: '/rules',
+    component: Page,
+    children: [
+      {
+        path: "zcxy",
+        name: "rules-zcxy",
+        component: () => import("@mobile/views/rules/zcxy/Index.vue"),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: "yhkhfxgzs",
+        name: "rules-yhkhfxgzs",
+        component: () => import("@mobile/views/rules/fxgzs/Index.vue"),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: "yszc",
+        name: "rules-yszc",
+        component: () => import("@mobile/views/rules/yszc/Index.vue"),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: "gywm",
+        name: "rules-gywm",
+        component: () => import("@mobile/views/rules/gywm/Index.vue"),
+        meta: {
+          ignoreAuth: true,
+        },
+      },
+      {
+        path: "fwrx",
+        name: "rules-fwrx",
+        component: () => import("@mobile/views/rules/fwrx/Index.vue"),
+        meta: {
+          ignoreAuth: true,
+        }
+      }
+    ]
+  },
+  ...pageRoutes
+]
+
+const router = animateRouter.create({
+  history: createWebHashHistory(),
+  routes,
+})
+
+// 路由跳转拦截
+router.beforeEach((to, from, next) => {
+  clearPending()
+  // 判断服务是否加载完成
+  if (service.isReady) {
+    if (to.meta.ignoreAuth || loginStore.token) {
+      next()
+    } else {
+      if (to.matched.some((e) => e.name === 'home')) {
+        // 如果是主页导航页面,强制跳转到首页
+        next({
+          name: 'home-index',
+          replace: true,
+        })
+      } else {
+        next({
+          name: 'user-login',
+          query: { redirect: to.fullPath },
+        })
+      }
+    }
+  } else {
+    if (to.name === 'boot' || to.name === 'user-login') {
+      next()
+    } else {
+      next({
+        name: 'boot',
+        query: { redirect: to.fullPath },
+      })
+    }
+  }
+})
+
+export default router

+ 99 - 0
src/packages/thj/views/boot/Index.vue

@@ -0,0 +1,99 @@
+<template>
+  <div class="boot" :style="`background-image: url(${'./app/splashscreen/1080x1920.png'});`">
+    <Swipe class="boot__guide" :loop="false" v-if="state.showGuide">
+      <SwipeItem>
+        <img :src="'./app/splashscreen/1080x1920.png'" />
+      </SwipeItem>
+      <SwipeItem>
+        <img src="../../assets/images/guide-1.png" />
+      </SwipeItem>
+      <SwipeItem>
+        <img src="../../assets/images/guide-2.png" @click="skip(init())" />
+      </SwipeItem>
+    </Swipe>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { reactive, onUnmounted } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { Swipe, SwipeItem } from 'vant'
+import { showLoading, dialog } from '@/utils/vant'
+import { useLogin } from '@/business/login'
+import service from '@/services'
+import plus from '@/utils/h5plus'
+
+const { logining, initBaseData } = useLogin()
+const route = useRoute()
+const router = useRouter()
+const countdown = 1  // 倒计时秒数
+
+const state = reactive({
+  showGuide: false,
+  //showGuide: (!plus.hasPlus() || localStorage.getItem('muchinfo_app_showguide') === 'false') ? false : true, // 是否显示引导页
+  second: countdown, // 剩余秒数
+  currentRate: 100, // 当前进度
+  rate: 100, // 目标进度
+})
+
+const init = () => initBaseData(true) // 初始化数据
+const onLoad = state.showGuide ? Promise.resolve() : init()
+
+// 倒计时
+const timer = window.setInterval(() => {
+  state.second--
+  state.rate = (100 / countdown) * state.second
+  if (state.second <= 0) {
+    clearInterval(timer)
+    // 判断是否首次打开应用
+    if (!state.showGuide) {
+      skip(onLoad)
+    }
+  }
+}, 1000)
+
+// 跳过广告
+const skip = (promise: Promise<void>) => {
+  clearInterval(timer)
+  const toast = logining.value ? showLoading() : undefined
+
+  promise.then(() => {
+    localStorage.setItem('muchinfo_app_showguide', 'false')
+    const redirect = route.query.redirect
+    if (redirect) {
+      router.replace(redirect.toString())
+    } else {
+      router.replace({ name: 'home-index' })
+    }
+  }).catch((err) => {
+    if (service.isReady) {
+      router.replace({ name: 'home-index' })
+    } else {
+      tryInit(err)
+    }
+  }).finally(() => {
+    toast?.close()
+  })
+}
+
+// 初始化失败重试
+const tryInit = (message: string) => {
+  dialog({
+    message,
+    showCancelButton: plus.hasPlus(),
+    cancelButtonText: '退出',
+    confirmButtonText: '重试'
+  }).then(() => {
+    skip(init())
+  }).catch(() => {
+    plus.quit()
+  })
+}
+
+plus.setFullSreen()
+onUnmounted(() => plus.exitFullSreen())
+</script>
+
+<style lang="less" scoped>
+@import './index.less';
+</style>

+ 19 - 0
src/packages/thj/views/boot/index.less

@@ -0,0 +1,19 @@
+.boot {
+    height: 100vh;
+    background-color: #fff;
+    background-repeat: no-repeat;
+    background-position: center top;
+    background-size: cover;
+    overflow: hidden;
+
+    &__guide {
+        width: 100%;
+        height: 100%;
+
+        img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+        }
+    }
+}

+ 131 - 0
src/packages/thj/views/home/main/Index.vue

@@ -0,0 +1,131 @@
+<template>
+  <app-view class="home-main">
+    <template #header>
+      <app-navbar :title="globalStore.getSystemInfo('appName')" :show-back-button="false" />
+    </template>
+    <Banner :data-list="topBanners" />
+    <div class="home-main__container">
+      <app-block>
+        <Cell title="通知公告" value="更多" :to="{ name: 'notice-list' }" icon="volume" is-link />
+      </app-block>
+      <app-block class="home-main__chart" v-if="userStore.accountName && goodsGroup.length">
+        <Swipe :show-indicators="false" :loop="false">
+          <SwipeItem v-for="(list, i) in goodsGroup" :key="i">
+            <ul>
+              <template v-for="(item, n) in list" :key="n">
+                <li :class="[item.lastColor, item.goodsid === selectedGoods?.goodsid ? 'is-active' : '']"
+                  @click="onTabChange(item)">
+                  <div>
+                    <b style="color: #444;">{{ item.goodsname }}</b>
+                  </div>
+                  <div>
+                    <b>{{ item.last }}</b>
+                  </div>
+                  <div>
+                    <span>{{ item.rise }}</span>
+                    <span>{{ item.change }}</span>
+                  </div>
+                </li>
+              </template>
+            </ul>
+          </SwipeItem>
+        </Swipe>
+        <component :is="LineChart" :goodscode="selectedGoods.refgoodscode" v-if="showChart && selectedGoods" />
+      </app-block>
+    </div>
+  </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent, computed, nextTick, watch } from 'vue'
+import { Cell, Swipe, SwipeItem } from 'vant'
+import { parsePercent, handleNumberValue, formatDecimal } from '@/filters'
+import { queryQuoteGoodsList } from '@/services/api/swap'
+import { queryImageConfigs } from '@/services/api/common'
+import { useGlobalStore, useUserStore, useFuturesStore } from '@/stores'
+import quoteSocket from '@/services/websocket/quote'
+import Banner from '@mobile/components/base/banner/index.vue'
+
+const LineChart = defineAsyncComponent(() => import('@mobile/components/modules/echarts/line/index.vue'))
+
+const subscribe = quoteSocket.createSubscribe()
+const globalStore = useGlobalStore()
+const userStore = useUserStore()
+const futuresStore = useFuturesStore()
+const topBanners = shallowRef<string[]>([]) // 轮播图列表
+const goodsList = shallowRef<Model.QuoteGoodsListRsp[]>([]) // 掉期商品列表
+const selectedGoods = shallowRef<Model.QuoteGoodsListRsp>() // 选中的掉期商品
+const showChart = shallowRef(false)
+
+// 掉期商品组
+const goodsGroup = computed(() => {
+  const arr = []
+  const list = goodsList.value.map(({ goodsid, goodsname, refgoodscode }) => {
+    const quote = futuresStore.getGoodsQuote(refgoodscode)
+    const { lastColor, last = 0, rise = 0, change, decimalplace } = quote.value ?? {}
+    return {
+      goodsid,
+      goodsname,
+      refgoodscode,
+      lastColor,
+      last: handleNumberValue(formatDecimal(last, decimalplace)),
+      rise: handleNumberValue(formatDecimal(rise, decimalplace)),
+      change: parsePercent(change)
+    }
+  })
+  // 分割成三个一组
+  for (let i = 0; i < list.length; i += 3) {
+    arr.push(list.slice(i, i + 3))
+  }
+  return arr
+})
+
+// 切换掉期商品
+const onTabChange = (item: unknown) => {
+  showChart.value = false
+  selectedGoods.value = item as Model.QuoteGoodsListRsp
+
+  nextTick(() => {
+    showChart.value = true
+  })
+}
+
+queryImageConfigs({
+  data: {
+    imageType: 1,
+  }
+}).then((res) => {
+  topBanners.value = res.data.map((e) => e.imagepath)
+})
+
+watch(() => userStore.accountName, (accountName) => {
+  if (accountName) {
+    if (goodsList.value.length) {
+      const goodsCodes = goodsList.value.map((e) => e.refgoodscode)
+      subscribe.start(...goodsCodes)
+    } else {
+      // 掉期商品
+      queryQuoteGoodsList({
+        data: {
+          usertype: userStore.userType ?? 0,
+          marketids: userStore.getMarketId('TRADEMODE_TJMD').toString()
+        }
+      }).then((res) => {
+        if (res.data.length) {
+          const goodsCodes = res.data.map((e) => e.refgoodscode)
+          goodsList.value = res.data
+          selectedGoods.value = res.data[0]
+          showChart.value = true
+          subscribe.start(...goodsCodes)
+        }
+      })
+    }
+  }
+}, {
+  immediate: true
+})
+</script>
+
+<style lang="less">
+@import "./index.less";
+</style>

+ 125 - 0
src/packages/thj/views/home/main/index.less

@@ -0,0 +1,125 @@
+@import '@mobile/assets/themes/base/mixin.less';
+
+.home-main {
+    &__header {
+        background: linear-gradient(var(--navbar-background), var(--navbar-background) 60%, transparent 60%);
+        padding: 10px;
+    }
+
+    &__iconbar {
+        ul {
+            display: flex;
+            flex-wrap: wrap;
+            padding-top: 12px;
+
+            &:last-child {
+                padding-bottom: 12px;
+            }
+
+            li {
+                display: flex;
+                flex-direction: column;
+                align-items: center;
+                width: calc(~'100% / 4');
+                text-align: center;
+
+                .app-iconfont {
+                    &__icon {
+                        font-size: 40px;
+                    }
+
+                    &__label {
+                        font-size: 12px;
+                        margin-top: 5px;
+                    }
+                }
+            }
+        }
+    }
+
+    &__titlebar {
+        .van-cell__title {
+            font-size: 16px;
+            font-weight: bold;
+        }
+
+        .van-cell__value {
+            flex: none;
+            color: #666;
+        }
+    }
+
+    &__market {
+        .scrollbar {
+            width: 100%;
+            padding: 10px;
+        }
+
+        .van-swipe {
+            height: 32px;
+            background-color: #f6f6f6;
+
+            ul {
+                display: flex;
+                justify-content: space-around;
+                align-items: center;
+                height: inherit;
+                font-size: 13px;
+            }
+        }
+    }
+
+    &__news {
+        .article {
+            &-item {
+                .van-cell__title {
+                    span {
+                        .mixin-text-overflow()
+                    }
+                }
+
+                .van-cell__value {
+                    flex: initial;
+                    font-size: 12px;
+                    margin-left: 24px;
+                }
+            }
+        }
+    }
+
+    &__chart {
+        ul {
+            display: flex;
+            text-align: center;
+            color: #777;
+            line-height: 22px;
+
+            li {
+                flex: 1;
+                padding: 6px 0;
+
+                &.is-active {
+                    &::before {
+                        background-color: transparent
+                    }
+
+                    &.g-price-up {
+                        background-color: #fff3f3;
+                    }
+
+                    &.g-price-down {
+                        background-color: #eefff2;
+                    }
+                }
+
+                span {
+                    font-size: 12px;
+
+                    +span {
+                        margin-left: 5px;
+                    }
+                }
+            }
+        }
+    }
+}

+ 216 - 0
src/packages/thj/views/mine/Index.vue

@@ -0,0 +1,216 @@
+<template>
+    <app-view class="mine">
+        <template #header>
+            <app-navbar title="我的" :show-back-button="false" @ready="onReady" />
+        </template>
+        <div ref="headerRef" class="mine-header">
+            <div class="mine-header__wrapper">
+                <div class="profile">
+                    <div class="profile-user">
+                        <div class="profile-user__avatar" @click="routerTo('user-avatar')">
+                            <img class="g-image--avatar" :src="userStore.userAvatar" />
+                        </div>
+                        <div class="profile-user__info">
+                            <div class="top">
+                                <span>{{ userStore.customerName }}</span>
+                                <Icon name="checked" color="var(--van-tag-success-color)"
+                                    v-if="authStatus === AuthStatus.Certified" />
+                                <Icon name="warning" color="var(--van-tag-warning-color)" v-else />
+                            </div>
+                            <div class="bottom">{{ loginStore.loginId }}</div>
+                        </div>
+                    </div>
+                    <div class="profile-account">
+                        <span>正常</span>
+                        <span>{{ currentAccount.accountid ?? 0 }}</span>
+                    </div>
+                </div>
+                <div class="bank">
+                    <ul>
+                        <li>
+                            <span>余额</span>
+                            <span>{{ currentAccount.currentbalance?.toFixed(2) }}</span>
+                        </li>
+                        <li>
+                            <span>净值</span>
+                            <span>{{ currentAccount.hazardValue?.toFixed(2) }}</span>
+                        </li>
+                    </ul>
+                    <ul>
+                        <li>
+                            <span>预扣</span>
+                            <span>{{ currentAccount.freezeMargin?.toFixed(2) }}</span>
+                        </li>
+                        <li>
+                            <span>占用</span>
+                            <span>{{ currentAccount.usedmargin?.toFixed(2) }}</span>
+                        </li>
+                    </ul>
+                    <ul>
+                        <li>
+                            <span>可用</span>
+                            <span>{{ currentAccount.avaiableMoney?.toFixed(2) }}</span>
+                        </li>
+                        <li>
+                            <span>风险率</span>
+                            <span :class="currentAccount.hazardRatioColor">
+                                {{ parsePercent(currentAccount.hazardRatio) }}
+                            </span>
+                        </li>
+                    </ul>
+                </div>
+                <div class="button">
+                    <Button type="danger" size="small" round @click="doInOutMoney('0')">入金</Button>
+                    <Button size="small" round @click="doInOutMoney('1')">出金</Button>
+                </div>
+            </div>
+        </div>
+        <app-block class="mine-iconbar">
+            <ul>
+                <li @click="routerTo('order-position')">
+                    <Iconfont label-direction="bottom" icon="g-icon-position--line">我的持仓</Iconfont>
+                </li>
+                <li @click="routerTo('order-list')">
+                    <Iconfont label-direction="bottom" icon="g-icon-order--line">我的订单</Iconfont>
+                </li>
+                <li @click="routerTo('order-delivery')">
+                    <Iconfont label-direction="bottom" icon="g-icon-delivery--line">线下交收</Iconfont>
+                </li>
+            </ul>
+        </app-block>
+        <app-block class="g-navmenu">
+            <CellGroup>
+                <Cell is-link :to="{ name: 'bank-capital' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-capital">资金信息</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'account-certification' }" v-if="authStatus !== AuthStatus.Certified">
+                    <template #title>
+                        <Iconfont icon="g-icon-certification">实名认证</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'bank-sign' }" v-if="authStatus === AuthStatus.Certified">
+                    <template #title>
+                        <Iconfont icon="g-icon-sign">签约账户</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'mine-profile' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-profile">个人信息</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-zcxy' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-zcxy">用户注册协议</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-yszc' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-yszc">关于隐私</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-fwrx' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-fwrx">服务热线</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'mine-setting' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-setting">设置</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-gywm' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-gywm">关于我们</Iconfont>
+                    </template>
+                </Cell>
+            </CellGroup>
+        </app-block>
+        <div class="mine-footer">
+            <Button class="button-logout" type="danger" size="small" round @click="userLogout">退出登录</Button>
+        </div>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, onActivated, computed } from 'vue'
+import { Cell, CellGroup, Button, Icon } from 'vant'
+import { fullloading, dialog } from '@/utils/vant'
+import { parsePercent } from '@/filters'
+import { useNavigation } from '@mobile/router/navigation'
+import { AuthStatus } from '@/constants/account'
+import { queryBankAccountSign } from '@/services/api/bank'
+import { useLoginStore, useAccountStore, useUserStore } from '@/stores'
+import eventBus from '@/services/bus'
+import Iconfont from '@/components/base/iconfont/index.vue'
+
+const { router, routerTo } = useNavigation()
+const loginStore = useLoginStore()
+const userStore = useUserStore()
+const accountStore = useAccountStore()
+const { currentAccount } = accountStore.$toRefs()
+
+const headerRef = shallowRef<HTMLDivElement>()
+const authStatus = computed(() => userStore.userAccount.hasauth) // 实名认证状态
+
+const onReady = (el: HTMLDivElement) => {
+    // 设置背景图位置
+    headerRef.value?.style.setProperty('background-position', `0 -${el.clientHeight}px`)
+}
+
+/// 进行出入金操作判断
+const doInOutMoney = (tab: string) => {
+    if (authStatus.value === AuthStatus.Certified) {
+        fullloading((hideLoading) => {
+            queryBankAccountSign().then((res) => {
+                hideLoading()
+                const { signstatus } = res.data[0] ?? {}
+                /// 只有已签约的情况下才可以进行出入金
+                if (signstatus && signstatus === 4) {
+                    router.push({ name: 'bank-wallet', query: { tab } })
+                } else {
+                    dialog({
+                        message: '请先添加签约账户信息!',
+                        showCancelButton: true,
+                        confirmButtonText: '去签约'
+                    }).then(() => {
+                        router.push({ name: 'bank-sign' })
+                    })
+                }
+            }).catch(() => {
+                hideLoading('加载失败', 'fail')
+            })
+        }, '正在加载...')
+    } else {
+        dialog({
+            message: '请先实名认证,再进行该操作!',
+            showCancelButton: true,
+            confirmButtonText: '去实名'
+        }).then(() => {
+            router.push({ name: 'account-certification' })
+        })
+    }
+}
+
+const userLogout = () => {
+    dialog({
+        message: '是否退出当前账号?',
+        showCancelButton: true
+    }).then(() => {
+        loginStore.clearAutoLoginData()
+        eventBus.$emit('LogoutNotify')
+    })
+}
+
+onActivated(() => {
+    if (authStatus.value !== AuthStatus.Certified) {
+        userStore.getUserData()
+    }
+    accountStore.getAccountList()
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 167 - 0
src/packages/thj/views/mine/index.less

@@ -0,0 +1,167 @@
+@import '@mobile/assets/themes/base/mixin.less';
+
+.mine {
+    @backgroundImage: linear-gradient(var(--navbar-background), var(--navbar-background) 150px, transparent 150px);
+
+    .app-navbar {
+        background-image: @backgroundImage;
+
+        &__wrapper {
+            color: #fff;
+            background-color: transparent;
+        }
+    }
+
+    &-header {
+        color: #000;
+        background-color: #fff;
+        background-image: @backgroundImage;
+        padding: 0 18px;
+
+        &__wrapper {
+            background-color: #fff;
+            border-top-left-radius: 10px;
+            border-top-right-radius: 10px;
+            padding: 12px;
+        }
+
+        .profile {
+            display: flex;
+
+            &-user {
+                flex: 1;
+                display: flex;
+                align-items: center;
+
+                .g-image--avatar {
+                    width: 40px;
+                    height: 40px;
+                    border-radius: 50%;
+                    font-size: 0;
+                    margin-right: 8px;
+                }
+
+                &__info {
+                    flex: 1;
+                    padding-right: 16px;
+
+                    .top {
+                        display: flex;
+                        align-items: center;
+                        font-size: 12px;
+                        color: #A1B1C5;
+
+                        span {
+                            .mixin-text-overflow()
+                        }
+
+                        .van-icon {
+                            line-height: normal;
+                            margin-left: 2px;
+                        }
+                    }
+
+                    .bottom {
+                        line-height: 20px;
+                        font-size: 15px;
+                        font-weight: bold;
+                    }
+                }
+            }
+
+            &-account {
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+
+                span {
+                    line-height: 20px;
+
+                    &:first-child {
+                        font-size: 12px;
+                        color: #46D63C;
+
+                        &::before {
+                            content: '资金账户';
+                            color: #A1B1C5;
+                            margin-right: 6px;
+                        }
+                    }
+
+                    &:last-child {
+                        font-size: 15px;
+                        font-weight: bold;
+                    }
+                }
+            }
+        }
+
+        .bank {
+            display: flex;
+            justify-content: space-around;
+            padding: 18px 0;
+
+            ul {
+                li {
+                    display: flex;
+                    flex-direction: column;
+                    padding-bottom: 5px;
+
+                    span {
+                        line-height: 20px;
+
+                        &:first-child {
+                            font-size: 12px;
+                            color: #A1B1C5;
+                        }
+
+                        &:last-child {
+                            font-size: 15px;
+                            font-weight: bold;
+                        }
+                    }
+                }
+            }
+        }
+
+        .button {
+            display: flex;
+            justify-content: space-around;
+
+            .van-button {
+                width: 140px;
+                box-shadow: 0 3px 7px 0 #e0e2e8;
+            }
+        }
+    }
+
+    &-iconbar {
+        ul {
+            display: flex;
+            background-color: #fff;
+            padding: 12px;
+
+            li {
+                flex: 1;
+                display: flex;
+                flex-direction: column;
+                align-items: center;
+
+                .g-icon {
+                    font-size: 28px;
+                    margin-bottom: 2px;
+                }
+            }
+        }
+    }
+
+    &-footer {
+        text-align: center;
+        padding: 10px 0;
+
+        .button-logout {
+            width: 50%;
+            border: 0;
+        }
+    }
+}

+ 20 - 0
src/packages/thj/views/order/delivery/Index.vue

@@ -0,0 +1,20 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar title="交收提货" />
+        </template>
+        <component :is="components[0].component" />
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { defineAsyncComponent } from 'vue'
+
+const components = [
+    {
+        name: 'goods',
+        title: '现货提货单',
+        component: defineAsyncComponent(() => import('@mobile/views/order/delivery/components/spot/list/Index.vue')),
+    }
+]
+</script>

+ 59 - 0
src/packages/thj/views/order/list/Index.vue

@@ -0,0 +1,59 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar title="我的订单">
+                <template #right v-if="selectedComponent.history">
+                    <div class="button-more" @click="openComponent(selectedComponent.name)">
+                        <span>更多</span>
+                    </div>
+                </template>
+            </app-navbar>
+        </template>
+        <Tabs class="van-tabs--list" v-model:active="active" :swipe-threshold="4">
+            <template v-for="(item, index) in components" :key="index">
+                <Tab :title="item.title" :name="index">
+                    <component :is="item.component" />
+                </Tab>
+            </template>
+        </Tabs>
+        <component ref="componentRef" :is="selectedComponent.history" @closed="closeComponent"
+            v-if="componentId && selectedComponent.history" />
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent, computed } from 'vue'
+import { Tab, Tabs } from 'vant'
+import { useComponent } from '@/hooks/component'
+
+const components = [
+{
+        name: 'swaporder',
+        title: '掉期委托',
+        component: defineAsyncComponent(() => import('@mobile/views/order/list/components/swaporder/list/Index.vue')),
+        history: defineAsyncComponent(() => import('@mobile/views/order/list/components/swaporder/history/Index.vue')),
+    },
+    {
+        name: 'swaptrade',
+        title: '掉期成交',
+        component: defineAsyncComponent(() => import('@mobile/views/order/list/components/swaptrade/list/Index.vue')),
+        history: defineAsyncComponent(() => import('@mobile/views/order/list/components/swaptrade/history/Index.vue')),
+    },
+    {
+        name: 'listingorder',
+        title: '挂牌委托',
+        component: defineAsyncComponent(() => import('@mobile/views/order/list/components/listingorder/list/Index.vue')),
+        history: defineAsyncComponent(() => import('@mobile/views/order/list/components/listingorder/history/Index.vue')),
+    },
+    {
+        name: 'listingtrade',
+        title: '挂牌成交',
+        component: defineAsyncComponent(() => import('@mobile/views/order/list/components/listingtrade/list/Index.vue')),
+        history: defineAsyncComponent(() => import('@mobile/views/order/list/components/listingtrade/history/Index.vue')),
+    }
+]
+
+const active = shallowRef(0)
+const selectedComponent = computed(() => components[active.value])
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+</script>

+ 34 - 0
src/packages/thj/views/order/position/Index.vue

@@ -0,0 +1,34 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar title="我的持仓" />
+        </template>
+        <Tabs class="van-tabs--list" v-model:active="active" :swipe-threshold="4">
+            <template v-for="(item, index) in components" :key="index">
+                <Tab :title="item.title" :name="index">
+                    <component :is="item.component" />
+                </Tab>
+            </template>
+        </Tabs>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { Tab, Tabs } from 'vant'
+
+const components = [
+    {
+        name: 'goods',
+        title: '掉期持仓',
+        component: defineAsyncComponent(() => import('@mobile/views/order/position/components/swap/list/Index.vue')),
+    },
+    {
+        name: 'spot',
+        title: '现货持仓',
+        component: defineAsyncComponent(() => import('@mobile/views/order/position/components/spot/list/Index.vue')),
+    },
+]
+
+const active = shallowRef(0)
+</script>

+ 13 - 0
src/packages/thj/views/user/login/Index.vue

@@ -0,0 +1,13 @@
+<template>
+  <AppLogin :logo-src="logoImage" :show-yhkhfxgzs="false" />
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted } from 'vue'
+import plus from '@/utils/h5plus'
+import AppLogin from '@mobile/components/layouts/login/index.vue'
+import logoImage from '../../../assets/images/login-logo.png'
+
+onMounted(() => plus.setStatusBarStyle('dark'))
+onUnmounted(() => plus.setStatusBarStyle('light'))
+</script>

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

@@ -276,6 +276,7 @@ export const useFuturesStore = defineStore(() => {
             marketmarginalgorithm: 0,
             marketmarginvalue: 0,
             qtydecimalplace: 0,
+            goodstradetype: 0,
             maxspread: 0,
             minspread: 0,
             goodsorder: '',
@@ -335,6 +336,7 @@ export const useFuturesStore = defineStore(() => {
                     tradeproperty: item.tradeproperty,
                     provideraccountid: item.provideraccountid,
                     provideruserid: item.provideruserid,
+                    goodstradetype: item.goodstradetype
                 } = goods)
 
                 item.iscannotbuy = goods.iscannotbuy ?? 0

+ 6 - 1
src/stores/modules/position.ts

@@ -123,7 +123,12 @@ export const useSBYJOrderStore = defineStore(() => {
             e.tHDetailEx.depositRate = calcDepositRate(e)
             e.tHDetailEx.floatPL = calcFloatpl(e)
         })
-        return state.orderList
+        return state.orderList.filter((e) => {
+            // 任务 #5753
+            const { tHDetailEx, agreeUnit } = e
+            const qty = (tHDetailEx.holderQty - tHDetailEx.freezeQty) * agreeUnit
+            return qty > 0
+        })
     })
 
     // 计算浮动盈亏

+ 1 - 0
src/types/model/market.d.ts

@@ -141,6 +141,7 @@ declare namespace Model {
         tradeproperty: number; // 交易属性 - 1:收益权(可做空) 2:所有权(不可做空) 3:期权 4:现货 5:参考行情 6:通道交易 7:币交易 8:场外期权
         provideraccountid: number; // 发售方资金账户ID(49)\供货商资金账户ID(50)
         provideruserid: number; // 发售方用户ID(49)\供货商(50)
+        goodstradetype: number;//商品交易权限类型 - 1:可建可平 3:不可建可平
     }
 
     /** 查询新板块设置 响应 */

Некоторые файлы не были показаны из-за большого количества измененных файлов