From 90f7af7afa04d39c97f1727c4b6d7ec2708c5aac Mon Sep 17 00:00:00 2001 From: Junsen <951434130@qq.com> Date: Fri, 8 Aug 2025 13:02:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E7=AB=AF=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-mobile-admin/.commitlintrc.cjs | 3 + main/xiaozhi-mobile-admin/.editorconfig | 13 + main/xiaozhi-mobile-admin/.gitignore | 44 + main/xiaozhi-mobile-admin/.husky/commit-msg | 1 + main/xiaozhi-mobile-admin/.husky/pre-commit | 1 + main/xiaozhi-mobile-admin/.npmrc | 8 + main/xiaozhi-mobile-admin/LICENSE | 21 + main/xiaozhi-mobile-admin/README.md | 93 + main/xiaozhi-mobile-admin/eslint.config.mjs | 43 + main/xiaozhi-mobile-admin/favicon.ico | Bin 0 -> 14575 bytes main/xiaozhi-mobile-admin/index.html | 26 + main/xiaozhi-mobile-admin/manifest.config.ts | 155 + main/xiaozhi-mobile-admin/openapi-spec.yaml | 1086 ++ .../openapi-ts-request.config.ts | 13 + main/xiaozhi-mobile-admin/pages.config.ts | 23 + .../patches/@dcloudio__uni-h5.patch | 13 + main/xiaozhi-mobile-admin/pnpm-lock.yaml | 14871 ++++++++++++++++ main/xiaozhi-mobile-admin/pnpm-workspace.yaml | 6 + .../scripts/postupgrade.js | 35 + main/xiaozhi-mobile-admin/src/App.vue | 39 + .../src/api/agent/agent.ts | 185 + .../src/api/agent/types.ts | 107 + main/xiaozhi-mobile-admin/src/api/auth.ts | 127 + .../src/api/chat-history/chat-history.ts | 57 + .../src/api/chat-history/index.ts | 2 + .../src/api/chat-history/types.ts | 38 + .../src/api/device/device.ts | 55 + .../src/api/device/index.ts | 2 + .../src/api/device/types.ts | 21 + .../src/api/voiceprint/index.ts | 2 + .../src/api/voiceprint/types.ts | 29 + .../src/api/voiceprint/voiceprint.ts | 62 + .../src/components/.gitkeep | 0 main/xiaozhi-mobile-admin/src/env.d.ts | 34 + main/xiaozhi-mobile-admin/src/hooks/.gitkeep | 0 .../src/hooks/usePageAuth.ts | 50 + .../src/hooks/useRequest.ts | 51 + .../src/hooks/useUpload.ts | 160 + main/xiaozhi-mobile-admin/src/http/README.md | 36 + .../src/http/request/alova.ts | 119 + .../src/http/request/enum.ts | 66 + .../src/http/request/types.ts | 22 + .../src/layouts/default.vue | 17 + .../src/layouts/fg-tabbar/fg-tabbar.vue | 68 + .../src/layouts/fg-tabbar/tabbar.md | 17 + .../src/layouts/fg-tabbar/tabbar.ts | 11 + .../src/layouts/fg-tabbar/tabbarList.ts | 97 + .../src/layouts/tabbar.vue | 19 + main/xiaozhi-mobile-admin/src/main.ts | 19 + .../src/pages-sub/demo/index.vue | 27 + .../src/pages/agent/edit.vue | 1085 ++ .../src/pages/agent/tools.vue | 726 + .../src/pages/chat-history/detail.vue | 331 + .../src/pages/chat-history/index.vue | 342 + .../components/ultrasonic-config.vue | 684 + .../device-config/components/wifi-config.vue | 230 + .../components/wifi-selector.vue | 556 + .../src/pages/device-config/index.vue | 154 + .../src/pages/device/index.vue | 367 + .../src/pages/index/index.vue | 599 + .../src/pages/login/index.vue | 777 + .../src/pages/register/index.vue | 877 + .../src/pages/voiceprint/index.vue | 544 + .../src/router/interceptor.ts | 66 + .../src/static/app/icons/1024x1024.png | Bin 0 -> 458242 bytes .../src/static/app/icons/120x120.png | Bin 0 -> 17805 bytes .../src/static/app/icons/144x144.png | Bin 0 -> 24176 bytes .../src/static/app/icons/152x152.png | Bin 0 -> 26428 bytes .../src/static/app/icons/167x167.png | Bin 0 -> 30883 bytes .../src/static/app/icons/180x180.png | Bin 0 -> 35063 bytes .../src/static/app/icons/192x192.png | Bin 0 -> 38903 bytes .../src/static/app/icons/20x20.png | Bin 0 -> 1330 bytes .../src/static/app/icons/29x29.png | Bin 0 -> 1471 bytes .../src/static/app/icons/40x40.png | Bin 0 -> 1709 bytes .../src/static/app/icons/58x58.png | Bin 0 -> 2210 bytes .../src/static/app/icons/60x60.png | Bin 0 -> 2275 bytes .../src/static/app/icons/72x72.png | Bin 0 -> 2708 bytes .../src/static/app/icons/76x76.png | Bin 0 -> 2833 bytes .../src/static/app/icons/80x80.png | Bin 0 -> 2962 bytes .../src/static/app/icons/87x87.png | Bin 0 -> 3266 bytes .../src/static/app/icons/96x96.png | Bin 0 -> 3680 bytes .../src/static/images/.gitkeep | 0 .../src/static/images/default-avatar.png | Bin 0 -> 560 bytes .../src/static/images/home/main-top-bg.png | Bin 0 -> 978384 bytes main/xiaozhi-mobile-admin/src/static/logo.png | Bin 0 -> 13372 bytes main/xiaozhi-mobile-admin/src/static/logo.svg | 33 + .../src/static/tabbar/chat.png | Bin 0 -> 2153 bytes .../src/static/tabbar/chat_activate.png | Bin 0 -> 2155 bytes .../src/static/tabbar/device.png | Bin 0 -> 4058 bytes .../src/static/tabbar/device_activate.png | Bin 0 -> 4040 bytes .../src/static/tabbar/example.png | Bin 0 -> 1371 bytes .../src/static/tabbar/exampleHL.png | Bin 0 -> 1398 bytes .../src/static/tabbar/home.png | Bin 0 -> 1346 bytes .../src/static/tabbar/homeHL.png | Bin 0 -> 1415 bytes .../src/static/tabbar/microphone.png | Bin 0 -> 3189 bytes .../src/static/tabbar/microphone_activate.png | Bin 0 -> 3273 bytes .../src/static/tabbar/personal.png | Bin 0 -> 2457 bytes .../src/static/tabbar/personalHL.png | Bin 0 -> 2534 bytes .../src/static/tabbar/robot.png | Bin 0 -> 3471 bytes .../src/static/tabbar/robot_activate.png | Bin 0 -> 3508 bytes main/xiaozhi-mobile-admin/src/store/agent.ts | 122 + main/xiaozhi-mobile-admin/src/store/config.ts | 65 + main/xiaozhi-mobile-admin/src/store/index.ts | 20 + main/xiaozhi-mobile-admin/src/store/plugin.ts | 58 + main/xiaozhi-mobile-admin/src/store/user.ts | 83 + .../src/style/iconfont.css | 28 + .../xiaozhi-mobile-admin/src/style/index.scss | 19 + main/xiaozhi-mobile-admin/src/typings.d.ts | 28 + main/xiaozhi-mobile-admin/src/typings.ts | 15 + main/xiaozhi-mobile-admin/src/uni.scss | 77 + main/xiaozhi-mobile-admin/src/utils/index.ts | 172 + .../src/utils/platform.ts | 24 + .../xiaozhi-mobile-admin/src/utils/request.ts | 78 + main/xiaozhi-mobile-admin/src/utils/toast.ts | 65 + .../src/utils/uploadFile.ts | 324 + main/xiaozhi-mobile-admin/uno.config.ts | 65 + .../unpackage/res/icons/1024x1024.png | Bin 0 -> 458242 bytes .../unpackage/res/icons/120x120.png | Bin 0 -> 17805 bytes .../unpackage/res/icons/144x144.png | Bin 0 -> 24176 bytes .../unpackage/res/icons/152x152.png | Bin 0 -> 26428 bytes .../unpackage/res/icons/167x167.png | Bin 0 -> 30883 bytes .../unpackage/res/icons/180x180.png | Bin 0 -> 35063 bytes .../unpackage/res/icons/192x192.png | Bin 0 -> 38903 bytes .../unpackage/res/icons/20x20.png | Bin 0 -> 1330 bytes .../unpackage/res/icons/29x29.png | Bin 0 -> 1471 bytes .../unpackage/res/icons/40x40.png | Bin 0 -> 1709 bytes .../unpackage/res/icons/58x58.png | Bin 0 -> 2210 bytes .../unpackage/res/icons/60x60.png | Bin 0 -> 2275 bytes .../unpackage/res/icons/72x72.png | Bin 0 -> 2708 bytes .../unpackage/res/icons/76x76.png | Bin 0 -> 2833 bytes .../unpackage/res/icons/80x80.png | Bin 0 -> 2962 bytes .../unpackage/res/icons/87x87.png | Bin 0 -> 3266 bytes .../unpackage/res/icons/96x96.png | Bin 0 -> 3680 bytes main/xiaozhi-mobile-admin/vite.config.ts | 182 + 134 files changed, 26790 insertions(+) create mode 100644 main/xiaozhi-mobile-admin/.commitlintrc.cjs create mode 100644 main/xiaozhi-mobile-admin/.editorconfig create mode 100644 main/xiaozhi-mobile-admin/.gitignore create mode 100644 main/xiaozhi-mobile-admin/.husky/commit-msg create mode 100644 main/xiaozhi-mobile-admin/.husky/pre-commit create mode 100644 main/xiaozhi-mobile-admin/.npmrc create mode 100644 main/xiaozhi-mobile-admin/LICENSE create mode 100644 main/xiaozhi-mobile-admin/README.md create mode 100644 main/xiaozhi-mobile-admin/eslint.config.mjs create mode 100644 main/xiaozhi-mobile-admin/favicon.ico create mode 100644 main/xiaozhi-mobile-admin/index.html create mode 100644 main/xiaozhi-mobile-admin/manifest.config.ts create mode 100644 main/xiaozhi-mobile-admin/openapi-spec.yaml create mode 100644 main/xiaozhi-mobile-admin/openapi-ts-request.config.ts create mode 100644 main/xiaozhi-mobile-admin/pages.config.ts create mode 100644 main/xiaozhi-mobile-admin/patches/@dcloudio__uni-h5.patch create mode 100644 main/xiaozhi-mobile-admin/pnpm-lock.yaml create mode 100644 main/xiaozhi-mobile-admin/pnpm-workspace.yaml create mode 100644 main/xiaozhi-mobile-admin/scripts/postupgrade.js create mode 100644 main/xiaozhi-mobile-admin/src/App.vue create mode 100644 main/xiaozhi-mobile-admin/src/api/agent/agent.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/agent/types.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/auth.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/chat-history/chat-history.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/chat-history/index.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/chat-history/types.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/device/device.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/device/index.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/device/types.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/voiceprint/index.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/voiceprint/types.ts create mode 100644 main/xiaozhi-mobile-admin/src/api/voiceprint/voiceprint.ts create mode 100644 main/xiaozhi-mobile-admin/src/components/.gitkeep create mode 100644 main/xiaozhi-mobile-admin/src/env.d.ts create mode 100644 main/xiaozhi-mobile-admin/src/hooks/.gitkeep create mode 100644 main/xiaozhi-mobile-admin/src/hooks/usePageAuth.ts create mode 100644 main/xiaozhi-mobile-admin/src/hooks/useRequest.ts create mode 100644 main/xiaozhi-mobile-admin/src/hooks/useUpload.ts create mode 100644 main/xiaozhi-mobile-admin/src/http/README.md create mode 100644 main/xiaozhi-mobile-admin/src/http/request/alova.ts create mode 100644 main/xiaozhi-mobile-admin/src/http/request/enum.ts create mode 100644 main/xiaozhi-mobile-admin/src/http/request/types.ts create mode 100644 main/xiaozhi-mobile-admin/src/layouts/default.vue create mode 100644 main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/fg-tabbar.vue create mode 100644 main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.md create mode 100644 main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.ts create mode 100644 main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbarList.ts create mode 100644 main/xiaozhi-mobile-admin/src/layouts/tabbar.vue create mode 100644 main/xiaozhi-mobile-admin/src/main.ts create mode 100644 main/xiaozhi-mobile-admin/src/pages-sub/demo/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/agent/edit.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/agent/tools.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/chat-history/detail.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/chat-history/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/device-config/components/ultrasonic-config.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/device-config/components/wifi-config.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/device-config/components/wifi-selector.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/device-config/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/device/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/index/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/login/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/register/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/pages/voiceprint/index.vue create mode 100644 main/xiaozhi-mobile-admin/src/router/interceptor.ts create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/1024x1024.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/120x120.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/144x144.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/152x152.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/167x167.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/180x180.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/192x192.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/20x20.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/29x29.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/40x40.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/58x58.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/60x60.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/72x72.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/76x76.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/80x80.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/87x87.png create mode 100644 main/xiaozhi-mobile-admin/src/static/app/icons/96x96.png create mode 100644 main/xiaozhi-mobile-admin/src/static/images/.gitkeep create mode 100644 main/xiaozhi-mobile-admin/src/static/images/default-avatar.png create mode 100644 main/xiaozhi-mobile-admin/src/static/images/home/main-top-bg.png create mode 100644 main/xiaozhi-mobile-admin/src/static/logo.png create mode 100644 main/xiaozhi-mobile-admin/src/static/logo.svg create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/chat.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/chat_activate.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/device.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/device_activate.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/example.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/exampleHL.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/home.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/homeHL.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/microphone.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/microphone_activate.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/personal.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/personalHL.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/robot.png create mode 100644 main/xiaozhi-mobile-admin/src/static/tabbar/robot_activate.png create mode 100644 main/xiaozhi-mobile-admin/src/store/agent.ts create mode 100644 main/xiaozhi-mobile-admin/src/store/config.ts create mode 100644 main/xiaozhi-mobile-admin/src/store/index.ts create mode 100644 main/xiaozhi-mobile-admin/src/store/plugin.ts create mode 100644 main/xiaozhi-mobile-admin/src/store/user.ts create mode 100644 main/xiaozhi-mobile-admin/src/style/iconfont.css create mode 100644 main/xiaozhi-mobile-admin/src/style/index.scss create mode 100644 main/xiaozhi-mobile-admin/src/typings.d.ts create mode 100644 main/xiaozhi-mobile-admin/src/typings.ts create mode 100644 main/xiaozhi-mobile-admin/src/uni.scss create mode 100644 main/xiaozhi-mobile-admin/src/utils/index.ts create mode 100644 main/xiaozhi-mobile-admin/src/utils/platform.ts create mode 100644 main/xiaozhi-mobile-admin/src/utils/request.ts create mode 100644 main/xiaozhi-mobile-admin/src/utils/toast.ts create mode 100644 main/xiaozhi-mobile-admin/src/utils/uploadFile.ts create mode 100644 main/xiaozhi-mobile-admin/uno.config.ts create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/1024x1024.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/120x120.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/144x144.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/152x152.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/167x167.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/180x180.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/192x192.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/20x20.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/29x29.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/40x40.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/58x58.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/60x60.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/72x72.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/76x76.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/80x80.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/87x87.png create mode 100644 main/xiaozhi-mobile-admin/unpackage/res/icons/96x96.png create mode 100644 main/xiaozhi-mobile-admin/vite.config.ts diff --git a/main/xiaozhi-mobile-admin/.commitlintrc.cjs b/main/xiaozhi-mobile-admin/.commitlintrc.cjs new file mode 100644 index 00000000..98ee7dfc --- /dev/null +++ b/main/xiaozhi-mobile-admin/.commitlintrc.cjs @@ -0,0 +1,3 @@ +module.exports = { + extends: ['@commitlint/config-conventional'], +} diff --git a/main/xiaozhi-mobile-admin/.editorconfig b/main/xiaozhi-mobile-admin/.editorconfig new file mode 100644 index 00000000..7f098647 --- /dev/null +++ b/main/xiaozhi-mobile-admin/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] # 表示所有文件适用 +charset = utf-8 # 设置文件字符集为 utf-8 +indent_style = space # 缩进风格(tab | space) +indent_size = 2 # 缩进大小 +end_of_line = lf # 控制换行类型(lf | cr | crlf) +trim_trailing_whitespace = true # 去除行首的任意空白字符 +insert_final_newline = true # 始终在文件末尾插入一个新行 + +[*.md] # 表示仅 md 文件适用以下规则 +max_line_length = off # 关闭最大行长度限制 +trim_trailing_whitespace = false # 关闭末尾空格修剪 diff --git a/main/xiaozhi-mobile-admin/.gitignore b/main/xiaozhi-mobile-admin/.gitignore new file mode 100644 index 00000000..34ddbdf3 --- /dev/null +++ b/main/xiaozhi-mobile-admin/.gitignore @@ -0,0 +1,44 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +*.local + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.hbuilderx + +.stylelintcache +.eslintcache + +docs/.vitepress/dist +docs/.vitepress/cache + +src/types + +# lock 文件还是不要了,我主要的版本写死就好了 +# pnpm-lock.yaml +# package-lock.json + +# TIPS:如果某些文件已经加入了版本管理,现在重新加入 .gitignore 是不生效的,需要执行下面的操作 +# `git rm -r --cached .` 然后提交 commit 即可。 + +# git rm -r --cached file1 file2 ## 针对某些文件 +# git rm -r --cached dir1 dir2 ## 针对某些文件夹 +# git rm -r --cached . ## 针对所有文件 + +# 更新 uni-app 官方版本 +# npx @dcloudio/uvm@latest diff --git a/main/xiaozhi-mobile-admin/.husky/commit-msg b/main/xiaozhi-mobile-admin/.husky/commit-msg new file mode 100644 index 00000000..36158d92 --- /dev/null +++ b/main/xiaozhi-mobile-admin/.husky/commit-msg @@ -0,0 +1 @@ +npx --no-install commitlint --edit "$1" \ No newline at end of file diff --git a/main/xiaozhi-mobile-admin/.husky/pre-commit b/main/xiaozhi-mobile-admin/.husky/pre-commit new file mode 100644 index 00000000..c3ec64be --- /dev/null +++ b/main/xiaozhi-mobile-admin/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged --allow-empty \ No newline at end of file diff --git a/main/xiaozhi-mobile-admin/.npmrc b/main/xiaozhi-mobile-admin/.npmrc new file mode 100644 index 00000000..10ecfe22 --- /dev/null +++ b/main/xiaozhi-mobile-admin/.npmrc @@ -0,0 +1,8 @@ +# registry = https://registry.npmjs.org +registry = https://registry.npmmirror.com + +strict-peer-dependencies=false +auto-install-peers=true +shamefully-hoist=true +ignore-workspace-root-check=true +install-workspace-root=true diff --git a/main/xiaozhi-mobile-admin/LICENSE b/main/xiaozhi-mobile-admin/LICENSE new file mode 100644 index 00000000..9e91d10b --- /dev/null +++ b/main/xiaozhi-mobile-admin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 菲鸽 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/main/xiaozhi-mobile-admin/README.md b/main/xiaozhi-mobile-admin/README.md new file mode 100644 index 00000000..c088199e --- /dev/null +++ b/main/xiaozhi-mobile-admin/README.md @@ -0,0 +1,93 @@ +

