feat(i18n): ✨ add i18n for remaining pages and fix content disorder
fix unable to automatically download AI-generated content add github action to enter the corresponding key into the generation environment
This commit is contained in:
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -183,6 +183,26 @@ jobs:
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Prepare production config
|
||||
shell: bash
|
||||
env:
|
||||
YOUDAO_APP_KEY: ${{ secrets.YOUDAO_APP_KEY }}
|
||||
YOUDAO_APP_SECRET: ${{ secrets.YOUDAO_APP_SECRET }}
|
||||
TENCENT_API_KEY: ${{ secrets.TENCENT_API_KEY }}
|
||||
TENCENT_SECRET_ID: ${{ secrets.TENCENT_SECRET_ID }}
|
||||
TENCENT_MAP_KEY: ${{ secrets.TENCENT_MAP_KEY }}
|
||||
run: |
|
||||
mkdir -p src-tauri/configuration
|
||||
cat > src-tauri/configuration/production.yaml <<'EOF'
|
||||
youdao:
|
||||
app_key: "${YOUDAO_APP_KEY}"
|
||||
app_secret: "${YOUDAO_APP_SECRET}"
|
||||
tencent:
|
||||
api_key: "${TENCENT_API_KEY}"
|
||||
secret_id: "${TENCENT_SECRET_ID}"
|
||||
map_key: "${TENCENT_MAP_KEY}"
|
||||
EOF
|
||||
|
||||
# 安装 Rust
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable # Set this to dtolnay/rust-toolchain@nightly
|
||||
|
||||
26
docs/release-config.md
Normal file
26
docs/release-config.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 发布流程中的生产配置注入说明
|
||||
|
||||
在 GitHub Actions 的 release 流程(`.github/workflows/release.yml`)里,打包前会自动生成 `src-tauri/configuration/production.yaml`,将密钥写入其中。需要在仓库的 **Settings → Secrets and variables → Actions** 中配置以下 Secrets:
|
||||
|
||||
- `YOUDAO_APP_KEY`
|
||||
- `YOUDAO_APP_SECRET`
|
||||
- `TENCENT_API_KEY`
|
||||
- `TENCENT_SECRET_ID`
|
||||
- `TENCENT_MAP_KEY`
|
||||
|
||||
工作流会在 `publish-tauri` 任务中执行:
|
||||
|
||||
```bash
|
||||
mkdir -p src-tauri/configuration
|
||||
cat > src-tauri/configuration/production.yaml <<'EOF'
|
||||
youdao:
|
||||
app_key: "${YOUDAO_APP_KEY}"
|
||||
app_secret: "${YOUDAO_APP_SECRET}"
|
||||
tencent:
|
||||
api_key: "${TENCENT_API_KEY}"
|
||||
secret_id: "${TENCENT_SECRET_ID}"
|
||||
map_key: "${TENCENT_MAP_KEY}"
|
||||
EOF
|
||||
```
|
||||
|
||||
配置完成后,推送符合规则的标签(如 `v1.2.3`)触发发布时,以上内容会被写入生产配置文件参与打包,无需将密钥提交到仓库。***
|
||||
16
locales/en/home.json
vendored
16
locales/en/home.json
vendored
@@ -230,6 +230,22 @@
|
||||
"group_name_update_failed": "Failed to rename group"
|
||||
}
|
||||
},
|
||||
"manage_group_member": {
|
||||
"title": "Manage group members",
|
||||
"search_placeholder_mobile": "Search members~",
|
||||
"search_placeholder_pc": "Search group members",
|
||||
"selected_count": "Selected {count} members",
|
||||
"remove_button": "Remove from group",
|
||||
"dialog_negative": "Cancel",
|
||||
"dialog_positive": "Confirm",
|
||||
"remove_confirm": "Remove {count} members?",
|
||||
"channel_not_allowed": "Channels cannot remove members",
|
||||
"select_member_warning": "Select members to remove",
|
||||
"remove_success": "Removed {count} members",
|
||||
"remove_failed": "Failed to remove members, please retry",
|
||||
"confirm_remove_title": "Confirm removal",
|
||||
"channel_manage_unsupported": "Channels do not support member management"
|
||||
},
|
||||
"profile_card": {
|
||||
"online_status": "Online status",
|
||||
"status": {
|
||||
|
||||
43
locales/en/message.json
vendored
43
locales/en/message.json
vendored
@@ -187,6 +187,49 @@
|
||||
"open_main_panel": "Open main panel",
|
||||
"exit": "Exit"
|
||||
},
|
||||
"location": {
|
||||
"modal": {
|
||||
"title": {
|
||||
"map_error": "Map error",
|
||||
"location_error": "Location failed",
|
||||
"default": "Pick a location"
|
||||
},
|
||||
"result": {
|
||||
"map_error_title": "Map failed to load",
|
||||
"location_error_title": "Failed to get location"
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "Cancel",
|
||||
"retry": "Retry",
|
||||
"send": "Send location"
|
||||
},
|
||||
"loading": {
|
||||
"locating": "Fetching location...",
|
||||
"map": "Loading map..."
|
||||
},
|
||||
"info": {
|
||||
"current": "Current location",
|
||||
"fetching_address": "Getting address...",
|
||||
"coordinate": "Coord: {lat}, {lng}",
|
||||
"unknown_address": "Unknown address"
|
||||
},
|
||||
"errors": {
|
||||
"missing_api_key": "Tencent Map API key not configured",
|
||||
"geocode_failed": "Failed to fetch address"
|
||||
}
|
||||
},
|
||||
"map": {
|
||||
"marker_current": "Current location"
|
||||
},
|
||||
"hook": {
|
||||
"permission_check_failed": "Failed to check geolocation permission",
|
||||
"unsupported": "Geolocation is not supported in this browser",
|
||||
"error_generic": "Failed to obtain location",
|
||||
"permission_denied": "Location permission denied",
|
||||
"position_unavailable": "Location unavailable",
|
||||
"timeout": "Location request timed out"
|
||||
}
|
||||
},
|
||||
"update_window": {
|
||||
"updating": "Updating",
|
||||
"fetch_commit_failed": "Failed to load release notes for v{version}",
|
||||
|
||||
16
locales/zh-CN/home.json
vendored
16
locales/zh-CN/home.json
vendored
@@ -229,6 +229,22 @@
|
||||
"group_name_update_failed": "群名称更新失败"
|
||||
}
|
||||
},
|
||||
"manage_group_member": {
|
||||
"title": "管理群成员",
|
||||
"search_placeholder_mobile": "搜索成员~",
|
||||
"search_placeholder_pc": "搜索群成员",
|
||||
"selected_count": "已选择 {count} 人",
|
||||
"remove_button": "踢出群聊",
|
||||
"dialog_negative": "取消",
|
||||
"dialog_positive": "确定",
|
||||
"remove_confirm": "确定要踢出 {count} 位成员吗?",
|
||||
"channel_not_allowed": "频道不允许踢出成员",
|
||||
"select_member_warning": "请选择要踢出的成员",
|
||||
"remove_success": "成功踢出 {count} 位成员",
|
||||
"remove_failed": "踢出失败,请重试",
|
||||
"confirm_remove_title": "确认踢出",
|
||||
"channel_manage_unsupported": "频道不支持管理成员"
|
||||
},
|
||||
"profile_card": {
|
||||
"online_status": "在线状态",
|
||||
"status": {
|
||||
|
||||
43
locales/zh-CN/message.json
vendored
43
locales/zh-CN/message.json
vendored
@@ -187,6 +187,49 @@
|
||||
"open_main_panel": "打开主面板",
|
||||
"exit": "退出"
|
||||
},
|
||||
"location": {
|
||||
"modal": {
|
||||
"title": {
|
||||
"map_error": "地图错误",
|
||||
"location_error": "位置获取失败",
|
||||
"default": "选择位置"
|
||||
},
|
||||
"result": {
|
||||
"map_error_title": "地图加载失败",
|
||||
"location_error_title": "位置获取失败"
|
||||
},
|
||||
"buttons": {
|
||||
"cancel": "取消",
|
||||
"retry": "重试",
|
||||
"send": "发送位置"
|
||||
},
|
||||
"loading": {
|
||||
"locating": "正在获取位置...",
|
||||
"map": "地图加载中..."
|
||||
},
|
||||
"info": {
|
||||
"current": "当前位置",
|
||||
"fetching_address": "获取地址中...",
|
||||
"coordinate": "坐标: {lat}, {lng}",
|
||||
"unknown_address": "未知地址"
|
||||
},
|
||||
"errors": {
|
||||
"missing_api_key": "腾讯地图API密钥未配置",
|
||||
"geocode_failed": "获取地址失败"
|
||||
}
|
||||
},
|
||||
"map": {
|
||||
"marker_current": "当前位置"
|
||||
},
|
||||
"hook": {
|
||||
"permission_check_failed": "检查地理位置权限失败",
|
||||
"unsupported": "浏览器不支持地理位置功能",
|
||||
"error_generic": "获取位置失败",
|
||||
"permission_denied": "位置权限被拒绝",
|
||||
"position_unavailable": "位置信息不可用",
|
||||
"timeout": "获取位置超时"
|
||||
}
|
||||
},
|
||||
"update_window": {
|
||||
"updating": "更新中",
|
||||
"fetch_commit_failed": "v{version} 版本更新内容获取失败",
|
||||
|
||||
9
package.json
vendored
9
package.json
vendored
@@ -108,20 +108,19 @@
|
||||
"driver.js": "^1.3.6",
|
||||
"es-toolkit": "^1.41.0",
|
||||
"file-type": "^21.0.0",
|
||||
"github-markdown-css": "^5.8.1",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"hula-emojis": "^1.2.31",
|
||||
"internal-ip": "^8.0.1",
|
||||
"mermaid": "^11.12.1",
|
||||
"mitt": "^3.0.1",
|
||||
"naive-ui": "^2.43.1",
|
||||
"naive-ui": "^2.43.2",
|
||||
"p-limit": "^7.2.0",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"pinia-shared-state": "^1.0.1",
|
||||
"seemly": "^0.3.10",
|
||||
"stream-markdown": "^0.0.10",
|
||||
"stream-monaco": "^0.0.6",
|
||||
"stream-monaco": "^0.0.7",
|
||||
"tauri-plugin-mic-recorder-api": "^2.0.0",
|
||||
"tauri-plugin-safe-area-insets": "^0.1.0",
|
||||
"three": "^0.181.0",
|
||||
@@ -167,14 +166,14 @@
|
||||
"postcss-pxtorem": "^6.1.0",
|
||||
"prettier": "^3.6.2",
|
||||
"release-it": "^17.11.0",
|
||||
"sass": "1.93.2",
|
||||
"sass": "1.94.2",
|
||||
"typescript": "^5.9.3",
|
||||
"unplugin-auto-import": "^20.2.0",
|
||||
"unplugin-vue-components": "^30.0.0",
|
||||
"vite": "7.2.4",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"vitest": "^4.0.8",
|
||||
"vue-tsc": "^3.1.3",
|
||||
"vue-tsc": "^3.1.5",
|
||||
"web-vitals": "^5.1.0"
|
||||
},
|
||||
"config": {
|
||||
|
||||
309
pnpm-lock.yaml
generated
vendored
309
pnpm-lock.yaml
generated
vendored
@@ -107,9 +107,6 @@ importers:
|
||||
file-type:
|
||||
specifier: ^21.0.0
|
||||
version: 21.0.0
|
||||
github-markdown-css:
|
||||
specifier: ^5.8.1
|
||||
version: 5.8.1
|
||||
grapheme-splitter:
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4
|
||||
@@ -126,29 +123,29 @@ importers:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1
|
||||
naive-ui:
|
||||
specifier: ^2.43.1
|
||||
version: 2.43.1(vue@3.5.25(typescript@5.9.3))
|
||||
specifier: ^2.43.2
|
||||
version: 2.43.2(vue@3.5.25(typescript@5.9.3))
|
||||
p-limit:
|
||||
specifier: ^7.2.0
|
||||
version: 7.2.0
|
||||
pinia:
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
pinia-plugin-persistedstate:
|
||||
specifier: ^4.7.1
|
||||
version: 4.7.1(pinia@3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)))
|
||||
version: 4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)))
|
||||
pinia-shared-state:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1(pinia@3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)))
|
||||
version: 1.0.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)))
|
||||
seemly:
|
||||
specifier: ^0.3.10
|
||||
version: 0.3.10
|
||||
stream-markdown:
|
||||
specifier: ^0.0.10
|
||||
version: 0.0.10(shiki@3.15.0)
|
||||
version: 0.0.10(shiki@3.17.0)
|
||||
stream-monaco:
|
||||
specifier: ^0.0.6
|
||||
version: 0.0.6(monaco-editor@0.52.2)
|
||||
specifier: ^0.0.7
|
||||
version: 0.0.7(monaco-editor@0.52.2)
|
||||
tauri-plugin-mic-recorder-api:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
@@ -178,7 +175,7 @@ importers:
|
||||
version: 11.1.12(vue@3.5.25(typescript@5.9.3))
|
||||
vue-renderer-markdown:
|
||||
specifier: 0.0.62-beta.1
|
||||
version: 0.0.62-beta.1(katex@0.16.25)(mermaid@11.12.1)(shiki@3.15.0)(stream-markdown@0.0.10(shiki@3.15.0))(stream-monaco@0.0.6(monaco-editor@0.52.2))(vue-i18n@11.1.12(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
|
||||
version: 0.0.62-beta.1(katex@0.16.25)(mermaid@11.12.1)(shiki@3.17.0)(stream-markdown@0.0.10(shiki@3.17.0))(stream-monaco@0.0.7(monaco-editor@0.52.2))(vue-i18n@11.1.12(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
|
||||
vue-router:
|
||||
specifier: ^4.6.3
|
||||
version: 4.6.3(vue@3.5.25(typescript@5.9.3))
|
||||
@@ -233,13 +230,13 @@ importers:
|
||||
version: 66.5.4
|
||||
'@unocss/vite':
|
||||
specifier: ^66.5.4
|
||||
version: 66.5.4(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))
|
||||
version: 66.5.4(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))
|
||||
version: 6.0.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))
|
||||
'@vitejs/plugin-vue-jsx':
|
||||
specifier: ^5.1.1
|
||||
version: 5.1.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))
|
||||
version: 5.1.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^4.0.8
|
||||
version: 4.0.8(vitest@4.0.8)
|
||||
@@ -280,8 +277,8 @@ importers:
|
||||
specifier: ^17.11.0
|
||||
version: 17.11.0(typescript@5.9.3)
|
||||
sass:
|
||||
specifier: 1.93.2
|
||||
version: 1.93.2
|
||||
specifier: 1.94.2
|
||||
version: 1.94.2
|
||||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
@@ -293,16 +290,16 @@ importers:
|
||||
version: 30.0.0(@babel/parser@7.28.5)(vue@3.5.25(typescript@5.9.3))
|
||||
vite:
|
||||
specifier: 7.2.4
|
||||
version: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
version: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite-plugin-vue-setup-extend:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))
|
||||
version: 0.4.0(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))
|
||||
vitest:
|
||||
specifier: ^4.0.8
|
||||
version: 4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
version: 4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vue-tsc:
|
||||
specifier: ^3.1.3
|
||||
version: 3.1.3(typescript@5.9.3)
|
||||
specifier: ^3.1.5
|
||||
version: 3.1.5(typescript@5.9.3)
|
||||
web-vitals:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0
|
||||
@@ -1668,26 +1665,26 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@shikijs/core@3.15.0':
|
||||
resolution: {integrity: sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg==}
|
||||
'@shikijs/core@3.17.0':
|
||||
resolution: {integrity: sha512-/HjeOnbc62C+n33QFNFrAhUlIADKwfuoS50Ht0pxujxP4QjZAlFp5Q+OkDo531SCTzivx5T18khwyBdKoPdkuw==}
|
||||
|
||||
'@shikijs/engine-javascript@3.15.0':
|
||||
resolution: {integrity: sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg==}
|
||||
'@shikijs/engine-javascript@3.17.0':
|
||||
resolution: {integrity: sha512-WwF99xdP8KfuDrIbT4wxyypfhoIxMeeOCp1AiuvzzZ6JT5B3vIuoclL8xOuuydA6LBeeNXUF/XV5zlwwex1jlA==}
|
||||
|
||||
'@shikijs/engine-oniguruma@3.15.0':
|
||||
resolution: {integrity: sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA==}
|
||||
'@shikijs/engine-oniguruma@3.17.0':
|
||||
resolution: {integrity: sha512-flSbHZAiOZDNTrEbULY8DLWavu/TyVu/E7RChpLB4WvKX4iHMfj80C6Hi3TjIWaQtHOW0KC6kzMcuB5TO1hZ8Q==}
|
||||
|
||||
'@shikijs/langs@3.15.0':
|
||||
resolution: {integrity: sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A==}
|
||||
'@shikijs/langs@3.17.0':
|
||||
resolution: {integrity: sha512-icmur2n5Ojb+HAiQu6NEcIIJ8oWDFGGEpiqSCe43539Sabpx7Y829WR3QuUW2zjTM4l6V8Sazgb3rrHO2orEAw==}
|
||||
|
||||
'@shikijs/monaco@3.15.0':
|
||||
resolution: {integrity: sha512-MKURaG5ehas44DBOfw0szEp89fA3WTERl7B6MjWcRQMIvHd++OQmPLyk1wcWbqZ3Jcvj0QBCJw+5tR/IBW016g==}
|
||||
'@shikijs/monaco@3.17.0':
|
||||
resolution: {integrity: sha512-M/1lh+VKALKBNE4esjPXt5qCmkZ1KOIviDcTbfq7eP9EX/K1WPQR/kcHc5MTGlB+4iqSWiRghUHdCReRghx/wg==}
|
||||
|
||||
'@shikijs/themes@3.15.0':
|
||||
resolution: {integrity: sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ==}
|
||||
'@shikijs/themes@3.17.0':
|
||||
resolution: {integrity: sha512-/xEizMHLBmMHwtx4JuOkRf3zwhWD2bmG5BRr0IPjpcWpaq4C3mYEuTk/USAEglN0qPrTwEHwKVpSu/y2jhferA==}
|
||||
|
||||
'@shikijs/types@3.15.0':
|
||||
resolution: {integrity: sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw==}
|
||||
'@shikijs/types@3.17.0':
|
||||
resolution: {integrity: sha512-wjLVfutYWVUnxAjsWEob98xgyaGv0dTEnMZDruU5mRjVN7szcGOfgO+997W2yR6odp+1PtSBNeSITRRTfUzK/g==}
|
||||
|
||||
'@shikijs/vscode-textmate@10.0.2':
|
||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||
@@ -1956,8 +1953,8 @@ packages:
|
||||
'@types/lodash-es@4.17.12':
|
||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||
|
||||
'@types/lodash@4.17.20':
|
||||
resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==}
|
||||
'@types/lodash@4.17.21':
|
||||
resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
||||
@@ -2174,9 +2171,6 @@ packages:
|
||||
'@vue/compiler-core@3.5.13':
|
||||
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
|
||||
|
||||
'@vue/compiler-core@3.5.22':
|
||||
resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==}
|
||||
|
||||
'@vue/compiler-core@3.5.24':
|
||||
resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==}
|
||||
|
||||
@@ -2186,9 +2180,6 @@ packages:
|
||||
'@vue/compiler-dom@3.5.13':
|
||||
resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==}
|
||||
|
||||
'@vue/compiler-dom@3.5.22':
|
||||
resolution: {integrity: sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==}
|
||||
|
||||
'@vue/compiler-dom@3.5.24':
|
||||
resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==}
|
||||
|
||||
@@ -2225,8 +2216,8 @@ packages:
|
||||
'@vue/devtools-shared@7.7.7':
|
||||
resolution: {integrity: sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==}
|
||||
|
||||
'@vue/language-core@3.1.3':
|
||||
resolution: {integrity: sha512-KpR1F/eGAG9D1RZ0/T6zWJs6dh/pRLfY5WupecyYKJ1fjVmDMgTPw9wXmKv2rBjo4zCJiOSiyB8BDP1OUwpMEA==}
|
||||
'@vue/language-core@3.1.5':
|
||||
resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
@@ -2312,8 +2303,8 @@ packages:
|
||||
alien-signals@2.0.8:
|
||||
resolution: {integrity: sha512-844G1VLkk0Pe2SJjY0J8vp8ADI73IM4KliNu2OGlYzWpO28NexEUvjHTcFjFX3VXoiUtwTbHxLNI9ImkcoBqzA==}
|
||||
|
||||
alien-signals@3.0.5:
|
||||
resolution: {integrity: sha512-+2bRQFO1f9GLeIabDQWJlluL1NspZlLjpjaSSwwpl+9Tz5tS/3KrceHdwjNvIMEbYWSpoqtOPuXLTSoPgvIEWw==}
|
||||
alien-signals@3.1.1:
|
||||
resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==}
|
||||
|
||||
ansi-align@3.0.1:
|
||||
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
|
||||
@@ -2774,6 +2765,9 @@ packages:
|
||||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
cwise-compiler@1.1.3:
|
||||
resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==}
|
||||
|
||||
@@ -2954,8 +2948,8 @@ packages:
|
||||
peerDependencies:
|
||||
date-fns: ^3.0.0 || ^4.0.0
|
||||
|
||||
date-fns@3.6.0:
|
||||
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
|
||||
date-fns@4.1.0:
|
||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||
|
||||
dayjs@1.11.19:
|
||||
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
|
||||
@@ -3324,10 +3318,6 @@ packages:
|
||||
git-url-parse@14.0.0:
|
||||
resolution: {integrity: sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==}
|
||||
|
||||
github-markdown-css@5.8.1:
|
||||
resolution: {integrity: sha512-8G+PFvqigBQSWLQjyzgpa2ThD9bo7+kDsriUIidGcRhXgmcaAWUIpCZf8DavJgc+xifjbCG+GvMyWr0XMXmc7g==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -3471,8 +3461,8 @@ packages:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
immutable@5.1.3:
|
||||
resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==}
|
||||
immutable@5.1.4:
|
||||
resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||
@@ -3933,8 +3923,8 @@ packages:
|
||||
engines: {node: '>= 20'}
|
||||
hasBin: true
|
||||
|
||||
mdast-util-to-hast@13.2.0:
|
||||
resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
|
||||
mdast-util-to-hast@13.2.1:
|
||||
resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==}
|
||||
|
||||
mdn-data@2.12.2:
|
||||
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
|
||||
@@ -4059,8 +4049,8 @@ packages:
|
||||
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
|
||||
engines: {node: ^18.17.0 || >=20.5.0}
|
||||
|
||||
naive-ui@2.43.1:
|
||||
resolution: {integrity: sha512-w52W0mOhdOGt4uucFSZmP0DI44PCsFyuxeLSs9aoUThfIuxms90MYjv46Qrr7xprjyJRw5RU6vYpCx4o9ind3A==}
|
||||
naive-ui@2.43.2:
|
||||
resolution: {integrity: sha512-YlLMnGrwGTOc+zMj90sG3ubaH5/7czsgLgGcjTLA981IUaz8r6t4WIujNt8r9PNr+dqv6XNEr0vxkARgPPjfBQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
@@ -4142,8 +4132,8 @@ packages:
|
||||
oniguruma-parser@0.12.1:
|
||||
resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
|
||||
|
||||
oniguruma-to-es@4.3.3:
|
||||
resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==}
|
||||
oniguruma-to-es@4.3.4:
|
||||
resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==}
|
||||
|
||||
open@10.1.0:
|
||||
resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
|
||||
@@ -4315,11 +4305,11 @@ packages:
|
||||
peerDependencies:
|
||||
pinia: ^3.0.0
|
||||
|
||||
pinia@3.0.3:
|
||||
resolution: {integrity: sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==}
|
||||
pinia@3.0.4:
|
||||
resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==}
|
||||
peerDependencies:
|
||||
typescript: '>=4.4.4'
|
||||
vue: ^2.7.0 || ^3.5.11
|
||||
typescript: '>=4.5.0'
|
||||
vue: ^3.5.11
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
@@ -4529,8 +4519,8 @@ packages:
|
||||
safer-buffer@2.1.2:
|
||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||
|
||||
sass@1.93.2:
|
||||
resolution: {integrity: sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==}
|
||||
sass@1.94.2:
|
||||
resolution: {integrity: sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -4581,8 +4571,8 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
shiki@3.15.0:
|
||||
resolution: {integrity: sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw==}
|
||||
shiki@3.17.0:
|
||||
resolution: {integrity: sha512-lUZfWsyW7czITYTdo/Tb6ZM4VfyXlzmKYBQBjTz+pBzPPkP08RgIt00Ls1Z50Cl3SfwJsue6WbJeF3UgqLVI9Q==}
|
||||
|
||||
siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
@@ -4680,8 +4670,8 @@ packages:
|
||||
peerDependencies:
|
||||
shiki: '>=3.13.0'
|
||||
|
||||
stream-monaco@0.0.6:
|
||||
resolution: {integrity: sha512-ZyhDI9rIhcWEw7ld8az8Qu2Iug1pL4lwR+V/yzxuOok72mBPvSR3LVbOUxq7Rcb6dF1it2BWDmpiORJcw5c7kw==}
|
||||
stream-monaco@0.0.7:
|
||||
resolution: {integrity: sha512-VqqEpuOptFw1K/hDxCFZ2sA8dgTFdON0SdKovfddeJMK7vaS3jddkDl41D2avq4mpQ6x2fnYXSEXsmc5oswdlA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
monaco-editor: ^0.52.2
|
||||
@@ -5215,8 +5205,8 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
|
||||
vue-tsc@3.1.3:
|
||||
resolution: {integrity: sha512-StMNfZHwPIXQgY3KxPKM0Jsoc8b46mDV3Fn2UlHCBIwRJApjqrSwqeMYgWf0zpN+g857y74pv7GWuBm+UqQe1w==}
|
||||
vue-tsc@3.1.5:
|
||||
resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: '>=5.0.0'
|
||||
@@ -6561,39 +6551,39 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.53.1':
|
||||
optional: true
|
||||
|
||||
'@shikijs/core@3.15.0':
|
||||
'@shikijs/core@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/types': 3.17.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-to-html: 9.0.5
|
||||
|
||||
'@shikijs/engine-javascript@3.15.0':
|
||||
'@shikijs/engine-javascript@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/types': 3.17.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
oniguruma-to-es: 4.3.3
|
||||
oniguruma-to-es: 4.3.4
|
||||
|
||||
'@shikijs/engine-oniguruma@3.15.0':
|
||||
'@shikijs/engine-oniguruma@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/types': 3.17.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
|
||||
'@shikijs/langs@3.15.0':
|
||||
'@shikijs/langs@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/types': 3.17.0
|
||||
|
||||
'@shikijs/monaco@3.15.0':
|
||||
'@shikijs/monaco@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/core': 3.15.0
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/core': 3.17.0
|
||||
'@shikijs/types': 3.17.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
|
||||
'@shikijs/themes@3.15.0':
|
||||
'@shikijs/themes@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/types': 3.17.0
|
||||
|
||||
'@shikijs/types@3.15.0':
|
||||
'@shikijs/types@3.17.0':
|
||||
dependencies:
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
@@ -6869,9 +6859,9 @@ snapshots:
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
'@types/lodash': 4.17.20
|
||||
'@types/lodash': 4.17.21
|
||||
|
||||
'@types/lodash@4.17.20': {}
|
||||
'@types/lodash@4.17.21': {}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
dependencies:
|
||||
@@ -6965,7 +6955,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@unocss/core': 66.5.4
|
||||
|
||||
'@unocss/vite@66.5.4(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))':
|
||||
'@unocss/vite@66.5.4(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
'@unocss/config': 66.5.4
|
||||
@@ -6976,7 +6966,7 @@ snapshots:
|
||||
pathe: 2.0.3
|
||||
tinyglobby: 0.2.15
|
||||
unplugin-utils: 0.3.1
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
|
||||
'@vant/area-data@2.1.0': {}
|
||||
|
||||
@@ -6986,22 +6976,22 @@ snapshots:
|
||||
dependencies:
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
|
||||
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.4
|
||||
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4)
|
||||
'@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4)
|
||||
'@rolldown/pluginutils': 1.0.0-beta.41
|
||||
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.4)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-vue@6.0.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))':
|
||||
'@vitejs/plugin-vue@6.0.1(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))(vue@3.5.25(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.29
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
|
||||
'@vitest/coverage-v8@4.0.8(vitest@4.0.8)':
|
||||
@@ -7017,7 +7007,7 @@ snapshots:
|
||||
magicast: 0.5.1
|
||||
std-env: 3.10.0
|
||||
tinyrainbow: 3.0.3
|
||||
vitest: 4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vitest: 4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7030,13 +7020,13 @@ snapshots:
|
||||
chai: 6.2.0
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vitest/mocker@4.0.8(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))':
|
||||
'@vitest/mocker@4.0.8(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.0.8
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
|
||||
'@vitest/pretty-format@4.0.8':
|
||||
dependencies:
|
||||
@@ -7064,7 +7054,7 @@ snapshots:
|
||||
sirv: 3.0.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vitest: 4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vitest: 4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
|
||||
'@vitest/utils@4.0.8':
|
||||
dependencies:
|
||||
@@ -7140,14 +7130,6 @@ snapshots:
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-core@3.5.22':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@vue/shared': 3.5.22
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-core@3.5.24':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
@@ -7169,11 +7151,6 @@ snapshots:
|
||||
'@vue/compiler-core': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
|
||||
'@vue/compiler-dom@3.5.22':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
|
||||
'@vue/compiler-dom@3.5.24':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.24
|
||||
@@ -7255,12 +7232,12 @@ snapshots:
|
||||
dependencies:
|
||||
rfdc: 1.4.1
|
||||
|
||||
'@vue/language-core@3.1.3(typescript@5.9.3)':
|
||||
'@vue/language-core@3.1.5(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@volar/language-core': 2.4.23
|
||||
'@vue/compiler-dom': 3.5.22
|
||||
'@vue/shared': 3.5.22
|
||||
alien-signals: 3.0.5
|
||||
'@vue/compiler-dom': 3.5.25
|
||||
'@vue/shared': 3.5.25
|
||||
alien-signals: 3.1.1
|
||||
muggle-string: 0.4.1
|
||||
path-browserify: 1.0.1
|
||||
picomatch: 4.0.3
|
||||
@@ -7347,7 +7324,7 @@ snapshots:
|
||||
|
||||
alien-signals@2.0.8: {}
|
||||
|
||||
alien-signals@3.0.5: {}
|
||||
alien-signals@3.1.1: {}
|
||||
|
||||
ansi-align@3.0.1:
|
||||
dependencies:
|
||||
@@ -7832,6 +7809,8 @@ snapshots:
|
||||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
cwise-compiler@1.1.3:
|
||||
dependencies:
|
||||
uniq: 1.0.1
|
||||
@@ -8040,11 +8019,11 @@ snapshots:
|
||||
|
||||
data-uri-to-buffer@6.0.2: {}
|
||||
|
||||
date-fns-tz@3.2.0(date-fns@3.6.0):
|
||||
date-fns-tz@3.2.0(date-fns@4.1.0):
|
||||
dependencies:
|
||||
date-fns: 3.6.0
|
||||
date-fns: 4.1.0
|
||||
|
||||
date-fns@3.6.0: {}
|
||||
date-fns@4.1.0: {}
|
||||
|
||||
dayjs@1.11.19: {}
|
||||
|
||||
@@ -8446,8 +8425,6 @@ snapshots:
|
||||
dependencies:
|
||||
git-up: 7.0.0
|
||||
|
||||
github-markdown-css@5.8.1: {}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
@@ -8542,7 +8519,7 @@ snapshots:
|
||||
comma-separated-tokens: 2.0.3
|
||||
hast-util-whitespace: 3.0.0
|
||||
html-void-elements: 3.0.0
|
||||
mdast-util-to-hast: 13.2.0
|
||||
mdast-util-to-hast: 13.2.1
|
||||
property-information: 7.1.0
|
||||
space-separated-tokens: 2.0.2
|
||||
stringify-entities: 4.0.4
|
||||
@@ -8608,7 +8585,7 @@ snapshots:
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
immutable@5.1.3: {}
|
||||
immutable@5.1.4: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
@@ -9031,7 +9008,7 @@ snapshots:
|
||||
|
||||
marked@16.4.1: {}
|
||||
|
||||
mdast-util-to-hast@13.2.0:
|
||||
mdast-util-to-hast@13.2.1:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -9161,18 +9138,18 @@ snapshots:
|
||||
|
||||
mute-stream@2.0.0: {}
|
||||
|
||||
naive-ui@2.43.1(vue@3.5.25(typescript@5.9.3)):
|
||||
naive-ui@2.43.2(vue@3.5.25(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@css-render/plugin-bem': 0.15.14(css-render@0.15.14)
|
||||
'@css-render/vue3-ssr': 0.15.14(vue@3.5.25(typescript@5.9.3))
|
||||
'@types/katex': 0.16.7
|
||||
'@types/lodash': 4.17.20
|
||||
'@types/lodash': 4.17.21
|
||||
'@types/lodash-es': 4.17.12
|
||||
async-validator: 4.2.5
|
||||
css-render: 0.15.14
|
||||
csstype: 3.1.3
|
||||
date-fns: 3.6.0
|
||||
date-fns-tz: 3.2.0(date-fns@3.6.0)
|
||||
csstype: 3.2.3
|
||||
date-fns: 4.1.0
|
||||
date-fns-tz: 3.2.0(date-fns@4.1.0)
|
||||
evtd: 0.2.4
|
||||
highlight.js: 11.11.1
|
||||
lodash: 4.17.21
|
||||
@@ -9257,7 +9234,7 @@ snapshots:
|
||||
|
||||
oniguruma-parser@0.12.1: {}
|
||||
|
||||
oniguruma-to-es@4.3.3:
|
||||
oniguruma-to-es@4.3.4:
|
||||
dependencies:
|
||||
oniguruma-parser: 0.12.1
|
||||
regex: 6.0.1
|
||||
@@ -9423,18 +9400,18 @@ snapshots:
|
||||
|
||||
pidtree@0.6.0: {}
|
||||
|
||||
pinia-plugin-persistedstate@4.7.1(pinia@3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))):
|
||||
pinia-plugin-persistedstate@4.7.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))):
|
||||
dependencies:
|
||||
defu: 6.1.4
|
||||
optionalDependencies:
|
||||
pinia: 3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
pinia: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
|
||||
pinia-shared-state@1.0.1(pinia@3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))):
|
||||
pinia-shared-state@1.0.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))):
|
||||
dependencies:
|
||||
broadcast-channel: 7.0.0
|
||||
pinia: 3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
pinia: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||
|
||||
pinia@3.0.3(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)):
|
||||
pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@vue/devtools-api': 7.7.7
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
@@ -9698,10 +9675,10 @@ snapshots:
|
||||
|
||||
safer-buffer@2.1.2: {}
|
||||
|
||||
sass@1.93.2:
|
||||
sass@1.94.2:
|
||||
dependencies:
|
||||
chokidar: 4.0.3
|
||||
immutable: 5.1.3
|
||||
immutable: 5.1.4
|
||||
source-map-js: 1.2.1
|
||||
optionalDependencies:
|
||||
'@parcel/watcher': 2.5.1
|
||||
@@ -9758,14 +9735,14 @@ snapshots:
|
||||
interpret: 1.4.0
|
||||
rechoir: 0.6.2
|
||||
|
||||
shiki@3.15.0:
|
||||
shiki@3.17.0:
|
||||
dependencies:
|
||||
'@shikijs/core': 3.15.0
|
||||
'@shikijs/engine-javascript': 3.15.0
|
||||
'@shikijs/engine-oniguruma': 3.15.0
|
||||
'@shikijs/langs': 3.15.0
|
||||
'@shikijs/themes': 3.15.0
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/core': 3.17.0
|
||||
'@shikijs/engine-javascript': 3.17.0
|
||||
'@shikijs/engine-oniguruma': 3.17.0
|
||||
'@shikijs/langs': 3.17.0
|
||||
'@shikijs/themes': 3.17.0
|
||||
'@shikijs/types': 3.17.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
@@ -9859,16 +9836,16 @@ snapshots:
|
||||
markdown-it-task-checkbox: 1.0.6
|
||||
markdown-it-ts: 0.0.2-beta.3
|
||||
|
||||
stream-markdown@0.0.10(shiki@3.15.0):
|
||||
stream-markdown@0.0.10(shiki@3.17.0):
|
||||
dependencies:
|
||||
shiki: 3.15.0
|
||||
shiki: 3.17.0
|
||||
|
||||
stream-monaco@0.0.6(monaco-editor@0.52.2):
|
||||
stream-monaco@0.0.7(monaco-editor@0.52.2):
|
||||
dependencies:
|
||||
'@shikijs/monaco': 3.15.0
|
||||
'@shikijs/monaco': 3.17.0
|
||||
alien-signals: 2.0.8
|
||||
monaco-editor: 0.52.2
|
||||
shiki: 3.15.0
|
||||
shiki: 3.17.0
|
||||
|
||||
string-argv@0.3.2: {}
|
||||
|
||||
@@ -10230,13 +10207,13 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vite-plugin-vue-setup-extend@0.4.0(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)):
|
||||
vite-plugin-vue-setup-extend@0.4.0(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
'@vue/compiler-sfc': 3.5.13
|
||||
magic-string: 0.25.9
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
|
||||
vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1):
|
||||
vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -10248,15 +10225,15 @@ snapshots:
|
||||
'@types/node': 24.10.0
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
sass: 1.93.2
|
||||
sass: 1.94.2
|
||||
terser: 5.37.0
|
||||
tsx: 4.19.2
|
||||
yaml: 2.8.1
|
||||
|
||||
vitest@4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1):
|
||||
vitest@4.0.8(@types/node@24.10.0)(@vitest/ui@4.0.8)(happy-dom@20.0.2)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.8
|
||||
'@vitest/mocker': 4.0.8(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))
|
||||
'@vitest/mocker': 4.0.8(vite@7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1))
|
||||
'@vitest/pretty-format': 4.0.8
|
||||
'@vitest/runner': 4.0.8
|
||||
'@vitest/snapshot': 4.0.8
|
||||
@@ -10273,7 +10250,7 @@ snapshots:
|
||||
tinyexec: 0.3.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.93.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
vite: 7.2.4(@types/node@24.10.0)(jiti@2.6.1)(sass@1.94.2)(terser@5.37.0)(tsx@4.19.2)(yaml@2.8.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 24.10.0
|
||||
@@ -10338,7 +10315,7 @@ snapshots:
|
||||
dependencies:
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
|
||||
vue-renderer-markdown@0.0.62-beta.1(katex@0.16.25)(mermaid@11.12.1)(shiki@3.15.0)(stream-markdown@0.0.10(shiki@3.15.0))(stream-monaco@0.0.6(monaco-editor@0.52.2))(vue-i18n@11.1.12(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)):
|
||||
vue-renderer-markdown@0.0.62-beta.1(katex@0.16.25)(mermaid@11.12.1)(shiki@3.17.0)(stream-markdown@0.0.10(shiki@3.17.0))(stream-monaco@0.0.7(monaco-editor@0.52.2))(vue-i18n@11.1.12(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.7.4
|
||||
stream-markdown-parser: 0.0.19
|
||||
@@ -10346,9 +10323,9 @@ snapshots:
|
||||
optionalDependencies:
|
||||
katex: 0.16.25
|
||||
mermaid: 11.12.1
|
||||
shiki: 3.15.0
|
||||
stream-markdown: 0.0.10(shiki@3.15.0)
|
||||
stream-monaco: 0.0.6(monaco-editor@0.52.2)
|
||||
shiki: 3.17.0
|
||||
stream-markdown: 0.0.10(shiki@3.17.0)
|
||||
stream-monaco: 0.0.7(monaco-editor@0.52.2)
|
||||
vue-i18n: 11.1.12(vue@3.5.25(typescript@5.9.3))
|
||||
|
||||
vue-resize@2.0.0-alpha.1(vue@3.5.25(typescript@5.9.3)):
|
||||
@@ -10360,10 +10337,10 @@ snapshots:
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.25(typescript@5.9.3)
|
||||
|
||||
vue-tsc@3.1.3(typescript@5.9.3):
|
||||
vue-tsc@3.1.5(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@volar/typescript': 2.4.23
|
||||
'@vue/language-core': 3.1.3(typescript@5.9.3)
|
||||
'@vue/language-core': 3.1.5(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
|
||||
vue-virtual-scroller@2.0.0-beta.8(vue@3.5.25(typescript@5.9.3)):
|
||||
|
||||
@@ -109,7 +109,6 @@ import { isDesktop } from '@/utils/PlatformConstants'
|
||||
import { useBotStore } from '@/stores/bot'
|
||||
import { useAssistantModelPresets, type AssistantModelPreset } from '@/hooks/useAssistantModelPresets'
|
||||
import HuLaAssistant from './HuLaAssistant.vue'
|
||||
import 'github-markdown-css/github-markdown.css'
|
||||
|
||||
// 当前语言
|
||||
const currentLang = ref<'zh' | 'en'>('zh')
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
type LocationData = {
|
||||
latitude: number
|
||||
longitude: number
|
||||
@@ -51,6 +52,7 @@ const props = withDefaults(defineProps<LocationMapProps>(), {
|
||||
})
|
||||
|
||||
const emit = defineEmits<LocationMapEmits>()
|
||||
const { t } = useI18n()
|
||||
|
||||
// 地图实例和状态
|
||||
const mapRef = ref()
|
||||
@@ -91,7 +93,7 @@ const markerGeometries = computed(() => [
|
||||
id: 'current',
|
||||
styleId: 'current-location',
|
||||
position: mapCenter.value,
|
||||
properties: { title: '当前位置' },
|
||||
properties: { title: t('message.location.map.marker_current') },
|
||||
draggable: props.draggable
|
||||
}
|
||||
])
|
||||
|
||||
@@ -25,11 +25,15 @@
|
||||
|
||||
<!-- 地图加载错误 -->
|
||||
<div v-if="mapError" class="h-340px flex-center">
|
||||
<n-result status="error" title="地图加载失败" :description="mapError">
|
||||
<n-result status="error" :title="t('message.location.modal.result.map_error_title')" :description="mapError">
|
||||
<template #footer>
|
||||
<n-flex justify="center" :size="12">
|
||||
<n-button secondary @click="modalVisible = false">取消</n-button>
|
||||
<n-button type="primary" secondary @click="retryMapLoad">重试</n-button>
|
||||
<n-button secondary @click="modalVisible = false">
|
||||
{{ t('message.location.modal.buttons.cancel') }}
|
||||
</n-button>
|
||||
<n-button type="primary" secondary @click="retryMapLoad">
|
||||
{{ t('message.location.modal.buttons.retry') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-result>
|
||||
@@ -37,11 +41,18 @@
|
||||
|
||||
<!-- 位置获取失败 -->
|
||||
<div v-else-if="locationState.error && !selectedLocation" class="h-340px flex-center">
|
||||
<n-result status="warning" title="位置获取失败" :description="locationState.error">
|
||||
<n-result
|
||||
status="warning"
|
||||
:title="t('message.location.modal.result.location_error_title')"
|
||||
:description="locationState.error">
|
||||
<template #footer>
|
||||
<n-flex justify="center" :size="12">
|
||||
<n-button secondary @click="modalVisible = false">取消</n-button>
|
||||
<n-button type="primary" secondary @click="relocate">重试</n-button>
|
||||
<n-button secondary @click="modalVisible = false">
|
||||
{{ t('message.location.modal.buttons.cancel') }}
|
||||
</n-button>
|
||||
<n-button type="primary" secondary @click="relocate">
|
||||
{{ t('message.location.modal.buttons.retry') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-result>
|
||||
@@ -54,7 +65,13 @@
|
||||
<!-- 地图加载中 -->
|
||||
<div v-if="locationState.loading || mapLoading" class="flex-col-center gap-42px">
|
||||
<n-spin :size="42" />
|
||||
<p class="text-(14px [--text-cplor])">{{ locationState.loading ? '正在获取位置...' : '地图加载中...' }}</p>
|
||||
<p class="text-(14px [--text-cplor])">
|
||||
{{
|
||||
locationState.loading
|
||||
? t('message.location.modal.loading.locating')
|
||||
: t('message.location.modal.loading.map')
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 地图组件 -->
|
||||
@@ -72,12 +89,17 @@
|
||||
<!-- 位置信息显示 -->
|
||||
<div v-if="selectedLocation" class="rounded-6px bg-#fefefe dark:bg-#303030 p-12px">
|
||||
<n-flex vertical :size="8">
|
||||
<span class="text-14px font-medium">当前位置</span>
|
||||
<span class="text-14px font-medium">{{ t('message.location.modal.info.current') }}</span>
|
||||
<div class="text-12px text-gray-500">
|
||||
{{ selectedLocation.address || '获取地址中...' }}
|
||||
{{ selectedLocation.address || t('message.location.modal.info.fetching_address') }}
|
||||
</div>
|
||||
<div class="text-11px text-gray-400">
|
||||
坐标: {{ selectedLocation.latitude.toFixed(6) }}, {{ selectedLocation.longitude.toFixed(6) }}
|
||||
{{
|
||||
t('message.location.modal.info.coordinate', {
|
||||
lat: selectedLocation.latitude.toFixed(6),
|
||||
lng: selectedLocation.longitude.toFixed(6)
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
</n-flex>
|
||||
</div>
|
||||
@@ -85,7 +107,9 @@
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<n-flex v-if="showActionButtons" align="center" :size="24" class="py-8px">
|
||||
<n-button type="primary" secondary :loading="sendingLocation" @click="handleConfirm">发送位置</n-button>
|
||||
<n-button type="primary" secondary :loading="sendingLocation" @click="handleConfirm">
|
||||
{{ t('message.location.modal.buttons.send') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</div>
|
||||
</n-modal>
|
||||
@@ -97,6 +121,7 @@ import { reverseGeocode } from '@/services/mapApi'
|
||||
import { getSettings } from '@/services/tauriCommand'
|
||||
import { isMac, isWindows } from '@/utils/PlatformConstants'
|
||||
import LocationMap from './LocationMap.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
type LocationData = {
|
||||
latitude: number
|
||||
@@ -136,11 +161,13 @@ const mapError = ref<string | null>(null)
|
||||
const sendingLocation = ref(false)
|
||||
const apiKey = ref('')
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
// 计算属性
|
||||
const modalTitle = computed(() => {
|
||||
if (mapError.value) return '地图错误'
|
||||
if (locationState.error) return '位置获取失败'
|
||||
return '选择位置'
|
||||
if (mapError.value) return t('message.location.modal.title.map_error')
|
||||
if (locationState.error) return t('message.location.modal.title.location_error')
|
||||
return t('message.location.modal.title.default')
|
||||
})
|
||||
|
||||
const showActionButtons = computed(() => {
|
||||
@@ -163,15 +190,20 @@ const getLocation = async () => {
|
||||
// 设置 API key
|
||||
apiKey.value = settings.tencent?.map_key || ''
|
||||
if (!apiKey.value) {
|
||||
throw new Error('腾讯地图API密钥未配置')
|
||||
const missingKeyMsg = t('message.location.modal.errors.missing_api_key')
|
||||
mapError.value = missingKeyMsg
|
||||
throw new Error(missingKeyMsg)
|
||||
}
|
||||
|
||||
// 获取地址信息
|
||||
const geocodeResult = await reverseGeocode(result.transformed.lat, result.transformed.lng).catch((error) => {
|
||||
console.warn('获取地址失败:', error)
|
||||
console.warn(t('message.location.modal.errors.geocode_failed'), error)
|
||||
return null
|
||||
})
|
||||
const address = geocodeResult?.formatted_addresses?.recommend || geocodeResult?.address || '未知地址'
|
||||
const address =
|
||||
geocodeResult?.formatted_addresses?.recommend ||
|
||||
geocodeResult?.address ||
|
||||
t('message.location.modal.info.unknown_address')
|
||||
|
||||
selectedLocation.value = {
|
||||
latitude: result.transformed.lat,
|
||||
@@ -216,7 +248,7 @@ const handleLocationChange = async (newLocation: { lat: number; lng: number }) =
|
||||
|
||||
// 获取新位置的地址
|
||||
const geocodeResult = await reverseGeocode(newLocation.lat, newLocation.lng).catch((error) => {
|
||||
console.warn('获取地址失败:', error)
|
||||
console.warn(t('message.location.modal.errors.geocode_failed'), error)
|
||||
return null
|
||||
})
|
||||
const address =
|
||||
|
||||
@@ -455,7 +455,7 @@ export const useChatMain = (isHistoryMode = false, options: UseChatMainOptions =
|
||||
},
|
||||
|
||||
{
|
||||
label: () => (isMac() ? t('menu.show_in_finder') : t('menu.open_folder')),
|
||||
label: () => (isMac() ? t('menu.show_in_finder') : t('menu.show_in_folder')),
|
||||
icon: 'file2',
|
||||
click: async (item: RightMouseMessageItem) => {
|
||||
console.log('打开文件夹的item项:', item)
|
||||
@@ -655,7 +655,7 @@ export const useChatMain = (isHistoryMode = false, options: UseChatMainOptions =
|
||||
},
|
||||
|
||||
{
|
||||
label: () => (isMac() ? t('menu.show_in_finder') : t('menu.open_folder')),
|
||||
label: () => (isMac() ? t('menu.show_in_finder') : t('menu.show_in_folder')),
|
||||
icon: 'file2',
|
||||
click: async (item: RightMouseMessageItem) => {
|
||||
console.log('打开文件夹的item项:', item)
|
||||
@@ -750,7 +750,7 @@ export const useChatMain = (isHistoryMode = false, options: UseChatMainOptions =
|
||||
}
|
||||
},
|
||||
{
|
||||
label: () => (isMac() ? t('menu.show_in_finder') : t('menu.open_folder')),
|
||||
label: () => (isMac() ? t('menu.show_in_finder') : t('menu.show_in_folder')),
|
||||
icon: 'file2',
|
||||
click: async (item: MessageType) => {
|
||||
const fileUrl = item.message.body.url || item.message.body.content
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { transformCoordinates } from '@/services/mapApi'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
type GeolocationState = {
|
||||
loading: boolean
|
||||
@@ -15,6 +16,7 @@ type GeolocationOptions = {
|
||||
}
|
||||
|
||||
export const useGeolocation = () => {
|
||||
const { t } = useI18n()
|
||||
const state = ref<GeolocationState>({
|
||||
loading: false,
|
||||
error: null,
|
||||
@@ -37,7 +39,7 @@ export const useGeolocation = () => {
|
||||
state.value.permission = permission.state
|
||||
return permission.state
|
||||
} catch (error) {
|
||||
console.warn('检查地理位置权限失败:', error)
|
||||
console.warn(t('message.location.hook.permission_check_failed'), error)
|
||||
}
|
||||
}
|
||||
return 'prompt'
|
||||
@@ -47,7 +49,8 @@ export const useGeolocation = () => {
|
||||
const getCurrentPosition = async (options?: GeolocationOptions): Promise<GeolocationPosition> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!navigator.geolocation) {
|
||||
reject(new Error('浏览器不支持地理位置功能'))
|
||||
const unsupportedError = t('message.location.hook.unsupported')
|
||||
reject(new Error(unsupportedError))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,17 +72,17 @@ export const useGeolocation = () => {
|
||||
},
|
||||
(error) => {
|
||||
state.value.loading = false
|
||||
let errorMessage = '获取位置失败'
|
||||
let errorMessage = t('message.location.hook.error_generic')
|
||||
|
||||
switch (error.code) {
|
||||
case error.PERMISSION_DENIED:
|
||||
errorMessage = '位置权限被拒绝'
|
||||
errorMessage = t('message.location.hook.permission_denied')
|
||||
break
|
||||
case error.POSITION_UNAVAILABLE:
|
||||
errorMessage = '位置信息不可用'
|
||||
errorMessage = t('message.location.hook.position_unavailable')
|
||||
break
|
||||
case error.TIMEOUT:
|
||||
errorMessage = '获取位置超时'
|
||||
errorMessage = t('message.location.hook.timeout')
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -861,6 +861,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { fetch as nativeFetch } from '@tauri-apps/plugin-http'
|
||||
import { type InputInst, UploadFileInfo } from 'naive-ui'
|
||||
import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
@@ -1026,70 +1027,123 @@ const conversationTokens = computed(() => {
|
||||
})
|
||||
const serverTokenUsage = ref<number | null>(null)
|
||||
|
||||
type ImageWorkerResponse = {
|
||||
success: boolean
|
||||
url: string
|
||||
buffer?: ArrayBuffer
|
||||
error?: string
|
||||
}
|
||||
const aiMediaDownloadTasks = new Map<string, Promise<ArrayBuffer>>()
|
||||
|
||||
type ImageWorkerWaiter = {
|
||||
resolve: (buffer: ArrayBuffer) => void
|
||||
reject: (reason?: unknown) => void
|
||||
}
|
||||
// 将各种可能的二进制返回形式统一转成 ArrayBuffer,兼容 plugin-http/浏览器 fetch 等场景
|
||||
const convertHttpDataToArrayBuffer = (rawData: unknown): ArrayBuffer => {
|
||||
if (rawData === null || rawData === undefined) {
|
||||
throw new Error('图片数据为空')
|
||||
}
|
||||
|
||||
const aiImageWorkerRequests = new Map<string, ImageWorkerWaiter[]>()
|
||||
let aiImageDownloadWorker: Worker | null = null
|
||||
const aiImageWorkerUrl = new URL('../../../workers/imageDownloader.ts', import.meta.url)
|
||||
if (rawData instanceof ArrayBuffer) {
|
||||
return rawData
|
||||
}
|
||||
|
||||
const ensureAiImageWorker = () => {
|
||||
if (aiImageDownloadWorker || typeof window === 'undefined') return
|
||||
aiImageDownloadWorker = new Worker(aiImageWorkerUrl, { type: 'module' })
|
||||
aiImageDownloadWorker.onmessage = (event: MessageEvent<ImageWorkerResponse>) => {
|
||||
const { url, success, buffer, error } = event.data
|
||||
const waiters = aiImageWorkerRequests.get(url)
|
||||
if (!waiters?.length) return
|
||||
aiImageWorkerRequests.delete(url)
|
||||
if (!success || !buffer) {
|
||||
waiters.forEach(({ reject }) => reject(new Error(error || '下载失败')))
|
||||
return
|
||||
if (rawData instanceof Uint8Array) {
|
||||
return rawData.slice().buffer
|
||||
}
|
||||
|
||||
if (ArrayBuffer.isView(rawData)) {
|
||||
// 复制一份,避免 SharedArrayBuffer 类型不兼容
|
||||
const view = rawData as ArrayBufferView
|
||||
const copy = new Uint8Array(view.byteLength)
|
||||
copy.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength))
|
||||
return copy.buffer
|
||||
}
|
||||
|
||||
if (Array.isArray(rawData)) {
|
||||
return Uint8Array.from(rawData).buffer
|
||||
}
|
||||
|
||||
if (typeof rawData === 'object') {
|
||||
const maybeData = (rawData as { data?: number[] }).data
|
||||
if (Array.isArray(maybeData)) {
|
||||
return Uint8Array.from(maybeData).buffer
|
||||
}
|
||||
waiters.forEach(({ resolve }) => resolve(buffer))
|
||||
}
|
||||
|
||||
if (typeof rawData === 'string') {
|
||||
const binaryString = atob(rawData)
|
||||
const len = binaryString.length
|
||||
const bytes = new Uint8Array(len)
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i)
|
||||
}
|
||||
return bytes.buffer
|
||||
}
|
||||
|
||||
throw new Error('无法解析图片数据')
|
||||
}
|
||||
|
||||
const requestAiImageBuffer = (url: string) => {
|
||||
ensureAiImageWorker()
|
||||
if (!aiImageDownloadWorker) {
|
||||
return Promise.reject(new Error('Web Worker 不可用'))
|
||||
// 下载 AI 媒体的二进制数据:同 URL 复用 Promise,避免重复下载;按 plugin-http 的多种返回形态兜底
|
||||
const requestAiMediaBuffer = (url: string) => {
|
||||
if (!url) {
|
||||
return Promise.reject(new Error('图片地址无效'))
|
||||
}
|
||||
const waiters = aiImageWorkerRequests.get(url)
|
||||
if (waiters && waiters.length > 0) {
|
||||
return new Promise<ArrayBuffer>((resolve, reject) => {
|
||||
waiters.push({ resolve, reject })
|
||||
|
||||
const existingTask = aiMediaDownloadTasks.get(url)
|
||||
if (existingTask) {
|
||||
return existingTask
|
||||
}
|
||||
|
||||
const downloadTask = (async () => {
|
||||
const response = await nativeFetch(url, {
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
return new Promise<ArrayBuffer>((resolve, reject) => {
|
||||
aiImageWorkerRequests.set(url, [{ resolve, reject }])
|
||||
aiImageDownloadWorker!.postMessage({ url })
|
||||
|
||||
const anyResponse = response as any
|
||||
const status = typeof anyResponse.status === 'number' ? anyResponse.status : 200
|
||||
const statusText = typeof anyResponse.statusText === 'string' ? anyResponse.statusText : ''
|
||||
const ok = 'ok' in anyResponse ? Boolean(anyResponse.ok) : status >= 200 && status < 400
|
||||
|
||||
if (!ok) {
|
||||
throw new Error(`下载失败: ${status} ${statusText}`.trim())
|
||||
}
|
||||
|
||||
// 优先使用标准的 arrayBuffer
|
||||
if (typeof anyResponse.arrayBuffer === 'function') {
|
||||
const buffer = await anyResponse.arrayBuffer()
|
||||
if (buffer instanceof ArrayBuffer) {
|
||||
return buffer
|
||||
}
|
||||
}
|
||||
|
||||
// plugin-http 额外提供的 bytes 方法
|
||||
if (typeof anyResponse.bytes === 'function') {
|
||||
const bytes = await anyResponse.bytes()
|
||||
return convertHttpDataToArrayBuffer(bytes)
|
||||
}
|
||||
|
||||
// 最后回退 data 字段
|
||||
if ('data' in anyResponse) {
|
||||
return convertHttpDataToArrayBuffer(anyResponse.data)
|
||||
}
|
||||
|
||||
throw new Error('无法解析图片数据')
|
||||
})().finally(() => {
|
||||
aiMediaDownloadTasks.delete(url)
|
||||
})
|
||||
|
||||
aiMediaDownloadTasks.set(url, downloadTask)
|
||||
return downloadTask
|
||||
}
|
||||
|
||||
const getAiImageExtension = (url: string) => {
|
||||
// 解析媒体扩展名,默认回退为指定后缀
|
||||
const getAiMediaExtension = (url: string, fallback = 'png') => {
|
||||
const cleanUrl = url.split(/[?#]/)[0] || ''
|
||||
const ext = cleanUrl.split('.').pop() || ''
|
||||
if (!ext || ext.length > 5 || ext.includes('/')) return 'png'
|
||||
if (!ext || ext.length > 5 || ext.includes('/')) return fallback
|
||||
return ext
|
||||
}
|
||||
|
||||
const buildAiImageFileName = async (url: string) => {
|
||||
const ext = getAiImageExtension(url)
|
||||
const buildAiMediaFileName = async (url: string, fallbackExt: string, prefix: string) => {
|
||||
const ext = getAiMediaExtension(url, fallbackExt)
|
||||
try {
|
||||
const hash = await md5FromString(url)
|
||||
return `${hash}.${ext}`
|
||||
return `${prefix}-${hash}.${ext}`
|
||||
} catch (error) {
|
||||
console.error('生成 AI 图片文件名失败:', error)
|
||||
return `ai-image-${Date.now()}.${ext}`
|
||||
console.error('生成 AI 媒体文件名失败:', error)
|
||||
return `${prefix}-${Date.now()}.${ext}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1102,7 +1156,7 @@ const ensureLocalAiImage = async (remoteUrl: string, messageIndex: number) => {
|
||||
: targetMessage.content === remoteUrl
|
||||
if (!isSameImage) return
|
||||
try {
|
||||
const fileName = await buildAiImageFileName(remoteUrl)
|
||||
const fileName = await buildAiMediaFileName(remoteUrl, 'png', 'ai-image')
|
||||
const existsResult = await resolveAiImagePath({
|
||||
userUid: userStore.userInfo.uid,
|
||||
conversationId: currentChat.value.id,
|
||||
@@ -1110,7 +1164,7 @@ const ensureLocalAiImage = async (remoteUrl: string, messageIndex: number) => {
|
||||
})
|
||||
let absolutePath = existsResult.absolutePath
|
||||
if (!existsResult.exists) {
|
||||
const buffer = await requestAiImageBuffer(remoteUrl)
|
||||
const buffer = await requestAiMediaBuffer(remoteUrl)
|
||||
const data = new Uint8Array(buffer)
|
||||
const saved = await persistAiImageFile({
|
||||
userUid: userStore.userInfo.uid,
|
||||
@@ -1130,6 +1184,82 @@ const ensureLocalAiImage = async (remoteUrl: string, messageIndex: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 视频本地化:与图片同目录策略,下载后替换展示 URL
|
||||
const ensureLocalAiVideo = async (remoteUrl: string, messageIndex: number) => {
|
||||
if (!remoteUrl || !userStore.userInfo?.uid || !currentChat.value.id) return
|
||||
const targetMessage = messageList.value[messageIndex]
|
||||
if (!targetMessage || targetMessage.type !== 'assistant') return
|
||||
const isSameVideo = targetMessage.videoUrl
|
||||
? targetMessage.videoUrl === remoteUrl
|
||||
: targetMessage.content === remoteUrl
|
||||
if (!isSameVideo) return
|
||||
try {
|
||||
const fileName = await buildAiMediaFileName(remoteUrl, 'mp4', 'ai-video')
|
||||
const existsResult = await resolveAiImagePath({
|
||||
userUid: userStore.userInfo.uid,
|
||||
conversationId: currentChat.value.id,
|
||||
fileName
|
||||
})
|
||||
let absolutePath = existsResult.absolutePath
|
||||
if (!existsResult.exists) {
|
||||
const buffer = await requestAiMediaBuffer(remoteUrl)
|
||||
const data = new Uint8Array(buffer)
|
||||
const saved = await persistAiImageFile({
|
||||
userUid: userStore.userInfo.uid,
|
||||
conversationId: currentChat.value.id,
|
||||
fileName,
|
||||
data
|
||||
})
|
||||
absolutePath = saved.absolutePath
|
||||
}
|
||||
if (messageList.value[messageIndex]) {
|
||||
const displayUrl = convertFileSrc(absolutePath)
|
||||
messageList.value[messageIndex].content = displayUrl
|
||||
messageList.value[messageIndex].videoUrl = remoteUrl
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('AI 视频本地化失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 音频本地化:与图片同目录策略,下载后替换展示 URL
|
||||
const ensureLocalAiAudio = async (remoteUrl: string, messageIndex: number) => {
|
||||
if (!remoteUrl || !userStore.userInfo?.uid || !currentChat.value.id) return
|
||||
const targetMessage = messageList.value[messageIndex]
|
||||
if (!targetMessage || targetMessage.type !== 'assistant') return
|
||||
const isSameAudio = targetMessage.audioUrl
|
||||
? targetMessage.audioUrl === remoteUrl
|
||||
: targetMessage.content === remoteUrl
|
||||
if (!isSameAudio) return
|
||||
try {
|
||||
const fileName = await buildAiMediaFileName(remoteUrl, 'mp3', 'ai-audio')
|
||||
const existsResult = await resolveAiImagePath({
|
||||
userUid: userStore.userInfo.uid,
|
||||
conversationId: currentChat.value.id,
|
||||
fileName
|
||||
})
|
||||
let absolutePath = existsResult.absolutePath
|
||||
if (!existsResult.exists) {
|
||||
const buffer = await requestAiMediaBuffer(remoteUrl)
|
||||
const data = new Uint8Array(buffer)
|
||||
const saved = await persistAiImageFile({
|
||||
userUid: userStore.userInfo.uid,
|
||||
conversationId: currentChat.value.id,
|
||||
fileName,
|
||||
data
|
||||
})
|
||||
absolutePath = saved.absolutePath
|
||||
}
|
||||
if (messageList.value[messageIndex]) {
|
||||
const displayUrl = convertFileSrc(absolutePath)
|
||||
messageList.value[messageIndex].content = displayUrl
|
||||
messageList.value[messageIndex].audioUrl = remoteUrl
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('AI 音频本地化失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const getMessageBubbleClass = (message: Message) => {
|
||||
if (message.type === 'assistant' && isRenderableAiImage(message)) {
|
||||
return []
|
||||
@@ -1946,6 +2076,8 @@ const pollVideoStatus = async (
|
||||
}
|
||||
}
|
||||
|
||||
void ensureLocalAiVideo(video.videoUrl, messageIndex)
|
||||
|
||||
window.$message.success('视频生成成功')
|
||||
|
||||
scrollToBottom()
|
||||
@@ -2076,6 +2208,8 @@ const pollAudioStatus = async (audioId: number, messageIndex: number, prompt: st
|
||||
}
|
||||
}
|
||||
|
||||
void ensureLocalAiAudio(audio.audioUrl, messageIndex)
|
||||
|
||||
window.$message.success('音频生成成功')
|
||||
|
||||
scrollToBottom()
|
||||
@@ -2361,9 +2495,20 @@ const loadMessages = async (conversationId: string) => {
|
||||
if (userStore.userInfo?.uid && currentChat.value.id) {
|
||||
void Promise.all(
|
||||
messageList.value.map((msg, index) => {
|
||||
if (msg.type !== 'assistant' || msg.msgType !== AiMsgContentTypeEnum.IMAGE) return Promise.resolve()
|
||||
const remoteUrl = msg.imageUrl || msg.content
|
||||
return ensureLocalAiImage(remoteUrl, index)
|
||||
if (msg.type !== 'assistant') return Promise.resolve()
|
||||
if (msg.msgType === AiMsgContentTypeEnum.IMAGE) {
|
||||
const remoteUrl = msg.imageUrl || msg.content
|
||||
return ensureLocalAiImage(remoteUrl, index)
|
||||
}
|
||||
if (msg.msgType === AiMsgContentTypeEnum.VIDEO) {
|
||||
const remoteUrl = msg.videoUrl || msg.content
|
||||
return ensureLocalAiVideo(remoteUrl, index)
|
||||
}
|
||||
if (msg.msgType === AiMsgContentTypeEnum.AUDIO) {
|
||||
const remoteUrl = msg.audioUrl || msg.content
|
||||
return ensureLocalAiAudio(remoteUrl, index)
|
||||
}
|
||||
return Promise.resolve()
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -2678,9 +2823,6 @@ onUnmounted(() => {
|
||||
useMitt.off('refresh-model-list', handleRefreshModelList)
|
||||
useMitt.off('open-generation-history', handleOpenHistory)
|
||||
useMitt.off('left-chat-title', handleLeftChatTitle)
|
||||
aiImageDownloadWorker?.terminate()
|
||||
aiImageDownloadWorker = null
|
||||
aiImageWorkerRequests.clear()
|
||||
})
|
||||
|
||||
// 监听会话切换,停止旧会话的轮询任务
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
:hidden-right="true"
|
||||
:enable-default-background="false"
|
||||
:enable-shadow="false"
|
||||
room-name="管理群成员" />
|
||||
:room-name="t('home.manage_group_member.title')" />
|
||||
|
||||
<!-- 顶部搜索框 -->
|
||||
<div class="px-16px mt-10px flex gap-3">
|
||||
@@ -16,7 +16,7 @@
|
||||
<n-input
|
||||
v-model:value="keyword"
|
||||
class="rounded-10px w-full bg-gray-100 relative text-14px"
|
||||
placeholder="搜索成员~"
|
||||
:placeholder="t('home.manage_group_member.search_placeholder_mobile')"
|
||||
clearable
|
||||
spellCheck="false"
|
||||
autoComplete="off"
|
||||
@@ -61,7 +61,11 @@
|
||||
</span>
|
||||
<div class="text-12px text-gray-500 flex items-center gap-4px truncate">
|
||||
<n-badge :color="item.activeStatus === OnlineEnum.ONLINE ? '#1ab292' : '#909090'" dot />
|
||||
{{ item.activeStatus === OnlineEnum.ONLINE ? '在线' : '离线' }}
|
||||
{{
|
||||
item.activeStatus === OnlineEnum.ONLINE
|
||||
? t('home.friends_list.status.online')
|
||||
: t('home.friends_list.status.offline')
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,9 +78,11 @@
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="px-16px py-10px bg-white border-t border-gray-200 flex justify-between items-center">
|
||||
<span class="text-14px">已选择 {{ selectedList.length }} 人</span>
|
||||
<span class="text-14px">
|
||||
{{ t('home.manage_group_member.selected_count', { count: selectedList.length }) }}
|
||||
</span>
|
||||
<n-button type="error" :disabled="selectedList.length === 0" :loading="isLoading" @click="handleMobileRemove">
|
||||
踢出群聊
|
||||
{{ t('home.manage_group_member.remove_button') }}
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,7 +93,7 @@
|
||||
<!-- PC端头部 -->
|
||||
<div class="flex-shrink-0">
|
||||
<div class="flex items-center justify-between px-20px py-16px border-b border-[--line-color]">
|
||||
<h2 class="text-16px font-medium text-[--text-color]">管理群成员</h2>
|
||||
<h2 class="text-16px font-medium text-[--text-color]">{{ t('home.manage_group_member.title') }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,7 +107,7 @@
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
class="border-(solid 1px [--line-color]) rounded-8px"
|
||||
placeholder="搜索群成员">
|
||||
:placeholder="t('home.manage_group_member.search_placeholder_pc')">
|
||||
<template #prefix>
|
||||
<svg class="w-12px h-12px"><use href="#search"></use></svg>
|
||||
</template>
|
||||
@@ -141,7 +147,11 @@
|
||||
</span>
|
||||
<div class="text-11px text-[--chat-text-color] flex items-center gap-4px truncate">
|
||||
<n-badge :color="item.activeStatus === OnlineEnum.ONLINE ? '#1ab292' : '#909090'" dot />
|
||||
{{ item.activeStatus === OnlineEnum.ONLINE ? '在线' : '离线' }}
|
||||
{{
|
||||
item.activeStatus === OnlineEnum.ONLINE
|
||||
? t('home.friends_list.status.online')
|
||||
: t('home.friends_list.status.offline')
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,14 +164,20 @@
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="px-20px py-12px bg-[--bg-popover] border-t border-[--line-color] flex justify-between items-center">
|
||||
<span class="text-13px text-[--text-color]">已选择 {{ selectedList.length }} 人</span>
|
||||
<span class="text-13px text-[--text-color]">
|
||||
{{ t('home.manage_group_member.selected_count', { count: selectedList.length }) }}
|
||||
</span>
|
||||
<n-popconfirm v-model:show="showDeleteConfirm">
|
||||
<template #icon>
|
||||
<svg class="size-22px"><use href="#explosion"></use></svg>
|
||||
</template>
|
||||
<template #action>
|
||||
<n-button size="small" tertiary @click.stop="showDeleteConfirm = false">取消</n-button>
|
||||
<n-button size="small" type="error" @click.stop="handleRemove">确定</n-button>
|
||||
<n-button size="small" tertiary @click.stop="showDeleteConfirm = false">
|
||||
{{ t('home.manage_group_member.dialog_negative') }}
|
||||
</n-button>
|
||||
<n-button size="small" type="error" @click.stop="handleRemove">
|
||||
{{ t('home.manage_group_member.dialog_positive') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<template #trigger>
|
||||
<n-button
|
||||
@@ -170,10 +186,10 @@
|
||||
type="error"
|
||||
:disabled="selectedList.length === 0"
|
||||
:loading="isLoading">
|
||||
踢出群聊
|
||||
{{ t('home.manage_group_member.remove_button') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要踢出 {{ selectedList.length }} 位成员吗?
|
||||
{{ t('home.manage_group_member.remove_confirm', { count: selectedList.length }) }}
|
||||
</n-popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
@@ -188,6 +204,7 @@ import { useGroupStore } from '@/stores/group'
|
||||
import { useGlobalStore } from '@/stores/global'
|
||||
import { AvatarUtils } from '@/utils/AvatarUtils'
|
||||
import router from '@/router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
defineOptions({
|
||||
name: 'ManageGroupMember'
|
||||
@@ -200,6 +217,7 @@ const emit = defineEmits<{
|
||||
const groupStore = useGroupStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const dialog = useDialog()
|
||||
const { t } = useI18n()
|
||||
|
||||
const keyword = ref('')
|
||||
const selectedList = ref<string[]>([])
|
||||
@@ -248,12 +266,12 @@ const handleClose = () => {
|
||||
|
||||
const validateRemoval = () => {
|
||||
if (globalStore.currentSessionRoomId === '1') {
|
||||
window.$message.warning('频道不允许踢出成员')
|
||||
window.$message.warning(t('home.manage_group_member.channel_not_allowed'))
|
||||
return false
|
||||
}
|
||||
|
||||
if (selectedList.value.length === 0) {
|
||||
window.$message.warning('请选择要踢出的成员')
|
||||
window.$message.warning(t('home.manage_group_member.select_member_warning'))
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -275,13 +293,13 @@ const handleRemove = async () => {
|
||||
try {
|
||||
await groupStore.removeGroupMembers(members, globalStore.currentSessionRoomId)
|
||||
|
||||
window.$message.success(`成功踢出 ${count} 位成员`)
|
||||
window.$message.success(t('home.manage_group_member.remove_success', { count }))
|
||||
selectedList.value = []
|
||||
handleClose()
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('踢出失败:', error)
|
||||
window.$message.error('踢出失败,请重试')
|
||||
window.$message.error(t('home.manage_group_member.remove_failed'))
|
||||
return false
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
@@ -293,10 +311,10 @@ const handleMobileRemove = () => {
|
||||
if (!validateRemoval()) return
|
||||
|
||||
dialog.warning({
|
||||
title: '确认踢出',
|
||||
content: `确定要踢出 ${selectedList.value.length} 位成员吗?`,
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
title: t('home.manage_group_member.confirm_remove_title'),
|
||||
content: t('home.manage_group_member.remove_confirm', { count: selectedList.value.length }),
|
||||
positiveText: t('home.manage_group_member.dialog_positive'),
|
||||
negativeText: t('home.manage_group_member.dialog_negative'),
|
||||
onPositiveClick: handleRemove
|
||||
})
|
||||
}
|
||||
@@ -313,7 +331,7 @@ const calculateScrollHeight = () => {
|
||||
onMounted(async () => {
|
||||
// 如果是频道(roomId === '1'),直接返回上一页
|
||||
if (globalStore.currentSessionRoomId === '1') {
|
||||
window.$message.warning('频道不支持管理成员')
|
||||
window.$message.warning(t('home.manage_group_member.channel_manage_unsupported'))
|
||||
handleClose()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
@click="toggleStatus(item)"
|
||||
class="p-6px rounded-4px hover:bg-[--tray-hover]">
|
||||
<img class="size-14px" :src="item.url" alt="" />
|
||||
<span>{{ item.title }}</span>
|
||||
<span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{{ translateStateTitle(item.title) }}
|
||||
</span>
|
||||
</n-flex>
|
||||
<n-flex
|
||||
@click="createWebviewWindow(t('message.tray.online_status_window_title'), 'onlineStatus', 320, 480)"
|
||||
@@ -21,7 +23,7 @@
|
||||
<svg class="size-14px">
|
||||
<use href="#more"></use>
|
||||
</svg>
|
||||
<span>{{ t('message.tray.more_status') }}</span>
|
||||
<span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">{{ t('message.tray.more_status') }}</span>
|
||||
</n-flex>
|
||||
|
||||
<component :is="division" />
|
||||
@@ -106,6 +108,13 @@ const division = () => {
|
||||
return <div class={'h-1px bg-[--line-color] w-full'}></div>
|
||||
}
|
||||
|
||||
const translateStateTitle = (title?: string) => {
|
||||
if (!title) return ''
|
||||
const key = `auth.onlineStatus.states.${title}`
|
||||
const translated = t(key)
|
||||
return translated === key ? title : translated
|
||||
}
|
||||
|
||||
const handleExit = () => {
|
||||
/** 退出时关闭锁屏 */
|
||||
lockScreen.value.enable = false
|
||||
|
||||
Reference in New Issue
Block a user