li.shaoyi 2 年之前
父节点
当前提交
739bfc0cfd

+ 201 - 46
package-lock.json

@@ -45,6 +45,7 @@
         "@vue/cli-service": "~5.0.0",
         "@vue/eslint-config-typescript": "^9.1.0",
         "compression-webpack-plugin": "^10.0.0",
+        "copy-webpack-plugin": "^11.0.0",
         "eslint": "^7.32.0",
         "eslint-plugin-vue": "^8.0.3",
         "less": "^4.0.0",
@@ -3035,6 +3036,26 @@
         "postcss": "^8.1.0"
       }
     },
+    "node_modules/@vue/cli-service/node_modules/copy-webpack-plugin": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz",
+      "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==",
+      "dev": true,
+      "dependencies": {
+        "fast-glob": "^3.2.7",
+        "glob-parent": "^6.0.1",
+        "globby": "^11.0.3",
+        "normalize-path": "^3.0.0",
+        "schema-utils": "^3.1.1",
+        "serialize-javascript": "^6.0.0"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "peerDependencies": {
+        "webpack": "^5.1.0"
+      }
+    },
     "node_modules/@vue/cli-service/node_modules/cosmiconfig": {
       "version": "7.1.0",
       "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -3572,6 +3593,20 @@
         "postcss": "^8.2.15"
       }
     },
+    "node_modules/@vue/cli-service/node_modules/schema-utils": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz",
+      "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
     "node_modules/@vue/cli-service/node_modules/semver": {
       "version": "7.5.0",
       "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.0.tgz",
@@ -5374,45 +5409,93 @@
       }
     },
     "node_modules/copy-webpack-plugin": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz",
-      "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==",
+      "version": "11.0.0",
+      "resolved": "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz",
+      "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==",
       "dev": true,
       "dependencies": {
-        "fast-glob": "^3.2.7",
+        "fast-glob": "^3.2.11",
         "glob-parent": "^6.0.1",
-        "globby": "^11.0.3",
+        "globby": "^13.1.1",
         "normalize-path": "^3.0.0",
-        "schema-utils": "^3.1.1",
+        "schema-utils": "^4.0.0",
         "serialize-javascript": "^6.0.0"
       },
       "engines": {
-        "node": ">= 12.13.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/webpack"
+        "node": ">= 14.15.0"
       },
       "peerDependencies": {
         "webpack": "^5.1.0"
       }
     },
-    "node_modules/copy-webpack-plugin/node_modules/schema-utils": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
-      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+    "node_modules/copy-webpack-plugin/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
       "dev": true,
       "dependencies": {
-        "@types/json-schema": "^7.0.8",
-        "ajv": "^6.12.5",
-        "ajv-keywords": "^3.5.2"
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+      "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3"
+      },
+      "peerDependencies": {
+        "ajv": "^8.8.2"
+      }
+    },
+    "node_modules/copy-webpack-plugin/node_modules/globby": {
+      "version": "13.2.2",
+      "resolved": "https://registry.npmmirror.com/globby/-/globby-13.2.2.tgz",
+      "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
+      "dev": true,
+      "dependencies": {
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.3.0",
+        "ignore": "^5.2.4",
+        "merge2": "^1.4.1",
+        "slash": "^4.0.0"
       },
       "engines": {
-        "node": ">= 10.13.0"
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      }
+    },
+    "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/copy-webpack-plugin/node_modules/schema-utils": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz",
+      "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.9",
+        "ajv": "^8.9.0",
+        "ajv-formats": "^2.1.1",
+        "ajv-keywords": "^5.1.0"
       },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/webpack"
+      "engines": {
+        "node": ">= 12.13.0"
+      }
+    },
+    "node_modules/copy-webpack-plugin/node_modules/slash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmmirror.com/slash/-/slash-4.0.0.tgz",
+      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
       }
     },
     "node_modules/core-js": {
@@ -7586,9 +7669,9 @@
       "dev": true
     },
     "node_modules/fast-glob": {
-      "version": "3.2.12",
-      "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz",
-      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz",
+      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
       "dev": true,
       "dependencies": {
         "@nodelib/fs.stat": "^2.0.2",
@@ -8463,9 +8546,9 @@
       ]
     },
     "node_modules/ignore": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
-      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "version": "5.2.4",
+      "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
       "dev": true,
       "engines": {
         "node": ">= 4"
@@ -15567,6 +15650,20 @@
             "postcss-value-parser": "^4.2.0"
           }
         },
+        "copy-webpack-plugin": {
+          "version": "9.1.0",
+          "resolved": "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz",
+          "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==",
+          "dev": true,
+          "requires": {
+            "fast-glob": "^3.2.7",
+            "glob-parent": "^6.0.1",
+            "globby": "^11.0.3",
+            "normalize-path": "^3.0.0",
+            "schema-utils": "^3.1.1",
+            "serialize-javascript": "^6.0.0"
+          }
+        },
         "cosmiconfig": {
           "version": "7.1.0",
           "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -15915,6 +16012,17 @@
             "postcss-selector-parser": "^6.0.5"
           }
         },
+        "schema-utils": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz",
+          "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+          "dev": true,
+          "requires": {
+            "@types/json-schema": "^7.0.8",
+            "ajv": "^6.12.5",
+            "ajv-keywords": "^3.5.2"
+          }
+        },
         "semver": {
           "version": "7.5.0",
           "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.0.tgz",
@@ -17333,29 +17441,76 @@
       "dev": true
     },
     "copy-webpack-plugin": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz",
