chore: chore update

This commit is contained in:
Z.X.PING
2025-07-02 22:09:08 +08:00
24 changed files with 549 additions and 174 deletions

2
.npmrc
View File

@@ -4,3 +4,5 @@ registry = https://registry.npmmirror.com
strict-peer-dependencies=false
auto-install-peers=true
shamefully-hoist=true
ignore-workspace-root-check=true
install-workspace-root=true

View File

@@ -1,14 +0,0 @@
node_modules
# unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用
auto-import.d.ts
# vite-plugin-uni-pages 生成的类型文件,每次切换分支都一堆不同的,所以直接 .gitignore
uni-pages.d.ts
# 插件生成的文件
src/pages.json
src/manifest.json
# 忽略自动生成文件
src/service/app/**

View File

@@ -1,19 +0,0 @@
// @see https://prettier.io/docs/en/options
module.exports = {
singleQuote: true,
printWidth: 100,
tabWidth: 2,
useTabs: false,
semi: false,
trailingComma: 'all',
endOfLine: 'auto',
htmlWhitespaceSensitivity: 'ignore',
overrides: [
{
files: '*.{json,jsonc}',
options: {
trailingComma: 'none',
},
},
],
}

77
.vscode/settings.json vendored
View File

@@ -1,54 +1,10 @@
{
// 默认格式化工具选择prettier
"editor.defaultFormatter": "esbenp.prettier-vscode",
// 配置stylelint检查的文件类型范围
"stylelint.validate": ["css", "scss", "vue", "html"], // 与package.json的scripts对应
"stylelint.enable": true,
"css.validate": false,
"less.validate": false,
"scss.validate": false,
"[shellscript]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[dotenv]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// 配置语言的文件关联
"files.associations": {
"pages.json": "jsonc", // pages.json 可以写注释
"manifest.json": "jsonc" // manifest.json 可以写注释
},
"cSpell.words": [
"aliyun",
"Aplipay",
"climblee",
"commitlint",
"dcloudio",
"iconfont",
"oxlint",
"qrcode",
"refresherrefresh",
"scrolltolower",
"tabbar",
"Toutiao",
"unibest",
"uview",
"uvui",
"vitepress",
"Wechat",
"WechatMiniprogram",
"Weixin"
],
"typescript.tsdk": "node_modules\\typescript\\lib",
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
@@ -59,16 +15,6 @@
"eslint.config.mjs": ".commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
},
// // 保存的时候自动格式化
// "prettier.enable": true,
// "editor.formatOnSave": true,
// // 开启自动修复
// "editor.codeActionsOnSave": {
// "source.fixAll": "explicit",
// "source.fixAll.eslint": "explicit",
// "source.fixAll.stylelint": "explicit"
// },
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
@@ -117,5 +63,26 @@
"scss",
"pcss",
"postcss"
],
"cSpell.words": [
"alova",
"Aplipay",
"climblee",
"commitlint",
"dcloudio",
"iconfont",
"oxlint",
"qrcode",
"refresherrefresh",
"scrolltolower",
"tabbar",
"Toutiao",
"uniapp",
"unibest",
"uview",
"uvui",
"Wechat",
"WechatMiniprogram",
"Weixin"
]
}

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 菲鸽
Copyright (c) 2025 菲鸽
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,11 +1,11 @@
<p align="center">
<a href="https://github.com/feige996/unibest">
<a href="https://github.com/unibest-tech/unibest">
<img width="160" src="./src/static/logo.svg">
</a>
</p>
<h1 align="center">
<a href="https://github.com/feige996/unibest" target="_blank">unibest - 最好的 uniapp 开发框架</a>
<a href="https://github.com/unibest-tech/unibest" target="_blank">unibest - 最好的 uniapp 开发框架</a>
</h1>
<div align="center">

5
env/.env vendored
View File

@@ -9,8 +9,11 @@ VITE_APP_PUBLIC_BASE=/
# 登录页面
VITE_LOGIN_URL = '/pages/login/index'
# 第一个请求地址
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
# 第二个请求地址
VITE_API_SECONDARY_URL = 'https://ukw0y1.laf.run'
VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'
# 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。

View File

@@ -7,6 +7,15 @@ export default uniHelper({
ignores: [
'src/uni_modules/',
'dist',
// unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用
'auto-import.d.ts',
// vite-plugin-uni-pages 生成的类型文件,每次切换分支都一堆不同的,所以直接 .gitignore
'uni-pages.d.ts',
// 插件生成的文件
'src/pages.json',
'src/manifest.json',
// 忽略自动生成文件
'src/service/app/**',
],
rules: {
'no-console': 'off',
@@ -19,4 +28,16 @@ export default uniHelper({
'ts/no-empty-object-type': 'off',
'no-extend-native': 'off',
},
formatters: {
/**
* Format CSS, LESS, SCSS files, also the `<style>` blocks in Vue
* By default uses Prettier
*/
css: true,
/**
* Format HTML files
* By default uses Prettier
*/
html: true,
},
})

