feat: 大量升级,v2.0.0
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
<!-- 本文件会自动导入 -->
|
||||
<template>
|
||||
<span>
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
42
src/hooks/useRequest.ts
Normal file
42
src/hooks/useRequest.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
type IUseRequestOptions<T> = {
|
||||
/** 是否立即执行,如果是则在onLoad执行 */
|
||||
immediate?: boolean
|
||||
/** 初始化数据 */
|
||||
initialData?: T
|
||||
}
|
||||
|
||||
/**
|
||||
* useRequest是一个定制化的请求钩子,用于处理异步请求和响应。
|
||||
* @param func 一个执行异步请求的函数,返回一个包含响应数据的Promise。
|
||||
* @param options 包含请求选项的对象 {immediate, initialData}。
|
||||
* @param options.immediate 是否立即执行请求,默认为true。
|
||||
* @param options.initialData 初始化数据,默认为undefined。
|
||||
* @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
|
||||
*/
|
||||
export default function useRequest<T>(
|
||||
func: () => Promise<IResData<T>>,
|
||||
options: IUseRequestOptions<T> = { immediate: true },
|
||||
) {
|
||||
const loading = ref(false)
|
||||
const error = ref(false)
|
||||
const data = ref<T>()
|
||||
const run = async () => {
|
||||
loading.value = true
|
||||
func()
|
||||
.then((res) => {
|
||||
data.value = res.data
|
||||
error.value = false
|
||||
})
|
||||
.catch((err) => {
|
||||
error.value = err
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
options.immediate && run()
|
||||
})
|
||||
return { loading, error, data, run }
|
||||
}
|
||||
9
src/i18n.d.ts
vendored
9
src/i18n.d.ts
vendored
@@ -1,9 +0,0 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
export {}
|
||||
|
||||
declare module 'vue' {
|
||||
interface ComponentCustomProperties {
|
||||
$t: (key: string, opt?: Record<string, any>) => string
|
||||
$tm: (key: string, opt?: Record<string, any>) => [] | { [p: string]: any }
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
export { routeInterceptor } from './route'
|
||||
export { requestInterceptor } from './request'
|
||||
export { prototypeInterceptor } from './prototype'
|
||||
|
||||
13
src/interceptors/prototype.ts
Normal file
13
src/interceptors/prototype.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const prototypeInterceptor = {
|
||||
install() {
|
||||
// 解决低版本手机不识别 array.at() 导致运行报错的问题
|
||||
if (typeof Array.prototype.at !== 'function') {
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Array.prototype.at = function (index: number) {
|
||||
if (index < 0) return this[this.length + index]
|
||||
if (index >= this.length) return undefined
|
||||
return this[index]
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import qs from 'qs'
|
||||
import { useUserStore } from '@/store'
|
||||
import { platform } from '@/utils/platform'
|
||||
|
||||
export type CustomRequestOptions = UniApp.RequestOptions & {
|
||||
query?: Record<string, any>
|
||||
/** 出错时是否隐藏错误提示 */
|
||||
hideErrorToast?: boolean
|
||||
} & IUniUploadFileOptions // 添加uni.uploadFile参数类型
|
||||
|
||||
// 请求基地址
|
||||
const baseURL = import.meta.env.VITE_SERVER_BASEURL
|
||||
// 请求基准地址
|
||||
const baseUrl = import.meta.env.VITE_SERVER_BASEURL
|
||||
|
||||
// 拦截器配置
|
||||
const httpInterceptor = {
|
||||
@@ -22,19 +25,19 @@ const httpInterceptor = {
|
||||
options.url += `?${queryStr}`
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 非 http 开头需拼接地址
|
||||
// 非 http 开头需拼接地址
|
||||
if (!options.url.startsWith('http')) {
|
||||
options.url = baseURL + options.url
|
||||
options.url = baseUrl + options.url
|
||||
// TIPS: 如果需要对接多个后端服务,也可以在这里处理,拼接成所需要的地址
|
||||
}
|
||||
// 2. 请求超时
|
||||
// 1. 请求超时
|
||||
options.timeout = 10000 // 10s
|
||||
// 3. 添加小程序端请求头标识
|
||||
// 2. (可选)添加小程序端请求头标识
|
||||
options.header = {
|
||||
platform: 'mp-weixin', // 可选值与 uniapp 定义的平台一致,告诉后台来源
|
||||
platform, // 可选,与 uniapp 定义的平台一致,告诉后台来源
|
||||
...options.header,
|
||||
}
|
||||
// 4. 添加 token 请求头标识
|
||||
// 3. 添加 token 请求头标识
|
||||
const userStore = useUserStore()
|
||||
const { token } = userStore.userInfo as unknown as IUserInfo
|
||||
if (token) {
|
||||
|
||||
@@ -21,7 +21,7 @@ const isDev = import.meta.env.DEV
|
||||
const navigateToInterceptor = {
|
||||
// 注意,这里的url是 '/' 开头的,如 '/pages/index/index',跟 'pages.json' 里面的 path 不同
|
||||
invoke({ url }: { url: string }) {
|
||||
console.log(url) // /pages/route-interceptor/index?name=feige&age=30
|
||||
// console.log(url) // /pages/route-interceptor/index?name=feige&age=30
|
||||
const path = url.split('?')[0]
|
||||
let needLoginPages: string[] = []
|
||||
// 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
|
||||
@@ -30,18 +30,17 @@ const navigateToInterceptor = {
|
||||
} else {
|
||||
needLoginPages = _needLoginPages
|
||||
}
|
||||
console.log(needLoginPages.includes(path))
|
||||
|
||||
if (needLoginPages.includes(path)) {
|
||||
const isLogin = isLogined()
|
||||
if (isLogin) {
|
||||
return true
|
||||
}
|
||||
const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
|
||||
uni.navigateTo({ url: redirectRoute })
|
||||
return false
|
||||
const isNeedLogin = needLoginPages.includes(path)
|
||||
if (!isNeedLogin) {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
const hasLogin = isLogined()
|
||||
if (hasLogin) {
|
||||
return true
|
||||
}
|
||||
const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
|
||||
uni.navigateTo({ url: redirectRoute })
|
||||
return false
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,3 @@
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.default-layout {
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="text-center p-4">
|
||||
<view class="demo-layout">
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import store from './store'
|
||||
import { routeInterceptor, requestInterceptor } from './interceptors'
|
||||
import 'virtual:svg-icons-register'
|
||||
import { routeInterceptor, requestInterceptor, prototypeInterceptor } from './interceptors'
|
||||
import 'virtual:uno.css'
|
||||
import '@/style/index.scss'
|
||||
|
||||
@@ -11,6 +10,7 @@ export function createApp() {
|
||||
app.use(store)
|
||||
app.use(routeInterceptor)
|
||||
app.use(requestInterceptor)
|
||||
app.use(prototypeInterceptor)
|
||||
return {
|
||||
app,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "unibest",
|
||||
"appid": "H5871D791",
|
||||
"name": "unibest-base",
|
||||
"appid": "H57F2ACE4",
|
||||
"description": "",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
@@ -71,7 +71,6 @@
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion": "3",
|
||||
"locale": "zh-Hans",
|
||||
"h5": {
|
||||
"router": {
|
||||
"base": "/"
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# 分包配置
|
||||
|
||||
在 `vite.config.ts` 中进行配置。
|
||||
|
||||
```ts
|
||||
import { defineConfig } from 'vite'
|
||||
import UniPages from '@uni-helper/vite-plugin-uni-pages'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
UniPages({
|
||||
// ... 其他配置
|
||||
subPackages: [
|
||||
'src/pages-sub', // 是个数组,可以配置多个
|
||||
],
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
@@ -59,6 +59,14 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "请求"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/index/request2",
|
||||
"type": "page",
|
||||
"layout": "demo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请求"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": []
|
||||
|
||||
@@ -16,27 +16,19 @@
|
||||
鸽友们好,我是
|
||||
<text class="text-red-500">菲鸽</text>
|
||||
</view>
|
||||
<view class="text-center mt-8">
|
||||
<view class="text-center mt-8 text-#fff">
|
||||
<wd-button type="primary" @click="gotoPage('request')">去请求页</wd-button>
|
||||
<wd-button type="primary" @click="gotoPage('request2')" class="ml-2">
|
||||
去请求页2 (请求状态一体化)
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="text-center py-4">
|
||||
当前平台是:
|
||||
<text class="text-red-500">{{ PLATFORM.platform }}</text>
|
||||
</view>
|
||||
<view class="text-center desc mt-10">设计稿样式编写:</view>
|
||||
<view class="text-center desc">设计稿是750px,css里面全部写rpx 即可</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PLATFORM from '@/utils/platform'
|
||||
|
||||
// 获取屏幕边界到安全区域距离
|
||||
const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||
|
||||
console.log(PLATFORM)
|
||||
|
||||
const gotoPage = (page: string) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/index/${page}`,
|
||||
|
||||
@@ -19,16 +19,21 @@
|
||||
<view class="text-center text-2xl mt-2 mb-8">最好用的 uniapp 开发模板</view>
|
||||
|
||||
<view class="text-justify max-w-100 m-auto text-4 indent mb-2">{{ description }}</view>
|
||||
<view class="mt-8 text-center">
|
||||
<text class="text-green-400">当前模板分支:base</text>
|
||||
<view class="text-center mt-8">
|
||||
当前平台是:
|
||||
<text class="text-green-500">{{ PLATFORM.platform }}</text>
|
||||
</view>
|
||||
<view class="text-center mt-4">
|
||||
模板分支是:
|
||||
<text class="text-green-500">base</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PLATFORM from '@/utils/platform'
|
||||
// 获取屏幕边界到安全区域距离
|
||||
const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||
|
||||
const author = ref('菲鸽')
|
||||
const description = ref(
|
||||
'unibest 是一个集成了多种工具和技术的 uniapp 开发模板,由 uniapp + Vue3 + Ts + Vite4 + UnoCss + UniUI + VSCode 构建,模板具有代码提示、自动格式化、统一配置、代码片段等功能,并内置了许多常用的基本组件和基本功能,让你编写 uniapp 拥有 best 体验。',
|
||||
|
||||
@@ -8,35 +8,35 @@
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<view class="mt-6">
|
||||
<!-- http://localhost:9000/#/pages/index/request -->
|
||||
<button @click="getFoo" class="my-4">测试 GET 请求</button>
|
||||
<view class="text-xl">请求数据如下</view>
|
||||
<view class="text-green h-10">{{ JSON.stringify(data) }}</view>
|
||||
<view class="text-xl">完整数据</view>
|
||||
<view class="text-green h-20">{{ JSON.stringify(originalData) }}</view>
|
||||
<button @click="postFoo" class="my-4">测试 POST 请求</button>
|
||||
<view class="text-xl">请求数据如下</view>
|
||||
<view class="text-green h-10">{{ JSON.stringify(data2) }}</view>
|
||||
|
||||
<button class="my-8" type="warn" @click="reset">一键清空数据</button>
|
||||
|
||||
<view class="p-6 text-center">
|
||||
<view class="my-2">使用的是 laf 云后台</view>
|
||||
<view class="text-green-400">我的推荐码,可以获得佣金</view>
|
||||
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="my-2 text-center">
|
||||
<a class="my-2 text-center" :href="recommendUrl" target="_blank">{{ recommendUrl }}</a>
|
||||
<view class="my-2">
|
||||
<a class="my-2" :href="recommendUrl" target="_blank">{{ recommendUrl }}</a>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="my-2 text-left text-sm">{{ recommendUrl }}</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- http://localhost:9000/#/pages/index/request -->
|
||||
<button @click="getFoo" class="my-6">1.测试 GET 请求</button>
|
||||
<view class="text-xl">请求数据如下</view>
|
||||
<view class="text-green h-10">{{ JSON.stringify(data) }}</view>
|
||||
<view class="text-xl">完整数据</view>
|
||||
<view class="text-green h-16">{{ JSON.stringify(originalData) }}</view>
|
||||
<button @click="postFoo" class="my-6">2.测试 POST 请求</button>
|
||||
<view class="text-xl">请求数据如下</view>
|
||||
<view class="text-green h-10">{{ JSON.stringify(data2) }}</view>
|
||||
<button class="my-6" type="warn" @click="reset">3.一键清空数据</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getFooAPI, postFooAPI, IFooItem } from '@/service/foo'
|
||||
import { getFooAPI, postFooAPI, IFooItem } from '@/service/index/foo'
|
||||
|
||||
const recommendUrl = ref('http://laf.run/signup?code=ohaOgIX')
|
||||
|
||||
@@ -44,6 +44,7 @@ onLoad(() => {
|
||||
getFoo()
|
||||
postFoo()
|
||||
})
|
||||
|
||||
const originalData = ref<IResData<IFooItem>>()
|
||||
const data = ref<IFooItem>()
|
||||
const getFoo = async () => {
|
||||
|
||||
30
src/pages/index/request2.vue
Normal file
30
src/pages/index/request2.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<route lang="json5">
|
||||
{
|
||||
layout: 'demo',
|
||||
style: {
|
||||
navigationBarTitleText: '请求',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<view class="p-6 text-center">
|
||||
<!-- http://localhost:9000/#/pages/index/request -->
|
||||
<button @click="getFoo" class="my-6">测试 GET 请求</button>
|
||||
<view class="text-xl">请求数据如下</view>
|
||||
<view v-if="loading" class="text-blue h-10">加载中...</view>
|
||||
<view v-else class="text-green h-10">{{ JSON.stringify(data) }}</view>
|
||||
<button class="my-6" type="warn" @click="reset">一键清空数据</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getFooAPI, IFooItem } from '@/service/index/foo'
|
||||
|
||||
const { loading, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'), { immediate: true })
|
||||
|
||||
const getFoo = () => run()
|
||||
const reset = () => {
|
||||
data.value = undefined
|
||||
}
|
||||
</script>
|
||||
14
src/shime-uni.d.ts
vendored
14
src/shime-uni.d.ts
vendored
@@ -1,14 +0,0 @@
|
||||
export {}
|
||||
|
||||
declare module 'vue' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance
|
||||
interface ComponentCustomOptions extends Hooks {
|
||||
$uv?: any
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Uni {
|
||||
$uv?: any
|
||||
}
|
||||
}
|
||||
14
src/types/global.d.ts
vendored
Normal file
14
src/types/global.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
declare const __UNI_PLATFORM__:
|
||||
| 'h5'
|
||||
| 'app'
|
||||
| 'mp-alipay'
|
||||
| 'mp-baidu'
|
||||
| 'mp-jd'
|
||||
| 'mp-kuaishou'
|
||||
| 'mp-lark'
|
||||
| 'mp-qq'
|
||||
| 'mp-toutiao'
|
||||
| 'mp-weixin'
|
||||
| 'quickapp-webview'
|
||||
| 'quickapp-webview-huawei'
|
||||
| 'quickapp-webview-union'
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable no-unused-vars */
|
||||
// 全局要用的类型放到这里
|
||||
|
||||
type IResData<T> = {
|
||||
|
||||
@@ -22,10 +22,11 @@ export const http = <T>(options: CustomRequestOptions) => {
|
||||
reject(res)
|
||||
} else {
|
||||
// 其他错误 -> 根据后端错误信息轻提示
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: (res.data as IResData<T>).msg || '请求错误',
|
||||
})
|
||||
!options.hideErrorToast &&
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: (res.data as IResData<T>).msg || '请求错误',
|
||||
})
|
||||
reject(res)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ export const getIsTabbar = () => {
|
||||
return false
|
||||
}
|
||||
const pages = getCurrentPages()
|
||||
const lastPage = getArrElementByIdx(pages, -1)
|
||||
const lastPage = pages.at(-1)
|
||||
const currPath = lastPage.route
|
||||
return !!pagesJson.tabBar.list.find((e) => e.pagePath === currPath)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ export const currRoute = () => {
|
||||
const pages = getCurrentPages()
|
||||
console.log('pages:', pages)
|
||||
|
||||
const lastPage = getArrElementByIdx(pages, -1)
|
||||
const lastPage = pages.at(-1)
|
||||
const currRoute = (lastPage as any).$page
|
||||
// console.log('lastPage.$page:', currRoute)
|
||||
// console.log('lastPage.$page.fullpath:', currRoute.fullPath)
|
||||
@@ -105,9 +105,3 @@ export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((p
|
||||
* 只得到 path 数组
|
||||
*/
|
||||
export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path)
|
||||
|
||||
export const getArrElementByIdx = (arr: any[], index: number) => {
|
||||
if (index < 0) return arr[arr.length + index]
|
||||
if (index >= arr.length) return undefined
|
||||
return arr[index]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user