style: 统一代码格式和类型定义,测试eslint --fix, 还是有报错

This commit is contained in:
feige996 2025-06-21 16:56:24 +08:00
parent 9cf0c212bf
commit 227f19a93c
40 changed files with 396 additions and 367 deletions

60
.github/release.yml vendored
View File

@ -1,31 +1,31 @@
categories: categories:
- title: '🚀 新功能' - title: 🚀 新功能
labels: ['feat', 'feature'] labels: [feat, feature]
- title: '🛠️ 修复' - title: 🛠️ 修复
labels: ['fix', 'bugfix'] labels: [fix, bugfix]
- title: '💅 样式' - title: 💅 样式
labels: ['style'] labels: [style]
- title: '📄 文档' - title: 📄 文档
labels: ['docs'] labels: [docs]
- title: '⚡️ 性能' - title: ⚡️ 性能
labels: ['perf'] labels: [perf]
- title: '🧪 测试' - title: 🧪 测试
labels: ['test'] labels: [test]
- title: '♻️ 重构' - title: ♻️ 重构
labels: ['refactor'] labels: [refactor]
- title: '📦 构建' - title: 📦 构建
labels: ['build'] labels: [build]
- title: '🚨 补丁' - title: 🚨 补丁
labels: ['patch', 'hotfix'] labels: [patch, hotfix]
- title: '🌐 发布' - title: 🌐 发布
labels: ['release', 'publish'] labels: [release, publish]
- title: '🔧 流程' - title: 🔧 流程
labels: ['ci', 'cd', 'workflow'] labels: [ci, cd, workflow]
- title: '⚙️ 配置' - title: ⚙️ 配置
labels: ['config', 'chore'] labels: [config, chore]
- title: '📁 文件' - title: 📁 文件
labels: ['file'] labels: [file]
- title: '🎨 格式化' - title: 🎨 格式化
labels: ['format'] labels: [format]
- title: '🔀 其他' - title: 🔀 其他
labels: ['other', 'misc'] labels: [other, misc]

View File

