commit 9ee0c6c597a3cef596b17eb24dbd29aad2b40f4b
Author: 如初 <3236758982@qq.com>
Date: Tue Apr 14 15:06:26 2026 +0800
first commit
diff --git a/.commitlintrc.cjs b/.commitlintrc.cjs
new file mode 100644
index 0000000..98ee7df
--- /dev/null
+++ b/.commitlintrc.cjs
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: ['@commitlint/config-conventional'],
+}
diff --git a/.cursor/rules/api-http-patterns.mdc b/.cursor/rules/api-http-patterns.mdc
new file mode 100644
index 0000000..ab2f15e
--- /dev/null
+++ b/.cursor/rules/api-http-patterns.mdc
@@ -0,0 +1,37 @@
+# API 和 HTTP 请求规范
+
+## HTTP 请求封装
+- 可以使用 `简单http` 进行请求管理
+- HTTP 配置在 [src/http/](mdc:src/http/) 目录下
+- `简单http` - [src/http/http.ts](mdc:src/http/http.ts)
+- 请求拦截器在 [src/http/interceptor.ts](mdc:src/http/interceptor.ts)
+- 支持请求重试、缓存、错误处理
+
+## API 接口规范
+- API 接口定义在 [src/api/](mdc:src/api/) 目录下
+- 按功能模块组织 API 文件
+- 使用 TypeScript 定义请求和响应类型
+- 支持 `简单http`请求方式
+
+
+## 示例代码结构
+```typescript
+// API 接口定义
+export interface LoginParams {
+ username: string
+ password: string
+}
+
+export interface LoginResponse {
+ token: string
+ userInfo: UserInfo
+}
+```
+
+## 错误处理
+- 统一错误处理在拦截器中配置
+- 支持网络错误、业务错误、认证错误等
+- 自动处理 token 过期和刷新
+---
+globs: src/api/*.ts,src/http/*.ts
+---
diff --git a/.cursor/rules/development-workflow.mdc b/.cursor/rules/development-workflow.mdc
new file mode 100644
index 0000000..4da3f43
--- /dev/null
+++ b/.cursor/rules/development-workflow.mdc
@@ -0,0 +1,43 @@
+# 开发工作流程
+
+## 项目启动
+1. 安装依赖:`pnpm install`
+2. 开发环境:
+ - H5: `pnpm dev` 或 `pnpm dev:h5`
+ - 微信小程序: `pnpm dev:mp`
+ - 支付宝小程序: `pnpm dev:mp-alipay`
+ - APP: `pnpm dev:app`
+
+## 代码规范
+- 使用 ESLint 进行代码检查:`pnpm lint`
+- 自动修复代码格式:`pnpm lint:fix`
+- 使用 eslint 格式化代码
+- 遵循 TypeScript 严格模式
+
+## 构建和部署
+- H5 构建:`pnpm build:h5`
+- 微信小程序构建:`pnpm build:mp`
+- 支付宝小程序构建:`pnpm build:mp-alipay`
+- APP 构建:`pnpm build:app`
+- 类型检查:`pnpm type-check`
+
+## 开发工具
+- 推荐使用 VSCode 编辑器
+- 安装 Vue 和 TypeScript 相关插件
+- 使用 uni-app 开发者工具调试小程序
+- 使用 HBuilderX 调试 APP
+
+## 调试技巧
+- 使用 console.log 和 uni.showToast 调试
+- 利用 Vue DevTools 调试组件状态
+- 使用网络面板调试 API 请求
+- 平台差异测试和兼容性检查
+
+## 性能优化
+- 使用懒加载和代码分割
+- 优化图片和静态资源
+- 减少不必要的重渲染
+- 合理使用缓存策略
+---
+description: 开发工作流程和最佳实践指南
+---
diff --git a/.cursor/rules/project-overview.mdc b/.cursor/rules/project-overview.mdc
new file mode 100644
index 0000000..f0d613e
--- /dev/null
+++ b/.cursor/rules/project-overview.mdc
@@ -0,0 +1,36 @@
+---
+alwaysApply: true
+---
+# unibest 项目概览
+
+这是一个基于 uniapp + Vue3 + TypeScript + Vite5 + UnoCSS 的跨平台开发框架。
+
+## 项目特点
+- 支持 H5、小程序、APP 多平台开发
+- 使用最新的前端技术栈
+- 内置约定式路由、layout布局、请求封装、登录拦截、自定义tabbar等功能
+- 无需依赖 HBuilderX,支持命令行开发
+
+## 核心配置文件
+- [package.json](mdc:package.json) - 项目依赖和脚本配置
+- [vite.config.ts](mdc:vite.config.ts) - Vite 构建配置
+- [pages.config.ts](mdc:pages.config.ts) - 页面路由配置
+- [manifest.config.ts](mdc:manifest.config.ts) - 应用清单配置
+- [uno.config.ts](mdc:uno.config.ts) - UnoCSS 配置
+
+## 主要目录结构
+- `src/pages/` - 页面文件
+- `src/components/` - 组件文件
+- `src/layouts/` - 布局文件
+- `src/api/` - API 接口
+- `src/http/` - HTTP 请求封装
+- `src/store/` - 状态管理
+- `src/tabbar/` - 底部导航栏
+- `src/App.ku.vue` - 全局根组件(类似 App.vue 里面的 template作用)
+
+## 开发命令
+- `pnpm dev` - 开发 H5 版本
+- `pnpm dev:mp` - 开发微信小程序
+- `pnpm dev:mp-alipay` - 开发支付宝小程序(含钉钉)
+- `pnpm dev:app` - 开发 APP 版本
+- `pnpm build` - 构建生产版本
diff --git a/.cursor/rules/styling-css-patterns.mdc b/.cursor/rules/styling-css-patterns.mdc
new file mode 100644
index 0000000..25f14f2
--- /dev/null
+++ b/.cursor/rules/styling-css-patterns.mdc
@@ -0,0 +1,54 @@
+# 样式和 CSS 开发规范
+
+## UnoCSS 原子化 CSS
+- 项目使用 UnoCSS 作为原子化 CSS 框架
+- 配置在 [uno.config.ts](mdc:uno.config.ts)
+- 支持预设和自定义规则
+- 优先使用原子化类名,减少自定义 CSS
+
+## SCSS 规范
+- 使用 SCSS 预处理器
+- 样式文件使用 `lang="scss"` 和 `scoped` 属性
+- 遵循 BEM 命名规范
+- 使用变量和混入提高复用性
+
+## 样式组织
+- 全局样式在 [src/style/](mdc:src/style/) 目录下
+- 组件样式使用 scoped 作用域
+- 图标字体在 [src/style/iconfont.css](mdc:src/style/iconfont.css)
+- 主题变量在 [src/uni_modules/uni-scss/](mdc:src/uni_modules/uni-scss/) 目录下
+
+## 示例代码结构
+```vue
+
+
+ 标题
+
+
+
+
+
+
+
+
+## 响应式设计
+- 使用 rpx 单位适配不同屏幕
+- 支持横屏和竖屏布局
+- 使用 flexbox 和 grid 布局
+- 考虑不同平台的样式差异
+---
+globs: *.vue,*.scss,*.css
+---
diff --git a/.cursor/rules/uni-app-patterns.mdc b/.cursor/rules/uni-app-patterns.mdc
new file mode 100644
index 0000000..143b0b6
--- /dev/null
+++ b/.cursor/rules/uni-app-patterns.mdc
@@ -0,0 +1,62 @@
+# uni-app 开发规范
+
+## 页面开发
+- 页面文件放在 [src/pages/](mdc:src/pages/) 目录下
+- 使用约定式路由,文件名即路由路径
+- 页面配置在仅需要在 宏`definePage` 中配置标题等内容即可,会自动生成到 `pages.json` 中
+
+## 组件开发
+- 组件文件放在 [src/components/](mdc:src/components/) 或者 [src/pages/xx/components/](mdc:src/pages/xx/components/) 目录下
+- 使用 uni-app 内置组件和第三方组件库
+- 支持 wot-ui\uview-pro\uv-ui\sard-ui\uview-plus 等多种第三方组件库 和 z-paging 组件
+- 自定义组件遵循 uni-app 组件规范
+
+## 平台适配
+- 使用条件编译处理平台差异
+- 支持 H5、小程序、APP 多平台
+- 注意各平台的 API 差异
+- 使用 uni.xxx API 替代原生 API
+
+## 示例代码结构
+```vue
+
+
+
+
+
+
+
+
+
+ H5 特有内容
+
+
+
+```
+
+## 生命周期
+- 使用 uni-app 页面生命周期
+- onLoad、onShow、onReady、onHide、onUnload
+- 组件生命周期遵循 Vue3 规范
+- 注意页面栈和导航管理
+---
+globs: src/pages/*.vue,src/components/*.vue
+---
diff --git a/.cursor/rules/vue-typescript-patterns.mdc b/.cursor/rules/vue-typescript-patterns.mdc
new file mode 100644
index 0000000..d81cc8f
--- /dev/null
+++ b/.cursor/rules/vue-typescript-patterns.mdc
@@ -0,0 +1,53 @@
+# Vue3 + TypeScript 开发规范
+
+## Vue 组件规范
+- 使用 Composition API 和 `
+
+
+
+
+
+
+
+
+---
+globs: *.vue,*.ts,*.tsx
+---
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..7f09864
--- /dev/null
+++ b/.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/.gitignore b/.gitignore
new file mode 100644
index 0000000..201f3d7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,48 @@
+# 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
+# 单独把这个文件排除掉,用以解决部分电脑生成的 auto-import.d.ts 的API不完整导致类型提示报错问题
+!src/types/auto-import.d.ts
+src/manifest.json
+src/pages.json
+
+# 2025-10-15 by 菲鸽: 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/.husky/commit-msg b/.husky/commit-msg
new file mode 100644
index 0000000..36158d9
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1 @@
+npx --no-install commitlint --edit "$1"
\ No newline at end of file
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 0000000..c3ec64b
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+npx lint-staged --allow-empty
\ No newline at end of file
diff --git a/.image/admin-uniapp/01.png b/.image/admin-uniapp/01.png
new file mode 100644
index 0000000..9583882
Binary files /dev/null and b/.image/admin-uniapp/01.png differ
diff --git a/.image/admin-uniapp/02.png b/.image/admin-uniapp/02.png
new file mode 100644
index 0000000..0413f5b
Binary files /dev/null and b/.image/admin-uniapp/02.png differ
diff --git a/.image/admin-uniapp/03.png b/.image/admin-uniapp/03.png
new file mode 100644
index 0000000..6c48171
Binary files /dev/null and b/.image/admin-uniapp/03.png differ
diff --git a/.image/common/project-vs.png b/.image/common/project-vs.png
new file mode 100644
index 0000000..561e092
Binary files /dev/null and b/.image/common/project-vs.png differ
diff --git a/.image/common/ruoyi-vue-pro-architecture.png b/.image/common/ruoyi-vue-pro-architecture.png
new file mode 100644
index 0000000..7bd7d59
Binary files /dev/null and b/.image/common/ruoyi-vue-pro-architecture.png differ
diff --git a/.image/common/yudao-cloud-architecture.png b/.image/common/yudao-cloud-architecture.png
new file mode 100644
index 0000000..59416d8
Binary files /dev/null and b/.image/common/yudao-cloud-architecture.png differ
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..f47ca59
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,9 @@
+# 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
+node-options=--max-old-space-size=8192
diff --git a/.trae/rules/project_rules.md b/.trae/rules/project_rules.md
new file mode 100644
index 0000000..0f6064e
--- /dev/null
+++ b/.trae/rules/project_rules.md
@@ -0,0 +1,122 @@
+# unibest 项目概览
+
+这是一个基于 uniapp + Vue3 + TypeScript + Vite5 + UnoCSS 的跨平台开发框架。
+
+## 项目特点
+- 支持 H5、小程序、APP 多平台开发
+- 使用最新的前端技术栈
+- 内置约定式路由、layout布局、请求封装等功能
+- 无需依赖 HBuilderX,支持命令行开发
+
+## 核心配置文件
+- [package.json](mdc:package.json) - 项目依赖和脚本配置
+- [vite.config.ts](mdc:vite.config.ts) - Vite 构建配置
+- [pages.config.ts](mdc:pages.config.ts) - 页面路由配置
+- [manifest.config.ts](mdc:manifest.config.ts) - 应用清单配置
+- [uno.config.ts](mdc:uno.config.ts) - UnoCSS 配置
+
+## 主要目录结构
+- `src/pages/` - 页面文件
+- `src/components/` - 组件文件
+- `src/layouts/` - 布局文件
+- `src/api/` - API 接口
+- `src/http/` - HTTP 请求封装
+- `src/store/` - 状态管理
+- `src/tabbar/` - 底部导航栏
+- `src/App.ku.vue` - 全局根组件(类似 App.vue 里面的 template作用)
+
+## 开发命令
+- `pnpm dev` - 开发 H5 版本
+- `pnpm dev:mp` - 开发微信小程序
+- `pnpm dev:mp-alipay` - 开发支付宝小程序(含钉钉)
+- `pnpm dev:app` - 开发 APP 版本
+- `pnpm build` - 构建生产版本
+
+## Vue 组件规范
+- 使用 Composition API 和 `
+
+
+
+
+
+
+
+
+ H5 特有内容
+
+
+
+```
+
+## 生命周期
+- 使用 uni-app 页面生命周期
+- onLoad、onShow、onReady、onHide、onUnload
+- 组件生命周期遵循 Vue3 规范
+- 注意页面栈和导航管理
\ No newline at end of file
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..883b74d
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,15 @@
+{
+ "recommendations": [
+ "vue.volar",
+ "dbaeumer.vscode-eslint",
+ "antfu.unocss",
+ "antfu.iconify",
+ "evils.uniapp-vscode",
+ "uni-helper.uni-helper-vscode",
+ "uni-helper.uni-app-schemas-vscode",
+ "uni-helper.uni-highlight-vscode",
+ "uni-helper.uni-ui-snippets-vscode",
+ "uni-helper.uni-app-snippets-vscode",
+ "streetsidesoftware.code-spell-checker"
+ ]
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..34b0c74
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "chrome",
+ "name": "针对 localhost 启动 Chrome",
+ "request": "launch",
+ "url": "http://localhost:9000",
+ "env": { "NODE_ENV": "development" },
+ "sourceMaps": true,
+ "webRoot": "${workspaceFolder}"
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..405e410
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,96 @@
+{
+ // 配置语言的文件关联
+ "files.associations": {
+ "pages.json": "jsonc", // pages.json 可以写注释
+ "manifest.json": "jsonc" // manifest.json 可以写注释
+ },
+
+ "stylelint.enable": false, // 禁用 stylelint
+ "css.validate": false, // 禁用 CSS 内置验证
+ "scss.validate": false, // 禁用 SCSS 内置验证
+ "less.validate": false, // 禁用 LESS 内置验证
+
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "explorer.fileNesting.enabled": true,
+ "explorer.fileNesting.expand": false,
+ "explorer.fileNesting.patterns": {
+ "README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md",
+ "docker.md": "Dockerfile,docker*.md,nginx*,.dockerignore",
+ "pages.config.ts": "manifest.config.ts",
+ "package.json": "tsconfig.json,pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
+ "eslint.config.mjs": ".commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
+ },
+
+ // Disable the default formatter, use eslint instead
+ "prettier.enable": false,
+ "editor.formatOnSave": false,
+
+ // Auto fix
+ "editor.codeActionsOnSave": {
+ "source.fixAll.eslint": "explicit",
+ "source.organizeImports": "never"
+ },
+
+ // Silent the stylistic rules in you IDE, but still auto fix them
+ "eslint.rules.customizations": [
+ { "rule": "style/*", "severity": "off", "fixable": true },
+ { "rule": "format/*", "severity": "off", "fixable": true },
+ { "rule": "*-indent", "severity": "off", "fixable": true },
+ { "rule": "*-spacing", "severity": "off", "fixable": true },
+ { "rule": "*-spaces", "severity": "off", "fixable": true },
+ { "rule": "*-order", "severity": "off", "fixable": true },
+ { "rule": "*-dangle", "severity": "off", "fixable": true },
+ { "rule": "*-newline", "severity": "off", "fixable": true },
+ { "rule": "*quotes", "severity": "off", "fixable": true },
+ { "rule": "*semi", "severity": "off", "fixable": true }
+ ],
+
+ // Enable eslint for all supported languages
+ "eslint.validate": [
+ "javascript",
+ "javascriptreact",
+ "typescript",
+ "typescriptreact",
+ "vue",
+ "html",
+ "markdown",
+ "json",
+ "jsonc",
+ "yaml",
+ "toml",
+ "xml",
+ "gql",
+ "graphql",
+ "astro",
+ "svelte",
+ "css",
+ "less",
+ "scss",
+ "pcss",
+ "postcss"
+ ],
+ "cSpell.words": [
+ "alova",
+ "Aplipay",
+ "attributify",
+ "chooseavatar",
+ "climblee",
+ "commitlint",
+ "dcloudio",
+ "iconfont",
+ "oxlint",
+ "qrcode",
+ "refresherrefresh",
+ "scrolltolower",
+ "tabbar",
+ "Toutiao",
+ "uniapp",
+ "unibest",
+ "unocss",
+ "uview",
+ "uvui",
+ "Wechat",
+ "WechatMiniprogram",
+ "Weixin"
+ ]
+}
diff --git a/.vscode/vue3.code-snippets b/.vscode/vue3.code-snippets
new file mode 100644
index 0000000..b650b8a
--- /dev/null
+++ b/.vscode/vue3.code-snippets
@@ -0,0 +1,77 @@
+{
+ // Place your unibest 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
+ // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
+ // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
+ // used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
+ // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
+ // Placeholders with the same ids are connected.
+ // Example:
+ // "Print to console": {
+ // "scope": "javascript,typescript",
+ // "prefix": "log",
+ // "body": [
+ // "console.log('$1');",
+ // "$2"
+ // ],
+ // "description": "Log output to console"
+ // }
+ "Print unibest Vue3 SFC": {
+ "scope": "vue",
+ "prefix": "v3",
+ "body": [
+ "\n",
+ "",
+ " $3",
+ "\n",
+ "\n",
+ ],
+ },
+ "Print unibest style": {
+ "scope": "vue",
+ "prefix": "st",
+ "body": [
+ "\n"
+ ],
+ },
+ "Print unibest script": {
+ "scope": "vue",
+ "prefix": "sc",
+ "body": [
+ "\n"
+ ],
+ },
+ "Print unibest script with definePage": {
+ "scope": "vue",
+ "prefix": "scdp",
+ "body": [
+ "\n"
+ ],
+ },
+ "Print unibest template": {
+ "scope": "vue",
+ "prefix": "te",
+ "body": [
+ "",
+ " $1",
+ "\n"
+ ],
+ },
+}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9e91d10
--- /dev/null
+++ b/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/README.md b/README.md
new file mode 100644
index 0000000..f3aa906
--- /dev/null
+++ b/README.md
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+[](https://github.com/yudaocode/yudao-ui-admin-uniapp)
+[](https://gitee.com/yudaocode/yudao-ui-admin-uniapp/stargazers)
+
+
+
+
+
+
+---
+
+**严肃声明:现在、未来都不会有商业版本,所有代码全部开源!!**
+
+**「我喜欢写代码,乐此不疲」**
+**「我喜欢做开源,以此为乐」**
+
+我 🐶 在上海艰苦奋斗,早中晚在 top3 大厂认真搬砖,夜里为开源做贡献。
+
+如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。
+
+---
+
+## 🐶 新手必读
+
+平台兼容性:
+
+| H5 | iOS | Android | 微信小程序 | 支付宝小程序 | 字节小程序 | 百度小程序 | 钉钉小程序 | 快手小程序 | QQ 小程序 |
+|:--:|:---:|:-------:|:-----:|:------:|:-----:|:-----:|:-----:|:-----:|:------:|
+| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+
+* nodejs >= 20 && pnpm >= 9
+* 启动文档:
+* 视频教程:
+
+## 🐯 平台简介
+
+**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。本项目是 **芋道管理后台的移动端**:
+
+| 工作台 | 工作流 | 个人中心 |
+|:--------------------------------:|:--------------------------------:|:--------------------------------:|
+|  |  |  |
+
+* 采用 `Vue3` + `TypeScript` + `Vite5` + `UnoCSS` + `wot-design-uni` + `z-paging` 构成,使用最新的前端技术栈,无需依赖 `HBuilderX`,通过命令行方式运行 `H5`、`小程序` 和 `App`。
+* 内置了 `约定式路由`、`layout布局`、`请求封装`、`请求拦截`、`登录拦截`、`UnoCSS`、`i18n多语言` 等基础功能,提供了 `代码提示`、`自动格式化`、`统一配置`、`代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验。
+
+## ⚙️ 技术栈
+
+| 框架 | 说明 | 版本 |
+|-----------------------------------------------------|-------------------|--------|
+| [Vue](https://vuejs.org/) | 渐进式 JavaScript 框架 | 3.4.x |
+| [uni-app](https://uniapp.dcloud.io/) | 跨平台应用开发框架 | 3.0.x |
+| [TypeScript](https://www.typescriptlang.org/) | JavaScript 的超集 | 5.8.x |
+| [Vite](https://vitejs.dev/) | 下一代前端构建工具 | 5.2.x |
+| [Pinia](https://pinia.vuejs.org/) | Vue 状态管理库 | 2.0.x |
+| [UnoCSS](https://unocss.dev/) | 即时原子化 CSS 引擎 | 66.x |
+| [unibest](https://github.com/feige996/unibest) | 最好的 uniapp 框架 | 4.1.0 |
+| [wot-design-uni](https://wot-design-uni.pages.dev/) | 高颜值、轻量化 UI 组件库 | 1.13.x |
+| [z-paging](https://z-paging.zxlee.cn/) | 高性能分页组件 | 2.8.x |
+| [vue-i18n](https://vue-i18n.intlify.dev/) | 国际化解决方案 | 9.x |
+
+## ✨ 项目特性
+
+| 特性 | 说明 |
+|-------------------|-----------------------------------------|
+| 🚀 **约定式路由** | 基于文件系统自动生成路由,无需手动配置 |
+| 🎨 **Layout 布局** | 内置多种布局方案,支持 Tabbar 自定义 |
+| 📦 **请求封装** | 基于 uni.request 封装,支持拦截器、TypeScript 类型推导 |
+| 🔐 **登录拦截** | 内置完善的登录态管理与页面拦截机制 |
+| 🎯 **UnoCSS** | 原子化 CSS,按需生成,极致性能 |
+| 🌍 **i18n 多语言** | 内置国际化方案,轻松实现多语言切换 |
+| 📝 **代码规范** | ESLint + Prettier + Husky,保证代码质量 |
+| 🔧 **TypeScript** | 全面的 TypeScript 支持,类型安全 |
+| 📱 **多端适配** | 一套代码,多端运行(H5、小程序、App) |
+
+## 🔥 后端架构
+
+支持 Spring Boot、Spring Cloud 两种架构:
+
+### ① Spring Boot 单体架构
+
+文档地址:
+
+
+
+### ② Spring Cloud 微服务架构
+
+文档地址:
+
+
+
+## 😎 开源协议
+
+**为什么推荐使用本项目?**
+
+① 本项目采用比 Apache 2.0 更宽松的 [MIT License](https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE) 开源协议,个人与企业可 100% 免费使用,不用保留类作者、Copyright 信息。
+
+② 代码全部开源,不会像其他项目一样,只开源部分代码,让你无法了解整个项目的架构设计。[国产开源项目对比](https://www.yuque.com/xiatian-bsgny/lm0ec1/wqf8mn)
+
+
+
+③ 代码整洁、架构整洁,遵循《阿里巴巴 Java 开发手册》规范,代码注释详细,113770 行 Java 代码,42462 行代码注释。
\ No newline at end of file
diff --git a/docs/.vitepress/components/BuildInfo.vue b/docs/.vitepress/components/BuildInfo.vue
new file mode 100644
index 0000000..380ef56
--- /dev/null
+++ b/docs/.vitepress/components/BuildInfo.vue
@@ -0,0 +1,23 @@
+
+
+
+
构建时间: {{ buildTime }}
+
版本号: {{ version }}
+
+
+
+
+
+
diff --git a/docs/.vitepress/composables/cases.ts b/docs/.vitepress/composables/cases.ts
new file mode 100644
index 0000000..f96c451
--- /dev/null
+++ b/docs/.vitepress/composables/cases.ts
@@ -0,0 +1,25 @@
+import { ref, onMounted } from 'vue'
+import axios from 'axios'
+
+export type CaseData = {
+ name: string
+ image: string
+ description?: string
+}
+
+const data = ref([])
+
+export function useCaseData() {
+ const data = [
+ {
+ name: '调剂宝',
+ description: '一个专业的调剂助手,帮助你找到最适合自己的调剂方案。',
+ image:
+ 'https://private-user-images.githubusercontent.com/45726436/455309534-d6ae0ca0-9b42-4c01-8024-90f3d9690765.jpg?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTAwNDA4MjQsIm5iZiI6MTc1MDA0MDUyNCwicGF0aCI6Ii80NTcyNjQzNi80NTUzMDk1MzQtZDZhZTBjYTAtOWI0Mi00YzAxLTgwMjQtOTBmM2Q5NjkwNzY1LmpwZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA2MTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNjE2VDAyMjIwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTJiMTBjOWIwYmY3OTVmMTBkZmY1ZjM3MjhhZmQ0OTc4NmRkMjllZDM2MzMwMmQyOGYyMTFiNmU3MzE3N2FhMmMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.6NIPLDSN3n1LFQTSfynFOIa66DGh3QtIgSkx9zlEf54',
+ },
+ ]
+
+ return {
+ data,
+ }
+}
diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
new file mode 100644
index 0000000..c937727
--- /dev/null
+++ b/docs/.vitepress/config.mts
@@ -0,0 +1,271 @@
+import dayjs from 'dayjs'
+import { defineConfig } from 'vitepress'
+import llmsPlugin from 'vitepress-plugin-llms'
+import packageJson from '../../package.json'
+
+const buildTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
+
+const base = '/unibest/' // default is /
+
+// https://vitepress.dev/reference/site-config
+export default defineConfig({
+ lang: 'zh-CN',
+ base: base,
+ title: 'unibest 官方文档',
+ description: '最好用的 uniapp 开发模板',
+ lastUpdated: true,
+ cleanUrls: true,
+ head: [
+ ['link', { rel: 'icon', href: `${base}favicon.ico` }],
+ // 增加构建信息
+ ['meta', { name: 'build-time', content: buildTime }],
+ ['meta', { name: 'version', content: packageJson.version }],
+ [
+ 'meta',
+ {
+ name: 'keywords',
+ content: 'unibest, uniapp, uni-app, vue, vue3, vite,template, typescript, ts',
+ },
+ ],
+ [
+ 'meta',
+ {
+ name: 'author',
+ content: '菲鸽, 菲哥, 鸽鸽, feige996, feige996, 1020103647@qq.com',
+ },
+ ],
+ [
+ 'meta',
+ {
+ name: 'twitter:title',
+ content: '最好用的 uniapp 开发模板',
+ },
+ ],
+ // 添加 ICP 备案信息
+ ['meta', { name: 'icp', content: '粤ICP备2024160998号' }],
+ ['link', { rel: 'license', href: 'https://beian.miit.gov.cn/' }],
+ // 百度联盟meta
+ ['meta', { property: 'baidu_union_verify', content: '8ab9e6068e7febf94e684886f81f406f' }],
+ // 其他杂七杂八的 meta 标签
+ ['meta', { name: 'twitter:card', content: 'summary_large_image' }],
+ ['meta', { name: 'twitter:site', content: 'feige996' }],
+ [
+ 'meta',
+ {
+ name: 'twitter:image:src',
+ content:
+ 'https://opengraph.githubassets.com/1cac1150838995e1f7d1643c00eee51a5d884f2054f995c9d3225b07b0eddb39/feige996/unibest',
+ },
+ ],
+ [
+ 'meta',
+ {
+ property: 'og:image',
+ content:
+ 'https://opengraph.githubassets.com/1cac1150838995e1f7d1643c00eee51a5d884f2054f995c9d3225b07b0eddb39/feige996/unibest',
+ },
+ ],
+ [
+ 'meta',
+ {
+ property: 'og:image:alt',
+ content: '最好用的 uniapp 开发模板',
+ },
+ ],
+ ['meta', { property: 'og:image:width', content: '1200' }],
+ ['meta', { property: 'og:image:height', content: '600' }],
+ ['meta', { property: 'og:site_name', content: 'GitHub' }],
+ ['meta', { property: 'og:type', content: 'object' }],
+ [
+ 'meta',
+ {
+ property: 'og:title',
+ content: '最好用的 uniapp 开发模板',
+ },
+ ],
+ ['meta', { property: 'og:url', content: 'https://github.com/feige996/unibest' }],
+ [
+ 'meta',
+ {
+ property: 'og:description',
+ content: '最好用的 uniapp 开发模板',
+ },
+ ],
+ // 下面是百度统计代码
+ ['script', { async: '', src: 'https://hm.baidu.com/hm.js?081c2ec121383d9e7d5a35c5833ab6ff' }],
+ // 下面是不蒜子统计代码
+ ['script', { async: '', src: '//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js' }],
+ ],
+ markdown: {
+ theme: {
+ light: 'vitesse-light',
+ dark: 'vitesse-dark',
+ },
+ },
+ themeConfig: {
+ // https://vitepress.dev/reference/default-theme-config
+ logo: '/logo.svg',
+ siteTitle: 'unibest',
+ nav: [
+ {
+ text: '快速开始',
+ link: '/base/2-start',
+ activeMatch: '/base',
+ },
+ {
+ text: '🥤 打赏',
+ link: '/advanced/rewards/rewards',
+ },
+ {
+ text: '更新日志',
+ link: '/changelog/CHANGELOG',
+ },
+ {
+ text: '相关链接',
+ link: '/other/links/links',
+ },
+ {
+ text: 'unibest备用地址',
+ items: [
+ { text: 'unibest.tech(本站)', link: 'https://unibest.tech' },
+ { text: 'github page(备用)', link: 'https://feige996.github.io/unibest/' },
+ ],
+ },
+ ],
+ sidebar: [
+ {
+ text: '基础·必看',
+ base: '/base/',
+ items: [
+ { text: '介绍', link: '1-introduction' },
+ {
+ text: '快速开始',
+ link: '2-start',
+ },
+ { text: 'uni 插件', link: '3-plugin' },
+ { text: '样式篇', link: '4-style' },
+ // { text: '样式篇2', link: '4-style2' },
+ { text: '图标篇', link: '5-icons' },
+ { text: 'SVG篇', link: '6-svg' },
+ { text: 'UI库选型篇', link: 'ui/ui' },
+ { text: 'UI库替换篇', link: '7-ui' },
+ { text: '请求篇', link: '8-request' },
+ { text: '状态篇', link: '9-state' },
+ { text: '多语言篇', link: '10-i18n' },
+ { text: '运行发布', link: '11-build' },
+ { text: 'App 专题', link: '18-app' },
+ // { text: '环境变量', link: '12-env' },
+ { text: 'hbx 模板', link: '13-hbx' },
+ { text: '常见问题', link: '14-faq' },
+ { text: '常见问题2', link: '15-faq' },
+ // { text: '小程序标识', link: '16-terminology' },
+ { text: '自动生成代码', link: '17-generate' },
+ // { text: '最佳实践', link: '20-best' },
+ ],
+ },
+ {
+ text: '⭐ 优秀案例',
+ link: '/advanced/showcase/showcase',
+ },
+ {
+ text: '更新日志',
+ link: '/changelog/CHANGELOG',
+ },
+ {
+ text: '升级指南',
+ link: '/changelog/upgrade',
+ },
+ {
+ text: '社交',
+ base: '/advanced/',
+ items: [
+ { text: '🥤 打赏', link: 'rewards/rewards' },
+ { text: '微信交流群', link: 'wechat/wechat' },
+ { text: '赞助榜', link: 'sponsor/sponsor' },
+ ],
+ },
+ {
+ text: '延伸',
+ base: '/other/',
+ items: [
+ { text: '相关链接', link: 'links/links' },
+ { text: '图片占位图', link: 'image/image' },
+ { text: 'iconfont详细版', link: 'iconfont/iconfont' },
+ // { text: 'Git 提交优化', link: 'czg/czg' },
+ // { text: '文件资源展示优化', link: 'files/files' },
+ { text: 'unibest博客', link: 'blog' },
+ ],
+ },
+ ],
+ footer: {
+ message: 'Released under the MIT License.',
+ copyright: 'Copyright (c) 2024 菲鸽',
+ },
+ socialLinks: [
+ { icon: 'github', link: 'https://github.com/feige996/unibest' },
+ {
+ icon: {
+ svg: ``,
+ },
+ link: 'https://gitee.com/feige996/unibest',
+ ariaLabel: 'Gitee',
+ },
+ {
+ icon: {
+ svg: `
+`,
+ },
+ link: 'https://gitcode.com/feige996/unibest',
+ ariaLabel: 'GitCode',
+ },
+ // #1f80ff 是掘金的 logo 的颜色
+ {
+ icon: {
+ svg: ``,
+ },
+ link: 'https://juejin.cn/user/3263006241460792/posts',
+ ariaLabel: '菲鸽的掘金主页',
+ },
+ ],
+ search: {
+ provider: 'local',
+ options: {
+ locales: {
+ root: {
+ translations: {
+ button: {
+ buttonText: '搜索文档',
+ buttonAriaLabel: '搜索文档',
+ },
+ modal: {
+ displayDetails: '显示详情',
+ resetButtonTitle: '清除查询条件',
+ backButtonTitle: '返回',
+ noResultsText: '无法找到相关结果',
+ footer: {
+ selectText: '选择',
+ selectKeyAriaLabel: '选择',
+ navigateText: '切换',
+ navigateUpKeyAriaLabel: '切换',
+ navigateDownKeyAriaLabel: '切换',
+ closeText: '关闭',
+ closeKeyAriaLabel: '关闭',
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ vite: {
+ // 其他配置...
+ plugins: [llmsPlugin() as any],
+ },
+})
diff --git a/docs/.vitepress/layouts/Default.vue b/docs/.vitepress/layouts/Default.vue
new file mode 100644
index 0000000..6235948
--- /dev/null
+++ b/docs/.vitepress/layouts/Default.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/FreshImage.vue b/docs/.vitepress/theme/components/FreshImage.vue
new file mode 100644
index 0000000..5a60ff1
--- /dev/null
+++ b/docs/.vitepress/theme/components/FreshImage.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/HomeStar.vue b/docs/.vitepress/theme/components/HomeStar.vue
new file mode 100644
index 0000000..287ef53
--- /dev/null
+++ b/docs/.vitepress/theme/components/HomeStar.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/NavBarTitleAfter.vue b/docs/.vitepress/theme/components/NavBarTitleAfter.vue
new file mode 100644
index 0000000..f115b68
--- /dev/null
+++ b/docs/.vitepress/theme/components/NavBarTitleAfter.vue
@@ -0,0 +1,20 @@
+
+
+
+
+ {{ version }}
+
+
diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css
new file mode 100644
index 0000000..064f125
--- /dev/null
+++ b/docs/.vitepress/theme/custom.css
@@ -0,0 +1,84 @@
+/**
+ * Colors
+ * -------------------------------------------------------------------------- */
+:root {
+ --vp-c-brand-1: hsl(128, 56%, 38%);
+ --vp-c-brand-2: hsl(128, 56%, 55%);
+ --vp-c-brand-3: hsl(128, 56%, 45%);
+ --vp-c-brand-soft: rgba(98, 133, 208, 0.16);
+}
+/**
+ * Component: Home
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-home-hero-name-color: transparent;
+ --vp-home-hero-name-background: -webkit-linear-gradient(
+ 120deg,
+ hsl(128, 56%, 38%) 30%,
+ hsl(128, 56%, 60%)
+ );
+ --vp-home-hero-image-background-image: linear-gradient(
+ 120deg,
+ hsl(100, 56%, 45%) 30%,
+ hsl(120, 56%, 38%)
+ );
+ --vp-home-hero-image-filter: blur(40px);
+}
+@media (min-width: 640px) {
+ :root {
+ --vp-home-hero-image-filter: blur(56px);
+ }
+}
+
+@media (min-width: 960px) {
+ :root {
+ --vp-home-hero-image-filter: blur(72px);
+ }
+}
+
+.md-center > p {
+ display: flex;
+ /* justify-content: center; */
+ flex-wrap: wrap;
+ margin-top: -4px;
+ margin-right: -4px;
+}
+.md-center img {
+ display: inline-block;
+ height: 1.4em;
+ margin-top: 4px;
+ margin-right: 4px;
+ line-height: 1.6;
+}
+.md-center2 img {
+ display: inline-block;
+ margin-top: 4px;
+ margin-right: 4px;
+}
+
+.busuanzi_container {
+ display: flex;
+ justify-content: space-around;
+ opacity: 0.3;
+}
+
+@media (max-width: 960px) {
+ .busuanzi_container {
+ flex-direction: column;
+ padding-top: 12px;
+ padding-left: 30px;
+ }
+}
+@media (min-width: 961px) {
+ .busuanzi_container {
+ height: 60px;
+ line-height: 60px;
+ }
+}
+
+.icp_container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
new file mode 100644
index 0000000..ac3e97a
--- /dev/null
+++ b/docs/.vitepress/theme/index.ts
@@ -0,0 +1,28 @@
+// https://vitepress.dev/guide/custom-theme
+import type { Theme } from 'vitepress'
+import DefaultTheme from 'vitepress/theme'
+import { h } from 'vue'
+import './custom.css'
+
+import HomeStar from './components/HomeStar.vue'
+import NavBarTitleAfter from './components/NavBarTitleAfter.vue'
+import FreshImage from './components/FreshImage.vue'
+
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+
+export default {
+ extends: DefaultTheme,
+ Layout: () => {
+ return h(DefaultTheme.Layout, null, {
+ // https://vitepress.dev/guide/extending-default-theme#layout-slots
+ 'home-hero-info-after': () => h(HomeStar),
+ 'nav-bar-title-after': () => h(NavBarTitleAfter),
+ })
+ },
+ enhanceApp({ app, router, siteData }) {
+ // ...
+ app.component('FreshImage', FreshImage)
+ app.use(ElementPlus)
+ },
+} satisfies Theme
diff --git a/docs/advanced/me/image-2.png b/docs/advanced/me/image-2.png
new file mode 100644
index 0000000..b18b7ca
Binary files /dev/null and b/docs/advanced/me/image-2.png differ
diff --git a/docs/advanced/me/image-3.png b/docs/advanced/me/image-3.png
new file mode 100644
index 0000000..02473d5
Binary files /dev/null and b/docs/advanced/me/image-3.png differ
diff --git a/docs/advanced/me/me.md b/docs/advanced/me/me.md
new file mode 100644
index 0000000..867d601
--- /dev/null
+++ b/docs/advanced/me/me.md
@@ -0,0 +1,30 @@
+# 关于我
+
+我叫 `菲鸽`,江西宋城人。前端工程师,全栈实践者,精通 `vue`、`react`、`uniapp`、`typescript`、`小程序`、`Nodejs` 等。
+
+热爱编程,喜欢分享,平时比较宅,喜欢撸代码,偶尔打篮球和玩王者荣耀。
+
+
+
+## 找到我
+
+- Github: [feige996](https://github.com/feige996)
+- Gitee: [feige996](https://gitee.com/feige996)
+- 掘金:[菲鸽](https://juejin.cn/user/3263006241460792/posts)
+- 微信:`feige996` = `菲鸽`,大家都叫我 `鸽鸽`
+- QQ:`1020103647`
+- 邮箱:`1020103647@qq.com`
+
+## 微信公众号
+
+微信公众号:`菲鸽爱编程`
+
+
+
+
diff --git a/docs/advanced/me/screenshots/pay-wx.png b/docs/advanced/me/screenshots/pay-wx.png
new file mode 100644
index 0000000..8c8c633
Binary files /dev/null and b/docs/advanced/me/screenshots/pay-wx.png differ
diff --git a/docs/advanced/me/screenshots/wx-gzh.png b/docs/advanced/me/screenshots/wx-gzh.png
new file mode 100644
index 0000000..25fcb5b
Binary files /dev/null and b/docs/advanced/me/screenshots/wx-gzh.png differ
diff --git a/docs/advanced/me/screenshots/wx-me.png b/docs/advanced/me/screenshots/wx-me.png
new file mode 100644
index 0000000..efb91b9
Binary files /dev/null and b/docs/advanced/me/screenshots/wx-me.png differ
diff --git a/docs/advanced/rewards/assets/group-qq.jpg b/docs/advanced/rewards/assets/group-qq.jpg
new file mode 100644
index 0000000..6f6df26
Binary files /dev/null and b/docs/advanced/rewards/assets/group-qq.jpg differ
diff --git a/docs/advanced/rewards/assets/group-wx.jpg b/docs/advanced/rewards/assets/group-wx.jpg
new file mode 100644
index 0000000..78f2261
Binary files /dev/null and b/docs/advanced/rewards/assets/group-wx.jpg differ
diff --git a/docs/advanced/rewards/assets/pay-1.png b/docs/advanced/rewards/assets/pay-1.png
new file mode 100644
index 0000000..92e8019
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-1.png differ
diff --git a/docs/advanced/rewards/assets/pay-2.png b/docs/advanced/rewards/assets/pay-2.png
new file mode 100644
index 0000000..9004bed
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-2.png differ
diff --git a/docs/advanced/rewards/assets/pay-ali.png b/docs/advanced/rewards/assets/pay-ali.png
new file mode 100644
index 0000000..dce450a
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-ali.png differ
diff --git a/docs/advanced/rewards/assets/pay-w-5.png b/docs/advanced/rewards/assets/pay-w-5.png
new file mode 100644
index 0000000..8de0cf8
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-w-5.png differ
diff --git a/docs/advanced/rewards/assets/pay-wx-10.png b/docs/advanced/rewards/assets/pay-wx-10.png
new file mode 100644
index 0000000..c035320
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-wx-10.png differ
diff --git a/docs/advanced/rewards/assets/pay-wx-2.png b/docs/advanced/rewards/assets/pay-wx-2.png
new file mode 100644
index 0000000..9a5f692
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-wx-2.png differ
diff --git a/docs/advanced/rewards/assets/pay-wx-5-doc.png b/docs/advanced/rewards/assets/pay-wx-5-doc.png
new file mode 100644
index 0000000..e484ed0
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-wx-5-doc.png differ
diff --git a/docs/advanced/rewards/assets/pay-wx-5.png b/docs/advanced/rewards/assets/pay-wx-5.png
new file mode 100644
index 0000000..909c225
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-wx-5.png differ
diff --git a/docs/advanced/rewards/assets/pay-wx.png b/docs/advanced/rewards/assets/pay-wx.png
new file mode 100644
index 0000000..8c8c633
Binary files /dev/null and b/docs/advanced/rewards/assets/pay-wx.png differ
diff --git a/docs/advanced/rewards/rewards.md b/docs/advanced/rewards/rewards.md
new file mode 100644
index 0000000..03576e9
--- /dev/null
+++ b/docs/advanced/rewards/rewards.md
@@ -0,0 +1,8 @@
+# 🥤 打赏
+
+如果本项目对你的工作起到了帮助,加快了您的项目进展,解决了您的问题,欢迎 `打赏` !
+
+
+
+
+
diff --git a/docs/advanced/showcase/data.json b/docs/advanced/showcase/data.json
new file mode 100644
index 0000000..e69de29
diff --git a/docs/advanced/showcase/showcase.md b/docs/advanced/showcase/showcase.md
new file mode 100644
index 0000000..323d0ae
--- /dev/null
+++ b/docs/advanced/showcase/showcase.md
@@ -0,0 +1,81 @@
+# ⭐ 优秀案例
+
+我们非常欢迎大家一起贡献优秀的案例,欢迎在此 [issue](https://github.com/feige996/unibest/issues/139) 提交案例。
+
+`unibest` 已被很多公司和团队在生产环境使用,下面是一些优秀的案例:
+
+
+
+
+
+
+ {{ item.name }}
+ {{ item.desc }}
+
+
+
+
+
+
diff --git a/docs/advanced/showcase/云打牌.png b/docs/advanced/showcase/云打牌.png
new file mode 100644
index 0000000..d5ecf85
Binary files /dev/null and b/docs/advanced/showcase/云打牌.png differ
diff --git a/docs/advanced/showcase/佰润.png b/docs/advanced/showcase/佰润.png
new file mode 100644
index 0000000..9bfb8cf
Binary files /dev/null and b/docs/advanced/showcase/佰润.png differ
diff --git a/docs/advanced/showcase/卡路里伙伴.png b/docs/advanced/showcase/卡路里伙伴.png
new file mode 100644
index 0000000..4c3e607
Binary files /dev/null and b/docs/advanced/showcase/卡路里伙伴.png differ
diff --git a/docs/advanced/showcase/橙掌柜.png b/docs/advanced/showcase/橙掌柜.png
new file mode 100644
index 0000000..59fe07d
Binary files /dev/null and b/docs/advanced/showcase/橙掌柜.png differ
diff --git a/docs/advanced/showcase/监所通.png b/docs/advanced/showcase/监所通.png
new file mode 100644
index 0000000..1f8837c
Binary files /dev/null and b/docs/advanced/showcase/监所通.png differ
diff --git a/docs/advanced/showcase/监所邮.png b/docs/advanced/showcase/监所邮.png
new file mode 100644
index 0000000..c9a48c6
Binary files /dev/null and b/docs/advanced/showcase/监所邮.png differ
diff --git a/docs/advanced/showcase/进货平台.png b/docs/advanced/showcase/进货平台.png
new file mode 100644
index 0000000..94c82b2
Binary files /dev/null and b/docs/advanced/showcase/进货平台.png differ
diff --git a/docs/advanced/sponsor/sponsor.md b/docs/advanced/sponsor/sponsor.md
new file mode 100644
index 0000000..1397a8b
--- /dev/null
+++ b/docs/advanced/sponsor/sponsor.md
@@ -0,0 +1,62 @@
+# 赞助榜
+
+感谢所有赞助者!
+
+如需更改展示信息,或者需要展示更详细的信息,请联系我。
+
+如果需要展示产品、博客、友链啥的,也可以联系我,很乐意为您展示。
+
+> 金牌赞助者将额外获得首页产品展示位。
+
+## 200 元
+
+- 麦可
+- 程序员云创 [https://www.codecommitter.com/](https://www.codecommitter.com/)
+- 海鲜™ 深圳金济福科技有限公司[https://www.jinjifu.com/](https://www.jinjifu.com/)
+
+## 50 元
+
+- \*皮
+- 暗月隐落 [飞鸟快验 - 一个通用网络验证后台](https://www.fnkuaiyan.cn)
+
+## 20 元
+
+- \*捷
+- \*度
+- \*恼
+
+## 10-20 元
+
+- 薛柳(15)
+- 是魔王哒(12)
+
+## 10 元
+
+- \*辛
+- \*y
+- \*边
+
+## 5-10 元
+
+- Leo (9.90)
+- \*熙 (6.66)
+- 阿森纳 (6.66)
+- I am 小萝北 ²º²4 (6.60)
+- SUMMER (5)
+- \*峰 (5)
+- 阿云 (5)
+- nuYoah (5)
+- 许志成 (5)
+- JY_en_ke_hao (5)
+
+## 2 元及以下
+
+有 `15` 人,这里不一一列出。(如果希望展示,请联系我)
+
+## 红包打赏
+
+还有一部分群友是发 `专属红包` 打赏的,这里没有统计,如果需要展示,请联系我。
+
+---
+
+> 再次感谢所有赞助者、打赏者!
diff --git a/docs/advanced/wechat/wechat.md b/docs/advanced/wechat/wechat.md
new file mode 100644
index 0000000..01b3dc1
--- /dev/null
+++ b/docs/advanced/wechat/wechat.md
@@ -0,0 +1,12 @@
+# 微信交流群
+
+千万记得 `先看一遍文档`,可以解决大部分基础疑问。
+
+
+
+
+
+> 如果上面的微信群满了,请使用下面的 QQ 群,QQ 群不会过期,长期有效。
+
+①②③ 群已满,下面是 ④ 群。
+
diff --git a/docs/base/1-introduction.md b/docs/base/1-introduction.md
new file mode 100644
index 0000000..a486e08
--- /dev/null
+++ b/docs/base/1-introduction.md
@@ -0,0 +1,208 @@
+# 简介
+
+
+
+[](https://github.com/codercup/unibest)
+[](https://github.com/feige996/unibest)
+[](https://gitee.com/codercup/unibest)
+
+
+
+
+
+
+> 上面前 2 个 `star` 分别是旧仓库 `codercup` 和新仓库 `feige996` 的 `star` 数。
+
+`unibest` 是最好的 `uniapp` 开发框架,由 `uniapp` + `Vue3` + `Ts` + `Vite5` + `UnoCss` + `VSCode`(可选 `webstorm`) + `uni插件`+ `wot-ui`(可选其他 UI 库)构建,集成了多种工具和技术,使用了最新的前端技术栈,无需依靠 `HBuilderX`,通过命令行方式即可运行 `web`、`小程序` 和 `App`。(注:`App` 还是需要 `HBuilderX`)
+
+`unibest` 内置了 `约定式路由`、`layout布局`、`请求封装`、`请求拦截`、`登录拦截`、`UnoCSS`、`i18n多语言` 等基础功能,提供了 `代码提示`、`自动格式化`、`统一配置`、`代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验 ( `unibest 的由来`)。
+
+> `unibest` 目前支持 `H5`、`小程序` 和 `App`。
+
+::: tip ⭐⭐⭐⭐⭐
+如果 `unibest` 对您有帮助,希望你可以去 **Github** 或者 **Gitee(码云)** 帮我点个 ⭐ ,这将是对我极大的鼓励。
+
+
+
+[](https://github.com/feige996/unibest)
+
+
+
+[](https://gitee.com/feige996/unibest)
+
+:::
+
+::: tip 🌟🌟🌟🌟🌟
+旧的文档地址 [codercup/unibest](https://codercup.github.io/unibest-docs/)不再维护,尽量使用新地址[unibest.tech](https://unibest.tech)。
+:::
+
+## ⭐ Star History
+
+同类模板对比实时地址:[https://www.star-history.com/#Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&codercup/unibest&feige996/unibest&DaMaiCoding/uni-plus&Date](https://www.star-history.com/#Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&codercup/unibest&feige996/unibest&DaMaiCoding/uni-plus&Date)
+
+如图所示,两个高高的都是 `unibest`,分别是新旧仓库。
+
+黄色的是旧的 `codercup`,秘钥丢失,进不去了。粉色的新的仓库(`feige996`),目前正在积极维护。
+
+[](https://www.star-history.com/#Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&codercup/unibest&feige996/unibest&DaMaiCoding/uni-plus&Date)
+
+## 🗂 生成过程
+
+`unibest` 由最初始的官方 cli 脚手架模板生成,执行的命令如下:
+
+```sh
+npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project
+```
+
+`uniapp` 官方链接:[点击跳转 - quickstart-cli](https://uniapp.dcloud.net.cn/quickstart-cli.html)
+
+在官方生成的项目基础上,增加了如下内容:
+
+- 前端基础配置六件套
+ - prettier
+ - eslint
+ - stylelint
+ - husky
+ - lint-staged
+ - commitlint
+- UnoCSS
+- UnoCSS Icons
+- Uni 插件
+ - vite-plugin-uni-pages
+ - vite-plugin-uni-layouts
+ - vite-plugin-uni-manifest
+ - vite-plugin-uni-platform
+- UI 库(默认 `wot-ui`,支持替换其他 `UI库`)
+- pinia + pinia-plugin-persistedstate
+- 通用功能
+ - 请求封装
+ - 请求拦截
+ - 路由拦截
+
+## ✨ 特性
+
+- ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [esbuild](https://github.com/evanw/esbuild) - 就是快!
+
+- 🔥 最新语法 - `
+```
+
+:::
+
+## 3. Vue-Official ( ` vue.volar` ) 使用哪个版本?
+
+`2025-05-22` 更新 :经测试,最新可用版本为 `v2.2.8` ,`v2.2.10` 会报错。(可以关闭 vue.volar 的自动更新)
+
+
+
+## 4. 为啥不用 `vant-ui`?
+
+`vant-ui` 是 `WEB` 端 `UI 库`,不适用于 `uni-app`。
+
+`uni-app` 没有 `window`, `document` 等 `WEB API`,所以凡是使用 `WEB API` 的 `框架`、`UI 库` 等都不适用于 `uni-app`。
+
+## 4. 控制台报错 `[plugin:uni:mp-using-component] Unexpected token S in JSON at position 208`。
+
+控制台报错如下:
+
+
+原因是 `uni-pages` 这个插件最新版本 `0.2.22` 有问题,需要回退到 `0.2.20`。
+
+
+
+执行如下命令即可:
+
+```
+pnpm add @uni-helper/vite-plugin-uni-pages@0.2.20
+```
+
+> 因为 `unibest` 在 `2.3.0(含)` 之前没有把 `pnpm-lock.yaml` 加入到版本管理,导致小版还是有细微差别。
+>
+> 在 `2.4.0` 开始已经加入,不会再出现这个问题。
+
+## 5.不会 TypeScript 怎么办
+
+不管个人还是团队、产品或者项目,从长远考虑我们都建议你学习 TypeScript,因为它是未来的趋势,而且大部分框架、库、插件都是用 TypeScript 开发的,足以证明它是构建一款成熟稳健产品的基石。
+
+但考虑到实际情况,会各种客观原因存在,如果必须要用传统 JavaScript 进行开发,你可以在 `tsconfig.json` 里将 `allowJs` 设置为 `true` 即可,框架原有的 TypeScript 代码不会受到影响,并且你也可以在项目中使用 JavaScript 编写代码。
+
+## 6.微信小程序 `INVALID_LOGIN`
+
+微信小程序开发进入登录页时,可能导致如下问题:
+
+```text
+{errMsg: "navigateTo:fail Error: INVALID_LOGIN,
+access_token expired [20250103 17:08:03][touristappid]"}
+```
+
+> 解答:游客模式会出现该错误,微信扫码登录一下就可以了。
diff --git a/docs/base/16-terminology.md b/docs/base/16-terminology.md
new file mode 100644
index 0000000..dbb3d3b
--- /dev/null
+++ b/docs/base/16-terminology.md
@@ -0,0 +1,17 @@
+# 小程序的标识
+
+目前有以下 `9` 种小程序标识,对应小程序平台类型如下:
+
+| 类型 | 标识 |
+| ------------ | ----------- |
+| 微信小程序 | mp-weixin |
+| 支付宝小程序 | mp-alipay |
+| 抖音小程序 | mp-toutiao |
+| 飞书小程序 | mp-lark |
+| QQ小程序 | mp-qq |
+| 京东小程序 | mp-jd |
+| 小红书小程序 | mp-xhs |
+| 百度小程序 | mp-baidu |
+| 快手小程序 | mp-kuaishou |
+
+> 注意: `mp-toutiao` 就是抖音小程序,其他的都很好辨别。
diff --git a/docs/base/17-generate.md b/docs/base/17-generate.md
new file mode 100644
index 0000000..cbab48e
--- /dev/null
+++ b/docs/base/17-generate.md
@@ -0,0 +1,135 @@
+# 自动生成代码
+
+
+
+集成 [openapi-ts-request](https://github.com/openapi-ui/openapi-ts-request) 插件,可以根据接口文档自动生成 js,ts,uni.request,vue-query 代码。
+
+> 好用的话记得点赞,`star` 支持下。
+
+支持 apifox/swagger/opeanpi/yapi 等接口文档,更多配置详情请查看 [openapi-ts-request](https://github.com/openapi-ui/openapi-ts-request) 插件。
+
+## 如何使用
+
+你只需要将接口文档对应的接口配置url,复制到根目录的 `openapi-ts-request.config.ts` 插件的配置文件中的 `schemaPath` 字段中,然后运行 `npm run openapi-ts-request` 命令,就可以生成代码。
+支持同时配置多个接口文档url,生成的代码默认会放在 `src/service/app` 目录下,你可以自己调整生成代码的目录。
+
+配置如下:
+
+```ts
+import type { GenerateServiceProps } from 'openapi-ts-request'
+
+export default [
+ {
+ schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
+ serversPath: './src/service/app',
+ requestLibPath: `import request from '@/utils/request';\n import { CustomRequestOptions } from '@/interceptors/request';`,
+ requestOptionsType: 'CustomRequestOptions',
+ isGenReactQuery: true,
+ reactQueryMode: 'vue',
+ isGenJavaScript: false,
+ },
+] as GenerateServiceProps[]
+```
+
+## 生成 ts 代码
+
+ts 的 type 类型会默认生成在 `src/service/app/types.ts` 文件,你可以通过引入它们进行使用。
+
+```ts
+import { type Category } from '@/service/app'
+
+const category: Category = {
+ id: 1,
+ name: '张三',
+}
+```
+
+## 生成 uni.request 代码
+
+ts 的 uni.request 客户端会默认生成在 `src/service/app` 目录下,以模块名进行分类,你可以通过引入它们进行使用。
+
+```ts
+import { getPetById } from '@/service/app'
+
+onShow(() => {
+ const res = await getPetById({ id: 1 })
+ console.log('res: ', res)
+})
+```
+
+## 生成 vue-query 代码
+
+vue-query 的代码会默认生成在 `src/service/app` 目录下,以模块名进行分类,后缀为 `moduleName.vuequery.ts`,你可以通过引入它们进行使用。
+
+```ts
+import { useQuery } from '@tanstack/vue-query'
+import { findPetsByStatusQueryOptions, usePlaceOrderMutation } from '@/service/app'
+
+// get请求使用,findPetsByStatusQueryOptions 方法为自动生成 react-query 函数
+export function findPetsByStatusQueryOptions(options: {
+ // 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
+ params: API.findPetsByStatusParams;
+ options?: CustomRequestOptions;
+}) {
+ return queryOptions({
+ queryFn: async ({ queryKey }) => {
+ return apis.findPetsByStatus(queryKey[1] as typeof options);
+ },
+ queryKey: ['findPetsByStatus', options],
+ });
+}
+
+// vue-query useQuery 默认使用
+const {
+ data,
+ error
+ isLoading,
+ refetch,
+} = useQuery(findPetsByStatusQueryOptions({ params: { status: ['available'] } }))
+
+// vue-query useQuery 额外配置
+const {
+ data,
+ error
+ isLoading,
+ refetch,
+} = useQuery({
+ ...findPetsByStatusQueryOptions({ params: { status: ['available'] } }),
+ enabled: !!token,
+})
+
+// post, delete, patch请求使用,usePlaceOrderMutation 为自动生成 vue-query hook函数
+export function usePlaceOrderMutation(options?: {
+ onSuccess?: (value?: API.Order) => void;
+ onError?: (error?: DefaultError) => void;
+}) {
+ const { onSuccess, onError } = options || {};
+
+ const response = useMutation({
+ mutationFn: apis.placeOrder,
+ onSuccess(data: API.Order) {
+ onSuccess?.(data);
+ },
+ onError(error) {
+ onError?.(error);
+ },
+ });
+
+ return response;
+}
+
+// 定义请求
+const { mutate, isPending } = usePlaceOrderMutation({
+ onSuccess: (data) => {
+ console.log('success data: ', data)
+ },
+})
+
+// 提交请求
+mutate({
+ body: {
+ status: 'placed',
+ complete: true,
+ }
+})
+```
diff --git a/docs/base/17-good.png b/docs/base/17-good.png
new file mode 100644
index 0000000..9255189
Binary files /dev/null and b/docs/base/17-good.png differ
diff --git a/docs/base/18-app-1.png b/docs/base/18-app-1.png
new file mode 100644
index 0000000..cf4649a
Binary files /dev/null and b/docs/base/18-app-1.png differ
diff --git a/docs/base/18-app-2.png b/docs/base/18-app-2.png
new file mode 100644
index 0000000..190f5b2
Binary files /dev/null and b/docs/base/18-app-2.png differ
diff --git a/docs/base/18-app-3.png b/docs/base/18-app-3.png
new file mode 100644
index 0000000..cd0deae
Binary files /dev/null and b/docs/base/18-app-3.png differ
diff --git a/docs/base/18-app.md b/docs/base/18-app.md
new file mode 100644
index 0000000..699b627
--- /dev/null
+++ b/docs/base/18-app.md
@@ -0,0 +1,72 @@
+# App 专题
+
+## 1. 其他端正常,`App` 白屏
+
+请检查 `useXxxStore` 的调用,需要在函数内部调用,而不是在函数外部调用。(估计是顶层调用的时候 `pinia` 没有初始化,导致的问题,`app` 端独有的问题。)
+
+```ts
+// 错误写法
+const userStore = useUserStore()
+function foo() {
+ userStore.xxx
+}
+// 正确写法
+function foo() {
+ const userStore = useUserStore()
+ userStore.xxx
+}
+```
+
+## 2.unibest 的 `App` 模块配置
+
+> 核心解决办法就是把 `manifest.json` 的内容搬运到 `manifest.config.ts` 中。
+
+我们默认的的 `manifest.config.ts` 只包含了比较基础的 `uniapp` 配置,有的时候我们需要在打包 `app` 时在 `hbuilderx` 里面额外设置一些配置,那么就需要配置好后把 `manifest.json` 中的内容拷贝到 `manifest.config.ts` 中,后面运行就不会丢失了。
+
+举例子,我在 `manifest.json` 里面配置了 2个模块配置,如下:
+
+
+点击左侧下面的 `源码视图` 就可以看到增加了如下内容:
+
+
+只需要把对应的内容拷贝到 `manifest.config.ts` 中的 `distribute.plugins` 里面即可。
+
+## 3. `app` 热更新
+
+### 3.1 `ios` 模拟器热更新
+
+- `pnpm dev:app`
+- 把 `dist/dev/app` 文件夹导入到 `hbx编辑器` 里面,然后运行。这样在编码的时候是可以热更新的。
+
+> 但是上面的方法,在android 模拟器里面不生效。
+
+### 3.2 `android` 热更新
+
+- 在 `android` 里面,把`dist/dev/app` 文件夹导入到 `hbx编辑器` 里面运行,无法热更新!!
+- 需要把整个 `unibest 项目中的 src 文件夹` 导入到 `hbx编辑器` 里面,然后运行,这样就可以热更新。
+- 不管是模拟器还是真机调试,都是这样。
+
+### 3.3. `鸿蒙` 热更新
+
+同 `android` 热更新。
+
+## 4. 打包原生插件
+
+> 思路:你把整个 `unibest项目的src` 放到 `hbx编辑器`,然后在 `src/mainifest.json` 里面配置好 `原生插件`。然后 `copy` 到`manifest.config.ts`,接着自定义打包基座。
+> 注意,全程不需要用到 `pnp build dev:app` 这个命令.
+
+步骤:
+
+- 1. 先配置好 `原生插件`,再 `copy` 到 `manifest.config.ts`。
+
+ 
+
+- 2. 先打包自定义基座
+
+ 
+
+- 3. 使用自定义基座
+
+ 
+
+> 其他参看文章 [掘金教程 - Unibest 原生插件模块配置](https://juejin.cn/post/7496807547447427081)
diff --git a/docs/base/2-start.md b/docs/base/2-start.md
new file mode 100644
index 0000000..454ae39
--- /dev/null
+++ b/docs/base/2-start.md
@@ -0,0 +1,131 @@
+# 快速开始
+
+- 前置依赖
+
+ - **Node.js** - `>=v18`
+ - **pnpm** - `>=7.30`(推荐使用 `8.12+`)
+ - **`VSCode`** - 可选 `WebStrom`
+ - **`HBuilderX`** - `APP` 的运行和发布还是离不开它
+
+## 创建项目
+
+通过下面的命令可以快速生成项目模板,`pnpm create unibest <项目名称>` ,如果不写 `<项目名称>` 会进入命令行交互模式。
+
+```bash
+# 如果没有 pnpm,请先安装: npm i -g pnpm
+pnpm create unibest my-project
+# 时不时加一下 @latest 标识,这样可以使用最新版本的 create-unibest (2025-06-04 发布了 v1.18.5)
+pnpm create unibest@latest my-project
+```
+
+npm 创建如下(不推荐)
+:::details
+如果使用 `npm`,可能有缓存,需要加上 `@latest` 标识,如果创建失败,请使用 `pnpm` 安装。
+
+```bash
+npm create unibest my-project
+# 如果提示报错,或者生成的项目版本太旧,请使用下面的命令,增加 @latest 标识
+npm create unibest@latest my-project
+```
+
+:::
+实际操作截图如下:
+
+
+
+`create-unibest` 在 `v1.10.0` 开始会有版本号,如下:
+
+
+
+
+
+`create unibest` 支持 `-t` 参数选择模板,目前已有两大类 `8` 个模板
+
+- `普通` 模板( `4个` ):分别是 `base`、`tabbar`、`spa`、 `i18n`、`demo`。
+- `hbx` 模板(`2个` ):分别是 `hbx-base`、`hbx-demo`。
+
+不带 `-t` 参数时会默认生成 `base` 模板。
+
+`base` 模板是最基本的模板,更新最及时,推荐使用 `base` 模板创建新项目。其他几个模板也是基于 `base` 模板得到的。 `demo` 模板则作为参考用。
+
+`base` 模板的改动会自动同步到其他几个分支,通过 `github actions` 实现。
+
+::: details `tabbar 模板` 和 `spa 模板` 的区别
+
+- `tabbar` 模板里面的tabbar 路由是属于 `tabbar` 级别的,需要使用 `switchTabbar` 切换,`tabbar` 页面会有缓存,渲染性能较好。
+- `spa` 模板类似于前端的 `SPA 应用`,`tabbar` 完全是一个组件实现的。页面之间切换是通过前端状态控制,简单灵活,不受 `tabbar` 的配置限制,但性能不如 `tabbar` 模板。
+- 两者各有优点,按需选用。
+
+:::
+
+```sh
+# VS Code 模板
+pnpm create unibest my-project # 默认用 base 模板
+
+pnpm create unibest my-project -t base # 基础模板
+pnpm create unibest my-project -t tabbar # 自定义 tabbar 模板
+pnpm create unibest my-project -t spa # 单页应用 模板(使用一个组件模拟tabbar)
+pnpm create unibest my-project -t i18n # 多语言模板
+pnpm create unibest my-project -t demo # 所有demo的模板(包括i18n)
+
+# HBuilderX 模板,方便使用 uniCloud 云开发 (未来可以对接 uni-app x)
+pnpm create unibest my-project -t hbx-base # hbx的base模板
+pnpm create unibest my-project -t hbx-demo # hbx的demo模板,包含所有的demo
+```
+
+> 2024-12-29<周日> 发表了一篇文章:[【unibest】可以去掉hbx模版了,base模板一统天下](https://mp.weixin.qq.com/s/ybunFNkjKfV5yVLOMvqscg?token=1696234630&lang=zh_CN)
+>
+> 就是说 hbx 模板可以退出历史舞台了。
+
+## 项目仓库地址
+
+`github` 和 `gitee` 实时同步,代码一致。
+
+### 普通模板:
+
+- https://github.com/feige996/unibest
+- https://gitee.com/feige996/unibest
+
+> `demo` 模板是在 `hello-unibest` 项目中,仓库地址如下:
+
+- https://github.com/feige996/hello-unibest
+- https://gitee.com/feige996/hello-unibest
+
+### hbx 模板
+
+- https://github.com/uni-run/unibest-hbx
+
+> `hbx` 目前由 `青谷` 大佬维护,微信号:`qingguxixi`,[青谷 github 地址](https://github.com/Xiphin) 。
+
+## 安装、运行
+
+```bash [pnpm]
+pnpm i
+pnpm dev
+# dev默认运行的是h5,其他平台执行dev:,如:
+pnpm dev:mp-weixin
+```
+
+`pnpm dev` 之后在浏览器打开 `http://localhost:9000/`。
+
+> 其他平台构建和发布,查看 [运行发布篇](./11-build)。
+
+## 第一次 `commit`
+
+```bash
+git add .
+git commit -m "feat: init project"
+```
+
+## `v3` 代码块
+
+在 `vue` 文件中,输入 `v3` 按 `tab` 即可快速生成页面模板,可以大大加快页面生成。
+
+> 原理:基于 `VSCode` 代码块生成。
+
+
+
+## 注意事项
+
+- 若代码里面自动引入的 `API` 报错,只需要 `pnpm dev` 即可。
+- 若代码运行后,`H5端` 浏览器界面底部没有 `tabbar`, 刷新浏览器或者再次 `pnpm dev` 即可。
diff --git a/docs/base/20-best.md b/docs/base/20-best.md
new file mode 100644
index 0000000..04b0ec2
--- /dev/null
+++ b/docs/base/20-best.md
@@ -0,0 +1,31 @@
+# 最佳实践
+
+新项目使用 `base` 模板,可选 `tabbar` 模板。如果需要多语言,可以选 `i18n` 模板。
+
+同时参考 `demo` 模板,可以直接 `clone` `demo` 项目,用来参考用。
+
+
+
+## 创建项目
+
+推荐使用 `pnpm` :
+
+```sh
+# 新项目创建
+pnpm create unibest my-project -t base
+```
+
+## DEMO 模板
+
+`demo` 模版-在线地址:
+
+推荐先全部体验一下 `demo` 的示例
+
+## 必看章节
+
+- [介绍](/base/1-introduction)
+- [快速开始](/base/2-start)
+- [uni 插件](/base/3-plugin)
+- [常见问题](/base/14-faq)
+- [常见问题 2](/base/15-faq)
+- [运行发布](/base/11-build)
diff --git a/docs/base/3-plugin.md b/docs/base/3-plugin.md
new file mode 100644
index 0000000..7eb0c24
--- /dev/null
+++ b/docs/base/3-plugin.md
@@ -0,0 +1,158 @@
+# uni 插件
+
+## 引言
+
+有群友第一次看到 `unibest` 里面 `vue` 文件 `route-block` 这种写法,表示很奇怪,从来没见过!
+
+```vue
+
+{
+ layout: 'demo',
+ style: {
+ navigationBarTitleText: '标题',
+ },
+}
+
+
+
+ 菲鸽,你好,我喜欢你!
+
+```
+
+## uni 插件总览
+
+哈哈,这个当然是 `uni插件` 的功劳了,具体点是 `@uni-helper/vite-plugin-uni-pages` 插件的功劳,该插件由 `uni-helper` 官方团队开发。
+
+本文就来说说 `unibest` 都引入了哪些有用的 `uni插件`。下面这个表格描述了各个插件的主要作用。
+
+| 插件名 | 作用 |
+| :----------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| @dcloudio/vite-plugin-uni | **最核心的 `uni 插件`**,没有它就不能在 vite 项目跑 uniapp,其他所有的 `uni插件` 都需要经通过它的手来编译,所以写法上,都是先写 `UniXXX`,再写 `Uni`,见下文 |
+| @uni-helper/vite-plugin-uni-pages | `uni 插件`,也是 `unibest 灵魂插件`,`route-block` 就是它的功劳,让你可以直接在本文件就能设置页面的路元信息,无需跑去 `pages.json` 配置,同时支持 `pages.config.ts` 编写 `pages.json` |
+| @uni-helper/vite-plugin-uni-layouts | `uni 插件`,支持多种 `layouts` 布局,群友脑洞大开,充分利用这个特性实现平时不容易实现的布局 |
+| @uni-helper/vite-plugin-uni-manifest | `uni 插件`,支持 `manifest.config.ts` 编写 `manifest.json` |
+
+`UniXXX()` 插件都需要在 `uni()` 之前引入,因为最终都需要 `Uni` 来处理所有的代码。如下图:
+
+
+接下来介绍一下 `uni 插件`,其他 `通用插件` 大家都比较熟悉,不再赘述。
+
+`unibest` 引入了 `uni-helper` 团队的几个重要插件,少了它们 `unibest` 就缺少了灵魂,感谢 `uni-helper` 团队的贡献。`Uni 插件` 列表如下:
+
+- `vite-plugin-uni-pages`
+
+ - 介绍:为 `Vite` 下的 `uni-app` 提供基于文件系统的路由
+ - 额外:使用 `TypeScript` 来编写 `uni-app` 的 `pages.json`
+ - 访问地址:[@uni-helper/vite-plugin-uni-pages](https://github.com/uni-helper/vite-plugin-uni-pages)
+
+- `vite-plugin-uni-layouts`
+
+ - 介绍:为 `Vite` 下的 `uni-app` 提供类 `nuxt` 的 `layouts` 系统
+ - 访问地址:[@uni-helper/vite-plugin-uni-layouts](https://github.com/uni-helper/vite-plugin-uni-layouts)
+
+- `vite-plugin-uni-manifest`
+
+ - 介绍:使用 `TypeScript` 来编写 `uni-app` 的 `manifest.json`
+ - 访问地址:[@uni-helper/vite-plugin-uni-manifest](https://github.com/uni-helper/vite-plugin-uni-manifest)
+
+## vite-plugin-uni-pages
+
+得益于 [@uni-helper/vite-plugin-uni-pages](https://github.com/uni-helper/vite-plugin-uni-pages),约定式路由(文件路由)的实现轻而易举。
+
+`src/pages` 目录下的每个文件都代表着一个路由。要创建新页面,只需要在这个目录里新增 `.vue` 文件,插件会自动生成对应的 `pages.json` 文件。
+
+`route` 代码块则可以配置页面相关信息,这些信息会自动同步到 `page.json`,无需切换到 `page.json` 进行配置。
+
+> `pages.json` 文件是自动生成的,请不要手动修改,全局的东西请在 `pages.config.ts` 里面配置,页面上的东西请在 `vue` 文件的 `route` 代码块配置,如下图。
+
+```vue [src/pages/index.vue]
+
+
+
+{
+ style: {
+ navigationStyle: 'custom',
+ navigationBarTitleText: '首页',
+ },
+}
+
+
+
+
欢迎使用 unibest
+ unibest 是最好的 uniapp 开发模板
+
+
+```
+
+```vue [src/pages/about.vue]
+
+{
+ style: {
+ navigationBarTitleText: '关于',
+ },
+}
+
+
+
+ 通过 `/pages/about` 来访问这个页面
+
+
+```
+
+### 设置首页
+
+通过在 `route-block` 里面配置 `type="home"` 即可,尽量保证一个项目 `只有一个` 这个配置,如果有多个,会按照字母顺序来排列,最终可能不是您想要的效果。
+
+### 设置 pages 过滤和分包
+
+- 过滤:默认 `src/pages` 里面的 `vue` 文件都会生成一个页面,如果不需要生成页面可以对 `vite.config.ts` 中的 `UniPages` 进行 `exclude` 配置。
+
+- 分包:如果需要设置 `分包` 则可以通过 `subPackages` 进行配置,该配置项是个数组,可以配置多个 `分包`,注意分包的目录不能为 `src/pages` 里面的子目录。
+
+```ts [vite.config.ts]
+UniPages({
+ exclude: ['**/components/**/**.*'],
+ subPackages: ['src/pages-sub'], // 是个数组,可以配置多个,但不能为 `src/pages` 里面的子目录
+})
+```
+
+## vite-plugin-uni-layouts
+
+得益于 [@uni-helper/vite-plugin-uni-layouts](https://github.com/uni-helper/vite-plugin-uni-layouts),你可以轻松地切换不同的布局。
+
+`src/layouts` 文件夹下的 `vue` 文件都会自动生成一个布局,默认的布局文件名为 `default` ,路径 `src/layouts/default.vue` 。
+
+如果需要修改使用的布局,可以通过 `vue` 文件内 `route` 代码块指定需要的布局,如下示例使用 `demo` 布局。
+
+```vue [src/pages/demo.vue]{3}
+
+{
+ layout: 'demo',
+ style: {
+ navigationBarTitleText: '关于',
+ },
+}
+
+```
+
+```vue [src/layouts/demo.vue]
+
+
+
+
+
+
+
+```
+
+## vite-plugin-uni-manifest
+
+得益于 [@uni-helper/vite-plugin-uni-manifest](https://github.com/uni-helper/vite-plugin-uni-manifest),你可以使用 `TypeScript` 来编写 `manifest.json`。
+
+> `manifest.json` 文件是自动生成的,请不要手动修改,需要配置的内容请在 `manifest.config.ts` 里面配置。
+
+## 总结
+
+本文介绍了 `unibest` 引入的几个重要的 `uni插件`。
+
+如果还想了解更多信息,可以去 `uni-helper` [github 仓库](https://github.com/uni-helper) 看看。
diff --git a/docs/base/4-style.md b/docs/base/4-style.md
new file mode 100644
index 0000000..f5f7a64
--- /dev/null
+++ b/docs/base/4-style.md
@@ -0,0 +1,220 @@
+# 样式篇
+
+本篇主要介绍 `UnoCSS` 的使用,以及如何与 `设计稿尺寸` 对应。
+
+## UnoCSS
+
+[UnoCSS](https://unocss.dev/) 是按需使用的原子 CSS 引擎,提供了良好的样式支持。
+
+
+
+在 VSCode 中还可以预览,
+
+
+
+
+
+> 如果原子化 `UnoCSS` 没有预览效果,请安装 `VSCode` 插件 `antfu.unocss`。
+
+如果不记得原子类,可以查 `UnoCSS 的原子类`,[UnoCSS Interactive](https://unocss.dev/interactive/),如下图
+
+
+也可以查看 `tailwindcss` 的原子类,更加清晰明了,[链接 - tailwindcss](https://tailwindcss.com/),如下图:
+
+
+
+## 常用的原子类
+
+- 宽高内外边距: `w-2`, `h-4`, `px-6`, `mt-8`等
+- 前景色背景色:`text-green-400`, `bg-green-500`
+- border: `border-2`, `border-solid`, `border-green-600`, `b-r-2` (注意 `border` = `border-1`,就是说边框 `1px` 时,一般简写为 `border` )
+- border-radius: `rounded-full`, `rounded-6`, `rounded-sm` (不是 `br-10`, 也不是 `b-r-10`)
+- line-height: `leading-10` (不是 `l-10`, 也不是 `lh-10`)
+- hover: `hover:text-green-200`, `hover:bg-green-300`, `hover:border-dashed`
+- flex: `flex`, `items-center`, `justify-center`, `flex-1`
+
+## `UnoCSS` 配置
+
+下面内容选读:
+
+:::details
+`unocss.config.ts` 文件内容如下:
+
+```ts
+// uno.config.ts
+import {
+ type Preset,
+ defineConfig,
+ presetUno,
+ presetAttributify,
+ presetIcons,
+ transformerDirectives,
+ transformerVariantGroup,
+} from 'unocss'
+
+import { presetApplet, presetRemRpx, transformerAttributify } from 'unocss-applet'
+
+// @see https://unocss.dev/presets/legacy-compat
+import { presetLegacyCompat } from '@unocss/preset-legacy-compat'
+
+const isMp = process.env?.UNI_PLATFORM?.startsWith('mp') ?? false
+
+const presets: Preset[] = []
+if (isMp) {
+ // 使用小程序预设
+ presets.push(presetApplet(), presetRemRpx())
+} else {
+ presets.push(
+ // 非小程序用官方预设
+ presetUno(),
+ // 支持css class属性化
+ presetAttributify(),
+ )
+}
+export default defineConfig({
+ presets: [
+ ...presets,
+ // 支持图标,需要搭配图标库,eg: @iconify-json/carbon, 使用 ``
+ presetIcons({
+ scale: 1.2,
+ warn: true,
+ extraProperties: {
+ display: 'inline-block',
+ 'vertical-align': 'middle',
+ },
+ }),
+ // 将颜色函数 (rgb()和hsl()) 从空格分隔转换为逗号分隔,更好的兼容性app端,example:
+ // `rgb(255 0 0)` -> `rgb(255, 0, 0)`
+ // `rgba(255 0 0 / 0.5)` -> `rgba(255, 0, 0, 0.5)`
+ presetLegacyCompat({
+ commaStyleColorFunction: true,
+ }) as Preset,
+ ],
+ /**
+ * 自定义快捷语句
+ * @see https://github.com/unocss/unocss#shortcuts
+ */
+ shortcuts: [['center', 'flex justify-center items-center']],
+ transformers: [
+ // 启用 @apply 功能
+ transformerDirectives(),
+ // 启用 () 分组功能
+ // 支持css class组合,eg: `测试 unocss
`
+ transformerVariantGroup(),
+ // Don't change the following order
+ transformerAttributify({
+ // 解决与第三方框架样式冲突问题
+ prefixedOnly: true,
+ prefix: 'fg',
+ }),
+ ],
+ rules: [
+ [
+ 'p-safe',
+ {
+ padding:
+ 'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)',
+ },
+ ],
+ ['pt-safe', { 'padding-top': 'env(safe-area-inset-top)' }],
+ ['pb-safe', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
+ ],
+})
+
+/**
+ * 最终这一套组合下来会得到:
+ * mp 里面:mt-4 => margin-top: 32rpx == 16px
+ * h5 里面:mt-4 => margin-top: 1rem == 16px
+ *
+ * 另外,我们还可以推算出 UnoCSS 单位与设计稿差别4倍。
+ * 375 * 4 = 1500,把设计稿设置为1500,那么设计稿里多少px,unocss就写多少数值。
+ * 举个例子,设计稿显示某元素宽度100px,就写w-100即可。
+ *
+ * 如果是传统方式写样式,则推荐设计稿设置为 750,这样设计稿1px,代码写1rpx。
+ * rpx是响应式的,可以让不同设备的屏幕显示效果保持一致。
+ */
+```
+
+### UnoCSS presets
+
+主要有 `4`个:
+
+- `presetUno` —— `UnoCSS` 默认的预设,`H5端` 适用,`非H5端` 不支持,代码已经作区别处理。
+- `presetApplet` 小程序预设,因为默认 `Unocss 预设` 是针对 `WEB` 的,如果不加以处理,会报错,比如小程序不支持 `*`, 没有 `body` 等。该预设同样对 `APP` 生效。
+- `presetIcons`,专门使用 `UnoCSS Icons` 的,需要搭配图标库使用,eg: `@iconify-json/carbon`, 代码编写如 ``
+- `presetLegacyCompat` 针对低端 `APP` 不认识新的函数颜色的兼容性预设,可以将颜色函数 `rgb()和hsl()` 里面空格分隔转换为逗号分隔,更好的兼容性`APP`端,example:
+ > `rgb(255 0 0)` -> `rgb(255, 0, 0)`
+ >
+ > `rgba(255 0 0 / 0.5)` -> `rgba(255, 0, 0, 0.5)`
+
+### UnoCSS shortcuts
+
+```ts
+/**
+* 自定义快捷语句
+* @see https://github.com/unocss/unocss#shortcuts
+*/
+shortcuts: [['center', 'flex justify-center items-center']],
+```
+
+可以编写一些常用的快捷类名,如上表示 `center` 就是 `flex justify-center items-center` 的组合,合理的添加快捷类名可以加快样式编写。
+
+:::
+
+## 设计稿尺寸
+
+不同的编写方式,需要设置不同的设计稿尺寸,请看下文:
+
+### 1. 传统编写方式
+
+如果有设计稿,通常使用传统的编写 `CSS` 的方式,里面的对应尺寸规律如下。以蓝湖为例,假如设计稿宽度为 `750px`,则直接复制样式代码到 css 代码,同时把 `px` 批量替换为 `rpx` 即可。
+
+如果设计稿不是 `750px` 可以调整蓝湖的设置,让设计稿宽度为 `750px`。
+
+> 下面为一段辅助说明文案,从 `uniapp` 官网搬运而来。
+
+`rpx` 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。`uni-app` 规定屏幕基准宽度 `750rpx`。
+
+开发者可以通过设计稿基准宽度计算页面元素 `rpx` 值,设计稿 `1px` 与框架样式 `1rpx` 转换公式如下:
+
+`设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx`
+
+换言之,页面元素宽度在 `uni-app` 中的宽度计算公式:
+
+`750 * 元素在设计稿中的宽度 / 设计稿基准宽度`
+
+举例说明:
+
+若设计稿宽度为 `750px`,元素 `A` 在设计稿上的宽度为 `100px`,那么元素 `A` 在 `uni-app` 里面的宽度应该设为:`750 * 100 / 750`,结果为:`100rpx`。
+
+若设计稿宽度为 `640px`,元素 `A` 在设计稿上的宽度为 `100px`,那么元素 `A` 在 `uni-app` 里面的宽度应该设为:`750 * 100 / 640`,结果为:`117rpx`。
+
+若设计稿宽度为 `375px`,元素 `B` 在设计稿上的宽度为 `200px`,那么元素 `B` 在 `uni-app` 里面的宽度应该设为:`750 * 200 / 375`,结果为:`400rpx`。
+
+### 2. UnoCSS 编写方式
+
+经过上一节的 `unocss.config.ts` 配置,可以得到下面的组合:
+
+> mp 里面:mt-4 => margin-top: 32rpx == 16px
+>
+> h5 里面:mt-4 => margin-top: 1rem == 16px
+
+我们还是把设计稿设置为 `750`,设计稿上多少 `px` 的元素,写成多少 `rpx` 即可。
+
+元素 `A` 在设计稿上的宽度为 `100px`,则写 `w-100rpx` 即可。
+
+就是把 `传统编写方式` 中写在 `css` 中的样式搬到了 `UnoCSS` 中。
+
+如果要想用 `w-100` 这种方式,需要做额外的处理(待验证):
+
+:::details
+太忙了,有空再写吧。
+:::
+
+## 总结
+
+本文主要介绍了 `UnoCSS` 的使用,以及 `unocss.config.ts` 中的一些配置项。
+
+同时说明了设计稿在两种编写方式下的宽度的设置,分别为 `750` 和 `1500`.
+
+最后说明一下,`原子化CSS` 和 `传统方式` 两者不是互斥的,他们是互补的,合适的地方使用合适的方式。
diff --git a/docs/base/4-style2.md b/docs/base/4-style2.md
new file mode 100644
index 0000000..99ea1a5
--- /dev/null
+++ b/docs/base/4-style2.md
@@ -0,0 +1,41 @@
+# 关于使用 TailwindCSS
+
+对于 unibest 项目使用 TailwindCSS 的评估如下:
+
+1. **直接使用TailwindCSS的限制**:
+
+ - 原生TailwindCSS是为Web设计的,在小程序环境下会有兼容性问题
+ - 不支持rpx单位,在小程序适配上有困难
+ - 需要额外配置postcss和purgeCSS才能在小程序工作
+
+2. **当前UnoCSS的优势**:
+
+ - 您的项目已经配置了`unocss-applet`,专门为小程序优化
+ - 支持rpx单位转换(通过presetRemRpx)
+ - 支持小程序属性化写法(transformerAttributify)
+ - 体积更小,按需生成样式
+
+3. **替代方案建议**:
+
+ - 保持使用UnoCSS,它已经实现了Tailwind的大部分功能
+ - 可以通过安装`@unocss/preset-wind`来获得Tailwind风格的类名:
+
+ ```bash
+ pnpm add -D @unocss/preset-wind
+ ```
+
+ 然后在uno.config.ts中添加:
+
+ ```typescript
+ import { presetWind } from '@unocss/preset-wind'
+
+ export default defineConfig({
+ presets: [
+ presetWind(),
+ // 其他presets...
+ ],
+ })
+ ```
+
+4. **结论**:
+ 在uni-app项目中,UnoCSS是比原生TailwindCSS更合适的选择,特别是针对小程序开发。通过`preset-wind`可以获得类似Tailwind的开发体验。
diff --git a/docs/base/5-icons.md b/docs/base/5-icons.md
new file mode 100644
index 0000000..bd5e799
--- /dev/null
+++ b/docs/base/5-icons.md
@@ -0,0 +1,195 @@
+# 图标篇
+
+本文主要介绍了 `图标` 的使用方式,通常有以下几种方式使用图标:
+
+- `UI 库 Icons`
+- `UnoCSS Icons`
+- `iconfont`
+
+下面笔者一一介绍
+
+## UI 库 Icons
+
+如果您已经引入了 `UI库`,并且正好该 `UI库` 已经有你想要的 `Icons`,那直接用最方便了,无需额外引入其他库,代码也是最少的。
+
+这里介绍几个常用 `UI库` 的图标使用。
+
+### `uni-ui Icons`
+
+> 注意:`uni-ui Icons` 颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。
+
+```html
+
+
+
+
+```
+
+
+
+### `wot-ui Icons`
+
+> 注意:`wot-ui icons` 颜色可以通过 `color` 属性设置,也可以通过 `UnoCSS` 设置;同时设置时,`color` 属性优先级高。
+
+```html
+
+
+
+
+```
+
+
+
+### `uv-ui Icons`
+
+> 注意:跟 `uni-ui Icons` 一样,`uv-ui Icons` 的颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。
+
+```html
+
+
+
+
+```
+
+
+
+> 注意,经过检测这 `3个UI库Icons` 都不支持使用 `UnoCSS` 改变大小(优先级低被覆盖),必须使用 `size` 属性来设置大小才有效果(行内样式优先于 css 样式)。
+>
+> 另外,经过检测,都支持动态 `iconName`和动态 `color` ! 即下面这样的写法是生效的:
+
+```ts
+const iconName = ref('contact')
+const colorName = ref('red')
+onLoad(() => {
+ setTimeout(() => {
+ iconName.value = 'chat'
+ colorName.value = 'green'
+ }, 1000)
+})
+```
+
+```html
+
+
+```
+
+## `UnoCSS Icons`
+
+`UnoCSS Icons` 可以方便接入 `iconify` 图标库,后者拥有 `10万+` 的海量图标,总能找到你想要的。
+
+### 1. 安装 iconify
+
+在使用 `iconify` 之前需要安装对应的图标库,安装格式如下:
+
+`pnpm i -D @iconify-json/[the-collection-you-want]`
+
+以安装 `carbon` 为例,执行 `pnpm i -D @iconify-json/carbon` 即可。
+
+> `unibest` 已经装好了 `carbon` 图标库,可以直接使用。
+
+### 2. 找到 iconify 想要的图标名
+
+打开网址:
+
+- 在里面找到某个库,如 `carbon`。
+
+
+
+- 搜索想要的图表,如 `avatar`,出现的搜索结果,查看类名,也可以点击图标,会出现详情( `details` 里面)。
+
+
+
+
+
+- 如上图( `details` 里面),拿到 `carbon:user-avatar`。
+
+### 3. 编写代码
+
+- 代码里面 `class` 填写 `i-carbon-user-avatar`(所有的单词用中划线连接即可)并且支持改颜色。
+
+```html
+
+```
+
+
+
+> 如果图标没有预览效果,请安装 `VSCode` 插件 `antfu.iconify`。
+
+预览效果:
+
+
+
+### 4. 动态图标名
+
+昨天有网友反馈,`UnoCSS Icons` 无法使用动态类名,我来试试:(我先说结论:是支持的!)
+
+```ts
+const iconName = ref('i-carbon-car')
+onLoad(() => {
+ setTimeout(() => {
+ iconName.value = 'i-carbon-user-avatar'
+ }, 1000)
+})
+```
+
+```html
+
+```
+
+一秒后会由 `i-carbon-car`(一辆车) 变成 `i-carbon-user-avatar`(一个头像),一切都是 OK 的。
+
+### 5.再说动态图标名
+
+有的时候类名是动态的,比如是 a+b 拼凑的,比如是后端返回的,比如是跨文件的,这时候页面是无法显示出该图标的。因为 `UnoCSS` 还不知道具体的类名是啥,无法得到对应的图标。解决方案有2种:
+
+- 1. 在代码里写出完整的图标类名,并注释掉。(SFC 的任何位置都可以)
+
+- 2. 在 `unocss.config.ts` 的 `safelist` 配置该完整类名。[unocss safelist](https://unocss.dev/config/#safelist)
+
+## iconfont 图标库
+
+`iconfont` 同样有海量免费的图标,同时支持上传自己的图标。公司项目通常会有自己的图标,由专业的 `UI设计师` 设计,这时通常会使用 `iconfont` 方式使用图标。
+
+- 1. 打开`阿里巴巴矢量图标库 iconfont`,地址:[https://www.iconfont.cn/](https://www.iconfont.cn/),并登录。
+- 2. 寻找需要的图标,加入项目,也可以上传自己的图标。
+- 3. 图标方式选择 `Font class`,`项目设置` 勾选上 `base64`,否则`非H5端` 不支持,然后点击生成链接。
+
+
+
+
+- 4. 把上面的 `css` 链接里面的内容写入在 `style/iconfont.css`,并引入到 `style/index.scss`。
+- 5. 页面上直接写 `` 即可!
+
+```html
+
+ iconfont:
+
+
+
+
+```
+
+预览如下:
+
+
+
+> 上面的选择有疑问的可以看详细版 - [iconfont 详细版](/other/iconfont/iconfont)
+
+## 其它图标库
+
+其他优秀的可以免费商用的图标库:
+
+- 字节跳动的 `IconPark`,链接 [https://iconpark.oceanengine.com](https://iconpark.oceanengine.com/)。
+- 不知道谁家的 `yesicon`,链接 [https://yesicon.app](https://yesicon.app/)。
+
+## 总结
+
+本文介绍了 `3` 种使用图标的方式,分别是 `UI 库 Icons`、`UnoCSS Icons`、`iconfont`。
+
+- `UI 库 Icons` 颜色和大小属性都主要由 `UI 库` 本身控制,且都支持动态图标名和动态颜色。
+
+- `UnoCSS Icons` 最省心,强烈推荐使用。
+
+- `iconfont` 需要勾选 `Base64` 才能兼容多端。
+
+全文完~
diff --git a/docs/base/6-svg.md b/docs/base/6-svg.md
new file mode 100644
index 0000000..ae9352d
--- /dev/null
+++ b/docs/base/6-svg.md
@@ -0,0 +1,176 @@
+# SVG 篇
+
+上一章《五、图标篇》主要介绍了 `内置图标` 的使用,今天带给大家本地 `SVG` 图标的使用。
+
+> 注意:`小程序` 和 `APP` 都不支持 `SVG` 标签,只能通过 `image` 的方式使用。即下面的 `image + src` 方式。
+
+- `image + src` 方式
+
+ - `static目录` 图标
+ - `相对目录` 图标
+ - `线上地址` 图标
+
+> PS:`小程序` 和 `APP` 对 `图片` 也是这面几种方式,下面统一称为 “图片”。
+
+## `image + src` 方式
+
+如果图片在项目里面,根据放的位置不同,分为 2 种:`static目录`图标 , `相对目录`图标。
+
+### 1. `static目录` 图标
+
+这种方式直接编写代码即可,如下:
+
+```html
+
+```
+
+### 2. `相对目录` 图标
+
+这种方式需要先引入,再使用,代码编写如下:
+
+```html
+
+
+
+
+
+```
+
+### 3. `线上地址` 图标
+
+这种方式直接使用,代码编写如下:
+
+```html
+
+
+
+```
+
+## H5 额外支持的其他方式
+
+> `SvgComponent` 方式 和 `SvgIcon` 方式,仅 `H5端` 适用,感兴趣的可以阅读下。
+> 因为只有 `H5端` 支持,所以 unibest 没有引入这些,但是其他 `web` 项目可以参考。
+
+:::details
+
+### `SvgComponent` 方式
+
+从 `Web端` 过来的同学都知道 `SvgComponent` 这种方式,只需要引入 `vite-svg-loader` 插件即可,支持 `3种` 方式引入 `svg`: `url`, `raw`, `component`。
+
+- URL
+
+SVGs can be imported as URLs using the `?url` suffix:
+
+```js
+import iconUrl from './my-icon.svg?url'
+// 'data:image/svg+xml...'
+```
+
+Used in template:
+
+```html
+
+
+
+```
+
+- Raw
+
+SVGs can be imported as strings using the `?raw` suffix:
+
+```js
+import iconRaw from './my-icon.svg?raw'
+// '...'
+```
+
+Used in template:
+
+```html
+{{ iconRaw }}
+```
+
+- Component
+
+SVGs can be explicitly imported as Vue components using the `?component` suffix:
+
+```js
+import IconComponent from './my-icon.svg?component'
+//
+```
+
+Used in template:
+
+```html
+
+
+
+```
+
+但是目前经过测试,只有 `url` 的方式所有端可以使用,与上面的 `image + src - 相对目录 图标` 是一个效果。至于 `component` 只有 `H5端生效`,其他端不行。
+
+### `SvgIcon` 方式
+
+从 `Web端` 过来的同学都知道 `SvgIcon` 这种方式,只需要引入 `vite-plugin-svg-icons` 插件 + `vite 配置`,再编写一个通用的 `SvgIcon` 即可,但是同样只有 `H5端生效`,其他端不行。
+
+`vite` 配置如下:
+
+```
+createSvgIconsPlugin({
+ // 指定要缓存的文件夹
+ iconDirs: [path.resolve(process.cwd(), 'src/assets')],
+ // 指定symbolId格式
+ symbolId: 'icon-[dir]-[name]',
+}),
+```
+
+如上,只需要把 `svg` 放到 `src/assets` 目录即可。
+
+`SvgIcon` 代码如下:
+
+```html
+
+
+
+
+
+```
+
+使用方式如下:
+
+```html
+
+
+
+
+
+```
+
+> `SvgComponent` 依赖 `vite-svg-loader` 插件
+>
+> `SvgIcon` 依赖 `vite-plugin-svg-icons` 插件
+
+:::
+
+## 总结
+
+适用于跨端的 `svg 和 图片` 的使用方式,只有 `image + src` 的方式。其他方式只能用于 `web` 端,仅供参考。
+
+全文完~
diff --git a/docs/base/7-ui.md b/docs/base/7-ui.md
new file mode 100644
index 0000000..bf2e0e0
--- /dev/null
+++ b/docs/base/7-ui.md
@@ -0,0 +1,124 @@
+# UI 库替换篇
+
+## 2025-06-13 更新
+
+因为 `base` 模板加了登录相关的功能,这些功能都是使用 `wot-ui` 开发的,替换起来会很麻烦。如果想要替换成其他 `UI 库`,可以使用 `base-sard-ui` 模板,这个模板是最近添加的。因为最近 `sard-uniapp` 比较火,有群友想要,我就整理了一份最基础的出来,不带登录功能,所以用它来替换成其他 UI 库最合适最方便。
+
+## 默认 UI 库
+
+`unibest` 经过几次更迭,先后使用 `uni-ui`、`uv-ui`作为默认 UI 库,目前使用 `wot-ui` 为默认 UI 库。
+
+`wot-ui` 是 `vue3+ts` 编写的全端支持的 UI 库,编码体验比 `uv-ui` 更好;而官方维护的 `uni-ui` 则样式略丑,组件较少,故弃之。
+
+> `wot-ui` 全称 `wot-design-uni`,是 `wot-design` 的 `uniapp` 版本,文档地址:[https://wot-design-uni.netlify.app/](https://wot-design-uni.netlify.app/).
+
+---
+
+很多群友反馈有其他 `UI` 库的需求,那么更换 `UI 库` 需要哪些步骤呢?
+
+- 先卸载原有的 `wot-ui` 库
+- 再安装其他 `UI 库`
+
+下面我们简单描述一下更换 2 个主流 `UI库` —— `uni-ui` + `uv-ui` 的过程。
+
+> 当然也支持同时存在多个 `UI 库`,有 ES 摇树特性,不必担心打包后的体积。
+
+## 卸载 wot-ui 库
+
+卸载 `wot-ui` 过程如下:
+
+- 1. 删除 `wot-ui` 库:
+
+```sh
+ pnpm un wot-design-uni
+```
+
+- 2. `pages.config.ts` 文件 `easycom.custom` 删除相关配置:
+
+```diff
+easycom: {
+ autoscan: true,
+ custom: {
+- '^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue',
+ },
+},
+```
+
+- 3. ` tsconfig.json` 文件 `compilerOptions.types` 删除相关配置:
+
+```diff
+"types": [
+ "@dcloudio/types",
+ "@types/wechat-miniprogram",
+- "wot-design-uni/global.d.ts",
+ "./components.d.ts",
+ "./global.d.ts"
+]
+```
+
+## 安装 `uni-ui` 库
+
+- 1. 安装 `uni-ui` 库:
+
+```sh
+pnpm add @dcloudio/uni-ui
+```
+
+- 2. `pages.config.ts` 文件 `easycom.custom` 添加相关配置:
+
+```diff
+easycom: {
+ autoscan: true,
+ custom: {
++ '^uni-(.*)': '@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue',
+ },
+},
+```
+
+- 3. ` tsconfig.json` 文件 `compilerOptions.types` 添加相关配置:
+
+```diff
+"types": [
+ "@dcloudio/types",
+ "@types/wechat-miniprogram",
++ "@uni-helper/uni-ui-types",
+ "./components.d.ts",
+ "./global.d.ts"
+]
+```
+
+## 安装 `uv-ui` 库
+
+- 1. 安装 `uv-ui` 库:
+
+```sh
+pnpm add @climblee/uv-ui
+```
+
+- 2. `pages.config.ts` 文件 `easycom.custom` 添加相关配置:
+
+```diff
+easycom: {
+ autoscan: true,
+ custom: {
++ '^uv-(.*)': '@climblee/uv-ui/components/uv-$1/uv-$1.vue',
+ },
+},
+```
+
+- 3. ` tsconfig.json` 文件 `compilerOptions.types` 添加相关配置:
+
+```diff
+"types": [
+ "@dcloudio/types",
+ "@types/wechat-miniprogram",
++ "@ttou/uv-typings/shim",
++ "@ttou/uv-typings/v2",
+ "./components.d.ts",
+ "./global.d.ts"
+]
+```
+
+> 其他 UI 库的安装类似,不再赘述。
+
+全文完~
diff --git a/docs/base/8-request.md b/docs/base/8-request.md
new file mode 100644
index 0000000..a5b5a95
--- /dev/null
+++ b/docs/base/8-request.md
@@ -0,0 +1,252 @@
+# 请求篇
+
+本篇分为三块内容:
+
+- 普通请求
+- 图片上传
+- 多后台地址
+
+## 普通请求
+
+普通请求分 2 种处理,一种是只在页面请求一次的一次性请求,这种请求占大多数;一种是项目多处用到的请求,这种请求占小部分,需要单独编写一个请求函数放到 `api文件夹` or `service文件夹`。
+
+> `unibest` 里面是使用 `service文件夹` 后面不再说明。
+
+下面来分别演示:
+
+### 一次性请求
+
+`template` 部分编码如下:
+
+```html
+
+
+ 请求中...
+ 请求错误
+ {{ JSON.stringify(data) }}
+
+```
+
+`script` 部分使用 `菲鸽` 封装好的 `useRequest` 即可实现请求状态一体化,如下:
+
+```ts
+
+```
+
+看吧,使用非常简单。
+
+### 重复性请求
+
+`重复性请求` 与 `一次性请求` 的 `html部分` 是一样的,唯一的区别是 `请求函数` 放到了 `service文件夹`,如下所示:
+
+```ts
+
+```
+
+对应的 `src/service/index/foo.ts` 文件如下:
+
+```ts
+import { http, httpGet } from '@/utils/http'
+export interface IFooItem {
+ id: string
+ name: string
+}
+
+/** GET 请求 */
+export const getFooAPI = (name: string) => {
+ return http({
+ url: `/foo`,
+ method: 'GET',
+ query: { name },
+ })
+}
+
+/** GET 请求 - 再次简化,看大家是否喜欢这种简化 */
+export const getFooAPI2 = (name: string) => {
+ return httpGet('/foo', { name })
+}
+```
+
+依然非常简洁,深受妹子喜爱。
+
+> 完成范例如下
+
+```ts
+/** GET 请求 */
+export const getFooAPI = (name: string) => {
+ return http.get('/foo', { name })
+}
+/** GET 请求;支持 传递 header 的范例 */
+export const getFooAPI2 = (name: string) => {
+ return http.get('/foo', { name }, { 'Content-Type-100': '100' })
+}
+
+/** POST 请求 */
+export const postFooAPI = (name: string) => {
+ return http.post('/foo', { name })
+}
+/** POST 请求;需要传递 query 参数的范例;微信小程序经常有同时需要query参数和body参数的场景 */
+export const postFooAPI2 = (name: string) => {
+ return http.post('/foo', { name })
+}
+/** POST 请求;支持 传递 header 的范例 */
+export const postFooAPI3 = (name: string) => {
+ return http.post('/foo', { name }, { name }, { 'Content-Type-100': '100' })
+}
+```
+
+## 图片上传
+
+`template` 部分编码如下:
+
+```html
+
+
+ 选择图片并上传
+ 上传...
+
+ 上传后返回的图片地址:
+ {{ data }}
+
+
+
+
+
+
+```
+
+`script` 部分使用 `菲鸽` 封装好的 `useUpload` 即可实现请求状态一体化,如下:
+
+```ts
+
+```
+
+使用非常简单,深受汉子和妹子的喜爱。
+
+## 多后台地址
+
+上面的 `普通请求` 默认是只有一个请求地址的,在 `.env` 里面配置 `VITE_SERVER_BASEURL`,如下:
+
+```text
+VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
+```
+
+并且在 `src/interceptors/request.ts` 里面有设置:
+
+- 如果是 `http` 开头的请求路径,则直接请求
+- 如果不是,则拼接上 `VITE_SERVER_BASEURL`
+
+
+
+但在多后台地址时就不能这么玩了,需要处理如下:(关注上图的箭头部分)
+
+```ts
+// 可以写一个映射对象,如:
+const proxyMap = {
+ cms:'http://localhost:8080/cms',
+ ums:'http://localhost:8080/ums',
+}
+
+// 拦截器部分(上图箭头部分)修改如下
+Object.keys(proxyMap).forEach(key=>{
+ if(options.url.startsWith(`/${key}`)){
+ options.url = proxyMap[key] + options.url
+ }
+}
+
+// 接口调用的地方使用如下格式:
+export const getFooAPI = (name: string) => {
+ return http({
+ url: `/cms/foo`, // 看这里,前缀不用!!!
+ method: 'GET',
+ query: { name },
+ })
+}
+```
+
+## 支持header传递
+
+目前(v2.6.2)已经支持 `header` 了,具体使用方法如下:(最后一个参数就是 `header`,不需要不用传,需要才传。)
+
+```ts
+/** GET 请求 */
+export const getFooAPI = (name: string) => {
+ return http.get('/foo', { name }, { 'Content-Type': 'multipart/form-data' })
+}
+
+/** POST 请求 */
+export const postFooAPI = (name: string) => {
+ return http.post('/foo', { name }, { name }, { 'Content-Type': 'multipart/form-data' })
+}
+```
+
+低于v2.6.2版本,需要手动设置header,具体使用方法如下:(`utils/http.ts`)
+
+```diff
+/**
+ * GET 请求
+ * @param url 后台地址
+ * @param query 请求query参数
++ * @param header 请求头,默认为json格式
+ * @returns
+ */
+export const httpGet = (
+ url: string,
+ query?: Record,
++ header?: Record,
+) => {
+ return http({
+ url,
+ query,
+ method: 'GET',
++ header,
+ })
+}
+
+/**
+ * POST 请求
+ * @param url 后台地址
+ * @param data 请求body参数
+ * @param query 请求query参数,post请求也支持query,很多微信接口都需要
++ * @param header 请求头,默认为json格式
+ * @returns
+ */
+export const httpPost = (
+ url: string,
+ data?: Record,
+ query?: Record,
++ header?: Record,
+) => {
+ return http({
+ url,
+ query,
+ data,
+ method: 'POST',
++ header,
+ })
+}
+```
+
+## 环境变量配置
+
+- `普通请求` 需要在 `.env` 里面配置 `VITE_SERVER_BASEURL`,用在 `src/interceptors/request.ts` 文件拼接请求地址;而 `多后台地址` 时则用不上,可以删除。
+
+```text
+VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
+```
+
+- `图片上传` 需要在 `.env` 里面配置 `VITE_UPLOAD_BASEURL`:
+
+```text
+VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'
+```
+
+全文完~
diff --git a/docs/base/9-state.md b/docs/base/9-state.md
new file mode 100644
index 0000000..a4aa68b
--- /dev/null
+++ b/docs/base/9-state.md
@@ -0,0 +1,165 @@
+# 状态篇
+
+本文主要介绍了全局状态管理 `pinia` 和 简单状态 `ref` + `reactive`。
+
+## pinia
+
+`unibest` 已经内置了 `Pinia` + `pinia-plugin-persistedstate`(数据持久化插件),并提供了开箱即用的示例。
+
+### 兼容性处理
+
+本身 `pinia-plugin-persistedstate` 是不支持 `uniapp` 的,但是 `pinia-plugin-persistedstate` 提供了修改 `storage` 存储 API 的方式(默认是 `localStorage`,是一个 `WEB API`,`非H5端` 不支持),目前 `unibest` 已经处理好了。关键代码如下:
+
+```ts
+import { createPinia } from 'pinia'
+import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
+
+const store = createPinia()
+store.use(
+ createPersistedState({
+ storage: {
+ getItem: uni.getStorageSync, // 看这里
+ setItem: uni.setStorageSync, // 看这里
+ },
+ }),
+)
+```
+
+### 定义 `pinia` 全局状态
+
+`src/store/xxx.ts` 里面编写代码,如下是 `src/store/count.ts` 文件。
+
+注意 `defineStore` 第三个参数可以设置是否需要持久化,默认不需要。
+
+```ts [src/store/count.ts]{26}
+import { defineStore } from 'pinia'
+import { ref } from 'vue'
+
+export const useCountStore = defineStore(
+ 'count',
+ () => {
+ const count = ref(0)
+ const increment = () => {
+ count.value++
+ }
+ const decrement = () => {
+ count.value--
+ }
+ const reset = () => {
+ count.value = 0
+ }
+ return {
+ count,
+ decrement,
+ increment,
+ reset,
+ }
+ },
+ {
+ // 如果需要持久化就写 true, 不需要持久化就写 false(或者去掉这个配置项)
+ persist: true,
+ },
+)
+```
+
+> 请不要随意把数据丢到 `pinia`,能不用就不用。简单状态尽量使用 `ref` 或者 `reactive`。
+
+### 使用 `pinia` 全局状态
+
+在 `vue` 文件中就可以使用了,如下是 `src/pages/demo.vue` 文件:
+
+```vue
+
+
+ Count: {{ countStore.count }}
+
+
+
+
+
+
+
+```
+
+## 简单状态
+
+你可以直接使用 `Vue` 提供的 `ref` 或 `reactive` 方法来做简单状态管理。
+
+### ref
+
+如下是 `src/pages/demo/useCount.ts` 文件,定义简单状态。
+
+```ts [src/pages/demo/useCount.ts]
+// 全局状态
+const globalCount = ref(1)
+export function useCount() {
+ // 本地状态
+ const localCount = ref(1)
+ function increment() {
+ globalCount.value++
+ localCount.value++
+ }
+ return {
+ globalCount,
+ localCount,
+ increment,
+ }
+}
+```
+
+如下是 `src/pages/demo/index.vue`,与 `ref` 简单状态文件放到同一个目录下,方便管理。
+
+```vue [src/pages/demo/index.vue]
+
+
+
+
+
+```
+
+## reactive
+
+`reactive` 与 `ref` 类似。
+
+如下是 `src/pages/demo/count.ts` 文件,定义状态。
+
+```ts [src/pages/demo/count.ts]
+export const countStore = reactive({
+ count: 0,
+ increment() {
+ this.count++
+ },
+})
+```
+
+如下是 `src/pages/demo/index.vue`,与 `reactive` 简单状态文件放到同一个目录下,方便管理。
+
+```vue [src/pages/demo/index.vue]
+
+
+
+
+
+```
+
+## 总结
+
+本文介绍了 `unibest` 里面状态管理的 `2` 种方式:`pinia` 全局状态 和 `ref\reactive` 简单状态,分别演示了如何定义状态和使用状态。
+
+注意需要灵活使用 `pinia` 和 `简单状态`,局部的状态尽量使用 `简单状态` 的方式来处理,减少 `pinia` 里面全局变量的数量。
+
+全文完~
diff --git a/docs/base/assets/1-1.png b/docs/base/assets/1-1.png
new file mode 100644
index 0000000..00f92c0
Binary files /dev/null and b/docs/base/assets/1-1.png differ
diff --git a/docs/base/assets/10-1.png b/docs/base/assets/10-1.png
new file mode 100644
index 0000000..4cae7f6
Binary files /dev/null and b/docs/base/assets/10-1.png differ
diff --git a/docs/base/assets/10-2.png b/docs/base/assets/10-2.png
new file mode 100644
index 0000000..5717c7a
Binary files /dev/null and b/docs/base/assets/10-2.png differ
diff --git a/docs/base/assets/10-3.png b/docs/base/assets/10-3.png
new file mode 100644
index 0000000..5f686dd
Binary files /dev/null and b/docs/base/assets/10-3.png differ
diff --git a/docs/base/assets/10-android.mp4 b/docs/base/assets/10-android.mp4
new file mode 100644
index 0000000..22725ec
Binary files /dev/null and b/docs/base/assets/10-android.mp4 differ
diff --git a/docs/base/assets/10-ios.mp4 b/docs/base/assets/10-ios.mp4
new file mode 100644
index 0000000..bbd1adc
Binary files /dev/null and b/docs/base/assets/10-ios.mp4 differ
diff --git a/docs/base/assets/11-1.png b/docs/base/assets/11-1.png
new file mode 100644
index 0000000..078b145
Binary files /dev/null and b/docs/base/assets/11-1.png differ
diff --git a/docs/base/assets/11-10.png b/docs/base/assets/11-10.png
new file mode 100644
index 0000000..dd8dc4c
Binary files /dev/null and b/docs/base/assets/11-10.png differ
diff --git a/docs/base/assets/11-100.png b/docs/base/assets/11-100.png
new file mode 100644
index 0000000..6bacfa1
Binary files /dev/null and b/docs/base/assets/11-100.png differ
diff --git a/docs/base/assets/11-11.png b/docs/base/assets/11-11.png
new file mode 100644
index 0000000..994760f
Binary files /dev/null and b/docs/base/assets/11-11.png differ
diff --git a/docs/base/assets/11-12.png b/docs/base/assets/11-12.png
new file mode 100644
index 0000000..4241986
Binary files /dev/null and b/docs/base/assets/11-12.png differ
diff --git a/docs/base/assets/11-13.png b/docs/base/assets/11-13.png
new file mode 100644
index 0000000..a0afa4b
Binary files /dev/null and b/docs/base/assets/11-13.png differ
diff --git a/docs/base/assets/11-2.png b/docs/base/assets/11-2.png
new file mode 100644
index 0000000..43fe20b
Binary files /dev/null and b/docs/base/assets/11-2.png differ
diff --git a/docs/base/assets/11-3.png b/docs/base/assets/11-3.png
new file mode 100644
index 0000000..594245e
Binary files /dev/null and b/docs/base/assets/11-3.png differ
diff --git a/docs/base/assets/11-4.png b/docs/base/assets/11-4.png
new file mode 100644
index 0000000..7dae6e7
Binary files /dev/null and b/docs/base/assets/11-4.png differ
diff --git a/docs/base/assets/11-5.png b/docs/base/assets/11-5.png
new file mode 100644
index 0000000..7fee8d8
Binary files /dev/null and b/docs/base/assets/11-5.png differ
diff --git a/docs/base/assets/11-6.png b/docs/base/assets/11-6.png
new file mode 100644
index 0000000..a21127f
Binary files /dev/null and b/docs/base/assets/11-6.png differ
diff --git a/docs/base/assets/11-7.png b/docs/base/assets/11-7.png
new file mode 100644
index 0000000..e86538d
Binary files /dev/null and b/docs/base/assets/11-7.png differ
diff --git a/docs/base/assets/11-8.png b/docs/base/assets/11-8.png
new file mode 100644
index 0000000..ce08847
Binary files /dev/null and b/docs/base/assets/11-8.png differ
diff --git a/docs/base/assets/11-9.png b/docs/base/assets/11-9.png
new file mode 100644
index 0000000..b0dc3cd
Binary files /dev/null and b/docs/base/assets/11-9.png differ
diff --git a/docs/base/assets/13-1.png b/docs/base/assets/13-1.png
new file mode 100644
index 0000000..3e80275
Binary files /dev/null and b/docs/base/assets/13-1.png differ
diff --git a/docs/base/assets/13-2.png b/docs/base/assets/13-2.png
new file mode 100644
index 0000000..1bf1822
Binary files /dev/null and b/docs/base/assets/13-2.png differ
diff --git a/docs/base/assets/13-3.png b/docs/base/assets/13-3.png
new file mode 100644
index 0000000..77eb3a3
Binary files /dev/null and b/docs/base/assets/13-3.png differ
diff --git a/docs/base/assets/13-4.png b/docs/base/assets/13-4.png
new file mode 100644
index 0000000..6f5829e
Binary files /dev/null and b/docs/base/assets/13-4.png differ
diff --git a/docs/base/assets/13-5.png b/docs/base/assets/13-5.png
new file mode 100644
index 0000000..43d78a5
Binary files /dev/null and b/docs/base/assets/13-5.png differ
diff --git a/docs/base/assets/13-6.png b/docs/base/assets/13-6.png
new file mode 100644
index 0000000..fa52c3c
Binary files /dev/null and b/docs/base/assets/13-6.png differ
diff --git a/docs/base/assets/13-7.png b/docs/base/assets/13-7.png
new file mode 100644
index 0000000..21e6389
Binary files /dev/null and b/docs/base/assets/13-7.png differ
diff --git a/docs/base/assets/13-8.png b/docs/base/assets/13-8.png
new file mode 100644
index 0000000..26550a3
Binary files /dev/null and b/docs/base/assets/13-8.png differ
diff --git a/docs/base/assets/14-1.png b/docs/base/assets/14-1.png
new file mode 100644
index 0000000..ad1ac54
Binary files /dev/null and b/docs/base/assets/14-1.png differ
diff --git a/docs/base/assets/14-2.png b/docs/base/assets/14-2.png
new file mode 100644
index 0000000..479d5c3
Binary files /dev/null and b/docs/base/assets/14-2.png differ
diff --git a/docs/base/assets/14-3.png b/docs/base/assets/14-3.png
new file mode 100644
index 0000000..f6b08c4
Binary files /dev/null and b/docs/base/assets/14-3.png differ
diff --git a/docs/base/assets/14-4.png b/docs/base/assets/14-4.png
new file mode 100644
index 0000000..105f73b
Binary files /dev/null and b/docs/base/assets/14-4.png differ
diff --git a/docs/base/assets/14-5.png b/docs/base/assets/14-5.png
new file mode 100644
index 0000000..36b87c1
Binary files /dev/null and b/docs/base/assets/14-5.png differ
diff --git a/docs/base/assets/14-6.png b/docs/base/assets/14-6.png
new file mode 100644
index 0000000..4297e8a
Binary files /dev/null and b/docs/base/assets/14-6.png differ
diff --git a/docs/base/assets/15-1.png b/docs/base/assets/15-1.png
new file mode 100644
index 0000000..e2e0801
Binary files /dev/null and b/docs/base/assets/15-1.png differ
diff --git a/docs/base/assets/15-2.png b/docs/base/assets/15-2.png
new file mode 100644
index 0000000..e3977f7
Binary files /dev/null and b/docs/base/assets/15-2.png differ
diff --git a/docs/base/assets/15-3.png b/docs/base/assets/15-3.png
new file mode 100644
index 0000000..dec6eb5
Binary files /dev/null and b/docs/base/assets/15-3.png differ
diff --git a/docs/base/assets/15-4.png b/docs/base/assets/15-4.png
new file mode 100644
index 0000000..45f70f2
Binary files /dev/null and b/docs/base/assets/15-4.png differ
diff --git a/docs/base/assets/15-5.png b/docs/base/assets/15-5.png
new file mode 100644
index 0000000..d840595
Binary files /dev/null and b/docs/base/assets/15-5.png differ
diff --git a/docs/base/assets/15-6.png b/docs/base/assets/15-6.png
new file mode 100644
index 0000000..3e87d79
Binary files /dev/null and b/docs/base/assets/15-6.png differ
diff --git a/docs/base/assets/2-1.png b/docs/base/assets/2-1.png
new file mode 100644
index 0000000..ecdd0d1
Binary files /dev/null and b/docs/base/assets/2-1.png differ
diff --git a/docs/base/assets/2-2.png b/docs/base/assets/2-2.png
new file mode 100644
index 0000000..16ba08c
Binary files /dev/null and b/docs/base/assets/2-2.png differ
diff --git a/docs/base/assets/2-3.png b/docs/base/assets/2-3.png
new file mode 100644
index 0000000..d70c1af
Binary files /dev/null and b/docs/base/assets/2-3.png differ
diff --git a/docs/base/assets/2-4.gif b/docs/base/assets/2-4.gif
new file mode 100644
index 0000000..b79c8ca
Binary files /dev/null and b/docs/base/assets/2-4.gif differ
diff --git a/docs/base/assets/3-1.png b/docs/base/assets/3-1.png
new file mode 100644
index 0000000..b3cea9f
Binary files /dev/null and b/docs/base/assets/3-1.png differ
diff --git a/docs/base/assets/4-1.png b/docs/base/assets/4-1.png
new file mode 100644
index 0000000..c5cd71f
Binary files /dev/null and b/docs/base/assets/4-1.png differ
diff --git a/docs/base/assets/4-2.png b/docs/base/assets/4-2.png
new file mode 100644
index 0000000..954ae4d
Binary files /dev/null and b/docs/base/assets/4-2.png differ
diff --git a/docs/base/assets/4-3.png b/docs/base/assets/4-3.png
new file mode 100644
index 0000000..9d7ac72
Binary files /dev/null and b/docs/base/assets/4-3.png differ
diff --git a/docs/base/assets/4-4.png b/docs/base/assets/4-4.png
new file mode 100644
index 0000000..0a95e48
Binary files /dev/null and b/docs/base/assets/4-4.png differ
diff --git a/docs/base/assets/4-5.png b/docs/base/assets/4-5.png
new file mode 100644
index 0000000..be35b18
Binary files /dev/null and b/docs/base/assets/4-5.png differ
diff --git a/docs/base/assets/5-1.png b/docs/base/assets/5-1.png
new file mode 100644
index 0000000..dc8329c
Binary files /dev/null and b/docs/base/assets/5-1.png differ
diff --git a/docs/base/assets/5-10.png b/docs/base/assets/5-10.png
new file mode 100644
index 0000000..b8780e1
Binary files /dev/null and b/docs/base/assets/5-10.png differ
diff --git a/docs/base/assets/5-100.png b/docs/base/assets/5-100.png
new file mode 100644
index 0000000..fc479ef
Binary files /dev/null and b/docs/base/assets/5-100.png differ
diff --git a/docs/base/assets/5-11.png b/docs/base/assets/5-11.png
new file mode 100644
index 0000000..5276303
Binary files /dev/null and b/docs/base/assets/5-11.png differ
diff --git a/docs/base/assets/5-2.png b/docs/base/assets/5-2.png
new file mode 100644
index 0000000..6537f45
Binary files /dev/null and b/docs/base/assets/5-2.png differ
diff --git a/docs/base/assets/5-3.png b/docs/base/assets/5-3.png
new file mode 100644
index 0000000..de852b0
Binary files /dev/null and b/docs/base/assets/5-3.png differ
diff --git a/docs/base/assets/5-4.png b/docs/base/assets/5-4.png
new file mode 100644
index 0000000..43e7a0e
Binary files /dev/null and b/docs/base/assets/5-4.png differ
diff --git a/docs/base/assets/5-5.png b/docs/base/assets/5-5.png
new file mode 100644
index 0000000..b0d53b5
Binary files /dev/null and b/docs/base/assets/5-5.png differ
diff --git a/docs/base/assets/5-6.png b/docs/base/assets/5-6.png
new file mode 100644
index 0000000..f5e4d69
Binary files /dev/null and b/docs/base/assets/5-6.png differ
diff --git a/docs/base/assets/5-7.png b/docs/base/assets/5-7.png
new file mode 100644
index 0000000..9fdf441
Binary files /dev/null and b/docs/base/assets/5-7.png differ
diff --git a/docs/base/assets/5-8.png b/docs/base/assets/5-8.png
new file mode 100644
index 0000000..644a7ad
Binary files /dev/null and b/docs/base/assets/5-8.png differ
diff --git a/docs/base/assets/5-9.png b/docs/base/assets/5-9.png
new file mode 100644
index 0000000..e47a311
Binary files /dev/null and b/docs/base/assets/5-9.png differ
diff --git a/docs/base/assets/8-1.png b/docs/base/assets/8-1.png
new file mode 100644
index 0000000..e2ce75e
Binary files /dev/null and b/docs/base/assets/8-1.png differ
diff --git a/docs/base/image-18-2.png b/docs/base/image-18-2.png
new file mode 100644
index 0000000..66f46bd
Binary files /dev/null and b/docs/base/image-18-2.png differ
diff --git a/docs/base/image-18.png b/docs/base/image-18.png
new file mode 100644
index 0000000..46fe9cc
Binary files /dev/null and b/docs/base/image-18.png differ
diff --git a/docs/base/image.png b/docs/base/image.png
new file mode 100644
index 0000000..8c8c633
Binary files /dev/null and b/docs/base/image.png differ
diff --git a/docs/base/ui/image-1.png b/docs/base/ui/image-1.png
new file mode 100644
index 0000000..4ef423b
Binary files /dev/null and b/docs/base/ui/image-1.png differ
diff --git a/docs/base/ui/image-2.png b/docs/base/ui/image-2.png
new file mode 100644
index 0000000..f2b052e
Binary files /dev/null and b/docs/base/ui/image-2.png differ
diff --git a/docs/base/ui/image.png b/docs/base/ui/image.png
new file mode 100644
index 0000000..5487880
Binary files /dev/null and b/docs/base/ui/image.png differ
diff --git a/docs/base/ui/ui.md b/docs/base/ui/ui.md
new file mode 100644
index 0000000..cd56a95
--- /dev/null
+++ b/docs/base/ui/ui.md
@@ -0,0 +1,126 @@
+# UI 库选型篇
+
+## 背景
+
+`unibest` 作为最好的 `uniapp` 开发模板,那 `UI 框架` 的选择也是要仔细斟酌的。
+
+`unibest` 作为 `vue3` 项目,`vue2` 时代的 `uview` 就不考虑在内了。但是在 `uview` 的基础上衍生出来的支持 `vue3` 的 `uview 系` 的 `ui框架` 还有不少,而且热度很高。
+
+官方维护的 `uni-ui`,支持全端,而且有类型提示,但样式略丑,且其他优秀的 `UI 库` 已经包含了 `uni-ui` 的组件,所以直接用第三方 `UI 库` 就好了。
+
+> tip1: `uni-ui` 本身是 `js` 开发的,但是官方提供了完备的类型提示( by `@uni-helper/uni-ui-types`)所以看起来就像是 `ts` 开发的一样,开发体验很好。所有的组件都有提示,很方便,很贴心。
+
+> tip2: 再次重申一下 `uview` 不支持 `Vue3`,不然又有人问我为啥不用 `uview`。(臣妾做不到啊~)
+
+## UI 库总览
+
+经过搜寻了一番,目前参加对比的 UI 框架有:
+
+- uv-ui (uveiw 系) - [文档地址](https://www.uvui.cn/)
+- uview-plus (uveiw 系) - [文档地址](https://uiadmin.net/uview-plus/)
+- Wot Design Uni (wot 系) - [文档地址](https://wot-design-uni.netlify.app/)
+- TuniaoUI (图鸟系) - [文档地址](https://vue3.tuniaokj.com/zh-CN/)
+- Sard uniapp (Sard系) - [文档地址](https://sard.wzt.zone/sard-uniapp-docs/)
+
+还有 2 个 UI 框架也很优秀,大部分组件开源免费,还有一部分组件是收费的,有需要的可以看看。
+
+- FirstUI [文档链接](https://doc.firstui.cn/)
+- ThorUI [文档链接](https://thorui.cn/doc/)
+
+> 温馨提示:收费没有对错,只要做得好,提供优质的组件,自然有用户买单。
+
+---
+
+下面通过几个方面对 `UI 库` 进行对比
+
+## 开源热度
+
+截止到 `2024-05-30` 发表文章时的数据:
+
+| UI 框架 | uv-ui | uview-plus | wot-ui | TuniaoUI |
+| ------------ | :---: | :--------: | :----: | :------: |
+| github stars | 568 | 362 | 492 | 192 |
+| gitee stars | 555 | 126 | 35 | - |
+| github forks | 1.1k | 158 | 188 | 20 |
+| gitee forks | 75 | 4 | 30 | - |
+
+其实到这里就一决高下了,`github star 数`: `uv-ui(568)` > `wot-ui(492)` > `uview-plus(362)` > `TuniaoUI(192)`,其中 `uv-ui` 和 `wot-ui` 拔得头筹。
+
+[](https://star-history.com/#Moonofweisheng/wot-design-uni&climblee/uv-ui&ijry/uview-plus&tuniaoTech/tuniaoui-rc-vue3-uniapp&Date)
+
+源码仓库地址展示如下,_纯粹为了方便大家查阅_ (虽然大概率你们也不会去访问,/手动狗头)
+
+| UI 框架 | 文档地址 | github | gitee |
+| ---------- | ------------------------------------- | ------------------------------------------------------- | ------------------------------------------------- |
+| uv-ui | | | |
+| uview-plus | | | |
+| wot-ui | | | |
+| TuniaoUI | | | - |
+
+> 接着奏乐接着舞,我们继续正文 ^\_^
+
+## 多端支持情况
+
+| UI 框架 | uv-ui | uview-plus | wot-ui | TuniaoUI |
+| ------------ | ----- | ---------- | ------ | -------- |
+| h5 | ✅ | ✅ | ✅ | ✅ |
+| app(ios) | ✅ | ✅ | ✅ | ✅ |
+| app(android) | ✅ | ✅ | ✅ | ✅ |
+| 微信小程序 | ✅ | ✅ | ✅ | ✅ |
+| 支付宝小程序 | ✅ | ✅ | ✅ | ✅ |
+| QQ 小程序 | ✅ | ✅ | ❌ | ❌ |
+| 百度小程序 | ✅ | ✅ | ❌ | ❌ |
+| 头条小程序 | ✅ | ✅ | ❌ | ❌ |
+
+## 组件数量
+
+| UI 框架 | uv-ui | uview-plus | wot-ui | TuniaoUI |
+| -------- | :---: | :--------: | :----: | :------: |
+| 总数 | 67 | 67 | 71 | 55 |
+| 基础组件 | 8 | 11 | 8 | 5 |
+| 表单组件 | 16 | 17 | 20 | 14 |
+| 数据组件 | 13 | 4 | 18 | 4 |
+| 反馈组件 | 8 | 10 | 16 | 8 |
+| 布局组件 | 7 | 9 | - | 8 |
+| 导航组件 | 8 | 8 | 9 | 5 |
+| 其他组件 | 7 | 8 | - | 5 |
+| 内容组件 | - | - | - | 6 |
+
+组件数:`wot(71)` > `uv-ui(67)` = `uview-plus(67)` > `TuniaoUI(55)`
+
+## `ts` 支持情况
+
+查看 4 个组件库的源码,可以了解到:
+
+- `uv-ui` 和 `uView-plus` 都是 `js` 写的,并非 `ts`,可以通过 `ttou/uv-typings` 提供类型支持。
+- `wot` 和 `TuniaoUI` 都是 `ts` 写的,编码体验会好很多。
+
+> 小知识:代码里如何辨别一个库是否有 ts 支持,写代码的时候按 `ctrl + i` (Mac 里 `cmd + i`),如果有提示就是有,啥都没有就是没有。
+>
+> 举个例子,编写 ` 别说我偏心,两位 `ui` 框架的作者都是我的好友,我是 `uv-ui` 群的管理员,`wot-ui` 作者在我的大群里面。选择 `wot-ui` 确实因为它很优秀。
+
+## 总结
+
+很高兴我们已经为宇宙最强 `uniapp` 开发模板 `unibest` 选好了 `UI 组件库`,`wot-ui` 是最终的幸运儿。为此我特意去 `wot-ui` 官网里面捐赠了一杯咖啡钱给作者,开源不易,要支持一下。
diff --git a/docs/changelog/CHANGELOG.md b/docs/changelog/CHANGELOG.md
new file mode 100644
index 0000000..5a08373
--- /dev/null
+++ b/docs/changelog/CHANGELOG.md
@@ -0,0 +1,111 @@
+# CHANGELOG 更新日志
+
+## v2.12.1(2025-06-13)
+
+### `oxlint` 优化
+
+- `oxlint` 从 `0.11.0` 升级到 `1.0.0`。
+
+> 注意:最新的 `1.1.0` 还有问题,运行报错,所以使用 `1.0.0`。(别贪新)
+
+**提交代码的时候会自动触发。** 如果想主动检测,可以使用 `pnpm lint` 命令。
+
+## v2.11.1(2025-06-11)
+
+### `hello-unibest`
+
+- 新增 `echarts`(推荐) 和 `ucharts` 示例。
+
+### docs 文档
+
+- 更新 `App 专题` `热更新`内容。( `android端` 无法热更新的问题,已经解决了!)
+
+## v2.11.0(2025-06-03)
+
+
+
+### 依赖降级
+
+- 将 `unocss` 从 `66.0.0` 降级到 `65.4.2`。(因为有部分网友会出现问题,所以降级了。)
+
+### 新模板
+
+- 新增 `base-sard-ui` 模板,方便用户直接使用 `sard-ui` 这个UI库开发。
+
+## v2.10.1(2025-05-28)
+
+### 新功能
+
+- 实现基础的 `登录` 功能,支持 `微信小程序` 静默登录 和 `非小程序` 登录。
+
+
+
+## ...
+
+## v0.0.0(2023-12.21)
+
+创建项目,首次提交。
diff --git a/docs/changelog/image-1.png b/docs/changelog/image-1.png
new file mode 100644
index 0000000..4cbca4d
Binary files /dev/null and b/docs/changelog/image-1.png differ
diff --git a/docs/changelog/image-2.png b/docs/changelog/image-2.png
new file mode 100644
index 0000000..b83eb56
Binary files /dev/null and b/docs/changelog/image-2.png differ
diff --git a/docs/changelog/image-3.png b/docs/changelog/image-3.png
new file mode 100644
index 0000000..38e5a85
Binary files /dev/null and b/docs/changelog/image-3.png differ
diff --git a/docs/changelog/image-4.png b/docs/changelog/image-4.png
new file mode 100644
index 0000000..efd5775
Binary files /dev/null and b/docs/changelog/image-4.png differ
diff --git a/docs/changelog/image.png b/docs/changelog/image.png
new file mode 100644
index 0000000..968322a
Binary files /dev/null and b/docs/changelog/image.png differ
diff --git a/docs/changelog/upgrade.md b/docs/changelog/upgrade.md
new file mode 100644
index 0000000..b5a8a47
--- /dev/null
+++ b/docs/changelog/upgrade.md
@@ -0,0 +1,212 @@
+# 升级指南
+
+分为 `6` 部分的内容:(2025-06-14 周六)
+
+- `uniapp sdk 升级`
+- `uni-helper 插件升级`
+- `oxlint 升级`
+- `移除 eslint, stylelint`
+- `unocss 升级` (可选)
+- `vscode 配置文件升级` (可选)
+
+## uniapp sdk 升级
+
+```sh
+pnpm uvm # 升级 uniapp sdk
+# 如果以上命令不存在,请使用下面的
+npx @dcloudio/uvm@latest
+```
+
+然后进入交互式的升级模式,按照提示进行升级。期间包管理器选择 `pnpm`。
+
+升级完后,会自动引入 `vue-i18n`,不需要的可以删除它。(可选)
+
+## uni-helper 插件升级
+
+```sh
+"@uni-helper/uni-types": "1.0.0-alpha.3",
+"@uni-helper/unocss-preset-uni": "^0.2.11",
+"@uni-helper/vite-plugin-uni-components": "0.2.0",
+"@uni-helper/vite-plugin-uni-layouts": "0.1.10",
+"@uni-helper/vite-plugin-uni-manifest": "0.2.8",
+"@uni-helper/vite-plugin-uni-pages": "0.2.28",
+"@uni-helper/vite-plugin-uni-platform": "0.0.4",
+```
+
+把你项目里面的 `package.json` 里面的相关依赖包版本改成上面的。然后执行 `pnpm i` 安装。
+
+## oxlint 升级
+
+```sh
+pnpm add -D oxlint@v1.0.0 # 注意不要贪最新,最新的 v1.1.0 有问题,会报错。
+```
+
+`package.json` 里面的 `"lint-staged"` 内容改为:
+
+```json
+"lint-staged": {
+ "**/*.{html,cjs,json,md,scss,css,txt}": [
+ "prettier --write --cache"
+ ],
+ "**/*.{js,jsx,ts,tsx,vue,mjs,cjs,mts,cts}": [
+ "oxlint --fix",
+ "prettier --write --cache"
+ ],
+ "!**/{node_modules,dist}/**": []
+},
+```
+
+`package.json` 里面的 `scripts` 添加:
+
+```json
+scripts: {
+ // ... 其他
+ "lint": "oxlint",
+ "lint-fix": "oxlint --fix"
+}
+```
+
+然后在项目根目录新建 `.oxlintrc.json` 文件,内容如下:
+
+```json
+{
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
+ "extends": ["config:recommended"],
+ "plugins": ["import", "typescript", "unicorn"],
+ "rules": {
+ "no-console": "off",
+ "no-unused-vars": "off"
+ },
+ "env": {
+ "es6": true
+ },
+ "globals": {
+ "foo": "readonly"
+ },
+ "ignorePatterns": [
+ "node_modules",
+ "dist",
+ "src/static/**",
+ "src/uni_modules/**",
+ "vite.config.ts",
+ "uno.config.ts",
+ "pages.config.ts",
+ "manifest.config.ts"
+ ],
+ "settings": {},
+ "overrides": [
+ {
+ "files": ["*.test.ts", "*.spec.ts"],
+ "rules": {
+ "@typescript-eslint/no-explicit-any": "off"
+ }
+ }
+ ]
+}
+```
+
+## 移除 eslint, stylelint
+
+上面配置了 `oxlint` 后,`eslint` 不需要了,可以把 `依赖包` 和 `配置文件` 都都删除。
+
+`stylelint` 可以保留也可以删除,因为几乎都是用 `unocss` 来写样式的,所以 `stylelint` 不要也可以。
+
+## unocss 升级(可选)
+
+1、升级 `unocss`
+
+```sh
+pnpm add -D unocss@65.4.2 # 注意不要贪最新,最新的 v66+ 有问题,会报错。
+```
+
+2、 更新 `uno.config.ts` 配置文件
+
+```ts
+// https://www.npmjs.com/package/@uni-helper/unocss-preset-uni
+import { presetUni } from '@uni-helper/unocss-preset-uni'
+import {
+ defineConfig,
+ presetIcons,
+ presetAttributify,
+ transformerDirectives,
+ transformerVariantGroup,
+} from 'unocss'
+
+export default defineConfig({
+ presets: [
+ presetUni({
+ attributify: {
+ // prefix: 'fg-', // 如果加前缀,则需要在代码里面使用 `fg-` 前缀,如:
+ prefixedOnly: true,
+ },
+ }),
+ presetIcons({
+ scale: 1.2,
+ warn: true,
+ extraProperties: {
+ display: 'inline-block',
+ 'vertical-align': 'middle',
+ },
+ }),
+ // 支持css class属性化
+ presetAttributify(),
+ ],
+ transformers: [
+ // 启用指令功能:主要用于支持 @apply、@screen 和 theme() 等 CSS 指令
+ transformerDirectives(),
+ // 启用 () 分组功能
+ // 支持css class组合,eg: `测试 unocss
`
+ transformerVariantGroup(),
+ ],
+ shortcuts: [
+ {
+ center: 'flex justify-center items-center',
+ },
+ ],
+ rules: [
+ [
+ 'p-safe',
+ {
+ padding:
+ 'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)',
+ },
+ ],
+ ['pt-safe', { 'padding-top': 'env(safe-area-inset-top)' }],
+ ['pb-safe', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
+ ],
+ theme: {
+ colors: {
+ /** 主题色,用法如: text-primary */
+ primary: 'var(--wot-color-theme,#0957DE)',
+ },
+ fontSize: {
+ /** 提供更小号的字体,用法如:text-2xs */
+ '2xs': ['20rpx', '28rpx'],
+ '3xs': ['18rpx', '26rpx'],
+ },
+ },
+})
+```
+
+3、 更新 `vite.config.ts` 中 `unocss` 的引入方式:
+
+```ts
+export default async ({ command, mode }) => {
+ // @see https://unocss.dev/
+ const UnoCSS = (await import('unocss/vite')).default
+ // ... 其他代码
+})
+```
+
+## vscode 配置文件升级
+
+`.vscode/settings.json` 里面 `explorer.fileNesting.patterns` 配置如下:
+
+```json
+"explorer.fileNesting.patterns": {
+ "README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md",
+ "pages.config.ts": "manifest.config.ts,openapi-ts-request.config.ts",
+ "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
+ ".oxlintrc.json": "tsconfig.json,.commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
+}
+```
diff --git a/docs/gif/assets/auto-page.gif b/docs/gif/assets/auto-page.gif
new file mode 100644
index 0000000..b3de0e6
Binary files /dev/null and b/docs/gif/assets/auto-page.gif differ
diff --git a/docs/gif/assets/auto-sort.gif b/docs/gif/assets/auto-sort.gif
new file mode 100644
index 0000000..76d0ffe
Binary files /dev/null and b/docs/gif/assets/auto-sort.gif differ
diff --git a/docs/gif/assets/commit.gif b/docs/gif/assets/commit.gif
new file mode 100644
index 0000000..51a84ed
Binary files /dev/null and b/docs/gif/assets/commit.gif differ
diff --git a/docs/gif/assets/i18n.gif b/docs/gif/assets/i18n.gif
new file mode 100644
index 0000000..10c1202
Binary files /dev/null and b/docs/gif/assets/i18n.gif differ
diff --git a/docs/gif/assets/ios-run-app.gif b/docs/gif/assets/ios-run-app.gif
new file mode 100644
index 0000000..88d3d8f
Binary files /dev/null and b/docs/gif/assets/ios-run-app.gif differ
diff --git a/docs/gif/assets/lottery2.gif b/docs/gif/assets/lottery2.gif
new file mode 100644
index 0000000..8085046
Binary files /dev/null and b/docs/gif/assets/lottery2.gif differ
diff --git a/docs/gif/assets/lottery3.gif b/docs/gif/assets/lottery3.gif
new file mode 100644
index 0000000..f8e5de2
Binary files /dev/null and b/docs/gif/assets/lottery3.gif differ
diff --git a/docs/gif/assets/snippets.gif b/docs/gif/assets/snippets.gif
new file mode 100644
index 0000000..0ab04b8
Binary files /dev/null and b/docs/gif/assets/snippets.gif differ
diff --git a/docs/gif/assets/snippets2.gif b/docs/gif/assets/snippets2.gif
new file mode 100644
index 0000000..56ec517
Binary files /dev/null and b/docs/gif/assets/snippets2.gif differ
diff --git a/docs/gif/assets/snippets3.gif b/docs/gif/assets/snippets3.gif
new file mode 100644
index 0000000..b79c8ca
Binary files /dev/null and b/docs/gif/assets/snippets3.gif differ
diff --git a/docs/gif/assets/unocss-icons.gif b/docs/gif/assets/unocss-icons.gif
new file mode 100644
index 0000000..b7fc7f0
Binary files /dev/null and b/docs/gif/assets/unocss-icons.gif differ
diff --git a/docs/gif/assets/unocss.gif b/docs/gif/assets/unocss.gif
new file mode 100644
index 0000000..fdafc71
Binary files /dev/null and b/docs/gif/assets/unocss.gif differ
diff --git a/docs/gif/index.md b/docs/gif/index.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..8db9b6a
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,95 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+
+hero:
+ name: 'unibest'
+ text: '最好的 uniapp 框架'
+ tagline: '开箱即用,提供舒适开发体验'
+ image:
+ src: /logo.svg
+ alt: unibest
+ actions:
+ - theme: brand
+ text: 快速开始
+ link: /base/2-start
+ - theme: alt
+ text: 常见问题
+ link: /base/14-faq
+ - theme: brand
+ text: 🥤 打赏
+ link: /advanced/rewards/rewards
+ - theme: alt
+ text: ⭐ 优秀案例
+ link: /advanced/showcase/showcase
+ - theme: alt
+ text: 演示DEMO
+ link: https://feige996.github.io/hello-unibest/
+
+features:
+ - icon: 🔥
+ title: 多平台覆盖
+ details: 支持 微信小程序、H5、APP 和 支付宝小程序、钉钉小程序、抖音小程序等平台。
+ # linkText: 进入 Vue 官网
+ # link: https://cn.vuejs.org/
+ - icon: ⚡️
+ title: Vue3 + Vite5 + Pnpm + TypeScript
+ details: Vue3 + Vite5 + Pnpm + TypeScript 最强组合,飞一般的编码体验,同时支持 js 编写
+ # linkText: 进入 Vue 官网
+ # link: https://cn.vuejs.org/
+ - icon:
+ title: 拥抱宇宙最强编辑器 VS Code
+ details: 使用你最熟悉的 VS Code,无需切换编辑器,告别 HBuilderX 糟糕的编码体验
+ # linkText: 下载 VS Code
+ # link: https://code.visualstudio.com/
+
+ - icon:
+ title: UnoCSS + UnoCSS Icons
+ details: 高性能原子化 CSS 引擎 UnoCSS,还有 100000+ 图标为你所用,无需额外引入外链
+ # linkText: 进入 UnoCSS 官网
+ # link: https://unocss.dev/
+
+ - icon: 🗂
+ title: 基于文件的路由
+ details: 无需维护 pages.json,一切都是自动化
+
+ - icon: 📦
+ title: 布局系统
+ details: Layout 布局系统,一行代码切换不同布局
+
+ - icon: 🌈
+ title: 开箱即用的功能和组件
+ details: pinia、API自动导入、请求拦截、路由拦截、字体图标、多语言、自定义tabbar、SVG、UI库...
+ # - icon:
+ # title: Alova.js
+ # details: 轻量级请求库,一行代码完成各种复杂场景的网络请求。
+ # linkText: 进入 Alova官网
+ # link: https://alova.js.org/zh-CN
+ # - icon:
+ # title: 享受 Vite 无可比拟的体验
+ # details: 服务器即时启动,闪电般的热更新,还可以使用基于 Vite 生态的插件。
+ # - icon:
+
+ - icon: 🦾
+ title: 精心配置的代码规范
+ details: TypeScript + Prettier + ESLint + Stylelint + husky + lint-staged + commitlint 配置规范
+
+ - icon: 🎉
+ title: 一切为开发者考虑
+ details: 项目积极维护,打造最好用的 uniapp 开发框架
+---
+
+
+
+ 本站总访问量次
+
+
+ 本站总访客数人
+
+
+ 本文总阅读量次
+
+
+
diff --git a/docs/other/blog.md b/docs/other/blog.md
new file mode 100644
index 0000000..ece35f8
--- /dev/null
+++ b/docs/other/blog.md
@@ -0,0 +1,9 @@
+# 博客列表
+
+`unibest` 相关文章主要发布在 `掘金`,我的 [掘金 unibest 专栏](https://juejin.cn/column/7307183009604894735)。
+
+- [🔥2024 年最好用的 uniapp 开发模板,近一个月 star 数飙升!🔥](https://juejin.cn/post/7329034439408615451)
+- [【unibest】uniapp + vue3 超实用模板](https://juejin.cn/post/7315246744158191666)
+- [【unibest】uniapp + vue3 超实用模板(续)](https://juejin.cn/post/7315461542697500682)
+- [【unibest】uniapp + vue3 超实用模板(终)](https://juejin.cn/post/7321930742400188453)
+- [【unibest】uniapp + vue3 超实用模板(番外篇)](https://juejin.cn/editor/drafts/7315308701051519030)
diff --git a/docs/other/files/files.md b/docs/other/files/files.md
new file mode 100644
index 0000000..0d9304f
--- /dev/null
+++ b/docs/other/files/files.md
@@ -0,0 +1,14 @@
+# 文件资源展示优化
+
+> 本功能由 `⑤群` 群友 `Collapsar` 提供,感谢 `Collapsar` 的贡献。
+
+**未配置前的默认效果:**
+
+
+**配置后效果:**
+
+
+**相关代码:**
+
+
+> 如果觉得不需要这种查看方式,可以删除 or 注释掉 `.vscode/setting.json` 里面 `explorer.fileNesting.patterns` 配置。
diff --git a/docs/other/files/image-1.png b/docs/other/files/image-1.png
new file mode 100644
index 0000000..0afc92a
Binary files /dev/null and b/docs/other/files/image-1.png differ
diff --git a/docs/other/files/image-2.png b/docs/other/files/image-2.png
new file mode 100644
index 0000000..5aa7876
Binary files /dev/null and b/docs/other/files/image-2.png differ
diff --git a/docs/other/files/image-3.png b/docs/other/files/image-3.png
new file mode 100644
index 0000000..4a74222
Binary files /dev/null and b/docs/other/files/image-3.png differ
diff --git a/docs/other/iconfont/assets/5-10.png b/docs/other/iconfont/assets/5-10.png
new file mode 100644
index 0000000..3e3b05c
Binary files /dev/null and b/docs/other/iconfont/assets/5-10.png differ
diff --git a/docs/other/iconfont/assets/5-100.png b/docs/other/iconfont/assets/5-100.png
new file mode 100644
index 0000000..fc479ef
Binary files /dev/null and b/docs/other/iconfont/assets/5-100.png differ
diff --git a/docs/other/iconfont/assets/5-11.png b/docs/other/iconfont/assets/5-11.png
new file mode 100644
index 0000000..3ee0702
Binary files /dev/null and b/docs/other/iconfont/assets/5-11.png differ
diff --git a/docs/other/iconfont/assets/5-12.png b/docs/other/iconfont/assets/5-12.png
new file mode 100644
index 0000000..c85271b
Binary files /dev/null and b/docs/other/iconfont/assets/5-12.png differ
diff --git a/docs/other/iconfont/assets/5-13.png b/docs/other/iconfont/assets/5-13.png
new file mode 100644
index 0000000..9344d1b
Binary files /dev/null and b/docs/other/iconfont/assets/5-13.png differ
diff --git a/docs/other/iconfont/assets/5-14.png b/docs/other/iconfont/assets/5-14.png
new file mode 100644
index 0000000..c328784
Binary files /dev/null and b/docs/other/iconfont/assets/5-14.png differ
diff --git a/docs/other/iconfont/assets/5-15.png b/docs/other/iconfont/assets/5-15.png
new file mode 100644
index 0000000..9b41dfb
Binary files /dev/null and b/docs/other/iconfont/assets/5-15.png differ
diff --git a/docs/other/iconfont/assets/5-16.png b/docs/other/iconfont/assets/5-16.png
new file mode 100644
index 0000000..858f42c
Binary files /dev/null and b/docs/other/iconfont/assets/5-16.png differ
diff --git a/docs/other/iconfont/assets/5-17.png b/docs/other/iconfont/assets/5-17.png
new file mode 100644
index 0000000..c328784
Binary files /dev/null and b/docs/other/iconfont/assets/5-17.png differ
diff --git a/docs/other/iconfont/assets/5-18.png b/docs/other/iconfont/assets/5-18.png
new file mode 100644
index 0000000..f4c6b1d
Binary files /dev/null and b/docs/other/iconfont/assets/5-18.png differ
diff --git a/docs/other/iconfont/assets/5-19.png b/docs/other/iconfont/assets/5-19.png
new file mode 100644
index 0000000..642f89b
Binary files /dev/null and b/docs/other/iconfont/assets/5-19.png differ
diff --git a/docs/other/iconfont/assets/5-20.png b/docs/other/iconfont/assets/5-20.png
new file mode 100644
index 0000000..d057e6a
Binary files /dev/null and b/docs/other/iconfont/assets/5-20.png differ
diff --git a/docs/other/iconfont/assets/5-21.png b/docs/other/iconfont/assets/5-21.png
new file mode 100644
index 0000000..15a2913
Binary files /dev/null and b/docs/other/iconfont/assets/5-21.png differ
diff --git a/docs/other/iconfont/assets/5-22.png b/docs/other/iconfont/assets/5-22.png
new file mode 100644
index 0000000..8a594a5
Binary files /dev/null and b/docs/other/iconfont/assets/5-22.png differ
diff --git a/docs/other/iconfont/assets/5-23.png b/docs/other/iconfont/assets/5-23.png
new file mode 100644
index 0000000..b5b82db
Binary files /dev/null and b/docs/other/iconfont/assets/5-23.png differ
diff --git a/docs/other/iconfont/assets/5-9.png b/docs/other/iconfont/assets/5-9.png
new file mode 100644
index 0000000..ccc754d
Binary files /dev/null and b/docs/other/iconfont/assets/5-9.png differ
diff --git a/docs/other/iconfont/iconfont.md b/docs/other/iconfont/iconfont.md
new file mode 100644
index 0000000..80ff937
--- /dev/null
+++ b/docs/other/iconfont/iconfont.md
@@ -0,0 +1,108 @@
+## iconfont 图标库
+
+`iconfont` 同样有海量免费的图标,同时支持上传自己的图标。公司项目通常会有自己的图标,由专业的 `UI设计师` 设计,这时通常会使用 `iconfont` 方式使用图标。
+
+- 1. 打开`阿里巴巴矢量图标库 iconfont`,地址:https://www.iconfont.cn/,并登录。
+- 2. 寻找需要的图标,加入项目,也可以上传自己的图标。
+
+
+
+
+
+
+
+> 初次接触 `iconfont` 的同学,可能会找不到自己的项目,如下图:资源管理 -- 我的项目
+
+
+
+- 3.图标方式选择,如下图有 `Unicode` `Font class` `Symbol` 三种方式,分别预览和使用如下:
+
+
+
+
+
+
+
+- `Unicode` 的方式太落后,语义化不明显,不推荐;
+- `Symbol` 的方式太先进(背后原理是生成了 `SVG` 雪碧图),先进到 `小程序` 和 `APP` 都不支持,只能无奈放弃。
+
+> `Symbol` 的方式生成 `svg` 雪碧图,如下所示:
+>
+> 
+
+- `Font class` 则是我们最合适的选择,有 `Symbol` 一样的语义化(都是`icon-xxx`方式),引入和使用也方便( `Symbol` 是一个 `js` 文件,`Font class` 是一个 `css` 文件)。
+
+- 3. 点击选中 `Font class` 后再点击 `查看在线连接` 按钮,可以拿到一个 `css` 的链接,如 [//at.alicdn.com/t/c/font_4032028_mbcuy517h6.css](//at.alicdn.com/t/c/font_4032028_mbcuy517h6.css) ,如果期间新加入了图标,记得点击更新链接,会重新生成一个链接,只有最后面一串 hash 有改变,并且旧的链接依然可以访问。
+
+
+
+我们使用的是 `Font class` 的方式,只需要这一个 `css` 链接就行,无需 `下载至本地`,想要本地预览的话才需要 `下载至本地`。
+
+> `iconfont` 有默认的前缀 `icon-`,可以设置为其他的,如我的一个项目设置为 `bap-icon-`,以防跟其他的冲突。
+
+
+
+> 注意 `uniapp` 项目拿到 `css` 链接放到 `index.html` 是不对的,这样做只在 `h5` 中生效,`小程序` 和 `APP` 都不生效,正确的做法是放到代码里面显示引入。下面会讲:
+
+- 4.在 `style/index.scss` 中写上上面的 `css` 链接里面的内容(`style/index.scss` 已经在 `main.ts` 引入了,`unibest` 模板已经内置),如下
+
+> 注意: `url(//at.alicdn.com)` 里面的路径要改为 `url(https://at.alicdn.com)`,因为 APP 里面 `//` 是文件协议。 —— 设定 `https` 协议
+
+```css
+@font-face {
+ font-family: iconfont; /* Project id 4032028 */
+ src:
+ url('//at.alicdn.com/t/c/font_4032028_mbcuy517h6.woff2?t=1713685013355') format('woff2'),
+ url('//at.alicdn.com/t/c/font_4032028_mbcuy517h6.woff?t=1713685013355') format('woff'),
+ url('//at.alicdn.com/t/c/font_4032028_mbcuy517h6.ttf?t=1713685013355') format('truetype');
+}
+
+.iconfont {
+ font-family: iconfont !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-facebook::before {
+ content: '\e87d';
+}
+
+.icon-twitter::before {
+ content: '\e646';
+}
+
+.icon-telegram::before {
+ content: '\f245';
+}
+```
+
+- 5. 编写代码,``
+
+
+
+- 6. 预览,`h5 `端正常,APP 端不正常,小程序端看着正常,控制台也会报错,如下图:
+
+
+
+- 7. 这个怎么处理呢?转成 `base64` 是最快捷的,`iconfont` 本身就支持, `3`步搞定:
+
+ - 7.1 如下图,勾选 `Base64`
+
+ 
+
+ - 7.2 生成新链接,并得到新的 `css` 代码
+
+ 
+
+ - 7.3 引入新代码,刷新界面,小程序不报错了,APP 也正常了!
+
+ 
+
+
diff --git a/docs/other/image/assets/image-1.png b/docs/other/image/assets/image-1.png
new file mode 100644
index 0000000..cc073ce
Binary files /dev/null and b/docs/other/image/assets/image-1.png differ
diff --git a/docs/other/image/assets/image-2.png b/docs/other/image/assets/image-2.png
new file mode 100644
index 0000000..c45e2e7
Binary files /dev/null and b/docs/other/image/assets/image-2.png differ
diff --git a/docs/other/image/assets/unibest-项目架构.png b/docs/other/image/assets/unibest-项目架构.png
new file mode 100644
index 0000000..67667ac
Binary files /dev/null and b/docs/other/image/assets/unibest-项目架构.png differ
diff --git a/docs/other/image/image.md b/docs/other/image/image.md
new file mode 100644
index 0000000..8e3c051
--- /dev/null
+++ b/docs/other/image/image.md
@@ -0,0 +1,42 @@
+# 图片占位图
+
+- 色块占位图
+- 真实随机图片
+
+## 色块占位图
+
+下面是一个 `400x200 - 宽高,3c9cff - 背景颜色,fff - 文本颜色` 的色块占位图。
+
+
+
+可以通过下面几种方式生成,效果一样:
+
+| 官网地址 | 占位图片示例 |
+| :-------------------------------------------------- | :------------------------------------------------------------------------------------------------------- |
+| [https://placeholder.com](https://placeholder.com/) | [https://via.placeholder.com/400x200.png/3c9cff/fff](https://via.placeholder.com/400x200.png/3c9cff/fff) |
+| [https://dummyimage.com](https://dummyimage.com/) | [https://dummyimage.com/400x200/3c9cff/fff](https://dummyimage.com/400x200/3c9cff/fff) |
+| [https://fakeimg.pl](https://fakeimg.pl/) | [https://fakeimg.pl/400x200/3c9cff/fff](https://fakeimg.pl/400x200/3c9cff/fff) |
+
+代码编写举例:
+
+```vue
+
+```
+
+## 真实随机图片
+
+如果想生成某个宽高的随机图片,可以使用 [https://picsum.photos](https://picsum.photos)。
+
+格式如:`https://picsum.photos//?random=1`
+
+举例:[https://picsum.photos/400/200?random=1](https://picsum.photos/400/200?random=1)
+
+生成效果如下:
+
+
+
+代码编写举例:
+
+```vue
+
+```
diff --git a/docs/other/links/links.md b/docs/other/links/links.md
new file mode 100644
index 0000000..6f09187
--- /dev/null
+++ b/docs/other/links/links.md
@@ -0,0 +1,64 @@
+# 相关链接
+
+## Unibest Demo 分支演示地址
+
+- [演示地址](https://feige996.github.io/hello-unibest/#/)
+- [仓库地址-github](https://github.com/feige996/hello-unibest)
+- [仓库地址-gitee](https://gitee.com/feige996/hello-unibest)
+
+## UI 组件库
+
+- [wot-ui](https://wot-design-uni.cn) -- `五星推荐⭐⭐⭐⭐⭐,unibest默认内置`
+ > [wot-ui 备用地址](https://wot-design-uni.netlify.app)
+- [uni-ui](https://uniapp.dcloud.net.cn/component/uniui/uni-ui.html)
+- [uv-ui](https://www.uvui.cn/)
+- [uview-plus](https://uiadmin.net/uview-plus/)
+- [TuniaoUI](https://vue3.tuniaokj.com/zh-CN/)
+- [Sard uniapp](https://sard.wzt.zone/sard-uniapp-docs/)
+- [FirstUI](https://doc.firstui.cn/)(部分组件收费)
+- [ThorUI](https://thorui.cn/doc/)(部分组件收费)
+
+## 原子类 CSS
+
+- [UnoCSS](https://unocss.dev/) -- `五星推荐⭐⭐⭐⭐⭐`
+- [tailwindcss](https://tailwindcss.com/)
+
+## icons
+
+- [icones](https://icones.js.org/) -- `五星推荐⭐⭐⭐⭐⭐` used in `UnoCSS Icons`
+- [iconfont](https://www.iconfont.cn/)
+- [IconPark](https://iconpark.oceanengine.com)
+
+## 优质组件
+
+- [z-paging](https://z-paging.zxlee.cn/) -- `五星推荐⭐⭐⭐⭐⭐`
+
+ > 一个 `uni-app` 分页组件。
+ >
+ > 全平台兼容,支持自定义下拉刷新、上拉加载更多,支持虚拟列表,支持自动管理空数据图、点击返回顶部,支持聊天分页、本地分页,支持展示最后更新时间,支持国际化等等。
+
+- [mescroll](https://www.mescroll.com/)
+
+ > 精致的下拉刷新和上拉加载 js 框架,一套代码多端运行,支持 `uni-app`。
+
+## uni-app
+
+- [uni-app 官网](https://uniapp.dcloud.net.cn/)
+- [uni-app x 官网](https://doc.dcloud.net.cn/uni-app-x/)
+
+## 图表库
+
+- [ucharts](https://www.ucharts.cn/v2/#/)
+- [lime-echart](https://gitee.com/liangei/lime-echart)
+
+> 其他可以在 `uni-app` 插件市场找:[uniapp chart](https://ext.dcloud.net.cn/search?q=chart)
+
+## vue 相关
+
+- [Vue](https://cn.vuejs.org/)
+- [Vite](https://cn.vitejs.dev/)
+- [Pinia](https://pinia.vuejs.org/zh/)
+
+## 请求库
+
+- [Alova.js](https://alova.js.org/zh-CN)
diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico
new file mode 100644
index 0000000..47c577c
Binary files /dev/null and b/docs/public/favicon.ico differ
diff --git a/docs/public/logo.svg b/docs/public/logo.svg
new file mode 100644
index 0000000..ccb7343
--- /dev/null
+++ b/docs/public/logo.svg
@@ -0,0 +1,33 @@
+
+
\ No newline at end of file
diff --git a/env/.env b/env/.env
new file mode 100644
index 0000000..3ee0bd3
--- /dev/null
+++ b/env/.env
@@ -0,0 +1,50 @@
+VITE_APP_TITLE = '芋道管理系统'
+VITE_APP_PORT = 9000
+
+VITE_UNI_APPID = '__UNI__D1E5001'
+VITE_WX_APPID = 'wx1a832d51073d3a35'
+
+# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
+# https://uniapp.dcloud.net.cn/collocation/manifest.html#h5-router
+# 比如你要部署到 https://unibest.tech/doc/ ,则配置为 /doc/
+VITE_APP_PUBLIC_BASE=/
+
+# 后台请求地址
+VITE_SERVER_BASEURL = 'http://localhost:48080/admin-api'
+VITE_UPLOAD_BASEURL = 'http://localhost:48080/upload'
+# 备注:如果后台带统一前缀,则也要加到后面,eg: https://ukw0y1.laf.run/api
+
+# 注意,如果是微信小程序,还有一套请求地址的配置,根据 develop、trial、release 分别设置上传地址,见 `src/utils/index.ts`。
+
+# h5是否需要配置代理
+VITE_APP_PROXY_ENABLE = false
+# 下面的不用修改,只要不跟你后台的统一前缀冲突就行。如果修改了,记得修改 `nginx` 里面的配置
+VITE_APP_PROXY_PREFIX = '/admin-api'
+
+# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
+VITE_UPLOAD_TYPE=server
+
+# 静态资源地址
+VITE_STATIC_BASEURL = 'http://test.yudao.iocoder.cn'
+
+# 认证模式,'single' | 'double' ==> 单token | 双token
+VITE_AUTH_MODE = 'double'
+
+# 原生插件资源复制开关,控制是否启用 copy-native-resources 插件
+VITE_COPY_NATIVE_RES_ENABLE = false
+
+# 租户开关
+VITE_APP_TENANT_ENABLE=true
+# 验证码的开关
+VITE_APP_CAPTCHA_ENABLE=false
+# 默认账户密码
+VITE_APP_DEFAULT_LOGIN_TENANT_ID = 1
+VITE_APP_DEFAULT_LOGIN_USERNAME = admin
+VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123
+
+# API 加解密
+VITE_APP_API_ENCRYPT_ENABLE = true
+VITE_APP_API_ENCRYPT_HEADER = X-Api-Encrypt
+VITE_APP_API_ENCRYPT_ALGORITHM = AES
+VITE_APP_API_ENCRYPT_REQUEST_KEY = 52549111389893486934626385991395
+VITE_APP_API_ENCRYPT_RESPONSE_KEY = 96103715984234343991809655248883
diff --git a/env/.env.development b/env/.env.development
new file mode 100644
index 0000000..496bbe1
--- /dev/null
+++ b/env/.env.development
@@ -0,0 +1,9 @@
+# 变量必须以 VITE_ 为前缀才能暴露给外部读取
+NODE_ENV = 'development'
+# 是否去除console 和 debugger
+VITE_DELETE_CONSOLE = false
+# 是否开启sourcemap
+VITE_SHOW_SOURCEMAP = false
+
+# 后台请求地址
+# VITE_SERVER_BASEURL = 'http://localhost:48080'
diff --git a/env/.env.production b/env/.env.production
new file mode 100644
index 0000000..eef01df
--- /dev/null
+++ b/env/.env.production
@@ -0,0 +1,9 @@
+# 变量必须以 VITE_ 为前缀才能暴露给外部读取
+NODE_ENV = 'production'
+# 是否去除console 和 debugger
+VITE_DELETE_CONSOLE = true
+# 是否开启sourcemap
+VITE_SHOW_SOURCEMAP = false
+
+# 后台请求地址
+# VITE_SERVER_BASEURL = 'https://prod.xxx.com'
diff --git a/env/.env.test b/env/.env.test
new file mode 100644
index 0000000..5a975f8
--- /dev/null
+++ b/env/.env.test
@@ -0,0 +1,9 @@
+# 变量必须以 VITE_ 为前缀才能暴露给外部读取
+NODE_ENV = 'development'
+# 是否去除console 和 debugger
+VITE_DELETE_CONSOLE = false
+# 是否开启sourcemap
+VITE_SHOW_SOURCEMAP = false
+
+# 后台请求地址
+# VITE_SERVER_BASEURL = 'https://test.xxx.com'
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 0000000..045b049
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,64 @@
+import uniHelper from '@uni-helper/eslint-config'
+
+export default uniHelper({
+ unocss: true,
+ vue: true,
+ markdown: false,
+ ignores: [
+ // 忽略uni_modules目录
+ '**/uni_modules/',
+ // 忽略原生插件目录
+ '**/nativeplugins/',
+ '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/**',
+ ],
+ // https://eslint-config.antfu.me/rules
+ rules: {
+ 'no-useless-return': 'off',
+ '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',
+ 'style/brace-style': 'off', // 参考 https://github.com/antfu/eslint-config/issues/322 帖子:关闭此规则,使用下面的 brace-style 规则
+ 'vue/singleline-html-element-content-newline': [
+ 'error',
+ {
+ externalIgnores: ['text'],
+ },
+ ],
+ // vue SFC 调换顺序改这里
+ // 解释 by 芋艿:为什么 script 开始放在 template 前面:https://yb.tencent.com/s/1fYYlgBopLAT
+ 'vue/block-order': ['error', {
+ order: [['script', 'template'], 'style'],
+ }],
+ // add by 芋艿:else、catch、} 等,不换行:https://zh-hans.eslint.org/docs/latest/rules/brace-style
+ 'brace-style': ['error', '1tbs', {
+ allowSingleLine: true,
+ }],
+ },
+ formatters: {
+ /**
+ * Format CSS, LESS, SCSS files, also the `
diff --git a/src/api/bpm/category/index.ts b/src/api/bpm/category/index.ts
new file mode 100644
index 0000000..822cdf0
--- /dev/null
+++ b/src/api/bpm/category/index.ts
@@ -0,0 +1,51 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+const baseUrl = '/bpm/category'
+
+/** 流程分类 */
+export interface Category {
+ id?: number
+ name: string // 分类名
+ code: string // 分类标志
+ status: number // 分类状态
+ description?: string // 分类描述
+ sort: number // 分类排序
+ createTime?: Date
+}
+
+/** 获取流程分类分页列表 */
+export function getCategoryPage(params: PageParam) {
+ return http.get>(`${baseUrl}/page`, params)
+}
+
+/** 获取流程分类详情 */
+export function getCategory(id: number) {
+ return http.get(`${baseUrl}/get?id=${id}`)
+}
+
+/** 创建流程分类 */
+export function createCategory(data: Category) {
+ return http.post(`${baseUrl}/create`, data)
+}
+
+/** 更新流程分类 */
+export function updateCategory(data: Category) {
+ return http.put(`${baseUrl}/update`, data)
+}
+
+/** 删除流程分类 */
+export function deleteCategory(id: number) {
+ return http.delete(`${baseUrl}/delete?id=${id}`)
+}
+
+/** 获取流程分类简单列表 */
+export function getCategorySimpleList() {
+ return http.get(`${baseUrl}/simple-list`)
+}
+
+/** 批量修改流程分类的排序 */
+export function updateCategorySortBatch(ids: number[]) {
+ const params = ids.join(',')
+ return http.put(`${baseUrl}/update-sort-batch?ids=${params}`)
+}
diff --git a/src/api/bpm/definition/index.ts b/src/api/bpm/definition/index.ts
new file mode 100644
index 0000000..daf738e
--- /dev/null
+++ b/src/api/bpm/definition/index.ts
@@ -0,0 +1,26 @@
+import { http } from '@/http/http'
+
+/** 流程定义 */
+export interface ProcessDefinition {
+ id: string
+ key: string
+ name: string
+ description?: string
+ icon?: string
+ category: string
+ formType?: number
+ formId?: number
+ formCustomCreatePath?: string
+ formCustomViewPath?: string
+ suspensionState: number
+}
+
+/** 获取流程定义列表 */
+export function getProcessDefinitionList(params?: { suspensionState?: number }) {
+ return http.get('/bpm/process-definition/list', params)
+}
+
+/** 获取流程定义详情 */
+export function getProcessDefinition(id?: string, key?: string) {
+ return http.get('/bpm/process-definition/get', { id, key })
+}
diff --git a/src/api/bpm/oa/leave/index.ts b/src/api/bpm/oa/leave/index.ts
new file mode 100644
index 0000000..38ee117
--- /dev/null
+++ b/src/api/bpm/oa/leave/index.ts
@@ -0,0 +1,30 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 请假申请 */
+export interface Leave {
+ id: number
+ status: number
+ type: number
+ reason: string
+ processInstanceId: string
+ startTime: Date | any
+ endTime: Date | any
+ createTime: Date
+ startUserSelectAssignees?: Record
+}
+
+/** 创建请假申请 */
+export function createLeave(data: Partial) {
+ return http.post('/bpm/oa/leave/create', data)
+}
+
+/** 获得请假申请 */
+export function getLeave(id: number) {
+ return http.get(`/bpm/oa/leave/get?id=${id}`)
+}
+
+/** 获得请假申请分页 */
+export function getLeavePage(params: PageParam) {
+ return http.get>('/bpm/oa/leave/page', params)
+}
diff --git a/src/api/bpm/process-expression/index.ts b/src/api/bpm/process-expression/index.ts
new file mode 100644
index 0000000..ad8a6c7
--- /dev/null
+++ b/src/api/bpm/process-expression/index.ts
@@ -0,0 +1,38 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+const baseUrl = '/bpm/process-expression'
+
+/** 流程表达式 */
+export interface ProcessExpression {
+ id?: number
+ name: string // 表达式名字
+ status: number // 表达式状态
+ expression: string // 表达式
+ createTime?: Date
+}
+
+/** 获取流程表达式分页列表 */
+export function getProcessExpressionPage(params: PageParam) {
+ return http.get>(`${baseUrl}/page`, params)
+}
+
+/** 获取流程表达式详情 */
+export function getProcessExpression(id: number) {
+ return http.get(`${baseUrl}/get?id=${id}`)
+}
+
+/** 创建流程表达式 */
+export function createProcessExpression(data: ProcessExpression) {
+ return http.post(`${baseUrl}/create`, data)
+}
+
+/** 更新流程表达式 */
+export function updateProcessExpression(data: ProcessExpression) {
+ return http.put(`${baseUrl}/update`, data)
+}
+
+/** 删除流程表达式 */
+export function deleteProcessExpression(id: number) {
+ return http.delete(`${baseUrl}/delete?id=${id}`)
+}
diff --git a/src/api/bpm/process-listener/index.ts b/src/api/bpm/process-listener/index.ts
new file mode 100644
index 0000000..8a9b508
--- /dev/null
+++ b/src/api/bpm/process-listener/index.ts
@@ -0,0 +1,41 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+const baseUrl = '/bpm/process-listener'
+
+/** 流程监听器 */
+export interface ProcessListener {
+ id?: number
+ name: string // 监听器名字
+ type: string // 监听器类型
+ status: number // 监听器状态
+ event: string // 监听事件
+ valueType: string // 监听器值类型
+ value: string // 监听器值
+ createTime?: Date
+}
+
+/** 获取流程监听器分页列表 */
+export function getProcessListenerPage(params: PageParam) {
+ return http.get>(`${baseUrl}/page`, params)
+}
+
+/** 获取流程监听器详情 */
+export function getProcessListener(id: number) {
+ return http.get(`${baseUrl}/get?id=${id}`)
+}
+
+/** 创建流程监听器 */
+export function createProcessListener(data: ProcessListener) {
+ return http.post(`${baseUrl}/create`, data)
+}
+
+/** 更新流程监听器 */
+export function updateProcessListener(data: ProcessListener) {
+ return http.put(`${baseUrl}/update`, data)
+}
+
+/** 删除流程监听器 */
+export function deleteProcessListener(id: number) {
+ return http.delete(`${baseUrl}/delete?id=${id}`)
+}
diff --git a/src/api/bpm/processInstance/index.ts b/src/api/bpm/processInstance/index.ts
new file mode 100644
index 0000000..678acc5
--- /dev/null
+++ b/src/api/bpm/processInstance/index.ts
@@ -0,0 +1,141 @@
+import type { Task } from '@/api/bpm/task'
+import type { PageParam, PageResult } from '@/http/types'
+import type {
+ BpmCandidateStrategyEnum,
+ BpmNodeTypeEnum,
+} from '@/utils/constants'
+import { http } from '@/http/http'
+/** 流程实例用户信息 */
+export interface User {
+ id: number
+ nickname: string
+ avatar?: string
+ deptName?: string
+}
+
+/** 流程定义 */
+export interface ProcessDefinition {
+ id: string
+ key: string
+ name: string
+ description?: string
+ icon?: string
+ category: string
+ formType?: number
+ formId?: number
+ formCustomCreatePath?: string
+ formCustomViewPath?: string
+ suspensionState: number
+}
+
+/** 流程实例 */
+export interface ProcessInstance {
+ id: string
+ name: string
+ status: number
+ category?: string
+ categoryName?: string
+ createTime?: number
+ startTime?: number
+ endTime?: number
+ startUser?: User
+ businessKey?: string
+ processDefinition?: ProcessDefinition
+ summary?: {
+ key: string
+ value: string
+ }[]
+}
+
+/** 审批详情 */
+export interface ApprovalDetail {
+ processInstance: ProcessInstance
+ processDefinition: ProcessDefinition
+ activityNodes: ApprovalNodeInfo[]
+ todoTask: Task
+}
+
+/** 审批详情的节点信息 */
+export interface ApprovalNodeInfo {
+ candidateStrategy?: BpmCandidateStrategyEnum
+ candidateUsers?: User[]
+ endTime?: Date
+ id: string
+ name: string
+ nodeType: BpmNodeTypeEnum
+ startTime?: Date
+ status: number
+ processInstanceId?: string
+ tasks: ApprovalTaskInfo[]
+}
+
+/** 审批详情的节点的任务 */
+export interface ApprovalTaskInfo {
+ id: number
+ assigneeUser: User
+ ownerUser: User
+ reason: string
+ signPicUrl: string
+ status: number
+}
+
+/** 抄送流程实例 */
+export interface ProcessInstanceCopy {
+ id: string
+ processInstanceId: string
+ processInstanceName: string
+ startUser: User
+ createTime: number
+ summary?: {
+ key: string
+ value: string
+ }[]
+}
+
+/** 查询我发起的流程分页列表 */
+export function getProcessInstanceMyPage(params: PageParam) {
+ return http.get>('/bpm/process-instance/my-page', params)
+}
+
+/** 查询抄送我的流程分页列表 */
+export function getProcessInstanceCopyPage(params: PageParam) {
+ return http.get>('/bpm/process-instance/copy/page', params)
+}
+
+/** 查询流程实例详情 */
+export function getProcessInstance(id: string) {
+ return http.get(`/bpm/process-instance/get?id=${id}`)
+}
+
+/** 获取审批详情 */
+export function getApprovalDetail(params: { processDefinitionId?: string, processInstanceId?: string, activityId?: string, taskId?: string, processVariablesStr?: string }) {
+ return http.get('/bpm/process-instance/get-approval-detail', params)
+}
+
+/** 新增流程实例 */
+export function createProcessInstance(data: {
+ processDefinitionId: string
+ variables: Record
+}) {
+ return http.post('/bpm/process-instance/create', data)
+}
+
+/** 申请人取消流程实例 */
+export function cancelProcessInstanceByStartUser(id: string, reason: string) {
+ return http.delete('/bpm/process-instance/cancel-by-start-user', { id, reason })
+}
+
+/** 查询管理员流程实例分页 */
+export function getProcessInstanceManagerPage(params: PageParam) {
+ return http.get>('/bpm/process-instance/manager-page', params)
+}
+
+/** 管理员取消流程实例 */
+export function cancelProcessInstanceByAdmin(id: string, reason: string) {
+ return http.delete('/bpm/process-instance/cancel-by-admin', { id, reason })
+}
+
+/** 获取下一个节点审批人 */
+export function getNextApproveNodes(params) {
+ return http.get('/bpm/process-instance/get-next-approval-nodes', params)
+}
diff --git a/src/api/bpm/task/index.ts b/src/api/bpm/task/index.ts
new file mode 100644
index 0000000..41174f6
--- /dev/null
+++ b/src/api/bpm/task/index.ts
@@ -0,0 +1,102 @@
+import type { ProcessInstance } from '@/api/bpm/processInstance'
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 任务处理人 */
+// TODO @芋艿:貌似暂时不需要这个?!
+export interface TaskUser {
+ id: number
+ nickname: string
+ avatar?: string
+ deptName?: string
+}
+
+/** 操作按钮设置 */
+export interface OperationButtonSetting {
+ displayName: string // 按钮名称
+ enable: boolean // 是否启用
+}
+
+/** 流程任务 */
+export interface Task {
+ id: string
+ name: string
+ status: number
+ createTime: Date
+ endTime?: Date
+ durationInMillis?: number // 持续时间
+ reason?: string
+ assigneeUser?: TaskUser
+ ownerUser?: TaskUser
+ processInstanceId?: string // 流程实例 ID
+ processInstance: ProcessInstance
+ reasonRequire?: boolean // 是否填写审批意见
+ signEnable?: boolean // 是否需要签名
+ buttonsSetting?: Record // 按钮设置
+ children?: Task[] // 由加签生成,包含多层子任务
+}
+
+/** 查询待办任务分页列表 */
+export function getTaskTodoPage(params: PageParam) {
+ return http.get>('/bpm/task/todo-page', params)
+}
+
+/** 查询已办任务分页列表 */
+export function getTaskDonePage(params: PageParam) {
+ return http.get>('/bpm/task/done-page', params)
+}
+
+/** 审批通过 */
+export function approveTask(data: {
+ id: string
+ reason: string
+ signPicUrl?: string // 签名图片 URL
+ nextAssignees?: Record // 下一个节点审批人
+}) {
+ return http.put('/bpm/task/approve', data)
+}
+
+/** 审批拒绝 */
+export function rejectTask(data: { id: string, reason: string }) {
+ return http.put('/bpm/task/reject', data)
+}
+
+/** 根据流程实例 ID 查询任务列表 */
+export function getTaskListByProcessInstanceId(processInstanceId: string) {
+ return http.get(`/bpm/task/list-by-process-instance-id?processInstanceId=${processInstanceId}`)
+}
+
+/** 查询任务管理分页 */
+export function getTaskManagerPage(params: PageParam) {
+ return http.get>('/bpm/task/manager-page', params)
+}
+
+/** 委派任务 */
+export function delegateTask(data: { id: string, delegateUserId: string, reason: string }) {
+ return http.put('/bpm/task/delegate', data)
+}
+
+/** 转办任务 */
+export function transferTask(data: { id: string, assigneeUserId: string, reason: string }) {
+ return http.put('/bpm/task/transfer', data)
+}
+
+/** 退回任务 */
+export function returnTask(data: { id: string, targetTaskDefinitionKey: string, reason: string }) {
+ return http.put('/bpm/task/return', data)
+}
+
+/** 获取可退回的节点列表 */
+export function getTaskListByReturn(taskId: string) {
+ return http.get(`/bpm/task/list-by-return?id=${taskId}`)
+}
+
+/** 加签任务 */
+export function signCreateTask(data: { id: string, type: string, userIds: number[], reason: string }) {
+ return http.put('/bpm/task/create-sign', data)
+}
+
+/** 减签任务 */
+export function signDeleteTask(data: { id: string, reason: string }) {
+ return http.delete('/bpm/task/delete-sign', data)
+}
diff --git a/src/api/bpm/user-group/index.ts b/src/api/bpm/user-group/index.ts
new file mode 100644
index 0000000..188e54b
--- /dev/null
+++ b/src/api/bpm/user-group/index.ts
@@ -0,0 +1,45 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+const baseUrl = '/bpm/user-group'
+
+/** 用户组 */
+export interface UserGroup {
+ id?: number
+ name: string // 组名
+ description: string // 描述
+ userIds: number[] // 成员用户编号数组
+ status: number // 状态
+ remark: string // 备注
+ createTime?: Date
+}
+
+/** 获取用户组分页列表 */
+export function getUserGroupPage(params: PageParam) {
+ return http.get>(`${baseUrl}/page`, params)
+}
+
+/** 获取用户组详情 */
+export function getUserGroup(id: number) {
+ return http.get(`${baseUrl}/get?id=${id}`)
+}
+
+/** 创建用户组 */
+export function createUserGroup(data: UserGroup) {
+ return http.post(`${baseUrl}/create`, data)
+}
+
+/** 更新用户组 */
+export function updateUserGroup(data: UserGroup) {
+ return http.put(`${baseUrl}/update`, data)
+}
+
+/** 删除用户组 */
+export function deleteUserGroup(id: number) {
+ return http.delete(`${baseUrl}/delete?id=${id}`)
+}
+
+/** 获取用户组简单列表 */
+export function getUserGroupSimpleList() {
+ return http.get(`${baseUrl}/simple-list`)
+}
diff --git a/src/api/infra/api-access-log/index.ts b/src/api/infra/api-access-log/index.ts
new file mode 100644
index 0000000..86f93ef
--- /dev/null
+++ b/src/api/infra/api-access-log/index.ts
@@ -0,0 +1,36 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** API 访问日志信息 */
+export interface ApiAccessLog {
+ id: number
+ traceId: string
+ userId: number
+ userType: number
+ applicationName: string
+ requestMethod: string
+ requestParams: string
+ responseBody: string
+ requestUrl: string
+ userIp: string
+ userAgent: string
+ operateModule: string
+ operateName: string
+ operateType: number
+ beginTime: Date
+ endTime: Date
+ duration: number
+ resultCode: number
+ resultMsg: string
+ createTime: Date
+}
+
+/** 获取 API 访问日志分页列表 */
+export function getApiAccessLogPage(params: PageParam) {
+ return http.get>('/infra/api-access-log/page', params)
+}
+
+/** 获取 API 访问日志详情 */
+export function getApiAccessLog(id: number) {
+ return http.get(`/infra/api-access-log/get?id=${id}`)
+}
diff --git a/src/api/infra/api-error-log/index.ts b/src/api/infra/api-error-log/index.ts
new file mode 100644
index 0000000..6dc9cf0
--- /dev/null
+++ b/src/api/infra/api-error-log/index.ts
@@ -0,0 +1,45 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** API 错误日志信息 */
+export interface ApiErrorLog {
+ id: number
+ traceId: string
+ userId: number
+ userType: number
+ applicationName: string
+ requestMethod: string
+ requestParams: string
+ requestUrl: string
+ userIp: string
+ userAgent: string
+ exceptionTime: Date
+ exceptionName: string
+ exceptionMessage: string
+ exceptionRootCauseMessage: string
+ exceptionStackTrace: string
+ exceptionClassName: string
+ exceptionFileName: string
+ exceptionMethodName: string
+ exceptionLineNumber: number
+ processUserId: number
+ processStatus: number
+ processTime: Date
+ resultCode: number
+ createTime: Date
+}
+
+/** 获取 API 错误日志分页列表 */
+export function getApiErrorLogPage(params: PageParam) {
+ return http.get>('/infra/api-error-log/page', params)
+}
+
+/** 获取 API 错误日志详情 */
+export function getApiErrorLog(id: number) {
+ return http.get(`/infra/api-error-log/get?id=${id}`)
+}
+
+/** 更新 API 错误日志的处理状态 */
+export function updateApiErrorLogStatus(id: number, processStatus: number) {
+ return http.put(`/infra/api-error-log/update-status?id=${id}&processStatus=${processStatus}`)
+}
diff --git a/src/api/infra/config/index.ts b/src/api/infra/config/index.ts
new file mode 100644
index 0000000..159708d
--- /dev/null
+++ b/src/api/infra/config/index.ts
@@ -0,0 +1,45 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 参数配置信息 */
+export interface Config {
+ id?: number
+ category: string
+ name: string
+ key: string
+ value: string
+ type: number
+ visible: boolean
+ remark: string
+ createTime?: Date
+}
+
+/** 获取参数配置分页列表 */
+export function getConfigPage(params: PageParam) {
+ return http.get>('/infra/config/page', params)
+}
+
+/** 获取参数配置详情 */
+export function getConfig(id: number) {
+ return http.get(`/infra/config/get?id=${id}`)
+}
+
+/** 根据参数键名查询参数值 */
+export function getConfigKey(configKey: string) {
+ return http.get(`/infra/config/get-value-by-key?key=${configKey}`)
+}
+
+/** 创建参数配置 */
+export function createConfig(data: Config) {
+ return http.post('/infra/config/create', data)
+}
+
+/** 更新参数配置 */
+export function updateConfig(data: Config) {
+ return http.put('/infra/config/update', data)
+}
+
+/** 删除参数配置 */
+export function deleteConfig(id: number) {
+ return http.delete(`/infra/config/delete?id=${id}`)
+}
diff --git a/src/api/infra/data-source-config/index.ts b/src/api/infra/data-source-config/index.ts
new file mode 100644
index 0000000..eca2eb5
--- /dev/null
+++ b/src/api/infra/data-source-config/index.ts
@@ -0,0 +1,36 @@
+import { http } from '@/http/http'
+
+/** 数据源配置信息 */
+export interface DataSourceConfig {
+ id?: number
+ name: string
+ url: string
+ username: string
+ password: string
+ createTime?: Date
+}
+
+/** 获取数据源配置列表(无分页) */
+export function getDataSourceConfigList() {
+ return http.get('/infra/data-source-config/list')
+}
+
+/** 获取数据源配置详情 */
+export function getDataSourceConfig(id: number) {
+ return http.get(`/infra/data-source-config/get?id=${id}`)
+}
+
+/** 创建数据源配置 */
+export function createDataSourceConfig(data: DataSourceConfig) {
+ return http.post('/infra/data-source-config/create', data)
+}
+
+/** 更新数据源配置 */
+export function updateDataSourceConfig(data: DataSourceConfig) {
+ return http.put('/infra/data-source-config/update', data)
+}
+
+/** 删除数据源配置 */
+export function deleteDataSourceConfig(id: number) {
+ return http.delete(`/infra/data-source-config/delete?id=${id}`)
+}
diff --git a/src/api/infra/file/config/index.ts b/src/api/infra/file/config/index.ts
new file mode 100644
index 0000000..29626de
--- /dev/null
+++ b/src/api/infra/file/config/index.ts
@@ -0,0 +1,67 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 文件客户端配置 */
+export interface FileClientConfig {
+ basePath?: string
+ host?: string
+ port?: number
+ username?: string
+ password?: string
+ mode?: string
+ endpoint?: string
+ bucket?: string
+ accessKey?: string
+ accessSecret?: string
+ enablePathStyleAccess?: boolean
+ enablePublicAccess?: boolean
+ region?: string
+ domain?: string
+}
+
+/** 文件配置信息 */
+export interface FileConfig {
+ id?: number
+ name: string
+ storage?: number
+ master?: boolean
+ visible?: boolean
+ config?: FileClientConfig
+ remark?: string
+ createTime?: Date
+}
+
+/** 查询文件配置分页列表 */
+export function getFileConfigPage(params: PageParam) {
+ return http.get>('/infra/file-config/page', params)
+}
+
+/** 查询文件配置详情 */
+export function getFileConfig(id: number) {
+ return http.get(`/infra/file-config/get?id=${id}`)
+}
+
+/** 新增文件配置 */
+export function createFileConfig(data: FileConfig) {
+ return http.post('/infra/file-config/create', data)
+}
+
+/** 修改文件配置 */
+export function updateFileConfig(data: FileConfig) {
+ return http.put('/infra/file-config/update', data)
+}
+
+/** 删除文件配置 */
+export function deleteFileConfig(id: number) {
+ return http.delete(`/infra/file-config/delete?id=${id}`)
+}
+
+/** 更新文件配置为主配置 */
+export function updateFileConfigMaster(id: number) {
+ return http.put(`/infra/file-config/update-master?id=${id}`)
+}
+
+/** 测试文件配置 */
+export function testFileConfig(id: number) {
+ return http.get(`/infra/file-config/test?id=${id}`)
+}
diff --git a/src/api/infra/file/index.ts b/src/api/infra/file/index.ts
new file mode 100644
index 0000000..fa51247
--- /dev/null
+++ b/src/api/infra/file/index.ts
@@ -0,0 +1,97 @@
+import { useToast } from 'wot-design-uni'
+import { http } from '@/http/http'
+import { useTokenStore } from '@/store/token'
+import { useUserStore } from '@/store/user'
+
+/** 文件信息 */
+export interface FileVO {
+ id?: number
+ configId?: number
+ path: string
+ name?: string
+ url?: string
+ size?: number
+ type?: string
+ createTime?: Date
+}
+
+/** 文件预签名信息 */
+export interface FilePresignedUrlRespVO {
+ configId: number // 配置编号
+ uploadUrl: string // 文件上传 URL
+ url: string // 文件访问 URL
+ path: string // 文件路径
+}
+
+/** 创建文件请求 */
+export interface FileCreateReqVO {
+ configId: number
+ url: string
+ path: string
+ name: string
+ type?: string
+ size?: number
+}
+
+/** 获取文件预签名地址 */
+export function getFilePresignedUrl(name: string, directory?: string) {
+ return http.get('/infra/file/presigned-url', { name, directory })
+}
+
+/** 创建文件记录 */
+export function createFile(data: FileCreateReqVO) {
+ return http.post('/infra/file/create', data)
+}
+
+/** 获取文件详情 */
+export function getFile(id: number) {
+ return http.get(`/infra/file/get?id=${id}`)
+}
+
+/** 删除文件 */
+export function deleteFile(id: number) {
+ return http.delete(`/infra/file/delete?id=${id}`)
+}
+
+/**
+ * 上传文件到后端
+ *
+ * @param filePath 本地文件路径
+ * @param directory 目录(可选)
+ * @returns 文件访问 URL
+ */
+export function uploadFile(filePath: string, directory?: string): Promise {
+ const tokenStore = useTokenStore()
+ const userStore = useUserStore()
+ return new Promise((resolve, reject) => {
+ uni.uploadFile({
+ url: `${import.meta.env.VITE_SERVER_BASEURL}/infra/file/upload`,
+ filePath,
+ name: 'file',
+ header: {
+ 'Accept': '*/*',
+ 'tenant-id': userStore.tenantId,
+ 'Authorization': `Bearer ${tokenStore.validToken}`,
+ },
+ formData: directory ? { directory } : undefined,
+ success: (res) => {
+ if (res.statusCode === 200) {
+ const result = JSON.parse(res.data)
+ if (result.code === 0) {
+ resolve(result.data)
+ } else {
+ const toast = useToast()
+ toast.show(result.msg || '上传失败')
+ reject(new Error(result.msg || '上传失败'))
+ }
+ } else {
+ reject(new Error('上传失败'))
+ }
+ },
+ fail: (err) => {
+ console.error('上传失败:', err)
+ reject(err)
+ },
+ })
+ })
+}
diff --git a/src/api/infra/job/index.ts b/src/api/infra/job/index.ts
new file mode 100644
index 0000000..6010bed
--- /dev/null
+++ b/src/api/infra/job/index.ts
@@ -0,0 +1,60 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+// TODO @AI:不用 baseUrl 方式
+const baseUrl = '/infra/job'
+
+/** 定时任务信息 */
+export interface Job {
+ id?: number
+ name: string
+ status: number
+ handlerName: string
+ handlerParam: string
+ cronExpression: string
+ retryCount: number
+ retryInterval: number
+ monitorTimeout: number
+ createTime?: Date
+ nextTimes?: Date[]
+}
+
+/** 获取定时任务分页列表 */
+export function getJobPage(params: PageParam) {
+ return http.get>(`${baseUrl}/page`, params)
+}
+
+/** 获取定时任务详情 */
+export function getJob(id: number) {
+ return http.get(`${baseUrl}/get?id=${id}`)
+}
+
+/** 创建定时任务 */
+export function createJob(data: Job) {
+ return http.post(`${baseUrl}/create`, data)
+}
+
+/** 更新定时任务 */
+export function updateJob(data: Job) {
+ return http.put(`${baseUrl}/update`, data)
+}
+
+/** 删除定时任务 */
+export function deleteJob(id: number) {
+ return http.delete(`${baseUrl}/delete?id=${id}`)
+}
+
+/** 更新定时任务状态 */
+export function updateJobStatus(id: number, status: number) {
+ return http.put(`${baseUrl}/update-status`, { id, status })
+}
+
+/** 立即执行一次定时任务 */
+export function runJob(id: number) {
+ return http.put(`${baseUrl}/trigger?id=${id}`)
+}
+
+/** 获取定时任务的下 n 次执行时间 */
+export function getJobNextTimes(id: number) {
+ return http.get(`${baseUrl}/get_next_times?id=${id}`)
+}
diff --git a/src/api/infra/job/log/index.ts b/src/api/infra/job/log/index.ts
new file mode 100644
index 0000000..01cba2b
--- /dev/null
+++ b/src/api/infra/job/log/index.ts
@@ -0,0 +1,31 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+// TODO @AI:不用 baseUrl 方式
+const baseUrl = '/infra/job-log'
+
+/** 定时任务日志信息 */
+export interface JobLog {
+ id?: number
+ jobId: number
+ handlerName: string
+ handlerParam: string
+ cronExpression: string
+ executeIndex: string
+ beginTime: Date
+ endTime: Date
+ duration: string
+ status: number
+ createTime?: string
+ result: string
+}
+
+/** 获取定时任务日志分页列表 */
+export function getJobLogPage(params: PageParam) {
+ return http.get>(`${baseUrl}/page`, params)
+}
+
+/** 获取定时任务日志详情 */
+export function getJobLog(id: number) {
+ return http.get(`${baseUrl}/get?id=${id}`)
+}
diff --git a/src/api/login.ts b/src/api/login.ts
new file mode 100644
index 0000000..2d5404a
--- /dev/null
+++ b/src/api/login.ts
@@ -0,0 +1,148 @@
+import type {
+ AuthPermissionInfo,
+ IAuthLoginRes,
+ ICaptcha,
+ IDoubleTokenRes,
+} from './types/login'
+import { http } from '@/http/http'
+
+/**
+ * 登录表单
+ */
+export interface ILoginForm {
+ type: 'username' | 'register' | 'sms'
+ username?: string
+ password?: string
+ nickname?: string
+ captchaVerification?: string
+ mobile?: string
+ code?: string
+}
+
+/** 账号密码登录 Request VO */
+export interface AuthLoginReqVO {
+ password?: string
+ username?: string
+ captchaVerification?: string
+ // 绑定社交登录时,需要传递如下参数
+ socialType?: number
+ socialCode?: string
+ socialState?: string
+}
+
+/** 注册 Request VO */
+export interface AuthRegisterReqVO {
+ username: string
+ password: string
+ captchaVerification: string
+}
+
+/** 短信登录 Request VO */
+export interface AuthSmsLoginReqVO {
+ mobile: string
+ code: string
+}
+
+/** 发送短信验证码 Request VO */
+export interface AuthSmsSendReqVO {
+ mobile: string
+ scene: number
+}
+
+/** 租户信息 */
+export interface TenantVO {
+ id: number
+ name: string
+}
+
+/** 重置密码 Request VO */
+export interface AuthResetPasswordReqVO {
+ mobile: string
+ code: string
+ password: string
+}
+
+/** 获取验证码 */
+export function getCode(data: any) {
+ return http.post('/system/captcha/get', data, null, null, { original: true })
+}
+
+/** 校验验证码 */
+export function checkCaptcha(data: any) {
+ return http.post('/system/captcha/check', data, null, null, { original: true })
+}
+
+/** 使用账号密码登录 */
+export function login(data: AuthLoginReqVO) {
+ return http.post('/system/auth/login', data)
+}
+
+/** 注册用户 */
+export function register(data: AuthRegisterReqVO) {
+ return http.post('/system/auth/register', data)
+}
+
+/** 短信登录 */
+export function smsLogin(data: AuthSmsLoginReqVO) {
+ return http.post('/system/auth/sms-login', data)
+}
+
+/** 发送短信验证码 */
+export function sendSmsCode(data: AuthSmsSendReqVO) {
+ return http.post('/system/auth/send-sms-code', data)
+}
+
+/** 获取租户简单列表 */
+export function getTenantSimpleList() {
+ return http.get('/system/tenant/simple-list')
+}
+
+/** 根据租户域名获取租户信息 */
+export function getTenantByWebsite(website: string) {
+ return http.get(`/system/tenant/get-by-website?website=${website}`)
+}
+
+/** 通过短信重置密码 */
+export function smsResetPassword(data: AuthResetPasswordReqVO) {
+ return http.post('/system/auth/reset-password', data)
+}
+
+/** 刷新token */
+export function refreshToken(refreshToken: string) {
+ return http.post(`/system/auth/refresh-token?refreshToken=${refreshToken}`)
+}
+
+/** 获取权限信息 */
+export function getAuthPermissionInfo() {
+ return http.get('/system/auth/get-permission-info')
+}
+
+/** 退出登录 */
+export function logout() {
+ return http.post('/system/auth/logout')
+}
+
+// TODO @芋艿:三方登录
+/**
+ * 获取微信登录凭证
+ * @returns Promise 包含微信登录凭证(code)
+ */
+export function getWxCode() {
+ return new Promise((resolve, reject) => {
+ uni.login({
+ provider: 'weixin',
+ success: res => resolve(res),
+ fail: err => reject(new Error(err)),
+ })
+ })
+}
+
+// TODO @芋艿:三方登录
+/**
+ * 微信登录
+ * @param params 微信登录参数,包含code
+ * @returns Promise 包含登录结果
+ */
+export function wxLogin(data: { code: string }) {
+ return http.post('/auth/wxLogin', data)
+}
diff --git a/src/api/system/area/index.ts b/src/api/system/area/index.ts
new file mode 100644
index 0000000..3193d27
--- /dev/null
+++ b/src/api/system/area/index.ts
@@ -0,0 +1,19 @@
+import { http } from '@/http/http'
+
+/** 地区信息 */
+export interface Area {
+ id: number
+ name: string
+ parentId?: number
+ children?: Area[]
+}
+
+/** 获得地区树 */
+export function getAreaTree() {
+ return http.get('/system/area/tree')
+}
+
+/** 获得 IP 对应的地区名 */
+export function getAreaByIp(ip: string) {
+ return http.get(`/system/area/get-by-ip?ip=${ip}`)
+}
diff --git a/src/api/system/dept/index.ts b/src/api/system/dept/index.ts
new file mode 100644
index 0000000..5640cf7
--- /dev/null
+++ b/src/api/system/dept/index.ts
@@ -0,0 +1,45 @@
+import { http } from '@/http/http'
+
+/** 部门信息 */
+export interface Dept {
+ id?: number
+ name: string
+ parentId: number
+ status: number
+ sort: number
+ leaderUserId?: number
+ phone?: string
+ email?: string
+ createTime?: Date
+ children?: Dept[]
+}
+
+/** 获取部门列表 */
+export function getDeptList(params?: { name?: string, status?: number }) {
+ return http.get('/system/dept/list', params)
+}
+
+/** 获取部门精简列表 */
+export function getSimpleDeptList() {
+ return http.get('/system/dept/simple-list')
+}
+
+/** 获取部门详情 */
+export function getDept(id: number) {
+ return http.get(`/system/dept/get?id=${id}`)
+}
+
+/** 创建部门 */
+export function createDept(data: Dept) {
+ return http.post('/system/dept/create', data)
+}
+
+/** 更新部门 */
+export function updateDept(data: Dept) {
+ return http.put('/system/dept/update', data)
+}
+
+/** 删除部门 */
+export function deleteDept(id: number) {
+ return http.delete(`/system/dept/delete?id=${id}`)
+}
diff --git a/src/api/system/dict/data/index.ts b/src/api/system/dict/data/index.ts
new file mode 100644
index 0000000..609e285
--- /dev/null
+++ b/src/api/system/dict/data/index.ts
@@ -0,0 +1,46 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 字典数据 */
+export interface DictData {
+ id?: number
+ dictType: string
+ label: string
+ value: string
+ colorType?: string
+ cssClass?: string
+ sort?: number
+ status: number
+ remark?: string
+ createTime?: Date
+}
+
+/** 查询字典数据(精简)列表 */
+export function getSimpleDictDataList() {
+ return http.get('/system/dict-data/simple-list')
+}
+
+/** 查询字典数据分页列表 */
+export function getDictDataPage(params: PageParam) {
+ return http.get>('/system/dict-data/page', params)
+}
+
+/** 查询字典数据详情 */
+export function getDictData(id: number) {
+ return http.get(`/system/dict-data/get?id=${id}`)
+}
+
+/** 新增字典数据 */
+export function createDictData(data: DictData) {
+ return http.post('/system/dict-data/create', data)
+}
+
+/** 修改字典数据 */
+export function updateDictData(data: DictData) {
+ return http.put('/system/dict-data/update', data)
+}
+
+/** 删除字典数据 */
+export function deleteDictData(id: number) {
+ return http.delete(`/system/dict-data/delete?id=${id}`)
+}
diff --git a/src/api/system/dict/type/index.ts b/src/api/system/dict/type/index.ts
new file mode 100644
index 0000000..c9dbce8
--- /dev/null
+++ b/src/api/system/dict/type/index.ts
@@ -0,0 +1,42 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 字典类型 */
+export interface DictType {
+ id?: number
+ name: string
+ type: string
+ status: number
+ remark?: string
+ createTime?: Date
+}
+
+/** 查询字典类型(精简)列表 */
+export function getSimpleDictTypeList() {
+ return http.get('/system/dict-type/list-all-simple')
+}
+
+/** 查询字典类型分页列表 */
+export function getDictTypePage(params: PageParam) {
+ return http.get>('/system/dict-type/page', params)
+}
+
+/** 查询字典类型详情 */
+export function getDictType(id: number) {
+ return http.get(`/system/dict-type/get?id=${id}`)
+}
+
+/** 新增字典类型 */
+export function createDictType(data: DictType) {
+ return http.post('/system/dict-type/create', data)
+}
+
+/** 修改字典类型 */
+export function updateDictType(data: DictType) {
+ return http.put('/system/dict-type/update', data)
+}
+
+/** 删除字典类型 */
+export function deleteDictType(id: number) {
+ return http.delete(`/system/dict-type/delete?id=${id}`)
+}
diff --git a/src/api/system/login-log/index.ts b/src/api/system/login-log/index.ts
new file mode 100644
index 0000000..2b9cf70
--- /dev/null
+++ b/src/api/system/login-log/index.ts
@@ -0,0 +1,26 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 登录日志信息 */
+export interface LoginLog {
+ id?: number
+ traceId?: string
+ userId?: number
+ userType?: number
+ logType?: number
+ username?: string
+ userIp?: string
+ userAgent?: string
+ result?: number
+ createTime?: Date
+}
+
+/** 获取登录日志分页列表 */
+export function getLoginLogPage(params: PageParam) {
+ return http.get>('/system/login-log/page', params)
+}
+
+/** 获取登录日志详情 */
+export function getLoginLog(id: number) {
+ return http.get(`/system/login-log/get?id=${id}`)
+}
diff --git a/src/api/system/mail/account/index.ts b/src/api/system/mail/account/index.ts
new file mode 100644
index 0000000..3c1117b
--- /dev/null
+++ b/src/api/system/mail/account/index.ts
@@ -0,0 +1,45 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 邮箱账号信息 */
+export interface MailAccount {
+ id?: number
+ mail: string
+ username: string
+ password?: string
+ host: string
+ port: number
+ sslEnable: boolean
+ starttlsEnable: boolean
+ createTime?: string
+}
+
+/** 获取邮箱账号分页列表 */
+export function getMailAccountPage(params: PageParam) {
+ return http.get>('/system/mail-account/page', params)
+}
+
+/** 获取邮箱账号(精简)列表 */
+export function getSimpleMailAccountList() {
+ return http.get('/system/mail-account/simple-list')
+}
+
+/** 获取邮箱账号详情 */
+export function getMailAccount(id: number) {
+ return http.get(`/system/mail-account/get?id=${id}`)
+}
+
+/** 创建邮箱账号 */
+export function createMailAccount(data: MailAccount) {
+ return http.post('/system/mail-account/create', data)
+}
+
+/** 更新邮箱账号 */
+export function updateMailAccount(data: MailAccount) {
+ return http.put('/system/mail-account/update', data)
+}
+
+/** 删除邮箱账号 */
+export function deleteMailAccount(id: number) {
+ return http.delete(`/system/mail-account/delete?id=${id}`)
+}
diff --git a/src/api/system/mail/log/index.ts b/src/api/system/mail/log/index.ts
new file mode 100644
index 0000000..dbe23da
--- /dev/null
+++ b/src/api/system/mail/log/index.ts
@@ -0,0 +1,34 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 邮件日志信息 */
+export interface MailLog {
+ id?: number
+ userId?: number
+ userType?: number
+ templateId?: number
+ templateCode?: string
+ templateTitle?: string
+ templateContent?: string
+ templateParams?: Record
+ accountId?: number
+ fromMail?: string
+ toMails?: string[]
+ ccMails?: string[]
+ bccMails?: string[]
+ sendStatus?: number
+ sendTime?: string
+ sendMessageId?: string
+ sendException?: string
+ createTime?: string
+}
+
+/** 获取邮件日志分页列表 */
+export function getMailLogPage(params: PageParam) {
+ return http.get>('/system/mail-log/page', params)
+}
+
+/** 获取邮件日志详情 */
+export function getMailLog(id: number) {
+ return http.get(`/system/mail-log/get?id=${id}`)
+}
diff --git a/src/api/system/mail/template/index.ts b/src/api/system/mail/template/index.ts
new file mode 100644
index 0000000..70c2cb7
--- /dev/null
+++ b/src/api/system/mail/template/index.ts
@@ -0,0 +1,56 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 邮件模板信息 */
+export interface MailTemplate {
+ id?: number
+ name: string
+ code: string
+ accountId?: number
+ nickname?: string
+ title: string
+ content: string
+ status: number
+ remark?: string
+ params?: string[]
+ createTime?: string
+}
+
+/** 发送邮件请求 */
+export interface MailSendReqVO {
+ templateCode: string
+ templateParams: Record
+ toMails: string[]
+ ccMails?: string[]
+ bccMails?: string[]
+}
+
+/** 获取邮件模板分页列表 */
+export function getMailTemplatePage(params: PageParam) {
+ return http.get>('/system/mail-template/page', params)
+}
+
+/** 获取邮件模板详情 */
+export function getMailTemplate(id: number) {
+ return http.get(`/system/mail-template/get?id=${id}`)
+}
+
+/** 创建邮件模板 */
+export function createMailTemplate(data: MailTemplate) {
+ return http.post('/system/mail-template/create', data)
+}
+
+/** 更新邮件模板 */
+export function updateMailTemplate(data: MailTemplate) {
+ return http.put('/system/mail-template/update', data)
+}
+
+/** 删除邮件模板 */
+export function deleteMailTemplate(id: number) {
+ return http.delete(`/system/mail-template/delete?id=${id}`)
+}
+
+/** 发送邮件 */
+export function sendMail(data: MailSendReqVO) {
+ return http.post('/system/mail-template/send-mail', data)
+}
diff --git a/src/api/system/menu/index.ts b/src/api/system/menu/index.ts
new file mode 100644
index 0000000..b22b7f0
--- /dev/null
+++ b/src/api/system/menu/index.ts
@@ -0,0 +1,51 @@
+import { http } from '@/http/http'
+
+/** 菜单信息 */
+export interface Menu {
+ id?: number
+ name: string
+ permission: string
+ type: number
+ sort: number
+ parentId: number
+ path: string
+ icon: string
+ component: string
+ componentName?: string
+ status: number
+ visible: boolean
+ keepAlive: boolean
+ alwaysShow?: boolean
+ createTime?: Date
+ children?: Menu[]
+}
+
+/** 获取菜单列表 */
+export function getMenuList(params?: { name?: string, status?: number }) {
+ return http.get