+ + + +

+ +

+ unibest - 最好的 uniapp 开发框架 +

+ +
+旧仓库 codercup 进不去了,star 也拿不回来,这里也展示一下那个地址的 star. + +[![GitHub Repo stars](https://img.shields.io/github/stars/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest) +[![GitHub forks](https://img.shields.io/github/forks/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest) + +
+ +
+ +[![GitHub Repo stars](https://img.shields.io/github/stars/feige996/unibest?style=flat&logo=github)](https://github.com/feige996/unibest) +[![GitHub forks](https://img.shields.io/github/forks/feige996/unibest?style=flat&logo=github)](https://github.com/feige996/unibest) +[![star](https://gitee.com/feige996/unibest/badge/star.svg?theme=dark)](https://gitee.com/feige996/unibest/stargazers) +[![fork](https://gitee.com/feige996/unibest/badge/fork.svg?theme=dark)](https://gitee.com/feige996/unibest/members) +![node version](https://img.shields.io/badge/node-%3E%3D18-green) +![pnpm version](https://img.shields.io/badge/pnpm-%3E%3D7.30-green) +![GitHub package.json version (subfolder of monorepo)](https://img.shields.io/github/package-json/v/feige996/unibest) +![GitHub License](https://img.shields.io/github/license/feige996/unibest) + +
+ +`unibest` —— 最好的 `uniapp` 开发模板,由 `uniapp` + `Vue3` + `Ts` + `Vite5` + `UnoCss` + `wot-ui` + `z-paging` 构成,使用了最新的前端技术栈,无需依靠 `HBuilderX`,通过命令行方式运行 `web`、`小程序` 和 `App`(编辑器推荐 `VSCode`,可选 `webstorm`)。 + +`unibest` 内置了 `约定式路由`、`layout布局`、`请求封装`、`请求拦截`、`登录拦截`、`UnoCSS`、`i18n多语言` 等基础功能,提供了 `代码提示`、`自动格式化`、`统一配置`、`代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验 ( `unibest 的由来`)。 + +![](https://raw.githubusercontent.com/andreasbm/readme/master/screenshots/lines/rainbow.png) + +

+ 📖 文档地址(new) + | + 📱 DEMO 地址 +

+ +--- + +注意旧的地址 [codercup](https://github.com/codercup/unibest) 我进不去了,使用新的 [feige996](https://github.com/feige996/unibest)。PR和 issue 也请使用新地址,否则无法合并。 + +## 平台兼容性 + +| H5 | IOS | 安卓 | 微信小程序 | 字节小程序 | 快手小程序 | 支付宝小程序 | 钉钉小程序 | 百度小程序 | +| --- | --- | ---- | ---------- | ---------- | ---------- | ------------ | ---------- | ---------- | +| √ | √ | √ | √ | √ | √ | √ | √ | √ | + +注意每种 `UI框架` 支持的平台有所不同,详情请看各 `UI框架` 的官网,也可以看 `unibest` 文档。 + +## ⚙️ 环境 + +- node>=18 +- pnpm>=7.30 +- Vue Official>=2.1.10 +- TypeScript>=5.0 + +## 📂 快速开始 + +执行 `pnpm create unibest` 创建项目 +执行 `pnpm i` 安装依赖 +执行 `pnpm dev` 运行 `H5` +执行 `pnpm dev:mp` 运行 `微信小程序` + +## 📦 运行(支持热更新) + +- web平台: `pnpm dev:h5`, 然后打开 [http://localhost:9000/](http://localhost:9000/)。 +- weixin平台:`pnpm dev:mp` 然后打开微信开发者工具,导入本地文件夹,选择本项目的`dist/dev/mp-weixin` 文件。 +- APP平台:`pnpm dev:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/dev/app` 文件夹,选择运行到模拟器(开发时优先使用),或者运行的安卓/ios基座。 + +## 🔗 发布 + +- web平台: `pnpm build:h5`,打包后的文件在 `dist/build/h5`,可以放到web服务器,如nginx运行。如果最终不是放在根目录,可以在 `manifest.config.ts` 文件的 `h5.router.base` 属性进行修改。 +- weixin平台:`pnpm build:mp`, 打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。 +- APP平台:`pnpm build:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/build/app` 文件夹,选择发行 - APP云打包。 + +## 📄 License + +[MIT](https://opensource.org/license/mit/) + +Copyright (c) 2025 菲鸽 + +## 捐赠 + +

+special sponsor appwrite +special sponsor appwrite +

diff --git a/main/xiaozhi-mobile-admin/eslint.config.mjs b/main/xiaozhi-mobile-admin/eslint.config.mjs new file mode 100644 index 00000000..54ce246d --- /dev/null +++ b/main/xiaozhi-mobile-admin/eslint.config.mjs @@ -0,0 +1,43 @@ +import uniHelper from '@uni-helper/eslint-config' + +export default uniHelper({ + unocss: true, + vue: true, + markdown: false, + ignores: [ + 'src/uni_modules/', + 'dist', + // unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用 + 'auto-import.d.ts', + // vite-plugin-uni-pages 生成的类型文件,每次切换分支都一堆不同的,所以直接 .gitignore + 'uni-pages.d.ts', + // 插件生成的文件 + 'src/pages.json', + 'src/manifest.json', + // 忽略自动生成文件 + 'src/service/app/**', + ], + rules: { + 'no-console': 'off', + 'no-unused-vars': 'off', + 'vue/no-unused-refs': 'off', + 'unused-imports/no-unused-vars': 'off', + 'eslint-comments/no-unlimited-disable': 'off', + 'jsdoc/check-param-names': 'off', + 'jsdoc/require-returns-description': 'off', + 'ts/no-empty-object-type': 'off', + 'no-extend-native': 'off', + }, + formatters: { + /** + * Format CSS, LESS, SCSS files, also the ` diff --git a/main/xiaozhi-mobile-admin/src/api/agent/agent.ts b/main/xiaozhi-mobile-admin/src/api/agent/agent.ts new file mode 100644 index 00000000..09f352f2 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/agent/agent.ts @@ -0,0 +1,185 @@ +import type { + Agent, + AgentCreateData, + AgentDetail, + ModelOption, + RoleTemplate, +} from './types' +import { http } from '@/http/request/alova' + +// 获取智能体详情 +export function getAgentDetail(id: string) { + return http.Get(`/agent/${id}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取角色模板列表 +export function getRoleTemplates() { + return http.Get('/agent/template', { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取模型选项 +export function getModelOptions(modelType: string, modelName: string = '') { + return http.Get('/models/names', { + params: { + modelType, + modelName, + }, + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取智能体列表 +export function getAgentList() { + return http.Get('/agent/list', { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 创建智能体 +export function createAgent(data: AgentCreateData) { + return http.Post('/agent', data, { + meta: { + ignoreAuth: false, + toast: true, + }, + }) +} + +// 删除智能体 +export function deleteAgent(id: string) { + return http.Delete(`/agent/${id}`, { + meta: { + ignoreAuth: false, + toast: true, + }, + }) +} + +// 获取TTS音色列表 +export function getTTSVoices(ttsModelId: string, voiceName: string = '') { + return http.Get<{ id: string, name: string }[]>(`/models/${ttsModelId}/voices`, { + params: { + voiceName, + }, + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 更新智能体 +export function updateAgent(id: string, data: Partial) { + return http.Put(`/agent/${id}`, data, { + meta: { + ignoreAuth: false, + toast: true, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取插件列表 +export function getPluginFunctions() { + return http.Get(`/models/provider/plugin/names`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取mcp接入点 +export function getMcpAddress(agentId: string) { + return http.Get(`/agent/mcp/address/${agentId}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} + +// 获取mcp工具 +export function getMcpTools(agentId: string) { + return http.Get(`/agent/mcp/tools/${agentId}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取声纹列表 +export function getVoicePrintList(agentId: string) { + return http.Get(`/agent/voice-print/list/${agentId}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取语音对话记录 +export function getChatHistoryUser(agentId: string) { + return http.Get(`/agent/${agentId}/chat-history/user`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 新增声纹说话人 +export function createVoicePrint(data: { agentId: string, audioId: string, sourceName: string, introduce: string }) { + return http.Post('/agent/voice-print', data, { + meta: { + ignoreAuth: false, + toast: true, + }, + }) +} diff --git a/main/xiaozhi-mobile-admin/src/api/agent/types.ts b/main/xiaozhi-mobile-admin/src/api/agent/types.ts new file mode 100644 index 00000000..66559a23 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/agent/types.ts @@ -0,0 +1,107 @@ +// 智能体列表数据类型 +export interface Agent { + id: string + agentName: string + ttsModelName: string + ttsVoiceName: string + llmModelName: string + vllmModelName: string + memModelId: string + systemPrompt: string + summaryMemory: string | null + lastConnectedAt: string | null + deviceCount: number +} + +// 智能体创建数据类型 +export interface AgentCreateData { + agentName: string +} + +// 智能体详情数据类型 +export interface AgentDetail { + id: string + userId: string + agentCode: string + agentName: string + asrModelId: string + vadModelId: string + llmModelId: string + vllmModelId: string + ttsModelId: string + ttsVoiceId: string + memModelId: string + intentModelId: string + chatHistoryConf: number + systemPrompt: string + summaryMemory: string + langCode: string + language: string + sort: number + creator: string + createdAt: string + updater: string + updatedAt: string + functions: AgentFunction[] +} + +export interface AgentFunction { + id?: string + agentId?: string + pluginId: string + paramInfo: Record | null +} + +// 角色模板数据类型 +export interface RoleTemplate { + id: string + agentCode: string + agentName: string + asrModelId: string + vadModelId: string + llmModelId: string + vllmModelId: string + ttsModelId: string + ttsVoiceId: string + memModelId: string + intentModelId: string + chatHistoryConf: number + systemPrompt: string + summaryMemory: string + langCode: string + language: string + sort: number + creator: string + createdAt: string + updater: string + updatedAt: string +} + +// 模型选项数据类型 +export interface ModelOption { + id: string + modelName: string +} + +export interface PluginField { + key: string + type: string + label: string + default: string + selected?: boolean + editing?: boolean +} + +export interface PluginDefinition { + id: string + modelType: string + providerCode: string + name: string + fields: PluginField[] // 注意:原始是字符串,需要先 JSON.parse + sort: number + updater: string + updateDate: string + creator: string + createDate: string + [key: string]: any +} diff --git a/main/xiaozhi-mobile-admin/src/api/auth.ts b/main/xiaozhi-mobile-admin/src/api/auth.ts new file mode 100644 index 00000000..07cc3fa8 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/auth.ts @@ -0,0 +1,127 @@ +import { http } from '@/http/request/alova' + +// 登录接口数据类型 +export interface LoginData { + username: string + password: string + captcha: string + captchaId: string + areaCode?: string + mobile?: string +} + +// 登录响应数据类型 +export interface LoginResponse { + token: string + expire: number + clientHash: string +} + +// 验证码响应数据类型 +export interface CaptchaResponse { + captchaId: string + captchaImage: string +} + +// 获取验证码 +export function getCaptcha(uuid: string) { + return http.Get('/user/captcha', { + params: { uuid }, + meta: { + ignoreAuth: true, + toast: false, + }, + }) +} + +// 用户登录 +export function login(data: LoginData) { + return http.Post('/user/login', data, { + meta: { + ignoreAuth: true, + toast: true, + }, + }) +} + +// 用户信息响应数据类型 +export interface UserInfo { + id: number + username: string + realName: string + email: string + mobile: string + status: number + superAdmin: number +} + +// 公共配置响应数据类型 +export interface PublicConfig { + enableMobileRegister: boolean + version: string + year: string + allowUserRegister: boolean + mobileAreaList: Array<{ + name: string + key: string + }> + beianIcpNum: string + beianGaNum: string + name: string +} + +// 获取用户信息 +export function getUserInfo() { + return http.Get('/user/info', { + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} + +// 获取公共配置 +export function getPublicConfig() { + return http.Get('/user/pub-config', { + meta: { + ignoreAuth: true, + toast: false, + }, + }) +} + +// 注册数据类型 +export interface RegisterData { + username: string + password: string + confirmPassword: string + captcha: string + captchaId: string + areaCode: string + mobile: string + mobileCaptcha: string +} + +// 发送短信验证码 +export function sendSmsCode(data: { + phone: string + captcha: string + captchaId: string +}) { + return http.Post('/user/smsVerification', data, { + meta: { + ignoreAuth: true, + toast: false, + }, + }) +} + +// 用户注册 +export function register(data: RegisterData) { + return http.Post('/user/register', data, { + meta: { + ignoreAuth: true, + toast: true, + }, + }) +} diff --git a/main/xiaozhi-mobile-admin/src/api/chat-history/chat-history.ts b/main/xiaozhi-mobile-admin/src/api/chat-history/chat-history.ts new file mode 100644 index 00000000..8d6e396b --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/chat-history/chat-history.ts @@ -0,0 +1,57 @@ +import type { + ChatMessage, + ChatSessionsResponse, + GetSessionsParams, +} from './types' +import { http } from '@/http/request/alova' + +/** + * 获取聊天会话列表 + * @param agentId 智能体ID + * @param params 分页参数 + */ +export function getChatSessions(agentId: string, params: GetSessionsParams) { + return http.Get(`/agent/${agentId}/sessions`, { + params, + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} + +/** + * 获取聊天记录详情 + * @param agentId 智能体ID + * @param sessionId 会话ID + */ +export function getChatHistory(agentId: string, sessionId: string) { + return http.Get(`/agent/${agentId}/chat-history/${sessionId}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} + +/** + * 获取音频下载ID + * @param audioId 音频ID + */ +export function getAudioId(audioId: string) { + return http.Post(`/agent/audio/${audioId}`, {}, { + meta: { + ignoreAuth: false, + toast: false, + }, + }) +} + +/** + * 获取音频播放地址 + * @param downloadId 下载ID + */ +export function getAudioPlayUrl(downloadId: string) { + // 根据需求文档,这个是直接返回二进制的,所以我们直接构造URL + return `/agent/play/${downloadId}` +} diff --git a/main/xiaozhi-mobile-admin/src/api/chat-history/index.ts b/main/xiaozhi-mobile-admin/src/api/chat-history/index.ts new file mode 100644 index 00000000..ecf782a4 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/chat-history/index.ts @@ -0,0 +1,2 @@ +export * from './chat-history' +export * from './types' diff --git a/main/xiaozhi-mobile-admin/src/api/chat-history/types.ts b/main/xiaozhi-mobile-admin/src/api/chat-history/types.ts new file mode 100644 index 00000000..b895ed47 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/chat-history/types.ts @@ -0,0 +1,38 @@ +// 聊天会话列表项 +export interface ChatSession { + sessionId: string + createdAt: string + chatCount: number +} + +// 聊天会话列表响应 +export interface ChatSessionsResponse { + total: number + list: ChatSession[] +} + +// 聊天消息 +export interface ChatMessage { + createdAt: string + chatType: 1 | 2 // 1是用户,2是AI + content: string + audioId: string | null + macAddress: string +} + +// 用户消息内容(需要解析JSON) +export interface UserMessageContent { + speaker: string + content: string +} + +// 获取聊天会话列表参数 +export interface GetSessionsParams { + page: number + limit: number +} + +// 音频播放相关 +export interface AudioResponse { + data: string // 音频下载ID +} diff --git a/main/xiaozhi-mobile-admin/src/api/device/device.ts b/main/xiaozhi-mobile-admin/src/api/device/device.ts new file mode 100644 index 00000000..fc9d5f69 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/device/device.ts @@ -0,0 +1,55 @@ +import type { Device, FirmwareType } from './types' +import { http } from '@/http/request/alova' + +/** + * 获取设备类型列表 + */ +export function getFirmwareTypes() { + return http.Get('/admin/dict/data/type/FIRMWARE_TYPE') +} + +/** + * 获取绑定设备列表 + * @param agentId 智能体ID + */ +export function getBindDevices(agentId: string) { + return http.Get(`/device/bind/${agentId}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +/** + * 添加设备 + * @param agentId 智能体ID + * @param code 验证码 + */ +export function bindDevice(agentId: string, code: string) { + return http.Post(`/device/bind/${agentId}/${code}`, null) +} + +/** + * 设置设备OTA升级开关 + * @param deviceId 设备ID (MAC地址) + * @param autoUpdate 是否自动升级 0|1 + */ +export function updateDeviceAutoUpdate(deviceId: string, autoUpdate: number) { + return http.Put(`/device/update/${deviceId}`, { + autoUpdate, + }) +} + +/** + * 解绑设备 + * @param deviceId 设备ID (MAC地址) + */ +export function unbindDevice(deviceId: string) { + return http.Post('/device/unbind', { + deviceId, + }) +} diff --git a/main/xiaozhi-mobile-admin/src/api/device/index.ts b/main/xiaozhi-mobile-admin/src/api/device/index.ts new file mode 100644 index 00000000..aa5f6179 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/device/index.ts @@ -0,0 +1,2 @@ +export * from './device' +export * from './types' diff --git a/main/xiaozhi-mobile-admin/src/api/device/types.ts b/main/xiaozhi-mobile-admin/src/api/device/types.ts new file mode 100644 index 00000000..4b6165c5 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/device/types.ts @@ -0,0 +1,21 @@ +export interface FirmwareType { + name: string + key: string +} + +export interface Device { + id: string + userId: string + macAddress: string + lastConnectedAt: string + autoUpdate: number + board: string + alias?: string + agentId: string + appVersion: string + sort: number + updater?: string + updateDate: string + creator: string + createDate: string +} diff --git a/main/xiaozhi-mobile-admin/src/api/voiceprint/index.ts b/main/xiaozhi-mobile-admin/src/api/voiceprint/index.ts new file mode 100644 index 00000000..af56e69a --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/voiceprint/index.ts @@ -0,0 +1,2 @@ +export * from './types' +export * from './voiceprint' diff --git a/main/xiaozhi-mobile-admin/src/api/voiceprint/types.ts b/main/xiaozhi-mobile-admin/src/api/voiceprint/types.ts new file mode 100644 index 00000000..726b1783 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/voiceprint/types.ts @@ -0,0 +1,29 @@ +// 声纹信息响应类型 +export interface VoicePrint { + id: string + audioId: string + sourceName: string + introduce: string + createDate: string +} + +// 语音对话记录类型 +export interface ChatHistory { + content: string + audioId: string +} + +// 创建说话人数据类型 +export interface CreateSpeakerData { + agentId: string + audioId: string + sourceName: string + introduce: string +} + +// 通用响应类型 +export interface ApiResponse { + code: number + msg: string + data: T +} diff --git a/main/xiaozhi-mobile-admin/src/api/voiceprint/voiceprint.ts b/main/xiaozhi-mobile-admin/src/api/voiceprint/voiceprint.ts new file mode 100644 index 00000000..600696dd --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/api/voiceprint/voiceprint.ts @@ -0,0 +1,62 @@ +import type { + ChatHistory, + CreateSpeakerData, + VoicePrint, +} from './types' +import { http } from '@/http/request/alova' + +// 获取声纹列表 +export function getVoicePrintList(agentId: string) { + return http.Get(`/agent/voice-print/list/${agentId}`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 获取语音对话记录(用于选择声纹向量) +export function getChatHistory(agentId: string) { + return http.Get(`/agent/${agentId}/chat-history/user`, { + meta: { + ignoreAuth: false, + toast: false, + }, + cacheFor: { + expire: 0, + }, + }) +} + +// 新增说话人 +export function createVoicePrint(data: CreateSpeakerData) { + return http.Post('/agent/voice-print', data, { + meta: { + ignoreAuth: false, + toast: true, + }, + }) +} + +// 删除声纹 +export function deleteVoicePrint(id: string) { + return http.Delete(`/agent/voice-print/${id}`, { + meta: { + ignoreAuth: false, + toast: true, + }, + }) +} + +// 更新声纹信息 +export function updateVoicePrint(data: VoicePrint) { + return http.Put('/agent/voice-print', data, { + meta: { + ignoreAuth: false, + toast: true, + }, + }) +} diff --git a/main/xiaozhi-mobile-admin/src/components/.gitkeep b/main/xiaozhi-mobile-admin/src/components/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/main/xiaozhi-mobile-admin/src/env.d.ts b/main/xiaozhi-mobile-admin/src/env.d.ts new file mode 100644 index 00000000..b4a2c97b --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/env.d.ts @@ -0,0 +1,34 @@ +/// +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + + const component: DefineComponent<{}, {}, any> + export default component +} + +interface ImportMetaEnv { + /** 网站标题,应用名称 */ + readonly VITE_APP_TITLE: string + /** 服务端口号 */ + readonly VITE_SERVER_PORT: string + /** 后台接口地址 */ + readonly VITE_SERVER_BASEURL: string + /** H5是否需要代理 */ + readonly VITE_APP_PROXY: 'true' | 'false' + /** H5是否需要代理,需要的话有个前缀 */ + readonly VITE_APP_PROXY_PREFIX: string // 一般是/api + /** 上传图片地址 */ + readonly VITE_UPLOAD_BASEURL: string + /** 是否清除console */ + readonly VITE_DELETE_CONSOLE: string + // 更多环境变量... +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} + +declare const __VITE_APP_PROXY__: 'true' | 'false' +declare const __UNI_PLATFORM__: 'app' | 'h5' | 'mp-alipay' | 'mp-baidu' | 'mp-kuaishou' | 'mp-lark' | 'mp-qq' | 'mp-tiktok' | 'mp-weixin' | 'mp-xiaochengxu' diff --git a/main/xiaozhi-mobile-admin/src/hooks/.gitkeep b/main/xiaozhi-mobile-admin/src/hooks/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/main/xiaozhi-mobile-admin/src/hooks/usePageAuth.ts b/main/xiaozhi-mobile-admin/src/hooks/usePageAuth.ts new file mode 100644 index 00000000..fd006c81 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/hooks/usePageAuth.ts @@ -0,0 +1,50 @@ +import { onLoad } from '@dcloudio/uni-app' +import { useUserStore } from '@/store' +import { needLoginPages as _needLoginPages, getNeedLoginPages } from '@/utils' + +const loginRoute = import.meta.env.VITE_LOGIN_URL +const isDev = import.meta.env.DEV +function isLogined() { + const userStore = useUserStore() + return !!userStore.userInfo.username +} +// 检查当前页面是否需要登录 +export function usePageAuth() { + onLoad((options) => { + // 获取当前页面路径 + const pages = getCurrentPages() + const currentPage = pages[pages.length - 1] + const currentPath = `/${currentPage.route}` + + // 获取需要登录的页面列表 + let needLoginPages: string[] = [] + if (isDev) { + needLoginPages = getNeedLoginPages() + } + else { + needLoginPages = _needLoginPages + } + + // 检查当前页面是否需要登录 + const isNeedLogin = needLoginPages.includes(currentPath) + if (!isNeedLogin) { + return + } + + const hasLogin = isLogined() + if (hasLogin) { + return true + } + + // 构建重定向URL + const queryString = Object.entries(options || {}) + .map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`) + .join('&') + + const currentFullPath = queryString ? `${currentPath}?${queryString}` : currentPath + const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(currentFullPath)}` + + // 重定向到登录页 + uni.redirectTo({ url: redirectRoute }) + }) +} diff --git a/main/xiaozhi-mobile-admin/src/hooks/useRequest.ts b/main/xiaozhi-mobile-admin/src/hooks/useRequest.ts new file mode 100644 index 00000000..017a710a --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/hooks/useRequest.ts @@ -0,0 +1,51 @@ +import type { Ref } from 'vue' + +interface IUseRequestOptions { + /** 是否立即执行 */ + immediate?: boolean + /** 初始化数据 */ + initialData?: T +} + +interface IUseRequestReturn { + loading: Ref + error: Ref + data: Ref + run: () => Promise +} + +/** + * useRequest是一个定制化的请求钩子,用于处理异步请求和响应。 + * @param func 一个执行异步请求的函数,返回一个包含响应数据的Promise。 + * @param options 包含请求选项的对象 {immediate, initialData}。 + * @param options.immediate 是否立即执行请求,默认为false。 + * @param options.initialData 初始化数据,默认为undefined。 + * @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。 + */ +export default function useRequest( + func: () => Promise>, + options: IUseRequestOptions = { immediate: false }, +): IUseRequestReturn { + const loading = ref(false) + const error = ref(false) + const data = ref(options.initialData) as Ref + const run = async () => { + loading.value = true + return func() + .then((res) => { + data.value = res.data + error.value = false + return data.value + }) + .catch((err) => { + error.value = err + throw err + }) + .finally(() => { + loading.value = false + }) + } + + options.immediate && run() + return { loading, error, data, run } +} diff --git a/main/xiaozhi-mobile-admin/src/hooks/useUpload.ts b/main/xiaozhi-mobile-admin/src/hooks/useUpload.ts new file mode 100644 index 00000000..3080d5a7 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/hooks/useUpload.ts @@ -0,0 +1,160 @@ +import { ref } from 'vue' +import { getEnvBaseUploadUrl } from '@/utils' + +const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}` + +type TfileType = 'image' | 'file' +type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*' +type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage + +interface TOptions { + formData?: Record + maxSize?: number + accept?: T extends 'image' ? TImage[] : TFile[] + fileType?: T + success?: (params: any) => void + error?: (err: any) => void +} + +export default function useUpload(options: TOptions = {} as TOptions) { + const { + formData = {}, + maxSize = 5 * 1024 * 1024, + accept = ['*'], + fileType = 'image', + success, + error: onError, + } = options + + const loading = ref(false) + const error = ref(null) + const data = ref(null) + + const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string, size: number }) => { + if (size > maxSize) { + uni.showToast({ + title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`, + icon: 'none', + }) + return + } + + // const fileExtension = file?.tempFiles?.name?.split('.').pop()?.toLowerCase() + // const isTypeValid = accept.some((type) => type === '*' || type.toLowerCase() === fileExtension) + + // if (!isTypeValid) { + // uni.showToast({ + // title: `仅支持 ${accept.join(', ')} 格式的文件`, + // icon: 'none', + // }) + // return + // } + + loading.value = true + uploadFile({ + tempFilePath, + formData, + onSuccess: (res) => { + const { data: _data } = JSON.parse(res) + data.value = _data + // console.log('上传成功', res) + success?.(_data) + }, + onError: (err) => { + error.value = err + onError?.(err) + }, + onComplete: () => { + loading.value = false + }, + }) + } + + const run = () => { + // 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。 + // 微信小程序在2023年10月17日之后,使用本API需要配置隐私协议 + const chooseFileOptions = { + count: 1, + success: (res: any) => { + console.log('File selected successfully:', res) + // 小程序中res:{errMsg: "chooseImage:ok", tempFiles: [{fileType: "image", size: 48976, tempFilePath: "http://tmp/5iG1WpIxTaJf3ece38692a337dc06df7eb69ecb49c6b.jpeg"}]} + // h5中res:{errMsg: "chooseImage:ok", tempFilePaths: "blob:http://localhost:9000/f74ab6b8-a14d-4cb6-a10d-fcf4511a0de5", tempFiles: [File]} + // h5的File有以下字段:{name: "girl.jpeg", size: 48976, type: "image/jpeg"} + // App中res:{errMsg: "chooseImage:ok", tempFilePaths: "file:///Users/feige/xxx/gallery/1522437259-compressed-IMG_0006.jpg", tempFiles: [File]} + // App的File有以下字段:{path: "file:///Users/feige/xxx/gallery/1522437259-compressed-IMG_0006.jpg", size: 48976} + let tempFilePath = '' + let size = 0 + // #ifdef MP-WEIXIN + tempFilePath = res.tempFiles[0].tempFilePath + size = res.tempFiles[0].size + // #endif + // #ifndef MP-WEIXIN + tempFilePath = res.tempFilePaths[0] + size = res.tempFiles[0].size + // #endif + handleFileChoose({ tempFilePath, size }) + }, + fail: (err: any) => { + console.error('File selection failed:', err) + error.value = err + onError?.(err) + }, + } + + if (fileType === 'image') { + // #ifdef MP-WEIXIN + uni.chooseMedia({ + ...chooseFileOptions, + mediaType: ['image'], + }) + // #endif + + // #ifndef MP-WEIXIN + uni.chooseImage(chooseFileOptions) + // #endif + } + else { + uni.chooseFile({ + ...chooseFileOptions, + type: 'all', + }) + } + } + + return { loading, error, data, run } +} + +async function uploadFile({ + tempFilePath, + formData, + onSuccess, + onError, + onComplete, +}: { + tempFilePath: string + formData: Record + onSuccess: (data: any) => void + onError: (err: any) => void + onComplete: () => void +}) { + uni.uploadFile({ + url: VITE_UPLOAD_BASEURL, + filePath: tempFilePath, + name: 'file', + formData, + success: (uploadFileRes) => { + try { + const data = uploadFileRes.data + onSuccess(data) + } + catch (err) { + onError(err) + } + }, + fail: (err) => { + console.error('Upload failed:', err) + onError(err) + }, + complete: onComplete, + }) +} diff --git a/main/xiaozhi-mobile-admin/src/http/README.md b/main/xiaozhi-mobile-admin/src/http/README.md new file mode 100644 index 00000000..fd34fd52 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/http/README.md @@ -0,0 +1,36 @@ +# 请求库 + +当前项目使用 Alova 作为唯一的 HTTP 请求库: + +## 使用方式 + +- **Alova HTTP**:路径(src/http/request/alova.ts) +- **示例代码**:src/api/foo-alova.ts 和 src/api/foo.ts +- **API文档**:https://alova.js.org/ + +## 配置说明 + +Alova 实例已配置: +- 自动 Token 认证和刷新 +- 统一错误处理和提示 +- 支持动态域名切换 +- 内置请求/响应拦截器 + +## 使用示例 + +```typescript +import { http } from '@/http/request/alova' + +// GET 请求 +http.Get('/api/path', { + params: { id: 1 }, + headers: { 'Custom-Header': 'value' }, + meta: { toast: false } // 关闭错误提示 +}) + +// POST 请求 +http.Post('/api/path', data, { + params: { query: 'param' }, + headers: { 'Content-Type': 'application/json' } +}) +``` \ No newline at end of file diff --git a/main/xiaozhi-mobile-admin/src/http/request/alova.ts b/main/xiaozhi-mobile-admin/src/http/request/alova.ts new file mode 100644 index 00000000..d970a4c3 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/http/request/alova.ts @@ -0,0 +1,119 @@ +import type { uniappRequestAdapter } from '@alova/adapter-uniapp' +import type { IResponse } from './types' +import AdapterUniapp from '@alova/adapter-uniapp' +import { createAlova } from 'alova' +import { createServerTokenAuthentication } from 'alova/client' +import VueHook from 'alova/vue' +import { toast } from '@/utils/toast' +import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum' + +/** + * 创建请求实例 + */ +const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication< + typeof VueHook, + typeof uniappRequestAdapter +>({ + refreshTokenOnError: { + isExpired: (error) => { + return error.response?.status === ResultEnum.Unauthorized + }, + handler: async () => { + try { + // await authLogin(); + } + catch (error) { + // 切换到登录页 + await uni.reLaunch({ url: '/pages/login/index' }) + throw error + } + }, + }, +}) + +/** + * alova 请求实例 + */ +const alovaInstance = createAlova({ + baseURL: import.meta.env.VITE_SERVER_BASEURL, + ...AdapterUniapp(), + timeout: 5000, + statesHook: VueHook, + + beforeRequest: onAuthRequired((method) => { + // 设置默认 Content-Type + method.config.headers = { + 'Content-Type': ContentTypeEnum.JSON, + 'Accept': 'application/json, text/plain, */*', + ...method.config.headers, + } + + const { config } = method + const ignoreAuth = config.meta?.ignoreAuth + console.log('ignoreAuth===>', ignoreAuth) + + // 处理认证信息 + if (!ignoreAuth) { + const token = uni.getStorageSync('token') + if (!token) { + // 跳转到登录页 + uni.reLaunch({ url: '/pages/login/index' }) + throw new Error('[请求错误]:未登录') + } + // 添加 Authorization 头 + method.config.headers.Authorization = `Bearer ${token}` + } + + // 处理动态域名 + if (config.meta?.domain) { + method.baseURL = config.meta.domain + console.log('当前域名', method.baseURL) + } + }), + + responded: onResponseRefreshToken((response, method) => { + const { config } = method + const { requestType } = config + const { + statusCode, + data: rawData, + errMsg, + } = response as UniNamespace.RequestSuccessCallbackResult + + console.log(response) + + // 处理特殊请求类型(上传/下载) + if (requestType === 'upload' || requestType === 'download') { + return response + } + + // 处理 HTTP 状态码错误 + if (statusCode !== 200) { + const errorMessage = ShowMessage(statusCode) || `HTTP请求错误[${statusCode}]` + console.error('errorMessage===>', errorMessage) + toast.error(errorMessage) + throw new Error(`${errorMessage}:${errMsg}`) + } + + // 处理业务逻辑错误 + const { code, msg, data } = rawData as IResponse + if (code !== ResultEnum.Success) { + // 检查是否为token失效 + if (code === ResultEnum.Unauthorized) { + // 清除token并跳转到登录页 + uni.removeStorageSync('token') + uni.reLaunch({ url: '/pages/login/index' }) + throw new Error(`请求错误[${code}]:${msg}`) + } + + if (config.meta?.toast !== false) { + toast.warning(msg) + } + throw new Error(`请求错误[${code}]:${msg}`) + } + // 处理成功响应,返回业务数据 + return data + }), +}) + +export const http = alovaInstance diff --git a/main/xiaozhi-mobile-admin/src/http/request/enum.ts b/main/xiaozhi-mobile-admin/src/http/request/enum.ts new file mode 100644 index 00000000..1868fe08 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/http/request/enum.ts @@ -0,0 +1,66 @@ +export enum ResultEnum { + Success = 0, // 成功 + Error = 400, // 错误 + Unauthorized = 401, // 未授权 + Forbidden = 403, // 禁止访问(原为forbidden) + NotFound = 404, // 未找到(原为notFound) + MethodNotAllowed = 405, // 方法不允许(原为methodNotAllowed) + RequestTimeout = 408, // 请求超时(原为requestTimeout) + InternalServerError = 500, // 服务器错误(原为internalServerError) + NotImplemented = 501, // 未实现(原为notImplemented) + BadGateway = 502, // 网关错误(原为badGateway) + ServiceUnavailable = 503, // 服务不可用(原为serviceUnavailable) + GatewayTimeout = 504, // 网关超时(原为gatewayTimeout) + HttpVersionNotSupported = 505, // HTTP版本不支持(原为httpVersionNotSupported) +} +export enum ContentTypeEnum { + JSON = 'application/json;charset=UTF-8', + FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', + FORM_DATA = 'multipart/form-data;charset=UTF-8', +} +/** + * 根据状态码,生成对应的错误信息 + * @param {number|string} status 状态码 + * @returns {string} 错误信息 + */ +export function ShowMessage(status: number | string): string { + let message: string + switch (status) { + case 400: + message = '请求错误(400)' + break + case 401: + message = '未授权,请重新登录(401)' + break + case 403: + message = '拒绝访问(403)' + break + case 404: + message = '请求出错(404)' + break + case 408: + message = '请求超时(408)' + break + case 500: + message = '服务器错误(500)' + break + case 501: + message = '服务未实现(501)' + break + case 502: + message = '网络错误(502)' + break + case 503: + message = '服务不可用(503)' + break + case 504: + message = '网络超时(504)' + break + case 505: + message = 'HTTP版本不受支持(505)' + break + default: + message = `连接出错(${status})!` + } + return `${message},请检查网络或联系管理员!` +} diff --git a/main/xiaozhi-mobile-admin/src/http/request/types.ts b/main/xiaozhi-mobile-admin/src/http/request/types.ts new file mode 100644 index 00000000..824aa4f4 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/http/request/types.ts @@ -0,0 +1,22 @@ +// 通用响应格式 +export interface IResponse { + code: number | string + data: T + msg: string + status: string | number +} + +// 分页请求参数 +export interface PageParams { + page: number + pageSize: number + [key: string]: any +} + +// 分页响应数据 +export interface PageResult { + list: T[] + total: number + page: number + pageSize: number +} diff --git a/main/xiaozhi-mobile-admin/src/layouts/default.vue b/main/xiaozhi-mobile-admin/src/layouts/default.vue new file mode 100644 index 00000000..360c6b21 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/layouts/default.vue @@ -0,0 +1,17 @@ + + + diff --git a/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/fg-tabbar.vue b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/fg-tabbar.vue new file mode 100644 index 00000000..819aa6fb --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/fg-tabbar.vue @@ -0,0 +1,68 @@ + + + diff --git a/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.md b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.md new file mode 100644 index 00000000..2485b06d --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.md @@ -0,0 +1,17 @@ +# tabbar 说明 + +`tabbar` 分为 `4 种` 情况: + +- 0 `无 tabbar`,只有一个页面入口,底部无 `tabbar` 显示;常用语临时活动页。 +- 1 `原生 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。 + - 优势:原生自带的 tabbar,最先渲染,有缓存。 + - 劣势:只能使用 2 组图片来切换选中和非选中状态,修改颜色只能重新换图片(或者用 iconfont)。 +- 2 `有缓存自定义 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。 + - 优势:可以随意配置自己想要的 `svg icon`,切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。 + - 劣势:首次点击 tababr 会闪烁。 +- 3 `无缓存自定义 tabbar`,使用 `navigateTo` 切换 `tabbar`,`tabbar` 页面无缓存。使用了第三方 UI 库的 `tabbar` 组件。 + - 优势:可以随意配置自己想要的 svg icon,切换字体颜色方便。可以实现各种花里胡哨的动效等。 + - 劣势:首次点击 `tababr` 会闪烁,无缓存。 + + +> 注意:花里胡哨的效果需要自己实现,本模版不提供。 diff --git a/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.ts b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.ts new file mode 100644 index 00000000..03be03fb --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbar.ts @@ -0,0 +1,11 @@ +/** + * tabbar 状态,增加 storageSync 保证刷新浏览器时在正确的 tabbar 页面 + * 使用reactive简单状态,而不是 pinia 全局状态 + */ +export const tabbarStore = reactive({ + curIdx: uni.getStorageSync('app-tabbar-index') || 0, + setCurIdx(idx: number) { + this.curIdx = idx + uni.setStorageSync('app-tabbar-index', idx) + }, +}) diff --git a/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbarList.ts b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbarList.ts new file mode 100644 index 00000000..69fbfec0 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/layouts/fg-tabbar/tabbarList.ts @@ -0,0 +1,97 @@ +import type { TabBar } from '@uni-helper/vite-plugin-uni-pages' + +type FgTabBarItem = TabBar['list'][0] & { + icon: string + iconType: 'uiLib' | 'unocss' | 'iconfont' +} + +/** + * tabbar 选择的策略,更详细的介绍见 tabbar.md 文件 + * 0: 'NO_TABBAR' `无 tabbar` + * 1: 'NATIVE_TABBAR' `完全原生 tabbar` + * 2: 'CUSTOM_TABBAR_WITH_CACHE' `有缓存自定义 tabbar` + * 3: 'CUSTOM_TABBAR_WITHOUT_CACHE' `无缓存自定义 tabbar` + * + * 温馨提示:本文件的任何代码更改了之后,都需要重新运行,否则 pages.json 不会更新导致错误 + */ +export const TABBAR_MAP = { + NO_TABBAR: 0, + NATIVE_TABBAR: 1, + CUSTOM_TABBAR_WITH_CACHE: 2, + CUSTOM_TABBAR_WITHOUT_CACHE: 3, +} +// TODO:通过这里切换使用tabbar的策略 +export const selectedTabbarStrategy = TABBAR_MAP.NATIVE_TABBAR + +// selectedTabbarStrategy==NATIVE_TABBAR(1) 时,需要填 iconPath 和 selectedIconPath +// selectedTabbarStrategy==CUSTOM_TABBAR(2,3) 时,需要填 icon 和 iconType +// selectedTabbarStrategy==NO_TABBAR(0) 时,tabbarList 不生效 +export const tabbarList: FgTabBarItem[] = [ + { + iconPath: 'static/tabbar/robot.png', + selectedIconPath: 'static/tabbar/robot_activate.png', + pagePath: 'pages/index/index', + text: '首页', + icon: 'home', + // 选用 UI 框架自带的 icon 时,iconType 为 uiLib + iconType: 'uiLib', + }, + { + iconPath: 'static/tabbar/device.png', + selectedIconPath: 'static/tabbar/device_activate.png', + pagePath: 'pages/device/index', + text: '设备管理', + icon: 'i-carbon-laptop', + // 注意 unocss 的图标需要在 页面上引入一下,或者配置到 unocss.config.ts 的 safelist 中 + iconType: 'uiLib', + }, + { + iconPath: 'static/tabbar/microphone.png', + selectedIconPath: 'static/tabbar/microphone_activate.png', + pagePath: 'pages/voiceprint/index', + text: '声纹识别', + icon: 'i-carbon-microphone-filled', + iconType: 'uiLib', + }, + { + iconPath: 'static/tabbar/chat.png', + selectedIconPath: 'static/tabbar/chat_activate.png', + pagePath: 'pages/chat-history/index', + text: '聊天记录', + icon: 'i-carbon-chat-bot', + iconType: 'uiLib', + }, + // { + // pagePath: 'pages/my/index', + // text: '我的', + // icon: '/static/logo.svg', + // iconType: 'local', + // }, + // { + // pagePath: 'pages/mine/index', + // text: '我的', + // icon: 'iconfont icon-my', + // iconType: 'iconfont', + // }, +] + +// NATIVE_TABBAR(1) 和 CUSTOM_TABBAR_WITH_CACHE(2) 时,需要tabbar缓存 +export const cacheTabbarEnable = selectedTabbarStrategy === TABBAR_MAP.NATIVE_TABBAR + || selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE + +const _tabbar: TabBar = { + // 只有微信小程序支持 custom。App 和 H5 不生效 + custom: selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE, + color: '#e6e6e6', + selectedColor: '#667dea', + backgroundColor: '#fff', + borderStyle: 'black', + height: '50px', + fontSize: '10px', + iconWidth: '24px', + spacing: '3px', + list: tabbarList as unknown as TabBar['list'], +} + +// 0和1 需要显示底部的tabbar的各种配置,以利用缓存 +export const tabBar = cacheTabbarEnable ? _tabbar : undefined diff --git a/main/xiaozhi-mobile-admin/src/layouts/tabbar.vue b/main/xiaozhi-mobile-admin/src/layouts/tabbar.vue new file mode 100644 index 00000000..0c1bb1c6 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/layouts/tabbar.vue @@ -0,0 +1,19 @@ + + + diff --git a/main/xiaozhi-mobile-admin/src/main.ts b/main/xiaozhi-mobile-admin/src/main.ts new file mode 100644 index 00000000..ab429500 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/main.ts @@ -0,0 +1,19 @@ +import { VueQueryPlugin } from '@tanstack/vue-query' +import { createSSRApp } from 'vue' +import App from './App.vue' +import { routeInterceptor } from './router/interceptor' + +import store from './store' +import '@/style/index.scss' +import 'virtual:uno.css' + +export function createApp() { + const app = createSSRApp(App) + app.use(store) + app.use(routeInterceptor) + app.use(VueQueryPlugin) + + return { + app, + } +} diff --git a/main/xiaozhi-mobile-admin/src/pages-sub/demo/index.vue b/main/xiaozhi-mobile-admin/src/pages-sub/demo/index.vue new file mode 100644 index 00000000..4231cff4 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/pages-sub/demo/index.vue @@ -0,0 +1,27 @@ + +{ + "layout": "default", + "style": { + "navigationBarTitleText": "分包页面" + } +} + + + + + + + diff --git a/main/xiaozhi-mobile-admin/src/pages/agent/edit.vue b/main/xiaozhi-mobile-admin/src/pages/agent/edit.vue new file mode 100644 index 00000000..98526bb3 --- /dev/null +++ b/main/xiaozhi-mobile-admin/src/pages/agent/edit.vue @@ -0,0 +1,1085 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "编辑" + } +} + + + + +