@ -1,6 +1,6 @@
import path from 'node:path'
// manifest.config.ts // manifest.config.ts
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest' import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
import path from 'node:path'
import { loadEnv } from 'vite' import { loadEnv } from 'vite'
// 获取环境变量的范例 // 获取环境变量的范例
@ -14,14 +14,14 @@ const {
} = env } = env
export default defineManifestConfig({ export default defineManifestConfig({
name: VITE_APP_TITLE, 'name': VITE_APP_TITLE,
appid: VITE_UNI_APPID, 'appid': VITE_UNI_APPID,
description: '', 'description': '',
versionName: '1.0.0', 'versionName': '1.0.0',
versionCode: '100', 'versionCode': '100',
transformPx: false, 'transformPx': false,
locale: VITE_FALLBACK_LOCALE, // 'zh-Hans' 'locale': VITE_FALLBACK_LOCALE, // 'zh-Hans'
h5: { 'h5': {
router: { router: {
base: VITE_APP_PUBLIC_BASE, base: VITE_APP_PUBLIC_BASE,
}, },
@ -82,14 +82,14 @@ export default defineManifestConfig({
ios: { ios: {
appstore: 'static/app/icons/1024x1024.png', appstore: 'static/app/icons/1024x1024.png',
ipad: { ipad: {
app: 'static/app/icons/76x76.png', 'app': 'static/app/icons/76x76.png',
'app@2x': 'static/app/icons/152x152.png', 'app@2x': 'static/app/icons/152x152.png',
notification: 'static/app/icons/20x20.png', 'notification': 'static/app/icons/20x20.png',
'notification@2x': 'static/app/icons/40x40.png', 'notification@2x': 'static/app/icons/40x40.png',
'proapp@2x': 'static/app/icons/167x167.png', 'proapp@2x': 'static/app/icons/167x167.png',
settings: 'static/app/icons/29x29.png', 'settings': 'static/app/icons/29x29.png',
'settings@2x': 'static/app/icons/58x58.png', 'settings@2x': 'static/app/icons/58x58.png',
spotlight: 'static/app/icons/40x40.png', 'spotlight': 'static/app/icons/40x40.png',
'spotlight@2x': 'static/app/icons/80x80.png', 'spotlight@2x': 'static/app/icons/80x80.png',
}, },
iphone: { iphone: {
@ -107,7 +107,7 @@ export default defineManifestConfig({
}, },
}, },
/* 快应用特有相关 */ /* 快应用特有相关 */
quickapp: {}, 'quickapp': {},
/* 小程序特有相关 */ /* 小程序特有相关 */
'mp-weixin': { 'mp-weixin': {
appid: VITE_WX_APPID, appid: VITE_WX_APPID,
@ -130,8 +130,8 @@ export default defineManifestConfig({
'mp-toutiao': { 'mp-toutiao': {
usingComponents: true, usingComponents: true,
}, },
uniStatistics: { 'uniStatistics': {
enable: false, enable: false,
}, },
vueVersion: '3', 'vueVersion': '3',
}) })

View File

@ -3,7 +3,7 @@
// # 只需要执行下面的命令即可 // # 只需要执行下面的命令即可
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const { exec } = require('child_process') const { exec } = require('node:child_process')
// 定义要执行的命令 // 定义要执行的命令
const dependencies = [ const dependencies = [

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app' import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
import { usePageAuth } from '@/hooks/usePageAuth' import { usePageAuth } from '@/hooks/usePageAuth'
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
usePageAuth() usePageAuth()

View File

@ -1,4 +1,4 @@
import { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './login.typings' import type { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './login.typings'
import { http } from '@/utils/http' import { http } from '@/utils/http'
/** /**
@ -15,7 +15,7 @@ export interface ILoginForm {
* *
* @returns ICaptcha * @returns ICaptcha
*/ */
export const getCode = () => { export function getCode() {
return http.get<ICaptcha>('/user/getCode') return http.get<ICaptcha>('/user/getCode')
} }
@ -23,35 +23,35 @@ export const getCode = () => {
* *
* @param loginForm * @param loginForm
*/ */
export const login = (loginForm: ILoginForm) => { export function login(loginForm: ILoginForm) {
return http.post<IUserLogin>('/user/login', loginForm) return http.post<IUserLogin>('/user/login', loginForm)
} }
/** /**
* *
*/ */
export const getUserInfo = () => { export function getUserInfo() {
return http.get<IUserInfoVo>('/user/info') return http.get<IUserInfoVo>('/user/info')
} }
/** /**
* 退 * 退
*/ */
export const logout = () => { export function logout() {
return http.get<void>('/user/logout') return http.get<void>('/user/logout')
} }
/** /**
* *
*/ */
export const updateInfo = (data: IUpdateInfo) => { export function updateInfo(data: IUpdateInfo) {
return http.post('/user/updateInfo', data) return http.post('/user/updateInfo', data)
} }
/** /**
* *
*/ */
export const updateUserPassword = (data: IUpdatePassword) => { export function updateUserPassword(data: IUpdatePassword) {
return http.post('/user/updatePassword', data) return http.post('/user/updatePassword', data)
} }
@ -59,12 +59,12 @@ export const updateUserPassword = (data: IUpdatePassword) => {
* *
* @returns Promise (code) * @returns Promise (code)
*/ */
export const getWxCode = () => { export function getWxCode() {
return new Promise<UniApp.LoginRes>((resolve, reject) => { return new Promise<UniApp.LoginRes>((resolve, reject) => {
uni.login({ uni.login({
provider: 'weixin', provider: 'weixin',
success: (res) => resolve(res), success: res => resolve(res),
fail: (err) => reject(new Error(err)), fail: err => reject(new Error(err)),
}) })
}) })
} }
@ -78,6 +78,6 @@ export const getWxCode = () => {
* @param params code * @param params code
* @returns Promise * @returns Promise
*/ */
export const wxLogin = (data: { code: string }) => { export function wxLogin(data: { code: string }) {
return http.post<IUserLogin>('/user/wxLogin', data) return http.post<IUserLogin>('/user/wxLogin', data)
} }

View File

@ -1,7 +1,7 @@
/** /**
* *
*/ */
export type IUserInfoVo = { export interface IUserInfoVo {
id: number id: number
username: string username: string
avatar: string avatar: string
@ -11,7 +11,7 @@ export type IUserInfoVo = {
/** /**
* *
*/ */
export type IUserLogin = { export interface IUserLogin {
id: string id: string
username: string username: string
token: string token: string
@ -20,7 +20,7 @@ export type IUserLogin = {
/** /**
* *
*/ */
export type ICaptcha = { export interface ICaptcha {
captchaEnabled: boolean captchaEnabled: boolean
uuid: string uuid: string
image: string image: string
@ -28,7 +28,7 @@ export type ICaptcha = {
/** /**
* *
*/ */
export type IUploadSuccessInfo = { export interface IUploadSuccessInfo {
fileId: number fileId: number
originalName: string originalName: string
fileName: string fileName: string
@ -41,7 +41,7 @@ export type IUploadSuccessInfo = {
/** /**
* *
*/ */
export type IUpdateInfo = { export interface IUpdateInfo {
id: number id: number
name: string name: string
sex: string sex: string
@ -49,7 +49,7 @@ export type IUpdateInfo = {
/** /**
* *
*/ */
export type IUpdatePassword = { export interface IUpdatePassword {
id: number id: number
oldPassword: string oldPassword: string
newPassword: string newPassword: string

2
src/env.d.ts vendored
View File

@ -2,7 +2,7 @@
/// <reference types="vite-svg-loader" /> /// <reference types="vite-svg-loader" />
declare module '*.vue' { declare module '*.vue' {
import { DefineComponent } from 'vue' import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any> const component: DefineComponent<{}, {}, any>
export default component export default component

View File

@ -1,10 +1,10 @@
import { onLoad } from '@dcloudio/uni-app' import { onLoad } from '@dcloudio/uni-app'
import { needLoginPages as _needLoginPages, getNeedLoginPages } from '@/utils'
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
import { needLoginPages as _needLoginPages, getNeedLoginPages } from '@/utils'
const loginRoute = import.meta.env.VITE_LOGIN_URL const loginRoute = import.meta.env.VITE_LOGIN_URL
const isDev = import.meta.env.DEV const isDev = import.meta.env.DEV
const isLogined = () => { function isLogined() {
const userStore = useUserStore() const userStore = useUserStore()
return !!userStore.userInfo.username return !!userStore.userInfo.username
} }
@ -20,7 +20,8 @@ export function usePageAuth() {
let needLoginPages: string[] = [] let needLoginPages: string[] = []
if (isDev) { if (isDev) {
needLoginPages = getNeedLoginPages() needLoginPages = getNeedLoginPages()
} else { }
else {
needLoginPages = _needLoginPages needLoginPages = _needLoginPages
} }

View File

@ -1,6 +1,6 @@
import { UnwrapRef } from 'vue' import type { UnwrapRef } from 'vue'
type IUseRequestOptions<T> = { interface IUseRequestOptions<T> {
/** 是否立即执行 */ /** 是否立即执行 */
immediate?: boolean immediate?: boolean
/** 初始化数据 */ /** 初始化数据 */

View File

@ -7,7 +7,7 @@ type TfileType = 'image' | 'file'
type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*' type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*'
type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage
type TOptions<T extends TfileType> = { interface TOptions<T extends TfileType> {
formData?: Record<string, any> formData?: Record<string, any>
maxSize?: number maxSize?: number
accept?: T extends 'image' ? TImage[] : TFile[] accept?: T extends 'image' ? TImage[] : TFile[]
@ -72,7 +72,8 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
uni.chooseImage(chooseFileOptions) uni.chooseImage(chooseFileOptions)
// #endif // #endif
} else { }
else {
uni.chooseFile({ uni.chooseFile({
...chooseFileOptions, ...chooseFileOptions,
type: 'all', type: 'all',
@ -80,7 +81,7 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
} }
} }
const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string; size: number }) => { const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string, size: number }) => {
if (size > maxSize) { if (size > maxSize) {
uni.showToast({ uni.showToast({
title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`, title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`,
@ -102,7 +103,7 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
loading.value = true loading.value = true
uploadFile({ uploadFile({
tempFilePath: tempFilePath, tempFilePath,
formData, formData,
onSuccess: (res) => { onSuccess: (res) => {
const { data: _data } = JSON.parse(res) const { data: _data } = JSON.parse(res)
@ -145,7 +146,8 @@ async function uploadFile({
try { try {
const data = uploadFileRes.data const data = uploadFileRes.data
onSuccess(data) onSuccess(data)
} catch (err) { }
catch (err) {
onError(err) onError(err)
} }
}, },

View File

@ -1,3 +1,3 @@
export { routeInterceptor } from './route'
export { requestInterceptor } from './request'
export { prototypeInterceptor } from './prototype' export { prototypeInterceptor } from './prototype'
export { requestInterceptor } from './request'
export { routeInterceptor } from './route'

View File

@ -4,8 +4,10 @@ export const prototypeInterceptor = {
if (typeof Array.prototype.at !== 'function') { if (typeof Array.prototype.at !== 'function') {
// eslint-disable-next-line no-extend-native // eslint-disable-next-line no-extend-native
Array.prototype.at = function (index: number) { Array.prototype.at = function (index: number) {
if (index < 0) return this[this.length + index] if (index < 0)
if (index >= this.length) return undefined return this[this.length + index]
if (index >= this.length)
return undefined
return this[index] return this[index]
} }
} }

View File

@ -1,8 +1,7 @@
/* eslint-disable no-param-reassign */
import qs from 'qs' import qs from 'qs'
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
import { platform } from '@/utils/platform'
import { getEnvBaseUrl } from '@/utils' import { getEnvBaseUrl } from '@/utils'
import { platform } from '@/utils/platform'
export type CustomRequestOptions = UniApp.RequestOptions & { export type CustomRequestOptions = UniApp.RequestOptions & {
query?: Record<string, any> query?: Record<string, any>
@ -22,7 +21,8 @@ const httpInterceptor = {
const queryStr = qs.stringify(options.query) const queryStr = qs.stringify(options.query)
if (options.url.includes('?')) { if (options.url.includes('?')) {
options.url += `&${queryStr}` options.url += `&${queryStr}`
} else { }
else {
options.url += `?${queryStr}` options.url += `?${queryStr}`
} }
} }
@ -33,7 +33,8 @@ const httpInterceptor = {
if (JSON.parse(__VITE_APP_PROXY__)) { if (JSON.parse(__VITE_APP_PROXY__)) {
// 自动拼接代理前缀 // 自动拼接代理前缀
options.url = import.meta.env.VITE_APP_PROXY_PREFIX + options.url options.url = import.meta.env.VITE_APP_PROXY_PREFIX + options.url
} else { }
else {
options.url = baseUrl + options.url options.url = baseUrl + options.url
} }
// #endif // #endif

View File

@ -5,12 +5,12 @@
* 便使 * 便使
*/ */
import { useUserStore } from '@/store' import { useUserStore } from '@/store'
import { needLoginPages as _needLoginPages, getNeedLoginPages, getLastPage } from '@/utils' import { needLoginPages as _needLoginPages, getLastPage, getNeedLoginPages } from '@/utils'
// TODO Check // TODO Check
const loginRoute = import.meta.env.VITE_LOGIN_URL const loginRoute = import.meta.env.VITE_LOGIN_URL
const isLogined = () => { function isLogined() {
const userStore = useUserStore() const userStore = useUserStore()
return !!userStore.userInfo.username return !!userStore.userInfo.username
} }
@ -37,7 +37,8 @@ const navigateToInterceptor = {
// 为了防止开发时出现BUG这里每次都获取一下。生产环境可以移到函数外性能更好 // 为了防止开发时出现BUG这里每次都获取一下。生产环境可以移到函数外性能更好
if (isDev) { if (isDev) {
needLoginPages = getNeedLoginPages() needLoginPages = getNeedLoginPages()
} else { }
else {
needLoginPages = _needLoginPages needLoginPages = _needLoginPages
} }
const isNeedLogin = needLoginPages.includes(path) const isNeedLogin = needLoginPages.includes(path)

View File

@ -1,11 +1,3 @@
<template>
<wd-config-provider :themeVars="themeVars">
<slot />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import type { ConfigProviderThemeVars } from 'wot-design-uni' import type { ConfigProviderThemeVars } from 'wot-design-uni'
@ -15,3 +7,11 @@ const themeVars: ConfigProviderThemeVars = {
// buttonPrimaryColor: '#07c160', // buttonPrimaryColor: '#07c160',
} }
</script> </script>
<template>
<wd-config-provider :theme-vars="themeVars">
<slot />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>

View File

@ -1,11 +1,3 @@
<template>
<wd-config-provider :themeVars="themeVars">
<slot />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import type { ConfigProviderThemeVars } from 'wot-design-uni' import type { ConfigProviderThemeVars } from 'wot-design-uni'
@ -15,3 +7,11 @@ const themeVars: ConfigProviderThemeVars = {
// buttonPrimaryColor: '#07c160', // buttonPrimaryColor: '#07c160',
} }
</script> </script>
<template>
<wd-config-provider :theme-vars="themeVars">
<slot />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>

View File

@ -1,11 +1,43 @@
<script setup lang="ts">
import { tabbarStore } from './tabbar'
// 'i-carbon-code',
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy } from './tabbarList'
const customTabbarEnable = selectedTabbarStrategy === 1 || selectedTabbarStrategy === 2
/** tabbarList 里面的 path 从 pages.config.ts 得到 */
const tabbarList = _tabBarList.map(item => ({ ...item, path: `/${item.pagePath}` }))
function selectTabBar({ value: index }: { value: number }) {
const url = tabbarList[index].path
tabbarStore.setCurIdx(index)
if (cacheTabbarEnable) {
uni.switchTab({ url })
}
else {
uni.navigateTo({ url })
}
}
onLoad(() => {
// tabBar 2 tabBar
const hideRedundantTabbarEnable = selectedTabbarStrategy === 1
hideRedundantTabbarEnable
&& uni.hideTabBar({
fail(err) {
console.log('hideTabBar fail: ', err)
},
success(res) {
console.log('hideTabBar success: ', res)
},
})
})
</script>
<template> <template>
<wd-tabbar <wd-tabbar
v-if="customTabbarEnable" v-if="customTabbarEnable"
fixed
v-model="tabbarStore.curIdx" v-model="tabbarStore.curIdx"
bordered
safeAreaInsetBottom bordered safeareainsetbottom placeholder fixed
placeholder
@change="selectTabBar" @change="selectTabBar"
> >
<block v-for="(item, idx) in tabbarList" :key="item.path"> <block v-for="(item, idx) in tabbarList" :key="item.path">
@ -13,7 +45,7 @@
v-if="item.iconType === 'wot'" v-if="item.iconType === 'wot'"
:title="item.text" :title="item.text"
:icon="item.icon" :icon="item.icon"
></wd-tabbar-item> />
<wd-tabbar-item <wd-tabbar-item
v-else-if="item.iconType === 'unocss' || item.iconType === 'iconfont'" v-else-if="item.iconType === 'unocss' || item.iconType === 'iconfont'"
:title="item.text" :title="item.text"
@ -23,7 +55,7 @@
h-40rpx h-40rpx
w-40rpx w-40rpx
:class="[item.icon, idx === tabbarStore.curIdx ? 'is-active' : 'is-inactive']" :class="[item.icon, idx === tabbarStore.curIdx ? 'is-active' : 'is-inactive']"
></view> />
</template> </template>
</wd-tabbar-item> </wd-tabbar-item>
<wd-tabbar-item v-else-if="item.iconType === 'local'" :title="item.text"> <wd-tabbar-item v-else-if="item.iconType === 'local'" :title="item.text">
@ -34,35 +66,3 @@
</block> </block>
</wd-tabbar> </wd-tabbar>
</template> </template>
<script setup lang="ts">
// 'i-carbon-code',
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy } from './tabbarList'
import { tabbarStore } from './tabbar'
const customTabbarEnable = selectedTabbarStrategy === 1 || selectedTabbarStrategy === 2
/** tabbarList 里面的 path 从 pages.config.ts 得到 */
const tabbarList = _tabBarList.map((item) => ({ ...item, path: `/${item.pagePath}` }))
function selectTabBar({ value: index }: { value: number }) {
const url = tabbarList[index].path
tabbarStore.setCurIdx(index)
if (cacheTabbarEnable) {
uni.switchTab({ url })
} else {
uni.navigateTo({ url })
}
}
onLoad(() => {
// tabBar 2 tabBar
const hideRedundantTabbarEnable = selectedTabbarStrategy === 1
hideRedundantTabbarEnable &&
uni.hideTabBar({
fail(err) {
console.log('hideTabBar fail: ', err)
},
success(res) {
console.log('hideTabBar success: ', res)
},
})
})
</script>

View File

@ -1,15 +1,6 @@
<template>
<wd-config-provider :themeVars="themeVars">
<slot />
<fg-tabbar />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import FgTabbar from './fg-tabbar/fg-tabbar.vue'
import type { ConfigProviderThemeVars } from 'wot-design-uni' import type { ConfigProviderThemeVars } from 'wot-design-uni'
import FgTabbar from './fg-tabbar/fg-tabbar.vue'
const themeVars: ConfigProviderThemeVars = { const themeVars: ConfigProviderThemeVars = {
// colorTheme: 'red', // colorTheme: 'red',
@ -17,3 +8,12 @@ const themeVars: ConfigProviderThemeVars = {
// buttonPrimaryColor: '#07c160', // buttonPrimaryColor: '#07c160',
} }
</script> </script>
<template>
<wd-config-provider :theme-vars="themeVars">
<slot />
<FgTabbar />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>

View File

@ -1,11 +1,11 @@
import '@/style/index.scss'
import { VueQueryPlugin } from '@tanstack/vue-query' import { VueQueryPlugin } from '@tanstack/vue-query'
import 'virtual:uno.css'
import { createSSRApp } from 'vue' import { createSSRApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import { prototypeInterceptor, requestInterceptor, routeInterceptor } from './interceptors' import { prototypeInterceptor, requestInterceptor, routeInterceptor } from './interceptors'
import store from './store' import store from './store'
import '@/style/index.scss'
import 'virtual:uno.css'
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)

View File

@ -110,4 +110,4 @@
"base": "/" "base": "/"
} }
} }
} }

View File

@ -7,17 +7,21 @@
} }
</route> </route>
<template>
<view class="text-center">
<view class="m-8">http://localhost:9000/#/pages-sub/demo/index</view>
<view class="text-green-500">分包页面demo</view>
</view>
</template>
<script lang="ts" setup> <script lang="ts" setup>
// code here // code here
</script> </script>
<template>
<view class="text-center">
<view class="m-8">
http://localhost:9000/#/pages-sub/demo/index
</view>
<view class="text-green-500">
分包页面demo
</view>
</view>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
// //
</style> </style>

View File

@ -62,4 +62,4 @@
} }
], ],
"subPackages": [] "subPackages": []
} }

View File

@ -7,17 +7,6 @@
} }
</route> </route>
<template>
<view>
<view class="text-center text-3xl mt-8">
鸽友们好我是
<text class="text-red-500">菲鸽</text>
</view>
<RequestComp />
<UploadComp />
</view>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import RequestComp from './components/request.vue' import RequestComp from './components/request.vue'
import UploadComp from './components/upload.vue' import UploadComp from './components/upload.vue'
@ -33,6 +22,19 @@ const { safeAreaInsets } = uni.getSystemInfoSync()
console.log('about') console.log('about')
</script> </script>
<template>
<view>
<view class="mt-8 text-center text-3xl">
鸽友们好我是
<text class="text-red-500">
菲鸽
</text>
</view>
<RequestComp />
<UploadComp />
</view>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
.test-css { .test-css {
// 16rpx=>0.5rem // 16rpx=>0.5rem

View File

@ -7,36 +7,9 @@
} }
</route> </route>
<template>
<view class="p-6 text-center">
<view class="my-2">使用的是 laf 云后台</view>
<view class="text-green-400">我的推荐码可以获得佣金</view>
<!-- #ifdef H5 -->
<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 -->
<wd-button @click="run" class="my-6">发送请求</wd-button>
<view class="h-16">
<view v-if="loading">loading...</view>
<block v-else>
<view class="text-xl">请求数据如下</view>
<view class="text-green leading-8">{{ JSON.stringify(data) }}</view>
</block>
</view>
<wd-button type="error" @click="reset" class="my-6" :disabled="!data">重置数据</wd-button>
</view>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import { getFooAPI, postFooAPI, IFooItem } from '@/service/index/foo' import type { IFooItem } from '@/service/index/foo'
import { getFooAPI } from '@/service/index/foo'
// import { findPetsByStatusQueryOptions } from '@/service/app' // import { findPetsByStatusQueryOptions } from '@/service/app'
// import { useQuery } from '@tanstack/vue-query' // import { useQuery } from '@tanstack/vue-query'
@ -61,7 +34,51 @@ const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲
// refetch, // refetch,
// } = useQuery(findPetsByStatusQueryOptions({ params: { status: ['available'] } })) // } = useQuery(findPetsByStatusQueryOptions({ params: { status: ['available'] } }))
const reset = () => { function reset() {
data.value = initialData data.value = initialData
} }
</script> </script>
<template>
<view class="p-6 text-center">
<view class="my-2">
使用的是 laf 云后台
</view>
<view class="text-green-400">
我的推荐码可以获得佣金
</view>
<!-- #ifdef H5 -->
<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 -->
<wd-button class="my-6" @click="run">
发送请求
</wd-button>
<view class="h-16">
<view v-if="loading">
loading...
</view>
<block v-else>
<view class="text-xl">
请求数据如下
</view>
<view class="text-green leading-8">
{{ JSON.stringify(data) }}
</view>
</block>
</view>
<wd-button type="error" class="my-6" :disabled="!data" @click="reset">
重置数据
</wd-button>
</view>
</template>

View File

@ -7,13 +7,25 @@
} }
</route> </route>
<script lang="ts" setup>
const { loading, data, run } = useUpload()
</script>
<template> <template>
<view class="p-4 text-center"> <view class="p-4 text-center">
<wd-button @click="run">选择图片并上传</wd-button> <wd-button @click="run">
<view v-if="loading" class="text-blue h-10">上传...</view> 选择图片并上传
</wd-button>
<view v-if="loading" class="h-10 text-blue">
上传...
</view>
<template v-else> <template v-else>
<view class="m-2">上传后返回的接口数据</view> <view class="m-2">
<view class="m-2">{{ data }}</view> 上传后返回的接口数据
</view>
<view class="m-2">
{{ data }}
</view>
<view v-if="data" class="h-80 w-full"> <view v-if="data" class="h-80 w-full">
<image :src="data.url" mode="scaleToFill" /> <image :src="data.url" mode="scaleToFill" />
</view> </view>
@ -21,10 +33,6 @@
</view> </view>
</template> </template>
<script lang="ts" setup>
const { loading, data, run } = useUpload()
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
// //
</style> </style>

View File

@ -9,25 +9,6 @@
}, },
} }
</route> </route>
<template>
<view class="bg-white pt-2 px-4" :style="{ marginTop: safeAreaInsets?.top + 'px' }">
<view class="mt-12">
<image src="/static/logo.svg" alt="" class="w-28 h-28 block mx-auto" />
</view>
<view class="text-center text-4xl text-[#d14328] mt-4">unibest</view>
<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="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> <script lang="ts" setup>
import PLATFORM from '@/utils/platform' import PLATFORM from '@/utils/platform'
@ -69,3 +50,33 @@ onLoad(() => {
console.log('index') console.log('index')
</script> </script>
<template>
<view class="bg-white px-4 pt-2" :style="{ marginTop: `${safeAreaInsets?.top}px` }">
<view class="mt-12">
<image src="/static/logo.svg" alt="" class="mx-auto block h-28 w-28" />
</view>
<view class="mt-4 text-center text-4xl text-[#d14328]">
unibest
</view>
<view class="mb-8 mt-2 text-center text-2xl">
最好用的 uniapp 开发模板
</view>
<view class="m-auto mb-2 max-w-100 text-justify indent text-4">
{{ description }}
</view>
<view class="mt-8 text-center">
当前平台是
<text class="text-green-500">
{{ PLATFORM.platform }}
</text>
</view>
<view class="mt-4 text-center">
模板分支是
<text class="text-green-500">
base
</text>
</view>
</view>
</template>

View File

@ -1,27 +1,28 @@
import { http } from '@/utils/http' import { http } from '@/utils/http'
export interface IFooItem { export interface IFooItem {
id: string id: string
name: string name: string
} }
/** GET 请求 */ /** GET 请求 */
export const getFooAPI = (name: string) => { export function getFooAPI(name: string) {
return http.get<IFooItem>('/foo', { name }) return http.get<IFooItem>('/foo', { name })
} }
/** GET 请求;支持 传递 header 的范例 */ /** GET 请求;支持 传递 header 的范例 */
export const getFooAPI2 = (name: string) => { export function getFooAPI2(name: string) {
return http.get<IFooItem>('/foo', { name }, { 'Content-Type-100': '100' }) return http.get<IFooItem>('/foo', { name }, { 'Content-Type-100': '100' })
} }
/** POST 请求 */ /** POST 请求 */
export const postFooAPI = (name: string) => { export function postFooAPI(name: string) {
return http.post<IFooItem>('/foo', { name }) return http.post<IFooItem>('/foo', { name })
} }
/** POST 请求;需要传递 query 参数的范例微信小程序经常有同时需要query参数和body参数的场景 */ /** POST 请求;需要传递 query 参数的范例微信小程序经常有同时需要query参数和body参数的场景 */
export const postFooAPI2 = (name: string) => { export function postFooAPI2(name: string) {
return http.post<IFooItem>('/foo', { name }) return http.post<IFooItem>('/foo', { name })
} }
/** POST 请求;支持 传递 header 的范例 */ /** POST 请求;支持 传递 header 的范例 */
export const postFooAPI3 = (name: string) => { export function postFooAPI3(name: string) {
return http.post<IFooItem>('/foo', { name }, { name }, { 'Content-Type-100': '100' }) return http.post<IFooItem>('/foo', { name }, { name }, { 'Content-Type-100': '100' })
} }

View File

@ -1,14 +1,14 @@
import { import type { IUserInfoVo } from '@/api/login.typings'
login as _login,
getUserInfo as _getUserInfo,
wxLogin as _wxLogin,
logout as _logout,
getWxCode,
} from '@/api/login'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import {
getUserInfo as _getUserInfo,
login as _login,
logout as _logout,
wxLogin as _wxLogin,
getWxCode,
} from '@/api/login'
import { toast } from '@/utils/toast' import { toast } from '@/utils/toast'
import { IUserInfoVo } from '@/api/login.typings'
// 初始化状态 // 初始化状态
const userInfoState: IUserInfoVo = { const userInfoState: IUserInfoVo = {
@ -29,7 +29,8 @@ export const useUserStore = defineStore(
// 若头像为空 则使用默认头像 // 若头像为空 则使用默认头像
if (!val.avatar) { if (!val.avatar) {
val.avatar = userInfoState.avatar val.avatar = userInfoState.avatar
} else { }
else {
val.avatar = 'https://oss.laf.run/ukw0y1-site/avatar.jpg?feige' val.avatar = 'https://oss.laf.run/ukw0y1-site/avatar.jpg?feige'
} }
userInfo.value = val userInfo.value = val

6
src/typings.d.ts vendored
View File

@ -1,14 +1,14 @@
// 全局要用的类型放到这里 // 全局要用的类型放到这里
declare global { declare global {
type IResData<T> = { interface IResData<T> {
code: number code: number
msg: string msg: string
data: T data: T
} }
// uni.uploadFile文件上传参数 // uni.uploadFile文件上传参数
type IUniUploadFileOptions = { interface IUniUploadFileOptions {
file?: File file?: File
files?: UniApp.UploadFileOptionFiles[] files?: UniApp.UploadFileOptionFiles[]
filePath?: string filePath?: string
@ -16,7 +16,7 @@ declare global {
formData?: any formData?: any
} }
type IUserInfo = { interface IUserInfo {
nickname?: string nickname?: string
avatar?: string avatar?: string
/** 微信的 openid非微信没有这个字段 */ /** 微信的 openid非微信没有这个字段 */

View File

@ -6,7 +6,7 @@ export enum TestEnum {
} }
// uni.uploadFile文件上传参数 // uni.uploadFile文件上传参数
export type IUniUploadFileOptions = { export interface IUniUploadFileOptions {
file?: File file?: File
files?: UniApp.UploadFileOptionFiles[] files?: UniApp.UploadFileOptionFiles[]
filePath?: string filePath?: string

View File

@ -1,6 +1,6 @@
import { CustomRequestOptions } from '@/interceptors/request' import type { CustomRequestOptions } from '@/interceptors/request'
export const http = <T>(options: CustomRequestOptions) => { export function http<T>(options: CustomRequestOptions) {
// 1. 返回 Promise 对象 // 1. 返回 Promise 对象
return new Promise<IResData<T>>((resolve, reject) => { return new Promise<IResData<T>>((resolve, reject) => {
uni.request({ uni.request({
@ -15,18 +15,20 @@ export const http = <T>(options: CustomRequestOptions) => {
if (res.statusCode >= 200 && res.statusCode < 300) { if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data // 2.1 提取核心数据 res.data
resolve(res.data as IResData<T>) resolve(res.data as IResData<T>)
} else if (res.statusCode === 401) { }
else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页 // 401错误 -> 清理用户信息,跳转到登录页
// userStore.clearUserInfo() // userStore.clearUserInfo()
// uni.navigateTo({ url: '/pages/login/login' }) // uni.navigateTo({ url: '/pages/login/login' })
reject(res) reject(res)
} else { }
else {
// 其他错误 -> 根据后端错误信息轻提示 // 其他错误 -> 根据后端错误信息轻提示
!options.hideErrorToast && !options.hideErrorToast
uni.showToast({ && uni.showToast({
icon: 'none', icon: 'none',
title: (res.data as IResData<T>).msg || '请求错误', title: (res.data as IResData<T>).msg || '请求错误',
}) })
reject(res) reject(res)
} }
}, },
@ -49,12 +51,7 @@ export const http = <T>(options: CustomRequestOptions) => {
* @param header json格式 * @param header json格式
* @returns * @returns
*/ */
export const httpGet = <T>( export function httpGet<T>(url: string, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
url: string,
query?: Record<string, any>,
header?: Record<string, any>,
options?: Partial<CustomRequestOptions>,
) => {
return http<T>({ return http<T>({
url, url,
query, query,
@ -72,13 +69,7 @@ export const httpGet = <T>(
* @param header json格式 * @param header json格式
* @returns * @returns
*/ */
export const httpPost = <T>( export function httpPost<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
url: string,
data?: Record<string, any>,
query?: Record<string, any>,
header?: Record<string, any>,
options?: Partial<CustomRequestOptions>,
) => {
return http<T>({ return http<T>({
url, url,
query, query,
@ -91,13 +82,7 @@ export const httpPost = <T>(
/** /**
* PUT * PUT
*/ */
export const httpPut = <T>( export function httpPut<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
url: string,
data?: Record<string, any>,
query?: Record<string, any>,
header?: Record<string, any>,
options?: Partial<CustomRequestOptions>,
) => {
return http<T>({ return http<T>({
url, url,
data, data,
@ -111,12 +96,7 @@ export const httpPut = <T>(
/** /**
* DELETE query * DELETE query
*/ */
export const httpDelete = <T>( export function httpDelete<T>(url: string, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
url: string,
query?: Record<string, any>,
header?: Record<string, any>,
options?: Partial<CustomRequestOptions>,
) => {
return http<T>({ return http<T>({
url, url,
query, query,

View File

@ -1,7 +1,7 @@
import { pages, subPackages } from '@/pages.json' import { pages, subPackages } from '@/pages.json'
import { isMpWeixin } from './platform' import { isMpWeixin } from './platform'
export const getLastPage = () => { export function getLastPage() {
// getCurrentPages() 至少有1个元素所以不再额外判断 // getCurrentPages() 至少有1个元素所以不再额外判断
// const lastPage = getCurrentPages().at(-1) // const lastPage = getCurrentPages().at(-1)
// 上面那个在低版本安卓中打包会报错,所以改用下面这个【虽然我加了 src/interceptions/prototype.ts但依然报错】 // 上面那个在低版本安卓中打包会报错,所以改用下面这个【虽然我加了 src/interceptions/prototype.ts但依然报错】
@ -14,7 +14,7 @@ export const getLastPage = () => {
* path '/pages/login/index' * path '/pages/login/index'
* redirectPath '/pages/demo/base/route-interceptor' * redirectPath '/pages/demo/base/route-interceptor'
*/ */
export const currRoute = () => { export function currRoute() {
const lastPage = getLastPage() const lastPage = getLastPage()
const currRoute = (lastPage as any).$page const currRoute = (lastPage as any).$page
// console.log('lastPage.$page:', currRoute) // console.log('lastPage.$page:', currRoute)
@ -29,7 +29,7 @@ export const currRoute = () => {
return getUrlObj(fullPath) return getUrlObj(fullPath)
} }
const ensureDecodeURIComponent = (url: string) => { function ensureDecodeURIComponent(url: string) {
if (url.startsWith('%')) { if (url.startsWith('%')) {
return ensureDecodeURIComponent(decodeURIComponent(url)) return ensureDecodeURIComponent(decodeURIComponent(url))
} }
@ -40,7 +40,7 @@ const ensureDecodeURIComponent = (url: string) => {
* url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor * url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor
* : {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}} * : {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}}
*/ */
export const getUrlObj = (url: string) => { export function getUrlObj(url: string) {
const [path, queryStr] = url.split('?') const [path, queryStr] = url.split('?')
// console.log(path, queryStr) // console.log(path, queryStr)
@ -63,11 +63,11 @@ export const getUrlObj = (url: string) => {
* key needLogin, route-block 使 * key needLogin, route-block 使
* key pages key, key * key pages key, key
*/ */
export const getAllPages = (key = 'needLogin') => { export function getAllPages(key = 'needLogin') {
// 这里处理主包 // 这里处理主包
const mainPages = pages const mainPages = pages
.filter((page) => !key || page[key]) .filter(page => !key || page[key])
.map((page) => ({ .map(page => ({
...page, ...page,
path: `/${page.path}`, path: `/${page.path}`,
})) }))
@ -79,7 +79,7 @@ export const getAllPages = (key = 'needLogin') => {
const { root } = subPageObj const { root } = subPageObj
subPageObj.pages subPageObj.pages
.filter((page) => !key || page[key]) .filter(page => !key || page[key])
.forEach((page: { path: string } & Record<string, any>) => { .forEach((page: { path: string } & Record<string, any>) => {
subPages.push({ subPages.push({
...page, ...page,
@ -96,18 +96,18 @@ export const getAllPages = (key = 'needLogin') => {
* pages * pages
* path * path
*/ */
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((page) => page.path) export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map(page => page.path)
/** /**
* pages * pages
* path * path
*/ */
export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path) export const needLoginPages: string[] = getAllPages('needLogin').map(page => page.path)
/** /**
* baseUrl * baseUrl
*/ */
export const getEnvBaseUrl = () => { export function getEnvBaseUrl() {
// 请求基准地址 // 请求基准地址
let baseUrl = import.meta.env.VITE_SERVER_BASEURL let baseUrl = import.meta.env.VITE_SERVER_BASEURL
@ -136,7 +136,7 @@ export const getEnvBaseUrl = () => {
/** /**
* UPLOAD_BASEURL * UPLOAD_BASEURL
*/ */
export const getEnvBaseUploadUrl = () => { export function getEnvBaseUploadUrl() {
// 请求基准地址 // 请求基准地址
let baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL let baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL

View File

@ -1,11 +1,11 @@
import { CustomRequestOptions } from '@/interceptors/request' import type { CustomRequestOptions } from '@/interceptors/request'
/** /**
* 请求方法: 主要是对 uni.request openapi-ts-request request * 请求方法: 主要是对 uni.request openapi-ts-request request
* @param options * @param options
* @returns Promise * @returns Promise
*/ */
const http = <T>(options: CustomRequestOptions) => { function http<T>(options: CustomRequestOptions) {
// 1. 返回 Promise 对象 // 1. 返回 Promise 对象
return new Promise<T>((resolve, reject) => { return new Promise<T>((resolve, reject) => {
uni.request({ uni.request({
@ -20,18 +20,20 @@ const http = <T>(options: CustomRequestOptions) => {
if (res.statusCode >= 200 && res.statusCode < 300) { if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data // 2.1 提取核心数据 res.data
resolve(res.data as T) resolve(res.data as T)
} else if (res.statusCode === 401) { }
else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页 // 401错误 -> 清理用户信息,跳转到登录页
// userStore.clearUserInfo() // userStore.clearUserInfo()
// uni.navigateTo({ url: '/pages/login/login' }) // uni.navigateTo({ url: '/pages/login/login' })
reject(res) reject(res)
} else { }
else {
// 其他错误 -> 根据后端错误信息轻提示 // 其他错误 -> 根据后端错误信息轻提示
!options.hideErrorToast && !options.hideErrorToast
uni.showToast({ && uni.showToast({
icon: 'none', icon: 'none',
title: (res.data as T & { msg?: string })?.msg || '请求错误', title: (res.data as T & { msg?: string })?.msg || '请求错误',
}) })
reject(res) reject(res)
} }
}, },

View File

@ -21,8 +21,8 @@ export function showToast(options: ToastOptions | string) {
position: 'middle', position: 'middle',
message: '', message: '',
} }
const mergedOptions = const mergedOptions
typeof options === 'string' = typeof options === 'string'
? { ...defaultOptions, message: options } ? { ...defaultOptions, message: options }
: { ...defaultOptions, ...options } : { ...defaultOptions, ...options }
// 映射position到uniapp支持的格式 // 映射position到uniapp支持的格式

View File

@ -21,7 +21,7 @@ import { toast } from './toast'
*/ */
export const uploadFileUrl = { export const uploadFileUrl = {
/** 用户头像上传地址 */ /** 用户头像上传地址 */
USER_AVATAR: import.meta.env.VITE_SERVER_BASEURL + '/user/avatar', USER_AVATAR: `${import.meta.env.VITE_SERVER_BASEURL}/user/avatar`,
} }
/** /**
@ -31,12 +31,7 @@ export const uploadFileUrl = {
* @param formData * @param formData
* @param options * @param options
*/ */
export const useFileUpload = <T = string>( export function useFileUpload<T = string>(url: string, filePath: string, formData: Record<string, any> = {}, options: Omit<UploadOptions, 'sourceType' | 'sizeType' | 'count'> = {}) {
url: string,
filePath: string,
formData: Record<string, any> = {},
options: Omit<UploadOptions, 'sourceType' | 'sizeType' | 'count'> = {},
) => {
return useUpload<T>( return useUpload<T>(
url, url,
formData, formData,
@ -76,13 +71,9 @@ export interface UploadOptions {
* @param options * @param options
* @returns * @returns
*/ */
export const useUpload = <T = string>( export function useUpload<T = string>(url: string, formData: Record<string, any> = {}, options: UploadOptions = {},
url: string,
formData: Record<string, any> = {},
options: UploadOptions = {},
/** 直接传入文件路径,跳过选择器 */ /** 直接传入文件路径,跳过选择器 */
directFilePath?: string, directFilePath?: string) {
) => {
/** 上传中状态 */ /** 上传中状态 */
const loading = ref(false) const loading = ref(false)
/** 上传错误状态 */ /** 上传错误状态 */
@ -161,7 +152,8 @@ export const useUpload = <T = string>(
success: (res) => { success: (res) => {
const file = res.tempFiles[0] const file = res.tempFiles[0]
// 检查文件大小是否符合限制 // 检查文件大小是否符合限制
if (!checkFileSize(file.size)) return if (!checkFileSize(file.size))
return
// 开始上传 // 开始上传
loading.value = true loading.value = true
@ -295,7 +287,8 @@ function uploadFile<T>({
// 上传成功 // 上传成功
data.value = _data as T data.value = _data as T
onSuccess?.(_data) onSuccess?.(_data)
} catch (err) { }
catch (err) {
// 响应解析错误 // 响应解析错误
console.error('解析上传响应失败:', err) console.error('解析上传响应失败:', err)
error.value = true error.value = true
@ -320,7 +313,8 @@ function uploadFile<T>({
progress.value = res.progress progress.value = res.progress
onProgress?.(res.progress) onProgress?.(res.progress)
}) })
} catch (err) { }
catch (err) {
// 创建上传任务失败 // 创建上传任务失败
console.error('创建上传任务失败:', err) console.error('创建上传任务失败:', err)
error.value = true error.value = true

View File

@ -1,21 +1,15 @@
{ {
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"skipLibCheck": true, "lib": ["esnext", "dom"],
"baseUrl": ".",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "Node", "moduleResolution": "Node",
"resolveJsonModule": true,
"noImplicitThis": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"sourceMap": true,
"baseUrl": ".",
"paths": { "paths": {
"@/*": ["./src/*"], "@/*": ["./src/*"],
"@img/*": ["./src/static/*"] "@img/*": ["./src/static/*"]
}, },
"outDir": "dist", "resolveJsonModule": true,
"lib": ["esnext", "dom"],
"types": [ "types": [
"@dcloudio/types", "@dcloudio/types",
"@uni-helper/uni-types", "@uni-helper/uni-types",
@ -23,12 +17,17 @@
"wot-design-uni/global.d.ts", "wot-design-uni/global.d.ts",
"z-paging/types", "z-paging/types",
"./src/typings.d.ts" "./src/typings.d.ts"
] ],
"allowJs": true,
"noImplicitThis": true,
"sourceMap": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"outDir": "dist"
}, },
"vueCompilerOptions": { "vueCompilerOptions": {
"plugins": ["@uni-helper/uni-types/volar-plugin"] "plugins": ["@uni-helper/uni-types/volar-plugin"]
}, },
"exclude": ["node_modules"],
"include": [ "include": [
"src/**/*.ts", "src/**/*.ts",
"src/**/*.js", "src/**/*.js",
@ -37,5 +36,6 @@
"src/**/*.jsx", "src/**/*.jsx",
"src/**/*.vue", "src/**/*.vue",
"src/**/*.json" "src/**/*.json"
] ],
"exclude": ["node_modules"]
} }

View File

@ -2,8 +2,8 @@
import { presetUni } from '@uni-helper/unocss-preset-uni' import { presetUni } from '@uni-helper/unocss-preset-uni'
import { import {
defineConfig, defineConfig,
presetIcons,
presetAttributify, presetAttributify,
presetIcons,
transformerDirectives, transformerDirectives,
transformerVariantGroup, transformerVariantGroup,
} from 'unocss' } from 'unocss'
@ -20,7 +20,7 @@ export default defineConfig({
scale: 1.2, scale: 1.2,
warn: true, warn: true,
extraProperties: { extraProperties: {
display: 'inline-block', 'display': 'inline-block',
'vertical-align': 'middle', 'vertical-align': 'middle',
}, },
}), }),

View File

@ -1,5 +1,5 @@
import path from 'node:path'
import fs from 'fs-extra' import fs from 'fs-extra'
import path from 'path'
export function copyNativeRes() { export function copyNativeRes() {
const waitPath = path.resolve(__dirname, '../src/nativeResources') const waitPath = path.resolve(__dirname, '../src/nativeResources')
@ -31,7 +31,8 @@ export function copyNativeRes() {
console.log( console.log(
`[copyNativeRes] 成功将 nativeResources 目录中的资源移动到构建目录:${buildPath}`, `[copyNativeRes] 成功将 nativeResources 目录中的资源移动到构建目录:${buildPath}`,
) )
} catch (error) { }
catch (error) {
console.error(`[copyNativeRes] 复制资源失败:`, error) console.error(`[copyNativeRes] 复制资源失败:`, error)
} }
}, },

View File

@ -1,14 +1,15 @@
// src/plugins/updatePackageJson.ts // src/plugins/updatePackageJson.ts
import { Plugin } from 'vite' import type { Plugin } from 'vite'
import fs from 'fs/promises' import fs from 'node:fs/promises'
import path from 'path' import path from 'node:path'
const updatePackageJson = (): Plugin => { function updatePackageJson(): Plugin {
return { return {
name: 'update-package-json', name: 'update-package-json',
async buildStart() { async buildStart() {
// 只在生产环境构建时执行 // 只在生产环境构建时执行
if (process.env.NODE_ENV !== 'production') return if (process.env.NODE_ENV !== 'production')
return
const packageJsonPath = path.resolve(process.cwd(), 'package.json') const packageJsonPath = path.resolve(process.cwd(), 'package.json')
@ -21,10 +22,11 @@ const updatePackageJson = (): Plugin => {
packageJson['update-time'] = new Date().toISOString().split('T')[0] // YYYY-MM-DD packageJson['update-time'] = new Date().toISOString().split('T')[0] // YYYY-MM-DD
// 写回文件(保持 2 空格缩进) // 写回文件(保持 2 空格缩进)
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf-8') await fs.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf-8')
console.log(`[update-package-json] 更新时间戳: ${packageJson['update-time']}`) console.log(`[update-package-json] 更新时间戳: ${packageJson['update-time']}`)
} catch (error) { }
catch (error) {
console.error('[update-package-json] 插件执行失败:', error) console.error('[update-package-json] 插件执行失败:', error)
} }
}, },

View File

@ -1,27 +1,26 @@
import Uni from '@dcloudio/vite-plugin-uni'
import dayjs from 'dayjs'
import path from 'node:path' import path from 'node:path'
import { defineConfig, loadEnv } from 'vite' import Uni from '@dcloudio/vite-plugin-uni'
// @see https://uni-helper.js.org/vite-plugin-uni-pages import Components from '@uni-helper/vite-plugin-uni-components'
import UniPages from '@uni-helper/vite-plugin-uni-pages'
// @see https://uni-helper.js.org/vite-plugin-uni-layouts // @see https://uni-helper.js.org/vite-plugin-uni-layouts
import UniLayouts from '@uni-helper/vite-plugin-uni-layouts' import UniLayouts from '@uni-helper/vite-plugin-uni-layouts'
// @see https://github.com/uni-helper/vite-plugin-uni-manifest
import UniManifest from '@uni-helper/vite-plugin-uni-manifest'
// @see https://uni-helper.js.org/vite-plugin-uni-pages
import UniPages from '@uni-helper/vite-plugin-uni-pages'
// @see https://github.com/uni-helper/vite-plugin-uni-platform // @see https://github.com/uni-helper/vite-plugin-uni-platform
// 需要与 @uni-helper/vite-plugin-uni-pages 插件一起使用 // 需要与 @uni-helper/vite-plugin-uni-pages 插件一起使用
import UniPlatform from '@uni-helper/vite-plugin-uni-platform' import UniPlatform from '@uni-helper/vite-plugin-uni-platform'
// @see https://github.com/uni-helper/vite-plugin-uni-manifest
import UniManifest from '@uni-helper/vite-plugin-uni-manifest'
/** /**
* *
* @see https://github.com/uni-ku/bundle-optimizer * @see https://github.com/uni-ku/bundle-optimizer
*/ */
import Optimization from '@uni-ku/bundle-optimizer' import Optimization from '@uni-ku/bundle-optimizer'
import dayjs from 'dayjs'
import { visualizer } from 'rollup-plugin-visualizer' import { visualizer } from 'rollup-plugin-visualizer'
import AutoImport from 'unplugin-auto-import/vite' import AutoImport from 'unplugin-auto-import/vite'
import { defineConfig, loadEnv } from 'vite'
import ViteRestart from 'vite-plugin-restart' import ViteRestart from 'vite-plugin-restart'
import { copyNativeRes } from './vite-plugins/copyNativeRes'
import updatePackageJson from './vite-plugins/updatePackageJson' import updatePackageJson from './vite-plugins/updatePackageJson'
import Components from '@uni-helper/vite-plugin-uni-components'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default async ({ command, mode }) => { export default async ({ command, mode }) => {
@ -75,7 +74,7 @@ export default async ({ command, mode }) => {
// 自定义插件禁用 vite:vue 插件的 devToolsEnabled强制编译 vue 模板时 inline 为 true // 自定义插件禁用 vite:vue 插件的 devToolsEnabled强制编译 vue 模板时 inline 为 true
name: 'fix-vite-plugin-vue', name: 'fix-vite-plugin-vue',
configResolved(config) { configResolved(config) {
const plugin = config.plugins.find((p) => p.name === 'vite:vue') const plugin = config.plugins.find(p => p.name === 'vite:vue')
if (plugin && plugin.api && plugin.api.options) { if (plugin && plugin.api && plugin.api.options) {
plugin.api.options.devToolsEnabled = false plugin.api.options.devToolsEnabled = false
} }
@ -91,7 +90,7 @@ export default async ({ command, mode }) => {
// Optimization 插件需要 page.json 文件,故应在 UniPages 插件之后执行 // Optimization 插件需要 page.json 文件,故应在 UniPages 插件之后执行
Optimization({ Optimization({
enable: { enable: {
optimization: true, 'optimization': true,
'async-import': true, 'async-import': true,
'async-component': true, 'async-component': true,
}, },
@ -113,14 +112,14 @@ export default async ({ command, mode }) => {
}, },
}, },
// 打包分析插件h5 + 生产环境才弹出 // 打包分析插件h5 + 生产环境才弹出
UNI_PLATFORM === 'h5' && UNI_PLATFORM === 'h5'
mode === 'production' && && mode === 'production'
visualizer({ && visualizer({
filename: './node_modules/.cache/visualizer/stats.html', filename: './node_modules/.cache/visualizer/stats.html',
open: true, open: true,
gzipSize: true, gzipSize: true,
brotliSize: true, brotliSize: true,
}), }),
// 只有在 app 平台时才启用 copyNativeRes 插件 // 只有在 app 平台时才启用 copyNativeRes 插件
// UNI_PLATFORM === 'app' && copyNativeRes(), // UNI_PLATFORM === 'app' && copyNativeRes(),
Components({ Components({
@ -163,7 +162,7 @@ export default async ({ command, mode }) => {
[VITE_APP_PROXY_PREFIX]: { [VITE_APP_PROXY_PREFIX]: {
target: VITE_SERVER_BASEURL, target: VITE_SERVER_BASEURL,
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${VITE_APP_PROXY_PREFIX}`), ''), rewrite: path => path.replace(new RegExp(`^${VITE_APP_PROXY_PREFIX}`), ''),
}, },
} }
: undefined, : undefined,