View File

@@ -4,8 +4,14 @@ import process from 'node:process'
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
import { loadEnv } from 'vite'
// 手动解析命令行参数获取 mode
function getMode() {
const args = process.argv.slice(2)
const modeFlagIndex = args.findIndex(arg => arg === '--mode')
return modeFlagIndex !== -1 ? args[modeFlagIndex + 1] : args[0] === 'build' ? 'production' : 'development' // 默认 development
}
// 获取环境变量的范例
const env = loadEnv(process.env.NODE_ENV!, path.resolve(process.cwd(), 'env'))
const env = loadEnv(getMode(), path.resolve(process.cwd(), 'env'))
const {
VITE_APP_TITLE,
VITE_UNI_APPID,
@@ -24,7 +30,7 @@ export default defineManifestConfig({
'locale': VITE_FALLBACK_LOCALE, // 'zh-Hans'
'h5': {
router: {
base: VITE_APP_PUBLIC_BASE,
// base: VITE_APP_PUBLIC_BASE,
},
},
/* 5+App特有相关 */

View File

@@ -139,13 +139,13 @@
"@vue/tsconfig": "^0.1.3",
"autoprefixer": "^10.4.20",
"eslint": "^9.29.0",
"eslint-plugin-format": "^1.0.1",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"openapi-ts-request": "^1.1.2",
"postcss": "^8.4.49",
"postcss-html": "^1.7.0",
"postcss-scss": "^4.0.9",
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "1.77.8",
"terser": "^5.36.0",

94
pnpm-lock.yaml generated
View File

@@ -103,7 +103,7 @@ importers:
devDependencies:
'@antfu/eslint-config':
specifier: ^4.15.0
version: 4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)
version: 4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint-plugin-format@1.0.1(eslint@9.29.0(jiti@2.4.2)))(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)
'@commitlint/cli':
specifier: ^19.8.1
version: 19.8.1(@types/node@20.17.9)(typescript@5.7.2)
@@ -145,7 +145,7 @@ importers:
version: 3.4.8
'@uni-helper/eslint-config':
specifier: ^0.4.0
version: 0.4.0(@antfu/eslint-config@4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.29.0(jiti@2.4.2))
version: 0.4.0(@antfu/eslint-config@4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint-plugin-format@1.0.1(eslint@9.29.0(jiti@2.4.2)))(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.29.0(jiti@2.4.2))
'@uni-helper/uni-types':
specifier: 1.0.0-alpha.3
version: 1.0.0-alpha.3(@uni-helper/uni-app-types@1.0.0-alpha.3(typescript@5.7.2)(vue@3.5.15(typescript@5.7.2)))(@uni-helper/uni-cloud-types@1.0.0-alpha.3(typescript@5.7.2)(vue@3.5.15(typescript@5.7.2)))(@uni-helper/uni-ui-types@1.0.0-alpha.3(@uni-helper/uni-app-types@1.0.0-alpha.3(typescript@5.7.2)(vue@3.5.15(typescript@5.7.2)))(typescript@5.7.2)(vue@3.5.15(typescript@5.7.2)))(typescript@5.7.2)(vue@3.5.15(typescript@5.7.2))
@@ -188,6 +188,9 @@ importers:
eslint:
specifier: ^9.29.0
version: 9.29.0(jiti@2.4.2)
eslint-plugin-format:
specifier: ^1.0.1
version: 1.0.1(eslint@9.29.0(jiti@2.4.2))
husky:
specifier: ^9.1.7
version: 9.1.7
@@ -206,9 +209,6 @@ importers:
postcss-scss:
specifier: ^4.0.9
version: 4.0.9(postcss@8.4.49)
prettier:
specifier: ^3.5.3
version: 3.5.3
rollup-plugin-visualizer:
specifier: ^5.12.0
version: 5.12.0(rollup@4.41.1)
@@ -1149,6 +1149,15 @@ packages:
peerDependencies:
vite: ^5.2.8
'@dprint/formatter@0.3.0':
resolution: {integrity: sha512-N9fxCxbaBOrDkteSOzaCqwWjso5iAe+WJPsHC021JfHNj2ThInPNEF13ORDKta3llq5D1TlclODCvOvipH7bWQ==}
'@dprint/markdown@0.17.8':
resolution: {integrity: sha512-ukHFOg+RpG284aPdIg7iPrCYmMs3Dqy43S1ejybnwlJoFiW02b+6Bbr5cfZKFRYNP3dKGM86BqHEnMzBOyLvvA==}
'@dprint/toml@0.6.4':
resolution: {integrity: sha512-bZXIUjxr0LIuHWshZr/5mtUkOrnh0NKVZEF6ACojW5z7zkJu7s9sV2mMXm8XQDqN4cJzdHYUYzUyEGdfciaLJA==}
'@emnapi/core@1.4.3':
resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
@@ -1217,7 +1226,6 @@ packages:
'@esbuild/darwin-arm64@0.20.2':
resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.25.5':
@@ -1229,7 +1237,6 @@ packages:
'@esbuild/darwin-x64@0.20.2':
resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.25.5':
@@ -1945,6 +1952,10 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
'@pkgr/core@0.1.2':
resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@pkgr/core@0.2.7':
resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -1996,7 +2007,6 @@ packages:
'@rollup/rollup-darwin-x64@4.28.0':
resolution: {integrity: sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.41.1':
@@ -3554,6 +3564,11 @@ packages:
eslint-flat-config-utils@2.1.0:
resolution: {integrity: sha512-6fjOJ9tS0k28ketkUcQ+kKptB4dBZY2VijMZ9rGn8Cwnn1SH0cZBoPXT8AHBFHxmHcLFQK9zbELDinZ2Mr1rng==}
eslint-formatting-reporter@0.0.0:
resolution: {integrity: sha512-k9RdyTqxqN/wNYVaTk/ds5B5rA8lgoAmvceYN7bcZMBwU7TuXx5ntewJv81eF3pIL/CiJE+pJZm36llG8yhyyw==}
peerDependencies:
eslint: '>=8.40.0'
eslint-json-compat-utils@0.2.1:
resolution: {integrity: sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==}
engines: {node: '>=12'}
@@ -3570,6 +3585,9 @@ packages:
peerDependencies:
eslint: '*'
eslint-parser-plain@0.1.1:
resolution: {integrity: sha512-KRgd6wuxH4U8kczqPp+Oyk4irThIhHWxgFgLDtpgjUGVIS3wGrJntvZW/p6hHq1T4FOwnOtCNkvAI4Kr+mQ/Hw==}
eslint-plugin-antfu@3.1.1:
resolution: {integrity: sha512-7Q+NhwLfHJFvopI2HBZbSxWXngTwBLKxW1AGXLr2lEGxcEIK/AsDs8pn8fvIizl5aZjBbVbVK5ujmMpBe4Tvdg==}
peerDependencies:
@@ -3586,6 +3604,11 @@ packages:
peerDependencies:
eslint: '>=8'
eslint-plugin-format@1.0.1:
resolution: {integrity: sha512-Tdns+CDjS+m7QrM85wwRi2yLae88XiWVdIOXjp9mDII0pmTBQlczPCmjpKnjiUIY3yPZNLqb5Ms/A/JXcBF2Dw==}
peerDependencies:
eslint: ^8.40.0 || ^9.0.0
eslint-plugin-import-lite@0.3.0:
resolution: {integrity: sha512-dkNBAL6jcoCsXZsQ/Tt2yXmMDoNt5NaBh/U7yvccjiK8cai6Ay+MK77bMykmqQA2bTF6lngaLCDij6MTO3KkvA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -3778,6 +3801,9 @@ packages:
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
@@ -5413,6 +5439,10 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier-linter-helpers@1.0.0:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
prettier@3.5.3:
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
@@ -5864,6 +5894,10 @@ packages:
resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==}
engines: {node: ^14.18.0 || >=16.0.0}
synckit@0.9.3:
resolution: {integrity: sha512-JJoOEKTfL1urb1mDoEblhD9NhEbWmq9jHEMEnxoC4ujUaZ4itA8vKgwkFAyNClgxplLi9tsUKX+EduK0p/l7sg==}
engines: {node: ^14.18.0 || >=16.0.0}
systemjs@6.15.1:
resolution: {integrity: sha512-Nk8c4lXvMB98MtbmjX7JwJRgJOL8fluecYCfCeYBznwmpOs8Bf15hLM6z4z71EDAhQVrQrI+wt1aLWSXZq+hXA==}
@@ -6462,7 +6496,7 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
'@antfu/eslint-config@4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)':
'@antfu/eslint-config@4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint-plugin-format@1.0.1(eslint@9.29.0(jiti@2.4.2)))(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)':
dependencies:
'@antfu/install-pkg': 1.1.0
'@clack/prompts': 0.11.0
@@ -6503,6 +6537,7 @@ snapshots:
yaml-eslint-parser: 1.3.0
optionalDependencies:
'@unocss/eslint-plugin': 66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)
eslint-plugin-format: 1.0.1(eslint@9.29.0(jiti@2.4.2))
transitivePeerDependencies:
- '@eslint/json'
- '@vue/compiler-sfc'
@@ -8162,6 +8197,12 @@ snapshots:
- ts-node
- vue
'@dprint/formatter@0.3.0': {}
'@dprint/markdown@0.17.8': {}
'@dprint/toml@0.6.4': {}
'@emnapi/core@1.4.3':
dependencies:
'@emnapi/wasi-threads': 1.0.2
@@ -9039,6 +9080,8 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
'@pkgr/core@0.1.2': {}
'@pkgr/core@0.2.7': {}
'@polka/url@1.0.0-next.29': {}
@@ -9381,9 +9424,9 @@ snapshots:
'@typescript-eslint/types': 8.34.1
eslint-visitor-keys: 4.2.1
'@uni-helper/eslint-config@0.4.0(@antfu/eslint-config@4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.29.0(jiti@2.4.2))':
'@uni-helper/eslint-config@0.4.0(@antfu/eslint-config@4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint-plugin-format@1.0.1(eslint@9.29.0(jiti@2.4.2)))(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(eslint@9.29.0(jiti@2.4.2))':
dependencies:
'@antfu/eslint-config': 4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)
'@antfu/eslint-config': 4.15.0(@unocss/eslint-plugin@66.2.3(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2))(@vue/compiler-sfc@3.5.15)(eslint-plugin-format@1.0.1(eslint@9.29.0(jiti@2.4.2)))(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2)
'@eslint/eslintrc': 3.3.1
eslint: 9.29.0(jiti@2.4.2)
eslint-flat-config-utils: 2.1.0
@@ -10879,6 +10922,11 @@ snapshots:
dependencies:
pathe: 2.0.3
eslint-formatting-reporter@0.0.0(eslint@9.29.0(jiti@2.4.2)):
dependencies:
eslint: 9.29.0(jiti@2.4.2)
prettier-linter-helpers: 1.0.0
eslint-json-compat-utils@0.2.1(eslint@9.29.0(jiti@2.4.2))(jsonc-eslint-parser@2.4.0):
dependencies:
eslint: 9.29.0(jiti@2.4.2)
@@ -10889,6 +10937,8 @@ snapshots:
dependencies:
eslint: 9.29.0(jiti@2.4.2)
eslint-parser-plain@0.1.1: {}
eslint-plugin-antfu@3.1.1(eslint@9.29.0(jiti@2.4.2)):
dependencies:
eslint: 9.29.0(jiti@2.4.2)
@@ -10905,6 +10955,17 @@ snapshots:
eslint: 9.29.0(jiti@2.4.2)
eslint-compat-utils: 0.5.1(eslint@9.29.0(jiti@2.4.2))
eslint-plugin-format@1.0.1(eslint@9.29.0(jiti@2.4.2)):
dependencies:
'@dprint/formatter': 0.3.0
'@dprint/markdown': 0.17.8
'@dprint/toml': 0.6.4
eslint: 9.29.0(jiti@2.4.2)
eslint-formatting-reporter: 0.0.0(eslint@9.29.0(jiti@2.4.2))
eslint-parser-plain: 0.1.1
prettier: 3.5.3
synckit: 0.9.3
eslint-plugin-import-lite@0.3.0(eslint@9.29.0(jiti@2.4.2))(typescript@5.7.2):
dependencies:
'@eslint-community/eslint-utils': 4.7.0(eslint@9.29.0(jiti@2.4.2))
@@ -11235,6 +11296,8 @@ snapshots:
fast-deep-equal@3.1.3: {}
fast-diff@1.3.0: {}
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -13245,6 +13308,10 @@ snapshots:
prelude-ls@1.2.1: {}
prettier-linter-helpers@1.0.0:
dependencies:
fast-diff: 1.3.0
prettier@3.5.3: {}
pretty-format@27.5.1:
@@ -13712,6 +13779,11 @@ snapshots:
dependencies:
'@pkgr/core': 0.2.7
synckit@0.9.3:
dependencies:
'@pkgr/core': 0.1.2
tslib: 2.8.1
systemjs@6.15.1: {}
tapable@2.2.1: {}

