Compare commits
No commits in common. "main" and "v2.15.0" have entirely different histories.
@ -1,3 +1,106 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { execSync } = require('child_process')
|
||||
|
||||
const scopes = fs
|
||||
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name.replace(/s$/, ''))
|
||||
|
||||
// precomputed scope
|
||||
const scopeComplete = execSync('git status --porcelain || true')
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.find((r) => ~r.indexOf('M src'))
|
||||
?.replace(/(\/)/g, '%%')
|
||||
?.match(/src%%((\w|-)*)/)?.[1]
|
||||
?.replace(/s$/, '')
|
||||
|
||||
module.exports = {
|
||||
ignores: [(commit) => commit.includes('init')],
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
rules: {
|
||||
'body-leading-blank': [2, 'always'],
|
||||
'footer-leading-blank': [1, 'always'],
|
||||
'header-max-length': [2, 'always', 108],
|
||||
'subject-empty': [2, 'never'],
|
||||
'type-empty': [2, 'never'],
|
||||
'subject-case': [0],
|
||||
'type-enum': [
|
||||
2,
|
||||
'always',
|
||||
[
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'style',
|
||||
'docs',
|
||||
'test',
|
||||
'refactor',
|
||||
'build',
|
||||
'ci',
|
||||
'chore',
|
||||
'revert',
|
||||
'wip',
|
||||
'workflow',
|
||||
'types',
|
||||
'release',
|
||||
],
|
||||
],
|
||||
},
|
||||
prompt: {
|
||||
/** @use `pnpm commit :f` */
|
||||
alias: {
|
||||
f: 'docs: fix typos',
|
||||
r: 'docs: update README',
|
||||
s: 'style: update code format',
|
||||
b: 'build: bump dependencies',
|
||||
c: 'chore: update config',
|
||||
},
|
||||
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
|
||||
defaultScope: scopeComplete,
|
||||
scopes: [...scopes, 'mock'],
|
||||
allowEmptyIssuePrefixs: false,
|
||||
allowCustomIssuePrefixs: false,
|
||||
|
||||
// English
|
||||
typesAppend: [
|
||||
{ value: 'wip', name: 'wip: work in process' },
|
||||
{ value: 'workflow', name: 'workflow: workflow improvements' },
|
||||
{ value: 'types', name: 'types: type definition file changes' },
|
||||
],
|
||||
|
||||
// 中英文对照版
|
||||
// messages: {
|
||||
// type: '选择你要提交的类型 :',
|
||||
// scope: '选择一个提交范围 (可选):',
|
||||
// customScope: '请输入自定义的提交范围 :',
|
||||
// subject: '填写简短精炼的变更描述 :\n',
|
||||
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
|
||||
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
|
||||
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
|
||||
// customFooterPrefixs: '输入自定义issue前缀 :',
|
||||
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
|
||||
// confirmCommit: '是否提交或修改commit ?',
|
||||
// },
|
||||
// types: [
|
||||
// { value: 'feat', name: 'feat: 新增功能' },
|
||||
// { value: 'fix', name: 'fix: 修复缺陷' },
|
||||
// { value: 'docs', name: 'docs: 文档变更' },
|
||||
// { value: 'style', name: 'style: 代码格式' },
|
||||
// { value: 'refactor', name: 'refactor: 代码重构' },
|
||||
// { value: 'perf', name: 'perf: 性能优化' },
|
||||
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
|
||||
// { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
|
||||
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
|
||||
// { value: 'revert', name: 'revert: 回滚 commit' },
|
||||
// { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
|
||||
// { value: 'wip', name: 'wip: 正在开发中' },
|
||||
// { value: 'workflow', name: 'workflow: 工作流程改进' },
|
||||
// { value: 'types', name: 'types: 类型定义文件修改' },
|
||||
// ],
|
||||
// emptyScopesAlias: 'empty: 不填写',
|
||||
// customScopesAlias: 'custom: 自定义',
|
||||
},
|
||||
}
|
||||
|
60
.github/release.yml
vendored
60
.github/release.yml
vendored
@ -1,31 +1,31 @@
|
||||
categories:
|
||||
- title: 🚀 新功能
|
||||
labels: [feat, feature]
|
||||
- title: 🛠️ 修复
|
||||
labels: [fix, bugfix]
|
||||
- title: 💅 样式
|
||||
labels: [style]
|
||||
- title: 📄 文档
|
||||
labels: [docs]
|
||||
- title: ⚡️ 性能
|
||||
labels: [perf]
|
||||
- title: 🧪 测试
|
||||
labels: [test]
|
||||
- title: ♻️ 重构
|
||||
labels: [refactor]
|
||||
- title: 📦 构建
|
||||
labels: [build]
|
||||
- title: 🚨 补丁
|
||||
labels: [patch, hotfix]
|
||||
- title: 🌐 发布
|
||||
labels: [release, publish]
|
||||
- title: 🔧 流程
|
||||
labels: [ci, cd, workflow]
|
||||
- title: ⚙️ 配置
|
||||
labels: [config, chore]
|
||||
- title: 📁 文件
|
||||
labels: [file]
|
||||
- title: 🎨 格式化
|
||||
labels: [format]
|
||||
- title: 🔀 其他
|
||||
labels: [other, misc]
|
||||
- title: '🚀 新功能'
|
||||
labels: ['feat', 'feature']
|
||||
- title: '🛠️ 修复'
|
||||
labels: ['fix', 'bugfix']
|
||||
- title: '💅 样式'
|
||||
labels: ['style']
|
||||
- title: '📄 文档'
|
||||
labels: ['docs']
|
||||
- title: '⚡️ 性能'
|
||||
labels: ['perf']
|
||||
- title: '🧪 测试'
|
||||
labels: ['test']
|
||||
- title: '♻️ 重构'
|
||||
labels: ['refactor']
|
||||
- title: '📦 构建'
|
||||
labels: ['build']
|
||||
- title: '🚨 补丁'
|
||||
labels: ['patch', 'hotfix']
|
||||
- title: '🌐 发布'
|
||||
labels: ['release', 'publish']
|
||||
- title: '🔧 流程'
|
||||
labels: ['ci', 'cd', 'workflow']
|
||||
- title: '⚙️ 配置'
|
||||
labels: ['config', 'chore']
|
||||
- title: '📁 文件'
|
||||
labels: ['file']
|
||||
- title: '🎨 格式化'
|
||||
labels: ['format']
|
||||
- title: '🔀 其他'
|
||||
labels: ['other', 'misc']
|
||||
|
54
.github/workflows/auto-merge.yml
vendored
54
.github/workflows/auto-merge.yml
vendored
@ -24,57 +24,3 @@ jobs:
|
||||
git checkout i18n
|
||||
git merge main --no-ff -m "Auto merge main into i18n"
|
||||
git push origin i18n
|
||||
|
||||
merge-to-base-sard-ui:
|
||||
name: Merge main into base-sard-ui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||
|
||||
- name: Merge main into base-sard-ui
|
||||
run: |
|
||||
git config user.name "GitHub Actions"
|
||||
git config user.email "actions@github.com"
|
||||
git checkout base-sard-ui
|
||||
git merge main --no-ff -m "Auto merge main into base-sard-ui"
|
||||
git push origin base-sard-ui
|
||||
|
||||
merge-to-base-uv-ui:
|
||||
name: Merge main into base-uv-ui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||
|
||||
- name: Merge main into base-uv-ui
|
||||
run: |
|
||||
git config user.name "GitHub Actions"
|
||||
git config user.email "actions@github.com"
|
||||
git checkout base-uv-ui
|
||||
git merge main --no-ff -m "Auto merge main into base-uv-ui"
|
||||
git push origin base-uv-ui
|
||||
|
||||
merge-to-base-uview-plus:
|
||||
name: Merge main into base-uview-plus
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
|
||||
|
||||
- name: Merge main into base-uview-plus
|
||||
run: |
|
||||
git config user.name "GitHub Actions"
|
||||
git config user.email "actions@github.com"
|
||||
git checkout base-uview-plus
|
||||
git merge main --no-ff -m "Auto merge main into base-uview-plus"
|
||||
git push origin base-uview-plus
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -27,7 +27,7 @@ dist
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
|
||||
src/types
|
||||
types
|
||||
|
||||
# lock 文件还是不要了,我主要的版本写死就好了
|
||||
# pnpm-lock.yaml
|
||||
|
34
.oxlintrc.json
Normal file
34
.oxlintrc.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"extends": ["config:recommended"],
|
||||
"plugins": ["import", "typescript", "unicorn"],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"no-unused-vars": "off"
|
||||
},
|
||||
"env": {
|
||||
"es6": true
|
||||
},
|
||||
"globals": {
|
||||
"foo": "readonly"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"src/static/**",
|
||||
"src/uni_modules/**",
|
||||
"vite.config.ts",
|
||||
"uno.config.ts",
|
||||
"pages.config.ts",
|
||||
"manifest.config.ts"
|
||||
],
|
||||
"settings": {},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.test.ts", "*.spec.ts"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
76
.vscode/settings.json
vendored
76
.vscode/settings.json
vendored
@ -1,7 +1,14 @@
|
||||
{
|
||||
// 默认格式化工具选择prettier
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
|
||||
// 保存的时候自动格式化
|
||||
"editor.formatOnSave": true,
|
||||
//开启自动修复
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit",
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.stylelint": "explicit"
|
||||
},
|
||||
// 配置stylelint检查的文件类型范围
|
||||
"stylelint.validate": ["css", "scss", "vue", "html"], // 与package.json的scripts对应
|
||||
"stylelint.enable": true,
|
||||
@ -41,7 +48,6 @@
|
||||
"tabbar",
|
||||
"Toutiao",
|
||||
"unibest",
|
||||
"uview",
|
||||
"uvui",
|
||||
"Wechat",
|
||||
"WechatMiniprogram",
|
||||
@ -53,67 +59,7 @@
|
||||
"explorer.fileNesting.patterns": {
|
||||
"README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md",
|
||||
"pages.config.ts": "manifest.config.ts,openapi-ts-request.config.ts",
|
||||
"package.json": "tsconfig.json,pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
|
||||
"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,
|
||||
|
||||
// Auto fix
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
|
||||
// Silent the stylistic rules in you IDE, but still auto fix them
|
||||
"eslint.rules.customizations": [
|
||||
{ "rule": "style/*", "severity": "off", "fixable": true },
|
||||
{ "rule": "format/*", "severity": "off", "fixable": true },
|
||||
{ "rule": "*-indent", "severity": "off", "fixable": true },
|
||||
{ "rule": "*-spacing", "severity": "off", "fixable": true },
|
||||
{ "rule": "*-spaces", "severity": "off", "fixable": true },
|
||||
{ "rule": "*-order", "severity": "off", "fixable": true },
|
||||
{ "rule": "*-dangle", "severity": "off", "fixable": true },
|
||||
{ "rule": "*-newline", "severity": "off", "fixable": true },
|
||||
{ "rule": "*quotes", "severity": "off", "fixable": true },
|
||||
{ "rule": "*semi", "severity": "off", "fixable": true }
|
||||
],
|
||||
|
||||
// Enable eslint for all supported languages
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"vue",
|
||||
"html",
|
||||
"markdown",
|
||||
"json",
|
||||
"json5",
|
||||
"jsonc",
|
||||
"yaml",
|
||||
"toml",
|
||||
"xml",
|
||||
"gql",
|
||||
"graphql",
|
||||
"astro",
|
||||
"svelte",
|
||||
"css",
|
||||
"less",
|
||||
"scss",
|
||||
"pcss",
|
||||
"postcss"
|
||||
]
|
||||
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
|
||||
".oxlintrc.json": "tsconfig.json,.commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
|
||||
}
|
||||
}
|
||||
|
26
.vscode/vue3.code-snippets
vendored
26
.vscode/vue3.code-snippets
vendored
@ -27,12 +27,12 @@
|
||||
" },",
|
||||
"}",
|
||||
"</route>\n",
|
||||
"<script lang=\"ts\" setup>",
|
||||
"//$3",
|
||||
"</script>\n",
|
||||
"<template>",
|
||||
" <view class=\"\">$2</view>",
|
||||
"</template>\n",
|
||||
"<script lang=\"ts\" setup>",
|
||||
"//$3",
|
||||
"</script>\n",
|
||||
"<style lang=\"scss\" scoped>",
|
||||
"//$4",
|
||||
"</style>\n",
|
||||
@ -41,28 +41,16 @@
|
||||
"Print unibest style": {
|
||||
"scope": "vue",
|
||||
"prefix": "st",
|
||||
"body": [
|
||||
"<style lang=\"scss\" scoped>",
|
||||
"//",
|
||||
"</style>\n"
|
||||
],
|
||||
"body": ["<style lang=\"scss\" scoped>", "//", "</style>\n"],
|
||||
},
|
||||
"Print unibest script": {
|
||||
"scope": "vue",
|
||||
"prefix": "sc",
|
||||
"body": [
|
||||
"<script lang=\"ts\" setup>",
|
||||
"//$3",
|
||||
"</script>\n"
|
||||
],
|
||||
"body": ["<script lang=\"ts\" setup>", "//$3", "</script>\n"],
|
||||
},
|
||||
"Print unibest template": {
|
||||
"scope": "vue",
|
||||
"prefix": "te",
|
||||
"body": [
|
||||
"<template>",
|
||||
" <view class=\"\">$1</view>",
|
||||
"</template>\n"
|
||||
],
|
||||
"body": ["<template>", " <view class=\"\">$1</view>", "</template>\n"],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
import uniHelper from '@uni-helper/eslint-config'
|
||||
|
||||
export default uniHelper({
|
||||
unocss: true,
|
||||
vue: true,
|
||||
markdown: false,
|
||||
ignores: [
|
||||
'src/uni_modules/',
|
||||
'dist',
|
||||
],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'vue/no-unused-refs': 'off',
|
||||
'unused-imports/no-unused-vars': 'off',
|
||||
'eslint-comments/no-unlimited-disable': 'off',
|
||||
'jsdoc/check-param-names': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
'ts/no-empty-object-type': 'off',
|
||||
'no-extend-native': 'off',
|
||||
},
|
||||
})
|
@ -1,7 +1,6 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
// manifest.config.ts
|
||||
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
|
||||
import path from 'node:path'
|
||||
import { loadEnv } from 'vite'
|
||||
|
||||
// 获取环境变量的范例
|
||||
@ -15,14 +14,14 @@ const {
|
||||
} = env
|
||||
|
||||
export default defineManifestConfig({
|
||||
'name': VITE_APP_TITLE,
|
||||
'appid': VITE_UNI_APPID,
|
||||
'description': '',
|
||||
'versionName': '1.0.0',
|
||||
'versionCode': '100',
|
||||
'transformPx': false,
|
||||
'locale': VITE_FALLBACK_LOCALE, // 'zh-Hans'
|
||||
'h5': {
|
||||
name: VITE_APP_TITLE,
|
||||
appid: VITE_UNI_APPID,
|
||||
description: '',
|
||||
versionName: '1.0.0',
|
||||
versionCode: '100',
|
||||
transformPx: false,
|
||||
locale: VITE_FALLBACK_LOCALE, // 'zh-Hans'
|
||||
h5: {
|
||||
router: {
|
||||
base: VITE_APP_PUBLIC_BASE,
|
||||
},
|
||||
@ -83,14 +82,14 @@ export default defineManifestConfig({
|
||||
ios: {
|
||||
appstore: 'static/app/icons/1024x1024.png',
|
||||
ipad: {
|
||||
'app': 'static/app/icons/76x76.png',
|
||||
app: 'static/app/icons/76x76.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',
|
||||
'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',
|
||||
'spotlight': 'static/app/icons/40x40.png',
|
||||
spotlight: 'static/app/icons/40x40.png',
|
||||
'spotlight@2x': 'static/app/icons/80x80.png',
|
||||
},
|
||||
iphone: {
|
||||
@ -108,7 +107,7 @@ export default defineManifestConfig({
|
||||
},
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
'quickapp': {},
|
||||
quickapp: {},
|
||||
/* 小程序特有相关 */
|
||||
'mp-weixin': {
|
||||
appid: VITE_WX_APPID,
|
||||
@ -131,8 +130,8 @@ export default defineManifestConfig({
|
||||
'mp-toutiao': {
|
||||
usingComponents: true,
|
||||
},
|
||||
'uniStatistics': {
|
||||
uniStatistics: {
|
||||
enable: false,
|
||||
},
|
||||
'vueVersion': '3',
|
||||
vueVersion: '3',
|
||||
})
|
||||
|
35
package.json
35
package.json
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "unibest",
|
||||
"type": "commonjs",
|
||||
"version": "3.1.0",
|
||||
"version": "2.15.0",
|
||||
"description": "unibest - 最好的 uniapp 开发模板",
|
||||
"update-time": "2025-06-21",
|
||||
"update-time": "2025-06-17",
|
||||
"author": {
|
||||
"name": "feige996",
|
||||
"zhName": "菲鸽",
|
||||
@ -11,8 +11,8 @@
|
||||
"github": "https://github.com/feige996",
|
||||
"gitee": "https://gitee.com/feige996"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://unibest.tech",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/feige996/unibest",
|
||||
"repository-gitee": "https://gitee.com/feige996/unibest",
|
||||
"repository-old": "https://github.com/codercup/unibest",
|
||||
@ -72,8 +72,21 @@
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"openapi-ts-request": "openapi-ts",
|
||||
"prepare": "git init && husky",
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix"
|
||||
"lint": "oxlint",
|
||||
"lint-fix": "oxlint --fix"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.{html,cjs,json,md,scss,css,txt}": [
|
||||
"prettier --write --cache"
|
||||
],
|
||||
"**/*.{js,jsx,ts,tsx,vue,mjs,cjs,mts,cts}": [
|
||||
"oxlint --fix",
|
||||
"prettier --write --cache"
|
||||
],
|
||||
"!**/{node_modules,dist}/**": []
|
||||
},
|
||||
"resolutions": {
|
||||
"bin-wrapper": "npm:bin-wrapper-china"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-4060620250520001",
|
||||
@ -98,12 +111,12 @@
|
||||
"js-cookie": "^3.0.5",
|
||||
"pinia": "2.0.36",
|
||||
"pinia-plugin-persistedstate": "3.2.1",
|
||||
"qs": "6.5.3",
|
||||
"vue": "^3.4.21",
|
||||
"wot-design-uni": "^1.9.1",
|
||||
"z-paging": "2.8.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^4.15.0",
|
||||
"@commitlint/cli": "^19.8.1",
|
||||
"@commitlint/config-conventional": "^19.8.1",
|
||||
"@dcloudio/types": "^3.4.8",
|
||||
@ -117,7 +130,6 @@
|
||||
"@rollup/rollup-darwin-x64": "^4.28.0",
|
||||
"@types/node": "^20.17.9",
|
||||
"@types/wechat-miniprogram": "^3.4.8",
|
||||
"@uni-helper/eslint-config": "^0.4.0",
|
||||
"@uni-helper/uni-types": "1.0.0-alpha.3",
|
||||
"@uni-helper/unocss-preset-uni": "^0.2.11",
|
||||
"@uni-helper/vite-plugin-uni-components": "0.2.0",
|
||||
@ -126,15 +138,14 @@
|
||||
"@uni-helper/vite-plugin-uni-pages": "0.2.28",
|
||||
"@uni-helper/vite-plugin-uni-platform": "0.0.4",
|
||||
"@uni-ku/bundle-optimizer": "^1.3.3",
|
||||
"@unocss/eslint-plugin": "^66.2.3",
|
||||
"@unocss/preset-legacy-compat": "^0.59.4",
|
||||
"@vue/runtime-core": "^3.4.21",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.29.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.2.10",
|
||||
"openapi-ts-request": "^1.1.2",
|
||||
"oxlint": "1.0.0",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-html": "^1.7.0",
|
||||
"postcss-scss": "^4.0.9",
|
||||
@ -148,11 +159,5 @@
|
||||
"vite": "5.2.8",
|
||||
"vite-plugin-restart": "^0.4.2",
|
||||
"vue-tsc": "^2.2.10"
|
||||
},
|
||||
"resolutions": {
|
||||
"bin-wrapper": "npm:bin-wrapper-china"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "eslint --fix"
|
||||
}
|
||||
}
|
||||
|
2236
pnpm-lock.yaml
generated
2236
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,8 @@
|
||||
// # 在升级完后,会自动添加很多无用依赖,这需要删除以减小依赖包体积
|
||||
// # 只需要执行下面的命令即可
|
||||
|
||||
const { exec } = require('node:child_process')
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { exec } = require('child_process')
|
||||
|
||||
// 定义要执行的命令
|
||||
const dependencies = [
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
|
||||
import { usePageAuth } from '@/hooks/usePageAuth'
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
||||
import { usePageAuth } from '@/hooks/usePageAuth'
|
||||
|
||||
usePageAuth()
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './types/login'
|
||||
import { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './login.typings'
|
||||
import { http } from '@/utils/http'
|
||||
|
||||
/**
|
||||
@ -15,7 +15,7 @@ export interface ILoginForm {
|
||||
* 获取验证码
|
||||
* @returns ICaptcha 验证码
|
||||
*/
|
||||
export function getCode() {
|
||||
export const getCode = () => {
|
||||
return http.get<ICaptcha>('/user/getCode')
|
||||
}
|
||||
|
||||
@ -23,35 +23,35 @@ export function getCode() {
|
||||
* 用户登录
|
||||
* @param loginForm 登录表单
|
||||
*/
|
||||
export function login(loginForm: ILoginForm) {
|
||||
export const login = (loginForm: ILoginForm) => {
|
||||
return http.post<IUserLogin>('/user/login', loginForm)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
export function getUserInfo() {
|
||||
export const getUserInfo = () => {
|
||||
return http.get<IUserInfoVo>('/user/info')
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
export function logout() {
|
||||
export const logout = () => {
|
||||
return http.get<void>('/user/logout')
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户信息
|
||||
*/
|
||||
export function updateInfo(data: IUpdateInfo) {
|
||||
export const updateInfo = (data: IUpdateInfo) => {
|
||||
return http.post('/user/updateInfo', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*/
|
||||
export function updateUserPassword(data: IUpdatePassword) {
|
||||
export const updateUserPassword = (data: IUpdatePassword) => {
|
||||
return http.post('/user/updatePassword', data)
|
||||
}
|
||||
|
||||
@ -59,12 +59,12 @@ export function updateUserPassword(data: IUpdatePassword) {
|
||||
* 获取微信登录凭证
|
||||
* @returns Promise 包含微信登录凭证(code)
|
||||
*/
|
||||
export function getWxCode() {
|
||||
export const getWxCode = () => {
|
||||
return new Promise<UniApp.LoginRes>((resolve, reject) => {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: res => resolve(res),
|
||||
fail: err => reject(new Error(err)),
|
||||
success: (res) => resolve(res),
|
||||
fail: (err) => reject(new Error(err)),
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -78,6 +78,6 @@ export function getWxCode() {
|
||||
* @param params 微信登录参数,包含code
|
||||
* @returns Promise 包含登录结果
|
||||
*/
|
||||
export function wxLogin(data: { code: string }) {
|
||||
export const wxLogin = (data: { code: string }) => {
|
||||
return http.post<IUserLogin>('/user/wxLogin', data)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
export interface IUserInfoVo {
|
||||
export type IUserInfoVo = {
|
||||
id: number
|
||||
username: string
|
||||
avatar: string
|
||||
@ -11,7 +11,7 @@ export interface IUserInfoVo {
|
||||
/**
|
||||
* 登录返回的信息
|
||||
*/
|
||||
export interface IUserLogin {
|
||||
export type IUserLogin = {
|
||||
id: string
|
||||
username: string
|
||||
token: string
|
||||
@ -20,7 +20,7 @@ export interface IUserLogin {
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
export interface ICaptcha {
|
||||
export type ICaptcha = {
|
||||
captchaEnabled: boolean
|
||||
uuid: string
|
||||
image: string
|
||||
@ -28,7 +28,7 @@ export interface ICaptcha {
|
||||
/**
|
||||
* 上传成功的信息
|
||||
*/
|
||||
export interface IUploadSuccessInfo {
|
||||
export type IUploadSuccessInfo = {
|
||||
fileId: number
|
||||
originalName: string
|
||||
fileName: string
|
||||
@ -41,7 +41,7 @@ export interface IUploadSuccessInfo {
|
||||
/**
|
||||
* 更新用户信息
|
||||
*/
|
||||
export interface IUpdateInfo {
|
||||
export type IUpdateInfo = {
|
||||
id: number
|
||||
name: string
|
||||
sex: string
|
||||
@ -49,7 +49,7 @@ export interface IUpdateInfo {
|
||||
/**
|
||||
* 更新用户信息
|
||||
*/
|
||||
export interface IUpdatePassword {
|
||||
export type IUpdatePassword = {
|
||||
id: number
|
||||
oldPassword: string
|
||||
newPassword: string
|
7
src/env.d.ts
vendored
7
src/env.d.ts
vendored
@ -2,8 +2,8 @@
|
||||
/// <reference types="vite-svg-loader" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
@ -29,6 +29,3 @@ interface ImportMetaEnv {
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
|
||||
declare const __VITE_APP_PROXY__: 'true' | 'false'
|
||||
declare const __UNI_PLATFORM__: 'app' | 'h5' | 'mp-alipay' | 'mp-baidu' | 'mp-kuaishou' | 'mp-lark' | 'mp-qq' | 'mp-tiktok' | 'mp-weixin' | 'mp-xiaochengxu'
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useUserStore } from '@/store'
|
||||
import { needLoginPages as _needLoginPages, getNeedLoginPages } from '@/utils'
|
||||
import { useUserStore } from '@/store'
|
||||
|
||||
const loginRoute = import.meta.env.VITE_LOGIN_URL
|
||||
const isDev = import.meta.env.DEV
|
||||
function isLogined() {
|
||||
const isLogined = () => {
|
||||
const userStore = useUserStore()
|
||||
return !!userStore.userInfo.username
|
||||
}
|
||||
@ -20,8 +20,7 @@ export function usePageAuth() {
|
||||
let needLoginPages: string[] = []
|
||||
if (isDev) {
|
||||
needLoginPages = getNeedLoginPages()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
needLoginPages = _needLoginPages
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { UnwrapRef } from 'vue'
|
||||
import { UnwrapRef } from 'vue'
|
||||
|
||||
interface IUseRequestOptions<T> {
|
||||
type IUseRequestOptions<T> = {
|
||||
/** 是否立即执行 */
|
||||
immediate?: boolean
|
||||
/** 初始化数据 */
|
||||
|
@ -7,7 +7,7 @@ type TfileType = 'image' | 'file'
|
||||
type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*'
|
||||
type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage
|
||||
|
||||
interface TOptions<T extends TfileType> {
|
||||
type TOptions<T extends TfileType> = {
|
||||
formData?: Record<string, any>
|
||||
maxSize?: number
|
||||
accept?: T extends 'image' ? TImage[] : TFile[]
|
||||
@ -30,46 +30,6 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
|
||||
const error = ref<Error | null>(null)
|
||||
const data = ref<any>(null)
|
||||
|
||||
const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string, size: number }) => {
|
||||
if (size > maxSize) {
|
||||
uni.showToast({
|
||||
title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`,
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// const fileExtension = file?.tempFiles?.name?.split('.').pop()?.toLowerCase()
|
||||
// const isTypeValid = accept.some((type) => type === '*' || type.toLowerCase() === fileExtension)
|
||||
|
||||
// if (!isTypeValid) {
|
||||
// uni.showToast({
|
||||
// title: `仅支持 ${accept.join(', ')} 格式的文件`,
|
||||
// icon: 'none',
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
loading.value = true
|
||||
uploadFile({
|
||||
tempFilePath,
|
||||
formData,
|
||||
onSuccess: (res) => {
|
||||
const { data: _data } = JSON.parse(res)
|
||||
data.value = _data
|
||||
// console.log('上传成功', res)
|
||||
success?.(_data)
|
||||
},
|
||||
onError: (err) => {
|
||||
error.value = err
|
||||
onError?.(err)
|
||||
},
|
||||
onComplete: () => {
|
||||
loading.value = false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const run = () => {
|
||||
// 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
|
||||
// 微信小程序在2023年10月17日之后,使用本API需要配置隐私协议
|
||||
@ -112,8 +72,7 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.chooseImage(chooseFileOptions)
|
||||
// #endif
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uni.chooseFile({
|
||||
...chooseFileOptions,
|
||||
type: 'all',
|
||||
@ -121,6 +80,46 @@ export default function useUpload<T extends TfileType>(options: TOptions<T> = {}
|
||||
}
|
||||
}
|
||||
|
||||
const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string; size: number }) => {
|
||||
if (size > maxSize) {
|
||||
uni.showToast({
|
||||
title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`,
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// const fileExtension = file?.tempFiles?.name?.split('.').pop()?.toLowerCase()
|
||||
// const isTypeValid = accept.some((type) => type === '*' || type.toLowerCase() === fileExtension)
|
||||
|
||||
// if (!isTypeValid) {
|
||||
// uni.showToast({
|
||||
// title: `仅支持 ${accept.join(', ')} 格式的文件`,
|
||||
// icon: 'none',
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
loading.value = true
|
||||
uploadFile({
|
||||
tempFilePath: tempFilePath,
|
||||
formData,
|
||||
onSuccess: (res) => {
|
||||
const { data: _data } = JSON.parse(res)
|
||||
data.value = _data
|
||||
// console.log('上传成功', res)
|
||||
success?.(_data)
|
||||
},
|
||||
onError: (err) => {
|
||||
error.value = err
|
||||
onError?.(err)
|
||||
},
|
||||
onComplete: () => {
|
||||
loading.value = false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return { loading, error, data, run }
|
||||
}
|
||||
|
||||
@ -146,8 +145,7 @@ async function uploadFile({
|
||||
try {
|
||||
const data = uploadFileRes.data
|
||||
onSuccess(data)
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
onError(err)
|
||||
}
|
||||
},
|
||||
|
@ -1,3 +1,3 @@
|
||||
export { prototypeInterceptor } from './prototype'
|
||||
export { requestInterceptor } from './request'
|
||||
export { routeInterceptor } from './route'
|
||||
export { requestInterceptor } from './request'
|
||||
export { prototypeInterceptor } from './prototype'
|
||||
|
@ -2,11 +2,10 @@ 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
|
||||
if (index < 0) return this[this.length + index]
|
||||
if (index >= this.length) return undefined
|
||||
return this[index]
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import qs from 'qs'
|
||||
import { useUserStore } from '@/store'
|
||||
import { getEnvBaseUrl } from '@/utils'
|
||||
import { platform } from '@/utils/platform'
|
||||
import { stringifyQuery } from '@/utils/queryString'
|
||||
import { getEnvBaseUrl } from '@/utils'
|
||||
|
||||
export type CustomRequestOptions = UniApp.RequestOptions & {
|
||||
query?: Record<string, any>
|
||||
@ -18,11 +19,10 @@ const httpInterceptor = {
|
||||
invoke(options: CustomRequestOptions) {
|
||||
// 接口请求支持通过 query 参数配置 queryString
|
||||
if (options.query) {
|
||||
const queryStr = stringifyQuery(options.query)
|
||||
const queryStr = qs.stringify(options.query)
|
||||
if (options.url.includes('?')) {
|
||||
options.url += `&${queryStr}`
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
options.url += `?${queryStr}`
|
||||
}
|
||||
}
|
||||
@ -33,8 +33,7 @@ const httpInterceptor = {
|
||||
if (JSON.parse(__VITE_APP_PROXY__)) {
|
||||
// 自动拼接代理前缀
|
||||
options.url = import.meta.env.VITE_APP_PROXY_PREFIX + options.url
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
options.url = baseUrl + options.url
|
||||
}
|
||||
// #endif
|
||||
|
@ -5,12 +5,12 @@
|
||||
* 我这里应为大部分都可以随便进入,所以使用黑名单
|
||||
*/
|
||||
import { useUserStore } from '@/store'
|
||||
import { needLoginPages as _needLoginPages, getLastPage, getNeedLoginPages } from '@/utils'
|
||||
import { needLoginPages as _needLoginPages, getNeedLoginPages, getLastPage } from '@/utils'
|
||||
|
||||
// TODO Check
|
||||
const loginRoute = import.meta.env.VITE_LOGIN_URL
|
||||
|
||||
function isLogined() {
|
||||
const isLogined = () => {
|
||||
const userStore = useUserStore()
|
||||
return !!userStore.userInfo.username
|
||||
}
|
||||
@ -37,8 +37,7 @@ const navigateToInterceptor = {
|
||||
// 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
|
||||
if (isDev) {
|
||||
needLoginPages = getNeedLoginPages()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
needLoginPages = _needLoginPages
|
||||
}
|
||||
const isNeedLogin = needLoginPages.includes(path)
|
||||
|
@ -1,3 +1,11 @@
|
||||
<template>
|
||||
<wd-config-provider :themeVars="themeVars">
|
||||
<slot />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
|
||||
@ -7,11 +15,3 @@ const themeVars: ConfigProviderThemeVars = {
|
||||
// buttonPrimaryColor: '#07c160',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<wd-config-provider :theme-vars="themeVars">
|
||||
<slot />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
@ -1,3 +1,11 @@
|
||||
<template>
|
||||
<wd-config-provider :themeVars="themeVars">
|
||||
<slot />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
|
||||
@ -7,11 +15,3 @@ const themeVars: ConfigProviderThemeVars = {
|
||||
// buttonPrimaryColor: '#07c160',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<wd-config-provider :theme-vars="themeVars">
|
||||
<slot />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
@ -1,50 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { tabbarStore } from './tabbar'
|
||||
// 'i-carbon-code',
|
||||
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy } from './tabbarList'
|
||||
|
||||
// @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 }) {
|
||||
const url = tabbarList[index].path
|
||||
tabbarStore.setCurIdx(index)
|
||||
if (cacheTabbarEnable) {
|
||||
uni.switchTab({ url })
|
||||
}
|
||||
else {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
}
|
||||
onLoad(() => {
|
||||
// 解决原生 tabBar 未隐藏导致有2个 tabBar 的问题
|
||||
// @ts-expect-error 预知的判断
|
||||
const hideRedundantTabbarEnable = selectedTabbarStrategy === 1
|
||||
hideRedundantTabbarEnable
|
||||
&& uni.hideTabBar({
|
||||
fail(err) {
|
||||
console.log('hideTabBar fail: ', err)
|
||||
},
|
||||
success(res) {
|
||||
console.log('hideTabBar success: ', res)
|
||||
},
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<wd-tabbar
|
||||
v-if="customTabbarEnable"
|
||||
fixed
|
||||
v-model="tabbarStore.curIdx"
|
||||
bordered
|
||||
safeareainsetbottom
|
||||
safeAreaInsetBottom
|
||||
placeholder
|
||||
fixed
|
||||
@change="selectTabBar"
|
||||
>
|
||||
<block v-for="(item, idx) in tabbarList" :key="item.path">
|
||||
<wd-tabbar-item v-if="item.iconType === 'uiLib'" :title="item.text" :icon="item.icon" />
|
||||
<wd-tabbar-item
|
||||
v-if="item.iconType === 'wot'"
|
||||
:title="item.text"
|
||||
:icon="item.icon"
|
||||
></wd-tabbar-item>
|
||||
<wd-tabbar-item
|
||||
v-else-if="item.iconType === 'unocss' || item.iconType === 'iconfont'"
|
||||
:title="item.text"
|
||||
@ -54,7 +23,7 @@ onLoad(() => {
|
||||
h-40rpx
|
||||
w-40rpx
|
||||
:class="[item.icon, idx === tabbarStore.curIdx ? 'is-active' : 'is-inactive']"
|
||||
/>
|
||||
></view>
|
||||
</template>
|
||||
</wd-tabbar-item>
|
||||
<wd-tabbar-item v-else-if="item.iconType === 'local'" :title="item.text">
|
||||
@ -65,3 +34,35 @@ onLoad(() => {
|
||||
</block>
|
||||
</wd-tabbar>
|
||||
</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>
|
||||
|
@ -1,16 +1,16 @@
|
||||
# tabbar 说明
|
||||
|
||||
`tabbar` 分为 `4 种` 情况:
|
||||
tabbar 分为4种情况:
|
||||
|
||||
- `完全原生 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。
|
||||
- 优势:原生自带的 tabbar,最先渲染,有缓存。
|
||||
- 劣势:只能使用 2 组图片来切换选中和非选中状态,修改颜色只能重新换图片(或者用 iconfont)。
|
||||
- `半自定义 tabbar`,使用 `switchTab` 切换 tabbar,`tabbar` 页面有缓存。使用了第三方 UI 库的 `tabbar` 组件,并隐藏了原生 `tabbar` 的显示。
|
||||
- 优势:可以随意配置自己想要的 `svg icon`,切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。
|
||||
- 劣势:首次点击 tababr 会闪烁。
|
||||
- `全自定义 tabbar`,使用 `navigateTo` 切换 `tabbar`,`tabbar` 页面无缓存。使用了第三方 UI 库的 `tabbar` 组件。
|
||||
- 完全原生tabbar,使用 switchTab 切换 tabbar,tabbar页面有缓存。
|
||||
- 优势:原生自带的tabbar,最先渲染,有缓存。
|
||||
- 劣势:只能使用2组图片来切换选中和非选中状态,修改颜色只能重新换图片(或者用iconfont)。
|
||||
- 半自定义tabbar,使用 switchTab 切换 tabbar,tabbar页面有缓存。使用了第三方UI库的 tabbar 组件,并隐藏了原生 tabbar 的显示。
|
||||
- 优势:可以随意配置自己想要的 svg icon,切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。
|
||||
- 劣势:首次点击tababr会闪烁。
|
||||
- 全自定义tabbar,使用 navigateTo 切换tabbar,tabbar页面无缓存。使用了第三方UI库的 tabbar 组件。
|
||||
- 优势:可以随意配置自己想要的 svg icon,切换字体颜色方便。可以实现各种花里胡哨的动效等。
|
||||
- 劣势:首次点击 `tababr` 会闪烁,无缓存。
|
||||
- `无 tabbar`,只有一个页面入口,底部无 `tabbar` 显示;常用语临时活动页。
|
||||
- 劣势:首次点击tababr会闪烁,无缓存。
|
||||
- 无tabbar,只有一个页面入口,底部无tabbar显示;常用语临时活动页。
|
||||
|
||||
> 注意:花里胡哨的效果需要自己实现,本模版不提供。
|
||||
|
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* tabbar 选择的策略,更详细的介绍见 tabbar.md 文件
|
||||
* 0: 'NATIVE_TABBAR' `完全原生 tabbar`
|
||||
* 2: 'FULL_CUSTOM_TABBAR' `全自定义 tabbar`
|
||||
* 1: 'HALF_CUSTOM_TABBAR' `半自定义 tabbar`
|
||||
* 3: 'NO_TABBAR' `无 tabbar`
|
||||
* 0: 'NATIVE_TABBAR'
|
||||
* 2: 'FULL_CUSTOM_TABBAR'
|
||||
* 1: 'HALF_CUSTOM_TABBAR'
|
||||
* 3: 'NO_TABBAR'
|
||||
*
|
||||
* 温馨提示:本文件的任何代码更改了之后,都需要重新运行,否则 pages.json 不会更新导致错误
|
||||
*/
|
||||
@ -24,7 +24,7 @@ export const tabbarList = [
|
||||
pagePath: 'pages/index/index',
|
||||
text: '首页',
|
||||
icon: 'home',
|
||||
iconType: 'uiLib',
|
||||
iconType: 'wot',
|
||||
},
|
||||
{
|
||||
iconPath: 'static/tabbar/example.png',
|
||||
|
@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<wd-config-provider :themeVars="themeVars">
|
||||
<slot />
|
||||
<fg-tabbar />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
import FgTabbar from './fg-tabbar/fg-tabbar.vue'
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
|
||||
const themeVars: ConfigProviderThemeVars = {
|
||||
// colorTheme: 'red',
|
||||
@ -8,12 +17,3 @@ const themeVars: ConfigProviderThemeVars = {
|
||||
// buttonPrimaryColor: '#07c160',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<wd-config-provider :theme-vars="themeVars">
|
||||
<slot />
|
||||
<FgTabbar />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import '@/style/index.scss'
|
||||
import { VueQueryPlugin } from '@tanstack/vue-query'
|
||||
import 'virtual:uno.css'
|
||||
import { createSSRApp } from 'vue'
|
||||
|
||||
import App from './App.vue'
|
||||
import { prototypeInterceptor, requestInterceptor, routeInterceptor } from './interceptors'
|
||||
|
||||
import store from './store'
|
||||
import '@/style/index.scss'
|
||||
import 'virtual:uno.css'
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
|
@ -7,21 +7,17 @@
|
||||
}
|
||||
</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>
|
||||
// code here
|
||||
</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>
|
||||
|
@ -30,7 +30,7 @@
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "首页",
|
||||
"icon": "home",
|
||||
"iconType": "uiLib"
|
||||
"iconType": "wot"
|
||||
},
|
||||
{
|
||||
"iconPath": "static/tabbar/example.png",
|
||||
@ -62,4 +62,4 @@
|
||||
}
|
||||
],
|
||||
"subPackages": []
|
||||
}
|
||||
}
|
@ -7,6 +7,17 @@
|
||||
}
|
||||
</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>
|
||||
import RequestComp from './components/request.vue'
|
||||
import UploadComp from './components/upload.vue'
|
||||
@ -22,19 +33,6 @@ const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||
console.log('about')
|
||||
</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>
|
||||
.test-css {
|
||||
// 16rpx=>0.5rem
|
||||
|
@ -7,9 +7,36 @@
|
||||
}
|
||||
</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>
|
||||
import type { IFooItem } from '@/service/index/foo'
|
||||
import { getFooAPI } from '@/service/index/foo'
|
||||
import { getFooAPI, postFooAPI, IFooItem } from '@/service/index/foo'
|
||||
// import { findPetsByStatusQueryOptions } from '@/service/app'
|
||||
// import { useQuery } from '@tanstack/vue-query'
|
||||
|
||||
@ -34,51 +61,7 @@ const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲
|
||||
// refetch,
|
||||
// } = useQuery(findPetsByStatusQueryOptions({ params: { status: ['available'] } }))
|
||||
|
||||
function reset() {
|
||||
const reset = () => {
|
||||
data.value = initialData
|
||||
}
|
||||
</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>
|
||||
|
@ -7,25 +7,13 @@
|
||||
}
|
||||
</route>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const { loading, data, run } = useUpload()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="p-4 text-center">
|
||||
<wd-button @click="run">
|
||||
选择图片并上传
|
||||
</wd-button>
|
||||
<view v-if="loading" class="h-10 text-blue">
|
||||
上传...
|
||||
</view>
|
||||
<wd-button @click="run">选择图片并上传</wd-button>
|
||||
<view v-if="loading" class="text-blue h-10">上传...</view>
|
||||
<template v-else>
|
||||
<view class="m-2">
|
||||
上传后返回的接口数据:
|
||||
</view>
|
||||
<view class="m-2">
|
||||
{{ data }}
|
||||
</view>
|
||||
<view class="m-2">上传后返回的接口数据:</view>
|
||||
<view class="m-2">{{ data }}</view>
|
||||
<view v-if="data" class="h-80 w-full">
|
||||
<image :src="data.url" mode="scaleToFill" />
|
||||
</view>
|
||||
@ -33,6 +21,10 @@ const { loading, data, run } = useUpload()
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const { loading, data, run } = useUpload()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
||||
|
@ -9,6 +9,25 @@
|
||||
},
|
||||
}
|
||||
</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>
|
||||
import PLATFORM from '@/utils/platform'
|
||||
@ -41,7 +60,7 @@ safeAreaInsets = systemInfo.safeAreaInsets
|
||||
// #endif
|
||||
const author = ref('菲鸽')
|
||||
const description = ref(
|
||||
'unibest 是一个集成了多种工具和技术的 uniapp 开发模板,由 uniapp + Vue3 + Ts + Vite5 + UnoCss + VSCode 构建,模板具有代码提示、自动格式化、统一配置、代码片段等功能,并内置了许多常用的基本组件和基本功能,让你编写 uniapp 拥有 best 体验。',
|
||||
'unibest 是一个集成了多种工具和技术的 uniapp 开发模板,由 uniapp + Vue3 + Ts + Vite6 + UnoCss + VSCode 构建,模板具有代码提示、自动格式化、统一配置、代码片段等功能,并内置了许多常用的基本组件和基本功能,让你编写 uniapp 拥有 best 体验。',
|
||||
)
|
||||
// 测试 uni API 自动引入
|
||||
onLoad(() => {
|
||||
@ -50,46 +69,3 @@ onLoad(() => {
|
||||
|
||||
console.log('index')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-white px-4 pt-2" :style="{ marginTop: `${safeAreaInsets?.top}px` }">
|
||||
<view class="mt-10">
|
||||
<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-4 text-center">
|
||||
作者:
|
||||
<text class="text-green-500">
|
||||
菲鸽
|
||||
</text>
|
||||
</view>
|
||||
<view class="mt-4 text-center">
|
||||
官网地址:
|
||||
<text class="text-green-500">
|
||||
https://unibest.tech
|
||||
</text>
|
||||
</view>
|
||||
<view class="mt-6 h-1px bg-#eee" />
|
||||
<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>
|
||||
|
@ -1,28 +1,27 @@
|
||||
import { http } from '@/utils/http'
|
||||
|
||||
export interface IFooItem {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
/** GET 请求 */
|
||||
export function getFooAPI(name: string) {
|
||||
export const getFooAPI = (name: string) => {
|
||||
return http.get<IFooItem>('/foo', { name })
|
||||
}
|
||||
/** GET 请求;支持 传递 header 的范例 */
|
||||
export function getFooAPI2(name: string) {
|
||||
export const getFooAPI2 = (name: string) => {
|
||||
return http.get<IFooItem>('/foo', { name }, { 'Content-Type-100': '100' })
|
||||
}
|
||||
|
||||
/** POST 请求 */
|
||||
export function postFooAPI(name: string) {
|
||||
export const postFooAPI = (name: string) => {
|
||||
return http.post<IFooItem>('/foo', { name })
|
||||
}
|
||||
/** POST 请求;需要传递 query 参数的范例;微信小程序经常有同时需要query参数和body参数的场景 */
|
||||
export function postFooAPI2(name: string) {
|
||||
export const postFooAPI2 = (name: string) => {
|
||||
return http.post<IFooItem>('/foo', { name })
|
||||
}
|
||||
/** POST 请求;支持 传递 header 的范例 */
|
||||
export function postFooAPI3(name: string) {
|
||||
export const postFooAPI3 = (name: string) => {
|
||||
return http.post<IFooItem>('/foo', { name }, { name }, { 'Content-Type-100': '100' })
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import type { IUserInfoVo } from '@/api/types/login'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
getUserInfo as _getUserInfo,
|
||||
login as _login,
|
||||
logout as _logout,
|
||||
getUserInfo as _getUserInfo,
|
||||
wxLogin as _wxLogin,
|
||||
logout as _logout,
|
||||
getWxCode,
|
||||
} from '@/api/login'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { toast } from '@/utils/toast'
|
||||
import { IUserInfoVo } from '@/api/login.typings'
|
||||
|
||||
// 初始化状态
|
||||
const userInfoState: IUserInfoVo = {
|
||||
@ -29,8 +29,7 @@ export const useUserStore = defineStore(
|
||||
// 若头像为空 则使用默认头像
|
||||
if (!val.avatar) {
|
||||
val.avatar = userInfoState.avatar
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val.avatar = 'https://oss.laf.run/ukw0y1-site/avatar.jpg?feige'
|
||||
}
|
||||
userInfo.value = val
|
||||
@ -46,18 +45,6 @@ export const useUserStore = defineStore(
|
||||
uni.removeStorageSync('userInfo')
|
||||
uni.removeStorageSync('token')
|
||||
}
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
const getUserInfo = async () => {
|
||||
const res = await _getUserInfo()
|
||||
const userInfo = res.data
|
||||
setUserInfo(userInfo)
|
||||
uni.setStorageSync('userInfo', userInfo)
|
||||
uni.setStorageSync('token', userInfo.token)
|
||||
// TODO 这里可以增加获取用户路由的方法 根据用户的角色动态生成路由
|
||||
return res
|
||||
}
|
||||
/**
|
||||
* 用户登录
|
||||
* @param credentials 登录参数
|
||||
@ -75,7 +62,18 @@ export const useUserStore = defineStore(
|
||||
await getUserInfo()
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
const getUserInfo = async () => {
|
||||
const res = await _getUserInfo()
|
||||
const userInfo = res.data
|
||||
setUserInfo(userInfo)
|
||||
uni.setStorageSync('userInfo', userInfo)
|
||||
uni.setStorageSync('token', userInfo.token)
|
||||
// TODO 这里可以增加获取用户路由的方法 根据用户的角色动态生成路由
|
||||
return res
|
||||
}
|
||||
/**
|
||||
* 退出登录 并 删除用户信息
|
||||
*/
|
||||
|
6
src/typings.d.ts
vendored
6
src/typings.d.ts
vendored
@ -1,14 +1,14 @@
|
||||
// 全局要用的类型放到这里
|
||||
|
||||
declare global {
|
||||
interface IResData<T> {
|
||||
type IResData<T> = {
|
||||
code: number
|
||||
msg: string
|
||||
data: T
|
||||
}
|
||||
|
||||
// uni.uploadFile文件上传参数
|
||||
interface IUniUploadFileOptions {
|
||||
type IUniUploadFileOptions = {
|
||||
file?: File
|
||||
files?: UniApp.UploadFileOptionFiles[]
|
||||
filePath?: string
|
||||
@ -16,7 +16,7 @@ declare global {
|
||||
formData?: any
|
||||
}
|
||||
|
||||
interface IUserInfo {
|
||||
type IUserInfo = {
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
/** 微信的 openid,非微信没有这个字段 */
|
||||
|
@ -6,7 +6,7 @@ export enum TestEnum {
|
||||
}
|
||||
|
||||
// uni.uploadFile文件上传参数
|
||||
export interface IUniUploadFileOptions {
|
||||
export type IUniUploadFileOptions = {
|
||||
file?: File
|
||||
files?: UniApp.UploadFileOptionFiles[]
|
||||
filePath?: string
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { CustomRequestOptions } from '@/interceptors/request'
|
||||
import { CustomRequestOptions } from '@/interceptors/request'
|
||||
|
||||
export function http<T>(options: CustomRequestOptions) {
|
||||
export const http = <T>(options: CustomRequestOptions) => {
|
||||
// 1. 返回 Promise 对象
|
||||
return new Promise<IResData<T>>((resolve, reject) => {
|
||||
uni.request({
|
||||
@ -15,20 +15,18 @@ export function http<T>(options: CustomRequestOptions) {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
// 2.1 提取核心数据 res.data
|
||||
resolve(res.data as IResData<T>)
|
||||
}
|
||||
else if (res.statusCode === 401) {
|
||||
} else if (res.statusCode === 401) {
|
||||
// 401错误 -> 清理用户信息,跳转到登录页
|
||||
// userStore.clearUserInfo()
|
||||
// uni.navigateTo({ url: '/pages/login/login' })
|
||||
reject(res)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// 其他错误 -> 根据后端错误信息轻提示
|
||||
!options.hideErrorToast
|
||||
&& 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)
|
||||
}
|
||||
},
|
||||
@ -51,7 +49,12 @@ export function http<T>(options: CustomRequestOptions) {
|
||||
* @param header 请求头,默认为json格式
|
||||
* @returns
|
||||
*/
|
||||
export function httpGet<T>(url: string, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
|
||||
export const httpGet = <T>(
|
||||
url: string,
|
||||
query?: Record<string, any>,
|
||||
header?: Record<string, any>,
|
||||
options?: Partial<CustomRequestOptions>,
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
@ -69,7 +72,13 @@ export function httpGet<T>(url: string, query?: Record<string, any>, header?: Re
|
||||
* @param header 请求头,默认为json格式
|
||||
* @returns
|
||||
*/
|
||||
export function httpPost<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
|
||||
export const httpPost = <T>(
|
||||
url: string,
|
||||
data?: Record<string, any>,
|
||||
query?: Record<string, any>,
|
||||
header?: Record<string, any>,
|
||||
options?: Partial<CustomRequestOptions>,
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
@ -82,7 +91,13 @@ export function httpPost<T>(url: string, data?: Record<string, any>, query?: Rec
|
||||
/**
|
||||
* PUT 请求
|
||||
*/
|
||||
export function httpPut<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
|
||||
export const httpPut = <T>(
|
||||
url: string,
|
||||
data?: Record<string, any>,
|
||||
query?: Record<string, any>,
|
||||
header?: Record<string, any>,
|
||||
options?: Partial<CustomRequestOptions>,
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
data,
|
||||
@ -96,7 +111,12 @@ export function httpPut<T>(url: string, data?: Record<string, any>, query?: Reco
|
||||
/**
|
||||
* DELETE 请求(无请求体,仅 query)
|
||||
*/
|
||||
export function httpDelete<T>(url: string, query?: Record<string, any>, header?: Record<string, any>, options?: Partial<CustomRequestOptions>) {
|
||||
export const httpDelete = <T>(
|
||||
url: string,
|
||||
query?: Record<string, any>,
|
||||
header?: Record<string, any>,
|
||||
options?: Partial<CustomRequestOptions>,
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { pages, subPackages } from '@/pages.json'
|
||||
import { isMpWeixin } from './platform'
|
||||
|
||||
export function getLastPage() {
|
||||
export const getLastPage = () => {
|
||||
// getCurrentPages() 至少有1个元素,所以不再额外判断
|
||||
// const lastPage = getCurrentPages().at(-1)
|
||||
// 上面那个在低版本安卓中打包会报错,所以改用下面这个【虽然我加了 src/interceptions/prototype.ts,但依然报错】
|
||||
@ -14,7 +14,7 @@ export function getLastPage() {
|
||||
* path 如 '/pages/login/index'
|
||||
* redirectPath 如 '/pages/demo/base/route-interceptor'
|
||||
*/
|
||||
export function currRoute() {
|
||||
export const currRoute = () => {
|
||||
const lastPage = getLastPage()
|
||||
const currRoute = (lastPage as any).$page
|
||||
// console.log('lastPage.$page:', currRoute)
|
||||
@ -29,7 +29,7 @@ export function currRoute() {
|
||||
return getUrlObj(fullPath)
|
||||
}
|
||||
|
||||
function ensureDecodeURIComponent(url: string) {
|
||||
const ensureDecodeURIComponent = (url: string) => {
|
||||
if (url.startsWith('%')) {
|
||||
return ensureDecodeURIComponent(decodeURIComponent(url))
|
||||
}
|
||||
@ -40,7 +40,7 @@ function ensureDecodeURIComponent(url: string) {
|
||||
* 比如输入url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor
|
||||
* 输出: {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}}
|
||||
*/
|
||||
export function getUrlObj(url: string) {
|
||||
export const getUrlObj = (url: string) => {
|
||||
const [path, queryStr] = url.split('?')
|
||||
// console.log(path, queryStr)
|
||||
|
||||
@ -63,11 +63,11 @@ export function getUrlObj(url: string) {
|
||||
* 这里设计得通用一点,可以传递 key 作为判断依据,默认是 needLogin, 与 route-block 配对使用
|
||||
* 如果没有传 key,则表示所有的 pages,如果传递了 key, 则表示通过 key 过滤
|
||||
*/
|
||||
export function getAllPages(key = 'needLogin') {
|
||||
export const getAllPages = (key = 'needLogin') => {
|
||||
// 这里处理主包
|
||||
const mainPages = pages
|
||||
.filter(page => !key || page[key])
|
||||
.map(page => ({
|
||||
.filter((page) => !key || page[key])
|
||||
.map((page) => ({
|
||||
...page,
|
||||
path: `/${page.path}`,
|
||||
}))
|
||||
@ -79,7 +79,7 @@ export function getAllPages(key = 'needLogin') {
|
||||
const { root } = subPageObj
|
||||
|
||||
subPageObj.pages
|
||||
.filter(page => !key || page[key])
|
||||
.filter((page) => !key || page[key])
|
||||
.forEach((page: { path: string } & Record<string, any>) => {
|
||||
subPages.push({
|
||||
...page,
|
||||
@ -96,18 +96,18 @@ export function getAllPages(key = 'needLogin') {
|
||||
* 得到所有的需要登录的 pages,包括主包和分包的
|
||||
* 只得到 path 数组
|
||||
*/
|
||||
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map(page => page.path)
|
||||
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((page) => page.path)
|
||||
|
||||
/**
|
||||
* 得到所有的需要登录的 pages,包括主包和分包的
|
||||
* 只得到 path 数组
|
||||
*/
|
||||
export const needLoginPages: string[] = getAllPages('needLogin').map(page => page.path)
|
||||
export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path)
|
||||
|
||||
/**
|
||||
* 根据微信小程序当前环境,判断应该获取的 baseUrl
|
||||
*/
|
||||
export function getEnvBaseUrl() {
|
||||
export const getEnvBaseUrl = () => {
|
||||
// 请求基准地址
|
||||
let baseUrl = import.meta.env.VITE_SERVER_BASEURL
|
||||
|
||||
@ -136,7 +136,7 @@ export function getEnvBaseUrl() {
|
||||
/**
|
||||
* 根据微信小程序当前环境,判断应该获取的 UPLOAD_BASEURL
|
||||
*/
|
||||
export function getEnvBaseUploadUrl() {
|
||||
export const getEnvBaseUploadUrl = () => {
|
||||
// 请求基准地址
|
||||
let baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* 将对象序列化为URL查询字符串,用于替代第三方的 qs 库,节省宝贵的体积
|
||||
* 支持基本类型值和数组,不支持嵌套对象
|
||||
* @param obj 要序列化的对象
|
||||
* @returns 序列化后的查询字符串
|
||||
*/
|
||||
export function stringifyQuery(obj: Record<string, any>): string {
|
||||
if (!obj || typeof obj !== 'object' || Array.isArray(obj))
|
||||
return ''
|
||||
|
||||
return Object.entries(obj)
|
||||
.filter(([_, value]) => value !== undefined && value !== null)
|
||||
.map(([key, value]) => {
|
||||
// 对键进行编码
|
||||
const encodedKey = encodeURIComponent(key)
|
||||
|
||||
// 处理数组类型
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
.filter(item => item !== undefined && item !== null)
|
||||
.map(item => `${encodedKey}=${encodeURIComponent(item)}`)
|
||||
.join('&')
|
||||
}
|
||||
|
||||
// 处理基本类型
|
||||
return `${encodedKey}=${encodeURIComponent(value)}`
|
||||
})
|
||||
.join('&')
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import type { CustomRequestOptions } from '@/interceptors/request'
|
||||
import { CustomRequestOptions } from '@/interceptors/request'
|
||||
|
||||
/**
|
||||
* 请求方法: 主要是对 uni.request 的封装,去适配 openapi-ts-request 的 request 方法
|
||||
* @param options 请求参数
|
||||
* @returns 返回 Promise 对象
|
||||
*/
|
||||
function http<T>(options: CustomRequestOptions) {
|
||||
const http = <T>(options: CustomRequestOptions) => {
|
||||
// 1. 返回 Promise 对象
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
uni.request({
|
||||
@ -20,20 +20,18 @@ function http<T>(options: CustomRequestOptions) {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
// 2.1 提取核心数据 res.data
|
||||
resolve(res.data as T)
|
||||
}
|
||||
else if (res.statusCode === 401) {
|
||||
} else if (res.statusCode === 401) {
|
||||
// 401错误 -> 清理用户信息,跳转到登录页
|
||||
// userStore.clearUserInfo()
|
||||
// uni.navigateTo({ url: '/pages/login/login' })
|
||||
reject(res)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// 其他错误 -> 根据后端错误信息轻提示
|
||||
!options.hideErrorToast
|
||||
&& uni.showToast({
|
||||
icon: 'none',
|
||||
title: (res.data as T & { msg?: string })?.msg || '请求错误',
|
||||
})
|
||||
!options.hideErrorToast &&
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: (res.data as T & { msg?: string })?.msg || '请求错误',
|
||||
})
|
||||
reject(res)
|
||||
}
|
||||
},
|
||||
|
@ -21,8 +21,8 @@ export function showToast(options: ToastOptions | string) {
|
||||
position: 'middle',
|
||||
message: '',
|
||||
}
|
||||
const mergedOptions
|
||||
= typeof options === 'string'
|
||||
const mergedOptions =
|
||||
typeof options === 'string'
|
||||
? { ...defaultOptions, message: options }
|
||||
: { ...defaultOptions, ...options }
|
||||
// 映射position到uniapp支持的格式
|
||||
|
@ -21,7 +21,7 @@ import { toast } from './toast'
|
||||
*/
|
||||
export const uploadFileUrl = {
|
||||
/** 用户头像上传地址 */
|
||||
USER_AVATAR: `${import.meta.env.VITE_SERVER_BASEURL}/user/avatar`,
|
||||
USER_AVATAR: import.meta.env.VITE_SERVER_BASEURL + '/user/avatar',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -31,7 +31,12 @@ export const uploadFileUrl = {
|
||||
* @param formData 额外表单数据
|
||||
* @param options 上传选项
|
||||
*/
|
||||
export function useFileUpload<T = string>(url: string, filePath: string, formData: Record<string, any> = {}, options: Omit<UploadOptions, 'sourceType' | 'sizeType' | 'count'> = {}) {
|
||||
export const useFileUpload = <T = string>(
|
||||
url: string,
|
||||
filePath: string,
|
||||
formData: Record<string, any> = {},
|
||||
options: Omit<UploadOptions, 'sourceType' | 'sizeType' | 'count'> = {},
|
||||
) => {
|
||||
return useUpload<T>(
|
||||
url,
|
||||
formData,
|
||||
@ -71,9 +76,13 @@ export interface UploadOptions {
|
||||
* @param options 上传选项
|
||||
* @returns 上传状态和控制对象
|
||||
*/
|
||||
export function useUpload<T = string>(url: string, formData: Record<string, any> = {}, options: UploadOptions = {},
|
||||
export const useUpload = <T = string>(
|
||||
url: string,
|
||||
formData: Record<string, any> = {},
|
||||
options: UploadOptions = {},
|
||||
/** 直接传入文件路径,跳过选择器 */
|
||||
directFilePath?: string) {
|
||||
directFilePath?: string,
|
||||
) => {
|
||||
/** 上传中状态 */
|
||||
const loading = ref(false)
|
||||
/** 上传错误状态 */
|
||||
@ -152,8 +161,7 @@ export function useUpload<T = string>(url: string, formData: Record<string, any>
|
||||
success: (res) => {
|
||||
const file = res.tempFiles[0]
|
||||
// 检查文件大小是否符合限制
|
||||
if (!checkFileSize(file.size))
|
||||
return
|
||||
if (!checkFileSize(file.size)) return
|
||||
|
||||
// 开始上传
|
||||
loading.value = true
|
||||
@ -287,8 +295,7 @@ function uploadFile<T>({
|
||||
// 上传成功
|
||||
data.value = _data as T
|
||||
onSuccess?.(_data)
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
// 响应解析错误
|
||||
console.error('解析上传响应失败:', err)
|
||||
error.value = true
|
||||
@ -313,8 +320,7 @@ function uploadFile<T>({
|
||||
progress.value = res.progress
|
||||
onProgress?.(res.progress)
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
// 创建上传任务失败
|
||||
console.error('创建上传任务失败:', err)
|
||||
error.value = true
|
||||
|
@ -1,15 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"lib": ["esnext", "dom"],
|
||||
"baseUrl": ".",
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitThis": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"allowJs": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@img/*": ["./src/static/*"]
|
||||
},
|
||||
"resolveJsonModule": true,
|
||||
"outDir": "dist",
|
||||
"lib": ["esnext", "dom"],
|
||||
"types": [
|
||||
"@dcloudio/types",
|
||||
"@uni-helper/uni-types",
|
||||
@ -17,17 +23,12 @@
|
||||
"wot-design-uni/global.d.ts",
|
||||
"z-paging/types",
|
||||
"./src/typings.d.ts"
|
||||
],
|
||||
"allowJs": true,
|
||||
"noImplicitThis": true,
|
||||
"outDir": "dist",
|
||||
"sourceMap": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true
|
||||
]
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"plugins": ["@uni-helper/uni-types/volar-plugin"]
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.js",
|
||||
@ -36,6 +37,5 @@
|
||||
"src/**/*.jsx",
|
||||
"src/**/*.vue",
|
||||
"src/**/*.json"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
]
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
import { presetUni } from '@uni-helper/unocss-preset-uni'
|
||||
import {
|
||||
defineConfig,
|
||||
presetAttributify,
|
||||
presetIcons,
|
||||
presetAttributify,
|
||||
transformerDirectives,
|
||||
transformerVariantGroup,
|
||||
} from 'unocss'
|
||||
@ -20,7 +20,7 @@ export default defineConfig({
|
||||
scale: 1.2,
|
||||
warn: true,
|
||||
extraProperties: {
|
||||
'display': 'inline-block',
|
||||
display: 'inline-block',
|
||||
'vertical-align': 'middle',
|
||||
},
|
||||
}),
|
||||
|
@ -1,6 +1,5 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
|
||||
export function copyNativeRes() {
|
||||
const waitPath = path.resolve(__dirname, '../src/nativeResources')
|
||||
@ -32,8 +31,7 @@ export function copyNativeRes() {
|
||||
console.log(
|
||||
`[copyNativeRes] 成功将 nativeResources 目录中的资源移动到构建目录:${buildPath}`,
|
||||
)
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
console.error(`[copyNativeRes] 复制资源失败:`, error)
|
||||
}
|
||||
},
|
||||
|
@ -1,16 +1,14 @@
|
||||
// src/plugins/updatePackageJson.ts
|
||||
import type { Plugin } from 'vite'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { Plugin } from 'vite'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
function updatePackageJson(): Plugin {
|
||||
const updatePackageJson = (): Plugin => {
|
||||
return {
|
||||
name: 'update-package-json',
|
||||
async buildStart() {
|
||||
// 只在生产环境构建时执行
|
||||
if (process.env.NODE_ENV !== 'production')
|
||||
return
|
||||
if (process.env.NODE_ENV !== 'production') return
|
||||
|
||||
const packageJsonPath = path.resolve(process.cwd(), 'package.json')
|
||||
|
||||
@ -23,11 +21,10 @@ function updatePackageJson(): Plugin {
|
||||
packageJson['update-time'] = new Date().toISOString().split('T')[0] // YYYY-MM-DD
|
||||
|
||||
// 写回文件(保持 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']}`)
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
console.error('[update-package-json] 插件执行失败:', error)
|
||||
}
|
||||
},
|
||||
|
@ -1,27 +1,27 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import Uni from '@dcloudio/vite-plugin-uni'
|
||||
import Components from '@uni-helper/vite-plugin-uni-components'
|
||||
// @see https://uni-helper.js.org/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'
|
||||
import dayjs from 'dayjs'
|
||||
import path from 'node:path'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
// @see https://uni-helper.js.org/vite-plugin-uni-pages
|
||||
import UniPages from '@uni-helper/vite-plugin-uni-pages'
|
||||
// @see https://uni-helper.js.org/vite-plugin-uni-layouts
|
||||
import UniLayouts from '@uni-helper/vite-plugin-uni-layouts'
|
||||
// @see https://github.com/uni-helper/vite-plugin-uni-platform
|
||||
// 需要与 @uni-helper/vite-plugin-uni-pages 插件一起使用
|
||||
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
|
||||
*/
|
||||
import Optimization from '@uni-ku/bundle-optimizer'
|
||||
import dayjs from 'dayjs'
|
||||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import ViteRestart from 'vite-plugin-restart'
|
||||
import { copyNativeRes } from './vite-plugins/copyNativeRes'
|
||||
import updatePackageJson from './vite-plugins/updatePackageJson'
|
||||
import Components from '@uni-helper/vite-plugin-uni-components'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default async ({ command, mode }) => {
|
||||
@ -75,7 +75,7 @@ export default async ({ command, mode }) => {
|
||||
// 自定义插件禁用 vite:vue 插件的 devToolsEnabled,强制编译 vue 模板时 inline 为 true
|
||||
name: 'fix-vite-plugin-vue',
|
||||
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) {
|
||||
plugin.api.options.devToolsEnabled = false
|
||||
}
|
||||
@ -91,7 +91,7 @@ export default async ({ command, mode }) => {
|
||||
// Optimization 插件需要 page.json 文件,故应在 UniPages 插件之后执行
|
||||
Optimization({
|
||||
enable: {
|
||||
'optimization': true,
|
||||
optimization: true,
|
||||
'async-import': true,
|
||||
'async-component': true,
|
||||
},
|
||||
@ -113,14 +113,14 @@ export default async ({ command, mode }) => {
|
||||
},
|
||||
},
|
||||
// 打包分析插件,h5 + 生产环境才弹出
|
||||
UNI_PLATFORM === 'h5'
|
||||
&& mode === 'production'
|
||||
&& visualizer({
|
||||
filename: './node_modules/.cache/visualizer/stats.html',
|
||||
open: true,
|
||||
gzipSize: true,
|
||||
brotliSize: true,
|
||||
}),
|
||||
UNI_PLATFORM === 'h5' &&
|
||||
mode === 'production' &&
|
||||
visualizer({
|
||||
filename: './node_modules/.cache/visualizer/stats.html',
|
||||
open: true,
|
||||
gzipSize: true,
|
||||
brotliSize: true,
|
||||
}),
|
||||
// 只有在 app 平台时才启用 copyNativeRes 插件
|
||||
// UNI_PLATFORM === 'app' && copyNativeRes(),
|
||||
Components({
|
||||
@ -163,7 +163,7 @@ export default async ({ command, mode }) => {
|
||||
[VITE_APP_PROXY_PREFIX]: {
|
||||
target: VITE_SERVER_BASEURL,
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(new RegExp(`^${VITE_APP_PROXY_PREFIX}`), ''),
|
||||
rewrite: (path) => path.replace(new RegExp(`^${VITE_APP_PROXY_PREFIX}`), ''),
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
|
Loading…
x
Reference in New Issue
Block a user