li.shaoyi há 3 meses atrás
pai
commit
34f02e7e6d
33 ficheiros alterados com 1671 adições e 110 exclusões
  1. 3 0
      oem/snhl/androidPrivacy.json
  2. BIN
      oem/snhl/apple-touch-icon-precomposed.png
  3. 16 0
      oem/snhl/config/appconfig.json
  4. 1 0
      oem/snhl/config/columns.json
  5. 301 0
      oem/snhl/config/router.json
  6. BIN
      oem/snhl/favicon.ico
  7. 309 0
      oem/snhl/manifest.json
  8. 2 2
      oem/tss/config/appconfig.json
  9. 14 0
      script/oem.env.json
  10. 2 2
      src/business/login/index.ts
  11. 33 47
      src/packages/mobile/components/layouts/login/index.vue
  12. 1 1
      src/packages/mobile/router/section.ts
  13. 31 43
      src/packages/mobile/views/pricing/list/Index.vue
  14. 5 4
      src/packages/mobile/views/rules/fwrx/Index.vue
  15. 6 5
      src/packages/mobile/views/rules/yszc/Index.vue
  16. 5 4
      src/packages/mobile/views/rules/zcxy/Index.vue
  17. 1 1
      src/packages/sbyj/views/user/login/Index.vue
  18. 7 0
      src/packages/snhl/App.vue
  19. BIN
      src/packages/snhl/assets/images/certification.png
  20. 72 0
      src/packages/snhl/index.html
  21. 35 0
      src/packages/snhl/main.ts
  22. 10 0
      src/packages/snhl/postcss.config.js
  23. 353 0
      src/packages/snhl/router/index.ts
  24. 19 0
      src/packages/snhl/views/boot/index.less
  25. 99 0
      src/packages/snhl/views/boot/index.vue
  26. 227 0
      src/packages/snhl/views/mine/index.vue
  27. 20 0
      src/packages/snhl/views/order/delivery/index.vue
  28. 47 0
      src/packages/snhl/views/order/list/index.vue
  29. 32 0
      src/packages/snhl/views/order/position/index.vue
  30. 7 0
      src/packages/snhl/views/user/login/index.vue
  31. 3 0
      src/packages/tss/views/boot/Index.vue
  32. 2 1
      src/stores/storage.ts
  33. 8 0
      src/types/model/common.d.ts

+ 3 - 0
oem/snhl/androidPrivacy.json

@@ -0,0 +1,3 @@
+{
+    "prompt" : "none"
+}

BIN
oem/snhl/apple-touch-icon-precomposed.png


+ 16 - 0
oem/snhl/config/appconfig.json

@@ -0,0 +1,16 @@
+{
+  "appId": "com.snhl.release",
+  "appName": "三农互联",
+  "version": "1.0.0",
+  "versionCode": "100000",
+  "apiUrl": "http://192.168.31.210:8080/cfg?key=test_210",
+  "tradeChannel": "ws",
+  "modules": [
+    "register"
+  ],
+  "quotationProperties": [
+    "holdvolume"
+  ],
+  "riskType": 1,
+  "i18nEnabled": false
+}

+ 1 - 0
oem/snhl/config/columns.json

@@ -0,0 +1 @@
+[]

+ 301 - 0
oem/snhl/config/router.json

