diff --git a/.gitignore b/.gitignore index 7cca4bc58..3a39506ff 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ app/.test-tmp-stream/ /.spool TUICallKit-Vue3/.env /.codegraph +app/artifacts/ diff --git a/admin/pnpm-lock.yaml b/admin/pnpm-lock.yaml index 4018d18a4..959292acf 100644 --- a/admin/pnpm-lock.yaml +++ b/admin/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 4.0.12 '@tencentcloud/chat-uikit-vue3': specifier: ^4.5.4 - version: 4.5.4(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tencentcloud/universal-api@2.4.1)(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)) + version: 4.5.4(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tencentcloud/universal-api@2.4.1)(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(debug@4.4.3(supports-color@7.2.0))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)) '@trtc/calls-uikit-vue': specifier: ^4.4.6 version: 4.5.0 @@ -37,10 +37,13 @@ importers: version: 5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.33(typescript@5.7.3)) axios: specifier: ^1.7.9 - version: 1.16.0 + version: 1.16.0(debug@4.4.3(supports-color@7.2.0)) + cos-js-sdk-v5: + specifier: ^1.10.1 + version: 1.10.1 css-color-function: specifier: ^1.3.3 - version: 1.3.3 + version: 1.3.3(supports-color@7.2.0) echarts: specifier: ^5.6.0 version: 5.6.0 @@ -50,6 +53,9 @@ importers: highlight.js: specifier: ^11.11.1 version: 11.11.1 + hls.js: + specifier: ^1.6.16 + version: 1.7.2 html2canvas: specifier: ^1.4.1 version: 1.4.1 @@ -101,19 +107,19 @@ importers: version: 0.2.3 '@vitejs/plugin-legacy': specifier: ^6.0.1 - version: 6.0.1(terser@5.46.2)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)) + version: 6.0.1(supports-color@7.2.0)(terser@5.46.2)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)) '@vitejs/plugin-vue': specifier: ^5.2.1 version: 5.2.1(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))(vue@3.5.33(typescript@5.7.3)) '@vitejs/plugin-vue-jsx': specifier: ^4.1.1 - version: 4.1.1(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))(vue@3.5.33(typescript@5.7.3)) + version: 4.1.1(supports-color@7.2.0)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))(vue@3.5.33(typescript@5.7.3)) '@vue/eslint-config-prettier': specifier: ^10.2.0 - version: 10.2.0(eslint@9.39.4(jiti@1.21.7))(prettier@3.8.3) + version: 10.2.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.8.3) '@vue/eslint-config-typescript': specifier: ^14.4.0 - version: 14.7.0(eslint-plugin-vue@9.32.0(eslint@9.39.4(jiti@1.21.7)))(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) + version: 14.7.0(eslint-plugin-vue@9.32.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0))(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) '@vue/tsconfig': specifier: ^0.7.0 version: 0.7.0(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)) @@ -125,13 +131,13 @@ importers: version: 3.4.2 eslint: specifier: ^9.10.0 - version: 9.39.4(jiti@1.21.7) + version: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) eslint-plugin-simple-import-sort: specifier: ^12.1.1 - version: 12.1.1(eslint@9.39.4(jiti@1.21.7)) + version: 12.1.1(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)) eslint-plugin-vue: specifier: ^9.32.0 - version: 9.32.0(eslint@9.39.4(jiti@1.21.7)) + version: 9.32.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0) execa: specifier: ^9.5.2 version: 9.6.1 @@ -161,7 +167,7 @@ importers: version: 19.1.0(@vueuse/core@12.7.0(typescript@5.7.3)) unplugin-vue-components: specifier: ^28.4.0 - version: 28.4.0(@babel/parser@7.29.3)(vue@3.5.33(typescript@5.7.3)) + version: 28.4.0(@babel/parser@7.29.3)(supports-color@7.2.0)(vue@3.5.33(typescript@5.7.3)) vite: specifier: ^6.1.1 version: 6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2) @@ -170,7 +176,7 @@ importers: version: 2.0.0(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)) vite-plugin-svg-icons: specifier: ^2.0.1 - version: 2.0.1(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)) + version: 2.0.1(supports-color@7.2.0)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)) vite-plugin-vue-setup-extend: specifier: ^0.4.0 version: 0.4.0(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)) @@ -1295,6 +1301,9 @@ packages: '@tencentcloud/chat@3.6.6': resolution: {integrity: sha512-PYPGUoZHw3GjDgM0N72qr0K/Wjp28HAoGaND077sbUQEwYFaMjZ1tuBQZugFG6v8OS8Ihx71yqNshR3xDHvYaA==} + '@tencentcloud/chat@3.6.7': + resolution: {integrity: sha512-HEmyOFTWRzP4PlHNNVSk3dxEq8wYcyqhGkYT2a0/qgSFD6X7DBwrJWnD5K4HnVXqEafnwF7c8FUIkr2OvxXoMQ==} + '@tencentcloud/lite-chat@1.6.13': resolution: {integrity: sha512-1/KIsc41gdG65afPcC+OYSoS4F+Vf7JliVmq0jZDLQ+Ktll2NQzEtVVp7RDpAfn5aGMSA/W4/2y2cGyeINzkvA==} @@ -1640,6 +1649,11 @@ packages: '@volar/typescript@2.4.28': resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true '@vue/babel-helper-vue-transform-on@1.5.0': resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} @@ -2222,6 +2236,9 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + cos-js-sdk-v5@1.10.1: + resolution: {integrity: sha512-a4SRfCY5g6Z35C7OWe9te/S1zk77rVQzfpvZ33gmTdJQzKxbNbEG7Aw/v453XwVMsQB352FIf7KRMm5Ya/wlZQ==} + crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -2563,6 +2580,7 @@ packages: eslint@9.39.4: resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -2660,6 +2678,10 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-xml-parser@4.5.0: + resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} + hasBin: true + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -2885,6 +2907,9 @@ packages: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} + hls.js@1.7.2: + resolution: {integrity: sha512-CW/pPvSOFIRsosbwxrYaE9ERmpTo5fbTqL7wCvuCFlqW1Bmb1K5fXsY7yiH95rmlr4rVuA7UXHbM/cIXQ6AXwg==} + html-void-elements@2.0.1: resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==} @@ -4145,6 +4170,9 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + strnum@1.1.2: + resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} @@ -4682,20 +4710,20 @@ snapshots: '@babel/compat-data@7.29.3': {} - '@babel/core@7.29.0': + '@babel/core@7.29.0(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helpers': 7.29.2 '@babel/parser': 7.29.3 '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -4730,45 +4758,45 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.29.3(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@7.2.0) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) + '@babel/traverse': 7.29.0(supports-color@7.2.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.18.6(@babel/core@7.29.0)': + '@babel/helper-create-regexp-features-plugin@7.18.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.18.6 regexpu-core: 5.3.2 - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.29.0)': + '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.1 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.0)': + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) lodash.debounce: 4.0.8 resolve: 1.22.12 transitivePeerDependencies: @@ -4776,26 +4804,26 @@ snapshots: '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.28.5(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.28.6(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-imports': 7.28.6(supports-color@7.2.0) '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -4805,27 +4833,27 @@ snapshots: '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.1 - '@babel/helper-wrap-function': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/helper-wrap-function': 7.28.6(supports-color@7.2.0) + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-member-expression-to-functions': 7.28.5(supports-color@7.2.0) '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.27.1(supports-color@7.2.0)': dependencies: - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -4836,10 +4864,10 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helper-wrap-function@7.28.6': + '@babel/helper-wrap-function@7.28.6(supports-color@7.2.0)': dependencies: '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -4853,503 +4881,503 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.3(@babel/core@7.29.0)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) - '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.18.6(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.18.6(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-imports': 7.28.6(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 '@babel/template': 7.28.6 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.29.4(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-systemjs@7.29.4(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/traverse': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@7.2.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/helper-plugin-utils': 7.28.6 - '@babel/preset-env@7.29.5(@babel/core@7.29.0)': + '@babel/preset-env@7.29.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: '@babel/compat-data': 7.29.3 - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.3(@babel/core@7.29.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) - '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-modules-systemjs': 7.29.4(@babel/core@7.29.0) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) - '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.0) - babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.0) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.0) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.3(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-modules-systemjs': 7.29.4(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0(supports-color@7.2.0)) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) core-js-compat: 3.49.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0(supports-color@7.2.0))': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 '@babel/types': 7.29.0 esutils: 2.0.3 @@ -5364,7 +5392,7 @@ snapshots: '@babel/parser': 7.29.3 '@babel/types': 7.29.0 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.0(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 @@ -5372,7 +5400,7 @@ snapshots: '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -5462,17 +5490,17 @@ snapshots: '@esbuild/win32-x64@0.25.0': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))': dependencies: - eslint: 9.39.4(jiti@1.21.7) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.2': + '@eslint/config-array@0.21.2(supports-color@7.2.0)': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -5485,10 +5513,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.5': + '@eslint/eslintrc@3.3.5(supports-color@7.2.0)': dependencies: ajv: 6.15.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -5787,18 +5815,18 @@ snapshots: '@tencentcloud/chat-uikit-engine@2.5.8': dependencies: - '@tencentcloud/chat': 3.6.6 + '@tencentcloud/chat': 3.6.7 tim-profanity-filter-plugin: 1.1.0 tim-upload-plugin: 1.4.3 - '@tencentcloud/chat-uikit-vue3@4.5.4(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tencentcloud/universal-api@2.4.1)(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3))': + '@tencentcloud/chat-uikit-vue3@4.5.4(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tencentcloud/universal-api@2.4.1)(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(debug@4.4.3(supports-color@7.2.0))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3))': dependencies: '@tencentcloud/chat': 3.6.6 '@tencentcloud/chat-uikit-engine': 2.5.8 '@tencentcloud/uikit-base-component-vue3': 1.3.9(vue@3.5.33(typescript@5.7.3)) '@tencentcloud/universal-api': 2.4.1 classnames: 2.5.1 - tuikit-atomicx-vue3: 4.5.7(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)) + tuikit-atomicx-vue3: 4.5.7(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(debug@4.4.3(supports-color@7.2.0))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)) vue: 3.5.33(typescript@5.7.3) transitivePeerDependencies: - '@tencentcloud/tuiroom-engine-js' @@ -5811,6 +5839,8 @@ snapshots: '@tencentcloud/chat@3.6.6': {} + '@tencentcloud/chat@3.6.7': {} + '@tencentcloud/lite-chat@1.6.13': {} '@tencentcloud/tui-core-lite@1.0.1': @@ -5819,7 +5849,7 @@ snapshots: '@tencentcloud/tui-core@2.5.1': dependencies: - '@tencentcloud/chat': 3.6.6 + '@tencentcloud/chat': 3.6.7 tim-profanity-filter-plugin: 1.1.0 tim-upload-plugin: 1.4.3 @@ -6068,15 +6098,15 @@ snapshots: '@types/web-bluetooth@0.0.21': {} - '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3)': + '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3))(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) '@typescript-eslint/scope-manager': 8.59.2 - '@typescript-eslint/type-utils': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) + '@typescript-eslint/type-utils': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.59.2 - eslint: 9.39.4(jiti@1.21.7) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.7.3) @@ -6084,23 +6114,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3)': + '@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3)': dependencies: '@typescript-eslint/scope-manager': 8.59.2 '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.59.2(supports-color@7.2.0)(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.59.2 - debug: 4.4.3 - eslint: 9.39.4(jiti@1.21.7) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.2(typescript@5.7.3)': + '@typescript-eslint/project-service@8.59.2(supports-color@7.2.0)(typescript@5.7.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.7.3) '@typescript-eslint/types': 8.59.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -6114,13 +6144,13 @@ snapshots: dependencies: typescript: 5.7.3 - '@typescript-eslint/type-utils@8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3)': + '@typescript-eslint/type-utils@8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3)': dependencies: '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.7.3) - '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - debug: 4.4.3 - eslint: 9.39.4(jiti@1.21.7) + '@typescript-eslint/typescript-estree': 8.59.2(supports-color@7.2.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) ts-api-utils: 2.5.0(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: @@ -6128,13 +6158,13 @@ snapshots: '@typescript-eslint/types@8.59.2': {} - '@typescript-eslint/typescript-estree@8.59.2(typescript@5.7.3)': + '@typescript-eslint/typescript-estree@8.59.2(supports-color@7.2.0)(typescript@5.7.3)': dependencies: - '@typescript-eslint/project-service': 8.59.2(typescript@5.7.3) + '@typescript-eslint/project-service': 8.59.2(supports-color@7.2.0)(typescript@5.7.3) '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.7.3) '@typescript-eslint/types': 8.59.2 '@typescript-eslint/visitor-keys': 8.59.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) minimatch: 10.2.5 semver: 7.7.4 tinyglobby: 0.2.16 @@ -6143,13 +6173,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3)': + '@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)) '@typescript-eslint/scope-manager': 8.59.2 '@typescript-eslint/types': 8.59.2 - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.7.3) - eslint: 9.39.4(jiti@1.21.7) + '@typescript-eslint/typescript-estree': 8.59.2(supports-color@7.2.0)(typescript@5.7.3) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -6196,10 +6226,10 @@ snapshots: '@uppy/utils': 4.0.1 nanoid: 3.3.12 - '@vitejs/plugin-legacy@6.0.1(terser@5.46.2)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))': + '@vitejs/plugin-legacy@6.0.1(supports-color@7.2.0)(terser@5.46.2)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))': dependencies: - '@babel/core': 7.29.0 - '@babel/preset-env': 7.29.5(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/preset-env': 7.29.5(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) browserslist: 4.28.2 browserslist-to-esbuild: 2.1.1(browserslist@4.28.2) core-js: 3.49.0 @@ -6211,11 +6241,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue-jsx@4.1.1(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))(vue@3.5.33(typescript@5.7.3))': + '@vitejs/plugin-vue-jsx@4.1.1(supports-color@7.2.0)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2))(vue@3.5.33(typescript@5.7.3))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) vite: 6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2) vue: 3.5.33(typescript@5.7.3) transitivePeerDependencies: @@ -6232,35 +6262,37 @@ snapshots: '@volar/source-map@2.4.28': {} - '@volar/typescript@2.4.28': + '@volar/typescript@2.4.28(typescript@5.7.3)': dependencies: '@volar/language-core': 2.4.28 path-browserify: 1.0.1 vscode-uri: 3.1.0 + optionalDependencies: + typescript: 5.7.3 '@vue/babel-helper-vue-transform-on@1.5.0': {} - '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.0)': + '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: - '@babel/helper-module-imports': 7.28.6 + '@babel/helper-module-imports': 7.28.6(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0(supports-color@7.2.0)) '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 + '@babel/traverse': 7.29.0(supports-color@7.2.0) '@babel/types': 7.29.0 '@vue/babel-helper-vue-transform-on': 1.5.0 - '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0) + '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) '@vue/shared': 3.5.33 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.0(supports-color@7.2.0) transitivePeerDependencies: - supports-color - '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.0)': + '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0)': dependencies: '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-module-imports': 7.28.6(supports-color@7.2.0) '@babel/helper-plugin-utils': 7.28.6 '@babel/parser': 7.29.3 '@vue/compiler-sfc': 3.5.33 @@ -6306,23 +6338,23 @@ snapshots: '@vue/devtools-api@6.6.4': {} - '@vue/eslint-config-prettier@10.2.0(eslint@9.39.4(jiti@1.21.7))(prettier@3.8.3)': + '@vue/eslint-config-prettier@10.2.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.8.3)': dependencies: - eslint: 9.39.4(jiti@1.21.7) - eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@1.21.7)) - eslint-plugin-prettier: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@1.21.7)))(eslint@9.39.4(jiti@1.21.7))(prettier@3.8.3) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) + eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)) + eslint-plugin-prettier: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)))(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.8.3) prettier: 3.8.3 transitivePeerDependencies: - '@types/eslint' - '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@9.32.0(eslint@9.39.4(jiti@1.21.7)))(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3)': + '@vue/eslint-config-typescript@14.7.0(eslint-plugin-vue@9.32.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0))(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3)': dependencies: - '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - eslint: 9.39.4(jiti@1.21.7) - eslint-plugin-vue: 9.32.0(eslint@9.39.4(jiti@1.21.7)) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) + eslint-plugin-vue: 9.32.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0) fast-glob: 3.3.3 - typescript-eslint: 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@1.21.7)) + typescript-eslint: 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + vue-eslint-parser: 10.4.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0) optionalDependencies: typescript: 5.7.3 transitivePeerDependencies: @@ -6615,35 +6647,35 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axios@1.16.0: + axios@1.16.0(debug@4.4.3(supports-color@7.2.0)): dependencies: - follow-redirects: 1.16.0 + follow-redirects: 1.16.0(debug@4.4.3(supports-color@7.2.0)) form-data: 4.0.5 proxy-from-env: 2.1.0 transitivePeerDependencies: - debug - babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.0): + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0): dependencies: '@babel/compat-data': 7.29.3 - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.0): + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.0): + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) + '@babel/core': 7.29.0(supports-color@7.2.0) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0(supports-color@7.2.0))(supports-color@7.2.0) transitivePeerDependencies: - supports-color @@ -6695,7 +6727,7 @@ snapshots: dependencies: balanced-match: 4.0.4 - braces@2.3.2: + braces@2.3.2(supports-color@7.2.0): dependencies: arr-flatten: 1.1.0 array-unique: 0.3.2 @@ -6703,7 +6735,7 @@ snapshots: fill-range: 4.0.0 isobject: 3.0.1 repeat-element: 1.1.4 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@7.2.0) snapdragon-node: 2.1.1 split-string: 3.1.0 to-regex: 3.0.2 @@ -6930,6 +6962,10 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cos-js-sdk-v5@1.10.1: + dependencies: + fast-xml-parser: 4.5.0 + crelt@1.0.6: {} cross-spawn@7.0.6: @@ -6940,11 +6976,11 @@ snapshots: crypt@0.0.2: {} - css-color-function@1.3.3: + css-color-function@1.3.3(supports-color@7.2.0): dependencies: balanced-match: 0.1.0 color: 0.11.4 - debug: 3.2.7 + debug: 3.2.7(supports-color@7.2.0) rgb: 0.1.0 transitivePeerDependencies: - supports-color @@ -7005,17 +7041,23 @@ snapshots: de-indent@1.0.2: {} - debug@2.6.9: + debug@2.6.9(supports-color@7.2.0): dependencies: ms: 2.0.0 + optionalDependencies: + supports-color: 7.2.0 - debug@3.2.7: + debug@3.2.7(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 - debug@4.4.3: + debug@4.4.3(supports-color@7.2.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 7.2.0 decode-uri-component@0.2.2: {} @@ -7290,33 +7332,33 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@1.21.7)): + eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)): dependencies: - eslint: 9.39.4(jiti@1.21.7) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) - eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@1.21.7)))(eslint@9.39.4(jiti@1.21.7))(prettier@3.8.3): + eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)))(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.8.3): dependencies: - eslint: 9.39.4(jiti@1.21.7) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@1.21.7)) + eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)) - eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.4(jiti@1.21.7)): + eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)): dependencies: - eslint: 9.39.4(jiti@1.21.7) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) - eslint-plugin-vue@9.32.0(eslint@9.39.4(jiti@1.21.7)): + eslint-plugin-vue@9.32.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) - eslint: 9.39.4(jiti@1.21.7) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.4 - vue-eslint-parser: 9.4.3(eslint@9.39.4(jiti@1.21.7)) + vue-eslint-parser: 9.4.3(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -7346,14 +7388,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.4(jiti@1.21.7): + eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 + '@eslint/config-array': 0.21.2(supports-color@7.2.0) '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 + '@eslint/eslintrc': 3.3.5(supports-color@7.2.0) '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.8 @@ -7363,7 +7405,7 @@ snapshots: ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -7454,14 +7496,14 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - expand-brackets@2.1.4: + expand-brackets@2.1.4(supports-color@7.2.0): dependencies: - debug: 2.6.9 + debug: 2.6.9(supports-color@7.2.0) define-property: 0.2.5 extend-shallow: 2.0.1 posix-character-classes: 0.1.1 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@7.2.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -7481,15 +7523,15 @@ snapshots: assign-symbols: 1.0.0 is-extendable: 1.0.1 - extglob@2.0.4: + extglob@2.0.4(supports-color@7.2.0): dependencies: array-unique: 0.3.2 define-property: 1.0.0 - expand-brackets: 2.1.4 + expand-brackets: 2.1.4(supports-color@7.2.0) extend-shallow: 2.0.1 fragment-cache: 0.2.1 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@7.2.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -7510,6 +7552,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-xml-parser@4.5.0: + dependencies: + strnum: 1.1.2 + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -7552,7 +7598,9 @@ snapshots: flatted@3.4.2: {} - follow-redirects@1.16.0: {} + follow-redirects@1.16.0(debug@4.4.3(supports-color@7.2.0)): + optionalDependencies: + debug: 4.4.3(supports-color@7.2.0) for-each@0.3.5: dependencies: @@ -7739,6 +7787,8 @@ snapshots: highlight.js@11.11.1: {} + hls.js@1.7.2: {} + html-void-elements@2.0.1: {} html2canvas@1.4.1: @@ -8151,20 +8201,20 @@ snapshots: merge2@1.4.1: {} - micromatch@3.1.0: + micromatch@3.1.0(supports-color@7.2.0): dependencies: arr-diff: 4.0.0 array-unique: 0.3.2 - braces: 2.3.2 + braces: 2.3.2(supports-color@7.2.0) define-property: 1.0.0 extend-shallow: 2.0.1 - extglob: 2.0.4 + extglob: 2.0.4(supports-color@7.2.0) fragment-cache: 0.2.1 kind-of: 5.1.0 - nanomatch: 1.2.13 + nanomatch: 1.2.13(supports-color@7.2.0) object.pick: 1.3.0 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@7.2.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -8232,7 +8282,7 @@ snapshots: nanoid@3.3.12: {} - nanomatch@1.2.13: + nanomatch@1.2.13(supports-color@7.2.0): dependencies: arr-diff: 4.0.0 array-unique: 0.3.2 @@ -8243,7 +8293,7 @@ snapshots: kind-of: 6.0.3 object.pick: 1.3.0 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@7.2.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -8964,10 +9014,10 @@ snapshots: dependencies: kind-of: 3.2.2 - snapdragon@0.8.2: + snapdragon@0.8.2(supports-color@7.2.0): dependencies: base: 0.11.2 - debug: 2.6.9 + debug: 2.6.9(supports-color@7.2.0) define-property: 0.2.5 extend-shallow: 2.0.1 map-cache: 0.2.2 @@ -9086,6 +9136,8 @@ snapshots: dependencies: js-tokens: 9.0.1 + strnum@1.1.2: {} + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -9108,7 +9160,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svg-baker@1.7.0: + svg-baker@1.7.0(supports-color@7.2.0): dependencies: bluebird: 3.7.2 clone: 2.1.2 @@ -9116,7 +9168,7 @@ snapshots: image-size: 0.5.5 loader-utils: 1.4.2 merge-options: 1.0.1 - micromatch: 3.1.0 + micromatch: 3.1.0(supports-color@7.2.0) postcss: 5.2.17 postcss-prefix-selector: 1.16.1(postcss@5.2.17) posthtml-rename-id: 1.0.12 @@ -9288,7 +9340,7 @@ snapshots: tsml@1.0.1: {} - tuikit-atomicx-vue3@4.5.7(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)): + tuikit-atomicx-vue3@4.5.7(@tencentcloud/chat-uikit-engine@2.5.8)(@tencentcloud/chat@3.6.6)(@tencentcloud/tuiroom-engine-js@3.5.2)(@tencentcloud/uikit-base-component-vue3@1.3.9(vue@3.5.33(typescript@5.7.3)))(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(debug@4.4.3(supports-color@7.2.0))(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)): dependencies: '@tencentcloud/chat': 3.6.6 '@tencentcloud/chat-uikit-engine': 2.5.8 @@ -9303,7 +9355,7 @@ snapshots: '@tiptap/suggestion': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2) '@tiptap/vue-3': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(vue@3.5.33(typescript@5.7.3)) '@vue/tsconfig': 0.7.0(typescript@5.7.3)(vue@3.5.33(typescript@5.7.3)) - axios: 1.16.0 + axios: 1.16.0(debug@4.4.3(supports-color@7.2.0)) classnames: 2.5.1 date-fns: 4.1.0 eventemitter3: 4.0.7 @@ -9369,13 +9421,13 @@ snapshots: typed-array-buffer: 1.0.3 typed-array-byte-offset: 1.0.4 - typescript-eslint@8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3): + typescript-eslint@8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.7.3) - '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7))(typescript@5.7.3) - eslint: 9.39.4(jiti@1.21.7) + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3))(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.59.2(supports-color@7.2.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.7.3) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -9450,10 +9502,10 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.4 - unplugin-vue-components@28.4.0(@babel/parser@7.29.3)(vue@3.5.33(typescript@5.7.3)): + unplugin-vue-components@28.4.0(@babel/parser@7.29.3)(supports-color@7.2.0)(vue@3.5.33(typescript@5.7.3)): dependencies: chokidar: 3.6.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) local-pkg: 1.1.2 magic-string: 0.30.21 mlly: 1.8.2 @@ -9527,15 +9579,15 @@ snapshots: pathe: 0.2.0 vite: 6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2) - vite-plugin-svg-icons@2.0.1(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)): + vite-plugin-svg-icons@2.0.1(supports-color@7.2.0)(vite@6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2)): dependencies: '@types/svgo': 2.6.4 cors: 2.8.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@7.2.0) etag: 1.8.1 fs-extra: 10.0.0 pathe: 0.2.0 - svg-baker: 1.7.0 + svg-baker: 1.7.0(supports-color@7.2.0) svgo: 2.8.2 vite: 6.4.2(@types/node@22.19.17)(jiti@1.21.7)(sass@1.79.6)(terser@5.46.2) transitivePeerDependencies: @@ -9587,10 +9639,10 @@ snapshots: optionalDependencies: '@vue/runtime-core': 3.5.33 - vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@1.21.7)): + vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - debug: 4.4.3 - eslint: 9.39.4(jiti@1.21.7) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 espree: 11.2.0 @@ -9599,10 +9651,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-eslint-parser@9.4.3(eslint@9.39.4(jiti@1.21.7)): + vue-eslint-parser@9.4.3(eslint@9.39.4(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0): dependencies: - debug: 4.4.3 - eslint: 9.39.4(jiti@1.21.7) + debug: 4.4.3(supports-color@7.2.0) + eslint: 9.39.4(jiti@1.21.7)(supports-color@7.2.0) eslint-scope: 7.1.1 eslint-visitor-keys: 3.3.0 espree: 9.3.1 @@ -9619,7 +9671,7 @@ snapshots: vue-tsc@2.2.2(typescript@5.7.3): dependencies: - '@volar/typescript': 2.4.28 + '@volar/typescript': 2.4.28(typescript@5.7.3) '@vue/language-core': 2.2.2(typescript@5.7.3) typescript: 5.7.3 diff --git a/admin/src/api/file.ts b/admin/src/api/file.ts index 2d60dd2c1..9f81ff782 100644 --- a/admin/src/api/file.ts +++ b/admin/src/api/file.ts @@ -100,6 +100,7 @@ export interface OssCredentialsResponse { host?: string cdn_domain?: string key_prefix?: string + object_key?: string max_size?: number duration?: number expired_time?: number @@ -111,8 +112,10 @@ export interface OssCredentialsResponse { } } +export type OssDirectUploadType = 'video' | 'voice' | 'desktop_package' + /** 申请 STS 临时凭证 */ -export function getOssCredentials(params: { type: 'video' }) { +export function getOssCredentials(params: { type: OssDirectUploadType; name?: string }) { return request.post({ url: '/upload/ossCredentials', params @@ -121,7 +124,7 @@ export function getOssCredentials(params: { type: 'video' }) { /** 直传完成回执:写 file 表 + HEAD 校验 */ export function confirmOssUpload(params: { - type: 'video' + type: OssDirectUploadType key: string name: string size: number diff --git a/admin/src/api/first_visit.ts b/admin/src/api/first_visit.ts index 1ead7ef01..9660aa68d 100644 --- a/admin/src/api/first_visit.ts +++ b/admin/src/api/first_visit.ts @@ -168,11 +168,12 @@ export interface FirstVisitConversionFanDetailRow { wecom_userid: string wecom_staff_name: string add_time: string | null - is_deleted: boolean - delete_time: string | null + is_deleted?: boolean + delete_time?: string | null } -export interface FirstVisitConversionFansDetailResult { +export interface FirstVisitConversionFansDetailResult { + can_view_deleted_fans?: boolean lists?: FirstVisitConversionFanDetailRow[] rows?: FirstVisitConversionFanDetailRow[] total?: number @@ -237,11 +238,105 @@ export function wecomPromotionOverview() { export function wecomPromotionSavePool(params: Record) { return request.post({ url: '/firstvisit.wecomPromotion/savePool', params, timeout: 120000 }) } + +export interface WecomPromotionTagGroup { + group_id: string + group_name: string + tag: Array<{ id: string; name: string }> +} + +export function wecomPromotionTagOptions() { + return request.get<{ tag_groups: WecomPromotionTagGroup[] }>({ + url: '/firstvisit.wecomPromotion/tagOptions' + }) +} + +export function wecomPromotionCreateTag(params: { name: string }) { + return request.post<{ tag: { id: string; name: string }; group_id: string; group_name: string; reused: boolean }>({ + url: '/firstvisit.wecomPromotion/createTag', params, timeout: 30000 + }, { ignoreCancelToken: true }) +} + +export function wecomPromotionUploadWelcomeMedia(file: File, type: 'image' | 'video' | 'file') { + const data = new FormData() + data.append('file', file) + data.append('type', type) + return request.post<{ asset_id: string; name: string; type: string }>({ + url: '/firstvisit.wecomPromotion/uploadWelcomeMedia', + data, + headers: { 'Content-Type': 'multipart/form-data' }, + timeout: 120000 + }, { ignoreCancelToken: true }) +} -export function wecomPromotionSaveWidget(params: Record) { - return request.post({ url: '/firstvisit.wecomPromotion/saveWidget', params }) -} - +export function wecomPromotionSaveWidget(params: Record) { + return request.post({ url: '/firstvisit.wecomPromotion/saveWidget', params }) +} + +export interface WecomPromotionBatchSetOperatorsParams { + pool_ids: number[] + operator_admin_ids: number[] + action: 'grant' | 'revoke' +} + +export interface WecomPromotionBatchSetOperatorsResult { + action: 'grant' | 'revoke' + pool_ids: number[] + operator_admin_ids: number[] + affected: number +} + +export function wecomPromotionBatchSetOperators(params: WecomPromotionBatchSetOperatorsParams) { + return request.post({ + url: '/firstvisit.wecomPromotion/batchSetOperators', + params + }) +} + +export interface WecomPromotionBatchUpdatePoolsParams { + pool_ids: number[] + changes: { + skip_verify?: 0 | 1 + fallback_url?: string + status?: 0 | 1 + automation_config?: Record + member_status?: { + member_admin_ids: number[] + status: 0 | 1 + } + } +} + +export interface WecomPromotionBatchUpdatePoolResult { + id: number + name: string + success: boolean + sync_error?: string + sync_queued?: boolean + member_matched?: number + member_updated?: number + error?: string +} + +export interface WecomPromotionBatchUpdatePoolsResult { + pool_ids: number[] + updated: number + failed: number + sync_error_count: number + sync_queued_count: number + member_matched: number + member_updated: number + results: WecomPromotionBatchUpdatePoolResult[] +} + +export function wecomPromotionBatchUpdatePools(params: WecomPromotionBatchUpdatePoolsParams) { + return request.post({ + url: '/firstvisit.wecomPromotion/batchUpdatePools', + params, + timeout: 120000 + }, { ignoreCancelToken: true }) +} + export function wecomPromotionDeletePool(params: { id: number }) { return request.post({ url: '/firstvisit.wecomPromotion/deletePool', params, timeout: 120000 }) } diff --git a/admin/src/api/qywx.ts b/admin/src/api/qywx.ts index a07040532..4b93db64b 100644 --- a/admin/src/api/qywx.ts +++ b/admin/src/api/qywx.ts @@ -5,6 +5,11 @@ export function qywxCustomerLists(params: any) { return request.get({ url: '/qywx.customer/lists', params }) } +// 删除一条本地企业微信客户同步记录 +export function qywxCustomerDelete(params: { id: number }) { + return request.post({ url: '/qywx.customer/delete', params }) +} + // 同步企业微信客户 export function qywxCustomerSync() { return request.post({ url: '/qywx.customer/sync' }) diff --git a/admin/src/api/tcm.ts b/admin/src/api/tcm.ts index fb32bc976..4b5b9d99b 100644 --- a/admin/src/api/tcm.ts +++ b/admin/src/api/tcm.ts @@ -578,6 +578,11 @@ export function prescriptionOrderAddLog(params: { return request.post({ url: '/tcm.prescriptionOrder/addLog', params }) } +/** 移除单笔收款关联,总金额不变,同步更新已付金额和需代收 */ +export function prescriptionOrderUnlinkPayOrder(params: { id: number; pay_order_id: number }) { + return request.post({ url: '/tcm.prescriptionOrder/unlinkPayOrder', params }) +} + /** 修改订单金额 */ export function prescriptionOrderUpdateAmount(params: { id: number; amount: number }) { return request.post({ url: '/tcm.prescriptionOrder/updateAmount', params }) diff --git a/admin/src/components/upload/index.vue b/admin/src/components/upload/index.vue index eead4783d..98b3a5b62 100644 --- a/admin/src/components/upload/index.vue +++ b/admin/src/components/upload/index.vue @@ -51,8 +51,10 @@ import useAppStore from '@/stores/modules/app' import useUserStore from '@/stores/modules/user' import feedback from '@/utils/feedback' import { + DirectUploadApiError, DirectUploadFallbackError, - uploadVideoDirectToCos + uploadDirectToCos, + type DirectUploadType } from '@/utils/oss-direct-upload' export default defineComponent({ @@ -83,7 +85,7 @@ export default defineComponent({ type: Boolean, default: false }, - // 视频直传到 OSS(绕开服务器中转,仅 type=video 生效) + // 直传到对象存储,绕开服务器中转 direct: { type: Boolean, default: false @@ -102,8 +104,10 @@ export default defineComponent({ const visible = ref(false) const fileList = ref([]) - // 仅 video/voice + direct 时才接管 http-request - const useDirect = computed(() => props.direct && ['video', 'voice'].includes(props.type)) + const directTypes: DirectUploadType[] = ['video', 'voice', 'desktop_package'] + const useDirect = computed( + () => props.direct && directTypes.includes(props.type as DirectUploadType) + ) const handleProgress = () => { visible.value = true @@ -131,7 +135,10 @@ export default defineComponent({ fileList.value = [] emit('allSuccess') } - feedback.msgError(`${file.name}文件上传失败`) + if (!(event instanceof DirectUploadApiError)) { + const message = event instanceof Error ? event.message : '' + feedback.msgError(message || `${file.name}文件上传失败`) + } uploadRefs.value?.abort(file) visible.value = false emit('change', file) @@ -153,18 +160,20 @@ export default defineComponent({ return '.wmv,.avi,.mpg,.mpeg,.3gp,.mov,.mp4,.flv,.rmvb,.mkv' case 'voice': return '.mp3,.wav,.wma,.m4a,.aac,.amr' + case 'desktop_package': + return '.exe,.zip' default: return '*' } }) - // 走 COS 直传:成功时模拟老接口的响应 envelope,失败/降级时回到默认 XHR + // 走 COS 直传:成功时模拟老接口的响应 envelope const httpRequest = async (options: UploadRequestOptions) => { visible.value = true try { - const data = await uploadVideoDirectToCos({ + const data = await uploadDirectToCos({ file: options.file, - type: props.type as any, + type: props.type as DirectUploadType, cid: Number((options.data as any)?.cid ?? 0), onProgress(info) { // 触发 ElUpload 内部进度(保持与默认上传一致的体验) @@ -178,6 +187,12 @@ export default defineComponent({ ;(options as any).onSuccess?.({ code: RequestCodeEnum.SUCCESS, msg: 'ok', data }) } catch (err: any) { if (err instanceof DirectUploadFallbackError) { + if (props.type === 'desktop_package') { + ;(options as any).onError?.( + new Error('当前未启用腾讯云 COS,安装包无法直传,请配置 COS 后重试') + ) + return + } feedback.msgWarning('当前存储不支持直传,已切换为普通上传') await defaultXhrUpload(options) return diff --git a/admin/src/utils/oss-direct-upload.ts b/admin/src/utils/oss-direct-upload.ts index 90637d1f1..1cd284624 100644 --- a/admin/src/utils/oss-direct-upload.ts +++ b/admin/src/utils/oss-direct-upload.ts @@ -3,10 +3,11 @@ import COS from 'cos-js-sdk-v5' import { confirmOssUpload, getOssCredentials, - type OssCredentialsResponse + type OssCredentialsResponse, + type OssDirectUploadType } from '@/api/file' -export type DirectUploadType = 'video' +export type DirectUploadType = OssDirectUploadType export interface DirectUploadProgress { /** 0-100 */ @@ -37,8 +38,17 @@ export interface DirectUploadOptions { const SLICE_SIZE = 5 * 1024 * 1024 // 5MB const ASYNC_LIMIT = 3 +async function callDirectUploadApi(request: () => Promise): Promise { + try { + return await request() + } catch (error) { + // request 拦截器已经展示过接口/网络错误,上传组件只负责收口失败状态 + throw new DirectUploadApiError(error) + } +} + function buildKey(prefix: string, file: File): string { - const ext = (file.name.split('.').pop() || 'mp4').toLowerCase() + const ext = (file.name.split('.').pop() || 'bin').toLowerCase() const ts = Date.now() const rand = Math.random().toString(36).slice(2, 10) return `${prefix}${ts}-${rand}.${ext}` @@ -48,8 +58,13 @@ function buildKey(prefix: string, file: File): string { * 直传到腾讯云 COS(含 STS 凭证申请、分片上传、回执) * 不支持降级 / fallback=true 时抛错,由调用方决定走老链路。 */ -export async function uploadVideoDirectToCos(options: DirectUploadOptions): Promise { - const credentials: OssCredentialsResponse = await getOssCredentials({ type: options.type }) +export async function uploadDirectToCos(options: DirectUploadOptions): Promise { + const credentials: OssCredentialsResponse = await callDirectUploadApi(() => + getOssCredentials({ + type: options.type, + name: options.file.name + }) + ) if (credentials.fallback) { const handled = options.onFallback?.(credentials.provider) ?? false @@ -66,7 +81,7 @@ export async function uploadVideoDirectToCos(options: DirectUploadOptions): Prom if (credentials.max_size && options.file.size > credentials.max_size) { const mb = Math.round(credentials.max_size / 1024 / 1024) - throw new Error(`视频体积超出上限(${mb}MB)`) + throw new Error(`文件体积超出上限(${mb}MB)`) } const cred = credentials.credentials @@ -85,7 +100,7 @@ export async function uploadVideoDirectToCos(options: DirectUploadOptions): Prom } }) - const key = buildKey(credentials.key_prefix, options.file) + const key = credentials.object_key || buildKey(credentials.key_prefix, options.file) await new Promise((resolve, reject) => { cos.uploadFile( @@ -117,14 +132,16 @@ export async function uploadVideoDirectToCos(options: DirectUploadOptions): Prom ) }) - const confirmed = await confirmOssUpload({ - type: options.type, - key, - name: options.file.name, - size: options.file.size, - content_type: options.file.type || '', - cid: options.cid ?? 0 - }) + const confirmed = await callDirectUploadApi(() => + confirmOssUpload({ + type: options.type, + key, + name: options.file.name, + size: options.file.size, + content_type: options.file.type || '', + cid: options.cid ?? 0 + }) + ) options.onProgress?.({ percent: 100, loaded: options.file.size, total: options.file.size, speed: 0 }) @@ -140,3 +157,14 @@ export class DirectUploadFallbackError extends Error { this.provider = provider } } + +/** 请求层已经展示过错误,避免 ElUpload 再弹一条通用失败提示。 */ +export class DirectUploadApiError extends Error { + readonly originalError: unknown + + constructor(error: unknown) { + super('') + this.name = 'DirectUploadApiError' + this.originalError = error + } +} diff --git a/admin/src/views/consumer/prescription/components/PrescriptionOrderDetailDrawer.vue b/admin/src/views/consumer/prescription/components/PrescriptionOrderDetailDrawer.vue index 35c628472..d6a5e0b5a 100644 --- a/admin/src/views/consumer/prescription/components/PrescriptionOrderDetailDrawer.vue +++ b/admin/src/views/consumer/prescription/components/PrescriptionOrderDetailDrawer.vue @@ -541,6 +541,19 @@ {{ formatOrderTime(row.create_time) }} + + + @@ -1014,6 +1027,7 @@ import { prescriptionOrderLogisticsTrace, prescriptionOrderLogisticsJdUpdate, prescriptionOrderPaidPayOrders, + prescriptionOrderUnlinkPayOrder, prescriptionOrderPatchPrescriptionUsage } from '@/api/tcm' import { getDictData } from '@/api/app' @@ -1107,6 +1121,38 @@ const detailLoading = ref(false) const detailData = ref | null>(null) const detailLogs = ref([]) const detailUnlinkedPayOrders = ref([]) +const unlinkPayOrderId = ref(null) +const canUnlinkPayOrder = computed(() => + !props.readonly && canUpdateAmount(detailData.value) && hasPerm('tcm.prescriptionOrder/unlinkPayOrder') +) + +async function confirmUnlinkPayOrder(row: { id: number; order_no?: string; amount: number | string; status: number | string }) { + const orderId = Number(detailData.value?.id) + const payOrderId = Number(row.id) + if (!canUnlinkPayOrder.value || !orderId || !payOrderId || unlinkPayOrderId.value !== null) return + if (![2, 5].includes(Number(row.status))) return + + unlinkPayOrderId.value = payOrderId + try { + await feedback.confirm( + `确定移除收款记录「${row.order_no || '#' + payOrderId}」(¥${formatMoney(row.amount)})?` + + '仅解除关联,原收款记录保留;订单总金额不变,已付金额与需代收金额按剩余关联收款重新计算。' + ) + if (!detailVisible.value || Number(detailData.value?.id) !== orderId) return + const res: any = await prescriptionOrderUnlinkPayOrder({ id: orderId, pay_order_id: payOrderId }) + const updated = res?.data ?? res + if (Number(detailData.value?.id) === orderId && Number(updated?.id) === orderId) { + Object.assign(detailData.value!, updated) + } + feedback.msgSuccess('收款关联已移除,金额已同步更新') + emit('detail-changed') + await refreshIfCurrent(orderId) + } catch { + /* 取消不提交;接口错误由拦截器提示,保留当前收款记录 */ + } finally { + unlinkPayOrderId.value = null + } +} const detailPrescription = computed(() => { const p = detailData.value?.prescription diff --git a/admin/src/views/consumer/prescription/components/prescription-order-utils.ts b/admin/src/views/consumer/prescription/components/prescription-order-utils.ts index 7b9342690..e2ca64c0c 100644 --- a/admin/src/views/consumer/prescription/components/prescription-order-utils.ts +++ b/admin/src/views/consumer/prescription/components/prescription-order-utils.ts @@ -168,6 +168,7 @@ export function logActionText(act: string) { ship: '确认发货', withdraw: '撤销', link_pay_order: '关联支付单', + unlink_pay_order: '移除收款关联', completion_request: '完单申请', auto_complete: '自动完成', revoke_rx_audit: '撤回处方审核', diff --git a/admin/src/views/fans/qywx.vue b/admin/src/views/fans/qywx.vue index 657520ec8..f2b39c128 100644 --- a/admin/src/views/fans/qywx.vue +++ b/admin/src/views/fans/qywx.vue @@ -94,15 +94,32 @@ @keyup.enter="resetPage" /> - - + - - + @keyup.enter="resetPage" + /> + + + + + + + — + + + - + @@ -500,6 +553,21 @@ {{ formatTime(firstExternalAddTime(currentCustomer)) }} + + +
+ + + {{ source.label }} + + +
+ 未记录
{{ formatTime(currentCustomer.update_time) }} @@ -549,8 +617,9 @@ import { Refresh, Setting, DataLine, CollectionTag } from '@element-plus/icons-v import { usePaging } from '@/hooks/usePaging' import feedback from '@/utils/feedback' import { - qywxCustomerLists, - qywxCustomerSync, + qywxCustomerLists, + qywxCustomerDelete, + qywxCustomerSync, qywxCustomerStats, qywxSyncSettingsGet, qywxSyncSettingsSave, @@ -563,6 +632,7 @@ const syncing = ref(false) const showSyncSettings = ref(false) const showDetail = ref(false) const currentCustomer = ref(null) +const deletingCustomerId = ref(null) const stats = reactive({ total: 0, @@ -591,17 +661,19 @@ const syncSettings = reactive({ interval: 3600 }) -const queryParams = reactive<{ - name: string - follow_user: string - tag_ids: string[] +const queryParams = reactive<{ + name: string + follow_user: string + add_way: number | '' + tag_ids: string[] add_time_start: string add_time_end: string dedupe_mode: 'first' | 'any' }>({ - name: '', - follow_user: '', - tag_ids: [], + name: '', + follow_user: '', + add_way: '', + tag_ids: [], add_time_start: '', add_time_end: '', dedupe_mode: 'first' @@ -639,6 +711,22 @@ interface TagStatsPayload { groups: TagGroup[] } +interface AddChannel { + state: string + label: string + source_type: 'promotion_pool' | 'state' + pool_id: number + user_id: string + event_time: number +} + +interface AddSource extends AddChannel { + key: string + add_way: number | null + channel_label: string + staff_name: string +} + const tagStats = reactive({ total_tags: 0, total_relations: 0, @@ -847,10 +935,11 @@ const { pager, getLists, resetPage, resetParams } = usePaging({ params: queryParams }) -function handleReset() { - queryParams.name = '' - queryParams.follow_user = '' - queryParams.tag_ids = [] +function handleReset() { + queryParams.name = '' + queryParams.follow_user = '' + queryParams.add_way = '' + queryParams.tag_ids = [] queryParams.add_time_start = '' queryParams.add_time_end = '' queryParams.dedupe_mode = 'first' @@ -964,6 +1053,34 @@ function viewDetail(row: any) { showDetail.value = true } +async function handleDelete(row: Record) { + const id = Number(row.id) + if (!Number.isInteger(id) || id <= 0 || deletingCustomerId.value !== null) return + + const customerName = String(row.name || row.external_userid || '该客户') + try { + await feedback.confirm( + `确定删除企业微信客户“${customerName}”吗?此操作仅删除系统内的同步记录,不会删除企业微信中的客户关系;后续重新同步时可能再次出现。` + ) + } catch { + return + } + + deletingCustomerId.value = id + try { + await qywxCustomerDelete({ id }) + if (pager.page > 1 && pager.lists.length === 1) { + pager.page -= 1 + } + await Promise.all([getLists(), loadStats(), loadTagStats()]) + feedback.msgSuccess('删除成功') + } catch (e: any) { + feedback.msgError(e?.message || e?.msg || '删除失败') + } finally { + deletingCustomerId.value = null + } +} + /** 列表接口会写入 admin_name(admin.work_wechat_userid = userid) */ function formatFollowUser(user: Record) { const adminName = String(user?.admin_name ?? '').trim() @@ -985,6 +1102,167 @@ function followStaffTooltip(user: Record) { return parts.join('|') } +function customerAddChannels(row: Record | null | undefined): AddChannel[] { + if (!row) return [] + if (Array.isArray(row.add_channels)) { + return row.add_channels + .map((channel: Record): AddChannel => ({ + state: String(channel?.state ?? '').trim(), + label: String(channel?.label ?? channel?.state ?? '').trim(), + source_type: channel?.source_type === 'promotion_pool' ? 'promotion_pool' : 'state', + pool_id: Number(channel?.pool_id ?? 0), + user_id: String(channel?.user_id ?? '').trim(), + event_time: Number(channel?.event_time ?? 0) + })) + .filter((channel: AddChannel) => channel.state !== '') + } + + // 兼容仅返回原始渠道数组的旧接口/灰度节点。 + if (!Array.isArray(row.add_channel_states)) return [] + return row.add_channel_states + .map((state: unknown) => String(state ?? '').trim()) + .filter((state: string) => state !== '') + .map((state: string) => ({ + state, + label: state, + source_type: 'state' as const, + pool_id: 0, + user_id: '', + event_time: 0 + })) +} + +const ADD_WAY_LABELS: Record = { + 0: '未知添加方式', + 1: '通过扫描二维码添加', + 2: '通过搜索手机号添加', + 3: '通过名片分享添加', + 4: '通过群聊添加', + 5: '通过手机通讯录添加', + 6: '通过微信联系人添加', + 8: '安装第三方应用时自动添加', + 9: '通过搜索邮箱添加', + 10: '通过视频号添加', + 11: '通过日程参与人添加', + 12: '通过会议参与人添加', + 13: '通过微信好友添加', + 14: '通过智慧硬件专属客服添加', + 15: '通过上门服务客服添加', + 16: '通过获客链接添加', + 17: '通过定制开发添加', + 18: '通过需求回复添加', + 21: '通过第三方售前客服添加', + 22: '通过可能的商务伙伴添加', + 24: '通过接受微信好友申请添加', + 201: '通过内部成员共享添加', + 202: '通过管理员或负责人分配添加' +} + +const ADD_WAY_OPTIONS = Object.entries(ADD_WAY_LABELS).map(([value, label]) => ({ + value: Number(value), + label +})) + +function normalizeAddWay(value: unknown): number | null { + if (typeof value === 'number' && Number.isInteger(value) && value >= 0) return value + if (typeof value !== 'string' || !/^\d+$/.test(value.trim())) return null + return Number(value.trim()) +} + +function addWayLabel(addWay: number) { + return ADD_WAY_LABELS[addWay] || `其他添加方式(${addWay})` +} + +function customerAddSources(row: Record | null | undefined): AddSource[] { + if (!row) return [] + + const channels = customerAddChannels(row) + const usedChannelIndexes = new Set() + const sources: AddSource[] = [] + const followUsers = Array.isArray(row.follow_users) ? row.follow_users : [] + + followUsers.forEach((user: Record, index: number) => { + const userId = String(user?.userid ?? user?.UserId ?? '').trim() + const state = String(user?.state ?? user?.State ?? '').trim() + const addWay = normalizeAddWay(user?.add_way ?? user?.AddWay) + + let channelIndex = channels.findIndex( + (channel, i) => + !usedChannelIndexes.has(i) && + userId !== '' && + state !== '' && + channel.user_id === userId && + channel.state === state + ) + if (channelIndex < 0 && state !== '') { + channelIndex = channels.findIndex( + (channel, i) => !usedChannelIndexes.has(i) && channel.state === state + ) + } + if (channelIndex < 0 && userId !== '') { + channelIndex = channels.findIndex( + (channel, i) => !usedChannelIndexes.has(i) && channel.user_id === userId + ) + } + + const channel = channelIndex >= 0 ? channels[channelIndex] : undefined + if (channelIndex >= 0) usedChannelIndexes.add(channelIndex) + if (addWay === null && state === '' && !channel) return + + const labelFromApi = String(user?.add_way_label ?? '').trim() + const sourceType = channel?.source_type ?? (/^zyt_pool:[1-9]\d*$/.test(state) ? 'promotion_pool' : 'state') + const label = labelFromApi || (addWay !== null + ? addWayLabel(addWay) + : sourceType === 'promotion_pool' + ? '通过获客链接添加' + : '通过其他渠道添加') + + sources.push({ + key: `follow:${index}:${userId}:${addWay ?? 'unknown'}:${state}`, + add_way: addWay, + label, + state: state || channel?.state || '', + channel_label: channel?.label || '', + source_type: sourceType, + pool_id: channel?.pool_id || 0, + user_id: userId || channel?.user_id || '', + staff_name: formatFollowUser(user), + event_time: channel?.event_time || Number(user?.createtime ?? 0) + }) + }) + + // 兼容事件日志中仍有记录、但当前 follow_users 已不存在或旧接口未返回 add_way 的客户。 + channels.forEach((channel, index) => { + if (usedChannelIndexes.has(index)) return + sources.push({ + ...channel, + key: `channel:${index}:${channel.user_id}:${channel.state}`, + add_way: channel.source_type === 'promotion_pool' ? 16 : null, + label: channel.source_type === 'promotion_pool' ? '通过获客链接添加' : '通过其他渠道添加', + channel_label: channel.label, + staff_name: channel.user_id || '—' + }) + }) + + return sources.sort((a, b) => b.event_time - a.event_time) +} + +function addSourceTooltip(source: AddSource) { + const parts: string[] = [] + parts.push(`添加方式:${source.label}`) + if (source.source_type === 'promotion_pool' && source.channel_label) { + parts.push(`获客助手方案:${source.channel_label}`) + } + if (source.staff_name && source.staff_name !== '—') parts.push(`跟进人:${source.staff_name}`) + if (source.event_time > 0) parts.push(`添加时间:${formatTime(source.event_time)}`) + if (source.state) parts.push(`渠道参数:${source.state}`) + return parts.join('|') +} + +function remainingAddSourcesTooltip(row: Record) { + return customerAddSources(row).slice(1).map(addSourceTooltip).join('\n') +} + /** * 添加时间:优先接口字段 external_first_add_time(同步写入 + 列表对未回填行按 JSON 兜底); * 再解析 follow_users;最后退回 create_time diff --git a/admin/src/views/first_visit/conversion/index.vue b/admin/src/views/first_visit/conversion/index.vue index 33477569b..9d52ac22c 100644 --- a/admin/src/views/first_visit/conversion/index.vue +++ b/admin/src/views/first_visit/conversion/index.vue @@ -108,7 +108,7 @@ (-{{ formatNumber(dashboard.summary.deleted_fans_count) }}) - {{ metric.hint }} + {{ metric.hint }} @@ -154,7 +154,7 @@

