Explorar o código

feat: 把 docs 仓库移动到本仓库

Burt hai 1 ano
pai
achega
b2bf1efef3
Modificáronse 100 ficheiros con 2911 adicións e 0 borrados
  1. 3 0
      .gitignore
  2. 23 0
      docs/.vitepress/components/BuildInfo.vue
  3. 220 0
      docs/.vitepress/config.mts
  4. 26 0
      docs/.vitepress/layouts/Default.vue
  5. 50 0
      docs/.vitepress/theme/components/HomeStar.vue
  6. 21 0
      docs/.vitepress/theme/components/NavBarTitleAfter.vue
  7. 84 0
      docs/.vitepress/theme/custom.css
  8. 22 0
      docs/.vitepress/theme/index.ts
  9. BIN=BIN
      docs/advanced/me/image-2.png
  10. BIN=BIN
      docs/advanced/me/image-3.png
  11. 30 0
      docs/advanced/me/me.md
  12. BIN=BIN
      docs/advanced/me/screenshots/pay-wx.png
  13. BIN=BIN
      docs/advanced/me/screenshots/wx-gzh.png
  14. BIN=BIN
      docs/advanced/me/screenshots/wx-me.png
  15. BIN=BIN
      docs/advanced/rewards/assets/group-qq.jpg
  16. BIN=BIN
      docs/advanced/rewards/assets/group-wx.jpg
  17. BIN=BIN
      docs/advanced/rewards/assets/pay-1.png
  18. BIN=BIN
      docs/advanced/rewards/assets/pay-2.png
  19. BIN=BIN
      docs/advanced/rewards/assets/pay-ali.png
  20. BIN=BIN
      docs/advanced/rewards/assets/pay-w-5.png
  21. BIN=BIN
      docs/advanced/rewards/assets/pay-wx-10.png
  22. BIN=BIN
      docs/advanced/rewards/assets/pay-wx-2.png
  23. BIN=BIN
      docs/advanced/rewards/assets/pay-wx-5-doc.png
  24. BIN=BIN
      docs/advanced/rewards/assets/pay-wx-5.png
  25. BIN=BIN
      docs/advanced/rewards/assets/pay-wx.png
  26. 8 0
      docs/advanced/rewards/rewards.md
  27. 61 0
      docs/advanced/sponsor/sponsor.md
  28. BIN=BIN
      docs/advanced/wechat/image-1.png
  29. BIN=BIN
      docs/advanced/wechat/image-2.png
  30. BIN=BIN
      docs/advanced/wechat/image.png
  31. 14 0
      docs/advanced/wechat/wechat.md
  32. 196 0
      docs/base/1-introduction.md
  33. 163 0
      docs/base/10-i18n.md
  34. 111 0
      docs/base/11-build.md
  35. 89 0
      docs/base/12-env.md
  36. 67 0
      docs/base/13-hbx.md
  37. 116 0
      docs/base/14-faq.md
  38. 267 0
      docs/base/15-faq.md
  39. 119 0
      docs/base/2-start.md
  40. 25 0
      docs/base/20-best.md
  41. 158 0
      docs/base/3-plugin.md
  42. 220 0
      docs/base/4-style.md
  43. 189 0
      docs/base/5-icons.md
  44. 181 0
      docs/base/6-svg.md
  45. 120 0
      docs/base/7-ui.md
  46. 163 0
      docs/base/8-request.md
  47. 165 0
      docs/base/9-state.md
  48. BIN=BIN
      docs/base/assets/1-1.png
  49. BIN=BIN
      docs/base/assets/10-1.png
  50. BIN=BIN
      docs/base/assets/10-2.png
  51. BIN=BIN
      docs/base/assets/10-3.png
  52. BIN=BIN
      docs/base/assets/10-android.mp4
  53. BIN=BIN
      docs/base/assets/10-ios.mp4
  54. BIN=BIN
      docs/base/assets/11-1.png
  55. BIN=BIN
      docs/base/assets/11-10.png
  56. BIN=BIN
      docs/base/assets/11-100.png
  57. BIN=BIN
      docs/base/assets/11-11.png
  58. BIN=BIN
      docs/base/assets/11-12.png
  59. BIN=BIN
      docs/base/assets/11-13.png
  60. BIN=BIN
      docs/base/assets/11-2.png
  61. BIN=BIN
      docs/base/assets/11-3.png
  62. BIN=BIN
      docs/base/assets/11-4.png
  63. BIN=BIN
      docs/base/assets/11-5.png
  64. BIN=BIN
      docs/base/assets/11-6.png
  65. BIN=BIN
      docs/base/assets/11-7.png
  66. BIN=BIN
      docs/base/assets/11-8.png
  67. BIN=BIN
      docs/base/assets/11-9.png
  68. BIN=BIN
      docs/base/assets/13-1.png
  69. BIN=BIN
      docs/base/assets/13-2.png
  70. BIN=BIN
      docs/base/assets/13-3.png
  71. BIN=BIN
      docs/base/assets/13-4.png
  72. BIN=BIN
      docs/base/assets/13-5.png
  73. BIN=BIN
      docs/base/assets/13-6.png
  74. BIN=BIN
      docs/base/assets/13-7.png
  75. BIN=BIN
      docs/base/assets/13-8.png
  76. BIN=BIN
      docs/base/assets/14-1.png
  77. BIN=BIN
      docs/base/assets/14-2.png
  78. BIN=BIN
      docs/base/assets/14-3.png
  79. BIN=BIN
      docs/base/assets/14-4.png
  80. BIN=BIN
      docs/base/assets/14-5.png
  81. BIN=BIN
      docs/base/assets/14-6.png
  82. BIN=BIN
      docs/base/assets/15-1.png
  83. BIN=BIN
      docs/base/assets/15-2.png
  84. BIN=BIN
      docs/base/assets/15-3.png
  85. BIN=BIN
      docs/base/assets/15-4.png
  86. BIN=BIN
      docs/base/assets/15-5.png
  87. BIN=BIN
      docs/base/assets/15-6.png
  88. BIN=BIN
      docs/base/assets/2-1.png
  89. BIN=BIN
      docs/base/assets/2-2.png
  90. BIN=BIN
      docs/base/assets/2-3.png
  91. BIN=BIN
      docs/base/assets/2-4.gif
  92. BIN=BIN
      docs/base/assets/3-1.png
  93. BIN=BIN
      docs/base/assets/4-1.png
  94. BIN=BIN
      docs/base/assets/4-2.png
  95. BIN=BIN
      docs/base/assets/4-3.png
  96. BIN=BIN
      docs/base/assets/4-4.png
  97. BIN=BIN
      docs/base/assets/4-5.png
  98. BIN=BIN
      docs/base/assets/5-1.png
  99. BIN=BIN
      docs/base/assets/5-10.png
  100. 0 0
      docs/base/assets/5-100.png

+ 3 - 0
.gitignore

@@ -24,6 +24,9 @@ dist
 .stylelintcache
 .stylelintcache
 .eslintcache
 .eslintcache
 
 
+docs/.vitepress/dist
+docs/.vitepress/cache
+
 # lock 文件还是不要了,我主要的版本写死就好了
 # lock 文件还是不要了,我主要的版本写死就好了
 # pnpm-lock.yaml
 # pnpm-lock.yaml
 # package-lock.json
 # package-lock.json

+ 23 - 0
docs/.vitepress/components/BuildInfo.vue

@@ -0,0 +1,23 @@
+<!-- .vitepress/components/BuildInfo.vue -->
+<template>
+  <div class="build-info" :data-build-time="buildTime" :data-version="version">
+    <p>构建时间: {{ buildTime }}</p>
+    <p>版本号: {{ version }}</p>
+  </div>
+</template>
+
+<script setup>
+import { inject } from 'vue'
+
+const buildTime = inject('buildTime')
+const version = inject('version')
+</script>
+
+<style scoped>
+.build-info {
+  padding: 10px;
+  margin-top: 20px;
+  text-align: center;
+  background-color: #f8f8f8;
+}
+</style>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 220 - 0
docs/.vitepress/config.mts


+ 26 - 0
docs/.vitepress/layouts/Default.vue

@@ -0,0 +1,26 @@
+<!-- .vitepress/layouts/Default.vue -->
+<template>
+  <div class="custom-layout">
+    <VPLayout>
+      <template #layout-bottom>
+        <footer class="footer">
+          <p>© 2024 菲鸽科技</p>
+          <p><a href="https://beian.miit.gov.cn" target="_blank">粤ICP备2024160998号</a></p>
+          <BuildInfo />
+        </footer>
+      </template>
+    </VPLayout>
+  </div>
+</template>
+
+<script setup>
+import VPLayout from '@theme-default/Layout.vue'
+</script>
+
+<style scoped>
+.footer {
+  padding: 20px;
+  text-align: center;
+  background-color: #f8f8f8;
+}
+</style>

+ 50 - 0
docs/.vitepress/theme/components/HomeStar.vue