-      "integrity": "sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA==",
+      "version": "11.0.0",
+      "resolved": "https://registry.npmmirror.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz",
+      "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==",
       "dev": true,
       "requires": {
-        "fast-glob": "^3.2.7",
+        "fast-glob": "^3.2.11",
         "glob-parent": "^6.0.1",
-        "globby": "^11.0.3",
+        "globby": "^13.1.1",
         "normalize-path": "^3.0.0",
-        "schema-utils": "^3.1.1",
+        "schema-utils": "^4.0.0",
         "serialize-javascript": "^6.0.0"
       },
       "dependencies": {
+        "ajv": {
+          "version": "8.12.0",
+          "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz",
+          "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+          "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.3"
+          }
+        },
+        "globby": {
+          "version": "13.2.2",
+          "resolved": "https://registry.npmmirror.com/globby/-/globby-13.2.2.tgz",
+          "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
+          "dev": true,
+          "requires": {
+            "dir-glob": "^3.0.1",
+            "fast-glob": "^3.3.0",
+            "ignore": "^5.2.4",
+            "merge2": "^1.4.1",
+            "slash": "^4.0.0"
+          }
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        },
         "schema-utils": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
-          "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+          "version": "4.2.0",
+          "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-4.2.0.tgz",
+          "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
           "dev": true,
           "requires": {
-            "@types/json-schema": "^7.0.8",
-            "ajv": "^6.12.5",
-            "ajv-keywords": "^3.5.2"
+            "@types/json-schema": "^7.0.9",
+            "ajv": "^8.9.0",
+            "ajv-formats": "^2.1.1",
+            "ajv-keywords": "^5.1.0"
           }
+        },
+        "slash": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmmirror.com/slash/-/slash-4.0.0.tgz",
+          "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+          "dev": true
         }
       }
     },