View File

@@ -1,2 +1,6 @@
packages:
- '**'
- '!node_modules'
patchedDependencies:
'@dcloudio/uni-h5': patches/@dcloudio__uni-h5.patch

View File

@@ -1,16 +1,17 @@
import { http } from '@/utils/request/alova'
import { API_DOMAINS, http } from '@/utils/request/alova'
export interface IFooItem {
id: string
export interface IFoo {
id: number
name: string
}
export function foo() {
return http.Get<IFooItem>('/foo', {
return http.Get<IFoo>('/foo', {
params: {
name: '菲鸽',
page: 1,
pageSize: 10,
},
meta: { domain: API_DOMAINS.SECONDARY }, // 用于切换请求地址
})
}

View File

@@ -1,4 +1,4 @@
import type { UnwrapRef } from 'vue'
import type { Ref } from 'vue'
interface IUseRequestOptions<T> {
/** 是否立即执行 */
@@ -7,6 +7,13 @@ interface IUseRequestOptions<T> {
initialData?: T
}
interface IUseRequestReturn<T> {
loading: Ref<boolean>
error: Ref<boolean | Error>
data: Ref<T | undefined>
run: () => Promise<T | undefined>
}
/**
* useRequest是一个定制化的请求钩子用于处理异步请求和响应。
* @param func 一个执行异步请求的函数返回一个包含响应数据的Promise。
@@ -18,15 +25,15 @@ interface IUseRequestOptions<T> {
export default function useRequest<T>(
func: () => Promise<IResData<T>>,
options: IUseRequestOptions<T> = { immediate: false },
) {
): IUseRequestReturn<T> {
const loading = ref(false)
const error = ref(false)
const data = ref<T>(options.initialData)
const data = ref<T | undefined>(options.initialData) as Ref<T | undefined>
const run = async () => {
loading.value = true
return func()
.then((res) => {
data.value = res.data as UnwrapRef<T>
data.value = res.data
error.value = false
return data.value
})

View File

@@ -1,10 +1,12 @@
<script setup lang="ts">
import { tabbarStore } from './tabbar'
// 'i-carbon-code',
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy } from './tabbarList'
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy, TABBAR_MAP } from './tabbarList'
const customTabbarEnable
= selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE
|| selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITHOUT_CACHE
// @ts-expect-error 预知的判断
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 }) {
@@ -19,8 +21,7 @@ function selectTabBar({ value: index }: { value: number }) {
}
onLoad(() => {
// 解决原生 tabBar 未隐藏导致有2个 tabBar 的问题
// @ts-expect-error 预知的判断
const hideRedundantTabbarEnable = selectedTabbarStrategy === 1
const hideRedundantTabbarEnable = selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE
hideRedundantTabbarEnable
&& uni.hideTabBar({
fail(err) {

View File

@@ -2,15 +2,16 @@
`tabbar` 分为 `4 种` 情况:
- 0 `完全原生 tabbar`使用 `switchTab` 切换 tabbar`tabbar` 页面有缓存
- 0 ` tabbar`只有一个页面入口,底部无 `tabbar` 显示;常用语临时活动页
- 1 `原生 tabbar`,使用 `switchTab` 切换 tabbar`tabbar` 页面有缓存。
- 优势:原生自带的 tabbar最先渲染有缓存。
- 劣势:只能使用 2 组图片来切换选中和非选中状态,修改颜色只能重新换图片(或者用 iconfont
- 1 `自定义 tabbar`,使用 `switchTab` 切换 tabbar`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。
- 2 `有缓存自定义 tabbar`,使用 `switchTab` 切换 tabbar`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。
- 优势:可以随意配置自己想要的 `svg icon`,切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。
- 劣势:首次点击 tababr 会闪烁。
- 2 `自定义 tabbar`,使用 `navigateTo` 切换 `tabbar``tabbar` 页面无缓存。使用了第三方 UI 库的 `tabbar` 组件。
- 3 `无缓存自定义 tabbar`,使用 `navigateTo` 切换 `tabbar``tabbar` 页面无缓存。使用了第三方 UI 库的 `tabbar` 组件。
- 优势:可以随意配置自己想要的 svg icon切换字体颜色方便。可以实现各种花里胡哨的动效等。
- 劣势:首次点击 `tababr` 会闪烁,无缓存。
- 3 `无 tabbar`,只有一个页面入口,底部无 `tabbar` 显示;常用语临时活动页。
> 注意:花里胡哨的效果需要自己实现,本模版不提供。

View File

@@ -1,19 +1,24 @@
/**
* tabbar 选择的策略,更详细的介绍见 tabbar.md 文件
* 0: 'NATIVE_TABBAR' `完全原生 tabbar`
* 2: 'FULL_CUSTOM_TABBAR' `全自定义 tabbar`
* 1: 'HALF_CUSTOM_TABBAR' `半自定义 tabbar`
* 3: 'NO_TABBAR' `无 tabbar`
* 0: 'NO_TABBAR' `无 tabbar`
* 1: 'NATIVE_TABBAR' `完全原生 tabbar`
* 2: 'CUSTOM_TABBAR_WITH_CACHE' `有缓存自定义 tabbar`
* 3: 'CUSTOM_TABBAR_WITHOUT_CACHE' `无缓存自定义 tabbar`
*
* 温馨提示:本文件的任何代码更改了之后,都需要重新运行,否则 pages.json 不会更新导致错误
*/
export const TABBAR_MAP = {
NO_TABBAR: 0,
NATIVE_TABBAR: 1,
CUSTOM_TABBAR_WITH_CACHE: 2,
CUSTOM_TABBAR_WITHOUT_CACHE: 3,
}
// TODO通过这里切换使用tabbar的策略
export const selectedTabbarStrategy = 0
export const selectedTabbarStrategy = TABBAR_MAP.NATIVE_TABBAR
// selectedTabbarStrategy==0 时,需要填 iconPath 和 selectedIconPath
// selectedTabbarStrategy==1 or 2 时,需要填 icon 和 iconType
// selectedTabbarStrategy==3tabbarList 不生效
// selectedTabbarStrategy==NATIVE_TABBAR(1) 时,需要填 iconPath 和 selectedIconPath
// selectedTabbarStrategy==CUSTOM_TABBAR(2,3) 时,需要填 icon 和 iconType
// selectedTabbarStrategy==NO_TABBAR(0)tabbarList 不生效
export const tabbarList = [
{
iconPath: 'static/tabbar/home.png',
@@ -21,6 +26,7 @@ export const tabbarList = [
pagePath: 'pages/index/index',
text: '首页',
icon: 'home',
// 选用 UI 框架自带的 icon时iconType 为 uiLib
iconType: 'uiLib',
},
{
@@ -46,8 +52,9 @@ export const tabbarList = [
// },
]
// 0 和 1需要tabbar缓存
export const cacheTabbarEnable = selectedTabbarStrategy < 2
// NATIVE_TABBAR(1) 和 CUSTOM_TABBAR_WITH_CACHE(2)需要tabbar缓存
export const cacheTabbarEnable = selectedTabbarStrategy === TABBAR_MAP.NATIVE_TABBAR
|| selectedTabbarStrategy === TABBAR_MAP.CUSTOM_TABBAR_WITH_CACHE
const _tabbar = {
color: '#999999',

View File

@@ -106,8 +106,6 @@
},
"vueVersion": "3",
"h5": {
"router": {
"base": "/"
}
"router": {}
}
}

View File

@@ -12,6 +12,7 @@ import { useRequest } from 'alova/client'
import { foo } from '@/api/alova-foo'
const initialData = undefined
const { loading, data, send } = useRequest(foo, {
initialData,
immediate: true,
@@ -39,6 +40,10 @@ function reset() {
{{ JSON.stringify(data) }}
</view>
</block>
<view class="text-red">
{{ data?.id }}
</view>
</view>
<button class="my-6 w-200px text-red" :disabled="!data" @click="reset">
重置数据

150
src/utils/dateUtil.ts Normal file
View File

@@ -0,0 +1,150 @@
import dayjs from 'dayjs'
import calendar from 'dayjs/plugin/calendar'
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
import relativeTime from 'dayjs/plugin/relativeTime'
import updateLocale from 'dayjs/plugin/updateLocale'
import utc from 'dayjs/plugin/utc'
import weekday from 'dayjs/plugin/weekday'
import 'dayjs/locale/zh-cn'
dayjs.extend(calendar)
dayjs.extend(quarterOfYear)
dayjs.extend(relativeTime)
dayjs.extend(updateLocale)
dayjs.extend(utc)
dayjs.extend(weekday)
dayjs.locale('zh-cn')
dayjs.updateLocale('zh-cn', {
calendar: {
sameDay: 'HH:mm',
nextDay: '[明天]',
nextWeek: 'dddd',
lastDay: '[昨天] HH:mm',
lastWeek: 'dddd HH:mm',
sameElse: 'YYYY年M月D日 HH:mm',
},
relativeTime: {
future: '%s后',
past: '%s前',
s: '几秒',
m: '1分钟',
mm: '%d分钟',
h: '1小时',
hh: '%d小时',
d: '1天',
dd: '%d天',
M: '1个月',
MM: '%d个月',
y: '1年',
yy: '%d年',
},
})
/** 时间工具 */
export const dateUtil = dayjs
export const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
export const DATE_FORMAT = 'YYYY-MM-DD'
export const TIME_FORMAT = 'HH:mm'
/**
* 格式化日期
* @param _date 日期对象、时间戳或字符串
* @param format 格式字符串
* @returns 格式化后的日期字符串
*/
function _format(_date: dayjs.ConfigType, format: string): string {
if (!_date) {
return _date as any
}
const date = dateUtil(_date)
return date.isValid() ? date.format(format) : (_date as string)
}
/**
* 格式化为日期时间字符串
* @param date 日期对象、时间戳或字符串
* @param format 格式字符串,默认为 DATETIME_FORMAT
* @returns 格式化后的日期时间字符串
*/
export function formatToDatetime(date: dayjs.ConfigType = undefined, format: string = DATETIME_FORMAT): string {
return _format(date, format)
}
/**
* 格式化为日期字符串
* @param date 日期对象、时间戳或字符串
* @param format 格式字符串,默认为 DATE_FORMAT
* @returns 格式化后的日期字符串
*/
export function formatToDate(date: dayjs.ConfigType = undefined, format: string = DATE_FORMAT): string {
return _format(date, format)
}
/**
* 格式化为日期字符串
* @param date 日期对象、时间戳或字符串
* @param format 格式字符串,默认为 TIME_FORMAT
* @returns 格式化后的日期字符串
*/
export function formatToTime(date: dayjs.ConfigType = undefined, format: string = TIME_FORMAT): string {
return _format(date, format)
}
/**
* 时间人性化显示
* @param date 要格式化的日期
* @param oppositeDate 参考日期,默认为当前时间
* @returns 人性化的时间字符串
*/
export function humanizedDate(date: dayjs.ConfigType, oppositeDate: dayjs.ConfigType = undefined): string {
if (!date || !dateUtil(date).isValid()) {
return ''
}
const now = oppositeDate ? dateUtil(oppositeDate) : dateUtil()
const diffSeconds = now.diff(date, 'second')
const diffMinutes = now.diff(date, 'minute')
const diffHours = now.diff(date, 'hour')
const diffDays = now.diff(date, 'day')
if (diffSeconds < 60) {
return `${diffSeconds}秒前`
}
else if (diffMinutes < 60) {
return `${diffMinutes}分钟前`
}
else if (diffHours < 24) {
return `${diffHours}小时前`
}
else if (diffDays < 7) {
return `${diffDays}天前`
}
else {
return formatToDatetime(date)
}
}
/**
* 获取时辰问候语
* @returns 根据当前时间返回相应的问候语
*/
export function getGreeting(): string {
const currentHour = dateUtil().hour()
if (currentHour >= 5 && currentHour < 12) {
return '早上好'
}
else if (currentHour >= 12 && currentHour < 14) {
return '中午好'
}
else if (currentHour >= 14 && currentHour < 18) {
return '下午好'
}
else if (currentHour >= 18 && currentHour < 24) {
return '晚上好'
}
else {
return '深夜了'
}
}

View File

@@ -1,35 +1,111 @@
import type { uniappRequestAdapter } from '@alova/adapter-uniapp'
import type { IResponse } from './types'
import AdapterUniapp from '@alova/adapter-uniapp'
import { createAlova } from 'alova'
import { createServerTokenAuthentication } from 'alova/client'
import VueHook from 'alova/vue'
import { toast } from '@/utils/toast'
import { ContentTypeEnum, ResultEnum, ShowMessage } from './enum'
const baseURL = JSON.parse(__VITE_APP_PROXY__)
? import.meta.env.VITE_APP_PROXY_PREFIX
: import.meta.env.VITE_SERVER_BASEURL
// 配置动态Tag
export const API_DOMAINS = {
DEFAULT: import.meta.env.VITE_SERVER_BASEURL,
SECONDARY: import.meta.env.VITE_API_SECONDARY_URL,
}
export const http = createAlova({
baseURL,
...AdapterUniapp(),
async responded(res: UniApp.RequestSuccessCallbackResult, method) {
console.log('responded:', method, res)
// 请求成功的拦截器
// 状态码 2xx参考 axios 的设计
const resData = res.data as IResData<any>
if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data
return resData.data
}
else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页
// userStore.clearUserInfo()
// uni.navigateTo({ url: '/pages/login/login' })
console.log(res)
throw new Error(resData.msg || '401错误')
}
else {
uni.showToast({
icon: 'none',
title: (resData).msg || '请求错误',
})
throw new Error(resData.msg || '请求错误')
}
/**
* 创建请求实例
*/
const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication<
typeof VueHook,
typeof uniappRequestAdapter
>({
refreshTokenOnError: {
isExpired: (error) => {
return error.response?.status === ResultEnum.Unauthorized
},
handler: async () => {
try {
// await authLogin();
}
catch (error) {
// 切换到登录页
await uni.reLaunch({ url: '/pages/common/login/index' })
throw error
}
},
},
})
/**
* alova 请求实例
*/
const alovaInstance = createAlova({
baseURL: import.meta.env.VITE_API_BASE_URL,
...AdapterUniapp(),
timeout: 5000,
statesHook: VueHook,
beforeRequest: onAuthRequired((method) => {
// 设置默认 Content-Type
method.config.headers = {
ContentType: ContentTypeEnum.JSON,
Accept: 'application/json, text/plain, */*',
...method.config.headers,
}
const { config } = method
const ignoreAuth = !config.meta?.ignoreAuth
console.log('ignoreAuth===>', ignoreAuth)
// 处理认证信息 自行处理认证问题
if (ignoreAuth) {
const token = 'getToken()'
if (!token) {
throw new Error('[请求错误]:未登录')
}
// method.config.headers.token = token;
}
// 处理动态域名
if (config.meta?.domain) {
method.baseURL = config.meta.domain
console.log('当前域名', method.baseURL)
}
}),
responded: onResponseRefreshToken((response, method) => {
const { config } = method
const { requestType } = config
const {
statusCode,
data: rawData,
errMsg,
} = response as UniNamespace.RequestSuccessCallbackResult
// 处理特殊请求类型(上传/下载)
if (requestType === 'upload' || requestType === 'download') {
return response
}
// 处理 HTTP 状态码错误
if (statusCode !== 200) {
const errorMessage = ShowMessage(statusCode) || `HTTP请求错误[${statusCode}]`
console.error('errorMessage===>', errorMessage)
toast.error(errorMessage)
throw new Error(`${errorMessage}${errMsg}`)
}
// 处理业务逻辑错误
const { code, message, data } = rawData as IResponse
if (code !== ResultEnum.Success) {
if (config.meta?.toast !== false) {
toast.warning(message)
}
throw new Error(`请求错误[${code}]${message}`)
}
// 处理成功响应,返回业务数据
return data
}),
})
export const http = alovaInstance

66
src/utils/request/enum.ts Normal file
View File

@@ -0,0 +1,66 @@
export enum ResultEnum {
Success = 0, // 成功
Error = 400, // 错误
Unauthorized = 401, // 未授权
Forbidden = 403, // 禁止访问原为forbidden
NotFound = 404, // 未找到原为notFound
MethodNotAllowed = 405, // 方法不允许原为methodNotAllowed
RequestTimeout = 408, // 请求超时原为requestTimeout
InternalServerError = 500, // 服务器错误原为internalServerError
NotImplemented = 501, // 未实现原为notImplemented
BadGateway = 502, // 网关错误原为badGateway
ServiceUnavailable = 503, // 服务不可用原为serviceUnavailable
GatewayTimeout = 504, // 网关超时原为gatewayTimeout
HttpVersionNotSupported = 505, // HTTP版本不支持原为httpVersionNotSupported
}
export enum ContentTypeEnum {
JSON = 'application/json;charset=UTF-8',
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
FORM_DATA = 'multipart/form-data;charset=UTF-8',
}
/**
* 根据状态码,生成对应的错误信息
* @param {number|string} status 状态码
* @returns {string} 错误信息
*/
export function ShowMessage(status: number | string): string {
let message: string
switch (status) {
case 400:
message = '请求错误(400)'
break
case 401:
message = '未授权,请重新登录(401)'
break
case 403:
message = '拒绝访问(403)'
break
case 404:
message = '请求出错(404)'
break
case 408:
message = '请求超时(408)'
break
case 500:
message = '服务器错误(500)'
break
case 501:
message = '服务未实现(501)'
break
case 502:
message = '网络错误(502)'
break
case 503:
message = '服务不可用(503)'
break
case 504:
message = '网络超时(504)'
break
case 505:
message = 'HTTP版本不受支持(505)'
break
default:
message = `连接出错(${status})!`
}
return `${message},请检查网络或联系管理员!`
}

View File

@@ -0,0 +1,22 @@
// 通用响应格式
export interface IResponse<T = any> {
code: number | string
data: T
message: string
status: string | number
}
// 分页请求参数
export interface PageParams {
page: number
pageSize: number
[key: string]: any
}
// 分页响应数据
export interface PageResult<T> {
list: T[]
total: number
page: number
pageSize: number
}

View File

@@ -48,6 +48,7 @@ export default async ({ command, mode }) => {
VITE_SERVER_BASEURL,
VITE_DELETE_CONSOLE,
VITE_SHOW_SOURCEMAP,
VITE_APP_PUBLIC_BASE,
VITE_APP_PROXY,
VITE_APP_PROXY_PREFIX,
} = env
@@ -55,7 +56,7 @@ export default async ({ command, mode }) => {
return {
envDir: './env', // 自定义env目录
base: VITE_APP_PUBLIC_BASE,
plugins: [
UniPages({
exclude: ['**/components/**/**.*'],
@@ -168,19 +169,17 @@ export default async ({ command, mode }) => {
}
: undefined,
},
esbuild: {
drop: VITE_DELETE_CONSOLE === 'true' ? ['console', 'debugger'] : ['debugger'],
},
build: {
sourcemap: false,
// 方便非h5端调试
// sourcemap: VITE_SHOW_SOURCEMAP === 'true', // 默认是false
target: 'es6',
// 开发环境不用压缩
minify: mode === 'development' ? false : 'terser',
terserOptions: {
compress: {
drop_console: VITE_DELETE_CONSOLE === 'true',
drop_debugger: true,
},
},
minify: mode === 'development' ? false : 'esbuild',
},
}
}