@@ -0,0 +1,50 @@
+<template>
+  <p class="home-star">
+    <a href="https://github.com/codercup/unibest">
+      <img
+        alt="GitHub Repo stars"
+        src="https://img.shields.io/github/stars/codercup/unibest?logo=github&color=%234d80f0&link=https%3A%2F%2Fgithub.com%2Fcodercup%2Funibest"
+      />
+    </a>
+    <a href="https://github.com/feige996/unibest">
+      <img
+        alt="GitHub Repo stars"
+        src="https://img.shields.io/github/stars/feige996/unibest?logo=github&color=%234d80f0&link=https%3A%2F%2Fgithub.com%2Ffeige996%2Funibest"
+      />
+    </a>
+
+    <a href="https://gitee.com/codercup/unibest/stargazers">
+      <img src="https://gitee.com/codercup/unibest/badge/star.svg?theme=gray" alt="star" />
+    </a>
+
+    <!-- <a href="https://gitee.com/feige996/unibest/stargazers">
+      <img src="https://gitee.com/feige996/unibest/badge/star.svg?theme=gray" alt="star" />
+    </a> -->
+
+    <a href="https://github.com/feige996/unibest">
+      <img alt="GitHub" src="https://img.shields.io/github/license/feige996/unibest?logo=github" />
+    </a>
+
+    <a href="https://www.npmjs.com/package/create-unibest">
+      <img
+        alt="npm"
+        src="https://img.shields.io/npm/dw/create-unibest?logo=npm&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fcreate-unibest"
+      />
+    </a>
+
+    <!-- <a href="https://www.npmjs.com/package/create-unibest">
+      <img src="https://img.shields.io/npm/dt/create-unibest?style=flat-square" />
+    </a> -->
+  </p>
+</template>
+
+<style>
+.home-star {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  align-items: center;
+  justify-content: center;
+  padding-top: 24px;
+}
+</style>

+ 21 - 0
docs/.vitepress/theme/components/NavBarTitleAfter.vue

@@ -0,0 +1,21 @@
+<script setup lang="ts">
+// TODO: 从远程地址获取版本号
+const version = '2.5.0'
+</script>
+
+<template>
+  <span
+    style="
+      display: inline-block;
+      padding: 0 4px;
+      margin-left: 4px;
+      font-size: 10px;
+      font-weight: 700;
+      color: green;
+      background-color: azure;
+      border-radius: 4px;
+    "
+  >
+    {{ version }}
+  </span>
+</template>

+ 84 - 0
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;
+}

+ 22 - 0
docs/.vitepress/theme/index.ts

@@ -0,0 +1,22 @@
+// 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'
+
+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 }) {
+    // ...
+  },
+} satisfies Theme

BIN=BIN
docs/advanced/me/image-2.png


BIN=BIN
docs/advanced/me/image-3.png


+ 30 - 0
docs/advanced/me/me.md