明细数据列表

-

展开部门可查看人员明细;加粉=总进线=区间新增加粉(按员工+客户去重,包含区间内添加后已删客户,剔除继承客户、扫一扫/搜手机号/名片分享添加及区间前已加过的重加),(-N)表示加粉总数中已删除;挂号=已支付且实收低于 10 元的订单,预约=有效预约记录;开口率=开口/加粉,挂号率=挂号/加粉,面诊率=面诊/挂号(看挂号后流失),预约率=面诊/预约(看预约后未面诊),面诊接诊率=接诊诊单/面诊,接诊率=接诊诊单/总进线

+

展开部门可查看人员明细;加粉=总进线=区间新增“员工+客户”组合(同一员工的同一客户只计一次,同一客户进入不同员工分别计数;包含区间内添加后已删客户,剔除继承客户、扫一扫/搜手机号/名片分享添加及区间前已存在的相同组合);挂号=已支付且实收低于 10 元的订单,预约=有效预约记录;开口率=开口/加粉,挂号率=挂号/加粉,面诊率=面诊/挂号(看挂号后流失),预约率=面诊/预约(看预约后未面诊),面诊接诊率=接诊诊单/面诊,接诊率=接诊诊单/总进线

{{ dashboard.rows.length }} 个顶层节点
@@ -193,7 +193,7 @@ v-if="hasFans(row.add_fans_count)" type="button" class="fan-count-value fan-detail-trigger fan-detail-trigger--table" - title="查看该行加粉客户明细" + title="查看该行加粉组合明细" @click.stop="openFansDetail(row)" > {{ formatNumber(row.add_fans_count) }} @@ -339,7 +339,7 @@ - + @@ -403,7 +403,7 @@ const emptyDashboard = () => ({ time_type: 'today', time_label: '今日', start_date: '', end_date: '', generated_at: '', scope_value: 4, scope_label: '', selected_dept_name: '', selected_assistant_name: '', selected_media_channel_code: '', selected_media_channel_name: '', open_count_source: '', ranking_kind: 'hidden', - can_view_finance: false + can_view_finance: false, can_view_deleted_fans: false }, filters: { departments: [] as any[], @@ -431,6 +431,7 @@ const query = reactive({ const customDateRange = ref([]) const fansDetailVisible = ref(false) const fansDetailLoading = ref(false) +const fansDetailCanViewDeletedFans = ref(false) const fansDetailRows = ref([]) const fansDetailPager = reactive({ page_no: 1, page_size: 20, total: 0 }) const fansDetailEntity = ref<{ type: 'dept' | 'member'; id: string | number; adminId?: number; name: string }>({ @@ -447,7 +448,7 @@ const timeOptions = [ { label: '自定义', value: 'custom' } ] const metricCards: Array<{ key: string; label: string; type: MetricType; hint: string }> = [ - { key: 'add_fans_count', label: '加粉数', type: 'count', hint: '区间新增加粉(含已删除);(-N)为其中已删除' }, + { key: 'add_fans_count', label: '加粉数', type: 'count', hint: '区间新增员工+客户组合(不同员工分别计数,含已删除)' }, { key: 'total_open_count', label: '开口数', type: 'count', hint: '来源于个人业绩录入' }, { key: 'interview_count', label: '面诊', type: 'count', hint: '已完成预约' }, { key: 'completed_order_count', label: '接诊诊单', type: 'count', hint: '业务订单,按创建人归属并过滤无效单' }, @@ -465,6 +466,9 @@ const scopeDescription = computed(() => { return parts.join(' · ') }) const canViewFinance = computed(() => Boolean(dashboard.meta.can_view_finance)) +// 仅服务端按登录账号精确判定为admin时放行;缺失、字符串或角色权限均不能兜底放行。 +const canViewDeletedFans = computed(() => dashboard.meta.can_view_deleted_fans === true) +const canViewDeletedFansDetail = computed(() => canViewDeletedFans.value && fansDetailCanViewDeletedFans.value) const visibleMetricCards = computed(() => canViewFinance.value ? metricCards @@ -514,7 +518,7 @@ const rankingKind = computed(() => dashboard.meta.ranking_kind || ( )) const showRankings = computed(() => rankingKind.value !== 'hidden') const rankingSubject = computed(() => rankingKind.value === 'member' ? '组内成员' : '小组') -const fansDetailTitle = computed(() => `${fansDetailEntity.value.name} · 加粉客户明细`) +const fansDetailTitle = computed(() => `${fansDetailEntity.value.name} · 加粉组合明细`) const detailRangeText = computed(() => { const startDate = dashboard.meta.start_date || query.start_date || '' const endDate = dashboard.meta.end_date || query.end_date || '' @@ -542,6 +546,7 @@ let latestFansDetailRequestId = 0 async function loadDashboard() { const requestId = ++latestDashboardRequestId loading.value = true + dashboard.meta.can_view_deleted_fans = false try { const params: FirstVisitConversionParams = { ...query } if (params.time_type === 'custom') { @@ -608,6 +613,7 @@ async function loadFansDetail() { if (!fansDetailVisible.value) return const requestId = ++latestFansDetailRequestId fansDetailLoading.value = true + fansDetailCanViewDeletedFans.value = false try { const params: FirstVisitConversionFansDetailParams = { ...query, @@ -623,6 +629,7 @@ async function loadFansDetail() { } const result = await firstVisitConversionFansDetail(params) as FirstVisitConversionFansDetailResult if (requestId !== latestFansDetailRequestId) return + fansDetailCanViewDeletedFans.value = result?.can_view_deleted_fans === true const rows = Array.isArray(result?.lists) ? result.lists : (Array.isArray(result?.rows) ? result.rows : []) fansDetailRows.value = rows fansDetailPager.total = Number(result?.count ?? result?.total ?? rows.length) || 0 @@ -630,7 +637,7 @@ async function loadFansDetail() { if (requestId !== latestFansDetailRequestId) return fansDetailRows.value = [] fansDetailPager.total = 0 - ElMessage.error(error?.message || '加粉客户明细加载失败') + ElMessage.error(error?.message || '加粉组合明细加载失败') } finally { if (requestId === latestFansDetailRequestId) fansDetailLoading.value = false } @@ -644,6 +651,7 @@ function handleFansDetailSizeChange() { function resetFansDetail() { ++latestFansDetailRequestId fansDetailLoading.value = false + fansDetailCanViewDeletedFans.value = false fansDetailRows.value = [] fansDetailPager.page_no = 1 fansDetailPager.total = 0 @@ -654,7 +662,7 @@ function hasFans(value: any) { } function isDeletedFan(row: FirstVisitConversionFanDetailRow) { - return Boolean(row.is_deleted) + return canViewDeletedFansDetail.value && Boolean(row.is_deleted) } function fanCustomerName(row: FirstVisitConversionFanDetailRow) { @@ -685,7 +693,7 @@ function formatNumber(value: any) { } function hasDeletedFans(value: any) { - return Math.round(Number(value || 0)) > 0 + return canViewDeletedFans.value && Math.round(Number(value || 0)) > 0 } function formatMoney(value: any) { diff --git a/admin/src/views/first_visit/wecom_promotion/components/PromotionAutomationForm.vue b/admin/src/views/first_visit/wecom_promotion/components/PromotionAutomationForm.vue new file mode 100644 index 000000000..af05c1f9b --- /dev/null +++ b/admin/src/views/first_visit/wecom_promotion/components/PromotionAutomationForm.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/admin/src/views/first_visit/wecom_promotion/components/WelcomeMessageEditor.vue b/admin/src/views/first_visit/wecom_promotion/components/WelcomeMessageEditor.vue new file mode 100644 index 000000000..dd3617fd5 --- /dev/null +++ b/admin/src/views/first_visit/wecom_promotion/components/WelcomeMessageEditor.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/admin/src/views/first_visit/wecom_promotion/components/promotion-automation.ts b/admin/src/views/first_visit/wecom_promotion/components/promotion-automation.ts new file mode 100644 index 000000000..daff63b42 --- /dev/null +++ b/admin/src/views/first_visit/wecom_promotion/components/promotion-automation.ts @@ -0,0 +1,214 @@ +export interface PromotionMemberChoice { + id: number + name: string + userid: string + dept_names: string[] +} + +export type WelcomeAttachment = + | { msgtype: 'image'; image: { asset_id?: string; pic_url?: string } } + | { msgtype: 'video'; video: { asset_id: string } } + | { msgtype: 'file'; file: { asset_id: string } } + | { msgtype: 'link'; link: { title: string; url: string; desc: string; picurl?: string } } + | { msgtype: 'miniprogram'; miniprogram: { title: string; appid: string; page: string; pic_asset_id: string } } + +export interface WelcomeMessage { + text: string + attachments: WelcomeAttachment[] +} + +export interface WeeklySlot { + weekdays: number[] + start: string + end: string +} + +export interface ReceptionSlot extends WeeklySlot { + member_admin_ids: number[] +} + +export interface WelcomeSlot extends WeeklySlot, WelcomeMessage {} + +export interface PromotionAutomationConfig { + reception_mode: 'always' | 'scheduled' + reception_schedule: ReceptionSlot[] + backup_member_admin_ids: number[] + tags_enabled: boolean + tag_ids: string[] + remark_enabled: boolean + remark_template: string + description_enabled: boolean + description: string + welcome_mode: 'default' | 'channel' | 'none' + welcome: WelcomeMessage + welcome_schedule_enabled: boolean + welcome_schedule: WelcomeSlot[] +} + +export type PromotionAutomationSaveConfig = Omit & { + tags_enabled: 0 | 1 + remark_enabled: 0 | 1 + description_enabled: 0 | 1 + welcome_schedule_enabled: 0 | 1 + } + +export const weekdays = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'] +export const templateTokens = [ + { label: '客户昵称', value: '{customer_name}' }, + { label: '员工昵称', value: '{employee_name}' }, + { label: '添加时间', value: '{add_time}' } +] + +export const utf8Length = (value: string): number => new TextEncoder().encode(value).length + +export function validateCustomTagName(value: string): string { + if (!value.trim()) return '请输入自定义标签名称' + if (/[\p{C}\u2028\u2029]/u.test(value)) return '标签名称不能包含换行、控制字符或不可见格式字符' + if (Array.from(value.trim()).length > 30) return '标签名称最多 30 个字符' + return '' +} + +export function defaultAutomationConfig(): PromotionAutomationConfig { + return { + reception_mode: 'always', reception_schedule: [], backup_member_admin_ids: [], + tags_enabled: false, tag_ids: [], remark_enabled: false, remark_template: '{customer_name}', + description_enabled: false, description: '', welcome_mode: 'default', + welcome: { text: '', attachments: [] }, welcome_schedule_enabled: false, welcome_schedule: [] + } +} + +// Only copy the editable contract. Server-resolved userids never come back in a save payload. +export function cloneAutomationConfig(source?: Partial | null): PromotionAutomationConfig { + const defaults = defaultAutomationConfig() + if (!source) return defaults + const copy = JSON.parse(JSON.stringify(source)) as PromotionAutomationConfig + return { + reception_mode: copy.reception_mode === 'scheduled' ? 'scheduled' : 'always', + reception_schedule: (copy.reception_schedule || []).map(({ weekdays, start, end, member_admin_ids }) => ({ + weekdays: [...weekdays], start, end, member_admin_ids: member_admin_ids.map(Number) + })), + backup_member_admin_ids: (copy.backup_member_admin_ids || []).map(Number), + tags_enabled: Boolean(copy.tags_enabled), tag_ids: [...(copy.tag_ids || [])], + remark_enabled: Boolean(copy.remark_enabled), remark_template: copy.remark_template ?? defaults.remark_template, + description_enabled: Boolean(copy.description_enabled), description: copy.description || '', + welcome_mode: copy.welcome_mode || 'default', + welcome: { text: copy.welcome?.text || '', attachments: copy.welcome?.attachments || [] }, + welcome_schedule_enabled: Boolean(copy.welcome_schedule_enabled), + welcome_schedule: (copy.welcome_schedule || []).map(({ weekdays, start, end, text, attachments }) => ({ + weekdays: [...weekdays], start, end, text: text || '', attachments: attachments || [] + })) + } +} + +/** Keep the save payload compatible with backends and transports that use 0/1 switches. */ +export function serializeAutomationConfig(config: PromotionAutomationConfig): PromotionAutomationSaveConfig { + return { + ...config, + tags_enabled: config.tags_enabled ? 1 : 0, + remark_enabled: config.remark_enabled ? 1 : 0, + description_enabled: config.description_enabled ? 1 : 0, + welcome_schedule_enabled: config.welcome_schedule_enabled ? 1 : 0 + } +} + +export function previewTemplate(template: string, employee = '小陈', limit?: number): string { + const date = new Intl.DateTimeFormat('en-CA', { + timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit', day: '2-digit' + }).format(new Date()) + const text = template.replace(/\{(customer_name|employee_name|add_time)\}/g, (token) => ({ + '{customer_name}': '张女士', '{employee_name}': employee, '{add_time}': date + }[token] || token)) + return limit ? Array.from(text).slice(0, limit).join('') : text +} + +export function isWebUrl(value: string): boolean { + try { return ['https:', 'http:'].includes(new URL(value).protocol) } catch { return false } +} + +function validateSlot(slot: WeeklySlot, label: string): string { + if (!slot.weekdays.length || slot.weekdays.some((day) => day < 1 || day > 7)) return `${label}请选择星期` + if (!/^(?:[01]\d|2[0-3]):[0-5]\d$/.test(slot.start) || !/^(?:[01]\d|2[0-3]):[0-5]\d$/.test(slot.end)) return `${label}请填写有效的起止时间` + if (slot.start === slot.end) return `${label}开始与结束时间不能相同,全天接待请选择全天模式` + return '' +} + +export function validateWelcomeMessage(message: WelcomeMessage, label: string, required = true): string { + if (Array.from(message.text).length > 1200) return `${label}正文不能超过 1200 字` + if (utf8Length(message.text) > 4000) return `${label}正文不能超过 4000 UTF-8 字节,请减少表情或文字` + if (message.attachments.length > 9) return `${label}最多添加 9 个附件` + if (required && !message.text.trim() && !message.attachments.length) return `${label}请填写正文或添加附件` + for (const [index, attachment] of message.attachments.entries()) { + const prefix = `${label}第 ${index + 1} 个附件:` + switch (attachment.msgtype) { + case 'image': + if (!attachment.image.asset_id && !isWebUrl(attachment.image.pic_url || '')) return prefix + '请上传图片或填写有效图片地址' + break + case 'video': + if (!attachment.video.asset_id) return prefix + '请先上传视频' + break + case 'file': + if (!attachment.file.asset_id) return prefix + '请先上传文件' + break + case 'link': + if (!attachment.link.title.trim() || !isWebUrl(attachment.link.url)) return prefix + '请填写网页标题和有效的 HTTP/HTTPS 链接' + if (utf8Length(attachment.link.title) > 128 || utf8Length(attachment.link.desc) > 512) return prefix + '网页标题限 128 字节,描述限 512 字节' + if (attachment.link.picurl && !isWebUrl(attachment.link.picurl)) return prefix + '网页封面地址无效' + break + case 'miniprogram': + if (!attachment.miniprogram.title.trim() || !attachment.miniprogram.appid.trim() || !attachment.miniprogram.page.trim() || !attachment.miniprogram.pic_asset_id) return prefix + '请填写小程序标题、AppID、页面路径并上传封面' + if (utf8Length(attachment.miniprogram.title) > 64) return prefix + '小程序标题不能超过 64 字节' + break + } + } + return '' +} + +/** Weekly minute occupancy also catches Sunday-to-Monday and overnight overlap. */ +export function welcomeScheduleOverlap(slots: WeeklySlot[]): boolean { + const minutes = new Set() + for (const slot of slots) { + const [sh, sm] = slot.start.split(':').map(Number) + const [eh, em] = slot.end.split(':').map(Number) + const start = sh * 60 + sm + const duration = (eh * 60 + em - start + 1440) % 1440 + for (const day of new Set(slot.weekdays)) { + for (let offset = 0; offset < duration; offset++) { + const minute = ((day - 1) * 1440 + start + offset) % 10080 + if (minutes.has(minute)) return true + minutes.add(minute) + } + } + } + return false +} + +export function validateAutomationConfig(config: PromotionAutomationConfig, mainMemberIds: number[]): string { + if (config.backup_member_admin_ids.some((id) => mainMemberIds.includes(id))) return '备用成员不能与主接待成员重复' + if (config.reception_schedule.length > 30 || config.welcome_schedule.length > 30) return '每类时段最多添加 30 条' + if (config.reception_mode === 'scheduled') { + if (!config.reception_schedule.length) return '按时段接待至少需要一个接待时段' + if (!config.backup_member_admin_ids.length) return '按时段接待至少需要一名备用成员,以承接非接待时段的客户' + } + for (const [index, slot] of config.reception_schedule.entries()) { + const error = validateSlot(slot, `接待时段 ${index + 1}:`) + if (error) return error + if (!slot.member_admin_ids.length) return `接待时段 ${index + 1}:请至少选择一名成员` + if (slot.member_admin_ids.some((id) => !mainMemberIds.includes(id))) return `接待时段 ${index + 1}:成员必须来自主接待成员,请重新选择` + } + if (config.tags_enabled && !config.tag_ids.length) return '启用客户标签后,请选择一个企业微信标签,或创建自定义标签' + if (config.tag_ids.length > 1) return '客户标签只能选择一个,请重新选择或清空原标签' + if (config.remark_enabled && !config.remark_template.trim()) return '请填写客户备注模板' + if (Array.from(config.remark_template).length > 200) return '客户备注模板不能超过 200 字' + if (config.description_enabled && !config.description.trim()) return '请填写客户描述' + if (Array.from(config.description).length > 150) return '客户描述不能超过 150 字' + const error = validateWelcomeMessage(config.welcome, '基础渠道欢迎语:', config.welcome_mode === 'channel') + if (error) return error + if (config.welcome_mode === 'channel' && config.welcome_schedule_enabled && !config.welcome_schedule.length) return '请至少添加一个分时欢迎语时段' + for (const [index, slot] of config.welcome_schedule.entries()) { + const error = validateSlot(slot, `欢迎语时段 ${index + 1}:`) || validateWelcomeMessage(slot, `欢迎语时段 ${index + 1}:`) + if (error) return error + } + if (welcomeScheduleOverlap(config.welcome_schedule)) return '分时欢迎语的时间范围不能重叠(跨午夜时段归属开始日)' + return '' +} diff --git a/admin/src/views/first_visit/wecom_promotion/index.vue b/admin/src/views/first_visit/wecom_promotion/index.vue index 62f7227f3..3d25de80a 100644 --- a/admin/src/views/first_visit/wecom_promotion/index.vue +++ b/admin/src/views/first_visit/wecom_promotion/index.vue @@ -51,28 +51,66 @@ 创建第一个方案 @@ -343,14 +382,18 @@ - +
+ + - + 新生成的官方直链不经过本站跳转;此项仅兼容旧安装代码。 + + - +
+ +
+ + +
+ + + +
+ 已选方案 + {{ pool.name }} + 另有 {{ batchConfigPools.length - 8 }} 个 +
+ + +
+

基础设置

+
+
+ 批量修改验证方式 + + + +
+
+ 批量修改运行状态 + + + +
+
+
+ 批量修改兜底获客助手链接 + + + 新生成的官方直链不经过本站跳转;此项仅兼容旧安装代码。 + +
+
+ +
+

员工上下线

+

所选员工会在其已加入的所选方案中统一上线或下线;不属于某个方案的员工不会被加入该方案。为保证方案级原子提交,员工上下线需单独批量保存。

+
+ 批量修改员工上线状态 +
+ + + 批量上线 + 批量下线 + + + + + + + 勾选部门可全选其下员工;已选 {{ batchConfigForm.member_admin_ids.length }} 名。 + +
+ +
+
+ +
+

自动化设置

+

先选择要覆盖的分组。未选择的接待、客户或欢迎语设置不会随本次批量操作改变。

+
+ 批量修改接待设置 + 批量修改客户设置 + 批量修改欢迎语设置 +
+ + +
+ +
+
+ +
+ + + + + + + 添加操作人 + 移除操作人 + + 批量添加不会覆盖各方案已有操作人;批量移除只撤销本次选中的账号。 + + + + + + 添加时可选择当前管理范围内的启用账号;授权后账号会自动获得本页面入口,且只能访问已授权方案。 + +
+ 当前授权 +
+ {{ pool.name }} + {{ operatorNames(pool) }} +
+

另有 {{ accessDialogPools.length - 5 }} 个方案

+
+
+
@@ -424,6 +685,8 @@ import { Promotion, Refresh, Search, SetUp, User, Warning } from '@element-plus/icons-vue' import { + wecomPromotionBatchSetOperators, + wecomPromotionBatchUpdatePools, wecomPromotionCheckApiPermission, wecomPromotionCustomerStats, wecomPromotionDeletePool, @@ -435,9 +698,13 @@ import { } from '@/api/first_visit' import type { WecomPromotionCustomerChatStatus } from '@/api/first_visit' -import WecomFloatingWidgetBuilder from './components/WecomFloatingWidgetBuilder.vue' - +import WecomFloatingWidgetBuilder from './components/WecomFloatingWidgetBuilder.vue' +import PromotionAutomationForm from './components/PromotionAutomationForm.vue' +import { cloneAutomationConfig, defaultAutomationConfig, isWebUrl, serializeAutomationConfig, validateAutomationConfig } from './components/promotion-automation' +import type { PromotionAutomationConfig } from './components/promotion-automation' + type TabName = 'links' | 'customer-stats' | 'configuration' | 'install' +type BatchAutomationSection = 'reception' | 'customer' | 'welcome' interface PromotionDepartmentOption { id: number | string @@ -454,6 +721,22 @@ interface PromotionMemberOption { dept_names: string[] } +interface BatchMemberStatusOption extends PromotionMemberOption { + pool_count: number + online_count: number + offline_count: number +} + +interface PromotionOperatorOption { + id: number + name: string + disable: number + can_grant: boolean + display_dept_id?: number + dept_ids: number[] + dept_names: string[] +} + interface PromotionMemberTreeNode { value: number | string label: string @@ -466,13 +749,15 @@ interface PromotionMemberTreeNode { } const emptyOverview = () => ({ - meta: { scope_label: '', generated_at: '' }, + meta: { admin_id: 0, scope_label: '', generated_at: '' }, config: { mode: 'internal', configured: false, ready: false, missing: [] as string[], corp_id_masked: '', agent_id: '', secret_configured: false, callback_ready: false, callback_url: '', official_doc: '' }, summary: { configured_apps: 0, pool_count: 0, online_links: 0, today_clicks: 0 }, pools: [] as any[], links: [] as any[], member_options: [] as PromotionMemberOption[], + operator_options: [] as PromotionOperatorOption[], department_options: [] as PromotionDepartmentOption[], + automation_installed: false, customer_acquisition_link_example: 'https://work.weixin.qq.com/ca/xxxxxxxx' }) @@ -481,6 +766,7 @@ const loading = ref(false) const activeTab = ref('links') const selectedPoolId = ref() const selectedInstallPoolId = ref() +const selectedPoolIds = ref([]) const poolDialogVisible = ref(false) const savingPool = ref(false) const checkingApi = ref(false) @@ -488,7 +774,20 @@ const memberDialogVisible = ref(false) const savingMember = ref(false) const togglingMemberId = ref(0) const deletingPoolId = ref(0) -const poolForm = reactive({ id: 0, name: '', fallback_url: '', status: 1, member_admin_ids: [] as number[], skip_verify: 0, main_url: '' }) +const accessDialogVisible = ref(false) +const savingAccess = ref(false) +const batchConfigDialogVisible = ref(false) +const savingBatchConfig = ref(false) +const batchConfigBusy = ref(false) +const batchConfigScroll = ref() +const batchConfigError = ref('') +const poolForm = reactive({ id: 0, name: '', fallback_url: '', status: 1, member_admin_ids: [] as number[], skip_verify: 0, main_url: '', automation_config: defaultAutomationConfig() }) +const poolFormScroll = ref() +const poolFormError = ref('') +const automationBusy = ref(false) +const accessForm = reactive({ pool_ids: [] as number[], operator_admin_ids: [] as number[], action: 'grant' as 'grant' | 'revoke' }) +const batchConfigApply = reactive({ skip_verify: false, fallback_url: false, status: false, member_status: false, reception: false, customer: false, welcome: false }) +const batchConfigForm = reactive({ pool_ids: [] as number[], skip_verify: 0, fallback_url: '', status: 1, member_admin_ids: [] as number[], member_status: 1 as 0 | 1, automation_config: defaultAutomationConfig() }) const memberForm = reactive({ id: 0, name: '', userid: '', daily_limit: 0, status: 1, active_range: [] as string[], remark: '' }) const customerStatsLoading = ref(false) const customerStatsLoaded = ref(false) @@ -510,6 +809,98 @@ const customerStats = reactive({ const selectedPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedPoolId.value)) const selectedMemberRules = computed(() => Array.isArray(selectedPool.value?.member_rules) ? selectedPool.value.member_rules : []) const selectedInstallPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedInstallPoolId.value)) +const accessDialogPools = computed(() => overview.pools.filter((item: any) => accessForm.pool_ids.includes(Number(item.id)))) +const manageablePoolIds = computed(() => overview.pools + .filter((pool: any) => pool.can_manage_access) + .map((pool: any) => Number(pool.id))) +const selectedManageablePoolCount = computed(() => { + const selected = new Set(selectedPoolIds.value) + return manageablePoolIds.value.filter((id) => selected.has(id)).length +}) +const allManageablePoolsSelected = computed(() => manageablePoolIds.value.length > 0 + && selectedManageablePoolCount.value === manageablePoolIds.value.length) +const someManageablePoolsSelected = computed(() => selectedManageablePoolCount.value > 0 + && selectedManageablePoolCount.value < manageablePoolIds.value.length) +const batchConfigPools = computed(() => overview.pools.filter((item: any) => batchConfigForm.pool_ids.includes(Number(item.id)))) +const batchMemberStatusOptions = computed(() => { + const memberOptionById = new Map(overview.member_options.map((member) => [Number(member.id), member])) + const grouped = new Map }>() + batchConfigPools.value.forEach((pool: any) => { + const poolId = Number(pool.id) + const memberRules = Array.isArray(pool.member_rules) ? pool.member_rules : [] + memberRules.forEach((rule: any) => { + const adminId = Number(rule.admin_id) + if (adminId <= 0) return + const member = memberOptionById.get(adminId) + const current = grouped.get(adminId) || { + id: adminId, + name: String(rule.name || member?.name || rule.userid || `员工 ${adminId}`), + userid: String(member?.userid || rule.userid || ''), + display_dept_id: Number(member?.display_dept_id || 0), + dept_ids: Array.isArray(member?.dept_ids) ? member.dept_ids.map(Number).filter((id) => id > 0) : [], + dept_names: Array.isArray(member?.dept_names) + ? member.dept_names.map(String).filter(Boolean) + : (Array.isArray(rule.dept_names) ? rule.dept_names.map(String).filter(Boolean) : []), + pool_count: 0, + online_count: 0, + offline_count: 0, + pool_ids: new Set() + } + if (!current.pool_ids.has(poolId)) { + current.pool_ids.add(poolId) + current.pool_count++ + if (Number(rule.enabled) === 1) current.online_count++ + else current.offline_count++ + } + grouped.set(adminId, current) + }) + }) + return [...grouped.values()] + .map(({ pool_ids: _poolIds, ...member }) => member) + .sort((left, right) => left.name.localeCompare(right.name, 'zh-CN')) +}) +const batchMemberStatusById = computed(() => new Map( + batchMemberStatusOptions.value.map((member) => [member.id, member]) +)) +const batchMemberDepartmentTree = computed(() => buildMemberDepartmentTree( + overview.department_options, + batchMemberStatusOptions.value, + { + selectableDepartments: true, + memberDetail: (member) => { + const status = batchMemberStatusById.value.get(member.id) + return status + ? `${status.pool_count} 个方案 · 已上线 ${status.online_count} / 已下线 ${status.offline_count}` + : '' + } + } +)) +const batchMemberTreeDefaultExpandedKeys = computed(() => batchMemberDepartmentTree.value.map((node) => node.value)) +const batchMemberOfflineBlockedPools = computed(() => { + if (!batchConfigApply.member_status || batchConfigForm.member_status !== 0) return [] + const targetAdminIds = new Set(batchConfigForm.member_admin_ids.map(Number)) + return batchConfigPools.value.filter((pool: any) => { + const rules = Array.isArray(pool.member_rules) ? pool.member_rules : [] + const targetedEnabled = rules.some((rule: any) => Number(rule.enabled) === 1 && targetAdminIds.has(Number(rule.admin_id))) + const remainingAvailable = rules.some((rule: any) => Number(rule.enabled) === 1 + && (batchConfigApply.reception || rule.reception_available) + && !targetAdminIds.has(Number(rule.admin_id))) + return targetedEnabled && !remainingAvailable + }) +}) +const batchPrimaryMemberSets = computed(() => batchConfigPools.value.map((pool: any) => new Set( + (Array.isArray(pool.member_admin_ids) ? pool.member_admin_ids : []).map(Number) +))) +const batchPrimaryMemberUnion = computed(() => [...new Set(batchPrimaryMemberSets.value.flatMap((ids) => [...ids]))]) +const batchSharedPrimaryMemberIds = computed(() => { + const sets = batchPrimaryMemberSets.value + if (!sets.length) return [] + return [...sets[0]].filter((id) => sets.slice(1).every((ids) => ids.has(id))) +}) +const batchDisabledAutomationSections = computed(() => ( + (['reception', 'customer', 'welcome'] as BatchAutomationSection[]) + .filter((section) => !batchConfigApply[section]) +)) const memberTreeProps = { value: 'value', label: 'label', children: 'children', disabled: 'disabled' } const memberDepartmentTree = computed(() => buildMemberDepartmentTree(overview.department_options, overview.member_options)) const memberTreeDefaultExpandedKeys = computed(() => memberDepartmentTree.value.map((node) => node.value)) @@ -527,17 +918,29 @@ const customerMemberOptions = computed(() => customerStats.member_options.length department_name: Array.isArray(item.dept_names) ? item.dept_names.join(' / ') : (item.department_name || item.dept_name || '') }))) -watch(() => overview.pools.map((item: any) => Number(item.id)).join(','), () => { - const ids = overview.pools.map((item: any) => Number(item.id)) - if (!selectedPoolId.value || !ids.includes(selectedPoolId.value)) selectedPoolId.value = ids[0] - if (!selectedInstallPoolId.value || !ids.includes(selectedInstallPoolId.value)) selectedInstallPoolId.value = ids[0] -}, { immediate: true }) +watch(() => overview.pools.map((item: any) => `${Number(item.id)}:${item.can_manage_access ? 1 : 0}`).join(','), () => { + const ids = overview.pools.map((item: any) => Number(item.id)) + const manageableIds = new Set(overview.pools + .filter((item: any) => item.can_manage_access) + .map((item: any) => Number(item.id))) + if (!selectedPoolId.value || !ids.includes(selectedPoolId.value)) selectedPoolId.value = ids[0] + if (!selectedInstallPoolId.value || !ids.includes(selectedInstallPoolId.value)) selectedInstallPoolId.value = ids[0] + selectedPoolIds.value = selectedPoolIds.value.filter((id) => manageableIds.has(id)) +}, { immediate: true }) -watch(activeTab, (tab) => { - if (tab === 'customer-stats' && !customerStatsLoaded.value) loadCustomerStats() -}) +watch(activeTab, (tab) => { + if (tab === 'customer-stats' && !customerStatsLoaded.value) loadCustomerStats() +}) + +watch(() => accessForm.action, (action) => { + if (action !== 'grant') return + const grantableIds = new Set(overview.operator_options + .filter((operator) => operator.can_grant) + .map((operator) => Number(operator.id))) + accessForm.operator_admin_ids = accessForm.operator_admin_ids.filter((id) => grantableIds.has(Number(id))) +}) -async function loadOverview() { +async function loadOverview() { loading.value = true try { const result: any = await wecomPromotionOverview() @@ -546,11 +949,245 @@ async function loadOverview() { ElMessage.error(error?.message || '企业微信推广配置加载失败') } finally { loading.value = false - } -} - + } +} + +function togglePoolSelection(pool: any, checked: unknown) { + if (!pool?.can_manage_access) return + const id = Number(pool.id) + const next = new Set(selectedPoolIds.value) + checked ? next.add(id) : next.delete(id) + selectedPoolIds.value = [...next] +} + +function toggleAllPoolSelection(checked: unknown) { + selectedPoolIds.value = checked ? [...manageablePoolIds.value] : [] +} + +function openBatchConfigDialog(poolIds: number[] = selectedPoolIds.value) { + const manageableIds = new Set(overview.pools + .filter((pool: any) => pool.can_manage_access) + .map((pool: any) => Number(pool.id))) + const ids = [...new Set(poolIds.map(Number).filter((id) => manageableIds.has(id)))] + if (!ids.length) return ElMessage.warning('请先选择可管理的分流方案') + if (ids.length > 100) return ElMessage.warning('单次最多设置 100 个分流方案') + const reference = overview.pools.find((pool: any) => Number(pool.id) === ids[0]) + Object.assign(batchConfigApply, { + skip_verify: false, + fallback_url: false, + status: false, + member_status: false, + reception: false, + customer: false, + welcome: false + }) + Object.assign(batchConfigForm, { + pool_ids: ids, + skip_verify: Number(reference?.skip_verify) === 1 ? 1 : 0, + fallback_url: String(reference?.fallback_url || ''), + status: Number(reference?.status) === 1 ? 1 : 0, + member_admin_ids: [], + member_status: 1, + automation_config: cloneAutomationConfig(reference?.automation_config) + }) + batchConfigError.value = '' + batchConfigBusy.value = false + batchConfigDialogVisible.value = true +} + +function copyAutomationSection( + target: PromotionAutomationConfig, + source: PromotionAutomationConfig, + keys: Array +) { + const targetRecord = target as unknown as Record + const sourceRecord = source as unknown as Record + keys.forEach((key) => { targetRecord[key] = JSON.parse(JSON.stringify(sourceRecord[key])) }) +} + +function setBatchConfigError(message: string) { + batchConfigError.value = message + batchConfigScroll.value?.scrollTo({ top: 0, behavior: 'smooth' }) + ElMessage.warning(message) +} + +async function saveBatchConfig() { + if (savingBatchConfig.value || batchConfigBusy.value) return + batchConfigError.value = '' + const hasAutomationChange = overview.automation_installed + && (batchConfigApply.reception || batchConfigApply.customer || batchConfigApply.welcome) + const hasMemberStatusChange = batchConfigApply.member_status + const hasPoolConfigChange = batchConfigApply.skip_verify || batchConfigApply.fallback_url || batchConfigApply.status || hasAutomationChange + if (!batchConfigApply.skip_verify && !batchConfigApply.fallback_url && !batchConfigApply.status && !hasMemberStatusChange && !hasAutomationChange) { + return setBatchConfigError('请至少勾选一项需要批量修改的配置') + } + if (hasMemberStatusChange && hasPoolConfigChange) { + return setBatchConfigError('员工上下线需要单独批量保存,请取消其他方案配置修改') + } + if (hasMemberStatusChange && !batchConfigForm.member_admin_ids.length) { + return setBatchConfigError('请至少选择一名需要批量上线或下线的员工') + } + if (hasMemberStatusChange && batchConfigForm.member_admin_ids.length > 100) { + return setBatchConfigError('单次最多设置 100 名员工,请减少选择范围') + } + if (hasMemberStatusChange && batchConfigForm.member_status === 0 && batchMemberOfflineBlockedPools.value.length) { + return setBatchConfigError(`${batchMemberOfflineBlockedPools.value[0].name} 至少需要保留一名当前可用的上线员工`) + } + if (batchConfigApply.fallback_url && batchConfigForm.fallback_url.trim() && !isWebUrl(batchConfigForm.fallback_url.trim())) { + return setBatchConfigError('兜底获客助手链接必须为有效的 HTTP/HTTPS 地址') + } + + const automation = cloneAutomationConfig(batchConfigForm.automation_config) + if (batchConfigApply.reception && automation.reception_mode !== 'scheduled') automation.reception_schedule = [] + if (batchConfigApply.welcome && automation.welcome_mode !== 'channel') automation.welcome = { text: '', attachments: [] } + if (batchConfigApply.welcome && (automation.welcome_mode !== 'channel' || !automation.welcome_schedule_enabled)) automation.welcome_schedule = [] + if (hasAutomationChange) { + const validationConfig = defaultAutomationConfig() + if (batchConfigApply.reception) copyAutomationSection(validationConfig, automation, ['reception_mode', 'reception_schedule', 'backup_member_admin_ids']) + if (batchConfigApply.customer) copyAutomationSection(validationConfig, automation, ['tags_enabled', 'tag_ids', 'remark_enabled', 'remark_template', 'description_enabled', 'description']) + if (batchConfigApply.welcome) copyAutomationSection(validationConfig, automation, ['welcome_mode', 'welcome', 'welcome_schedule_enabled', 'welcome_schedule']) + const backupConflict = batchConfigApply.reception + && automation.backup_member_admin_ids.some((id) => batchPrimaryMemberUnion.value.includes(Number(id))) + const validationError = backupConflict + ? '备用成员不能是任一所选方案的主接待成员' + : validateAutomationConfig(validationConfig, batchSharedPrimaryMemberIds.value) + if (validationError) return setBatchConfigError(validationError) + } + + const changes: { + skip_verify?: 0 | 1 + fallback_url?: string + status?: 0 | 1 + automation_config?: Record + member_status?: { member_admin_ids: number[]; status: 0 | 1 } + } = {} + if (batchConfigApply.skip_verify) changes.skip_verify = batchConfigForm.skip_verify === 1 ? 1 : 0 + if (batchConfigApply.fallback_url) changes.fallback_url = batchConfigForm.fallback_url.trim() + if (batchConfigApply.status) changes.status = batchConfigForm.status === 1 ? 1 : 0 + if (hasMemberStatusChange) { + changes.member_status = { + member_admin_ids: [...batchConfigForm.member_admin_ids], + status: batchConfigForm.member_status + } + } + if (hasAutomationChange) { + const serialized = serializeAutomationConfig(automation) as unknown as Record + const automationPatch: Record = {} + const assignKeys = (keys: string[]) => keys.forEach((key) => { automationPatch[key] = serialized[key] }) + if (batchConfigApply.reception) assignKeys(['reception_mode', 'reception_schedule', 'backup_member_admin_ids']) + if (batchConfigApply.customer) assignKeys(['tags_enabled', 'tag_ids', 'remark_enabled', 'remark_template', 'description_enabled', 'description']) + if (batchConfigApply.welcome) assignKeys(['welcome_mode', 'welcome', 'welcome_schedule_enabled', 'welcome_schedule']) + changes.automation_config = automationPatch + } + + savingBatchConfig.value = true + try { + const result = await wecomPromotionBatchUpdatePools({ + pool_ids: [...batchConfigForm.pool_ids], + changes + }) + if (result.updated === 0) { + const detail = result.results + .slice(0, 2) + .map((item) => `${item.name || `方案 ${item.id}`}:${item.error || '保存失败'}`) + .join(';') + return setBatchConfigError(detail || '所选方案均未能保存,请检查配置后重试') + } + batchConfigDialogVisible.value = false + selectedPoolIds.value = [] + await loadOverview() + const memberStatusText = batchConfigForm.member_status === 1 ? '上线' : '下线' + const memberResultText = hasMemberStatusChange + ? (result.member_updated > 0 + ? `,${result.member_updated} 条员工规则已${memberStatusText}` + : `,所选员工均已处于${memberStatusText}状态`) + : '' + if (result.failed > 0) { + const detail = result.results + .filter((item) => !item.success) + .slice(0, 2) + .map((item) => `${item.name || `方案 ${item.id}`}:${item.error || '保存失败'}`) + .join(';') + ElMessage.warning(`已更新 ${result.updated} 个方案,${result.failed} 个失败${memberResultText}${detail ? `。${detail}` : ''}`) + } else if (result.sync_error_count > 0) { + ElMessage.warning(`已更新 ${result.updated} 个方案${memberResultText},其中 ${result.sync_error_count} 个企微范围将在后台自动重试同步`) + } else if (result.sync_queued_count > 0) { + ElMessage.success(`已批量更新 ${result.updated} 个分流方案${memberResultText},${result.sync_queued_count} 个企微链接配置将在后台同步`) + } else { + ElMessage.success(`已批量更新 ${result.updated} 个分流方案${memberResultText}`) + } + } catch (error: any) { + setBatchConfigError(error?.message || '批量修改分流方案失败') + } finally { + savingBatchConfig.value = false + } +} + +function openAccessDialog(poolIds: number[] = selectedPoolIds.value) { + const manageableIds = new Set(overview.pools + .filter((pool: any) => pool.can_manage_access) + .map((pool: any) => Number(pool.id))) + const ids = [...new Set(poolIds.map(Number).filter((id) => manageableIds.has(id)))] + if (!ids.length) return ElMessage.warning('请先选择可管理的分流方案') + if (ids.length > 100) return ElMessage.warning('单次最多设置 100 个分流方案') + Object.assign(accessForm, { + pool_ids: ids, + operator_admin_ids: [], + action: 'grant' + }) + accessDialogVisible.value = true +} + +async function savePoolOperators() { + if (!accessForm.pool_ids.length) return ElMessage.warning('请至少选择一个分流方案') + if (!accessForm.operator_admin_ids.length) return ElMessage.warning('请至少选择一名操作人') + savingAccess.value = true + try { + const result = await wecomPromotionBatchSetOperators({ + pool_ids: [...accessForm.pool_ids], + operator_admin_ids: [...accessForm.operator_admin_ids], + action: accessForm.action + }) + accessDialogVisible.value = false + selectedPoolIds.value = [] + await loadOverview() + const actionLabel = accessForm.action === 'grant' ? '添加' : '移除' + ElMessage.success(result?.affected + ? `已批量${actionLabel} ${result.affected} 条方案操作权限` + : '权限设置已检查,没有需要变更的记录') + } catch (error: any) { + ElMessage.error(error?.message || '批量设置访问操作失败') + } finally { + savingAccess.value = false + } +} + +function operatorOptionLabel(operator: PromotionOperatorOption) { + const departments = Array.isArray(operator.dept_names) && operator.dept_names.length + ? operator.dept_names.join(' / ') + : '未分部门' + const unavailable = Number(operator.disable) === 1 ? ' · 已禁用' : '' + return `${operator.name} · ${departments}${unavailable}` +} + +function operatorNames(pool: any) { + const operators = Array.isArray(pool?.operators) ? pool.operators : [] + if (!operators.length) return '仅原管理范围可操作' + return operators + .map((operator: any) => `${operator.name || `账号 ${operator.id}`}${Number(operator.disable) === 1 ? '(已禁用)' : ''}`) + .join('、') +} + +function accessSummary(pool: any) { + const linkState = pool?.main_url ? '官方链接已生成' : '待生成链接' + const operatorCount = Array.isArray(pool?.operator_admin_ids) ? pool.operator_admin_ids.length : 0 + return operatorCount > 0 ? `${linkState} · ${operatorCount} 人可操作` : linkState +} + function openPoolDialog(pool?: any) { const selectableMemberIds = new Set(overview.member_options.map((member) => Number(member.id))) + poolFormError.value = '' + automationBusy.value = false Object.assign(poolForm, pool ? { id: Number(pool.id), name: pool.name, @@ -560,7 +1197,8 @@ function openPoolDialog(pool?: any) { ? pool.member_admin_ids.map(Number).filter((memberId: number) => selectableMemberIds.has(memberId)) : [], skip_verify: Number(pool.skip_verify) === 1 ? 1 : 0, - main_url: pool.main_url || '' + main_url: pool.main_url || '', + automation_config: cloneAutomationConfig(pool.automation_config) } : { id: 0, name: '', @@ -568,25 +1206,51 @@ function openPoolDialog(pool?: any) { status: 1, member_admin_ids: [], skip_verify: 0, - main_url: '' + main_url: '', + automation_config: defaultAutomationConfig() }) poolDialogVisible.value = true } async function savePool() { - if (!poolForm.name.trim()) return ElMessage.warning('请输入分流方案名称') - if (!poolForm.member_admin_ids.length) return ElMessage.warning('请至少选择一名获客医助') + if (savingPool.value || automationBusy.value) return + poolFormError.value = '' + const automation = cloneAutomationConfig(poolForm.automation_config) + // Disabled sections do not submit unfinished draft rows or draft attachments. + if (automation.reception_mode !== 'scheduled') automation.reception_schedule = [] + if (automation.welcome_mode !== 'channel') automation.welcome = { text: '', attachments: [] } + if (automation.welcome_mode !== 'channel' || !automation.welcome_schedule_enabled) automation.welcome_schedule = [] + const error = !poolForm.name.trim() ? '请输入分流方案名称' + : !poolForm.member_admin_ids.length ? '请至少选择一名主接待成员' + : poolForm.fallback_url.trim() && !isWebUrl(poolForm.fallback_url.trim()) ? '兜底获客助手链接必须为有效的 HTTP/HTTPS 地址' + : overview.automation_installed ? validateAutomationConfig(automation, poolForm.member_admin_ids) : '' + if (error) { + poolFormError.value = error + poolFormScroll.value?.scrollTo({ top: 0, behavior: 'smooth' }) + return ElMessage.warning(error) + } savingPool.value = true - try { - const result: any = await wecomPromotionSavePool({ ...poolForm }) - poolDialogVisible.value = false + try { + const { automation_config: _draft, ...base } = poolForm + const result: any = await wecomPromotionSavePool({ + ...base, + name: poolForm.name.trim(), + fallback_url: poolForm.fallback_url.trim(), + ...(overview.automation_installed ? { automation_config: serializeAutomationConfig(automation) } : {}) + }) + if (overview.automation_installed && result?.automation_saved !== true) { + throw new Error('方案已提交,但服务端未确认标签和欢迎语配置保存成功,请刷新后重试') + } + poolDialogVisible.value = false await loadOverview() if (result?.id) selectedPoolId.value = Number(result.id) result?.sync_error ? ElMessage.warning('方案已保存,企业微信多人范围将在后台自动重试同步') : ElMessage.success(poolForm.id ? '分流方案已保存' : '分流方案和官方获客链接已创建') - } catch (error: any) { - ElMessage.error(error?.message || '分流方案保存失败') + } catch (error: any) { + poolFormError.value = error?.message || (typeof error === 'string' ? error : '分流方案保存失败,请检查配置或稍后重试') + poolFormScroll.value?.scrollTo({ top: 0, behavior: 'smooth' }) + ElMessage.error(poolFormError.value) } finally { savingPool.value = false } @@ -787,10 +1451,17 @@ function eligibility(row: any) { if (Number(row.active_start) > 0 && Number(row.active_start) > now) return { label: '尚未生效', className: 'is-waiting' } if (Number(row.active_end) > 0 && Number(row.active_end) < now) return { label: '已过期', className: 'is-error' } if (Number(row.daily_limit) > 0 && todayCount(row) >= Number(row.daily_limit)) return { label: '今日已达上限', className: 'is-waiting' } - if (Number(row.sync_status) === 3) return { label: '企微同步重试中', className: 'is-waiting' } - if (Number(row.sync_status) === 4) return { label: '暂无可用成员', className: 'is-error' } + if (Number(selectedPool.value?.status) === 0) return { label: '方案已停用', className: 'is-muted' } + if (row.reception_available === false || row.reception_available === 0) return { label: row.is_backup ? '备用待命' : '非接待时段', className: 'is-waiting' } + if (row.is_backup) return { label: '备用接待中', className: 'is-ok' } return { label: '可参与分流', className: 'is-ok' } } + +function routeStatus(row: any) { + const available = eligibility(row).className === 'is-ok' + if (row.is_in_remote_range) return { label: available ? '企微路由中' : '待移出', className: available ? 'is-online' : 'is-offline' } + return { label: available ? '待同步' : '未在路由范围', className: 'is-offline' } +} function todayCount(row: any) { const today = new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit', day: '2-digit' }).format(new Date()) @@ -799,7 +1470,11 @@ function todayCount(row: any) { function buildMemberDepartmentTree( departmentOptions: PromotionDepartmentOption[], - memberOptions: PromotionMemberOption[] + memberOptions: PromotionMemberOption[], + options: { + selectableDepartments?: boolean + memberDetail?: (member: PromotionMemberOption) => string + } = {} ): PromotionMemberTreeNode[] { const availableDeptIds = new Set() const collectDeptIds = (departments: PromotionDepartmentOption[]) => { @@ -844,7 +1519,8 @@ function buildMemberDepartmentTree( const placedMemberIds = new Set() const toMemberNode = (member: PromotionMemberOption): PromotionMemberTreeNode => { const departments = member.dept_names.length ? member.dept_names.join(' / ') : '未分部门' - const detail = member.userid ? `${departments} · ${member.userid}` : departments + const detail = options.memberDetail?.(member) + || (member.userid ? `${departments} · ${member.userid}` : departments) return { value: member.id, label: member.name, @@ -879,7 +1555,7 @@ function buildMemberDepartmentTree( value: `dept:${departmentId}`, label: departmentName, kind: 'department', - disabled: true, + disabled: !options.selectableDepartments, member_count: memberCount, search_text: `${path.join(' ')} ${children.map((child) => child.search_text).join(' ')}`.toLocaleLowerCase(), children @@ -896,7 +1572,7 @@ function buildMemberDepartmentTree( value: 'dept:unassigned', label: '未分部门', kind: 'department', - disabled: true, + disabled: !options.selectableDepartments, member_count: children.length, search_text: `未分部门 ${children.map((child) => child.search_text).join(' ')}`.toLocaleLowerCase(), children @@ -912,7 +1588,8 @@ function filterMemberTreeNode(keyword: string, data: any) { function memberSummary(pool: any) { const ids = Array.isArray(pool?.member_admin_ids) ? pool.member_admin_ids : [] - return ids.length ? `${ids.length} 名医助` : '未选择医助' + const backupCount = pool?.automation_config?.backup_member_admin_ids?.length || 0 + return ids.length ? `${ids.length} 名主接待${backupCount ? ` · ${backupCount} 名备用` : ''}` : '未选择医助' } function memberRuleDetail(row: any) { @@ -1074,18 +1751,24 @@ h1, h2, h3, p { margin: 0; } .tab-nav button { display: flex; align-items: center; gap: 7px; min-width: 132px; height: 54px; justify-content: center; border: 0; border-bottom: 3px solid transparent; color: #5e6d80; background: transparent; cursor: pointer; font-size: 14px; } .tab-nav button.active { border-bottom-color: var(--teal); color: #0d8277; font-weight: 700; } .tab-content { min-height: 460px; padding: 20px; } -.section-heading { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 16px; } -.section-heading h2 { font-size: 17px; }.section-heading p { margin-top: 5px; color: var(--muted); font-size: 12px; } -.pool-layout { display: grid; grid-template-columns: 252px minmax(0, 1fr); min-height: 430px; border: 1px solid var(--line); border-radius: 11px; overflow: hidden; } -.pool-sidebar { padding: 8px; border-right: 1px solid var(--line); background: #f7f9fa; } -.pool-item { display: grid; grid-template-columns: 9px 1fr 16px; align-items: center; gap: 9px; width: 100%; min-height: 62px; margin-bottom: 5px; padding: 10px; border: 1px solid transparent; border-radius: 8px; text-align: left; background: transparent; cursor: pointer; } -.pool-item:hover { background: #fff; }.pool-item.active { border-color: #bfe1dc; background: #fff; box-shadow: 0 5px 16px rgba(25,69,70,.05); } +.section-heading { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 16px; } +.section-heading h2 { font-size: 17px; }.section-heading p { margin-top: 5px; color: var(--muted); font-size: 12px; } +.section-heading-actions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px; } +.section-heading-actions .el-button + .el-button { margin-left: 0; } +.selection-count { color: #117f75; font-size: 11px; font-weight: 600; } +.pool-layout { display: grid; grid-template-columns: 252px minmax(0, 1fr); height: clamp(430px, calc(100vh - 330px), 720px); min-height: 430px; border: 1px solid var(--line); border-radius: 11px; overflow: hidden; } +.pool-sidebar { min-height: 0; padding: 8px; border-right: 1px solid var(--line); overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable; background: #f7f9fa; } +.pool-select-all { display: flex; position: sticky; z-index: 2; top: 0; align-items: center; justify-content: space-between; min-height: 42px; margin: 0 0 8px; padding: 4px 8px; border-bottom: 1px solid var(--line); background: #f7f9fa; }.pool-select-all :deep(.el-checkbox) { margin-right: 0; }.pool-select-all span { color: #8c98a7; font-size: 10px; } +.pool-select-row { display: grid; grid-template-columns: 22px minmax(0, 1fr); align-items: center; gap: 4px; margin-bottom: 5px; } +.pool-select-row :deep(.el-checkbox) { justify-content: center; margin-right: 0; } +.pool-item { display: grid; grid-template-columns: 9px minmax(0, 1fr) 16px; align-items: center; gap: 9px; width: 100%; min-height: 62px; padding: 10px; border: 1px solid transparent; border-radius: 8px; text-align: left; background: transparent; cursor: pointer; } +.pool-item:hover { background: #fff; }.pool-select-row.active .pool-item { border-color: #bfe1dc; background: #fff; box-shadow: 0 5px 16px rgba(25,69,70,.05); } .pool-item strong, .pool-item small { display: block; }.pool-item strong { overflow: hidden; color: #253348; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }.pool-item small { margin-top: 4px; color: #8c98a7; font-size: 10px; } .pool-status { width: 8px; height: 8px; border-radius: 50%; }.pool-status.online { background: #18a277; }.pool-status.offline { background: #aab3bf; }.pool-item > .el-icon { color: #9ca7b4; } -.pool-main { min-width: 0; }.pool-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 78px; padding: 12px 15px; border-bottom: 1px solid var(--line); } +.pool-main { display: flex; min-width: 0; min-height: 0; flex-direction: column; overflow: hidden; }.pool-toolbar { display: flex; flex: 0 0 auto; align-items: center; justify-content: space-between; gap: 16px; min-height: 78px; padding: 12px 15px; border-bottom: 1px solid var(--line); } .pool-title-row { gap: 8px; }.pool-title-row h3 { font-size: 15px; }.pool-toolbar p { margin-top: 6px; color: #8b97a6; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 10px; }.toolbar-actions { flex-wrap: wrap; justify-content: flex-end; gap: 7px; }.toolbar-actions .el-button + .el-button { margin-left: 0; } .status-tag, .owner-tag, .availability { display: inline-flex; align-items: center; min-height: 22px; padding: 0 8px; border-radius: 11px; font-size: 10px; }.status-tag.is-online, .availability.is-ok { color: #16895f; background: #eaf8ef; }.status-tag.is-offline, .availability.is-muted { color: #788696; background: #eef2f5; }.owner-tag { color: #50728c; background: #edf4f8; }.availability.is-error { color: #d94b4b; background: #ffeded; }.availability.is-waiting { color: #b86c1f; background: #fff1dd; } -.link-table, .account-table { --el-table-header-bg-color: #f7f9fb; }.link-table :deep(th.el-table__cell), .account-table :deep(th.el-table__cell) { color: #67768a; font-weight: 500; }.member-cell strong, .member-cell small { display: block; }.member-cell small { margin-top: 3px; color: #8d98a7; font-size: 10px; }.muted { color: #9aa4b0; } +.legacy-sync-alert { flex: 0 0 auto; }.member-table-area { min-height: 0; flex: 1 1 auto; overflow: hidden; }.link-table, .account-table { --el-table-header-bg-color: #f7f9fb; }.link-table :deep(th.el-table__cell), .account-table :deep(th.el-table__cell) { color: #67768a; font-weight: 500; }.member-cell strong, .member-cell small { display: block; }.member-cell small { margin-top: 3px; color: #8d98a7; font-size: 10px; }.muted { color: #9aa4b0; } .remote-id { display: block; overflow: hidden; color: #68778b; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } .link-id-cell { display: grid; gap: 4px; min-width: 0; } .wecom-url { display: block; overflow: hidden; color: #148f83; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; line-height: 1.4; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; } @@ -1113,6 +1796,26 @@ h1, h2, h3, p { margin: 0; } .member-tree-option__count { flex: 0 0 auto; color: #98a2b3; font-size: 11px; } .member-tree-option__detail { overflow: hidden; color: #8b97a6; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } .form-grid, .rule-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }.form-tip { display: block; margin-top: 5px; color: #8b97a6; font-size: 10px; }.link-form .el-select, .link-form .el-input-number { width: 100%; } -@media (max-width: 1100px) { .heading-actions { flex-wrap: wrap; justify-content: flex-end; }.metric-grid, .customer-metric-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }.pool-layout { grid-template-columns: 210px minmax(0,1fr); }.pool-toolbar { align-items: flex-start; flex-direction: column; } } -@media (max-width: 760px) { .promotion-page { padding: 10px; }.page-header, .section-heading { align-items: flex-start; flex-direction: column; }.update-time { display: none; }.metric-grid, .customer-metric-grid, .form-grid, .rule-form-grid { grid-template-columns: 1fr; }.tab-nav { overflow-x: auto; }.tab-nav button { min-width: 112px; }.tab-content { padding: 14px; }.pool-layout { grid-template-columns: 1fr; }.pool-sidebar { display: flex; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); }.pool-item { min-width: 190px; }.callback-list > div { grid-template-columns: 1fr 48px; padding: 8px 0; }.callback-list dt { grid-column: 1 / -1; }.install-pool-select { width: 100%; }.customer-heading-actions { width: 100%; justify-content: flex-end; }.customer-filter-bar :deep(.el-form-item) { width: 100%; margin-right: 0; }.customer-filter-bar :deep(.el-form-item__content), .customer-filter-bar .el-select { width: 100%; }.customer-filter-bar .filter-actions :deep(.el-form-item__content) { justify-content: flex-end; }.customer-pagination { align-items: flex-start; flex-direction: column; }.customer-pagination :deep(.el-pagination) { max-width: 100%; flex-wrap: wrap; justify-content: flex-start; } } +.access-form { margin-top: 16px; } +.access-pool-preview { padding: 12px 14px; border: 1px solid var(--line); border-radius: 8px; background: #f8fafb; } +.access-pool-preview > strong { display: block; margin-bottom: 7px; font-size: 12px; } +.access-pool-preview > div { display: grid; grid-template-columns: minmax(120px, .8fr) minmax(0, 1.6fr); gap: 12px; padding: 6px 0; border-top: 1px solid #edf0f2; font-size: 11px; } +.access-pool-preview span { overflow: hidden; color: #344054; text-overflow: ellipsis; white-space: nowrap; } +.access-pool-preview small, .access-pool-preview p { color: #8491a2; font-size: 10px; } +.access-pool-preview small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.access-pool-preview p { margin-top: 7px; } +.pool-form-scroll { max-height: 70vh; overflow-y: auto; overflow-x: hidden; padding: 0 10px 6px 2px; } +.pool-form-error { margin-bottom: 18px; } +.batch-config-error { margin-top: 14px; } +.batch-pool-summary { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-top: 14px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; background: #f8fafb; } +.batch-pool-summary strong { margin-right: 3px; font-size: 12px; }.batch-pool-summary span { padding: 4px 8px; border-radius: 12px; color: #426078; background: #eaf1f5; font-size: 10px; }.batch-pool-summary small { color: #8491a2; font-size: 10px; } +.batch-config-form { margin-top: 16px; }.batch-config-section { margin-bottom: 18px; padding: 16px; border: 1px solid var(--line); border-radius: 9px; background: #fff; }.batch-config-section > h3 { margin: 0 0 14px; color: #303b4d; font-size: 14px; } +.batch-field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }.batch-field { padding: 12px; border: 1px solid #dfe6ec; border-radius: 8px; transition: opacity .2s ease, background .2s ease; }.batch-field.is-disabled { opacity: .58; background: #f7f8fa; }.batch-field :deep(.el-form-item) { margin: 10px 0 0; } +.batch-member-status-field { padding: 14px; }.batch-member-status-grid { display: grid; grid-template-columns: minmax(190px, .7fr) minmax(0, 1.6fr); gap: 14px; } +.batch-section-tip { margin: -6px 0 12px; color: #8491a2; font-size: 11px; line-height: 1.6; }.batch-section-selectors { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }.batch-section-selectors :deep(.el-checkbox) { margin-right: 0; }.automation-batch-section :deep(.automation-note) { margin-top: 14px; } +.uploading-save-tip { color: #b88230; font-size: 12px; margin-right: 16px; } +.sync-retry-tip { color: #b88230; font-size: 10px; line-height: 1.6; margin-top: 4px; } +:global(.promotion-pool-dialog) { max-width: calc(100vw - 32px); margin-top: 5vh; } +@media (max-width: 1100px) { .heading-actions { flex-wrap: wrap; justify-content: flex-end; }.metric-grid, .customer-metric-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }.pool-layout { grid-template-columns: 210px minmax(0,1fr); }.pool-toolbar { align-items: flex-start; flex-direction: column; } } +@media (max-width: 760px) { .promotion-page { padding: 10px; }.page-header, .section-heading { align-items: flex-start; flex-direction: column; }.section-heading-actions { width: 100%; justify-content: flex-start; }.update-time { display: none; }.metric-grid, .customer-metric-grid, .form-grid, .rule-form-grid, .batch-field-grid, .batch-member-status-grid { grid-template-columns: 1fr; }.tab-nav { overflow-x: auto; }.tab-nav button { min-width: 112px; }.tab-content { padding: 14px; }.pool-layout { height: auto; min-height: 0; grid-template-columns: 1fr; }.pool-sidebar { display: flex; overflow-x: auto; overflow-y: hidden; border-right: 0; border-bottom: 1px solid var(--line); scrollbar-gutter: auto; }.pool-select-all { position: static; min-width: 126px; flex: 0 0 126px; margin: 0 6px 0 0; border-right: 1px solid var(--line); border-bottom: 0; }.pool-main { overflow: visible; }.member-table-area { height: 420px; min-height: 320px; flex: none; }.pool-select-row { min-width: 220px; }.pool-item { min-width: 190px; }.callback-list > div { grid-template-columns: 1fr 48px; padding: 8px 0; }.callback-list dt { grid-column: 1 / -1; }.install-pool-select { width: 100%; }.customer-heading-actions { width: 100%; justify-content: flex-end; }.customer-filter-bar :deep(.el-form-item) { width: 100%; margin-right: 0; }.customer-filter-bar :deep(.el-form-item__content), .customer-filter-bar .el-select { width: 100%; }.customer-filter-bar .filter-actions :deep(.el-form-item__content) { justify-content: flex-end; }.customer-pagination { align-items: flex-start; flex-direction: column; }.customer-pagination :deep(.el-pagination) { max-width: 100%; flex-wrap: wrap; justify-content: flex-start; }.access-pool-preview > div { grid-template-columns: 1fr; gap: 3px; } } diff --git a/admin/src/views/order/index.vue b/admin/src/views/order/index.vue index 0a882618e..babfce450 100644 --- a/admin/src/views/order/index.vue +++ b/admin/src/views/order/index.vue @@ -677,6 +677,32 @@
+ + + + + +