@@ -18911,9 +19066,9 @@
       "dev": true
     },
     "fast-glob": {
-      "version": "3.2.12",
-      "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz",
-      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz",
+      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
       "dev": true,
       "requires": {
         "@nodelib/fs.stat": "^2.0.2",
@@ -19554,9 +19709,9 @@
       "dev": true
     },
     "ignore": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
-      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "version": "5.2.4",
+      "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
       "dev": true
     },
     "image-size": {

+ 1 - 0
package.json

@@ -53,6 +53,7 @@
     "@vue/cli-service": "~5.0.0",
     "@vue/eslint-config-typescript": "^9.1.0",
     "compression-webpack-plugin": "^10.0.0",
+    "copy-webpack-plugin": "^11.0.0",
     "eslint": "^7.32.0",
     "eslint-plugin-vue": "^8.0.3",
     "less": "^4.0.0",

+ 1 - 1
public/config/appconfig.json

@@ -1,6 +1,6 @@
 {
   "version": "1.0.0",
   "versionCode": "100000",
-  "apiUrl": "http://192.168.31.171:8080/cfg?key=test_171",
+  "apiUrl": "http://192.168.31.204:8080/cfg?key=test_204",
   "appName": "多元世纪"
 }

+ 9 - 2
public/manifest.json

@@ -2,7 +2,7 @@
     "@platforms" : [ "android", "iPhone", "iPad" ],
     "id" : "H5E4A9458",
     /*应用的标识*/
-    "name" : "多元演示系统",
+    "name" : "多元世纪",
     /*应用名称,程序桌面图标名称*/
     "version" : {
         "name" : "1.0.0",
@@ -145,7 +145,14 @@
                 /*Android应用打包使用密钥库中证书的密码*/
                 "aliasname" : "",
                 /*Android应用打包使用密钥库中证书的别名*/
-                "permissions" : [],
+                "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" : 29

+ 1 - 29
src/business/user/account.ts

@@ -182,7 +182,7 @@ export function useRequestWillFace() {
             loading.value = true
             return await requestWillFace({
                 data: {
-                    ... willFaceFormData
+                    ...willFaceFormData
                 }
             })
         } finally {
@@ -195,32 +195,4 @@ export function useRequestWillFace() {
         willFaceFormData,
         willFace
     }
-}
-
-// 证件号重复校验
-export function useCheckCardNum() {
-    const loading = shallowRef(false)
-
-    const checkCardNumFormData = reactive<Model.CheckCardNumReq>({
-        userid: loginStore.userId
-    })
-
-    const checkCardNum = async () => {
-        try {
-            loading.value = true
-            return await requestCheckCardNum({
-                data: {
-                    ...checkCardNumFormData
-                }
-            })
-        } finally {
-            loading.value = false
-        }
-    }
-
-    return {
-        loading,
-        checkCardNumFormData,
-        checkCardNum,
-    }
 }

+ 17 - 0
src/constants/market.ts

@@ -17,4 +17,21 @@ export function getTHJMarketList() {
 export function getTHJMarketName(value: number) {
     const enums = getTHJMarketList()
     return getEnumTypeName(enums, value)
+}
+
+/**
+ * 获取市场运行状态列表
+ * @returns 
+ */
+export function getRunStatusList() {
+    return getEnumTypeList('runstatus')
+}
+
+/**
+ * 获取市场运行状态名称
+ * @returns 
+ */
+export function getRunStatusName(value: number) {
+    const enums = getRunStatusList()
+    return getEnumTypeName(enums, value)
 }

+ 1 - 0
src/packages/gstj/views/mine/Index.vue

@@ -182,6 +182,7 @@ const userLogout = () => {
         message: '是否退出当前账号?',
         showCancelButton: true
     }).then(() => {
+        authStatus.value = AuthStatus.Uncertified
         loginStore.clearAutoLoginData()
         eventBus.$emit('LogoutNotify')
     })

+ 1 - 0
src/packages/mobile/views/mine/Index.vue

@@ -182,6 +182,7 @@ const userLogout = () => {
         message: '是否退出当前账号?',
         showCancelButton: true
     }).then(() => {
+        authStatus.value = AuthStatus.Uncertified
         loginStore.clearAutoLoginData()
         eventBus.$emit('LogoutNotify')
     })

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

@@ -34,7 +34,7 @@
         </div>
         <div class="app-footer__center">
             <app-auth-component code="bottom">
-                <el-select placeholder="请选择资金账户" :disabled="loading" v-model="currentAccountId" @change="onAccountChange"
+                <el-select placeholder="请选择资金账户" :disabled="loading" v-model="currentAccountId" @change="getAccountList"
                     v-if="false">
                     <el-option :label="item.accountid" :value="item.accountid" v-for="(item, index) in accountList"
                         :key="index" />
@@ -52,12 +52,7 @@ import { useAccountStore } from '@/stores'
 import AppAuthComponent from '@pc/components/modules/auth-component/index.vue'
 import AppListing from '@pc/components/modules/listing/index.vue'
 
-const { accountList, currentAccount, currentAccountId, loading, getAccountPositionList } = useAccountStore()
-
-// 切换资金账户
-const onAccountChange = () => {
-    getAccountPositionList()
-}
+const { accountList, currentAccount, currentAccountId, loading, getAccountList } = useAccountStore()
 </script>
 
 <style lang="less">

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

@@ -6,14 +6,28 @@
     &__statusbar {
         display: flex;
         align-items: center;
-        color: #fff;
+        color: #ACB8C0;
+        font-size: 13px;
         background-color: #181e22;
         border-top: 1px solid #363f45;
+        padding: 8px 0;
 
         .statusbar {
             &-right {
-                padding: 5px;
                 margin-left: auto;
+
+                ul {
+                    display: flex;
+                    align-items: center;
+
+                    li {
+                        padding: 0 20px;
+
+                        &:not(:first-child) {
+                            border-left: 1px solid #363f45;
+                        }
+                    }
+                }
             }
         }
     }

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

@@ -33,8 +33,20 @@
       <div class="statusbar-left">
       </div>
       <div class="statusbar-right">
-        <!-- <span>{{ serverTime?.format('MM/DD') }}</span> -->
-        <span>{{ serverTime?.format('HH:mm:ss') }}</span>
+        <ul>
+          <li>
+            <span>用户ID:</span>
+            <span>{{ loginStore.userId }}</span>
+          </li>
+          <li>
+            <span>登录ID:</span>
+            <span>{{ loginStore.loginId }}</span>
+          </li>
+          <li>
+            <!-- <span>{{ serverTime?.format('MM/DD') }}</span> -->
+            <span>{{ serverTime?.format('HH:mm:ss') }}</span>
+          </li>
+        </ul>
       </div>
     </div>
   </div>
@@ -45,7 +57,7 @@ import { ref, onMounted, onUnmounted } from 'vue'
 import { RouteRecordNormalized, RouteRecordName } from 'vue-router'
 import { timerTask } from '@/utils/timer'
 import { getServerTime } from '@/services/api/common'
-import { useGlobalStore } from '@/stores'
+import { useGlobalStore, useLoginStore } from '@/stores'
 import eventBus from '@/services/bus'
 import moment, { Moment } from 'moment'
 import AppHeader from '../header/index.vue'
@@ -54,6 +66,7 @@ import AppNavbar from '../navbar/index.vue'
 import AppSidebar from '../sidebar/index.vue'
 
 const globalStore = useGlobalStore()
+const loginStore = useLoginStore()
 const isCollapse = ref(globalStore.isMobile)
 const serverTime = ref<Moment>()
 

+ 12 - 0
src/packages/pc/components/modules/quote/price/index.vue

@@ -51,6 +51,18 @@
                     <span>振幅</span>
                     <span>{{ parsePercent(quote.amplitude) }}</span>
                 </li>
+                <li>
+                    <span>成交量</span>
+                    <span>{{ handleNumberValue(quote.totalvolume) }}</span>
+                </li>
+                <li>
+                    <span>成交额</span>
+                    <span>{{ handleNumberValue(quote.totalturnover) }}</span>
+                </li>
+                <li>
+                    <span>持仓量</span>
+                    <span>{{ handleNumberValue(quote.holdvolume) }}</span>
+                </li>
             </ul>
         </div>
     </div>

+ 0 - 4
src/packages/pc/views/footer/goods/position/index.vue

@@ -5,10 +5,6 @@
         <template #buyorsell="{ value }">
             {{ getBuyOrSellName(value) }}
         </template>
-        <!-- 均价-->
-        <template #averageprice="{ row }">
-            <span>{{ formatDecimal(row.averageprice, row.decimalplace) }}</span>
-        </template>
         <!-- 最新价 -->
         <template #lastprice="{ row }">
             <span :class="row.lastColor">

+ 1 - 1
src/packages/pc/views/market/trade/goods/detail/components/chart/index.less

@@ -10,7 +10,7 @@
     >.block-right {
         display: flex;
         flex-direction: column;
-        width: 240px;
+        width: 260px;
         background-color: #14181B;
         border-left: 1px solid #33393D;
         overflow: hidden;

+ 25 - 5
src/packages/pc/views/market/trade/goods/detail/index.vue

@@ -13,12 +13,15 @@
                             <span>{{ quote.goodsname }}</span>
                         </li>
                     </ul>
-                    <div class="buttonbar" v-if="false">
-                        <template v-if="active">
-                            <!-- <el-button type="info" style="min-width: 60px;">刷新</el-button> -->
+                    <div class="buttonbar">
+                        <!-- <template v-if="active">
+                            <el-button type="info" style="min-width: 60px;">刷新</el-button>
                             <el-button type="primary" @click="active = false">买卖大厅</el-button>
                         </template>
-                        <el-button type="primary" @click="active = true" v-else>图表</el-button>
+                        <el-button type="primary" @click="active = true" v-else>图表</el-button> -->
+                        <template v-if="market">
+                            <span style="color: #3a87f7;padding: 10px;">市场状态:{{ getRunStatusName(market.runstatus) }}</span>
+                        </template>
                     </div>
                 </div>
             </template>
@@ -29,7 +32,11 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, computed, defineAsyncComponent } from 'vue'
+import { onUnmounted, shallowRef, computed, defineAsyncComponent } from 'vue'
+import { timerTask } from '@/utils/timer'
+import { getRunStatusName } from '@/constants/market'
+import { useRequest } from '@/hooks/request'
+import { queryMarketRun } from '@/services/api/market'
 import { useFuturesStore } from '@/stores'
 
 const Chart = defineAsyncComponent(() => import('./components/chart/index.vue'))
@@ -48,4 +55,17 @@ const quote = futuresStore.getGoodsQuote(props.goodsId)
 const active = shallowRef(true)
 
 const goodsCode = computed(() => quote.value?.goodscode ?? '')
+
+const { data: market, run } = useRequest(queryMarketRun, {
+    params: {
+        marketID: quote.value?.marketid
+    },
+    onSuccess: (res) => {
+        market.value = res.data[0]
+        // 每1分钟轮询刷新
+        timerTask.setTimeout(() => run(), 60 * 1000, 'getMarketRun')
+    }
+})
+
+onUnmounted(() => timerTask.clearTimeout('getMarketRun'))
 </script>

+ 17 - 1
src/packages/qxst/components/base/uploader/index.vue

@@ -4,11 +4,18 @@
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue'
+import { ref, PropType, watch } from 'vue'
 import { showFailToast, Uploader, UploaderFileListItem } from 'vant'
 import service from '@/services'
 import axios from 'axios'
 
+const props = defineProps({
+    files: {
+        type: Array as PropType<string[]>,
+        default: () => ([])
+    }
+})
+
 const emit = defineEmits(['success'])
 const fileList = ref<UploaderFileListItem[]>([])
 
@@ -40,4 +47,13 @@ const afterRead = (file: any) => {
 const onDelete = () => {
     emit('success', '')
 }
+
+watch(() => props.files, () => {
+    fileList.value = []
+    props.files.forEach((url) => {
+        fileList.value.push({
+            url
+        })
+    })
+})
 </script>

+ 69 - 71
src/packages/qxst/views/account/certification/Index.vue

@@ -5,28 +5,29 @@
         </template>
         <Form ref="formRef" class="g-form__container" @submit="onCheckCardNum" :loading="loading">
             <CellGroup inset>
-                <Field v-model="formData.name" name="name" label="姓名" placeholder="请输入用户姓名"
-                    :rules="formRules.name" />
-                <Field name="mobile" readonly label="手机号码" >
-                    <template #input>
-                        <span>{{ mobile2 }}</span>
-                    </template>
-                </Field>
+                <Field v-model="formData.name" name="name" label="姓名" placeholder="请输入用户姓名" :rules="formRules.name"
+                    :readonly="isReadonly" />
+                <Field v-model="formData.mobile" name="mobile" readonly label="手机号码" />
                 <Field name="idCardType" label="证件类型" :rules="formRules.idCardType" is-link>
                     <template #input>
-                        <app-select v-model="formData.idCardType" placeholder="请选择证件类型" :options="getAQCertificateTypeList()" />
+                        <app-select v-model="formData.idCardType" placeholder="请选择证件类型"
+                            :options="getAQCertificateTypeList()" :readonly="isReadonly" />
                     </template>
                 </Field>
-                <Field v-model="formData.idCard" name="cardnum" label="证件号码" placeholder="请输入证件号码"
-                    :rules="formRules.idCard" />
+                <Field v-model="formData.idCard" name="cardnum" label="证件号码" placeholder="请输入证件号码" :rules="formRules.idCard"
+                    :readonly="isReadonly" />
                 <Field name="idCardPhoto" label="证件正面照片" :rules="formRules.idCardPhoto">
                     <template #input>
-                        <app-uploader @success="b_afterRead" />
+                        <Image fit="contain" :src="getFileUrl(formData.idCardPhoto)" width="100" height="100"
+                            v-if="isReadonly" />
+                        <app-uploader @success="f_afterRead" v-else />
                     </template>
                 </Field>
                 <Field name="idCardPhotoBackURL" label="证件反面照片" :rules="formRules.idCardPhotoBackURL">
                     <template #input>
-                        <app-uploader @success="f_afterRead" />
+                        <Image fit="contain" :src="getFileUrl(formData.idCardPhotoBackURL)" width="100" height="100"
+                            v-if="isReadonly" />
+                        <app-uploader @success="b_afterRead" v-else />
                     </template>
                 </Field>
             </CellGroup>
@@ -34,21 +35,23 @@
         <img src="../../../assets/images/certification.png" />
         <template #footer>
             <div class="g-form__footer inset">
-                <Button type="danger" @click="formRef?.submit" :disabled="!canAdd" round block>提交实名认证</Button>
+                <Button type="danger" :loading="buttonLoading" @click="onSubmit" round block>提交实名认证</Button>
             </div>
         </template>
-        <component ref="componentRef" v-bind="{ formData }" :is="componentMap.get(componentId)" @closed="closeComponent" v-if="componentId" />
+        <component ref="componentRef" v-bind="{ formData }" :is="componentMap.get(componentId)" @closed="closeComponent"
+            v-if="componentId" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, defineAsyncComponent } from 'vue'
-import { CellGroup, Button, Field, Form, FormInstance, showFailToast, FieldRule } from 'vant'
+import { shallowRef, defineAsyncComponent, onMounted, computed } from 'vue'
+import { CellGroup, Button, Field, Form, FormInstance, showFailToast, FieldRule, Image } from 'vant'
 import { fullloading, dialog } from '@/utils/vant';
+import { getFileUrl } from '@/filters';
 import { getAQCertificateTypeList } from "@/constants/account";
 import { useRequest } from '@/hooks/request'
-import { queryUserESignRecord } from '@/services/api/account';
-import { adddUserReq, useCheckCardNum } from '@/business/user/account';
+import { queryUserESignRecord, requestCheckCardNum } from '@/services/api/account';
+import { adddUserReq } from '@/business/user/account';
 import { validateRules } from '@/constants/regex';
 import { useComponent } from '@/hooks/component'
 import { useUserStore } from '@/stores'
@@ -56,43 +59,39 @@ import AppSelect from '../../../components/base/select/index.vue'
 import AppUploader from '../../../components/base/uploader/index.vue'
 import { useNavigation } from '../../../router/navigation'
 
+const componentMap = new Map<string, unknown>([
+    ['certification-next', defineAsyncComponent(() => import('./components/certification-next/Index.vue'))], // 爱签-实名认证第二步
+])
+
 const { router } = useNavigation()
+const userStore = useUserStore()
 const formRef = shallowRef<FormInstance>()
-const { formData, formSubmit } = adddUserReq()
-const canAdd = shallowRef(false)
+const { formData, formSubmit, loading } = adddUserReq()
 
 const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
     router.back()
 })