@@ -0,0 +1,30 @@
+# 关于我
+
+我叫 `菲鸽`,江西宋城人。前端工程师,全栈实践者,精通 `vue`、`react`、`uniapp`、`typescript`、`小程序`、`Nodejs` 等。
+
+热爱编程,喜欢分享,平时比较宅,喜欢撸代码,偶尔打篮球和玩王者荣耀。
+
+<!-- ![alt text](image-2.png) -->
+
+## 找到我
+
+- Github: [feige996](https://github.com/feige996)
+- Gitee: [feige996](https://gitee.com/feige996)
+- 掘金:[菲鸽](https://juejin.cn/user/3263006241460792/posts)
+- 微信:`feige996` = `菲鸽`,大家都叫我 `鸽鸽`
+- QQ:`1020103647`
+- 邮箱:`1020103647@qq.com`
+
+## 微信公众号
+
+微信公众号:`菲鸽爱编程`
+
+![微信公众号](./screenshots/wx-gzh.png)
+
+<!-- ## 靓照
+
+五一陪儿子玩,不料给我拍出来美美的靓照,正好没有合适的照片,就用它了。
+
+`2024年5月5日`,最新鲜的照片了。
+
+![alt text](image-3.png) -->

BIN=BIN
docs/advanced/me/screenshots/pay-wx.png


BIN=BIN
docs/advanced/me/screenshots/wx-gzh.png


BIN=BIN
docs/advanced/me/screenshots/wx-me.png


BIN=BIN
docs/advanced/rewards/assets/group-qq.jpg


BIN=BIN
docs/advanced/rewards/assets/group-wx.jpg


BIN=BIN
docs/advanced/rewards/assets/pay-1.png


BIN=BIN
docs/advanced/rewards/assets/pay-2.png


BIN=BIN
docs/advanced/rewards/assets/pay-ali.png


BIN=BIN
docs/advanced/rewards/assets/pay-w-5.png


BIN=BIN
docs/advanced/rewards/assets/pay-wx-10.png


BIN=BIN
docs/advanced/rewards/assets/pay-wx-2.png


BIN=BIN
docs/advanced/rewards/assets/pay-wx-5-doc.png


BIN=BIN
docs/advanced/rewards/assets/pay-wx-5.png


BIN=BIN
docs/advanced/rewards/assets/pay-wx.png


+ 8 - 0
docs/advanced/rewards/rewards.md

@@ -0,0 +1,8 @@
+# 🥤 打赏
+
+如果本项目对你的工作起到了帮助,加快了您的项目进展,解决了您的问题,欢迎 `打赏` !
+
+<p align='center'>
+<img alt="special sponsor appwrite" src="./assets/pay-1.png" height="330" style="display:inline-block; height:330px;">
+<img alt="special sponsor appwrite" src="./assets/pay-2.png" height="330" style="display:inline-block; height:330px; margin-left:10px;">
+</p>

+ 61 - 0
docs/advanced/sponsor/sponsor.md

@@ -0,0 +1,61 @@
+# 赞助榜
+
+感谢所有赞助者!
+
+如需更改展示信息,或者需要展示更详细的信息,请联系我。
+
+如果需要展示产品、博客、友链啥的,也可以联系我,很乐意为您展示。
+
+> 金牌赞助者将额外获得首页产品展示位。
+
+## 200 元
+
+- 麦可
+- 程序员云创 [https://www.codecommitter.com/](https://www.codecommitter.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` 人,这里不一一列出。(如果希望展示,请联系我)
+
+## 红包打赏
+
+还有一部分群友是发 `专属红包` 打赏的,这里没有统计,如果需要展示,请联系我。
+
+---
+
+> 再次感谢所有赞助者、打赏者!

BIN=BIN
docs/advanced/wechat/image-1.png


BIN=BIN
docs/advanced/wechat/image-2.png


BIN=BIN
docs/advanced/wechat/image.png


+ 14 - 0
docs/advanced/wechat/wechat.md

@@ -0,0 +1,14 @@
+# 微信交流群
+
+> 作者最近比较忙,本来想隐藏交流群的,但是还是有人通过加我微信,要去交流群,索性还是放开吧。
+
+最近作者在复习,准备面试,群消息关注较少,希望见谅。
+
+再次提醒,千万记得 `先看一遍文档`,两个小时就看完了吧。
+
+![alt text](https://oss.laf.run/ukw0y1-site/unibest-discussion-group/wechat.jpeg)
+
+> 如果上面的微信群满了,请使用下面的 QQ 群,QQ 群不会过期,长期有效。
+
+① 群已满,下面是 ② 群。
+![alt text](https://oss.laf.run/ukw0y1-site/unibest-discussion-group/qq.jpeg)

+ 196 - 0
docs/base/1-introduction.md

@@ -0,0 +1,196 @@
+# 简介
+
+<div class="md-center" style="margin-top: 20px;">
+
+[![GitHub Repo stars](https://img.shields.io/github/stars/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest)
+[![GitHub Repo stars](https://img.shields.io/github/stars/feige996/unibest?style=flat&logo=github)](https://github.com/feige996/unibest)
+[![star](https://gitee.com/codercup/unibest/badge/star.svg?theme=dark)](https://gitee.com/codercup/unibest)
+![node version](https://img.shields.io/badge/node-%3E%3D18-green)
+![pnpm version](https://img.shields.io/badge/pnpm-%3E%3D7.30-green)
+![GitHub License](https://img.shields.io/github/license/codercup/unibest)
+
+</div>
+
+> 上面前 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`。
+
+## ⭐ Star History
+
+Github Star History 实时地址:[https://star-history.com/#codercup/unibest&Date](https://star-history.com/#codercup/unibest&Date) 。
+
+[![Star History Chart](https://api.star-history.com/svg?repos=codercup/unibest&type=Date)](https://star-history.com/#codercup/unibest&Date)
+
+与同类型模板对比,如下图,红色的为 `unibest`,后来居上,遥遥领先。
+
+:::details
+
+[![Star History Chart](https://api.star-history.com/svg?repos=codercup/unibest,Ares-Chang/uni-vitesse,uni-helper/vitesse-uni-app&type=Date)](https://star-history.com/#codercup/unibest&Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&Date)
+
+同类模板对比实时地址:[https://star-history.com/#codercup/unibest&Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&Date](https://star-history.com/#codercup/unibest&Ares-Chang/uni-vitesse&uni-helper/vitesse-uni-app&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) - 就是快!
+
+- 🔥 最新语法 - `<script lang="ts" setup>` 语法
+
+- 🎨 [UnoCSS](https://unocss.dev/) - 高性能且极具灵活性的即时原子化 CSS 引擎
+
+- 😃 [UnoCSS Icons](https://unocss.dev/presets/icons) & [icones](https://icones.js.org/) - 海量图标供你选择
+
+- 🍍 [pinia](https://pinia.vuejs.org/) & [pinia-plugin-persistedstate](https://prazdevs.github.io/pinia-plugin-persistedstate/zh/guide/) - 全端适配的全局数据管理
+
+- 🗂 `uni.request` 请求封装 - 一键引入,快捷使用
+
+- 📦 `路由拦截` 基础封装,支持扩展,快捷使用,拒绝黑盒
+
+- 📥 [API 自动加载](https://github.com/antfu/unplugin-auto-import) - 直接使用 Composition API 无需引入
+
+- 🎉 `v3` Code Snippets 加快你的页面生成
+
+- 🦾 `Pritter` & `ESLint` & `Stylelint` & `husky` & `lint-staged` + `commitlint` - 保证代码质量
+
+- 🌈 `TypeScript` 加持,同时又兼容 `js` ,同时满足不同人群
+
+- 💡 `ES6 import` 自动排序,`css 属性` 自动排序,增强编码一致性
+
+- 🖥 `多环境` 配置分开,想则怎么配置就怎么配置
+
+## 📦 目录结构
+
+通过 `tree -I node_modules -I dist -I .git -a > tree.md` 命令生成。
+
+```txt
+.
+├── .editorconfig
+├── .eslintignore
+├── .eslintrc-auto-import.json
+├── .eslintrc.cjs
+├── .gitignore
+├── .husky
+├── .npmrc
+├── .prettierignore
+├── .prettierrc.cjs
+├── .stylelintignore
+├── .stylelintrc.cjs
+├── .vscode
+├── LICENSE
+├── README.md
+├── commitlint.config.cjs
+├── env
+│   ├── .env
+│   ├── .env.development
+│   ├── .env.production
+│   └── .env.test
+├── favicon.ico
+├── index.html
+├── manifest.config.ts
+├── package.json
+├── pages.config.ts
+├── src
+│   ├── App.vue
+│   ├── components
+│   │   └── .gitkeep
+│   ├── env.d.ts
+│   ├── hooks
+│   │   ├── .gitkeep
+│   │   ├── useRequest.ts
+│   │   └── useUpload.ts
+│   ├── interceptors
+│   │   ├── index.ts
+│   │   ├── prototype.ts
+│   │   ├── request.ts
+│   │   └── route.ts
+│   ├── layouts
+│   │   ├── default.vue
+│   │   └── demo.vue
+│   ├── main.ts
+│   ├── manifest.json
+│   ├── pages
+│   │   ├── about
+│   │   │   ├── about.vue
+│   │   │   └── components
+│   │   │   ├── request.vue
+│   │   │   └── upload.vue
+│   │   └── index
+│   │   └── index.vue
+│   ├── pages-sub
+│   │   └── demo
+│   │   └── index.vue
+│   ├── pages.json
+│   ├── service
+│   │   └── index
+│   │   └── foo.ts
+│   ├── static
+│   │   ├── images
+│   │   │   └── .gitkeep
+│   │   ├── logo.svg
+│   │   └── tabbar
+│   │   ├── example.png
+│   │   ├── exampleHL.png
+│   │   ├── home.png
+│   │   ├── homeHL.png
+│   │   ├── personal.png
+│   │   └── personalHL.png
+│   ├── store
+│   │   ├── index.ts
+│   │   └── user.ts
+│   ├── style
+│   │   └── index.scss
+│   ├── types
+│   │   ├── auto-import.d.ts
+│   │   ├── global.d.ts
+│   │   ├── shims-uni.d.ts
+│   │   └── uni-pages.d.ts
+│   ├── typings.ts
+│   ├── uni.scss
+│   ├── uni_modules
+│   │   └── .gitkeep
+│   └── utils
+│   ├── http.ts
+│   ├── index.ts
+│   └── platform.ts
+├── tsconfig.json
+├── uni-pages.d.ts
+├── uno.config.ts
+└── vite.config.ts
+```

+ 163 - 0
docs/base/10-i18n.md

@@ -0,0 +1,163 @@
+# 多语言篇
+
+`多语言` 是一个常见的需求, `unibest` 专门开发了一个 `i18n`模板,可以直接生成 `多语言模板项目`。
+
+```sh
+pnpm create unibest my-project -t i18n
+```
+
+`vue组件` 里面使用方式如下:
+
+```html
+<view class="m-4">{{ $t('app.name') }}</view>
+```
+
+`非vue组件` 里面怎么使用呢?比如 `ts` 文件。
+
+这时需要用到作者编写的 `translate` 函数,使用方式如下:
+
+```ts
+import { translate as t } from '@/locale/index'
+
+/** 非vue 文件使用 i18n */
+export const testI18n = () => {
+  console.log(t('app.name'))
+  // 下面同样生效
+  uni.showModal({
+    title: 'i18n 测试',
+    content: t('app.name'),
+  })
+}
+```
+
+上面基本的使用都是没问题的,但是传递参数时,只有 `H5端` 生效,`其他端` 是不生效的,代码如下:
+
+```html
+<view class="m-4">{{ $t('weight', { heavy: 100 }) }}</view>
+```
+
+`H5端` 效果如下,正常显示:
+
+![alt text](./assets/10-1.png)
+
+`非H5端` 效果如下,异常显示:
+
+![alt text](./assets/10-2.png)
+
+下面我们就来处理这个问题。
+
+## 多语言传参
+
+上面提到 `vue-i18n` 在 `非H5端` 传参时显示异常,那我们就来处理一下,主要方式就是通过 `正则` 替换 `多语言字符串`。
+
+编写一个函数 `formatI18n`,如下:
+
+```ts
+/**
+ * formatI18n('我是{name},身高{detail.height},体重{detail.weight}',{name:'张三',detail:{height:178,weight:'75kg'}})
+ * 暂不支持数组
+ * @param template 多语言模板字符串,eg: `我是{name}`
+ * @param obj 需要传递的对象,里面的key与多语言字符串对应,eg: `{name:'菲鸽'}`
+ * @returns
+ */
+export function formatI18n(template, data) {
+  const match = /\{(.*?)\}/g.exec(template)
+  if (match) {
+    const variableList = match[0].replace('{', '').replace('}', '').split('.')
+    let result = data
+    for (let i = 0; i < variableList.length; i++) {
+      result = result[variableList[i]] || ''
+    }
+    return formatStr(template.replace(match[0], result), data)
+  } else {
+    return template
+  }
+}
+```
+
+`vue组件` 里面使用方式如下:
+
+```html
+<view class="m-4">{{ formatI18n(translate('introduction'), user) }}</view>
+```
+
+用到的函数引入如下:
+
+```js
+import { formatI18n, translate } from '@/locale/index'
+```
+
+对应的 en.json 文件如下:
+
+```json
+{ "introduction": "I am {name},height:{detail.height},weight:{detail.weight}" }
+```
+
+`user` 对象如下:
+
+```js
+{name:'张三',detail:{height:178,weight:'75kg'}}
+```
+
+这样,在 `H5端` 和 `非H5端` 都能正常显示,如下:
+
+![alt text](./assets/10-3.png)
+
+very good !
+
+## 导航栏标题
+
+目前发现 `导航栏标题` 在 `小程序端` 不会跟随多语言切换而切换,比如说刚开始是中文,切换成英文后,页面内容都变成英文了,标题栏还是中文。
+
+> `App端` 说明:`App模拟器`,以我的 `mac电脑` `ios模拟器` 来说,是正常的,可以直接切换,多语言也是生效的。
+>
+> 但是 `安卓真机` 会出现`切换多语言后,自动重启,然后界面多语言是生效的`。
+>
+> 既然 `App 正常`,这里主要说 `小程序端` 不正常的处理。
+
+`小程序端` 需要使用 `uni.setNavigationBarTitle` 来手动处理,`API` 使用如下:
+
+```js
+uni.setNavigationBarTitle({
+  title: '新的标题',
+})
+```
+
+结合 `translate` 函数,则:
+
+```js
+uni.setNavigationBarTitle({
+  title: translate('app.name'),
+})
+```
+
+可以满足大部分场景。
+
+## tabbar 标题
+
+同 `导航栏标题`。
+
+## App 端视频
+
+这里给出 `2` 个 `App端` 的视频,加深开发者的认识和印象。
+
+:::details
+
+### `ios模拟器` 多语言直接就是生效的
+
+<video src="./assets/10-ios.mp4" controls="controls" width="100%" height="100%"></video>
+
+### `安卓真机` 会自动重启,重启后界面多语言是生效的
+
+<video src="./assets/10-android.mp4" controls="controls" width="100%" height="100%"></video>
+:::
+
+## 总结
+
+本文介绍了 `unibest` 里面使用 `多语言` 的基本方式,还处理了 `3` 个多端异常的问题:
+
+- `多语言传参` 不生效 BUG
+- `导航栏标题` 切换多语言不生效 BUG
+- `tabbar标题` 切换多语言不生效 BUG
+
+全文完~

+ 111 - 0
docs/base/11-build.md

@@ -0,0 +1,111 @@
+# 运行发布
+
+## 运行
+
+- `h5 平台`: `pnpm dev:h5`( 或者简单点 `pnpm dev` ),然后浏览器打开 `http://localhost:9000/`。
+- `wx 小程序`:`pnpm dev:mp-weixin`,然后打开微信开发者工具,导入本地文件夹,选择本项目的 `dist/dev/mp-weixin` 文件。
+- ![alt text](./assets/11-1.png)
+
+- `APP 平台`:`pnpm dev:app`,然后打开 `HBuilderX`,导入刚刚生成的 `dist/dev/app` 文件夹,选择运行到 `模拟器`( `开发时优先使用` ),或者 `运行到安卓/ios 基座` (真机调试时使用) 。
+
+![alt text](./assets/11-2.png)
+
+![alt text](./assets/11-3.png)
+![alt text](./assets/11-4.png)
+
+> 如果需要配置其他模拟器,可以参考:[安装模拟器](https://uniapp.dcloud.net.cn/tutorial/run/installSimulator.html)
+
+> 这样操作的话,开发时都会有热更新,开发体验很爽!
+
+## 发布
+
+- `h5 平台`: `pnpm build:h5`,打包后的文件在 `dist/build/h5`,可以放到 web 服务器,如 nginx 运行。如果最终不是放在根目录,可以在 `manifest.config.ts` 文件的 `h5.router.base` 属性进行修改。
+- `wx 小程序`:`pnpm build:mp-weixin`,打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。
+- `APP 平台`:`pnpm build:app`,然后打开 `HBuilderX`,导入刚刚生成的 `dist/build/app` 文件夹,选择 `发行` - `原生APP-云打包`。
+
+![alt text](./assets/11-13.png)
+![alt text](./assets/11-5.png)
+![alt text](./assets/11-6.png)
+
+> 熟悉原生 APP 开发的开发者也可以使用 `原生APP-本地打包`。
+
+## APP 打包注意事项(上)
+
+很多开发者发现打包失败,或者打包白屏,这里简单说明一下。
+
+- 1. 重新获取自己的 `AppId`
+
+![alt text](./assets/11-7.png)
+
+- 2. 根据上面获取到的 `AppId` 修改 `env/.env` 文件的 `VITE_UNI_APPID` 字段
+
+![alt text](./assets/11-8.png)
+
+- 3. (可选)云打包如果有出现解析时出问题的,把 `minSdkVersion` 版本改低一点就好了,比如 `21`。(最低 `21`,不能低于 `21`;我模板里面设置的是 `30`)。
+
+![alt text](./assets/11-9.png)
+
+## APP 打包注意事项 (下)
+
+### `uni-app SDK` 版本
+
+> 特别备注:`2024-05-03`,新的 `base` 模板的 `uni-app SDK` 版本已经升级到 `4.14` 了。
+>
+> ![alt text](./assets/11-100.png)
+
+`2024-04-14`,新的 `base` 模板的 `uni-app SDK` 版本已经升级到 `4.08` ,记得更新您的 `HBuilderx` 版本。
+
+`"@dcloudio/uni-app": "3.0.0-4000820240401001"` 表示 `uni-app` 为 `3.0.0` 版本,对应的 `HBuilderx` 版本为 `4.08`,后面的 `20240401001` 是发布日期。
+
+> `40008` 第一个数字 `4` 表示主要版本,后面每 `2` 位数为一组,所以代表 `4.0.8`。
+>
+> 类似的,`30812` 代表 `3.8.12` 版本,`30909` 代表 `3.9.9` 版本。
+>
+> 另外,从 `3.99` 开始,后面 2 个小版本合并书写,于是 `3.9.9` 变成 `3.99`,`4.0.8` 变成 `4.08`。
+
+`unibest` 历史用过的 `@dcloudio/uni-app` 版本:
+
+```text
+"@dcloudio/uni-app": "3.0.0-3081220230817001",  => 3.8.12
+"@dcloudio/uni-app": "3.0.0-3090920231225001",  => 3.99
+"@dcloudio/uni-app": "3.0.0-4000820240401001",  => 4.08
+"@dcloudio/uni-app": "3.0.0-4010420240430001",  => 4.14
+```
+
+![alt text](./assets/11-10.png)
+
+### `uni-app SDK` 版本匹配 `HBuilderX`
+
+> 温馨提示:下面的部分是使用 `uni-app` 版本为 `3.8.12` 时写的文档,适当参考~
+
+本模板使用的是 `3.8.12` 的库版本(`"@dcloudio/uni-app": "3.0.0-3081220230817001",`),所以尽量使用 `3.8.12` 版本的 `HBuilderX` 来打包,否则可能有未知的风险,出现情况如下图。
+
+> 原来的图不见了,重新补了一张。
+
+![alt text](./assets/11-11.png)
+
+上图表示您的 `HBuilderX` 版本是 `4.08`,但是代码 `uni-app SDK` (即 `"@dcloudio/uni-app": "3.0.0-4010420240430001"` ) 是 `4.14`,版本不匹配。
+
+- 点击 `ignore`(忽略) 后若可以正常使用,那就不用管。(可选添加如下配置)
+
+```json
+"app-plus" : { "compatible": { "ignoreVersion": true } }
+```
+
+- 如果出现白屏啥的,请更新您的 `HBuilderX` 到 `uni-app SDK` 相同版本(这里是 `4.14` )。
+
+### 多个 `HBuilderX` 版本安装
+
+> 温馨提示:下面的部分是使用 `uni-app` 版本为 `3.8.12` 时写的文档,适当参考~
+
+`MAC` 可以安装多个版本的软件,如下图我安装了 `3.8.12` (3.8.12.20230817) 和最新的 `3.99` (3.99.2023122611) 两个版本,平时的项目使用 `3.99`, 打包 `unibest` 的时候使用 `3.8.12`。
+
+![alt text](./assets/11-12.png)
+
+> `window` 系统也可以同时安装多个 `HBuilderX` 版本,安装时选择安装到不同目录下即可。
+
+## 总结
+
+本文描述了多端的运行和发布,希望对您有帮助。
+
+全文完~

+ 89 - 0
docs/base/12-env.md

@@ -0,0 +1,89 @@
+# 环境变量
+
+主要介绍 `vite` 环境变量和 `uni` 环境变量。
+
+## `vite` 环境变量
+
+`Vite` 在一个特殊的 `import.meta.env` 对象上暴露环境变量。环境变量定义在 `.env` 文件里。
+
+### .env 文件
+
+创建环境文件:
+
+```yml
+.env                # 所有情况下都会加载
+.env.local          # 所有情况下都会加载,但会被 git 忽略
+.env.[mode]         # 只在指定模式下加载
+.env.[mode].local   # 只在指定模式下加载,但会被 git 忽略
+
+# 注意 .env.local 无法覆盖 .env.[mode]
+```
+
+环境文件只包含环境变量的 `键值对` :
+
+```yml
+VITE_SOME_KEY=123
+DB_PASSWORD=foobar
+```
+
+> 为了防止意外地将一些环境变量泄漏到客户端,只有以 `VITE_` 为前缀的变量才会暴露给经过 `vite` 处理的代码。
+
+如上配置,只有 `VITE_SOME_KEY` 会被暴露为 `import.meta.env.VITE_SOME_KEY` 提供给客户端源码,而 `DB_PASSWORD` 则不会。
+
+```js
+console.log(import.meta.env.VITE_SOME_KEY) // "123"
+console.log(import.meta.env.DB_PASSWORD) // undefined
+```
+
+### mode 模式
+
+Vite 允许你为不同的构建环境指定不同的模式。通常在 `npm scripts` 里面指定 `mode` 参数:
+
+```sh
+"scripts": {
+    "dev": "uni",
+    "dev-dev": "uni --mode development",
+    "dev-test": "uni --mode test",
+    "dev-prod": "uni --mode production",
+}
+```
+
+运行不同模式的脚本时,`Vite` 会自动加载对应的 `.env.[mode]` 文件,就能获取到不同的环境变量。
+
+`Vite` 运行 `dev` 时默认会加载 `.env.development` 文件(若有)。
+
+`Vite` 运行 `build` 时默认会加载 `.env.production` 文件(若有)。
+
+故,如上配置 `pnpm dev` 与 `pnpm dev-dev` 是一个效果。
+
+## `uni` 环境变量
+
+`uni` 环境变量这里指运行 `uni` 的平台变量,通过 `vite` 的 `define` 配置可以暴露出来。
+
+```
+define: {
+  __UNI_PLATFORM__: JSON.stringify(UNI_PLATFORM),
+},
+```
+
+代码里面使用:
+
+```js
+export const platform = __UNI_PLATFORM__
+export const isH5 = __UNI_PLATFORM__ === 'h5'
+export const isApp = __UNI_PLATFORM__ === 'app'
+export const isMp = __UNI_PLATFORM__.startsWith('mp-')
+const PLATFORM = {
+  platform,
+  isH5,
+  isApp,
+  isMp,
+}
+export default PLATFORM
+```
+
+## 总结
+
+本文描写了 `vite` 环境变量和 `uni` 环境变量如何配置和使用。
+
+全文完~

+ 67 - 0
docs/base/13-hbx.md

@@ -0,0 +1,67 @@
+# hbx 模板
+
+为了方便使用 `HBuilderX` 的开发者,`unibest` 也提供 `hbx` 模板。
+
+`hbx 模板` 适用于 `2 类用户`
+
+- 使用 `uniCloud` 云开发的用户,必须使用 `hbx 版本`,因为 `uniCloud` 跟 `HBuilderX` 是绑定的。
+- 开发 `App` 的用户,可选使用 `hbx 版本`。
+
+## 仓库地址
+
+- gitee: [https://gitee.com/feige996/unibest-hbx.git](https://gitee.com/feige996/unibest-hbx.git)
+- github: [https://github.com/feige996/unibest-hbx.git](https://github.com/feige996/unibest-hbx.git)
+
+没有梯子的用户优先推荐使用 `gitee` 仓库,速度更快。(两个仓库会实时同步,无差别。)
+
+## 导入项目
+
+有 2 种方式导入项目:
+
+- 从 `Git` 导入...
+- 从本地目录导入...
+
+## 运行项目
+
+此时运行菜单会提示 `本项目类型无法运行`,如下图
+
+![alt text](./assets/13-1.png)
+
+![alt text](./assets/13-2.png)
+
+需要执行如下 2 步:
+
+- 项目下执行 `pnpm i`
+- 右键项目,选择 `重新识别项目类型`
+
+![alt text](./assets/13-3.png)
+
+## 运行效果
+
+经过上面的操作后,就可以正常运行了。
+
+- ios 模拟器运行效果如下:
+
+![alt text](./assets/13-4.png)
+
+![alt text](./assets/13-5.png)
+
+![alt text](./assets/13-6.png)
+
+- 微信小程序运行效果如下:
+
+![alt text](./assets/13-7.png)
+
+> 目前微信小程序静态资源还有点问题,如下图 `logo 不见了`,后续会修复。
+
+![alt text](./assets/13-8.png)
+
+> 另外还发现 `UnoCSS Icon` 不生效,原因未知。
+
+## 总结
+
+本文描述了 `hbx` 模板的由来,使用方式。
+
+有需要的可以试试,但是不太建议使用。另外精力有限,该模板不再维护。
+
+全文完~

+ 116 - 0
docs/base/14-faq.md

@@ -0,0 +1,116 @@
+# 常见问题
+
+本篇介绍一些常见的问题,会持续更新。
+
+## 1. 如何设置/修改首页?
+
+`vue` 文件的 `route-block` 块里面设置 `type="home"` 即可,请确保项目里面 `只有一个页面` 是这个配置。
+
+> 注意:如果有多个,会按照字母顺序排列,第一个是首页。(可能不是您的想要的效果。)
+
+## 2. 修改 `pages.json`、`manifest.json` 被覆盖问题
+
+- `pages.json`
+
+本项目引入了 `@uni-helper/vite-plugin-uni-pages`,`pages.json` 文件将会自动生成,手动修改 `pages.json` 将会被覆盖。
+
+全局的东西请在 `pages.config.ts` 里面配置,页面的东西请在 `vue` 文件的 `route-block` 配置。
+
+- `manifest.json`
+
+与上面类似。本项目引入了 `@uni-helper/vite-plugin-uni-manifest`,`manifest.json` 文件将会自动生成,手动修改 `manifest.json` 将会被覆盖。
+
+如需修改,请在 `manifest.config.ts` 里面修改。
+
+## 3. 怎么分包?
+
+`vite.config.ts` 里面有一个配置,如下:(其中 `subPackages` 就是用来分包的)
+
+```ts [vite.config.ts]{3}
+UniPages({
+    exclude: ['**/components/**/**.*'],
+    subPackages: ['src/pages-sub'], // 是个数组,可以配置多个
+}),
+```
+
+## 4. 首次运行 `pnpm:mp` 时报错。
+
+首次运行 `pnpm:mp` 时报错,报错如下:
+
+```text
+Error: ENOENT: no such file or directory, open '/Users/burtlai/unibest-projects/unibest/src/manifest.json'
+```
+
+首次运行 `非h5端` 时都可能出现上面的问题,需要先执行一下 `pnpm i` 以生成 `src/manifest.json` 文件,后面就不会报错了。
+
+## 5. `git commit` 报错。
+
+请看 `commitlint.config.ts` 里面的配置,需要满足对应的设定。根据自己的需要,可以修改 `commitlint.config.ts` 里面的配置。
+
+如果是一次的(比如引入了某个第三方库),可以通过 `--no-verify` 参数跳过校验:
+
+```sh
+git commit -m "feat: xxx" --no-verify
+```
+
+第三方库还有另外一种处理方式,放到特定的文件夹,然后在 `.eslintignore` 和 `.styleintignore` 里面加上该文件夹。
+
+## 6. `uni-app` 无法使用 `process.env` 变量,怎么办?
+
+使用 `import.meta.env` 替代!
+
+## 7. 如何跟随 `uni-app` 官方升级?
+
+项目下,执行 `npx @dcloudio/uvm@latest` 即可更新。
+
+![alt text](./assets/14-1.png)
+
+> 注意,上面的命令会自动安装 `vue-i18n`,可以手动删除(`pnpm un vue-i18n`),也可以不理它(没多大影响)。
+
+## 8. 如何把已经加入 `git` 管理的文件移出 `git` 管理?
+
+- 第一步,先把文件移出`git` 管理,操作如下:
+
+```text
+# git rm -r --cached file1 file2  ## 针对某些文件
+# git rm -r --cached dir1 dir2  ## 针对某些文件夹
+# git rm -r --cached .  ## 针对所有文件
+```
+
+- 第二步,提交 `commit` 以正式删除的文件
+
+> 总结:`git rm -r --cached .` + `git commit` 即可。
+
+## 9. 支付宝小程序运行报错。
+
+- 默认运行是会报错的,如下图
+  ![alt text](./assets/14-2.png)
+
+- 只需要勾上 `本地开发跳过 ES5 转译` 即可正常运行,如下图
+  ![alt text](./assets/14-3.png)
+
+> 总结:勾上 `本地开发跳过 ES5 转译` 即可。
+
+## 10. 支持 `uni-app x` 吗?
+
+不支持。但我们一直保持关注。[uni-app x 传送门](https://doc.dcloud.net.cn/uni-app-x/)
+
+目前 `unibest` 已经有 `hbx` 模板,后续接入 `uni-app x` 会很容易,坐等官方发布。
+
+## 11. 为啥 `vue` 已经 `3.4+` 了,还不支持 `defineModel` ?
+
+`uni-app` 官方虽然已经把 `vue` 升级到 `3.4+` 了,但是目前只有 `H5端` 支持 `defineModel`,其他端目前运行报错,详情请看 `uni-app` 官网的发布日志:
+
+[HBuilder X - Release Notes](https://3085868976.hiecheimaetu.com:22443/qn-GO8xCsKgpKDZWIBAkVCUkI1EnGmQUMT4.update.dcloud.net.cn/hbuilderx/changelog/4.14.2024043013.html)
+
+关键截图如下:
+
+![alt text](./assets/14-4.png)
+
+真实运行报错截图如下:(分别是 `小程序` 和 `APP` )
+
+![alt text](./assets/14-5.png)
+
+![alt text](./assets/14-6.png)
+
+全文完~

+ 267 - 0
docs/base/15-faq.md

@@ -0,0 +1,267 @@
+# 常见问题 2
+
+## 1. `wot-ui` 的 `toast` + `message-box` 不生效。
+
+- 1. `layout` 引入 `wot-ui` 的 `toast` + `message-box`。
+
+```vue [src/layouts/default.vue]
+<!-- src/layouts/default.vue -->
+<template>
+  <view>
+    <slot />
+    <wd-toast />
+    <wd-message-box />
+  </view>
+</template>
+```
+
+> `unibest@2.1.0` 开始已经默认引入。
+
+- 2.页面使用
+
+```ts
+import { useMessage } from 'wot-design-uni'
+
+const message = useMessage()
+const handleClick = () => {
+  // 顺便测试 message 的使用
+  message.show('显示隐藏切换')
+}
+```
+
+## 2. `uni-app` 插件市场的插件如何使用?
+
+`hbx` 模板可以直接引入,不在讨论范围内,下面描述的是 `普通模板`。
+
+> 如果该插件支持 `npm` 安装,则直接安装即可,推荐统一使用 `pnpm` 安装。接着根据该插件的文档使用即可。
+
+下面描写的是不支持 `npm` 安装的插件。
+
+这里以 `sp-editor` 富文本插件为例,[插件地址](https://ext.dcloud.net.cn/plugin?id=14726)
+
+- 1. 下载 `uni-app` 插件市场的代码。(居然要登录+看广告)
+
+![alt text](./assets/15-1.png)
+
+- 2. 解压并拷贝到 `unibest` 项目的 `uni_modules` 目录下。
+
+![alt text](./assets/15-2.png)
+
+- 3. 整理插件文件夹名称,把 `sp-editor_1.3.7` 改为 `sp-editor`。
+
+> 不改会报错,因为内部代码都是用 `sp-editor` 不带版本号的。会导致查找文件失败。
+
+![alt text](./assets/15-3.png)
+
+- 4. 代码直接使用,无需引入组件。( `uni-app插件` 有一套规范,`uni-app` 会自动查找,跟 `easycom` 类似。)
+
+```html
+<template>
+  <view class="home">
+    <view class="editor-box">
+      <sp-editor
+        :toolbar-config="{
+          excludeKeys: ['direction', 'date', 'lineHeight', 'letterSpacing', 'listCheck'],
+          iconSize: '18px',
+        }"
+        @init="initEditor"
+        @input="inputOver"
+        @upinImage="upinImage"
+        @overMax="overMax"
+        @addLink="addLink"
+        @exportHtml="exportHtml"
+      ></sp-editor>
+    </view>
+  </view>
+</template>
+```
+
+完整版见下:
+:::details
+
+```vue
+<route lang="json5">
+{
+  layout: 'demo',
+  style: { navigationBarTitleText: '富文本' },
+}
+</route>
+
+<template>
+  <view class="home">
+    <view class="editor-box">
+      <sp-editor
+        :toolbar-config="{
+          excludeKeys: ['direction', 'date', 'lineHeight', 'letterSpacing', 'listCheck'],
+          iconSize: '18px',
+        }"
+        @init="initEditor"
+        @input="inputOver"
+        @upinImage="upinImage"
+        @overMax="overMax"
+        @addLink="addLink"
+        @exportHtml="exportHtml"
+      ></sp-editor>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const editorIns = ref(null)
+
+/**
+ * 获取输入内容
+ * @param {Object} e {html,text} 内容的html文本,和text文本
+ */
+function inputOver(e) {
+  // 可以在此处获取到编辑器已编辑的内容
+  console.log('==== inputOver :', e)
+}
+
+/**
+ * 超出最大内容限制
+ * @param {Object} e {html,text} 内容的html文本,和text文本
+ */
+function overMax(e) {
+  // 若设置了最大字数限制,可在此处触发超出限制的回调
+  console.log('==== overMax :', e)
+}
+
+/**
+ * 编辑器就绪
+ * @param {Object} editor 编辑器实例,你可以自定义调用editor实例的方法
+ * @tutorial editor组件 https://uniapp.dcloud.net.cn/component/editor.html#editor-%E7%BB%84%E4%BB%B6
+ * @tutorial 相关api https://uniapp.dcloud.net.cn/api/media/editor-context.html
+ */
+function initEditor(editor) {
+  editorIns.value = editor // 保存编辑器实例
+  // 保存编辑器实例后,可以在此处获取后端数据,并赋值给编辑器初始化内容
+  preRender()
+}
+
+function preRender() {
+  setTimeout(() => {
+    // 异步获取后端数据后,初始化编辑器内容
+    editorIns.value.setContents({
+      html: `<div>&nbsp;&nbsp;猫猫<img src="https://img.yzcdn.cn/vant/cat.jpeg"/></div>`,
+    })
+  }, 1000)
+}
+
+/**
+ * 直接运行示例工程插入图片无法正常显示的看这里
+ * 因为插件默认采用云端存储图片的方式
+ * 以$emit('upinImage', tempFiles, this.editorCtx)的方式回调
+ * @param {Object} tempFiles
+ * @param {Object} editorCtx
+ */
+function upinImage(tempFiles, editorCtx) {
+  /**
+   * 本地临时插入图片预览
+   * 注意:这里仅是示例本地图片预览,因为需要将图片先上传到云端,再将图片插入到编辑器中
+   * 正式开发时,还请将此处注释,并解开下面 使用 uniCloud.uploadFile 上传图片的示例方法 的注释
+   * @tutorial https://uniapp.dcloud.net.cn/api/media/editor-context.html#editorcontext-insertimage
+   */
+  // #ifdef MP-WEIXIN
+  // 注意微信小程序的图片路径是在tempFilePath字段中
+  editorCtx.insertImage({
+    src: tempFiles[0].tempFilePath,
+    width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
+    success: function () {},
+  })
+  // #endif
+
+  // #ifndef MP-WEIXIN
+  editorCtx.insertImage({
+    src: tempFiles[0].path,
+    width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
+    success: function () {},
+  })
+  // #endif
+
+  /**
+   * 使用 uniCloud.uploadFile 上传图片的示例方法(可适用多选上传)
+   * 正式开发环境中,请将上面 本地临时插入图片预览 注释后,模仿以下写法
+   */
+  // tempFiles.forEach(async (item) => {
+  //   uni.showLoading({
+  //     title: '上传中请稍后',
+  //     mask: true
+  //   })
+  //   let upfile = await uniCloud.uploadFile({
+  //     filePath: item.path,
+  //     // 同名会导致报错 policy_does_not_allow_file_overwrite
+  //     // cloudPath可由 想要存储的文件夹/文件名 拼接,若不拼文件夹名则默认存储在cloudstorage文件夹中
+  //     cloudPath: `cloudstorage/${item.name}`,
+  //     cloudPathAsRealPath: true
+  //   })
+  //   editorCtx.insertImage({
+  //     src: upfile.fileID,
+  //     width: '80%', // 默认不建议铺满宽度100%,预留一点空隙以便用户编辑
+  //     success: function () {
+  //       uni.hideLoading()
+  //     }
+  //   })
+  // })
+}
+
+/**
+ * 导出 - toolbar需要开启export工具
+ * @param {string} e 导出的html内容
+ */
+function exportHtml(e) {
+  uni.navigateTo({
+    url: '/pages/out/out',
+    success(res) {
+      // 传至导出页面解析即可
+      res.eventChannel.emit('e-transmit-html', {
+        data: e,
+      })
+    },
+  })
+}
+
+/**
+ * 添加超链接
+ * @param {Object} e { text: '链接描述', href: '链接地址' }
+ */
+function addLink(e) {
+  console.log('==== addLink :', e)
+}
+</script>
+```
+
+:::
+
+## 3. Vue-Office 使用哪个版本?
+
+使用 `1.8x`,而不是 `2.x`,否则出现下面这样的问题:
+
+![alt text](./assets/15-4.png)
+
+## 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`。
+
+控制台报错如下:
+![alt text](./assets/15-6.png)
+
+原因是 `uni-pages` 这个插件最新版本 `0.2.22` 有问题,需要回退到 `0.2.20`。
+
+![alt text](./assets/15-5.png)
+
+执行如下命令即可:
+
+```
+pnpm add @uni-helper/vite-plugin-uni-pages@0.2.20
+```
+
+> 因为 `unibest` 在 `2.3.0(含)` 之前没有把 `pnpm-lock.yaml` 加入到版本管理,导致小版还是有细微差别。
+>
+> 在 `2.4.0` 开始已经加入,不会再出现这个问题。

+ 119 - 0
docs/base/2-start.md

@@ -0,0 +1,119 @@
+# 快速开始
+
+- 前置依赖
+
+  - **Node.js** - `>=v18`
+  - **pnpm** - `>=7.30`(推荐使用 `8.12+`)
+  - **`VSCode`** - 可选 `WebStrom`
+  - **`HBuilderX`** - `APP` 的运行和发布还是离不开它
+  - **Vue-Office** - `1.8x`,别升到 `2.x` !
+
+## 创建项目
+
+通过下面的命令可以快速生成项目模板,`pnpm create unibest <项目名称>` ,如果不写 `<项目名称>` 会进入命令行交互模式。
+
+```bash
+# 如果没有 pnpm,请先安装: npm i -g pnpm
+pnpm create unibest my-project
+```
+
+npm 创建如下(不推荐)
+:::details
+如果使用 `npm`,可能有缓存,需要加上 `@latest` 标识,如果创建失败,请使用 `pnpm` 安装。
+
+```bash
+npm create unibest my-project
+# 如果提示报错,或者生成的项目版本太旧,请使用下面的命令,增加 @latest 标识
+npm create unibest@latest my-project
+```
+
+:::
+实际操作截图如下:
+
+![create project](./assets/2-1.png)
+
+`create-unibest` 在 `v1.10.0` 开始会有版本号,如下:
+
+![alt text](./assets/2-2.png)
+
+![unibest templates](https://oss.laf.run/ukw0y1-site/xmind/unibest模板.png)
+
+`create unibest` 支持 `-t` 参数选择模板,目前已有两大类 `8` 个模板
+
+- `普通` 模板( `4个` ):分别是 `base`、`tabbar`、`i18n`、`demo`、~~`js`~~
+- `hbx` 模板(`2个` ):分别是 `hbx-base`、`hbx-demo`。
+
+不带 `-t` 参数时会默认生成 `base` 模板。
+
+`base` 模板是最基本的模板,更新最及时,推荐使用 `base` 模板创建新项目。其他几个模板也是基于 `base` 模板得到的。 `demo` 模板则作为参考用。
+
+`js` 模板不推荐使用,可以使用 `base` 模板替代,里面已经做了兼容配置,可以直接编写 `js`,原本的 `ts` 文件还能提供部分类型,何乐而不为?
+
+```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 i18n # 多语言模板
+pnpm create unibest my-project -t demo # 所有demo的模板(包括i18n)
+# pnpm create unibest my-project -t js # js 模板
+
+# 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
+```
+
+## 项目仓库地址
+
+`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/feige996/unibest-hbx
+- https://gitee.com/feige996/unibest-hbx
+
+> `hbx` 目前由 `青谷` 大佬维护,微信号:`qingguxixi`,[青谷 github 地址](https://github.com/Xiphin) 。
+
+## 安装、运行
+
+```bash [pnpm]
+pnpm i
+pnpm dev
+# dev默认运行的是h5,其他平台执行dev:<uni-platform>,如:
+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` 代码块生成。
+
+![alt text](./assets/2-4.gif)
+
+## 注意事项
+
+- 若代码里面自动引入的 `API` 报错,只需要 `pnpm dev` 即可。
+- 若代码运行后,`H5端` 浏览器界面底部没有 `tabbar`, 刷新浏览器或者再次 `pnpm dev` 即可。

+ 25 - 0
docs/base/20-best.md

@@ -0,0 +1,25 @@
+# 最佳实践
+
+新项目使用 `base` 模板,可选 `tabbar` 模板。如果需要多语言,可以选 `i18n` 模板。
+
+同时参考 `demo` 模板,可以直接 `clone` `demo` 项目,用来参考用。
+
+> 推荐先全部体验一下 `demo` 的示例
+
+```sh
+# 新项目创建
+pnpm create unibest my-project -b base
+# 参考项目
+git clone https://github.com/feige996/hello-unibest unibest-demo
+# 参考项目-gitee (与 github 同步,无梯子用户优先使用 gitee)
+git clone https://gitee.com/feige996/hello-unibest unibest-demo
+```
+
+## 必看章节
+
+- [介绍](/base/1-introduction)
+- [快速开始](/base/2-start)
+- [uni 插件](/base/3-plugin)
+- [常见问题](/base/14-faq)
+- [常见问题 2](/base/15-faq)
+- [运行发布](/base/11-build)

+ 158 - 0
docs/base/3-plugin.md

@@ -0,0 +1,158 @@
+# uni 插件
+
+## 引言
+
+有群友第一次看到 `unibest` 里面 `vue` 文件 `route-block` 这种写法,表示很奇怪,重来没见过!
+
+```vue
+<route lang="json5">
+{
+  layout: 'demo',
+  style: {
+    navigationBarTitleText: '标题',
+  },
+}
+</route>
+
+<template>
+  <view class="text-green-500">菲鸽,你好,我喜欢你!</view>
+</template>
+```
+
+## 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` 来处理所有的代码。如下图:
+![vite uni plugin](./assets/3-1.png)
+
+接下来介绍一下 `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]
+<!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page -->
+<!-- 推荐使用json5,更强大,且允许注释 -->
+<route lang="json5" type="home">
+{
+  style: {
+    navigationStyle: 'custom',
+    navigationBarTitleText: '首页',
+  },
+}
+</route>
+<template>
+  <div>
+    <h1>欢迎使用 unibest</h1>
+    <h4>unibest 是最好的 uniapp 开发模板</h4>
+  </div>
+</template>
+```
+
+```vue [src/pages/about.vue]
+<route lang="json5">
+{
+  style: {
+    navigationBarTitleText: '关于',
+  },
+}
+</route>
+<template>
+  <view>
+    <view>通过 `/pages/about` 来访问这个页面</view>
+  </view>
+</template>
+```
+
+### 设置首页
+
+通过在 `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}
+<route lang="json5">
+{
+  layout: 'demo',
+  style: {
+    navigationBarTitleText: '关于',
+  },
+}
+</route>
+```
+
+```vue [src/layouts/demo.vue]
+<template>
+  <view>
+    <!-- 这里可以写通用的布局,比如导航栏,tabbar等 -->
+    <!-- slot里面装的就是子页面的内容 -->
+    <slot />
+  </view>
+</template>
+```
+
+## 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) 看看。

+ 220 - 0
docs/base/4-style.md

@@ -0,0 +1,220 @@
+# 样式篇
+
+本篇主要介绍 `UnoCSS` 的使用,以及如何与 `设计稿尺寸` 对应。
+
+## UnoCSS
+
+[UnoCSS](https://unocss.dev/) 是按需使用的原子 CSS 引擎,提供了良好的样式支持。
+
+![alt text](./assets/4-1.png)
+
+在 VSCode 中还可以预览,
+
+![alt text](./assets/4-2.png)
+
+![alt text](./assets/4-3.png)
+
+> 如果原子化 `UnoCSS` 没有预览效果,请安装 `VSCode` 插件 `antfu.unocss`。
+
+如果不记得原子类,可以查 `UnoCSS 的原子类`,[UnoCSS Interactive](https://unocss.dev/interactive/),如下图
+![alt text](./assets/4-4.png)
+
+也可以查看 `tailwindcss` 的原子类,更加清晰明了,[链接 - tailwindcss](https://tailwindcss.com/),如下图:
+
+![alt text](./assets/4-5.png)
+
+## 常用的原子类
+
+- 宽高内外边距: `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, 使用 `<button class="i-carbon-sun dark:i-carbon-moon" />`
+    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: `<div class="hover:(bg-gray-400 font-medium) font-(light mono)">测试 unocss</div>`
+    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`, 代码编写如 `<button class="i-carbon-sun dark:i-carbon-moon" />`
+- `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` 和 `传统方式` 两者不是互斥的,他们是互补的,合适的地方使用合适的方式。

+ 189 - 0
docs/base/5-icons.md

@@ -0,0 +1,189 @@
+# 图标篇
+
+本文主要介绍了 `图标` 的使用方式,通常有以下几种方式使用图标:
+
+- `UI 库 Icons`
+- `UnoCSS Icons`
+- `iconfont`
+
+下面笔者一一介绍
+
+## UI 库 Icons
+
+如果您已经引入了 `UI库`,并且正好该 `UI库` 已经有你想要的 `Icons`,那直接用最方便了,无需额外引入其他库,代码也是最少的。
+
+这里介绍几个常用 `UI库` 的图标使用。
+
+### `uni-ui Icons`
+
+> 注意:`uni-ui Icons` 颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。
+
+```html
+<uni-icons type="contact" size="30"></uni-icons>
+<uni-icons type="contact" size="30" color="red"></uni-icons>
+<uni-icons type="contact" size="30" class="text-green"></uni-icons>
+<uni-icons type="contact" size="30" color="red" class="text-green"></uni-icons>
+```
+
+![alt text](./assets/5-1.png)
+
+### `wot-ui Icons`
+
+> 注意:`wot-ui icons` 颜色可以通过 `color` 属性设置,也可以通过 `UnoCSS` 设置;同时设置时,`color` 属性优先级高。
+
+```html
+<wd-icon name="add-circle"></wd-icon>
+<wd-icon name="add-circle" color="red"></wd-icon>
+<wd-icon name="add-circle" class="text-green"></wd-icon>
+<wd-icon name="add-circle" class="text-green" color="red"></wd-icon>
+```
+
+![alt text](./assets/5-2.png)
+
+### `uv-ui Icons`
+
+> 注意:跟 `uni-ui Icons` 一样,`uv-ui Icons` 的颜色只能通过 `color` 属性设置;使用 `UnoCSS` 设置无效。
+
+```html
+<uv-icon name="home"></uv-icon>
+<uv-icon name="home" color="red"></uv-icon>
+<uv-icon name="home" class="text-green"></uv-icon>
+<uv-icon name="home" color="red" class="text-green"></uv-icon>
+```
+
+![alt text](./assets/5-3.png)
+
+> 注意,经过检测这 `3个UI库Icons` 都不支持使用 `UnoCSS` 改变大小(优先级低被覆盖),必须使用 `size` 属性来设置大小才有效果(行内样式优先于 css 样式)。
+>
+> 另外,经过检测,都支持动态 `iconName`和动态 `color` ! 即下面这样的写法是生效的:
+
+```ts
+const iconName = ref<string>('contact')
+const colorName = ref<string>('red')
+onLoad(() => {
+  setTimeout(() => {
+    iconName.value = 'chat'
+    colorName.value = 'green'
+  }, 1000)
+})
+```
+
+```html
+<uni-icons :type="iconName" :color="colorName" class="text-green w-8"></uni-icons>
+<!-- 其他2个UI库同样生效 -->
+```
+
+## `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 想要的图标名
+
+打开网址:<https://icones.js.org/>
+
+- 在里面找到某个库,如 `carbon`。
+
+![alt text](./assets/5-4.png)
+
+- 搜索想要的图表,如 `avatar`,出现的搜索结果,查看类名,也可以点击图标,会出现详情( `details` 里面)。
+
+![alt text](./assets/5-5.png)
+
+![alt text](./assets/5-6.png)
+
+- 如上图( `details` 里面),拿到 `carbon:user-avatar`。
+
+### 3. 编写代码
+
+- 代码里面 `class` 填写 `i-carbon-user-avatar`(所有的单词用中划线连接即可)并且支持改颜色。
+
+```html
+<view class="i-carbon-user-avatar text-red" />
+```
+
+![alt text](./assets/5-7.png)
+
+> 如果图标没有预览效果,请安装 `VSCode` 插件 `antfu.iconify`。
+
+预览效果:
+
+![alt text](./assets/5-8.png)
+
+### 4. 动态图标名
+
+昨天有网友反馈,`UnoCSS Icons` 无法使用动态类名,我来试试:(我先说结论:是支持的!)
+
+```ts
+const iconName = ref<string>('i-carbon-car')
+onLoad(() => {
+  setTimeout(() => {
+    iconName.value = 'i-carbon-user-avatar'
+  }, 1000)
+})
+```
+
+```html
+<view :class="iconName" />
+```
+
+一秒后会由 `i-carbon-car`(一辆车) 变成 `i-carbon-user-avatar`(一个头像),一切都是 OK 的。
+
+> 但是注意,跨文件的话动态图标名不能生效。
+
+## iconfont 图标库
+
+`iconfont` 同样有海量免费的图标,同时支持上传自己的图标。公司项目通常会有自己的图标,由专业的 `UI设计师` 设计,这时通常会使用 `iconfont` 方式使用图标。
+
+- 1. 打开`阿里巴巴矢量图标库 iconfont`,地址:[https://www.iconfont.cn/](https://www.iconfont.cn/),并登录。
+- 2. 寻找需要的图标,加入项目,也可以上传自己的图标。
+- 3. 图标方式选择 `Font class`,`项目设置` 勾选上 `base64`,否则`非H5端` 不支持,然后点击生成链接。
+
+![alt text](./assets/5-9.png)
+![alt text](./assets/5-10.png)
+
+- 4. 把上面的 `css` 链接里面的内容写入在 `style/iconfont.css`,并引入到 `style/index.scss`。
+- 5. 页面上直接写 `<i class="iconfont icon-package text-red"></i>` 即可!
+
+```html
+<view class="m-4">
+  <text mr-2>iconfont:</text>
+  <i class="iconfont icon-package text-red"></i>
+  <i class="iconfont icon-chat text-red"></i>
+  <i class="iconfont icon-my text-red"></i>
+</view>
+```
+
+预览如下:
+
+![alt text](./assets/5-11.png)
+
+> 上面的选择有疑问的可以看详细版 - [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` 才能兼容多端。
+
+全文完~

+ 181 - 0
docs/base/6-svg.md

@@ -0,0 +1,181 @@
+# SVG 篇
+
+上一章《五、图标篇》主要介绍了 `线上图标` 的使用,今天带给大家本地 `SVG` 图标的使用。
+
+本地 `SVG` 图标使用方式主要有:
+
+- `image + src` 方式
+
+  - `static目录` 图标
+  - `相对目录` 图标
+  - `线上地址` 图标
+
+> **`图片`** 也是使用上面几种方式。
+
+## `image + src` 方式
+
+根据图片地址不同,分为 2 种:`static目录`图标 , `相对目录`图标。
+
+### 1. `static目录` 图标
+
+这种方式直接编写代码即可,如下:
+
+```html
+<image src="/static/svg/demo.svg" mode="scaleToFill" class="h-20 w-20" />
+```
+
+### 2. `相对目录` 图标
+
+这种方式需要先引入,再使用,代码编写如下:
+
+```html
+<template>
+  <image :src="iconUrl" mode="scaleToFill" class="h-20 w-20" />
+</template>
+
+<script lang="ts" setup>
+  import iconUrl from './demo.svg'
+</script>
+```
+
+### 3. `线上地址` 图标
+
+这种方式直接使用,代码编写如下:
+
+```html
+<template>
+  <image src="https://xxx.com/demo.svg" mode="scaleToFill" class="h-20 w-20" />
+</template>
+```
+
+## 其他
+
+> `SvgComponent` 方式 和 `SvgIcon` 方式,仅 `H5端` 适用,感兴趣的可以阅读下
+
+:::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
+<template>
+  <image :src="iconUrl" mode="scaleToFill" class="h-20 w-20" />
+</template>
+```
+
+- Raw
+
+SVGs can be imported as strings using the `?raw` suffix:
+
+```js
+import iconRaw from './my-icon.svg?raw'
+// '<?xml version="1.0"?>...'
+```
+
+Used in template:
+
+```html
+<template>{{ iconRaw }}</template>
+```
+
+- Component
+
+SVGs can be explicitly imported as Vue components using the `?component` suffix:
+
+```js
+import IconComponent from './my-icon.svg?component'
+// <IconComponent />
+```
+
+Used in template:
+
+```html
+<template>
+  <IconComponent />
+</template>
+```
+
+但是目前经过测试,只有 `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
+<template>
+  <svg aria-hidden="true">
+    <use :href="symbolId" :fill="color" />
+  </svg>
+</template>
+
+<script lang="ts" setup name="SvgIcon">
+  const props = withDefaults(
+    defineProps<{
+      prefix?: string
+      name: string
+      color?: string
+    }>(),
+    {
+      prefix: 'icon',
+      name: '',
+      color: '#333',
+    },
+  )
+  const symbolId = computed(() => `#${props.prefix}-${props.name}`)
+</script>
+```
+
+使用方式如下:
+
+```html
+<!-- src/assets/demo.svg -->
+<SvgIcon name="demo" class="h-20 w-20"></SvgIcon>
+
+<!-- src/assets/dir/demo.svg -->
+<SvgIcon name="dir-demo" class="h-20 w-20"></SvgIcon>
+```
+
+> `SvgComponent` 依赖 `vite-svg-loader` 插件
+>
+> `SvgIcon` 依赖 `vite-plugin-svg-icons` 插件
+
+:::
+
+## 总结
+
+本地 `svg` 的使用方式,如果要全端适配,那就只能使用 `image + src` 的方式。
+
+> `SvgComponent` 依赖 `vite-svg-loader` 插件
+>
+> `SvgIcon` 依赖 `vite-plugin-svg-icons` 插件
+
+其他 2 种方式 —— `SvgComponent` + `SvgIcon` 仅 `h5` 端生效,其他端都不能用,既然不能使用,那就删了,对应的 2 个插件也一起删了,目前 `base` 分支已经删了。
+
+全文完~

+ 120 - 0
docs/base/7-ui.md

@@ -0,0 +1,120 @@
+# 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 库的安装类似,不再赘述。
+
+全文完~

+ 163 - 0
docs/base/8-request.md

@@ -0,0 +1,163 @@
+# 请求篇
+
+本篇分为三块内容:
+
+- 普通请求
+- 图片上传
+- 多后台地址
+
+## 普通请求
+
+普通请求分 2 种处理,一种是只在页面请求一次的一次性请求,这种请求占大多数;一种是项目多处用到的请求,这种请求占小部分,需要单独编写一个请求函数放到 `api文件夹` or `service文件夹`。
+
+> `unibest` 里面是使用 `service文件夹` 后面不再说明。
+
+下面来分别演示:
+
+### 一次性请求
+
+`template` 部分编码如下:
+
+```html
+<template>
+  <button @click="run">请求</button>
+  <view v-if="loading" class="text-blue h-10">请求中...</view>
+  <view v-if="error" class="text-red h-10">请求错误</view>
+  <view v-else class="text-green h-10">{{ JSON.stringify(data) }}</view>
+</template>
+```
+
+`script` 部分使用 `菲鸽` 封装好的 `useRequest` 即可实现请求状态一体化,如下:
+
+```ts
+<script setup>
+type IFooItem = { name: string }
+const { loading, error, data, run } = useRequest<IFooItem>(() => httpGet('/foo', { name: '菲鸽' }))
+</script>
+```
+
+看吧,使用非常简单。
+
+### 重复性请求
+
+`重复性请求` 与 `一次性请求` 的 `html部分` 是一样的,唯一的区别是 `请求函数` 放到了 `service文件夹`,如下所示:
+
+```ts
+<script setup>
+import { getFooAPI, IFooItem } from '@/service/index/foo' // 看这里
+const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'))
+</script>
+```
+
+对应的 `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<IFooItem>({
+    url: `/foo`,
+    method: 'GET',
+    query: { name },
+  })
+}
+
+/** GET 请求 - 再次简化,看大家是否喜欢这种简化 */
+export const getFooAPI2 = (name: string) => {
+  return httpGet<IFooItem>('/foo', { name })
+}
+```
+
+依然非常简洁,深受妹子喜爱。
+
+## 图片上传
+
+`template` 部分编码如下:
+
+```html
+<template>
+  <view class="p-4 text-center">
+    <wd-button @click="run">选择图片并上传</wd-button>
+    <view v-if="loading" class="text-blue h-10">上传...</view>
+    <template v-else>
+      <view class="m-2">上传后返回的图片地址:</view>
+      <view class="m-2">{{ data }}</view>
+      <view class="h-80 w-full">
+        <image v-if="data" :src="data" mode="scaleToFill" />
+      </view>
+    </template>
+  </view>
+</template>
+```
+
+`script` 部分使用 `菲鸽` 封装好的 `useUpload` 即可实现请求状态一体化,如下:
+
+```ts
+<script lang="ts" setup>
+const { loading, data, run } = useUpload<string>({ user: '菲鸽' })
+</script>
+```
+
+使用非常简单,深受汉子和妹子的喜爱。
+
+## 多后台地址
+
+上面的 `普通请求` 默认是只有一个请求地址的,在 `.env` 里面配置 `VITE_SERVER_BASEURL`,如下:
+
+```text
+VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
+```
+
+并且在 `src/interceptors/request.ts` 里面有设置:
+
+- 如果是 `http` 开头的请求路径,则直接请求
+- 如果不是,则拼接上 `VITE_SERVER_BASEURL`
+
+![alt text](./assets/8-1.png)
+
+但在多后台地址时就不能这么玩了,需要处理如下:(关注上图的箭头部分)
+
+```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<IFooItem>({
+    url: `/cms/foo`, // 看这里,前缀不用!!!
+    method: 'GET',
+    query: { name },
+  })
+}
+```
+
+## 环境变量配置
+
+- `普通请求` 需要在 `.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'
+```
+
+全文完~

+ 165 - 0
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
+<template>
+  <view class="flex justify-center items-center text-blue-500 mt-4 mb-4">
+    <view class="w-20">Count: {{ countStore.count }}</view>
+    <button class="ml-2 mr-2" @click="countStore.decrement">-1</button>
+    <button class="ml-2 mr-2" @click="countStore.increment">+1</button>
+    <button class="ml-2 mr-2" @click="countStore.reset">重置</button>
+  </view>
+</template>
+
+<script lang="ts" setup>
+import { useCountStore } from '@/store'
+
+const countStore = useCountStore()
+</script>
+```
+
+## 简单状态
+
+你可以直接使用 `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]
+<script setup lang="ts">
+import useCount from './useCount.ts'
+const { globalCount, localCount, increment } = useCount()
+</script>
+
+<template>
+  <button @click="increment()">
+    {{ globalCount }}
+    {{ localCount }}
+  </button>
+</template>
+```
+
+## 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]
+<script setup lang="ts">
+import { countStore } from './count.ts'
+</script>
+
+<template>
+  <button @click="countStore.increment()">
+    {{ countStore.count }}
+  </button>
+</template>
+```
+
+## 总结
+
+本文介绍了 `unibest` 里面状态管理的 `2` 种方式:`pinia` 全局状态 和 `ref\reactive` 简单状态,分别演示了如何定义状态和使用状态。
+
+注意需要灵活使用 `pinia` 和 `简单状态`,局部的状态尽量使用 `简单状态` 的方式来处理,减少 `pinia` 里面全局变量的数量。
+
+全文完~

BIN=BIN
docs/base/assets/1-1.png


BIN=BIN
docs/base/assets/10-1.png


BIN=BIN
docs/base/assets/10-2.png


BIN=BIN
docs/base/assets/10-3.png


BIN=BIN
docs/base/assets/10-android.mp4


BIN=BIN
docs/base/assets/10-ios.mp4


BIN=BIN
docs/base/assets/11-1.png


BIN=BIN
docs/base/assets/11-10.png


BIN=BIN
docs/base/assets/11-100.png


BIN=BIN
docs/base/assets/11-11.png


BIN=BIN
docs/base/assets/11-12.png


BIN=BIN
docs/base/assets/11-13.png


BIN=BIN
docs/base/assets/11-2.png


BIN=BIN
docs/base/assets/11-3.png


BIN=BIN
docs/base/assets/11-4.png


BIN=BIN
docs/base/assets/11-5.png


BIN=BIN
docs/base/assets/11-6.png


BIN=BIN
docs/base/assets/11-7.png


BIN=BIN
docs/base/assets/11-8.png


BIN=BIN
docs/base/assets/11-9.png


BIN=BIN
docs/base/assets/13-1.png


BIN=BIN
docs/base/assets/13-2.png


BIN=BIN
docs/base/assets/13-3.png


BIN=BIN
docs/base/assets/13-4.png


BIN=BIN
docs/base/assets/13-5.png


BIN=BIN
docs/base/assets/13-6.png


BIN=BIN
docs/base/assets/13-7.png


BIN=BIN
docs/base/assets/13-8.png


BIN=BIN
docs/base/assets/14-1.png


BIN=BIN
docs/base/assets/14-2.png


BIN=BIN
docs/base/assets/14-3.png


BIN=BIN
docs/base/assets/14-4.png


BIN=BIN
docs/base/assets/14-5.png


BIN=BIN
docs/base/assets/14-6.png


BIN=BIN
docs/base/assets/15-1.png


BIN=BIN
docs/base/assets/15-2.png


BIN=BIN
docs/base/assets/15-3.png


BIN=BIN
docs/base/assets/15-4.png


BIN=BIN
docs/base/assets/15-5.png


BIN=BIN
docs/base/assets/15-6.png


BIN=BIN
docs/base/assets/2-1.png


BIN=BIN
docs/base/assets/2-2.png


BIN=BIN
docs/base/assets/2-3.png


BIN=BIN
docs/base/assets/2-4.gif


BIN=BIN
docs/base/assets/3-1.png


BIN=BIN
docs/base/assets/4-1.png


BIN=BIN
docs/base/assets/4-2.png


BIN=BIN
docs/base/assets/4-3.png


BIN=BIN
docs/base/assets/4-4.png


BIN=BIN
docs/base/assets/4-5.png


BIN=BIN
docs/base/assets/5-1.png


BIN=BIN
docs/base/assets/5-10.png


+ 0 - 0
docs/base/assets/5-100.png


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio