diff --git a/.cursor/rules/development-workflow.mdc b/.cursor/rules/development-workflow.mdc
index 7a8c901..4da3f43 100644
--- a/.cursor/rules/development-workflow.mdc
+++ b/.cursor/rules/development-workflow.mdc
@@ -5,6 +5,7 @@
2. 开发环境:
- H5: `pnpm dev` 或 `pnpm dev:h5`
- 微信小程序: `pnpm dev:mp`
+ - 支付宝小程序: `pnpm dev:mp-alipay`
- APP: `pnpm dev:app`
## 代码规范
@@ -15,7 +16,8 @@
## 构建和部署
- H5 构建:`pnpm build:h5`
-- 小程序构建:`pnpm build:mp`
+- 微信小程序构建:`pnpm build:mp`
+- 支付宝小程序构建:`pnpm build:mp-alipay`
- APP 构建:`pnpm build:app`
- 类型检查:`pnpm type-check`
diff --git a/.cursor/rules/project-overview.mdc b/.cursor/rules/project-overview.mdc
index 335b480..f0d613e 100644
--- a/.cursor/rules/project-overview.mdc
+++ b/.cursor/rules/project-overview.mdc
@@ -8,7 +8,7 @@ alwaysApply: true
## 项目特点
- 支持 H5、小程序、APP 多平台开发
- 使用最新的前端技术栈
-- 内置约定式路由、layout布局、请求封装等功能
+- 内置约定式路由、layout布局、请求封装、登录拦截、自定义tabbar等功能
- 无需依赖 HBuilderX,支持命令行开发
## 核心配置文件
@@ -26,9 +26,11 @@ alwaysApply: true
- `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/uni-app-patterns.mdc b/.cursor/rules/uni-app-patterns.mdc
index 956566d..143b0b6 100644
--- a/.cursor/rules/uni-app-patterns.mdc
+++ b/.cursor/rules/uni-app-patterns.mdc
@@ -3,12 +3,12 @@
## 页面开发
- 页面文件放在 [src/pages/](mdc:src/pages/) 目录下
- 使用约定式路由,文件名即路由路径
-- 页面配置在仅需要在 `route-block` 中配置标题等内容即可,会自动生成到 `pages.json` 中
+- 页面配置在仅需要在 宏`definePage` 中配置标题等内容即可,会自动生成到 `pages.json` 中
## 组件开发
-- 组件文件放在 [src/components/](mdc:src/components/) 目录下
+- 组件文件放在 [src/components/](mdc:src/components/) 或者 [src/pages/xx/components/](mdc:src/pages/xx/components/) 目录下
- 使用 uni-app 内置组件和第三方组件库
-- 支持 wot-design-uni\uv-ui\uview-plus 等多种第三方组件库 和 z-paging 组件
+- 支持 wot-ui\uview-pro\uv-ui\sard-ui\uview-plus 等多种第三方组件库 和 z-paging 组件
- 自定义组件遵循 uni-app 组件规范
## 平台适配
diff --git a/.cursor/rules/vue-typescript-patterns.mdc b/.cursor/rules/vue-typescript-patterns.mdc
index f726299..d81cc8f 100644
--- a/.cursor/rules/vue-typescript-patterns.mdc
+++ b/.cursor/rules/vue-typescript-patterns.mdc
@@ -4,10 +4,11 @@
- 使用 Composition API 和 `
-
+
{{ helloKuRoot }},这里可以配置全局的东西
@@ -40,7 +37,5 @@ defineExpose({
-
-
-
+
diff --git a/src/App.vue b/src/App.vue
index 9c47bc2..0ea6924 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -3,10 +3,10 @@ import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
import { navigateToInterceptor } from '@/router/interceptor'
onLaunch((options) => {
- console.log('App Launch', options)
+ console.log('App.vue onLaunch', options)
})
onShow((options) => {
- console.log('App Show', options)
+ console.log('App.vue onShow', options)
// 处理直接进入页面路由的情况:如h5直接输入路由、微信小程序分享后进入等
// https://github.com/unibest-tech/unibest/issues/192
if (options?.path) {
@@ -22,16 +22,5 @@ onHide(() => {
diff --git a/src/hooks/useScroll.md b/src/hooks/useScroll.md
new file mode 100644
index 0000000..bb2eace
--- /dev/null
+++ b/src/hooks/useScroll.md
@@ -0,0 +1,116 @@
+# 上拉刷新和下拉加载更多
+
+在 unibest 框架中,我们通过组合 `useScroll` Hook 可结合 `scroll-view` 组件来轻松实现上拉刷新和下拉加载更多的功能。
+场景一 页面滚动
+
+```
+definePage({
+ style: {
+ navigationBarTitleText: '上拉刷新和下拉加载更多',
+ enablePullDownRefresh: true,
+ onReachBottomDistance: 100,
+ },
+})
+```
+
+场景二 局部滚动 结合 `scroll-view`
+
+## 关键文件
+
+- `src/hooks/useScroll.ts`: 提供了核心的滚动逻辑处理 Hook。
+- `src/pages-sub/demo/scroll.vue`: 一个具体的实现示例页面。
+
+## `useScroll` Hook
+
+`useScroll` 是一个 Vue Composition API Hook,它封装了处理下拉刷新和上拉加载的通用逻辑。
+
+### 主要功能
+
+- **管理加载状态**: 自动处理 `loading`(加载中)、`finished`(已加载全部)和 `error`(加载失败)等状态。
+- **分页逻辑**: 内部维护分页参数(页码 `page` 和每页数量 `pageSize`)。
+- **事件处理**: 提供 `onScrollToLower`(滚动到底部)、`onRefresherRefresh`(下拉刷新)等方法,用于在视图层触发。
+- **数据合并**: 自动将新加载的数据追加到现有列表 `list` 中。
+
+### 使用方法
+
+```typescript
+import { useScroll } from '@/hooks/useScroll'
+import { getList } from '@/service/list' // 你的数据请求API
+
+const {
+ list, // 响应式的数据列表
+ loading, // 是否加载中
+ finished, // 是否已全部加载
+ error, // 是否加载失败
+ onScrollToLower, // 滚动到底部时触发的事件
+ onRefresherRefresh, // 下拉刷新时触发的事件
+} = useScroll(getList) // 将获取数据的API函数传入
+```
+
+## `scroll-view` 组件
+
+`scroll-view` 是 uni-app 提供的可滚动视图区域组件,它提供了一系列属性来支持下拉刷新和上拉加载。
+
+### 关键属性
+
+- `scroll-y`: 允许纵向滚动。
+- `refresher-enabled`: 启用下拉刷新。
+- `refresher-triggered`: 控制下拉刷新动画的显示与隐藏,通过 `loading` 状态绑定。
+- `@scrolltolower`: 滚动到底部时触发的事件,绑定 `onScrollToLower` 方法。
+- `@refresherrefresh`: 触发下拉刷新时触发的事件,绑定 `onRefresherRefresh` 方法。
+
+## 示例代码
+
+以下是 `src/pages-sub/demo/scroll.vue` 中的核心代码,展示了如何将 `useScroll` 和 `scroll-view` 结合使用。
+
+```vue
+
+
+
+
+ {{ item.name }}
+
+
+
+ 加载中...
+ 没有更多了
+ 加载失败,请重试
+
+
+
+
+
+
+
+```
+
+## 实现步骤总结
+
+1. **创建API**: 确保你有一个返回分页数据的API请求函数(例如 `getList`),它应该接受页码和页面大小作为参数。
+2. **调用 `useScroll`**: 在你的页面脚本中,导入并调用 `useScroll` Hook,将你的API函数作为参数传入。
+3. **模板绑定**:
+ - 使用 `scroll-view` 组件作为滚动容器。
+ - 将其 `refresher-triggered` 属性绑定到 `useScroll` 返回的 `loading` 状态。
+ - 将其 `@scrolltolower` 事件绑定到 `onScrollToLower` 方法。
+ - 将其 `@refresherrefresh` 事件绑定到 `onRefresherRefresh` 方法。
+4. **渲染列表**: 使用 `v-for` 指令渲染 `useScroll` 返回的 `list` 数组。
+5. **添加加载提示**: 根据 `loading`, `finished`, `error` 状态,在列表底部显示不同的提示信息,提升用户体验。
+
+通过以上步骤,你就可以在项目中快速集成一个功能完善、体验良好的上拉刷新和下拉加载列表。
\ No newline at end of file
diff --git a/src/http/alova.ts b/src/http/alova.ts
index 133f6af..b7b9ff6 100644
--- a/src/http/alova.ts
+++ b/src/http/alova.ts
@@ -4,7 +4,7 @@ import AdapterUniapp from '@alova/adapter-uniapp'
import { createAlova } from 'alova'
import { createServerTokenAuthentication } from 'alova/client'
import VueHook from 'alova/vue'
-import { LOGIN_PAGE } from '@/router/config'
+import { toLoginPage } from '@/utils/toLoginPage'
import { ContentTypeEnum, ResultEnum, ShowMessage } from './tools/enum'
// 配置动态Tag
@@ -31,7 +31,7 @@ const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthenticati
}
catch (error) {
// 切换到登录页
- await uni.reLaunch({ url: LOGIN_PAGE })
+ toLoginPage({ mode: 'reLaunch' })
throw error
}
},
diff --git a/src/http/http.ts b/src/http/http.ts
index eafe8e0..88f8508 100644
--- a/src/http/http.ts
+++ b/src/http/http.ts
@@ -1,9 +1,9 @@
import type { IDoubleTokenRes } from '@/api/types/login'
import type { CustomRequestOptions, IResponse } from '@/http/types'
import { nextTick } from 'vue'
-import { LOGIN_PAGE } from '@/router/config'
import { useTokenStore } from '@/store/token'
import { isDoubleTokenMode } from '@/utils'
+import { toLoginPage } from '@/utils/toLoginPage'
import { ResultEnum } from './tools/enum'
// 刷新 token 状态管理
@@ -32,7 +32,7 @@ export function http(options: CustomRequestOptions) {
if (!isDoubleTokenMode) {
// 未启用双token策略,清理用户信息,跳转到登录页
tokenStore.logout()
- uni.navigateTo({ url: LOGIN_PAGE })
+ toLoginPage()
return reject(res)
}
@@ -80,7 +80,7 @@ export function http(options: CustomRequestOptions) {
await tokenStore.logout()
// 跳转到登录页
setTimeout(() => {
- uni.navigateTo({ url: LOGIN_PAGE })
+ toLoginPage()
}, 2000)
}
finally {
@@ -96,9 +96,12 @@ export function http(options: CustomRequestOptions) {
if (res.statusCode >= 200 && res.statusCode < 300) {
// 处理业务逻辑错误
if (code !== ResultEnum.Success0 && code !== ResultEnum.Success200) {
- throw new Error(`请求错误[${code}]:${responseData.message || responseData.msg}`)
+ uni.showToast({
+ icon: 'none',
+ title: responseData.msg || responseData.message || '请求错误',
+ })
}
- return resolve(responseData.data as T)
+ return resolve(responseData.data)
}
// 处理其他错误
diff --git a/src/http/types.ts b/src/http/types.ts
index 42ac8e9..8187822 100644
--- a/src/http/types.ts
+++ b/src/http/types.ts
@@ -7,6 +7,9 @@ export type CustomRequestOptions = UniApp.RequestOptions & {
hideErrorToast?: boolean
} & IUniUploadFileOptions // 添加uni.uploadFile参数类型
+/** 主要提供给 openapi-ts-request 生成的代码使用 */
+export type CustomRequestOptions_ = Omit
+
export interface HttpRequestResult {
promise: Promise
requestTask: UniApp.RequestTask
diff --git a/src/http/vue-query.ts b/src/http/vue-query.ts
index 31d1eb3..69ca80d 100644
--- a/src/http/vue-query.ts
+++ b/src/http/vue-query.ts
@@ -4,7 +4,7 @@ import { http } from './http'
/*
* openapi-ts-request 工具的 request 跨客户端适配方法
*/
-export default function request(
+export default function request(
url: string,
options: Omit & {
params?: Record
@@ -26,5 +26,5 @@ export default function request(
delete requestOptions.headers
}
- return http(requestOptions)
+ return http(requestOptions)
}
diff --git a/src/layouts/default.vue b/src/layouts/default.vue
index 88a55d4..ba4672f 100644
--- a/src/layouts/default.vue
+++ b/src/layouts/default.vue
@@ -1,10 +1,3 @@
-
-
diff --git a/src/pages-fg/404/README.md b/src/pages-fg/404/README.md
deleted file mode 100644
index ecc8aa4..0000000
--- a/src/pages-fg/404/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# 404 页面
-
-`404页面` 只有在路由不存在时才会显示,如果您不需要可以删除该页面。但是建议保留。
\ No newline at end of file
diff --git a/src/pages-fg/404/index.vue b/src/pages-fg/404/index.vue
deleted file mode 100644
index 533e259..0000000
--- a/src/pages-fg/404/index.vue
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- 404
- 页面不存在
-
-
-
-
-
diff --git a/src/pages-fg/REAME.md b/src/pages-fg/REAME.md
deleted file mode 100644
index 55479de..0000000
--- a/src/pages-fg/REAME.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# pages-fg 说明
-
-为了尽量减少主包的大小,一些无关紧要但经常需要的页面(如登录页、注册页、404页等)放在了 `pages-fg` 目录下。
diff --git a/src/pages-fg/login/README.md b/src/pages-fg/login/README.md
deleted file mode 100644
index c851a76..0000000
--- a/src/pages-fg/login/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# 登录页
-需要输入账号、密码/验证码的登录页。
-
-## 适用性
-
-本页面主要用于 `h5` 和 `APP`。
-
-小程序通常有平台的登录方式 `uni.login` 通常用不到登录页,所以不适用于 `小程序`。(即默认情况下,小程序环境是不会走登录拦截逻辑的。)
-
-但是如果您的小程序也需要现实的 `登录页` 那也是可以使用的。
-
-在 `src/router/config.ts` 中有一个变量 `LOGIN_PAGE_ENABLE_IN_MP` 来控制是否在小程序中使用 `H5的登录页`。
-
-更多信息请看 `src/router` 文件夹的内容。
-
-## 登录跳转
-
-目前登录的跳转逻辑主要在 `src/router/interceptor.ts` 和 `src/pages/login/login.vue` 里面,默认会在登录后自动重定向到来源/配置的页面。
-
-如果与您的业务不符,您可以自行修改。
diff --git a/src/pages-fg/login/login.vue b/src/pages-fg/login/login.vue
deleted file mode 100644
index 0fa5e95..0000000
--- a/src/pages-fg/login/login.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
-
-
- 登录页
-
-
-
-
-
-
diff --git a/src/pages-fg/login/register.vue b/src/pages-fg/login/register.vue
deleted file mode 100644
index e9809f0..0000000
--- a/src/pages-fg/login/register.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
- 注册页
-
-
-
-
-
-
diff --git a/src/pages-sub/about/about.vue b/src/pages-sub/about/about.vue
deleted file mode 100644
index 005200d..0000000
--- a/src/pages-sub/about/about.vue
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
-
-
-
-
-
- 请求调用、unocss、static图片
-
-
-
-
-
- 当前是否登录:{{ tokenStore.hasLogin }}
-
-
-
-
-
-
-
-
-
-
-
-
- 简单hooks(非z-paging组件)
-
-
-
-
-
-
-
-
-
- 为了方便脚手架动态生成不同UI模板,本页的按钮统一使用UI库无关的原生button
-
-
-
-
-
diff --git a/src/pages-sub/about/alova.vue b/src/pages-sub/about/alova.vue
deleted file mode 100644
index 4b0c43f..0000000
--- a/src/pages-sub/about/alova.vue
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
- loading...
-
-
-
- 请求数据如下
-
-
- {{ JSON.stringify(data) }}
-
-
-
-
- {{ data?.id }}
-
-
-
-
-
-
-
diff --git a/src/pages-sub/about/components/Upload.vue b/src/pages-sub/about/components/Upload.vue
deleted file mode 100644
index 09547f5..0000000
--- a/src/pages-sub/about/components/Upload.vue
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
- 上传...
-
-
-
- 上传后返回的接口数据:
-
-
- {{ data }}
-
-
-
-
-
-
-
-
-
diff --git a/src/pages-sub/about/components/VBindCss.vue b/src/pages-sub/about/components/VBindCss.vue
deleted file mode 100644
index bc5a048..0000000
--- a/src/pages-sub/about/components/VBindCss.vue
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
- 测试v-bind css变量的具体文案
-
-
-
-
diff --git a/src/pages-sub/about/components/request-openapi.vue b/src/pages-sub/about/components/request-openapi.vue
deleted file mode 100644
index 64fb095..0000000
--- a/src/pages-sub/about/components/request-openapi.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
- 1)直接使用 openapi 生成的请求
-
-
-
-
- 请求数据如下
-
-
- {{ JSON.stringify(data) }}
-
-
-
- 2)直接使用 openapi + useRequest 生成的请求
-
-
-
-
-
- 请求数据如下
-
-
- {{ JSON.stringify(data2) }}
-
-
-
diff --git a/src/pages-sub/about/components/request.vue b/src/pages-sub/about/components/request.vue
deleted file mode 100644
index 73db16b..0000000
--- a/src/pages-sub/about/components/request.vue
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
-
- pages 里面的 vue 文件会扫描成页面,将自动添加到 pages.json 里面。
-
-
- 但是 components 里面的 vue 不会。
-
-
-
-
-
-
-
- loading...
-
-
-
- 错误: {{ error.message }}
-
-
- 错误: 未知错误
-
-
-
- 请求数据如下
-
-
- {{ JSON.stringify(data) }}
-
-
-
-
-
-
-
-
-
diff --git a/src/pages-sub/demo/components/request.vue b/src/pages-sub/demo/components/request.vue
deleted file mode 100644
index 7d7bff1..0000000
--- a/src/pages-sub/demo/components/request.vue
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
- loading...
-
-
-
- 请求数据如下
-
-
- {{ JSON.stringify(data) }}
-
-
-
-
-
-
-
-
diff --git a/src/pages-sub/demo/index.vue b/src/pages-sub/demo/index.vue
deleted file mode 100644
index 3d51c9a..0000000
--- a/src/pages-sub/demo/index.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
- http://localhost:9000/#/pages-sub/demo/index
-
-
- 分包页面demo
-
-
- 分包页面里面的components示例
-
-
-
-
-
-
-
-
-
diff --git a/src/pages-sub/demo/scroll.vue b/src/pages-sub/demo/scroll.vue
deleted file mode 100644
index 7961a30..0000000
--- a/src/pages-sub/demo/scroll.vue
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
- 加载失败,请重试
-
-
-
- {{ item.name }}
-
-
- 加载中...
-
-
- 没有更多了
-
-
-
-
diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue
index 687d096..27b81b8 100644
--- a/src/pages/index/index.vue
+++ b/src/pages/index/index.vue
@@ -1,7 +1,4 @@
-
+
@@ -62,53 +49,5 @@ function gotoAbout() {
https://unibest.tech
-
-
-
-
- 新手请看必看章节1:
-
-
-
-
-
- 新手请看必看章节1:
-
- https://unibest.tech/base/3-plugin
-
-
-
-
-
-
- 新手请看必看章节2:
-
-
-
-
-
- 新手请看必看章节2:
-
- https://unibest.tech/base/14-faq
-
-
-
-
-
-
- 设置主题变量
-
-
-
- UI组件官网:
- https://wot-design-uni.cn
-
-
-
-
- 前往示例页
-
-
-
diff --git a/src/pages/me/me.vue b/src/pages/me/me.vue
index c43a47c..5df9e2e 100644
--- a/src/pages/me/me.vue
+++ b/src/pages/me/me.vue
@@ -1,214 +1,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ userInfo.username }}
-
-
-
- ID: {{ userInfo.userId }}
-
-
-
-
-
- {{ JSON.stringify(userInfo, null, 2) }}
-
-
-
-
-
-
-
-
+
+ 我的页面
-
-
diff --git a/src/router/config.ts b/src/router/config.ts
deleted file mode 100644
index 2d0e52d..0000000
--- a/src/router/config.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { getAllPages } from '@/utils'
-
-export const LOGIN_STRATEGY_MAP = {
- DEFAULT_NO_NEED_LOGIN: 0, // 黑名单策略,默认可以进入APP
- DEFAULT_NEED_LOGIN: 1, // 白名单策略,默认不可以进入APP,需要强制登录
-}
-// TODO: 1/3 登录策略,默认使用`无需登录策略`,即默认不需要登录就可以访问
-export const LOGIN_STRATEGY = LOGIN_STRATEGY_MAP.DEFAULT_NO_NEED_LOGIN
-export const isNeedLoginMode = LOGIN_STRATEGY === LOGIN_STRATEGY_MAP.DEFAULT_NEED_LOGIN
-
-export const LOGIN_PAGE = '/pages-fg/login/login'
-export const REGISTER_PAGE = '/pages-fg/login/register'
-export const NOT_FOUND_PAGE = '/pages-fg/404/index'
-
-export const LOGIN_PAGE_LIST = [LOGIN_PAGE, REGISTER_PAGE]
-
-// 在 definePage 里面配置了 excludeLoginPath 的页面,功能与 EXCLUDE_LOGIN_PATH_LIST 相同
-export const excludeLoginPathList = getAllPages('excludeLoginPath').map(page => page.path)
-
-// 排除在外的列表,白名单策略指白名单列表,黑名单策略指黑名单列表
-// TODO: 2/3 在 definePage 配置 excludeLoginPath,或者在下面配置 EXCLUDE_LOGIN_PATH_LIST
-export const EXCLUDE_LOGIN_PATH_LIST = [
- '/pages/xxx/index', // 示例值
- '/pages-sub/xxx/index', // 示例值
- ...excludeLoginPathList, // 都是以 / 开头的 path
-]
-
-// 在小程序里面是否使用H5的登录页,默认为 false
-// 如果为 true 则复用 h5 的登录逻辑
-// TODO: 3/3 确定自己的登录页是否需要在小程序里面使用
-export const LOGIN_PAGE_ENABLE_IN_MP = false
diff --git a/src/router/interceptor.ts b/src/router/interceptor.ts
index 714fea4..b4092d5 100644
--- a/src/router/interceptor.ts
+++ b/src/router/interceptor.ts
@@ -1,23 +1,12 @@
-import { isMp } from '@uni-helper/uni-env'
/**
* by 菲鸽 on 2025-08-19
* 路由拦截,通常也是登录拦截
* 黑、白名单的配置,请看 config.ts 文件, EXCLUDE_LOGIN_PATH_LIST
*/
-import { useTokenStore } from '@/store/token'
-import { isPageTabbar, tabbarStore } from '@/tabbar/store'
-import { getAllPages, getLastPage, HOME_PAGE, parseUrlToObj } from '@/utils/index'
-import { EXCLUDE_LOGIN_PATH_LIST, isNeedLoginMode, LOGIN_PAGE, LOGIN_PAGE_ENABLE_IN_MP, NOT_FOUND_PAGE } from './config'
+import { tabbarStore } from '@/tabbar/store'
+import { getAllPages, getLastPage, parseUrlToObj } from '@/utils/index'
export const FG_LOG_ENABLE = false
-export function judgeIsExcludePath(path: string) {
- const isDev = import.meta.env.DEV
- if (!isDev) {
- return EXCLUDE_LOGIN_PATH_LIST.includes(path)
- }
- const allExcludeLoginPages = getAllPages('excludeLoginPath') // dev 环境下,需要每次都重新获取,否则新配置就不会生效
- return EXCLUDE_LOGIN_PATH_LIST.includes(path) || (isDev && allExcludeLoginPages.some(page => page.path === path))
-}
export const navigateToInterceptor = {
// 注意,这里的url是 '/' 开头的,如 '/pages/index/index',跟 'pages.json' 里面的 path 不同
@@ -44,76 +33,19 @@ export const navigateToInterceptor = {
}
// 处理路由不存在的情况
- if (getAllPages().every(page => page.path !== path) && path !== '/') {
+ if (path !== '/' && !getAllPages().some(page => page.path !== path)) {
console.warn('路由不存在:', path)
- uni.navigateTo({ url: NOT_FOUND_PAGE })
return false // 明确表示阻止原路由继续执行
}
+ // 插件页面
+ if (url.startsWith('plugin://')) {
+ FG_LOG_ENABLE && console.log('路由拦截器 4: plugin:// 路径 ==>', url)
+ path = url
+ }
+
// 处理直接进入路由非首页时,tabbarIndex 不正确的问题
tabbarStore.setAutoCurIdx(path)
-
- // 小程序里面使用平台自带的登录,则不走下面的逻辑
- if (isMp && !LOGIN_PAGE_ENABLE_IN_MP) {
- return true // 明确表示允许路由继续执行
- }
-
- const tokenStore = useTokenStore()
- FG_LOG_ENABLE && console.log('tokenStore.hasLogin:', tokenStore.hasLogin)
-
- // 不管黑白名单,登录了就直接去吧(但是当前不能是登录页)
- if (tokenStore.hasLogin) {
- if (path !== LOGIN_PAGE) {
- return true // 明确表示允许路由继续执行
- }
- else {
- console.log('已经登录,但是还在登录页', myQuery.redirect)
- const url = myQuery.redirect || HOME_PAGE
- if (isPageTabbar(url)) {
- uni.switchTab({ url })
- }
- else {
- uni.navigateTo({ url })
- }
- return false // 明确表示阻止原路由继续执行
- }
- }
- let fullPath = path
-
- if (Object.keys(myQuery).length) {
- fullPath += `?${Object.keys(myQuery).map(key => `${key}=${myQuery[key]}`).join('&')}`
- }
- const redirectUrl = `${LOGIN_PAGE}?redirect=${encodeURIComponent(fullPath)}`
-
- // #region 1/2 默认需要登录的情况(白名单策略) ---------------------------
- if (isNeedLoginMode) {
- // 需要登录里面的 EXCLUDE_LOGIN_PATH_LIST 表示白名单,可以直接通过
- if (judgeIsExcludePath(path)) {
- return true // 明确表示允许路由继续执行
- }
- // 否则需要重定向到登录页
- else {
- if (path === LOGIN_PAGE) {
- return true // 明确表示允许路由继续执行
- }
- FG_LOG_ENABLE && console.log('1 isNeedLogin(白名单策略) redirectUrl:', redirectUrl)
- uni.navigateTo({ url: redirectUrl })
- return false // 明确表示阻止原路由继续执行
- }
- }
- // #endregion 1/2 默认需要登录的情况(白名单策略) ---------------------------
-
- // #region 2/2 默认不需要登录的情况(黑名单策略) ---------------------------
- else {
- // 不需要登录里面的 EXCLUDE_LOGIN_PATH_LIST 表示黑名单,需要重定向到登录页
- if (judgeIsExcludePath(path)) {
- FG_LOG_ENABLE && console.log('2 isNeedLogin(黑名单策略) redirectUrl:', redirectUrl)
- uni.navigateTo({ url: redirectUrl })
- return false // 修改为false,阻止原路由继续执行
- }
- return true // 明确表示允许路由继续执行
- }
- // #endregion 2/2 默认不需要登录的情况(黑名单策略) ---------------------------
},
}
diff --git a/src/service/info.ts b/src/service/info.ts
index b3f8e6b..fe09da5 100644
--- a/src/service/info.ts
+++ b/src/service/info.ts
@@ -1,17 +1,13 @@
/* eslint-disable */
// @ts-ignore
import request from '@/http/vue-query';
-import { CustomRequestOptions } from '@/http/types';
+import { CustomRequestOptions_ } from '@/http/types';
import * as API from './types';
/** 用户信息 GET /user/info */
-export async function infoUsingGet({
- options,
-}: {
- options?: CustomRequestOptions;
-}) {
- return request('/user/info', {
+export function infoUsingGet({ options }: { options?: CustomRequestOptions_ }) {
+ return request('/user/info', {
method: 'GET',
...(options || {}),
});
diff --git a/src/service/listAll.ts b/src/service/listAll.ts
index 92ba293..bc1c683 100644
--- a/src/service/listAll.ts
+++ b/src/service/listAll.ts
@@ -1,18 +1,17 @@
/* eslint-disable */
// @ts-ignore
import request from '@/http/vue-query';
-import { CustomRequestOptions } from '@/http/types';
+import { CustomRequestOptions_ } from '@/http/types';
import * as API from './types';
-const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
/** 用户列表 GET /user/listAll */
-export async function listAllUsingGet({
+export function listAllUsingGet({
options,
}: {
- options?: CustomRequestOptions;
+ options?: CustomRequestOptions_;
}) {
- return request('/user/listAll', {
+ return request('/user/listAll', {
method: 'GET',
...(options || {}),
});
diff --git a/src/static/my-icons/copyright.svg b/src/static/my-icons/copyright.svg
new file mode 100644
index 0000000..8e69a8c
--- /dev/null
+++ b/src/static/my-icons/copyright.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/store/index.ts b/src/store/index.ts
index d5e3770..fe2ead1 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -1,4 +1,4 @@
-import { createPinia } from 'pinia'
+import { createPinia, setActivePinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
const store = createPinia()
@@ -10,10 +10,11 @@ store.use(
},
}),
)
+// 立即激活 Pinia 实例, 这样即使在 app.use(store)之前调用 store 也能正常工作 (解决APP端白屏问题)
+setActivePinia(store)
export default store
// 模块统一导出
-export * from './theme'
export * from './token'
export * from './user'
diff --git a/src/store/theme.ts b/src/store/theme.ts
deleted file mode 100644
index c3f1c55..0000000
--- a/src/store/theme.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import type { ConfigProviderThemeVars } from 'wot-design-uni'
-
-import { defineStore } from 'pinia'
-
-export const useThemeStore = defineStore(
- 'theme-store',
- () => {
- /** 主题 */
- const theme = ref<'light' | 'dark'>('light')
-
- /** 主题变量 */
- const themeVars = ref({
- // colorTheme: 'red',
- // buttonPrimaryBgColor: '#07c160',
- // buttonPrimaryColor: '#07c160',
- })
-
- /** 设置主题变量 */
- const setThemeVars = (partialVars: Partial) => {
- themeVars.value = { ...themeVars.value, ...partialVars }
- }
-
- /** 切换主题 */
- const toggleTheme = () => {
- theme.value = theme.value === 'light' ? 'dark' : 'light'
- }
-
- return {
- /** 设置主题变量 */
- setThemeVars,
- /** 切换主题 */
- toggleTheme,
- /** 主题变量 */
- themeVars,
- /** 主题 */
- theme,
- }
- },
- {
- persist: true,
- },
-)
diff --git a/src/tabbar/README.md b/src/tabbar/README.md
index c2b89eb..07d161d 100644
--- a/src/tabbar/README.md
+++ b/src/tabbar/README.md
@@ -5,17 +5,19 @@
`tabbar` 分为 `4 种` 情况:
- 0 `无 tabbar`,只有一个页面入口,底部无 `tabbar` 显示;常用语临时活动页。
-- 1 `原生 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。
- - 优势:原生自带的 tabbar,最先渲染,有缓存。
+
+- 1 `原生 tabbar`,使用 `switchTab` 切换 `tabbar`,`tabbar` 页面有缓存。
+ - 优势:原生自带的 `tabbar`,最先渲染,有缓存。
- 劣势:只能使用 2 组图片来切换选中和非选中状态,修改颜色只能重新换图片(或者用 iconfont)。
-- 2 `有缓存自定义 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。
+
+- 2 `有缓存自定义 tabbar`,使用 `switchTab` 切换 `tabbar`,`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。
- 优势:可以随意配置自己想要的 `svg icon`,切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。
- - 劣势:首次点击 tababr 会闪烁。
+ - 劣势:首次点击 `tabbar` 会闪烁。
+
- 3 `无缓存自定义 tabbar`,使用 `navigateTo` 切换 `tabbar`,`tabbar` 页面无缓存。使用了第三方 UI 库的 `tabbar` 组件。
- 优势:可以随意配置自己想要的 svg icon,切换字体颜色方便。可以实现各种花里胡哨的动效等。
- 劣势:首次点击 `tababr` 会闪烁,无缓存。
-
> 注意:花里胡哨的效果需要自己实现,本模版不提供。
## tabbar 配置说明
@@ -28,6 +30,7 @@
`config.ts` 专门配置 `nativeTabbarList` 和 `customTabbarList` 的相关信息,请按照文件里面的注释配置相关项。
使用 `原生tabbar` 时,不需要关心下面2个文件:
+
- `store.ts` ,专门给 `自定义 tabbar` 提供状态管理,代码几乎不需要修改。
- `index.vue` ,专门给 `自定义 tabbar` 提供渲染逻辑,代码可以稍微修改,以符合自己的需求。
@@ -42,6 +45,7 @@
"icon": "home",
}
```
+
- unocss 图标
```js
@@ -54,6 +58,7 @@
icon: 'i-carbon-code',
}
```
+
- iconfont 图标
```js
@@ -64,6 +69,7 @@
icon: 'iconfont icon-my',
}
```
+
- image 本地图片
```js
diff --git a/src/tabbar/config.ts b/src/tabbar/config.ts
index 2656ea4..141c07a 100644
--- a/src/tabbar/config.ts
+++ b/src/tabbar/config.ts
@@ -1,4 +1,5 @@
import type { TabBar } from '@uni-helper/vite-plugin-uni-pages'
+import type { CustomTabBarItem, NativeTabBarItem } from './types'
/**
* tabbar 选择的策略,更详细的介绍见 tabbar.md 文件
@@ -22,8 +23,6 @@ export const TABBAR_STRATEGY_MAP = {
// 如果是使用 CUSTOM_TABBAR(2,3),只需要配置 customTabbarList,nativeTabbarList 不生效
export const selectedTabbarStrategy = TABBAR_STRATEGY_MAP.CUSTOM_TABBAR_WITH_CACHE
-type NativeTabBarItem = TabBar['list'][number]
-
// TODO: 2/3. 使用 NATIVE_TABBAR 时,更新下面的 tabbar 配置
export const nativeTabbarList: NativeTabBarItem[] = [
{
@@ -40,18 +39,6 @@ export const nativeTabbarList: NativeTabBarItem[] = [
},
]
-// badge 显示一个数字或 小红点(样式可以直接在 tabbar/index.vue 里面修改)
-export type CustomTabBarItemBadge = number | 'dot'
-
-export interface CustomTabBarItem {
- text: string
- pagePath: string
- iconType: 'uiLib' | 'unocss' | 'iconfont' | 'image' // 不建议用 image 模式,需要配置2张图
- icon: any // 其实是 string 类型,这里是为了避免 ts 报错 (tabbar/index.vue 里面 uni-icons 那行)
- iconActive?: string // 只有在 image 模式下才需要,传递的是高亮的图片(PS: 不建议用 image 模式)
- badge?: CustomTabBarItemBadge
- isBulge?: boolean // 是否是中间的鼓包tabbarItem
-}
// TODO: 3/3. 使用 CUSTOM_TABBAR(2,3) 时,更新下面的 tabbar 配置
// 如果需要配置鼓包,需要在 'tabbar/store.ts' 里面设置,最后在 `tabbar/index.vue` 里面更改鼓包的图片
export const customTabbarList: CustomTabBarItem[] = [
diff --git a/src/tabbar/index.vue b/src/tabbar/index.vue
index c600530..20f2f10 100644
--- a/src/tabbar/index.vue
+++ b/src/tabbar/index.vue
@@ -1,6 +1,6 @@