-const mobile2 = useUserStore().userInfo?.mobile2 ?? ''
 
-const { checkCardNumFormData, checkCardNum} = useCheckCardNum()
-
-const componentMap = new Map<string, unknown>([
-    ['certification-next', defineAsyncComponent(() => import('./components/certification-next/Index.vue'))], // 爱签-实名认证第二步
-])
+const isReadonly = computed(() => {
+    const [firstStep] = userESignRecords.value
+    return firstStep?.recordstatus === 3
+})
 
 /// 查询记录
-const { loading  } = useRequest(queryUserESignRecord, {
+const { loading: buttonLoading, dataList: userESignRecords } = useRequest(queryUserESignRecord, {
     onSuccess: (res) => {
-        if(res.data.some((e)=>e.templatetype === 1 && e.recordstatus === 1)) {
-            canAdd.value = true
-        } else {
-            const item = res.data.find((e)=>e.templatetype === 1 && e.recordstatus === 3)
-            if (item) {
-                canAdd.value = false
-                const { name, idCard, idCardPhoto, idCardPhotoBackURL, mobile, idCardType } = JSON.parse(item.authinfo)
-                formData.name = name
-                formData.idCard = idCard
-                formData.idCardPhoto = idCardPhoto
-                formData.idCardPhotoBackURL = idCardPhotoBackURL
-                formData.idCardType = idCardType
-                formData.mobile = mobile
-                /// 进行下一步
-                openComponent('certification-next')
-            } 
+        const [firstStep] = res.data
+        if (firstStep?.recordstatus === 3) {
+            const { name, idCard, idCardPhoto, idCardPhotoBackURL, mobile, idCardType } = JSON.parse(firstStep.authinfo)
+            formData.name = name
+            formData.idCard = idCard
+            formData.idCardPhoto = idCardPhoto
+            formData.idCardPhotoBackURL = idCardPhotoBackURL
+            formData.idCardType = idCardType
+            formData.mobile = mobile
         }
-    }, onError: (err) => {
+    },
+    onError: (err) => {
         showFailToast(err)
         /// 报错返回
         router.back()
@@ -100,11 +99,11 @@ const { loading  } = useRequest(queryUserESignRecord, {
 })
 
 const b_afterRead = (filePath: string) => {
-    formData.idCardPhoto = filePath
+    formData.idCardPhotoBackURL = filePath
 }
 
 const f_afterRead = (filePath: string) => {
-    formData.idCardPhotoBackURL = filePath
+    formData.idCardPhoto = filePath
 }
 
 // 表单验证规则
@@ -145,37 +144,36 @@ const formRules: { [key in keyof Model.AddUserReq]?: FieldRule[] } = {
 
 const onCheckCardNum = () => {
     fullloading((hideLoading) => {
-        /// 证件号码
-        checkCardNumFormData.cardnum = formData.idCard
-        /// 请求校验
-        checkCardNum().then((res) => {
-            hideLoading()
-            /// 提交
-            if (res.code === 0) {
-               onSubmit()
-            } else {
-                showFailToast(res.message ?? '未知错误')
+        requestCheckCardNum({
+            data: {
+                cardnum: formData.idCard
             }
+        }).then(() => {
+            formSubmit().then(() => {
+                hideLoading()
+                dialog('提交请求成功').then(() => {
+                    /// 进行下一步
+                    openComponent('certification-next')
+                })
+            }).catch((err) => {
+                hideLoading(err, 'fail')
+            })
         }).catch((err) => {
-            showFailToast(err)
+            hideLoading(err, 'fail')
         })
     })
 }
 
 const onSubmit = () => {
-    fullloading((hideLoading) => {
-        /// 手机号码
-        formData.mobile = mobile2
-
-        formSubmit().then(() => {
-            hideLoading()
-            dialog('提交请求成功').then(() => {
-                /// 进行下一步
-                openComponent('certification-next')
-            })
-        }).catch((err) => {
-            showFailToast(err)
-        })
-    })
+    const [firstStep] = userESignRecords.value
+    if (!firstStep || firstStep.recordstatus === 1) {
+        formRef.value?.submit()
+    } else {
+        openComponent('certification-next')
+    }
 }
+
+onMounted(() => {
+    formData.mobile = userStore.userInfo?.mobile2 ?? ''
+})
 </script>

+ 84 - 73
src/packages/qxst/views/account/certification/components/certification-next/Index.vue

@@ -1,31 +1,42 @@
 <template>
     <app-modal direction="right" height="100%" v-model:show="showModal" :refresh="refresh">
-        <app-view class="g-form account-certification">
+        <app-view class="g-form">
             <template #header>
                 <app-navbar title="实名认证" @back="closed" />
             </template>
-            <CellGroup inset>
-                <Cell title="姓名" :value="formData.name" />
-                <Cell title="手机号码" :value="formData.mobile" />
-                <Cell title="证件类型" :value="getAQCertificateTypeListName(formData.idCardType ?? 1)" />
-                <Cell title="证件号码" :value="formData.idCard" />
-                <Field name="idCardPhoto" label="证件正面照片">
-                    <template #input>
-                        <Image :src="idCardPhoto" />
+            <div class="g-form__container">
+                <CellGroup inset>
+                    <Cell title="姓名" :value="formData.name" />
+                    <Cell title="手机号码" :value="formData.mobile" />
+                    <Cell title="证件类型" :value="getAQCertificateTypeListName(formData.idCardType ?? 1)" />
+                    <Cell title="证件号码" :value="formData.idCard" />
+                    <Cell title="证件正面照片">
+                        <template #value>
+                            <Image fit="contain" :src="idCardPhoto" width="100" height="100" />
+                        </template>
+                    </Cell>
+                    <Cell title="证件反面照片">
+                        <template #value>
+                            <Image fit="contain" :src="idCardPhotoBackURL" width="100" height="100" />
+                        </template>
+                    </Cell>
+                </CellGroup>
+                <CellGroup inset>
+                    <template v-for="(item, index) in secondStepList" :key="index">
+                        <Cell :title="item.templatename" :icon="iconName(item.recordstatus)" @click="signer(item)"
+                            is-link />
                     </template>
-                </Field>
-                <Field name="idCardPhotoBackURL" label="证件反面照片">
-                    <template #input>
-                        <Image :src="idCardPhotoBackURL" />
+                    <template v-if="secondStepList.every(e => e.recordstatus === 3)">
+                        <template v-for="(item, index) in thirdStepList" :key="index">
+                            <Cell title="视频认证" :icon="iconName(item.recordstatus)" @click="faceAuth()" is-link />
+                        </template>
                     </template>
-                </Field>
-            </CellGroup>
-            <CellGroup inset>
-                <Cell v-for="(item, index) in dataList.filter(obj => obj.templatetype === 2)" :key="index" :title="item.templatename" :icon="iconName(item.recordstatus)" :disable="[2, 4].includes(item.recordstatus)" @click="signer(item)" />
-            </CellGroup>
+                </CellGroup>
+            </div>
             <template #footer>
                 <div class="g-form__footer inset">
-                    <Button type="danger" :disable="!canAdd" @click="onSubmit()" round block>提交认证</Button>
+                    <Button type="danger" :disabled="dataList.some((e) => e.recordstatus !== 3)" @click="onSubmit()" round
+                        block>提交认证</Button>
                 </div>
             </template>
         </app-view>
@@ -34,7 +45,7 @@
 
 <script lang="ts" setup>
 import { shallowRef, computed, PropType } from 'vue'
-import { CellGroup, Button, Cell, Field, showFailToast, Image } from 'vant'
+import { CellGroup, Button, Cell, showFailToast, Image } from 'vant'
 import { fullloading, dialog } from '@/utils/vant';
 import { getAQCertificateTypeListName } from "@/constants/account";
 import { useRequest } from '@/hooks/request'
@@ -48,22 +59,18 @@ import AppModal from '@/components/base/modal/index.vue'
 const showModal = shallowRef(true)
 // 是否刷新父组件数据
 const refresh = shallowRef(false)
-const dataList = shallowRef<Model.UserESignRecordRsq[]>([])
-const { createSigner, templateNoFormData} = useRequestCreateContractAndAddSigner()
+const { createSigner, templateNoFormData } = useRequestCreateContractAndAddSigner()
 /// 意愿视频认证
-const { willFace, willFaceFormData} = useRequestWillFace()
-const { signCompleted} = useRequestSignCompleted()
-/// 可以认证
-const canAdd = shallowRef(false)
+const { willFace, willFaceFormData } = useRequestWillFace()
+const { signCompleted } = useRequestSignCompleted()
 
 /// 查询
-const { run } = useRequest(queryUserESignRecord, {
-    onSuccess: (res) => {
-        if (res.data.length != 0) { dataList.value = res.data  }
-        /// 只有全部签署才可以进行下一步
-        canAdd.value = dataList.value.some(obj => obj.templatetype === 2 && [2, 3].includes(obj.recordstatus) )
-    }
-})
+const { run, dataList } = useRequest(queryUserESignRecord)
+
+// 步骤2列表
+const secondStepList = computed(() => dataList.value.filter(obj => obj.templatetype === 2))
+// 步骤3列表
+const thirdStepList = computed(() => dataList.value.filter(obj => obj.templatetype === 3))
 
 const iconName = (type: number) => {
     switch (type) {
@@ -88,8 +95,12 @@ const idCardPhotoBackURL = computed(() => {
     return getFileUrl(image)
 })
 
-const openURL = (url: string) => {
-    plus.openWebview({ url, titleText: '实名认证' })
+const openWebview = (url: string) => {
+    plus.openWebview({
+        url,
+        titleText: '实名认证',
+        onClose: () => run()
+    })
 }
 
 const props = defineProps({
@@ -99,70 +110,70 @@ const props = defineProps({
     }
 })
 
-const completed = () => {
-    fullloading((hideLoading) => {
-        signCompleted().then(() => {
-            hideLoading()
-            dialog('实名认证提交请求成功').then(() => {
-                closed(true)
-            })
-        }).catch((err) => {
-            showFailToast(err)
-        })
-    })
-}
-
 const signer = (item: Model.UserESignRecordRsq) => {
     ///  如果是已签署
     if (item.recordstatus === 2) {
-        item.signurl != '' ? openURL(item.signurl) : showFailToast('合同地址错误')
-    } else if (item.recordstatus === 3) { 
-        item.contractfileaddr != '' ? openURL(item.contractfileaddr) : showFailToast('合同地址错误')
+        item.signurl ? openWebview(item.signurl) : showFailToast('合同地址错误')
+    } else if (item.recordstatus === 3) {
+        const fileUrl = getFileUrl(item.contractfileaddr)
+        item.contractfileaddr ? plus.openURL(fileUrl) : showFailToast('合同地址错误')
     } else {
         fullloading((hideLoading) => {
             templateNoFormData.templateNo = item.templateno
             /// 创建合同
             createSigner().then((res) => {
                 hideLoading()
-                openURL(res.data.signUrl)
+                openWebview(res.data.signUrl)
             }).catch((err) => {
-                showFailToast(err)
+                hideLoading(err, 'fail')
             })
         })
     }
 }
 
-/// 最终提交
-const onSubmit = () => {
-    /// 如果类型为3 状态为3的 已经进行视频认证成功
-    if (dataList.value.some(obj => obj.templatetype === 3 && obj.recordstatus === 3)) {
-        completed()
-    } else {
-        willface()
-    }
+// 视频认证
+const faceAuth = () => {
+    plus.requestPermissionCamera({
+        onSuccess: () => {
+            plus.requestPermissionRecordAudio({
+                onSuccess: () => {
+                    /// 进行视频认证
+                    willFaceFormData.idCardNo = props.formData.idCard
+                    willFaceFormData.realName = props.formData.name
+                    /// loading
+                    fullloading((hideLoading) => {
+                        willFace().then((res) => {
+                            hideLoading()
+                            openWebview(res.data.faceUrl)
+                        }).catch((err) => {
+                            hideLoading(err, 'fail')
+                        })
+                    })
+                }
+            })
+        }
+    })
 }
 
-/// 进行视频认证
-const willface = () => {
-    /// 参数信息
-    willFaceFormData.idCardNo = props.formData.idCard
-    willFaceFormData.realName = props.formData.name
-    /// loading
+/// 最终提交
+const onSubmit = () => {
     fullloading((hideLoading) => {
-        willFace().then((res) => {
+        signCompleted().then(() => {
             hideLoading()
-            openURL(res.data.faceUrl)
+            dialog('实名认证提交请求成功').then(() => {
+                closed(true)
+            })
         }).catch((err) => {
-            showFailToast(err)
+            hideLoading(err, 'fail')
         })
     })
 }
 
 // 接收窗口页面状态通知
 const documentVisibilityStateNotify = eventBus.$on('DocumentVisibilityStateNotify', (state) => {
-  if (state === 'visible') {
-    run()
-  }
+    if (state === 'visible') {
+        run()
+    }
 })
 
 // 关闭弹窗

+ 1 - 1
src/packages/qxst/views/goods/detail/Index.vue

@@ -5,7 +5,7 @@
         </template>
         <component :is="Price" v-bind="{ goodsCode }" />
         <component :is="Chart" v-bind="{ goodsCode }" />
-        <component :is="Forex" v-bind="{ goodsCode }" />
+        <component :is="Forex" v-bind="{ goodsCode }" :showMore="false" />
         <component :is="Tik" v-bind="{ goodsCode }" />
         <template #footer>
             <div class="g-form__footer">

+ 1 - 0
src/packages/qxst/views/mine/Index.vue

@@ -176,6 +176,7 @@ const userLogout = () => {
         message: '是否退出当前账号?',
         showCancelButton: true
     }).then(() => {
+        authStatus.value = AuthStatus.Uncertified
         loginStore.clearAutoLoginData()
         eventBus.$emit('LogoutNotify')
     })

+ 1 - 0
src/packages/sbyj/views/mine/index.vue

@@ -176,6 +176,7 @@ const userLogout = () => {
         message: '是否退出当前账号?',
         showCancelButton: true
     }).then(() => {
+        authStatus.value = AuthStatus.Uncertified
         loginStore.clearAutoLoginData()
         eventBus.$emit('LogoutNotify')
     })

+ 4 - 1
src/services/api/account/index.ts

@@ -204,6 +204,9 @@ export function requestCheckCardNum(config: RequestConfig<Model.CheckCardNumReq>
     return http.request<Model.CheckCardNumRsp>({
         method: 'get',
         url: service.getConfig('openApiUrl') + '/onlineopen/userInfo/checkCardNum',
-        params: config.data
+        params: {
+            userid: loginStore.userId,
+            ...config.data
+        },
     })
 }

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

@@ -12,7 +12,7 @@ export interface EnumType {
     disabled?: boolean;
 }
 
-const enumKeys = ['confirmStatus', 'deliveryPayMode', 'deliveryStatus', 'clientType', 'stepStatus', 'scoreConfigType', 'GZBSCPayStatus', 'performanceStatus', 'handlestatus', 'performanceType', 'accountBusinessCode', 'certificatetype', 'signstatus', 'thjOrderStatus', 'THJDeliveryMode', 'goodsunit', 'WROutInApplyStatus2', 'THJTransferStatus', 'WRTradeOrderStatus', 'THJMarket', 'THJProfitRoleType', 'appointmentModelOut', 'orderstatus', 'Pricemode2', 'buildtype', 'listingselecttype', 'certypeperson'] as const
+const enumKeys = ['confirmStatus', 'deliveryPayMode', 'deliveryStatus', 'clientType', 'stepStatus', 'scoreConfigType', 'GZBSCPayStatus', 'performanceStatus', 'handlestatus', 'performanceType', 'accountBusinessCode', 'certificatetype', 'signstatus', 'thjOrderStatus', 'THJDeliveryMode', 'goodsunit', 'WROutInApplyStatus2', 'THJTransferStatus', 'WRTradeOrderStatus', 'THJMarket', 'THJProfitRoleType', 'appointmentModelOut', 'orderstatus', 'Pricemode2', 'buildtype', 'listingselecttype', 'certypeperson', 'runstatus'] as const
 
 const enumMap = new Map<typeof enumKeys[number], ShallowRef<Model.EnumRsp[]>>()
 

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

@@ -144,6 +144,9 @@ export const useFuturesStore = defineStore(() => {
             limitup: quote.limitup ?? 0,
             limitdown: quote.limitdown ?? 0,
             averageprice: quote.averageprice ?? 0,
+            totalvolume: quote.totalvolume ?? 0,
+            totalturnover: quote.totalturnover ?? 0,
+            holdvolume: quote.holdvolume ?? 0,
             rise: 0,
             change: 0,
             amplitude: 0,
@@ -195,6 +198,10 @@ export const useFuturesStore = defineStore(() => {
             }
         }
 
+        item.opened = item.opened || item.last // 没有开盘价默认取最新价
+        item.highest = item.highest || item.last // 没有最高价默认取最新价
+        item.lowest = item.lowest || item.last // 没有最低价价默认取最新价
+
         // 处理最高最低价
         if (item.last) {
             if (item.last > item.highest) {
@@ -205,6 +212,7 @@ export const useFuturesStore = defineStore(() => {
             }
         }
 
+        item.averageprice = item.totalvolume ? item.totalturnover / (item.totalvolume * item.agreeunit) : 0 // 计算均价
         item.rise = item.last ? item.last - item.presettle : 0   // 涨跌额/涨跌: 最新价 - 昨结价
         item.change = item.presettle ? item.rise / item.presettle : 0 // 涨跌幅/幅度: (最新价 - 昨结价) / 昨结价
         item.amplitude = item.presettle ? (item.highest - item.lowest) / item.presettle : 0 // 振幅: (最高价 - 最低价 ) / 最新价

+ 8 - 0
src/stores/modules/futures@next.ts

@@ -144,6 +144,9 @@ export const useFuturesStore = defineStore(() => {
             limitup: quote.limitup ?? 0,
             limitdown: quote.limitdown ?? 0,
             averageprice: quote.averageprice ?? 0,
+            totalvolume: quote.totalvolume ?? 0,
+            totalturnover: quote.totalturnover ?? 0,
+            holdvolume: quote.holdvolume ?? 0,
             rise: 0,
             change: 0,
             amplitude: 0,
@@ -195,6 +198,10 @@ export const useFuturesStore = defineStore(() => {
             }
         }
 
+        item.opened = item.opened || item.last // 没有开盘价默认取最新价
+        item.highest = item.highest || item.last // 没有最高价默认取最新价
+        item.lowest = item.lowest || item.last // 没有最低价价默认取最新价
+
         // 处理最高最低价
         if (item.last) {
             if (item.last > item.highest) {
@@ -205,6 +212,7 @@ export const useFuturesStore = defineStore(() => {
             }
         }
 
+        item.averageprice = item.totalvolume ? item.totalturnover / (item.totalvolume * item.agreeunit) : 0 // 计算均价
         item.rise = item.last ? item.last - item.presettle : 0   // 涨跌额/涨跌: 最新价 - 昨结价
         item.change = item.presettle ? item.rise / item.presettle : 0 // 涨跌幅/幅度: (最新价 - 昨结价) / 昨结价
         item.amplitude = item.presettle ? (item.highest - item.lowest) / item.presettle : 0 // 振幅: (最高价 - 最低价 ) / 最新价

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

@@ -41,7 +41,7 @@ export const usePositionStore = defineStore(() => {
             const { last = 0, lastColor = '' } = quote.value ?? {}
 
             // 计算浮动盈亏
-            const closepl = (last * item.curpositionqty * item.agreeunit - item.curholderamount) * (item.buyorsell === BuyOrSell.Buy ? 1 : -1)
+            const closepl = last ? (last * item.curpositionqty * item.agreeunit - item.curholderamount) * (item.buyorsell === BuyOrSell.Buy ? 1 : -1) : 0
 
             result.push({
                 ...item,

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

@@ -125,5 +125,8 @@ declare namespace Model {
         trademode: number;
         quoteminunit: number;//行情最小变动单位 [整数,报价小数位一起使用]
         quotegear: number;//行情档位
+        totalvolume: number; // 总量
+        totalturnover: number; // 总金额
+        holdvolume: number; // 持仓
     }
 }

+ 59 - 1
src/utils/h5plus/index.ts

@@ -9,6 +9,11 @@ declare global {
     }
 }
 
+interface AndroidErrorCallback {
+    code: number;
+    message: string;
+}
+
 export default new (class {
     private readonly plusready = new Promise<void>((resolve) => {
         if (this.hasPlus()) {
@@ -342,7 +347,7 @@ export default new (class {
      * https://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.create
      * @param options 
      */
-    openWebview(options: { url: string; id?: string; titleText?: string; titleColor?: string; backgroundColor?: string; }) {
+    openWebview(options: { url: string; id?: string; titleText?: string; titleColor?: string; backgroundColor?: string; onClose?: () => void; }) {
         if (this.hasPlus()) {
             const styles = {
                 titleNView: {
@@ -355,6 +360,7 @@ export default new (class {
             this.onPlusReady((plus) => {
                 const wv = plus.webview.create(options.url, options.id ?? v4(), styles)
                 wv.show()
+                wv.addEventListener('close', () => options.onClose && options.onClose(), false)
             })
         } else {
             this.openURL(options.url)
@@ -482,4 +488,56 @@ export default new (class {
             })
         })
     }
+
+    /**
+     * 请求摄像头权限
+     */
+    requestPermissionCamera(options: Partial<{ onSuccess: () => void; onError: (message?: string) => void; }> = {}) {
+        const { onSuccess, onError } = options
+        if (this.hasPlus()) {
+            this.onPlusReady((plus) => {
+                plus.android.requestPermissions(['android.permission.CAMERA'], (e: { granted: string[]; deniedPresent: string[]; deniedAlways: string[]; }) => {
+                    if (e.deniedAlways.length > 0) {
+                        onError && onError('访问摄像头被拒绝')
+                    }
+                    if (e.deniedPresent.length > 0) {
+                        onError && onError('请打开摄像头权限')
+                    }
+                    if (e.granted.length > 0) {
+                        onSuccess && onSuccess()
+                    }
+                }, (e: AndroidErrorCallback) => {
+                    onError && onError(e.message)
+                })
+            })
+        } else {
+            onSuccess && onSuccess()
+        }
+    }
+
+    /**
+     * 请求麦克风权限
+     */
+    requestPermissionRecordAudio(options: Partial<{ onSuccess: () => void; onError: (message?: string) => void; }> = {}) {
+        const { onSuccess, onError } = options
+        if (this.hasPlus()) {
+            this.onPlusReady((plus) => {
+                plus.android.requestPermissions(['android.permission.RECORD_AUDIO'], (e: { granted: string[]; deniedPresent: string[]; deniedAlways: string[]; }) => {
+                    if (e.deniedAlways.length > 0) {
+                        onError && onError('访问麦克风被拒绝')
+                    }
+                    if (e.deniedPresent.length > 0) {
+                        onError && onError('请打开麦克风权限')
+                    }
+                    if (e.granted.length > 0) {
+                        onSuccess && onSuccess()
+                    }
+                }, (e: AndroidErrorCallback) => {
+                    onError && onError(e.message)
+                })
+            })
+        } else {
+            onSuccess && onSuccess()
+        }
+    }
 })