@@ -0,0 +1,301 @@
+[
+    {
+        "authType": 2,
+        "sort": 0,
+        "title": "底部单据菜单",
+        "code": "bottom",
+        "children": [
+            {
+                "authType": 2,
+                "sort": 1,
+                "title": "商品订单",
+                "code": "bottom_goods",
+                "component": "views/footer/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "持仓汇总",
+                        "code": "bottom_goods_position",
+                        "component": "views/footer/goods/position/index.vue",
+                        "children": [
+                            {
+                                "authType": 3,
+                                "title": "转让",
+                                "code": "bottom_goods_position_transfer",
+                                "component": "views/footer/goods/position/components/transfer/index.vue",
+                                "className": "el-button--danger"
+                            },
+                            {
+                                "authType": 3,
+                                "title": "交收",
+                                "code": "bottom_goods_position_delivery16",
+                                "component": "views/footer/goods/position/components/delivery16/index.vue",
+                                "className": "el-button--primary"
+                            },
+                            {
+                                "authType": 3,
+                                "title": "交收",
+                                "code": "bottom_goods_position_delivery50",
+                                "component": "views/footer/goods/position/components/delivery50/index.vue",
+                                "className": "el-button--primary"
+                            }
+                        ]
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 2,
+                        "title": "持仓明细",
+                        "code": "bottom_goods_detail",
+                        "component": "views/footer/goods/detail/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 3,
+                        "title": "委托",
+                        "code": "bottom_goods_order",
+                        "component": "views/footer/goods/order/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 4,
+                        "title": "成交",
+                        "code": "bottom_goods_trade",
+                        "component": "views/footer/goods/trade/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 5,
+                        "title": "交收",
+                        "code": "bottom_goods_delivery",
+                        "component": "views/footer/goods/delivery/index.vue"
+                    }
+                ]
+            },
+            {
+                "authType": 2,
+                "sort": 6,
+                "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_goods",
+                        "url": "goods",
+                        "urlType": 1,
+                        "component": "views/query/order/goods/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_order_goods_list",
+                                "component": "views/query/order/goods/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_order_goods_history",
+                                "component": "views/query/order/goods/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_goods",
+                        "url": "goods",
+                        "urlType": 1,
+                        "component": "views/query/trade/goods/index.vue",
+                        "children": [
+                            {
+                                "authType": 2,
+                                "sort": 1,
+                                "title": "当前记录",
+                                "code": "query_trade_goods_list",
+                                "component": "views/query/trade/goods/list/index.vue"
+                            },
+                            {
+                                "authType": 2,
+                                "sort": 2,
+                                "title": "历史记录",
+                                "code": "query_trade_goods_history",
+                                "component": "views/query/trade/goods/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": 5,
+                "title": "出入金申请记录",
+                "code": "query_inoutapply",
+                "url": "inoutapply",
+                "urlType": 1,
+                "component": "views/query/inoutapply/index.vue",
+                "children": [
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "当前记录",
+                        "code": "query_inoutapply_list",
+                        "component": "views/query/inoutapply/list/index.vue"
+                    },
+                    {
+                        "authType": 2,
+                        "sort": 1,
+                        "title": "历史记录",
+                        "code": "query_inoutapply_history",
+                        "component": "views/query/inoutapply/history/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": 4,
+                "title": "收货地址管理",
+                "code": "account_address",
+                "url": "address",
+                "urlType": 1,
+                "component": "views/account/address/index.vue"
+            },
+            {
+                "authType": 1,
+                "sort": 5,
+                "title": "发票信息管理",
+                "code": "account_receipt",
+                "url": "receipt",
+                "urlType": 1,
+                "component": "views/account/receipt/index.vue"
+            }
+        ]
+    }
+]

BIN
oem/snhl/favicon.ico


+ 309 - 0
oem/snhl/manifest.json

@@ -0,0 +1,309 @@
+{
+    "@platforms" : [ "android", "iPhone", "iPad" ],
+    "id" : "H5D0C0CD8",
+    /*应用的标识*/
+    "name" : "Tce-Vietnam",
+    /*应用名称,程序桌面图标名称*/
+    "version" : {
+        "name" : "1.0.0",
+        /*应用版本名称*/
+        "code" : 100000
+    },
+    "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\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_MEDIA_VISUAL_USER_SELECTED\"/>"
+                ],
+                "abiFilters" : [ "arm64-v8a" ],
+                "autoSdkPermissions" : false,
+                "minSdkVersion" : 34,
+                "targetSdkVersion" : 34,
+                "excludePermissions" : [
+                    "<uses-permission android:name=\"android.permission.READ_MEDIA_IMAGES\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_MEDIA_VIDEO\"/>"
+                ]
+            },
+            /*使用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" : false
+            },
+            "plugins" : {
+                "ad" : {},
+                "geolocation" : {},
+                "share" : {}
+            },
+            "ios" : {
+                "dSYMs" : false
+            }
+        }
+    },
+    "screenOrientation" : [ "portrait-primary" ]
+}

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

@@ -1,8 +1,8 @@
 {
   "appId": "com.muchinfo.tss",
   "appName": "TCE",
-  "version": "1.0.61",
-  "versionCode": "100061",
+  "version": "1.0.62",
+  "versionCode": "100062",
   "apiUrl": "http://192.168.31.210:8080/cfg?key=test_210",
   "tradeChannel": "ws",
   "showLoginAlert": true,

+ 14 - 0
script/oem.env.json

@@ -232,5 +232,19 @@
         "VUE_APP_ROOT": "src/packages/tss-vi/",
         "VUE_APP_OEM": "oem/tss-vi/",
         "VUE_APP_TRADE_CHANNEL": "ws"
+    },
+    {
+        "VUE_APP_ENV": "snhl",
+        "VUE_APP_NAME": "三农互联",
+        "VUE_APP_ROOT": "src/packages/snhl/",
+        "VUE_APP_OEM": "oem/snhl/",
+        "VUE_APP_TRADE_CHANNEL": "ws"
+    },
+    {
+        "VUE_APP_ENV": "snhl@pc",
+        "VUE_APP_NAME": "三农互联",
+        "VUE_APP_ROOT": "src/packages/pc/",
+        "VUE_APP_OEM": "oem/snhl/",
+        "VUE_APP_TRADE_CHANNEL": "ws"
     }
 ]

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

@@ -44,10 +44,10 @@ export function useLogin(persist = false) {
         await Promise.all([
             errorInfoStore.getErrorInfoList(),
             enumStore.getAllEnumList(),
-            userStore.getSystemParams()
+            userStore.getSystemParams(),
+            commonStore.fetcheDocuments()
         ])
         goodsCollectionStore.fetchGoodsCollections()
-        commonStore.fetcheDocuments()
     }
 
     const loadUserData = async () => {

+ 33 - 47
src/packages/mobile/components/layouts/login/index.vue

@@ -9,7 +9,7 @@
         <img :src="logoSrc" />
       </slot>
     </div>
-    <Form class="login-form" @submit="formSubmit">
+    <Form ref="formRef" class="login-form" @submit="formValidate">
       <CellGroup inset>
         <Field v-model="formData.userName" name="account" :label="$t('user.login.username')" label-align="top"
           size="large" :placeholder="$t('user.login.Pleaseenterausername')"
@@ -17,15 +17,12 @@
         <Field v-model="formData.password" name="password" type="password" :label="$t('user.login.password')"
           label-align="top" size="large" :placeholder="$t('user.login.Pleaseenterthepassword')"
           :rules="[{ required: true, message: $t('user.login.Pleaseenterthepassword') }]" autocomplete="off" />
-        <Cell>
-          <template #value>
-            <SliderVerify @statu="slide" style="width: 100%;" v-if="showSliderVerify" />
-          </template>
-        </Cell>
       </CellGroup>
-      <div class="button-submit">
-        <Button type="primary" native-type="submit" round block>{{ $t('user.login.login') }}</Button>
-      </div>
+      <ClickVerify class="button-submit" v-model:show="showClickVerify" @success="formSubmit">
+        <Button type="primary" native-type="submit" @click="formRef?.submit" round block>
+          {{ $t('user.login.login') }}
+        </Button>
+      </ClickVerify>
     </Form>
     <div class="login-link">
       <span @click="navigationTo('user-register')" v-if="globalStore.hasSystemModule('register')">{{
@@ -54,14 +51,14 @@
 
 <script lang="ts" setup>
 import { shallowRef } from 'vue'
-import { Button, Field, CellGroup,Cell, Form, Checkbox, showFailToast, showToast } from 'vant'
+import { FormInstance, Button, Field, CellGroup, Cell, Form, Checkbox, showFailToast, showToast } from 'vant'
 import { fullloading, dialog } from '@/utils/vant'
 import { useLogin } from '@/business/login'
 import { useNavigation } from '@mobile/router/navigation'
 import { useGlobalStore, i18n } from '@/stores'
 import service from '@/services'
-import SliderVerify from '@/components/base/slider-verify/index.vue' // 临时调用,待优化
 import logoImage from '../../../assets/images/login-logo.png'
+import ClickVerify from '@mobile/components/base/click-verify/index.vue'
 import AppLuanguage from '@mobile/components/modules/luanguage/index.vue'
 
 const props = defineProps({
@@ -87,9 +84,9 @@ const { global: { t } } = i18n
 const globalStore = useGlobalStore()
 const { setGlobalUrlParams, routerTo, routerBack } = useNavigation()
 const { formData, userLogin } = useLogin()
+const formRef = shallowRef<FormInstance>()
 const checked = shallowRef(false) // 是否同意协议管理
-const showSliderVerify = shallowRef(true) // 验证滑块组件重载
-const sliderVerifyStatus = shallowRef(false) // 滑块验证状态
+const showClickVerify = shallowRef(false) // 显示验证窗口
 
 const meta = document.getElementsByTagName('meta')
 const appVersion = meta.namedItem('revised')?.content ?? '0'
@@ -106,46 +103,35 @@ const navigationTo = (name: string) => {
   }, t('user.login.loading'))
 }
 
-// 滑块验证 
-const slide = (vfcStatu: { statu: string }) => {
-  if (vfcStatu.statu === 'success') {
-    sliderVerifyStatus.value = true
+// 表单验证
+const formValidate = () => {
+  if (checked.value) {
+    showClickVerify.value = true
   } else {
-    sliderVerifyStatus.value = false
+    showToast(t('user.login.tips2'))
   }
 }
 
+// 表单提交
 const formSubmit = () => {
-  if (sliderVerifyStatus.value) {
-    if (checked.value) {
-      fullloading((hideLoading) => {
-        userLogin().then((forcedPasswordChange) => {
-          hideLoading()
-          if (forcedPasswordChange) {
-            dialog(t('user.login.tips1')).then(() => {
-              setGlobalUrlParams({ forcedPasswordChange })
-              routerTo('user-password', true)
-            })
-          } else if (props.showReport) {
-            routerTo('report', true)
-          } else {
-            routerBack()
-          }
-        }).catch((err) => {
-          showSliderVerify.value = false
-          sliderVerifyStatus.value = false
-          formData.password = ''
-          hideLoading(err, 'fail')
-
-          setTimeout(() => {
-            showSliderVerify.value = true
-          }, 0)
+  fullloading((hideLoading) => {
+    userLogin().then((forcedPasswordChange) => {
+      hideLoading()
+      if (forcedPasswordChange) {
+        dialog(t('user.login.tips1')).then(() => {
+          setGlobalUrlParams({ forcedPasswordChange })
+          routerTo('user-password', true)
         })
-      }, t('user.login.logining'))
-    } else {
-      showToast(t('user.login.tips2'))
-    }
-  }
+      } else if (props.showReport) {
+        routerTo('report', true)
+      } else {
+        routerBack()
+      }
+    }).catch((err) => {
+      formData.password = ''
+      hideLoading(err, 'fail')
+    })
+  }, t('user.login.logining'))
 }
 </script>
 

+ 1 - 1
src/packages/mobile/router/section.ts

@@ -5,7 +5,7 @@ const homeRoutes: RouteRecordRaw[] = [
     {
         path: 'pricing',
         name: 'home-pricing',
-        component: () => import('@mobile/views/pricing/list/v2/index.vue'),
+        component: () => import('@mobile/views/pricing/list/Index.vue'),
     },
     {
         path: 'ballot',

+ 31 - 43
src/packages/mobile/views/pricing/list/Index.vue

@@ -3,38 +3,41 @@
         <template #header>
             <app-navbar :title="titleName" :show-back-button="showBackButton" />
         </template>
-        <app-list :columns="columns" :data-list="dataList" @row-click="rowClick">
+        <app-list :columns="columns" :data-list="futuresStore.marketGoodsList" @row-click="rowClick">
             <!-- 当前价 -->
             <template #last="{ row }">
-                <span :class="row.lastColor">{{ row.last }}</span>
+                <span :class="row.lastColor">{{ handleNumberValue(formatDecimal(row.last, row.decimalplace)) }}</span>
             </template>
             <!-- 涨跌 -->
             <template #rise="{ row }">
-                <span :class="row.lastColor">{{ row.rise }}</span>
+                <span :class="row.lastColor">{{ formatDecimal(row.rise, row.decimalplace) }}</span>
             </template>
             <!-- 幅度 -->
             <template #change="{ row }">
-                <span :class="row.lastColor">{{ row.change }}</span>
+                <span :class="row.lastColor">{{ parsePercent(row.change) }}</span>
             </template>
             <!-- 今开 -->
             <template #opened="{ row }">
-                <span :class="row.openedColor">{{ row.opened }}</span>
+                <span :class="row.openedColor">{{ handleNumberValue(formatDecimal(row.opened, row.decimalplace))
+                    }}</span>
             </template>
             <!-- 最低 -->
             <template #lowest="{ row }">
-                <span :class="row.lowestColor">{{ row.lowest }}</span>
+                <span :class="row.lowestColor">{{ handleNumberValue(formatDecimal(row.lowest, row.decimalplace))
+                    }}</span>
             </template>
             <!-- 最高 -->
             <template #highest="{ row }">
-                <span :class="row.highestColor">{{ row.highest }}</span>
+                <span :class="row.highestColor">{{ handleNumberValue(formatDecimal(row.highest, row.decimalplace))
+                    }}</span>
             </template>
             <!-- 买价 -->
             <template #ask="{ row }">
-                <span :class="row.askColor">{{ row.ask }}</span>
+                <span :class="row.askColor">{{ handleNumberValue(formatDecimal(row.ask, row.decimalplace)) }}</span>
             </template>
             <!-- 卖价 -->
             <template #bid="{ row }">
-                <span :class="row.bidColor">{{ row.bid }}</span>
+                <span :class="row.bidColor">{{ handleNumberValue(formatDecimal(row.bid, row.decimalplace)) }}</span>
             </template>
         </app-list>
     </app-view>
@@ -42,11 +45,10 @@
 
 <script lang="ts" setup>
 
-import { computed, onUnmounted,onActivated, PropType } from 'vue'
+import { computed, onUnmounted, onActivated, PropType, watch } from 'vue'
 import { parsePercent, handleNumberValue, formatDecimal } from '@/filters'
 import { useNavigation } from '@mobile/router/navigation'
 import { useFuturesStore, i18n } from '@/stores'
-import { ETradeMode } from '@/constants/client'
 import quoteSocket from '@/services/websocket/quote'
 import AppList from '@mobile/components/base/list/index.vue'
 import { BuyOrSell, BuildType } from '@/constants/order'
@@ -61,43 +63,14 @@ const props = defineProps({
     }
 })
 
-const { global: { t } } = i18n
+const { t } = i18n.global
 const { router, getQueryString } = useNavigation()
+const subscribe = quoteSocket.createSubscribe()
 const futuresStore = useFuturesStore()
 
 const title = getQueryString('title')
 const titleName = computed(() => title ? decodeURIComponent(title) : props.marketSection?.displayname ?? '订单点价')
 
-const dataList = computed(() => {
-    const list = futuresStore.getGoodsListByTradeMode(ETradeMode.TRADEMODE_MARKETMAKE)
-    return list.map((item) => {
-        const quote = futuresStore.getGoodsQuote(item.goodscode)
-        const { lastColor, openedColor, lowestColor, highestColor, last = 0, presettle = 0, rise = 0, change, amplitude, highest = 0, lowest = 0, opened = 0, ask = 0, bid = 0, bidColor, askColor, decimalplace } = quote.value ?? {}
-        return {
-            ...item,
-            lastColor,
-            openedColor,
-            lowestColor,
-            highestColor,
-            last: handleNumberValue(formatDecimal(last, decimalplace)),
-            rise: handleNumberValue(formatDecimal(rise, decimalplace)),
-            change: parsePercent(change),
-            opened: handleNumberValue(formatDecimal(opened, decimalplace)),
-            presettle: handleNumberValue(formatDecimal(presettle, decimalplace)),
-            lowest: handleNumberValue(formatDecimal(lowest, decimalplace)),
-            highest: handleNumberValue(formatDecimal(highest, decimalplace)),
-            amplitude: parsePercent(amplitude),
-            ask: handleNumberValue(formatDecimal(ask, decimalplace)),
-            bid: handleNumberValue(formatDecimal(bid, decimalplace)),
-            bidColor,
-            askColor
-        }
-    })
-})
-
-const goodsCodes = dataList.value.map((e) => e.goodscode.toUpperCase())
-const subscribe = quoteSocket.createSubscribe()
-
 const columns: Model.TableColumn[] = [
     { field: 'goodscode', label: t('quote.goodscode') },
     { field: 'last', label: t('quote.last') },
@@ -124,6 +97,21 @@ const rowClick = (row: Model.GoodsQuote) => {
     })
 }
 
-onActivated(() => subscribe.start(...goodsCodes))
+const getMarketGoodsList = () => {
+    const marketIds = getQueryString('markets') ?? props.marketSection?.marketids
+    const ids = marketIds?.split(',')
+    if (ids) {
+        futuresStore.setMarketId(...ids.map((id) => Number(id)))
+        const goodsCodes = futuresStore.marketGoodsList.map((e) => e.goodscode)
+        subscribe.start(...goodsCodes)
+    }
+}
+
+watch(() => props.marketSection?.marketids, () => {
+    subscribe.stop()
+    getMarketGoodsList()
+})
+
+onActivated(() => getMarketGoodsList())
 onUnmounted(() => subscribe.stop())
 </script>

+ 5 - 4
src/packages/mobile/views/rules/fwrx/Index.vue

@@ -3,13 +3,14 @@
         <template #header>
             <app-navbar :title="$t('rules.fwrx')" />
         </template>
-        <component :is="asyncComponent" :url="getHtmlFileUrl('fwrx.htm')" />
+        <HtmlContainer style="padding: 15px;" class="content" :context="formatHtmlString(commonStore.getDocumentById(1))" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-import { defineAsyncComponent } from 'vue'
-import { getHtmlFileUrl } from '@/filters'
+import { useCommonStore } from '@/stores/modules/common'
+import HtmlContainer from '@mobile/components/base/html-container/index.vue'
+import { formatHtmlString } from '@/filters'
 
-const asyncComponent = defineAsyncComponent(() => import('@mobile/components/base/html-panel/index.vue'))
+const commonStore = useCommonStore()
 </script>

+ 6 - 5
src/packages/mobile/views/rules/yszc/Index.vue

@@ -1,15 +1,16 @@
 <template>
     <app-view>
         <template #header>
-            <app-navbar :title="$t('rules.ryszc')" />
+            <app-navbar :title="$t('rules.yszc')" />
         </template>
-        <component :is="asyncComponent" :url="getHtmlFileUrl('yszc.htm')" />
+        <HtmlContainer style="padding: 15px;" class="content" :context="formatHtmlString(commonStore.getDocumentById(4))" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-import { defineAsyncComponent } from 'vue'
-import { getHtmlFileUrl } from '@/filters'
+import { useCommonStore } from '@/stores/modules/common'
+import HtmlContainer from '@mobile/components/base/html-container/index.vue'
+import { formatHtmlString } from '@/filters'
 
-const asyncComponent = defineAsyncComponent(() => import('@mobile/components/base/html-panel/index.vue'))
+const commonStore = useCommonStore()
 </script>

+ 5 - 4
src/packages/mobile/views/rules/zcxy/Index.vue

@@ -3,13 +3,14 @@
         <template #header>
             <app-navbar :title="$t('rules.zcxy')" />
         </template>
-        <component :is="asyncComponent" :url="getHtmlFileUrl('yhzcxy.htm')" />
+        <HtmlContainer style="padding: 15px;" class="content" :context="formatHtmlString(commonStore.getDocumentById(3))" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-import { defineAsyncComponent } from 'vue'
-import { getHtmlFileUrl } from '@/filters'
+import { useCommonStore } from '@/stores/modules/common'
+import HtmlContainer from '@mobile/components/base/html-container/index.vue'
+import { formatHtmlString } from '@/filters'
 
-const asyncComponent = defineAsyncComponent(() => import('@mobile/components/base/html-panel/index.vue'))
+const commonStore = useCommonStore()
 </script>

+ 1 - 1
src/packages/sbyj/views/user/login/Index.vue

@@ -2,7 +2,7 @@
   <app-statusbar class="login">
     <app-navback class="login-navback" />
     <div class="login-logo">
-      <img :src="'./img/login-logo.png'" />
+      <img :src="'./logo/logo-horizontal.png'" />
     </div>
     <Form ref="formRef" class="login-form" @submit="formValidate">
       <CellGroup inset>

+ 7 - 0
src/packages/snhl/App.vue

@@ -0,0 +1,7 @@
+<template>
+  <app-view />
+</template>
+
+<script lang="ts" setup>
+import AppView from '@mobile/App.vue'
+</script>

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


+ 72 - 0
src/packages/snhl/index.html

@@ -0,0 +1,72 @@
+<!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">
+  <link rel="apple-touch-icon-precomposed" href="<%= BASE_URL %>apple-touch-icon-precomposed.png">
+  <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>

+ 35 - 0
src/packages/snhl/main.ts

@@ -0,0 +1,35 @@
+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 '@mobile/assets/themes/style.less' // 主题样式
+// import { timerInterceptor } from '@/utils/timer'
+import { i18n } from '@/stores'
+// import Vconsole from 'vconsole'
+// new Vconsole()
+
+const app = createApp(App)
+app.use(i18n)
+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/snhl/postcss.config.js

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

+ 353 - 0
src/packages/snhl/router/index.ts

@@ -0,0 +1,353 @@
+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: '/register',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'register',
+        component: () => import('@mobile/views/user/register/home.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+        props: {
+          showYhkhfxgzs: false,
+          insetStyle: false
+        }
+      }
+    ]
+  },
+  {
+    path: '/',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'home',
+        component: () => import('@mobile/views/home/Index.vue'),
+        children: [
+          {
+            path: '',
+            name: 'home-index',
+            component: () => import('@mobile/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,
+        },
+        props: {
+          showYhkhfxgzs: false,
+          insetStyle: false
+        }
+      },
+      {
+        path: 'forget',
+        name: 'user-forget',
+        component: () => import('@mobile/views/user/forget/Index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+        props: {
+          insetStyle: false
+        }
+      },
+      {
+        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: '/account',
+    component: Page,
+    children: [
+      {
+        path: 'certification',
+        name: 'account-certification',
+        component: () => import('@mobile/views/account/certification/Index.vue'),
+      },
+      {
+        path: 'authresult',
+        name: 'account-authresult',
+        component: () => import('@mobile/views/account/authresult/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'),
+        props: {
+          showBackButton: true
+        }
+      },
+      {
+        path: 'delivery',
+        name: 'order-delivery',
+        component: () => import('../views/order/delivery/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') {
+      next()
+    } else {
+      next({
+        name: 'boot',
+        query: { redirect: to.fullPath },
+      })
+    }
+  }
+})
+
+export default router

+ 19 - 0
src/packages/snhl/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;
+        }
+    }
+}

+ 99 - 0
src/packages/snhl/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>

+ 227 - 0
src/packages/snhl/views/mine/index.vue

@@ -0,0 +1,227 @@
+<template>
+    <app-view class="mine">
+        <template #header>
+            <app-navbar :title="$t('mine.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">
+                        <div class="profile-account-first">
+                            <span>{{ $t('account.account') }}</span>
+                            <span class="status">{{ $t('mine.normal') }}</span>
+                        </div>
+                        <span>{{ currentAccount.accountid ?? 0 }}</span>
+                    </div>
+                </div>
+                <div class="bank">
+                    <ul>
+                        <li>
+                            <span>{{ $t('mine.balance') }}</span>
+                            <span>{{ currentAccount.currentbalance?.toFixed(2) }}</span>
+                        </li>
+                        <li>
+                            <span>{{ $t('mine.netWorth') }}</span>
+                            <span>{{ currentAccount.hazardValue?.toFixed(2) }}</span>
+                        </li>
+                    </ul>
+                    <ul>
+                        <li>
+                            <span>{{ $t('mine.freezeMargin') }}</span>
+                            <span>{{ currentAccount.freezeMargin?.toFixed(2) }}</span>
+                        </li>
+                        <li>
+                            <span>{{ $t('mine.usedMargin') }}</span>
+                            <span>{{ currentAccount.usedmargin?.toFixed(2) }}</span>
+                        </li>
+                    </ul>
+                    <ul>
+                        <li>
+                            <span>{{ $t('mine.availableFunds') }}</span>
+                            <span>{{ currentAccount.avaiableMoney?.toFixed(2) }}</span>
+                        </li>
+                        <li>
+                            <span>{{ $t('mine.riskRate') }}</span>
+                            <span :class="currentAccount.hazardRatioColor">
+                                {{ parsePercent(currentAccount.hazardRatio) }}
+                            </span>
+                        </li>
+                    </ul>
+                </div>
+                <div class="button">
+                    <Button type="danger" size="small" round @click="doInOutMoney('0')">{{ $t('mine.cashin') }}</Button>
+                    <Button size="small" round @click="doInOutMoney('1')">{{ $t('mine.cashout') }}</Button>
+                </div>
+            </div>
+        </div>
+        <app-block class="mine-iconbar">
+            <ul>
+                <li @click="routerTo('order-position')">
+                    <Iconfont label-direction="bottom" icon="g-icon-position--line">{{ $t('mine.myposition') }}</Iconfont>
+                </li>
+                <li @click="routerTo('order-list')">
+                    <Iconfont label-direction="bottom" icon="g-icon-order--line">{{ $t('mine.myorder') }}</Iconfont>
+                </li>
+                <li @click="routerTo('order-delivery')">
+                    <Iconfont label-direction="bottom" icon="g-icon-delivery--line">{{ $t('mine.delivery') }}</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">{{ $t('mine.fundsinfo') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'account-authresult' }" v-if="authStatus === AuthStatus.Submitted">
+                    <template #title>
+                        <Iconfont icon="g-icon-certification">{{ $t('mine.authentication') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'account-certification' }" v-else-if="authStatus !== AuthStatus.Certified">
+                    <template #title>
+                        <Iconfont icon="g-icon-certification">{{ $t('mine.authentication') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'bank-sign' }" v-if="authStatus === AuthStatus.Certified">
+                    <template #title>
+                        <Iconfont icon="g-icon-sign">{{ $t('mine.banksign') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'mine-profile' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-profile">{{ $t('mine.personalinformation') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-zcxy' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-zcxy">{{ $t('rules.zcxy') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-yszc' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-yszc">{{ $t('rules.yszc') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-fwrx' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-fwrx">{{ $t('rules.fwrx') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'mine-setting' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-setting">{{ $t('mine.settings') }}</Iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'rules-gywm' }">
+                    <template #title>
+                        <Iconfont icon="g-icon-gywm">{{ $t('mine.aboutus') }}</Iconfont>
+                    </template>
+                </Cell>
+            </CellGroup>
+        </app-block>
+        <div class="mine-footer">
+            <Button class="button-logout" type="danger" size="small" round @click="userLogout">{{ $t('common.logout') }}</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'
+import { i18n } from '@/stores'
+
+const { global: { t } } = i18n
+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: t('banksign.tips1'),
+                        showCancelButton: true,
+                        confirmButtonText: t('banksign.tips2')
+                    }).then(() => {
+                        router.push({ name: 'bank-sign' })
+                    })
+                }
+            }).catch(() => {
+                hideLoading(t('common.loadingfailed'), 'fail')
+            })
+        }, t('common.loading'))
+    } else {
+        dialog({
+            message: t('banksign.tips3'),
+            showCancelButton: true,
+            confirmButtonText: t('banksign.tips4')
+        }).then(() => {
+            router.push({ name: 'account-certification' })
+        })
+    }
+}
+
+const userLogout = () => {
+    dialog({
+        message: t('banksign.tips5'),
+        showCancelButton: true,
+        confirmButtonText: t('operation.confirm'),
+    }).then(() => {
+        loginStore.clearAutoLoginData()
+        eventBus.$emit('LogoutNotify')
+    })
+}
+
+onActivated(() => {
+    if (authStatus.value !== AuthStatus.Certified) {
+        userStore.getUserData()
+    }
+    accountStore.getAccountList()
+})
+</script>
+
+<style lang="less">
+@import '@mobile/views/mine/index.less';
+</style>

+ 20 - 0
src/packages/snhl/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: 'offline',
+        title: '线下交收单',
+        component: defineAsyncComponent(() => import('@mobile/views/order/delivery/components/offline/list/Index.vue')),
+    },
+]
+</script>

+ 47 - 0
src/packages/snhl/views/order/list/index.vue

@@ -0,0 +1,47 @@
+<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: 'goodsorder',
+        title: '订单委托',
+        component: defineAsyncComponent(() => import('@mobile/views/order/list/components/goodsorder/list/Index.vue')),
+        history: defineAsyncComponent(() => import('@mobile/views/order/list/components/goodsorder/history/Index.vue')),
+    },
+    {
+        name: 'goodstrade',
+        title: '订单成交',
+        component: defineAsyncComponent(() => import('@mobile/views/order/list/components/goodstrade/list/Index.vue')),
+        history: defineAsyncComponent(() => import('@mobile/views/order/list/components/goodstrade/history/Index.vue')),
+    }
+]
+
+const active = shallowRef(0)
+const selectedComponent = computed(() => components[active.value])
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+</script>

+ 32 - 0
src/packages/snhl/views/order/position/index.vue

@@ -0,0 +1,32 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar title="我的持仓">
+                <template #right>
+                    <div class="button-more" @click="openComponent('detail')">
+                        <span>明细</span>
+                    </div>
+                </template>
+            </app-navbar>
+        </template>
+        <component :is="components[0].component" />
+        <component ref="componentRef" :is="components[0].detail" @closed="closeComponent"
+            v-if="componentId" />
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { defineAsyncComponent } from 'vue'
+import { useComponent } from '@/hooks/component'
+
+const components = [
+    {
+        name: 'goods',
+        title: '订单持仓',
+        component: defineAsyncComponent(() => import('@mobile/views/order/position/components/goods/list/Index.vue')),
+        detail: defineAsyncComponent(() => import('@mobile/views/order/position/components/goods/detail/Index.vue')),
+    },
+]
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+</script>

+ 7 - 0
src/packages/snhl/views/user/login/index.vue

@@ -0,0 +1,7 @@
+<template>
+  <app-login />
+</template>
+
+<script lang="ts" setup>
+import AppLogin from '@mobile/components/layouts/login/index.vue'
+</script>

+ 3 - 0
src/packages/tss/views/boot/Index.vue

@@ -20,6 +20,7 @@ import { useRoute, useRouter } from 'vue-router'
 import { Swipe, SwipeItem } from 'vant'
 import { showLoading, dialog } from '@/utils/vant'
 import { useLogin } from '@/business/login'
+import { useCommonStore } from '@/stores/modules/common'
 import service from '@/services'
 import plus from '@/utils/h5plus'
 
@@ -28,6 +29,8 @@ const route = useRoute()
 const router = useRouter()
 const countdown = 1  // 倒计时秒数
 
+const commonStore=useCommonStore()
+
 const state = reactive({
   showGuide: false,
   //showGuide: (!plus.hasPlus() || localStorage.getItem('muchinfo_app_showguide') === 'false') ? false : true, // 是否显示引导页

+ 2 - 1
src/stores/storage.ts

@@ -1,9 +1,10 @@
 import { AppTheme } from '@/constants/theme'
+import { getClientLanguage } from '@/constants/language'
 import WebStorage from '@/utils/storage'
 
 function createLocalData() {
     return {
-        appLanguage: navigator.language,
+        appLanguage: getClientLanguage(),
         appTheme: AppTheme.Default,
         loginInfo: <Model.LoginRsp | undefined>undefined,
         autoLoginEncryptedData: '',

+ 8 - 0
src/types/model/common.d.ts

@@ -373,12 +373,20 @@ declare global {
 
         /** 获取终端文档配置信息 响应 */
         interface DocumnetConfigsRsp {
+            buttontext: string; // 按钮文本 [type = app启动配置]
+            buttontexten: string; // 按钮文本(英文) [type = app启动配置]
+            buttontextth: string; // 按钮文本(泰文) [type = app启动配置]
+            buttontexttw: string; // 按钮文本(繁体) [type = app启动配置]
+            buttontextvi: string; // 按钮文本(越南语) [type = app启动配置]
+            displayfrequency: number; // 显示频率 - 枚举 displayfrequency 1:首次 2:每次 3:间隔 [type = app启动配置]
             documentcontent: string; // 文档内容(简体)
             documentcontenten: string; // 文档内容(英文)
             documentcontentth: string; // 文档内容(泰文)
             documentcontenttw: string; // 文档内容(繁体)
             documentcontentvi: string; // 文档内容(越南语)
             documenttype: number; // 文档类型
+            intervaldays: number; // 间隔天数(displayfrequency=3时)[type = app启动配置]
+            isenabled: number; // 是否启用 - 0:不启用 1:启用 [type = app启动配置]
         }
     }
 }