提交 9a5912ba authored 作者: 王鹏飞's avatar 王鹏飞

feat: 新增直播下单

上级 ddb1d739
VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index
VITE_LAB_URL=https://bi.ezijing.com/bi/?proc=0&action=index VITE_LAB_URL=https://bi.ezijing.com/bi/?proc=0&action=index
VITE_SURVEYKING_URL=https://surveyking.ezijing.com VITE_SURVEYKING_URL=https://surveyking.ezijing.com
# 直播语音识别
VITE_ACCESS_KEY_ID=LTAI5t7YUVzDVSFLYvnuWGuq
VITE_ACCESS_KEY_SECRET=GBsohg5hSUP99dzIuRuCQilUXTSiYe
VITE_APP_KEY=W7Yqc8L49MEnnLsE
\ No newline at end of file
...@@ -302,6 +302,11 @@ ...@@ -302,6 +302,11 @@
"onWatcherCleanup": true, "onWatcherCleanup": true,
"useId": true, "useId": true,
"useModel": true, "useModel": true,
"useTemplateRef": true "useTemplateRef": true,
"createRef": true,
"onElementRemoval": true,
"useCountdown": true,
"usePreferredReducedTransparency": true,
"useSSRWidth": true
} }
} }
...@@ -28,6 +28,7 @@ declare global { ...@@ -28,6 +28,7 @@ declare global {
const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
const createRef: typeof import('@vueuse/core')['createRef']
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate'] const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise'] const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
...@@ -62,6 +63,7 @@ declare global { ...@@ -62,6 +63,7 @@ declare global {
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onClickOutside: typeof import('@vueuse/core')['onClickOutside'] const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
const onDeactivated: typeof import('vue')['onDeactivated'] const onDeactivated: typeof import('vue')['onDeactivated']
const onElementRemoval: typeof import('@vueuse/core')['onElementRemoval']
const onErrorCaptured: typeof import('vue')['onErrorCaptured'] const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke'] const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
const onLongPress: typeof import('@vueuse/core')['onLongPress'] const onLongPress: typeof import('@vueuse/core')['onLongPress']
...@@ -144,6 +146,7 @@ declare global { ...@@ -144,6 +146,7 @@ declare global {
const useCloned: typeof import('@vueuse/core')['useCloned'] const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode'] const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCountdown: typeof import('@vueuse/core')['useCountdown']
const useCounter: typeof import('@vueuse/core')['useCounter'] const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule'] const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar'] const useCssVar: typeof import('@vueuse/core')['useCssVar']
...@@ -224,12 +227,14 @@ declare global { ...@@ -224,12 +227,14 @@ declare global {
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePreferredReducedTransparency: typeof import('@vueuse/core')['usePreferredReducedTransparency']
const usePrevious: typeof import('@vueuse/core')['usePrevious'] const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useRafFn: typeof import('@vueuse/core')['useRafFn'] const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRoute: typeof import('vue-router')['useRoute'] const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter'] const useRouter: typeof import('vue-router')['useRouter']
const useSSRWidth: typeof import('@vueuse/core')['useSSRWidth']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation'] const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea'] const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag'] const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
......
...@@ -15,10 +15,11 @@ ...@@ -15,10 +15,11 @@
"@tinymce/tinymce-vue": "^5.0.1", "@tinymce/tinymce-vue": "^5.0.1",
"@vue-flow/controls": "^1.1.2", "@vue-flow/controls": "^1.1.2",
"@vue-flow/core": "^1.39.0", "@vue-flow/core": "^1.39.0",
"@vueuse/components": "^11.2.0", "@vueuse/components": "^13.3.0",
"@vueuse/core": "^11.2.0", "@vueuse/core": "^13.3.0",
"axios": "^1.6.8", "axios": "^1.6.8",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"echarts-wordcloud": "^2.1.0", "echarts-wordcloud": "^2.1.0",
...@@ -30,14 +31,16 @@ ...@@ -30,14 +31,16 @@
"nanoid": "^5.0.7", "nanoid": "^5.0.7",
"pinia": "^2.2.6", "pinia": "^2.2.6",
"scroll-into-view-if-needed": "^3.1.0", "scroll-into-view-if-needed": "^3.1.0",
"vue": "^3.5.12", "vue": "^3.5.15",
"vue-echarts": "^6.6.9", "vue-echarts": "^6.6.9",
"vue-router": "^4.4.5", "vue-markdown-render": "^2.2.1",
"vue-router": "^4.5.1",
"xss": "^1.0.15" "xss": "^1.0.15"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/node20": "^20.1.4", "@tsconfig/node20": "^20.1.4",
"@types/blueimp-md5": "^2.18.2", "@types/blueimp-md5": "^2.18.2",
"@types/crypto-js": "^4.2.2",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
"@types/node": "^20.17.6", "@types/node": "^20.17.6",
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.1.4",
...@@ -332,18 +335,18 @@ ...@@ -332,18 +335,18 @@
} }
}, },
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.25.9", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.25.9", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
...@@ -462,12 +465,12 @@ ...@@ -462,12 +465,12 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.2", "version": "7.27.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.3.tgz",
"integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "integrity": "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.0" "@babel/types": "^7.27.3"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
...@@ -549,13 +552,13 @@ ...@@ -549,13 +552,13 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.0", "version": "7.27.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz",
"integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.25.9" "@babel/helper-validator-identifier": "^7.27.1"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
...@@ -2282,6 +2285,13 @@ ...@@ -2282,6 +2285,13 @@
"integrity": "sha512-dJ9yRry9Olt5GAWlgCtE5dK9d/Dfhn/V7hna86eEO2Pn76+E8Y0S0n61iEUEGhWXXgtKtHxtZLVNwL8X+vLHzg==", "integrity": "sha512-dJ9yRry9Olt5GAWlgCtE5dK9d/Dfhn/V7hna86eEO2Pn76+E8Y0S0n61iEUEGhWXXgtKtHxtZLVNwL8X+vLHzg==",
"dev": true "dev": true
}, },
"node_modules/@types/crypto-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
"integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
...@@ -2771,53 +2781,53 @@ ...@@ -2771,53 +2781,53 @@
} }
}, },
"node_modules/@vue/compiler-core": { "node_modules/@vue/compiler-core": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.15.tgz",
"integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", "integrity": "sha512-nGRc6YJg/kxNqbv/7Tg4juirPnjHvuVdhcmDvQWVZXlLHjouq7VsKmV1hIxM/8yKM0VUfwT/Uzc0lO510ltZqw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.25.3", "@babel/parser": "^7.27.2",
"@vue/shared": "3.5.12", "@vue/shared": "3.5.15",
"entities": "^4.5.0", "entities": "^4.5.0",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map-js": "^1.2.0" "source-map-js": "^1.2.1"
} }
}, },
"node_modules/@vue/compiler-dom": { "node_modules/@vue/compiler-dom": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.15.tgz",
"integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", "integrity": "sha512-ZelQd9n+O/UCBdL00rlwCrsArSak+YLZpBVuNDio1hN3+wrCshYZEDUO3khSLAzPbF1oQS2duEoMDUHScUlYjA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-core": "3.5.12", "@vue/compiler-core": "3.5.15",
"@vue/shared": "3.5.12" "@vue/shared": "3.5.15"
} }
}, },
"node_modules/@vue/compiler-sfc": { "node_modules/@vue/compiler-sfc": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.15.tgz",
"integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", "integrity": "sha512-3zndKbxMsOU6afQWer75Zot/aydjtxNj0T2KLg033rAFaQUn2PGuE32ZRe4iMhflbTcAxL0yEYsRWFxtPro8RQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.25.3", "@babel/parser": "^7.27.2",
"@vue/compiler-core": "3.5.12", "@vue/compiler-core": "3.5.15",
"@vue/compiler-dom": "3.5.12", "@vue/compiler-dom": "3.5.15",
"@vue/compiler-ssr": "3.5.12", "@vue/compiler-ssr": "3.5.15",
"@vue/shared": "3.5.12", "@vue/shared": "3.5.15",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"magic-string": "^0.30.11", "magic-string": "^0.30.17",
"postcss": "^8.4.47", "postcss": "^8.5.3",
"source-map-js": "^1.2.0" "source-map-js": "^1.2.1"
} }
}, },
"node_modules/@vue/compiler-ssr": { "node_modules/@vue/compiler-ssr": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.15.tgz",
"integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", "integrity": "sha512-gShn8zRREZbrXqTtmLSCffgZXDWv8nHc/GhsW+mbwBfNZL5pI96e7IWcIq8XGQe1TLtVbu7EV9gFIVSmfyarPg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.12", "@vue/compiler-dom": "3.5.15",
"@vue/shared": "3.5.12" "@vue/shared": "3.5.15"
} }
}, },
"node_modules/@vue/compiler-vue2": { "node_modules/@vue/compiler-vue2": {
...@@ -2915,53 +2925,53 @@ ...@@ -2915,53 +2925,53 @@
} }
}, },
"node_modules/@vue/reactivity": { "node_modules/@vue/reactivity": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.15.tgz",
"integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", "integrity": "sha512-GaA5VUm30YWobCwpvcs9nvFKf27EdSLKDo2jA0IXzGS344oNpFNbEQ9z+Pp5ESDaxyS8FcH0vFN/XSe95BZtHQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/shared": "3.5.12" "@vue/shared": "3.5.15"
} }
}, },
"node_modules/@vue/runtime-core": { "node_modules/@vue/runtime-core": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.15.tgz",
"integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", "integrity": "sha512-CZAlIOQ93nj0OPpWWOx4+QDLCMzBNY85IQR4Voe6vIID149yF8g9WQaWnw042f/6JfvLttK7dnyWlC1EVCRK8Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/reactivity": "3.5.12", "@vue/reactivity": "3.5.15",
"@vue/shared": "3.5.12" "@vue/shared": "3.5.15"
} }
}, },
"node_modules/@vue/runtime-dom": { "node_modules/@vue/runtime-dom": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.15.tgz",
"integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", "integrity": "sha512-wFplHKzKO/v998up2iCW3RN9TNUeDMhdBcNYZgs5LOokHntrB48dyuZHspcahKZczKKh3v6i164gapMPxBTKNw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/reactivity": "3.5.12", "@vue/reactivity": "3.5.15",
"@vue/runtime-core": "3.5.12", "@vue/runtime-core": "3.5.15",
"@vue/shared": "3.5.12", "@vue/shared": "3.5.15",
"csstype": "^3.1.3" "csstype": "^3.1.3"
} }
}, },
"node_modules/@vue/server-renderer": { "node_modules/@vue/server-renderer": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.15.tgz",
"integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", "integrity": "sha512-Gehc693kVTYkLt6QSYEjGvqvdK2zZ/gf/D5zkgmvBdeB30dNnVZS8yY7+IlBmHRd1rR/zwaqeu06Ij04ZxBscg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-ssr": "3.5.12", "@vue/compiler-ssr": "3.5.15",
"@vue/shared": "3.5.12" "@vue/shared": "3.5.15"
}, },
"peerDependencies": { "peerDependencies": {
"vue": "3.5.12" "vue": "3.5.15"
} }
}, },
"node_modules/@vue/shared": { "node_modules/@vue/shared": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.15.tgz",
"integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", "integrity": "sha512-bKvgFJJL1ZX9KxMCTQY6xD9Dhe3nusd1OhyOb1cJYGqvAr0Vg8FIjHPMOEVbJ9GDT9HG+Bjdn4oS8ohKP8EvoA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vue/tsconfig": { "node_modules/@vue/tsconfig": {
...@@ -2971,128 +2981,60 @@ ...@@ -2971,128 +2981,60 @@
"dev": true "dev": true
}, },
"node_modules/@vueuse/components": { "node_modules/@vueuse/components": {
"version": "11.2.0", "version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/components/-/components-11.2.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/components/-/components-13.3.0.tgz",
"integrity": "sha512-L9uDsTcaMvz3x1tX2RepdmvDJGIHBiSeYVXNFfHceiM3mmPY6vfRlS/XqZTpip7FdXxu0s/zSmtZCffZGTNRXQ==", "integrity": "sha512-ZnJiVknPtlWyeE4qwIXkDOlHM3W4bgMCxgeXj1Dec/aF/+8N+yAj+7rRdRUWUnqr8uKRin368RjG1FPKsF2erA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vueuse/core": "11.2.0", "@vueuse/core": "13.3.0",
"@vueuse/shared": "11.2.0", "@vueuse/shared": "13.3.0"
"vue-demi": ">=0.14.10"
}
},
"node_modules/@vueuse/components/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}, },
"peerDependencies": { "peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.5.0"
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
} }
}, },
"node_modules/@vueuse/core": { "node_modules/@vueuse/core": {
"version": "11.2.0", "version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.2.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.3.0.tgz",
"integrity": "sha512-JIUwRcOqOWzcdu1dGlfW04kaJhW3EXnnjJJfLTtddJanymTL7lF1C0+dVVZ/siLfc73mWn+cGP1PE1PKPruRSA==", "integrity": "sha512-uYRz5oEfebHCoRhK4moXFM3NSCd5vu2XMLOq/Riz5FdqZMy2RvBtazdtL3gEcmDyqkztDe9ZP/zymObMIbiYSg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/web-bluetooth": "^0.0.20", "@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "11.2.0", "@vueuse/metadata": "13.3.0",
"@vueuse/shared": "11.2.0", "@vueuse/shared": "13.3.0"
"vue-demi": ">=0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
}, },
"peerDependencies": { "peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.5.0"
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
} }
}, },
"node_modules/@vueuse/core/node_modules/@types/web-bluetooth": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
"license": "MIT"
},
"node_modules/@vueuse/metadata": { "node_modules/@vueuse/metadata": {
"version": "11.2.0", "version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.2.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.3.0.tgz",
"integrity": "sha512-L0ZmtRmNx+ZW95DmrgD6vn484gSpVeRbgpWevFKXwqqQxW9hnSi2Ppuh2BzMjnbv4aJRiIw8tQatXT9uOB23dQ==", "integrity": "sha512-42IzJIOYCKIb0Yjv1JfaKpx8JlCiTmtCWrPxt7Ja6Wzoq0h79+YVXmBV03N966KEmDEESTbp5R/qO3AB5BDnGw==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
} }
}, },
"node_modules/@vueuse/shared": { "node_modules/@vueuse/shared": {
"version": "11.2.0", "version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.2.0.tgz", "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.3.0.tgz",
"integrity": "sha512-VxFjie0EanOudYSgMErxXfq6fo8vhr5ICI+BuE3I9FnX7ePllEsVrRQ7O6Q1TLgApeLuPKcHQxAXpP+KnlrJsg==", "integrity": "sha512-L1QKsF0Eg9tiZSFXTgodYnu0Rsa2P0En2LuLrIs/jgrkyiDuJSsPZK+tx+wU0mMsYHUYEjNsuE41uqqkuR8VhA==",
"license": "MIT", "license": "MIT",
"dependencies": {
"vue-demi": ">=0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
}, },
"peerDependencies": { "peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.5.0"
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
} }
}, },
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
...@@ -3499,7 +3441,6 @@ ...@@ -3499,7 +3441,6 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0" "license": "Python-2.0"
}, },
"node_modules/arr-diff": { "node_modules/arr-diff": {
...@@ -4063,6 +4004,7 @@ ...@@ -4063,6 +4004,7 @@
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"peer": true,
"dependencies": { "dependencies": {
"es-define-property": "^1.0.0", "es-define-property": "^1.0.0",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
...@@ -4077,6 +4019,35 @@ ...@@ -4077,6 +4019,35 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/callsites": { "node_modules/callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
...@@ -4498,6 +4469,12 @@ ...@@ -4498,6 +4469,12 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"license": "MIT"
},
"node_modules/css-line-break": { "node_modules/css-line-break": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
...@@ -4704,6 +4681,7 @@ ...@@ -4704,6 +4681,7 @@
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"peer": true,
"dependencies": { "dependencies": {
"es-define-property": "^1.0.0", "es-define-property": "^1.0.0",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
...@@ -4878,6 +4856,20 @@ ...@@ -4878,6 +4856,20 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/duplexify": { "node_modules/duplexify": {
"version": "3.7.1", "version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
...@@ -5118,12 +5110,10 @@ ...@@ -5118,12 +5110,10 @@
} }
}, },
"node_modules/es-define-property": { "node_modules/es-define-property": {
"version": "1.0.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dependencies": { "license": "MIT",
"get-intrinsic": "^1.2.4"
},
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
} }
...@@ -5136,6 +5126,18 @@ ...@@ -5136,6 +5126,18 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
...@@ -5909,15 +5911,21 @@ ...@@ -5909,15 +5911,21 @@
} }
}, },
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.2.4", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2", "function-bind": "^1.1.2",
"has-proto": "^1.0.1", "get-proto": "^1.0.1",
"has-symbols": "^1.0.3", "gopd": "^1.2.0",
"hasown": "^2.0.0" "has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
...@@ -5926,6 +5934,19 @@ ...@@ -5926,6 +5934,19 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/get-ready": { "node_modules/get-ready": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/get-ready/-/get-ready-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/get-ready/-/get-ready-1.0.0.tgz",
...@@ -6004,11 +6025,12 @@ ...@@ -6004,11 +6025,12 @@
} }
}, },
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.0.1", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dependencies": { "license": "MIT",
"get-intrinsic": "^1.1.3" "engines": {
"node": ">= 0.4"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
...@@ -6040,6 +6062,7 @@ ...@@ -6040,6 +6062,7 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"peer": true,
"dependencies": { "dependencies": {
"es-define-property": "^1.0.0" "es-define-property": "^1.0.0"
}, },
...@@ -6047,21 +6070,11 @@ ...@@ -6047,21 +6070,11 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.0.3", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
}, },
...@@ -6668,6 +6681,15 @@ ...@@ -6668,6 +6681,15 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"license": "MIT",
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/loader-runner": { "node_modules/loader-runner": {
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
...@@ -6776,9 +6798,9 @@ ...@@ -6776,9 +6798,9 @@
} }
}, },
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.12", "version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0" "@jridgewell/sourcemap-codec": "^1.5.0"
...@@ -6838,6 +6860,43 @@ ...@@ -6838,6 +6860,43 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/markdown-it": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz",
"integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/markdown-it/node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/md5.js": { "node_modules/md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
...@@ -6849,6 +6908,12 @@ ...@@ -6849,6 +6908,12 @@
"safe-buffer": "^5.1.2" "safe-buffer": "^5.1.2"
} }
}, },
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
"license": "MIT"
},
"node_modules/memoize-one": { "node_modules/memoize-one": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
...@@ -7419,9 +7484,13 @@ ...@@ -7419,9 +7484,13 @@
} }
}, },
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.12.3", "version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
...@@ -7921,9 +7990,9 @@ ...@@ -7921,9 +7990,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.47", "version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
...@@ -7940,8 +8009,8 @@ ...@@ -7940,8 +8009,8 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.8",
"picocolors": "^1.1.0", "picocolors": "^1.1.1",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
}, },
"engines": { "engines": {
...@@ -7974,15 +8043,16 @@ ...@@ -7974,15 +8043,16 @@
} }
}, },
"node_modules/postcss/node_modules/nanoid": { "node_modules/postcss/node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"license": "MIT",
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
...@@ -8086,11 +8156,12 @@ ...@@ -8086,11 +8156,12 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.11.2", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.0.4" "side-channel": "^1.1.0"
}, },
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
...@@ -8502,6 +8573,7 @@ ...@@ -8502,6 +8573,7 @@
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"peer": true,
"dependencies": { "dependencies": {
"define-data-property": "^1.1.4", "define-data-property": "^1.1.4",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
...@@ -8572,13 +8644,72 @@ ...@@ -8572,13 +8644,72 @@
} }
}, },
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.0.4", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
"side-channel-list": "^1.0.0",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"license": "MIT",
"dependencies": { "dependencies": {
"call-bind": "^1.0.0", "es-errors": "^1.3.0",
"get-intrinsic": "^1.0.2", "object-inspect": "^1.13.3"
"object-inspect": "^1.9.0" },
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
...@@ -9357,6 +9488,12 @@ ...@@ -9357,6 +9488,12 @@
} }
} }
}, },
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
"license": "MIT"
},
"node_modules/ufo": { "node_modules/ufo": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
...@@ -10166,16 +10303,16 @@ ...@@ -10166,16 +10303,16 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vue": { "node_modules/vue": {
"version": "3.5.12", "version": "3.5.15",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.15.tgz",
"integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", "integrity": "sha512-aD9zK4rB43JAMK/5BmS4LdPiEp8Fdh8P1Ve/XNuMF5YRf78fCyPE6FUbQwcaWQ5oZ1R2CD9NKE0FFOVpMR7gEQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.12", "@vue/compiler-dom": "3.5.15",
"@vue/compiler-sfc": "3.5.12", "@vue/compiler-sfc": "3.5.15",
"@vue/runtime-dom": "3.5.12", "@vue/runtime-dom": "3.5.15",
"@vue/server-renderer": "3.5.12", "@vue/server-renderer": "3.5.15",
"@vue/shared": "3.5.12" "@vue/shared": "3.5.15"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "*" "typescript": "*"
...@@ -10295,10 +10432,22 @@ ...@@ -10295,10 +10432,22 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/vue-markdown-render": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/vue-markdown-render/-/vue-markdown-render-2.2.1.tgz",
"integrity": "sha512-XkYnC0PMdbs6Vy6j/gZXSvCuOS0787Se5COwXlepRqiqPiunyCIeTPQAO2XnB4Yl04EOHXwLx5y6IuszMWSgyQ==",
"license": "MIT",
"dependencies": {
"markdown-it": "^13.0.2"
},
"peerDependencies": {
"vue": "^3.3.4"
}
},
"node_modules/vue-router": { "node_modules/vue-router": {
"version": "4.4.5", "version": "4.5.1",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz",
"integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==", "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/devtools-api": "^6.6.4" "@vue/devtools-api": "^6.6.4"
......
...@@ -22,10 +22,11 @@ ...@@ -22,10 +22,11 @@
"@tinymce/tinymce-vue": "^5.0.1", "@tinymce/tinymce-vue": "^5.0.1",
"@vue-flow/controls": "^1.1.2", "@vue-flow/controls": "^1.1.2",
"@vue-flow/core": "^1.39.0", "@vue-flow/core": "^1.39.0",
"@vueuse/components": "^11.2.0", "@vueuse/components": "^13.3.0",
"@vueuse/core": "^11.2.0", "@vueuse/core": "^13.3.0",
"axios": "^1.6.8", "axios": "^1.6.8",
"blueimp-md5": "^2.19.0", "blueimp-md5": "^2.19.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"echarts-wordcloud": "^2.1.0", "echarts-wordcloud": "^2.1.0",
...@@ -37,14 +38,16 @@ ...@@ -37,14 +38,16 @@
"nanoid": "^5.0.7", "nanoid": "^5.0.7",
"pinia": "^2.2.6", "pinia": "^2.2.6",
"scroll-into-view-if-needed": "^3.1.0", "scroll-into-view-if-needed": "^3.1.0",
"vue": "^3.5.12", "vue": "^3.5.15",
"vue-echarts": "^6.6.9", "vue-echarts": "^6.6.9",
"vue-router": "^4.4.5", "vue-markdown-render": "^2.2.1",
"vue-router": "^4.5.1",
"xss": "^1.0.15" "xss": "^1.0.15"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/node20": "^20.1.4", "@tsconfig/node20": "^20.1.4",
"@types/blueimp-md5": "^2.18.2", "@types/blueimp-md5": "^2.18.2",
"@types/crypto-js": "^4.2.2",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
"@types/node": "^20.17.6", "@types/node": "^20.17.6",
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.1.4",
......
class PCMProcessor extends AudioWorkletProcessor {
process(inputs) {
const input = inputs[0]
if (input.length > 0) {
const inputData = input[0] // 取第一个通道
const inputData16 = new Int16Array(inputData.length)
for (let i = 0; i < inputData.length; i++) {
// PCM 16-bit 转换
inputData16[i] = Math.max(-1, Math.min(1, inputData[i])) * 0x7fff
}
// 通过 port 向主线程发送处理后的数据
this.port.postMessage(inputData16.buffer, [inputData16.buffer])
}
return true // 保持处理器活跃
}
}
registerProcessor('pcm-processor', PCMProcessor)
import httpRequest from '@/utils/axios'
// 获取订单列表
export function getOrderList(params?: { live_commodity_type_id?: string; live_commodity_title?: string }) {
return httpRequest.get('/api/lab/v1/experiment/live-practice-order/list', { params })
}
import type { RouteRecordRaw } from 'vue-router'
import Layout from '@/components/layout/Index.vue'
const routes: RouteRecordRaw[] = [
{
path: '/live/order',
component: Layout,
children: [{ path: '', component: () => import('./views/Index.vue') }]
}
]
export { routes }
<script setup>
import LiveProductCategory from '@/components/LiveProductCategory.vue'
import { getOrderList } from '../api'
const appList = ref(null)
// 刷新
const handleRefresh = () => {
appList.value?.refetch()
}
const listParams = reactive({ name: '', live_commodity_type_id: '', live_commodity_title: '' })
// 列表配置
const listOptions = computed(() => {
return {
remote: {
httpRequest: getOrderList,
params: listParams,
beforeRequest(params, isReset) {
if (isReset) listParams.live_commodity_type_id = ''
params.live_commodity_type_id = listParams.live_commodity_type_id
return params
},
},
filters: [
{ label: '直播主题品类', prop: 'live_commodity_type_id', slots: 'filter-category' },
{ label: '直播主题名称', prop: 'live_commodity_title', type: 'input' },
],
columns: [
{ label: '序号', type: 'index', width: 60 },
{ label: '主播', prop: 'updated_operator_name' },
{
label: '商品信息',
prop: 'commodity_info',
computed({ row }) {
try {
const info = JSON.parse(row.commodity_info)
const [picture] = JSON.parse(info.picture_addreses) || []
return `<div style="display: flex; align-items: center; gap: 10px;"><img src="${picture.url}" width="100" />${info.title}</div>`
} catch (e) {
console.log(e)
}
return '--'
},
},
{
label: '单价/数量',
prop: 'num',
computed({ row }) {
return `¥${row.price}<br/>x${row.num}`
},
},
{ label: '订单编号', prop: 'id' },
{
label: '订单状态',
prop: 'status',
computed() {
return '待发货'
},
},
{ label: '下单时间', prop: 'updated_time' },
],
}
})
</script>
<template>
<AppCard title="订单管理">
<AppList v-bind="listOptions" ref="appList">
<template #filter-category>
<LiveProductCategory v-model="listParams.live_commodity_type_id" @change="handleRefresh"></LiveProductCategory>
</template>
</AppList>
</AppCard>
</template>
...@@ -61,3 +61,8 @@ export function getRecordList(params: { live_practice_id: string }) { ...@@ -61,3 +61,8 @@ export function getRecordList(params: { live_practice_id: string }) {
export function getRecord(params: { id: string }) { export function getRecord(params: { id: string }) {
return httpRequest.get('/api/lab/v1/experiment/live-practice/live-practice-record', { params }) return httpRequest.get('/api/lab/v1/experiment/live-practice/live-practice-record', { params })
} }
// 推送字幕
export function pushSubtitle(params: { subtitle: string; selling_point: string; marketing_campaign: string }) {
return httpRequest.get('/api/lab/v1/experiment/live-practice/push-subtitle', { params })
}
<script setup>
import Live from './Live.vue'
import LivePlayback from './LivePlayback.vue'
import { getTest, getRecord, pushSubtitle } from '../api'
import { useCountdown } from '@/composables/useCountdown'
const props = defineProps({
id: { type: String },
recordId: { type: String },
isView: { type: Boolean, default: false },
})
const { timeLeft, formattedTime, stop, reset } = useCountdown({
// 倒计时结束
onEnd: () => {
live.value?.stop()
},
})
const live = ref(null)
const detail = ref(null)
provide('detail', detail)
const duration = computed(() => {
return parseInt(detail.value?.duration) * 60 || 0
})
const isLocalUpload = computed(() => {
return detail.value?.upload_way == 2
})
async function fetchInfo() {
const res = await getTest({ id: props.id })
detail.value = res.data.detail
timeLeft.value = duration.value
}
watchEffect(() => {
!props.isView && fetchInfo()
})
// 商品卖点
const hotList = computed(() => {
return detail.value?.live_speech.selling_point.split(/;|;/)
})
// 营销活动
const actList = computed(() => {
return detail.value?.live_speech.marketing_campaign.split(/;|;/)
})
// 直播记录数据
const record = ref(null)
provide('record', record)
// 直播数据
const stats = computed(() => {
const result = { totalViewers: 0, peakViewers: 0, totalGifts: 0, totalLikes: 0, totalGiftViewers: 0 }
return Object.assign(result, record.value?.live_info.stats)
})
const timelines = ref([])
const fetchRecord = async () => {
const res = await getRecord({ id: props.recordId })
const resDetail = res.data.detail
record.value = { ...resDetail, live_info: JSON.parse(resDetail.live_info) }
detail.value = resDetail.live_practice_info
timeLeft.value = duration.value
timelines.value = JSON.parse(resDetail.subtitle)?.Result?.Sentences || []
}
onMounted(() => {
props.isView && fetchRecord()
})
// 毫秒转分钟 00:00,需要补0
const formatTime = (time) => {
const minutes = Math.floor(time / 1000 / 60)
const seconds = Math.floor((time / 1000) % 60)
return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}
const orderCount = ref(0)
const onSentenceEnd = async (result, data) => {
console.log('onSentenceEnd', result, data)
const res = await pushSubtitle({
subtitle: result,
selling_point: detail.value.live_speech.selling_point,
marketing_campaign: detail.value.live_speech.marketing_campaign,
})
orderCount.value = res.data.count
}
const currentStats = ref({})
const onStatsChange = (stats) => {
currentStats.value = stats
}
</script>
<template>
<div class="live-row">
<div class="live-col">
<template v-if="isView">
<LivePlayback :record="record" v-if="record"></LivePlayback>
</template>
<template v-else>
<Live
ref="live"
:isLocalUpload="isLocalUpload"
:onStart="() => reset(duration)"
:onStop="stop"
:onSentenceEnd="onSentenceEnd"
:onStatsChange="onStatsChange"
v-if="detail" />
</template>
</div>
<div class="live-col" style="flex: 1" v-if="isView">
<el-timeline style="max-width: 600px">
<el-timeline-item
placement="top"
v-for="(item, index) in timelines"
:key="index"
:timestamp="formatTime(item.BeginTime)">
{{ item.Text }}
</el-timeline-item>
</el-timeline>
</div>
<div class="live-col" style="flex: 1">
<h2 class="h2-title">直播话术</h2>
<div class="live-talk-content" v-html="detail?.live_speech.content"></div>
</div>
<div class="live-col" style="width: 350px" v-if="!isView">
<div class="live-col-box" v-if="isView">
<h2 class="h2-title">直播数据</h2>
<div class="live-data">
<dl>
<dt>观众总人数:</dt>
<dd>{{ stats.totalViewers }}</dd>
</dl>
<dl>
<dt>最高峰人数:</dt>
<dd>{{ stats.peakViewers }}</dd>
</dl>
<dl>
<dt>点赞数:</dt>
<dd>{{ stats.totalLikes }}</dd>
</dl>
<dl>
<dt>刷礼物人数:</dt>
<dd>{{ stats.totalGiftViewers }}</dd>
</dl>
<dl>
<dt>刷礼物总数:</dt>
<dd>{{ stats.totalGifts }}</dd>
</dl>
</div>
</div>
<div class="live-col-box" v-else>
<h2 class="h2-title">倒计时</h2>
<h3 class="live-time">{{ formattedTime }}</h3>
<div class="live-data">
<dl>
<dt>观众人数:</dt>
<dd>{{ currentStats.viewers }}</dd>
</dl>
<dl>
<dt>订单量:</dt>
<dd>{{ orderCount }}</dd>
</dl>
</div>
</div>
<div class="live-col-box">
<h2 class="h2-title">主题卖点</h2>
<ul class="live-tag live-tag__hot">
<li v-for="item in hotList" :key="item">{{ item }}</li>
</ul>
</div>
<div class="live-col-box">
<h2 class="h2-title">营销活动</h2>
<ul class="live-tag live-tag__act">
<li v-for="item in actList" :key="item">{{ item }}</li>
</ul>
</div>
</div>
</div>
</template>
<style lang="scss">
.live-row {
height: 100%;
display: flex;
gap: 20px;
}
.live-col {
padding: 20px;
border-radius: 10px;
border: 1px solid #eee;
max-height: 100%;
overflow-y: auto;
.h2-title {
margin-top: 0;
}
}
.live-tag {
margin: 20px 0;
background-color: #eee;
border-radius: 10px;
padding: 20px;
gap: 10px;
li {
line-height: 30px;
background-color: #fff;
text-align: center;
border: 1px solid rgba(105, 113, 140, 0.12);
}
}
.live-data {
padding: 0 0 20px 10px;
dl {
margin: 10px 0;
display: flex;
}
dt {
font-weight: bold;
}
}
.live-time {
height: 140px;
font-size: 72px;
text-align: center;
color: var(--main-color);
}
.live-tag__hot {
display: flex;
flex-wrap: wrap;
li {
flex: 0 0 calc(50% - 10px);
}
}
.live-tag__act {
li {
margin: 10px 0;
}
}
.live-talk-content {
max-height: 660px;
overflow-y: auto;
line-height: 24px;
}
</style>
...@@ -11,14 +11,24 @@ import { saveAs } from 'file-saver' ...@@ -11,14 +11,24 @@ import { saveAs } from 'file-saver'
import md5 from 'blueimp-md5' import md5 from 'blueimp-md5'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useLiveChat } from '../composables/useLiveChat' import { useLiveChat } from '../composables/useLiveChat'
import { useSpeechTranscriber } from '../composables/useSpeechTranscriber'
const props = defineProps({ const props = defineProps({
isLocalUpload: { type: Boolean, default: false }, isLocalUpload: { type: Boolean, default: false },
onStart: { type: Function, default: () => {} }, onStart: { type: Function, default: () => {} },
onStop: { type: Function, default: () => {} }, onStop: { type: Function, default: () => {} },
onSentenceEnd: { type: Function, default: () => {} },
onStatsChange: { type: Function, default: () => {} },
}) })
const { messages, viewers, stats, currentTime, start: startChat } = useLiveChat() const { messages, viewers, stats, currentTime, start: startChat } = useLiveChat()
watch(
() => [stats, viewers],
() => {
props.onStatsChange && props.onStatsChange({ ...stats, viewers: viewers.value.length })
},
{ immediate: true, deep: true }
)
const detail = inject('detail') const detail = inject('detail')
...@@ -50,6 +60,9 @@ const { send } = useSocket({ ...@@ -50,6 +60,9 @@ const { send } = useSocket({
} }
}, },
}) })
const { start: startSpeechTranscriber, stop: stopSpeechTranscriber } = useSpeechTranscriber({
onSentenceEnd: props.onSentenceEnd,
})
const { const {
stream, stream,
...@@ -61,8 +74,12 @@ const { ...@@ -61,8 +74,12 @@ const {
currentTime: currentLiveTime, currentTime: currentLiveTime,
} = useLive({ } = useLive({
onStart: () => { onStart: () => {
console.log('开始直播')
props.onStart && props.onStart() props.onStart && props.onStart()
startChat() startChat()
if (!props.isLocalUpload) {
startSpeechTranscriber(stream.value)
}
}, },
onRecord: async (blob) => { onRecord: async (blob) => {
if (props.isLocalUpload) return if (props.isLocalUpload) return
...@@ -75,6 +92,7 @@ const { ...@@ -75,6 +92,7 @@ const {
send(jsonData) send(jsonData)
}, },
onStop: (blob) => { onStop: (blob) => {
console.log('结束直播')
if (enabled.value) return if (enabled.value) return
props.onStop && props.onStop(blob) props.onStop && props.onStop(blob)
handleUpdateRecord({ live_video_size: blob.size.toString() }) handleUpdateRecord({ live_video_size: blob.size.toString() })
...@@ -83,6 +101,7 @@ const { ...@@ -83,6 +101,7 @@ const {
saveAs(blob, `${fileName.value}.mp4`) saveAs(blob, `${fileName.value}.mp4`)
ElMessageBox.alert('请将保存的本地视频文件上传服务端,否则会影响您的实操成绩评价!', '温馨提示') ElMessageBox.alert('请将保存的本地视频文件上传服务端,否则会影响您的实操成绩评价!', '温馨提示')
} }
stopSpeechTranscriber()
}, },
}) })
......
...@@ -46,7 +46,21 @@ const listOptions = { ...@@ -46,7 +46,21 @@ const listOptions = {
return row.live_video_addres ? '已上传' : '未上传' return row.live_video_addres ? '已上传' : '未上传'
}, },
}, },
{ label: '操作', slots: 'table-x', width: 150 }, {
label: '状态',
prop: 'ai_status',
computed({ row }) {
return row.ai_status || '--'
},
},
{
label: '评级',
prop: 'ai_level',
computed({ row }) {
return row.ai_level || '--'
},
},
{ label: '操作', slots: 'table-x', width: 120 },
], ],
} }
......
...@@ -72,7 +72,7 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }: ...@@ -72,7 +72,7 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
// Update currentTime every 100ms while recording // Update currentTime every 100ms while recording
timeUpdateInterval = setInterval(() => { timeUpdateInterval = setInterval(() => {
currentTime.value = Math.floor((Date.now() - startTime.value) / 1000) currentTime.value = Math.floor((Date.now() - startTime.value) / 1000)
}, 100) }, 1000 * 5)
} }
// 录像停止时处理 // 录像停止时处理
......
import axios from 'axios'
import Base64 from 'crypto-js/enc-base64'
import HmacSHA1 from 'crypto-js/hmac-sha1'
import { useWebSocket } from '@vueuse/core'
// https://help.aliyun.com/zh/isi/developer-reference/websocket
export function useSpeechTranscriber({ onSentenceEnd }: { onSentenceEnd?: (result: string, data: any) => void }) {
let audioContext: AudioContext
let audioInput: MediaStreamAudioSourceNode
const token = ref('')
const isTranscriptionStarted = ref(false)
const wsUrl = computed(() => {
return `wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1?token=${token.value}`
})
const header = {
appkey: import.meta.env.VITE_APP_KEY,
namespace: 'SpeechTranscriber',
task_id: crypto.randomUUID().replace(/-/g, ''),
message_id: crypto.randomUUID().replace(/-/g, ''),
}
const { send, status, open } = useWebSocket(wsUrl, {
autoConnect: false,
immediate: false,
onConnected: () => {
console.log('语音识别连接成功')
const startTranscriptionMessage = {
header: { ...header, name: 'StartTranscription' },
payload: {
format: 'pcm',
sample_rate: 16000,
enable_intermediate_result: true,
enable_punctuation_prediction: true,
enable_inverse_text_normalization: true,
},
}
send(JSON.stringify(startTranscriptionMessage))
},
onMessage: (ws, event) => {
try {
const data = JSON.parse(event.data)
if (data.header.name === 'TranscriptionStarted') {
isTranscriptionStarted.value = true
}
if (data.header.name === 'SentenceEnd') {
// 一句话结束
console.log(data.payload.result)
onSentenceEnd?.(data.payload.result, data)
}
} catch (e) {
console.log('error', e, event.data)
}
},
onError: (ws, event) => {
console.log('语音识别连接失败', event)
},
onDisconnected: (ws, event) => {
console.log('语音识别连接断开', event)
},
})
const start = async (stream: MediaStream) => {
console.log('开始录音', stream)
token.value = await getToken()
open()
try {
// 创建 AudioContext 并设定采样率
audioContext = new AudioContext({ sampleRate: 16000 })
audioInput = audioContext.createMediaStreamSource(stream)
// 加载 AudioWorkletProcessor 模块
await audioContext.audioWorklet.addModule('/processor.js')
// 创建自定义处理器节点
const audioWorkletNode = new AudioWorkletNode(audioContext, 'pcm-processor')
// 监听自定义消息
audioWorkletNode.port.onmessage = (event) => {
const inputData16 = event.data as ArrayBuffer
if (status.value === 'OPEN' && isTranscriptionStarted.value) {
send(inputData16) // 发送到后端或处理函数
}
}
// 连接音频流到处理器
audioInput.connect(audioWorkletNode)
// 如果你不需要播放,可以不连接 destination
// audioWorkletNode.connect(audioContext.destination);
} catch (e) {
console.error('录音失败: ' + e)
}
}
const stop = () => {
if (audioInput) {
audioInput.disconnect()
}
if (audioContext) {
audioContext.close()
}
const stopTranscriptionMessage = { header: { ...header, name: 'StopTranscription' } }
send(JSON.stringify(stopTranscriptionMessage))
}
return { start, stop }
}
async function getToken() {
const parameters: Record<string, string> = {
AccessKeyId: import.meta.env.VITE_ACCESS_KEY_ID,
Action: 'CreateToken',
Format: 'JSON',
RegionId: 'cn-shanghai',
SignatureMethod: 'HMAC-SHA1',
SignatureNonce: crypto.randomUUID(),
SignatureVersion: '1.0',
Timestamp: new Date().toISOString().replace(/\.\d{3}/, ''),
Version: '2019-02-28',
}
const specialUrlEncode = (text: string) => {
return encodeURIComponent(text).replace(/\+/g, '%20').replace(/\*/g, '%2A').replace(/%7E/g, '~')
}
const encodeParameters = (params: Record<string, string>) => {
return Object.keys(params)
.sort()
.map((key) => `${specialUrlEncode(key)}=${specialUrlEncode(params[key])}`)
.join('&')
}
const canonicalizedQueryString = encodeParameters(parameters)
const stringToSign = 'GET' + '&' + specialUrlEncode('/') + '&' + specialUrlEncode(canonicalizedQueryString)
const signature = Base64.stringify(HmacSHA1(stringToSign, `${import.meta.env.VITE_ACCESS_KEY_SECRET}&`))
const encodedSignature = specialUrlEncode(signature)
const url = `https://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${encodedSignature}&${canonicalizedQueryString}`
const response = await axios.get(url)
return response.data.Token.Id
}
...@@ -12,7 +12,7 @@ const routes: RouteRecordRaw[] = [ ...@@ -12,7 +12,7 @@ const routes: RouteRecordRaw[] = [
children: [ children: [
{ path: '', component: () => import('./views/Index.vue') }, { path: '', component: () => import('./views/Index.vue') },
{ path: 'demo', component: () => import('./views/Demo.vue') }, { path: 'demo', component: () => import('./views/Demo.vue') },
{ path: 'view', component: () => import('./views/Demo.vue'), props: { isView: true } }, { path: 'view', component: () => import('./views/View.vue') },
], ],
}, },
{ {
......
<script setup> <script setup>
import Live from '../components/Live.vue' import Demo from '../components/Demo.vue'
import LivePlayback from '../components/LivePlayback.vue'
import { getTest, getRecord } from '../api'
import { useCountdown } from '@/composables/useCountdown'
const props = defineProps({
isView: { type: Boolean, default: false },
})
const route = useRoute() const route = useRoute()
const id = route.query.id
const { timeLeft, formattedTime, stop, reset } = useCountdown({
// 倒计时结束
onEnd: () => {
live.value?.stop()
},
})
const live = ref(null)
const detail = ref(null)
provide('detail', detail)
const duration = computed(() => {
return parseInt(detail.value?.duration) * 60 || 0
})
const isLocalUpload = computed(() => {
return detail.value?.upload_way == 2
})
async function fetchInfo() {
const res = await getTest({ id: route.query.id })
detail.value = res.data.detail
timeLeft.value = duration.value
}
watchEffect(() => {
!props.isView && fetchInfo()
})
// 商品卖点
const hotList = computed(() => {
return detail.value?.live_speech.selling_point.split(/;|;/)
})
// 营销活动
const actList = computed(() => {
return detail.value?.live_speech.marketing_campaign.split(/;|;/)
})
// 直播记录数据
const record = ref(null)
provide('record', record)
// 直播数据
const stats = computed(() => {
const result = { totalViewers: 0, peakViewers: 0, totalGifts: 0, totalLikes: 0, totalGiftViewers: 0 }
return Object.assign(result, record.value?.live_info.stats)
})
const fetchRecord = async () => {
const res = await getRecord({ id: route.query.record_id })
const resDetail = res.data.detail
record.value = { ...resDetail, live_info: JSON.parse(resDetail.live_info) }
detail.value = resDetail.live_practice_info
timeLeft.value = duration.value
}
onMounted(() => {
props.isView && fetchRecord()
})
</script> </script>
<template> <template>
<AppCard :title="isView ? '查看历史直播详情' : '直播'" full> <AppCard title="直播" full>
<div class="live-row"> <Demo :id="id" />
<div class="live-col">
<template v-if="isView">
<LivePlayback :record="record" v-if="record"></LivePlayback>
</template>
<template v-else>
<Live
ref="live"
:isLocalUpload="isLocalUpload"
:onStart="() => reset(duration)"
:onStop="stop"
v-if="detail" />
</template>
</div>
<div class="live-col" style="flex: 1">
<h2 class="h2-title">直播话术</h2>
<div class="live-talk-content" v-html="detail?.live_speech.content"></div>
</div>
<div class="live-col" style="width: 350px">
<div class="live-col-box" v-if="isView">
<h2 class="h2-title">直播数据</h2>
<div class="live-data">
<dl>
<dt>观众总人数:</dt>
<dd>{{ stats.totalViewers }}</dd>
</dl>
<dl>
<dt>最高峰人数:</dt>
<dd>{{ stats.peakViewers }}</dd>
</dl>
<dl>
<dt>点赞数:</dt>
<dd>{{ stats.totalLikes }}</dd>
</dl>
<dl>
<dt>刷礼物人数:</dt>
<dd>{{ stats.totalGiftViewers }}</dd>
</dl>
<dl>
<dt>刷礼物总数:</dt>
<dd>{{ stats.totalGifts }}</dd>
</dl>
</div>
</div>
<div class="live-col-box" v-else>
<h2 class="h2-title">倒计时</h2>
<h3 class="live-time">{{ formattedTime }}</h3>
</div>
<div class="live-col-box">
<h2 class="h2-title">主题卖点</h2>
<ul class="live-tag live-tag__hot">
<li v-for="item in hotList" :key="item">{{ item }}</li>
</ul>
</div>
<div class="live-col-box">
<h2 class="h2-title">营销活动</h2>
<ul class="live-tag live-tag__act">
<li v-for="item in actList" :key="item">{{ item }}</li>
</ul>
</div>
</div>
</div>
</AppCard> </AppCard>
</template> </template>
<style lang="scss">
.live-row {
height: 100%;
display: flex;
gap: 20px;
}
.live-col {
padding: 20px;
border-radius: 10px;
border: 1px solid #eee;
.h2-title {
margin-top: 0;
}
}
.live-tag {
margin: 20px 0;
background-color: #eee;
border-radius: 10px;
padding: 20px;
gap: 10px;
li {
line-height: 30px;
background-color: #fff;
text-align: center;
border: 1px solid rgba(105, 113, 140, 0.12);
}
}
.live-data {
padding: 0 0 20px 10px;
dl {
margin: 10px 0;
display: flex;
}
dt {
font-weight: bold;
}
}
.live-time {
height: 140px;
font-size: 72px;
text-align: center;
color: var(--main-color);
}
.live-tag__hot {
display: flex;
flex-wrap: wrap;
li {
flex: 0 0 calc(50% - 10px);
}
}
.live-tag__act {
li {
margin: 10px 0;
}
}
.live-talk-content {
max-height: 660px;
overflow-y: auto;
line-height: 24px;
}
</style>
<script setup>
import VueMarkdown from 'vue-markdown-render'
import Demo from '../components/Demo.vue'
import { getRecord } from '../api'
const route = useRoute()
const id = route.query.id
const recordId = route.query.record_id
const dialogVisible = ref(false)
const detail = ref(null)
const fetchRecord = async () => {
const res = await getRecord({ id: recordId })
const resDetail = res.data.detail
detail.value = { ...resDetail, live_info: JSON.parse(resDetail.live_info) }
}
onMounted(() => {
fetchRecord()
})
const tipsList = {
A: [
{ title: '卖点讲解', content: '强化产品独特性与情感场景化表达。' },
{ title: '违规情况', content: '关注平台新规并规避敏感词。' },
{ title: '讲解时长', content: '精准分配时间,促销环节压缩冗余。' },
{ title: '其他建议', content: '模拟实战并复盘转化数据。' },
],
B: [
{ title: '卖点讲解', content: '场景化设计减少参数罗列。' },
{ title: '违规情况', content: '熟记合规词库并规避竞品对比。' },
{ title: '讲解时长', content: '控制节奏,促销环节提速。' },
{ title: '其他建议', content: '学习高感染力话术并准备互动模板。' },
],
C: [
{ title: '卖点讲解', content: '结构化表达并突出核心卖点。' },
{ title: '违规情况', content: '系统学习规则并使用AI审核。' },
{ title: '讲解时长', content: '分段练习并制定时间分配表。' },
{ title: '其他建议', content: '参加基础培训并拆解优秀案例。' },
],
D: [
{ title: '卖点讲解', content: '模板化练习并记忆关键词。' },
{ title: '违规情况', content: '精读合规手册并替换敏感词。' },
{ title: '讲解时长', content: '分段训练并使用计时器。' },
{ title: '其他建议', content: '录制回放并建立反馈机制。' },
],
}
const tips = computed(() => {
return tipsList[detail.value?.ai_level || 'A']
})
function formatDuration(seconds) {
const minutes = Math.floor(seconds / 60)
const remainingSeconds = (seconds % 60).toFixed(2)
return minutes > 0 ? `${minutes}m${remainingSeconds}s` : `${remainingSeconds}s`
}
</script>
<template>
<div class="live-view" v-if="detail">
<AppCard>
<div class="live-info">
<div class="live-info-header">
<h2>我的练习表现</h2>
<p>评分等级</p>
<h3>{{ detail.ai_level || '--' }}</h3>
<p>主播完成质量良好,需要关注细节勤加练习</p>
</div>
<div class="live-info-item">
<div>
<p>主播姓名</p>
<p>{{ detail.created_operator.real_name || detail.created_operator.nickname }}</p>
</div>
<div>
<p>直播时长</p>
<p>{{ formatDuration(detail.live_duration) }}</p>
</div>
<div>
<p>开始时间</p>
<p>{{ detail.live_start_time }}</p>
</div>
<div>
<p>结束时间</p>
<p>{{ detail.live_end_time }}</p>
</div>
<div>
<p>视频状态</p>
<p>已上传</p>
</div>
<div>
<p>观众总人数</p>
<p>{{ detail.live_info.stats.totalViewers }}</p>
</div>
<div>
<p>最高峰人数</p>
<p>{{ detail.live_info.stats.peakViewers }}</p>
</div>
<div>
<p>点赞数</p>
<p>{{ detail.live_info.stats.totalLikes }}</p>
</div>
<div>
<p>刷礼物人数</p>
<p>{{ detail.live_info.stats.totalGiftViewers }}</p>
</div>
<div>
<p>刷礼物总数</p>
<p>{{ detail.live_info.stats.totalGifts }}</p>
</div>
<div>
<p>下单量</p>
<p>{{ detail.orders_count }}</p>
</div>
<div>
<p>操作</p>
<el-button type="primary" link @click="dialogVisible = true">查看</el-button>
</div>
</div>
</div>
</AppCard>
<AppCard>
<h2 class="live-title">练习优化建议</h2>
<div v-for="(item, index) in tips" :key="index">
<p class="live-tips">
<b>{{ item.title }}</b> {{ item.content }}
</p>
</div>
</AppCard>
<AppCard>
<h2 class="live-title">违规情况</h2>
<div class="live-markdown">
<VueMarkdown :source="detail.illegal_word" v-if="detail.illegal_word" />
</div>
</AppCard>
<AppCard>
<h2 class="live-title">卖点讲解</h2>
<el-steps direction="vertical" :active="1">
<el-step
v-for="(item, index) in detail.words"
:key="index"
:title="item.name"
:status="item.time ? 'success' : 'error'">
<template #description> {{ item.time }} {{ item.subtitle }} </template>
</el-step>
</el-steps>
</AppCard>
<AppCard>
<h2 class="live-title">产生订单</h2>
<el-steps direction="vertical" :active="1">
<el-step
v-for="(item, index) in detail.words"
:key="index"
:title="item.name"
:status="item.time ? 'success' : 'error'">
<template #description> {{ item.time }} {{ item.subtitle }} </template>
</el-step>
</el-steps>
</AppCard>
<el-dialog v-model="dialogVisible" title="直播回放" width="1200px">
<div style="height: 740px">
<Demo :id="id" :recordId="recordId" :isView="true" />
</div>
</el-dialog>
</div>
</template>
<style lang="scss">
.live-view {
.live-info {
display: flex;
gap: 12px;
p {
font-size: 14px;
color: #525252;
margin: 10px 0;
}
.live-info-header {
display: flex;
flex-direction: column;
border-right: 1px solid #e5e5e5;
padding-right: 12px;
h2 {
font-size: 24px;
font-weight: bold;
}
h3 {
font-size: 40px;
font-weight: bold;
}
}
.live-info-item {
flex: 1;
display: flex;
flex-wrap: wrap;
gap: 12px;
div {
width: 180px;
}
}
}
.live-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
}
.live-tips {
margin-top: 10px;
font-size: 14px;
color: #000;
b {
font-size: 14px;
font-weight: bold;
margin-right: 20px;
}
}
.el-step__description {
margin-bottom: 20px;
}
.live-markdown {
line-height: 1.8;
li {
list-style: disc;
margin-left: 20px;
}
p {
margin: 10px 0;
}
strong,
b {
font-weight: bold;
}
}
}
</style>
...@@ -342,11 +342,24 @@ const adminMenus: IMenuItem[] = [ ...@@ -342,11 +342,24 @@ const adminMenus: IMenuItem[] = [
path: '/live', path: '/live',
icon: markRaw(IconLive), icon: markRaw(IconLive),
children: [ children: [
{ id: 21, name: '商品品类管理', path: '/live/product/category', icon: markRaw(IconLiveProductCategory) }, {
{ id: 22, name: '商品属性管理', path: '/live/product/attr', icon: markRaw(IconLiveProductAttr) }, id: 21,
{ id: 23, name: '商品管理', path: '/live/product/management', icon: markRaw(IconLiveProductManagement) }, name: '商品品类管理',
path: '/live/product/category',
icon: markRaw(IconLiveProductCategory),
role: [5, 6],
},
{ id: 22, name: '商品属性管理', path: '/live/product/attr', icon: markRaw(IconLiveProductAttr), role: [5, 6] },
{
id: 23,
name: '商品管理',
path: '/live/product/management',
icon: markRaw(IconLiveProductManagement),
role: [5, 6],
},
{ id: 24, name: '直播话术管理', path: '/live/talk', icon: markRaw(IconLiveTalk) }, { id: 24, name: '直播话术管理', path: '/live/talk', icon: markRaw(IconLiveTalk) },
{ id: 25, name: '直播', path: '/live/test', icon: markRaw(IconLiveTest) }, { id: 25, name: '直播', path: '/live/test', icon: markRaw(IconLiveTest) },
{ id: 201, name: '订单管理', path: '/live/order', icon: markRaw(IconCard) },
], ],
}, },
{ {
...@@ -372,13 +385,14 @@ export const useMenuStore = defineStore({ ...@@ -372,13 +385,14 @@ export const useMenuStore = defineStore({
getters: { getters: {
menus: (state) => { menus: (state) => {
const userStore = useUserStore() const userStore = useUserStore()
const userRole = userStore.role?.id const userRole = userStore.role?.id || 1
const userPermissions = userStore.menus || [] const userPermissions = userStore.menus || []
// 递归过滤菜单及其子菜单 // 递归过滤菜单及其子菜单
const filterMenus = (menus: IMenuItem[]): IMenuItem[] => { const filterMenus = (menus: IMenuItem[]): IMenuItem[] => {
return menus return menus
.filter((menu) => userPermissions.some((perm) => perm.id === menu.id)) .filter((menu) => userPermissions.some((perm) => perm.id === menu.id))
.filter((menu) => menu.role ? menu.role?.includes(userRole) : true)
.map((menu) => { .map((menu) => {
const filteredMenu: IMenuItem = { const filteredMenu: IMenuItem = {
...menu, ...menu,
......
...@@ -8,6 +8,7 @@ export interface IMenuItem { ...@@ -8,6 +8,7 @@ export interface IMenuItem {
studentPath?: string studentPath?: string
icon?: Component icon?: Component
children?: IMenuItem[] children?: IMenuItem[]
role?: number[]
} }
// 用户信息 // 用户信息
......
...@@ -50,11 +50,11 @@ export default defineConfig(({ mode }) => ({ ...@@ -50,11 +50,11 @@ export default defineConfig(({ mode }) => ({
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/qianfan/, ''), rewrite: (path) => path.replace(/^\/api\/qianfan/, ''),
}, },
'/api/lab': { // '/api/lab': {
target: 'http://local-com-resource-api.frontend.ezijing.com', // target: 'http://local-com-resource-api.frontend.ezijing.com',
changeOrigin: true, // changeOrigin: true,
rewrite: (path) => path.replace(/^\/api\/lab/, ''), // rewrite: (path) => path.replace(/^\/api\/lab/, ''),
}, // },
'/api': 'https://saas-dml.ezijing.com', '/api': 'https://saas-dml.ezijing.com',
}, },
}, },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论