├── hooks ├── .gitkeep └── useNavbarWeixin.ts ├── .stylelintignore ├── .eslintignore ├── favicon.ico ├── static ├── logo.png ├── tabbar │ ├── home.png │ ├── homeHL.png │ ├── example.png │ ├── personal.png │ ├── exampleHL.png │ └── personalHL.png └── logo.svg ├── service ├── foo.d.ts └── foo.ts ├── .prettierignore ├── .husky ├── pre-commit └── commit-msg ├── components ├── fly-header │ └── fly-header.vue ├── fly-navbar │ ├── README.md │ └── fly-navbar.vue ├── fly-login │ ├── screenshot.png │ ├── defaultAvatar.png │ ├── README.md │ └── fly-login.vue └── fly-content │ └── fly-content.vue ├── layouts ├── demo.vue └── default.vue ├── interceptors ├── index.ts ├── request.ts └── route.ts ├── pages ├── demo │ ├── page │ │ ├── img-min │ │ │ ├── test-bg.png │ │ │ └── index.vue │ │ ├── floating-bubble.vue │ │ ├── clock.vue │ │ ├── clock2.vue │ │ ├── lottery │ │ │ ├── nine-grid.vue │ │ │ └── big-wheel.vue │ │ ├── waterfall.vue │ │ └── sign.vue │ ├── base │ │ ├── uni-ui.vue │ │ ├── uni-ui-icons.vue │ │ ├── env.vue │ │ ├── enum.vue │ │ ├── unocss.vue │ │ ├── unocss-icons.vue │ │ ├── no-navbar.vue │ │ ├── navbar.vue │ │ ├── vconsole.vue │ │ ├── uv-ui.vue │ │ ├── mp-weixin-share.vue │ │ ├── pinia.vue │ │ ├── request.vue │ │ └── throughout.vue │ ├── route-interceptor │ │ ├── login-auto.vue │ │ ├── index.vue │ │ ├── login-model.vue │ │ └── login-page.vue │ └── index.vue ├── login │ └── index.vue ├── my │ ├── index.vue │ └── components │ │ └── wx-login.vue └── index │ ├── request.vue │ └── index.vue ├── env ├── .env.test ├── .env.production ├── .env.development └── .env ├── .npmrc ├── App.vue ├── main.js ├── .prettierrc.cjs ├── store ├── index.ts ├── count.ts └── user.ts ├── pages-sub └── demo.vue ├── .editorconfig ├── .vscode ├── extensions.json ├── settings.json └── vue3.code-snippets ├── typing.ts ├── env.d.ts ├── pages-bak ├── demo │ ├── unocss.vue │ └── pinia.vue └── index │ └── index.vue ├── index.html ├── .gitignore ├── tsconfig.json ├── LICENSE ├── shell └── postinstall.js ├── pages.config.ts ├── commitlint.config.cjs ├── .stylelintrc.cjs ├── uni.scss ├── utils ├── http.ts └── index.ts ├── .eslintrc-auto-import.json ├── .eslintrc.cjs ├── uno.config.ts ├── package.json ├── manifest.config.ts ├── vite.config.ts ├── README.md ├── unocss.css └── types └── auto-import.d.ts /hooks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | uni_modules/ -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | uni_modules/ 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/favicon.ico -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/logo.png -------------------------------------------------------------------------------- /service/foo.d.ts: -------------------------------------------------------------------------------- 1 | export interface IFooItem { 2 | id: string 3 | name: string 4 | } 5 | -------------------------------------------------------------------------------- /static/tabbar/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/tabbar/home.png -------------------------------------------------------------------------------- /static/tabbar/homeHL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/tabbar/homeHL.png -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用 2 | auto-import.d.ts 3 | -------------------------------------------------------------------------------- /static/tabbar/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/tabbar/example.png -------------------------------------------------------------------------------- /static/tabbar/personal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/tabbar/personal.png -------------------------------------------------------------------------------- /static/tabbar/exampleHL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/tabbar/exampleHL.png -------------------------------------------------------------------------------- /static/tabbar/personalHL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/static/tabbar/personalHL.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install -- lint-staged 5 | -------------------------------------------------------------------------------- /components/fly-header/fly-header.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /layouts/demo.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit 5 | -------------------------------------------------------------------------------- /components/fly-navbar/README.md: -------------------------------------------------------------------------------- 1 | # fly-navbar 2 | 3 | 建议本导航栏组件在设置 `"navigationStyle": "custom"` 的页面使用,目前支持微信小程序的页面滚动动画。 4 | -------------------------------------------------------------------------------- /interceptors/index.ts: -------------------------------------------------------------------------------- 1 | export { routeInterceptor } from './route' 2 | export { requestInterceptor } from './request' 3 | -------------------------------------------------------------------------------- /components/fly-login/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/components/fly-login/screenshot.png -------------------------------------------------------------------------------- /pages/demo/page/img-min/test-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/pages/demo/page/img-min/test-bg.png -------------------------------------------------------------------------------- /components/fly-login/defaultAvatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uni-run/unibest-hbx/HEAD/components/fly-login/defaultAvatar.png -------------------------------------------------------------------------------- /components/fly-login/README.md: -------------------------------------------------------------------------------- 1 | # fly-login 2 | 3 | 点击“点击显示微信头像”按钮后,出现的半屏登录弹窗,可以在任意页面引入。 4 | 5 | 仿“掘金小册”小程序。 6 | 7 | ![掘金小册登录](screenshot.png) 8 | -------------------------------------------------------------------------------- /env/.env.test: -------------------------------------------------------------------------------- 1 | # 变量必须以 VITE_ 为前缀才能暴露给外部读取 2 | NODE_ENV = 'development' 3 | # 是否去除console 和 debugger 4 | VITE_DELETE_CONSOLE = false 5 | 6 | # VITE_SERVER_BASEURL = 'https://xxx.com' 7 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # registry = https://registry.npmjs.org 2 | registry = https://registry.npmmirror.com 3 | 4 | strict-peer-dependencies=false 5 | auto-install-peers=true 6 | shamefully-hoist=true 7 | -------------------------------------------------------------------------------- /env/.env.production: -------------------------------------------------------------------------------- 1 | # 变量必须以 VITE_ 为前缀才能暴露给外部读取 2 | NODE_ENV = 'development' 3 | # 是否去除console 和 debugger 4 | VITE_DELETE_CONSOLE = true 5 | 6 | # VITE_SERVER_BASEURL = 'https://xxx.com' 7 | -------------------------------------------------------------------------------- /env/.env.development: -------------------------------------------------------------------------------- 1 | # 变量必须以 VITE_ 为前缀才能暴露给外部读取 2 | NODE_ENV = 'development' 3 | # 是否去除console 和 debugger 4 | VITE_DELETE_CONSOLE = false 5 | 6 | # VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run' 7 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /components/fly-content/fly-content.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /pages/demo/base/uni-ui.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: 'UniUI 使用' }, 5 | } 6 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /pages/demo/base/uni-ui-icons.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: 'UniUI Icons 使用' }, 5 | } 6 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /pages/demo/base/env.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '环境获取' }, 4 | } 5 | 6 | 7 | 10 | 11 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import { createSSRApp } from 'vue' 2 | import App from './App.vue' 3 | import store from './store' 4 | import { routeInterceptor, requestInterceptor } from './interceptors' 5 | import 'virtual:uno.css' 6 | 7 | export function createApp() { 8 | const app = createSSRApp(App) 9 | app.use(store) 10 | app.use(routeInterceptor) 11 | app.use(requestInterceptor) 12 | return { 13 | app, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | // @see https://prettier.io/docs/en/options 2 | module.exports = { 3 | singleQuote: true, 4 | printWidth: 100, 5 | tabWidth: 2, 6 | useTabs: false, 7 | semi: false, 8 | trailingComma: 'all', 9 | endOfLine: 'auto', 10 | htmlWhitespaceSensitivity: 'ignore', 11 | overrides: [ 12 | { 13 | files: '*.json', 14 | options: { 15 | trailingComma: 'none', 16 | }, 17 | }, 18 | ], 19 | } 20 | -------------------------------------------------------------------------------- /store/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia' 2 | import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化 3 | 4 | const store = createPinia() 5 | store.use( 6 | createPersistedState({ 7 | storage: { 8 | getItem: uni.getStorageSync, 9 | setItem: uni.setStorageSync, 10 | }, 11 | }), 12 | ) 13 | 14 | export default store 15 | 16 | // 模块统一导出 17 | export * from './user' 18 | export * from './count' 19 | -------------------------------------------------------------------------------- /pages/demo/base/enum.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | hide: true, 4 | style: { navigationBarTitleText: 'enum 使用' }, 5 | } 6 | 7 | 8 | 11 | 12 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /pages-sub/demo.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '分包页面 标题' }, 4 | } 5 | 6 | 7 | 13 | 14 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # .editorconfig 文件 2 | root = true 3 | 4 | [*] # 表示所有文件适用 5 | charset = utf-8 # 设置文件字符集为 utf-8 6 | indent_style = space # 缩进风格(tab | space) 7 | indent_size = 2 # 缩进大小 8 | end_of_line = lf # 控制换行类型(lf | cr | crlf) 9 | trim_trailing_whitespace = true # 去除行首的任意空白字符 10 | insert_final_newline = true # 始终在文件末尾插入一个新行 11 | 12 | [*.md] # 表示仅 md 文件适用以下规则 13 | max_line_length = off # 关闭最大行长度限制 14 | trim_trailing_whitespace = false # 关闭末尾空格修剪 15 | 16 | [*.json] 17 | insert_final_newline = false 18 | -------------------------------------------------------------------------------- /pages/demo/route-interceptor/login-auto.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'default', 4 | style: { 5 | navigationBarTitleText: '自动登录(无需拦截)', 6 | }, 7 | } 8 | 9 | 10 | 17 | 18 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /pages/demo/base/unocss.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: 'UnoCss 使用' }, 5 | } 6 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "vue.volar", 4 | "stylelint.vscode-stylelint", 5 | "esbenp.prettier-vscode", 6 | "dbaeumer.vscode-eslint", 7 | "antfu.unocss", 8 | "antfu.iconify", 9 | "evils.uniapp-vscode", 10 | "mrmaoddxxaa.create-uniapp-view", 11 | "uni-helper.uni-helper-vscode", 12 | "uni-helper.uni-app-schemas-vscode", 13 | "uni-helper.uni-highlight-vscode", 14 | "uni-helper.uni-ui-snippets-vscode", 15 | "uni-helper.uni-app-snippets-vscode", 16 | "uni-helper.uni-cloud-snippets-vscode" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /env/.env: -------------------------------------------------------------------------------- 1 | VITE_APP_TITLE = 'unibest' 2 | VITE_APP_PORT = 9000 3 | 4 | # github actions 部署地址根路径,用在 manifest.config.ts 里面的 h5.router.base 5 | VITE_APP_PUBLIC_BASE=/ 6 | 7 | # TODO: 记得修改 8 | VITE_UNI_APPID = 'H5871D791' 9 | VITE_WX_APPID = 'wxa2abb91f64032a2b' 10 | 11 | # fallback lacale:en, zh-Hans, zh-Hant 等 12 | # 必须要在 lacale 文件夹中配置对应的 json 文件!!! 13 | # 参考文档如下 14 | # https://uniapp.dcloud.net.cn/tutorial/i18n.html 15 | # https://uniapp.dcloud.net.cn/api/ui/locale.html#onlocalechange 打开页面后最下面的注意事项 16 | VITE_FALLBACK_LOCALE = 'zh-Hans' 17 | 18 | VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run' 19 | -------------------------------------------------------------------------------- /store/count.ts: -------------------------------------------------------------------------------- 1 | // src/store/useCountStore.ts 2 | import { defineStore } from 'pinia' 3 | import { ref } from 'vue' 4 | 5 | export const useCountStore = defineStore( 6 | 'count', 7 | () => { 8 | const count = ref(0) 9 | const increment = () => { 10 | count.value++ 11 | } 12 | const decrement = () => { 13 | count.value-- 14 | } 15 | const reset = () => { 16 | count.value = 0 17 | } 18 | return { 19 | count, 20 | decrement, 21 | increment, 22 | reset, 23 | } 24 | }, 25 | { 26 | persist: true, 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /pages/demo/base/unocss-icons.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: 'UnoCss Icons 使用' }, 5 | } 6 | 7 | 8 | 21 | -------------------------------------------------------------------------------- /typing.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | /* eslint-disable @typescript-eslint/no-unused-vars */ 3 | // 全局要用的类型放到这里 4 | 5 | type IResData = { 6 | code: number 7 | msg: string 8 | result: T 9 | } 10 | 11 | // uni.uploadFile文件上传参数 12 | type IUniUploadFileOptions = { 13 | file?: File 14 | files?: UniApp.UploadFileOptionFiles[] 15 | filePath?: string 16 | name?: string 17 | formData?: any 18 | } 19 | 20 | type IUserInfo = { 21 | nickname?: string 22 | avatar?: string 23 | /** 微信的 openid,非微信没有这个字段 */ 24 | openid?: string 25 | token?: string 26 | } 27 | 28 | enum TestEnum { 29 | A = 'a', 30 | B = 'b', 31 | } 32 | -------------------------------------------------------------------------------- /pages/demo/base/no-navbar.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '无导航栏', navigationStyle: 'custom' }, 4 | } 5 | 6 | 7 | 16 | 17 | 21 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | declare module '*.vue' { 5 | import { DefineComponent } from 'vue' 6 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 7 | const component: DefineComponent<{}, {}, any> 8 | export default component 9 | } 10 | 11 | interface ImportMetaEnv { 12 | readonly VITE_APP_TITLE: string 13 | readonly VITE_SERVER_PORT: string 14 | readonly VITE_SERVER_BASEURL: string 15 | readonly VITE_DELETE_CONSOLE: string 16 | // 更多环境变量... 17 | } 18 | 19 | interface ImportMeta { 20 | readonly env: ImportMetaEnv 21 | } 22 | -------------------------------------------------------------------------------- /pages-bak/demo/unocss.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { 4 | navigationBarTitleText: 'unocss', 5 | }, 6 | } 7 | 8 | 9 | 23 | -------------------------------------------------------------------------------- /pages/demo/base/navbar.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '自定义导航栏', navigationStyle: 'custom' }, 4 | } 5 | 6 | 7 | 21 | 22 | 29 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pages/demo/base/vconsole.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: '小程序vConsole' }, 5 | } 6 | 7 | 8 | 23 | -------------------------------------------------------------------------------- /service/foo.ts: -------------------------------------------------------------------------------- 1 | import { http, uniFileUpload } from '@/utils/http' 2 | import type { IFooItem } from './foo.d' 3 | 4 | export { IFooItem } 5 | 6 | /** get 请求 */ 7 | export const getFooAPI = (name: string) => { 8 | return http({ 9 | url: `/foo`, 10 | method: 'GET', 11 | query: { name }, 12 | }) 13 | } 14 | 15 | /** get 请求 */ 16 | export const postFooAPI = (name: string) => { 17 | return http({ 18 | url: `/foo`, 19 | method: 'POST', 20 | query: { name }, // post 请求也支持 query 21 | data: { name }, 22 | }) 23 | } 24 | 25 | // 文件上传 26 | export const fileUpload = (data: IUniUploadFileOptions) => { 27 | return uniFileUpload({ 28 | url: `/foo/upload`, 29 | method: 'POST', 30 | ...data, 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /store/user.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import { ref, computed } from 'vue' 3 | 4 | const initState = { nickname: '', avatar: '' } 5 | 6 | export const useUserStore = defineStore( 7 | 'user', 8 | () => { 9 | const userInfo = ref({ ...initState }) 10 | 11 | const setUserInfo = (val: IUserInfo) => { 12 | userInfo.value = val 13 | } 14 | 15 | const clearUserInfo = () => { 16 | userInfo.value = { ...initState } 17 | } 18 | const reset = () => { 19 | userInfo.value = { ...initState } 20 | } 21 | const isLogined = computed(() => !!userInfo.value.token) 22 | 23 | return { 24 | userInfo, 25 | setUserInfo, 26 | clearUserInfo, 27 | isLogined, 28 | reset, 29 | } 30 | }, 31 | { 32 | persist: true, 33 | }, 34 | ) 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | *.local 14 | 15 | # Editor directories and files 16 | .idea 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | .hbuilderx 23 | 24 | .stylelintcache 25 | 26 | # unplugin-auto-import 生成的类型文件 27 | # auto-import.d.ts 28 | # vite-plugin-uni-pages 生成的类型文件 29 | uni-pages.d.ts 30 | # 插件生成的文件 31 | pages.json 32 | manifest.json 33 | 34 | # lock 文件还是不要了,我主要的版本写死就好了 35 | pnpm-lock.yaml 36 | package-lock.json 37 | 38 | # TIPS:如果某些文件已经加入了版本管理,现在重新加入 .gitignore 是不生效的,需要执行下面的操作 39 | # `git rm -r --cached .` 然后提交 commit 即可。 40 | 41 | # git rm -r --cached file1 file2 ## 针对某些文件 42 | # git rm -r --cached dir1 dir2 ## 针对某些文件夹 43 | # git rm -r --cached . ## 针对所有文件 44 | -------------------------------------------------------------------------------- /pages/login/index.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '登录' }, 4 | } 5 | 6 | 7 | 15 | 16 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /pages/my/index.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '我的' }, 4 | } 5 | 6 | 11 | 12 | 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "resolveJsonModule": true, 8 | "noImplicitThis": true, 9 | "allowSyntheticDefaultImports": true, 10 | "allowJs": true, 11 | "sourceMap": true, 12 | "baseUrl": ".", 13 | "paths": { 14 | "@/*": ["./*"] 15 | }, 16 | "outDir": "dist", 17 | "lib": ["esnext", "dom"], 18 | "types": [ 19 | "@dcloudio/types", 20 | "@types/wechat-miniprogram", 21 | "@uni-helper/uni-app-types", 22 | "@uni-helper/uni-ui-types", 23 | "wot-design-uni/global.d.ts" 24 | ] 25 | }, 26 | "vueCompilerOptions": { 27 | "target": 3, 28 | "nativeTags": ["block", "template", "component", "slot"] 29 | }, 30 | "exclude": ["node_modules"], 31 | "include": [ 32 | "./**/*.ts", 33 | "./**/*.js", 34 | "./**/*.d.ts", 35 | "./**/*.tsx", 36 | "./**/*.jsx", 37 | "./**/*.vue", 38 | "./**/*.json", 39 | "main.js" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 菲鸽 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pages/demo/base/uv-ui.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: 'uv ui' }, 4 | } 5 | 6 | 7 | 20 | 21 | 46 | 47 | 50 | -------------------------------------------------------------------------------- /pages/my/components/wx-login.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '登录' }, 4 | } 5 | 6 | 7 | 22 | 23 | 40 | -------------------------------------------------------------------------------- /shell/postinstall.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 本文件会在依赖包安装时执行,用以生成 `src/manifest.json` 3 | * 如果不存在 `src/manifest.json` 会运行报错,提示找不到 `src/manifest.json` 4 | * 如果中途自己删除了 'src/manifest.json' 文件,记得手动执行本文件,可以右键 `Run Code` 快速执行 5 | * 6 | * 本文件是为了兼容 window 系统才生成的 7 | */ 8 | 9 | // eslint-disable-next-line @typescript-eslint/no-var-requires 10 | const fs = require('fs') 11 | 12 | const filePath = './manifest.json' 13 | 14 | if (fs.existsSync(filePath)) { 15 | // console.log(`${filePath}存在`) 16 | } else { 17 | // console.log(`${filePath}不存在,需要创建`) 18 | fs.writeFile(filePath, '{"vueVersion": "3"}\n', {}, () => { 19 | // console.log(`${filePath}已经成功创建,并写入{}`) 20 | }) 21 | } 22 | 23 | const filePath2 = './pages.json' 24 | if (fs.existsSync(filePath2)) { 25 | // console.log(`${filePath}存在`) 26 | } else { 27 | // console.log(`${filePath}不存在,需要创建`) 28 | fs.writeFile( 29 | filePath2, 30 | `{ 31 | "pages": [ 32 | { 33 | "path": "pages/index/index", 34 | "type": "home", 35 | "style": { 36 | "navigationStyle": "custom", 37 | "navigationBarTitleText": "首页" 38 | } 39 | } 40 | ] 41 | }\n`, 42 | {}, 43 | () => { 44 | // console.log(`${filePath}已经成功创建,并写入{}`) 45 | }, 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /pages/demo/route-interceptor/index.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '登陆拦截' }, 4 | } 5 | 6 | 7 | 22 | 23 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /pages/demo/page/img-min/index.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: '图片压缩' }, 5 | } 6 | 7 | 8 | 11 | 12 | 42 | -------------------------------------------------------------------------------- /pages.config.ts: -------------------------------------------------------------------------------- 1 | import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages' 2 | 3 | export default defineUniPages({ 4 | globalStyle: { 5 | navigationStyle: 'default', 6 | navigationBarTitleText: 'unibest', 7 | navigationBarBackgroundColor: '#f8f8f8', 8 | navigationBarTextStyle: 'black', 9 | backgroundColor: '#FFFFFF', 10 | h5: { 11 | navigationStyle: 'custom', 12 | }, 13 | }, 14 | easycom: { 15 | autoscan: true, 16 | custom: { 17 | '^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue', 18 | '^layout-(.*)-uni': '@/layouts/$1.vue', 19 | }, 20 | }, 21 | tabBar: { 22 | color: '#999999', 23 | selectedColor: '#018d71', 24 | backgroundColor: '#F8F8F8', 25 | borderStyle: 'black', 26 | height: '50px', 27 | fontSize: '10px', 28 | iconWidth: '24px', 29 | spacing: '3px', 30 | list: [ 31 | { 32 | iconPath: 'static/tabbar/home.png', 33 | selectedIconPath: 'static/tabbar/homeHL.png', 34 | pagePath: 'pages/index/index', 35 | text: '首页', 36 | }, 37 | { 38 | iconPath: 'static/tabbar/example.png', 39 | selectedIconPath: 'static/tabbar/exampleHL.png', 40 | pagePath: 'pages/demo/index', 41 | text: '示例', 42 | }, 43 | ], 44 | }, 45 | }) 46 | -------------------------------------------------------------------------------- /pages/demo/base/mp-weixin-share.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: '微信分享' }, 5 | } 6 | 7 | 8 | 22 | 23 | 42 | -------------------------------------------------------------------------------- /pages-bak/demo/pinia.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { 4 | navigationBarTitleText: 'pinia', 5 | }, 6 | } 7 | 8 | 9 | 24 | 25 | 42 | -------------------------------------------------------------------------------- /pages/demo/base/pinia.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { navigationBarTitleText: 'pinia+持久化' }, 5 | } 6 | 7 | 8 | 23 | 24 | 41 | -------------------------------------------------------------------------------- /commitlint.config.cjs: -------------------------------------------------------------------------------- 1 | // commitlint.config.cjs 2 | 3 | module.exports = { 4 | extends: ['@commitlint/config-conventional'], 5 | rules: { 6 | // 'body-leading-blank': [2, 'always'], // 主体前有空行,默认就是 always 7 | // 'footer-leading-blank': [2, 'always'], // 末行前有空行,默认就是 always 8 | // 'header-max-length': [2, 'always', 108], // 首行最大长度,默认就是 always,72 9 | // 'subject-empty': [2, 'never'], // 标题不可为空,默认就是 never 10 | // 'type-empty': [2, 'never'], // 类型不可为空,默认就是 never 11 | 12 | // 允许的类型 13 | 'type-enum': [ 14 | 2, 15 | 'always', 16 | [ 17 | 'build', // 构造工具、外部依赖(webpack、npm) 18 | 'chore', // 不涉及 src、test 的其他修改(构建过程或辅助工具的变更) 19 | 'ci', // 修改项目继续集成流程(Travis,Jenkins,GitLab CI,Circle等) 20 | 'docs', // 文档 21 | 'feat', // 新增功能 22 | 'fix', // bug 修复 23 | 'perf', // 性能优化 24 | 'refactor', // 重构 25 | 'revert', // 回退 26 | 'style', // 代码风格(不影响代码含义) 27 | 'test', // 测试 28 | 29 | // 下面几个是自定义新增的 30 | 'wip', // 开发中 31 | 'refine', // 小优化,没有到 refactor 的程度 32 | ], 33 | ], 34 | }, 35 | } 36 | 37 | // @see https://commitlint.js.org/#/reference-rules?id=type-enum 38 | // 默认值为: 39 | // [ 40 | // 'build', 41 | // 'chore', 42 | // 'ci', 43 | // 'docs', 44 | // 'feat', 45 | // 'fix', 46 | // 'perf', 47 | // 'refactor', 48 | // 'revert', 49 | // 'style', 50 | // 'test', 51 | // ]; 52 | -------------------------------------------------------------------------------- /interceptors/request.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-param-reassign */ 2 | import qs from 'qs' 3 | import { useUserStore } from '@/store' 4 | 5 | export type CustomRequestOptions = UniApp.RequestOptions & { 6 | query?: Record 7 | } & IUniUploadFileOptions // 添加uni.uploadFile参数类型 8 | 9 | // 请求基地址 10 | const baseURL = import.meta.env.VITE_SERVER_BASEURL 11 | 12 | // 拦截器配置 13 | const httpInterceptor = { 14 | // 拦截前触发 15 | invoke(options: CustomRequestOptions) { 16 | // 接口请求支持通过 query 参数配置 queryString 17 | if (options.query) { 18 | const queryStr = qs.stringify(options.query) 19 | if (options.url.includes('?')) { 20 | options.url += `&${queryStr}` 21 | } else { 22 | options.url += `?${queryStr}` 23 | } 24 | } 25 | 26 | // 1. 非 http 开头需拼接地址 27 | if (!options.url.startsWith('http')) { 28 | options.url = baseURL + options.url 29 | } 30 | // 2. 请求超时 31 | options.timeout = 10000 // 10s 32 | // 3. 添加小程序端请求头标识 33 | options.header = { 34 | platform: 'mp-weixin', // 可选值与 uniapp 定义的平台一致,告诉后台来源 35 | ...options.header, 36 | } 37 | // 4. 添加 token 请求头标识 38 | const userStore = useUserStore() 39 | const { token } = userStore.userInfo as unknown as IUserInfo 40 | if (token) { 41 | options.header.Authorization = `Bearer ${token}` 42 | } 43 | }, 44 | } 45 | 46 | export const requestInterceptor = { 47 | install() { 48 | // 拦截 request 请求 49 | uni.addInterceptor('request', httpInterceptor) 50 | // 拦截 uploadFile 文件上传 51 | uni.addInterceptor('uploadFile', httpInterceptor) 52 | }, 53 | } 54 | -------------------------------------------------------------------------------- /pages/index/request.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { 5 | navigationBarTitleText: '请求', 6 | }, 7 | } 8 | 9 | 10 | 33 | 34 | 56 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // 默认格式化工具选择prettier 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | // 保存的时候自动格式化 5 | "editor.formatOnSave": true, 6 | //开启自动修复 7 | "editor.codeActionsOnSave": { 8 | "source.fixAll": "explicit", 9 | "source.fixAll.eslint": "explicit", 10 | "source.fixAll.stylelint": "explicit" 11 | }, 12 | // 配置stylelint检查的文件类型范围 13 | "stylelint.validate": ["css", "scss", "vue", "html"], // 与package.json的scripts对应 14 | "stylelint.enable": true, 15 | "css.validate": false, 16 | "less.validate": false, 17 | "scss.validate": false, 18 | "[shellscript]": { 19 | "editor.defaultFormatter": "foxundermoon.shell-format" 20 | }, 21 | "[dotenv]": { 22 | "editor.defaultFormatter": "foxundermoon.shell-format" 23 | }, 24 | "[vue]": { 25 | "editor.defaultFormatter": "esbenp.prettier-vscode" 26 | }, 27 | "[typescript]": { 28 | "editor.defaultFormatter": "esbenp.prettier-vscode" 29 | }, 30 | "[jsonc]": { 31 | "editor.defaultFormatter": "esbenp.prettier-vscode" 32 | }, 33 | // 配置语言的文件关联 34 | "files.associations": { 35 | "pages.json": "jsonc", // pages.json 可以写注释 36 | "manifest.json": "jsonc" // manifest.json 可以写注释 37 | }, 38 | "cSpell.words": [ 39 | "climblee", 40 | "commitlint", 41 | "dcloudio", 42 | "feige", 43 | "qrcode", 44 | "refresherrefresh", 45 | "safeareainsets", 46 | "scrolltolower", 47 | "tabbar", 48 | "unibest", 49 | "uvui", 50 | "WechatMiniprogram" 51 | ], 52 | "typescript.tsdk": "node_modules\\typescript\\lib", 53 | "[json]": { 54 | "editor.defaultFormatter": "esbenp.prettier-vscode" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.stylelintrc.cjs: -------------------------------------------------------------------------------- 1 | // .stylelintrc.cjs 2 | 3 | module.exports = { 4 | root: true, 5 | extends: [ 6 | // stylelint-config-standard 替换成了更宽松的 stylelint-config-recommended 7 | 'stylelint-config-recommended', 8 | // stylelint-config-standard-scss 替换成了更宽松的 stylelint-config-recommended-scss 9 | 'stylelint-config-recommended-scss', 10 | 'stylelint-config-recommended-vue/scss', 11 | 'stylelint-config-html/vue', 12 | 'stylelint-config-recess-order', 13 | ], 14 | plugins: ['stylelint-prettier'], 15 | overrides: [ 16 | // 扫描 .vue/html 文件中的 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /.vscode/vue3.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | // Place your unibest 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 3 | // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 4 | // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 5 | // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 6 | // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 7 | // Placeholders with the same ids are connected. 8 | // Example: 9 | // "Print to console": { 10 | // "scope": "javascript,typescript", 11 | // "prefix": "log", 12 | // "body": [ 13 | // "console.log('$1');", 14 | // "$2" 15 | // ], 16 | // "description": "Log output to console" 17 | // } 18 | "Print unibest Vue3 SFC": { 19 | "scope": "vue", 20 | "prefix": "v3", 21 | "body": [ 22 | "\n", 25 | "\n", 28 | "\n", 31 | ], 32 | }, 33 | "Print unibest style": { 34 | "scope": "vue", 35 | "prefix": "st", 36 | "body": ["\n"], 37 | }, 38 | "Print unibest script": { 39 | "scope": "vue", 40 | "prefix": "sc", 41 | "body": ["\n"], 42 | }, 43 | "Print unibest template": { 44 | "scope": "vue", 45 | "prefix": "te", 46 | "body": ["\n"], 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /hooks/useNavbarWeixin.ts: -------------------------------------------------------------------------------- 1 | import { onReady } from '@dcloudio/uni-app' 2 | import { getIsTabbar, getArrElementByIdx } from '@/utils/index' 3 | 4 | export default () => { 5 | // 获取页面栈 6 | const pages = getCurrentPages() 7 | const isTabbar = getIsTabbar() 8 | 9 | // 页面滚动到底部时的操作,通常用于加载更多数据 10 | const onScrollToLower = () => {} 11 | // 获取屏幕边界到安全区域距离 12 | const { safeAreaInsets } = uni.getSystemInfoSync() 13 | 14 | // #ifdef MP-WEIXIN 15 | // 基于小程序的 Page 类型扩展 uni-app 的 Page 16 | type PageInstance = Page.PageInstance & WechatMiniprogram.Page.InstanceMethods 17 | // 获取当前页面实例,数组最后一项 18 | const pageInstance = getArrElementByIdx(getCurrentPages(), -1) as PageInstance 19 | 20 | // 页面渲染完毕,绑定动画效果 21 | onReady(() => { 22 | // 动画效果,导航栏背景色 23 | pageInstance.animate( 24 | '.fly-navbar', 25 | [{ backgroundColor: 'transparent' }, { backgroundColor: '#f8f8f8' }], 26 | 1000, 27 | { 28 | scrollSource: '#scroller', 29 | timeRange: 1000, 30 | startScrollOffset: 0, 31 | endScrollOffset: 50, 32 | }, 33 | ) 34 | // 动画效果,导航栏标题 35 | pageInstance.animate( 36 | '.fly-navbar .title', 37 | [{ color: 'transparent' }, { color: '#000' }], 38 | 1000, 39 | { 40 | scrollSource: '#scroller', 41 | timeRange: 1000, 42 | startScrollOffset: 0, 43 | endScrollOffset: 50, 44 | }, 45 | ) 46 | // 动画效果,导航栏返回按钮 47 | pageInstance.animate('.fly-navbar .left-icon', [{ color: '#fff' }, { color: '#000' }], 1000, { 48 | scrollSource: '#scroller', 49 | timeRange: 1000, 50 | startScrollOffset: 0, 51 | endScrollOffset: 50, 52 | }) 53 | }) 54 | // #endif 55 | 56 | return { 57 | pages, 58 | isTabbar, 59 | onScrollToLower, 60 | safeAreaInsets, 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /uni.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里是uni-app内置的常用样式变量 3 | * 4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App 6 | * 7 | */ 8 | 9 | /** 10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 11 | * 12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 13 | */ 14 | 15 | /* 颜色变量 */ 16 | 17 | /* 行为相关颜色 */ 18 | $uni-color-primary: #007aff; 19 | $uni-color-success: #4cd964; 20 | $uni-color-warning: #f0ad4e; 21 | $uni-color-error: #dd524d; 22 | 23 | /* 文字基本颜色 */ 24 | $uni-text-color: #333; //基本色 25 | $uni-text-color-inverse: #fff; //反色 26 | $uni-text-color-grey: #999; //辅助灰色,如加载更多的提示信息 27 | $uni-text-color-placeholder: #808080; 28 | $uni-text-color-disable: #c0c0c0; 29 | 30 | /* 背景颜色 */ 31 | $uni-bg-color: #ffffff; 32 | $uni-bg-color-grey: #f8f8f8; 33 | $uni-bg-color-hover: #f1f1f1; //点击状态颜色 34 | $uni-bg-color-mask: rgba(0, 0, 0, 0.4); //遮罩颜色 35 | 36 | /* 边框颜色 */ 37 | $uni-border-color: #c8c7cc; 38 | 39 | /* 尺寸变量 */ 40 | 41 | /* 文字尺寸 */ 42 | $uni-font-size-sm: 12px; 43 | $uni-font-size-base: 14px; 44 | $uni-font-size-lg: 16px; 45 | 46 | /* 图片尺寸 */ 47 | $uni-img-size-sm: 20px; 48 | $uni-img-size-base: 26px; 49 | $uni-img-size-lg: 40px; 50 | 51 | /* Border Radius */ 52 | $uni-border-radius-sm: 2px; 53 | $uni-border-radius-base: 3px; 54 | $uni-border-radius-lg: 6px; 55 | $uni-border-radius-circle: 50%; 56 | 57 | /* 水平间距 */ 58 | $uni-spacing-row-sm: 5px; 59 | $uni-spacing-row-base: 10px; 60 | $uni-spacing-row-lg: 15px; 61 | 62 | /* 垂直间距 */ 63 | $uni-spacing-col-sm: 4px; 64 | $uni-spacing-col-base: 8px; 65 | $uni-spacing-col-lg: 12px; 66 | 67 | /* 透明度 */ 68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 69 | 70 | /* 文章场景相关 */ 71 | $uni-color-title: #2c405a; // 文章标题颜色 72 | $uni-font-size-title: 20px; 73 | $uni-color-subtitle: #555555; // 二级标题颜色 74 | $uni-font-size-subtitle: 26px; 75 | $uni-color-paragraph: #3f536e; // 文章段落颜色 76 | $uni-font-size-paragraph: 15px; 77 | -------------------------------------------------------------------------------- /pages/demo/base/request.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'demo', 4 | style: { 5 | navigationBarTitleText: '请求', 6 | }, 7 | } 8 | 9 | 10 | 37 | 38 | 67 | -------------------------------------------------------------------------------- /components/fly-navbar/fly-navbar.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 39 | 40 | 72 | -------------------------------------------------------------------------------- /pages/demo/route-interceptor/login-model.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | style: { navigationBarTitleText: '登陆拦截 - 登陆弹窗' }, 4 | } 5 | 6 | 7 | 22 | 23 | 73 | 74 | 77 | -------------------------------------------------------------------------------- /pages/demo/page/floating-bubble.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | layout: 'default', 4 | hide: true, 5 | style: { navigationBarTitleText: '页面悬浮球' }, 6 | } 7 | 8 | 9 | 32 | 33 | 73 | 74 | 90 | -------------------------------------------------------------------------------- /pages/demo/route-interceptor/login-page.vue: -------------------------------------------------------------------------------- 1 | 2 | { 3 | needLogin: true, 4 | style: { navigationBarTitleText: '登陆拦截 - 登陆页面' }, 5 | } 6 | 7 | 8 | 18 | 19 | 70 | 71 | 74 | -------------------------------------------------------------------------------- /utils/http.ts: -------------------------------------------------------------------------------- 1 | import { CustomRequestOptions } from '@/interceptors/request' 2 | 3 | export const http = (options: CustomRequestOptions) => { 4 | // 1. 返回 Promise 对象 5 | return new Promise>((resolve, reject) => { 6 | uni.request({ 7 | ...options, 8 | dataType: 'json', 9 | // #ifndef MP-WEIXIN 10 | responseType: 'json', 11 | // #endif 12 | // 响应成功 13 | success(res) { 14 | // 状态码 2xx,参考 axios 的设计 15 | if (res.statusCode >= 200 && res.statusCode < 300) { 16 | // 2.1 提取核心数据 res.data 17 | resolve(res.data as IResData) 18 | } else if (res.statusCode === 401) { 19 | // 401错误 -> 清理用户信息,跳转到登录页 20 | // userStore.clearUserInfo() 21 | // uni.navigateTo({ url: '/pages/login/login' }) 22 | reject(res) 23 | } else { 24 | // 其他错误 -> 根据后端错误信息轻提示 25 | uni.showToast({ 26 | icon: 'none', 27 | title: (res.data as IResData).msg || '请求错误', 28 | }) 29 | reject(res) 30 | } 31 | }, 32 | // 响应失败 33 | fail(err) { 34 | uni.showToast({ 35 | icon: 'none', 36 | title: '网络错误,换个网络试试', 37 | }) 38 | reject(err) 39 | }, 40 | }) 41 | }) 42 | } 43 | 44 | // uni.uploadFile封装 45 | export const uniFileUpload = (options: CustomRequestOptions) => { 46 | // 1. 返回 Promise 对象 47 | return new Promise>((resolve, reject) => { 48 | uni.uploadFile({ 49 | ...options, 50 | // 响应成功 51 | success(res) { 52 | // 状态码 2xx,参考 axios 的设计 53 | if (res.statusCode >= 200 && res.statusCode < 300) { 54 | // 文件上传接口的rea.data的类型为string,这里转一下 55 | const resData = JSON.parse(res.data) as IResData 56 | resolve(resData) 57 | } else if (res.statusCode === 401) { 58 | // 401错误 -> 清理用户信息,跳转到登录页 59 | // userStore.clearUserInfo() 60 | // uni.navigateTo({ url: '/pages/login/login' }) 61 | reject(res) 62 | } else { 63 | // 其他错误 -> 根据后端错误信息轻提示 64 | uni.showToast({ 65 | icon: 'none', 66 | title: '文件上传错误', 67 | }) 68 | reject(res) 69 | } 70 | }, 71 | // 响应失败 72 | fail(err) { 73 | uni.showToast({ 74 | icon: 'none', 75 | title: '网络错误,换个网络试试', 76 | }) 77 | reject(err) 78 | }, 79 | }) 80 | }) 81 | } 82 | -------------------------------------------------------------------------------- /pages-bak/index/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | { 4 | style: { 5 | navigationStyle: 'custom', 6 | navigationBarTitleText: '首页', 7 | }, 8 | } 9 | 10 | 45 | 46 | 69 | 70 | 79 | -------------------------------------------------------------------------------- /pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | { 4 | style: { 5 | navigationStyle: 'custom', 6 | navigationBarTitleText: '首页', 7 | }, 8 | } 9 | 10 | 46 | 47 | 70 | 71 | 76 | -------------------------------------------------------------------------------- /.eslintrc-auto-import.json: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "Component": true, 4 | "ComponentPublicInstance": true, 5 | "ComputedRef": true, 6 | "EffectScope": true, 7 | "ExtractDefaultPropTypes": true, 8 | "ExtractPropTypes": true, 9 | "ExtractPublicPropTypes": true, 10 | "InjectionKey": true, 11 | "PropType": true, 12 | "Ref": true, 13 | "VNode": true, 14 | "WritableComputedRef": true, 15 | "computed": true, 16 | "createApp": true, 17 | "customRef": true, 18 | "defineAsyncComponent": true, 19 | "defineComponent": true, 20 | "effectScope": true, 21 | "getCurrentInstance": true, 22 | "getCurrentScope": true, 23 | "h": true, 24 | "inject": true, 25 | "isProxy": true, 26 | "isReactive": true, 27 | "isReadonly": true, 28 | "isRef": true, 29 | "markRaw": true, 30 | "nextTick": true, 31 | "onActivated": true, 32 | "onAddToFavorites": true, 33 | "onBackPress": true, 34 | "onBeforeMount": true, 35 | "onBeforeUnmount": true, 36 | "onBeforeUpdate": true, 37 | "onDeactivated": true, 38 | "onError": true, 39 | "onErrorCaptured": true, 40 | "onHide": true, 41 | "onLaunch": true, 42 | "onLoad": true, 43 | "onMounted": true, 44 | "onNavigationBarButtonTap": true, 45 | "onNavigationBarSearchInputChanged": true, 46 | "onNavigationBarSearchInputClicked": true, 47 | "onNavigationBarSearchInputConfirmed": true, 48 | "onNavigationBarSearchInputFocusChanged": true, 49 | "onPageNotFound": true, 50 | "onPageScroll": true, 51 | "onPullDownRefresh": true, 52 | "onReachBottom": true, 53 | "onReady": true, 54 | "onRenderTracked": true, 55 | "onRenderTriggered": true, 56 | "onResize": true, 57 | "onScopeDispose": true, 58 | "onServerPrefetch": true, 59 | "onShareAppMessage": true, 60 | "onShareTimeline": true, 61 | "onShow": true, 62 | "onTabItemTap": true, 63 | "onThemeChange": true, 64 | "onUnhandledRejection": true, 65 | "onUnload": true, 66 | "onUnmounted": true, 67 | "onUpdated": true, 68 | "provide": true, 69 | "reactive": true, 70 | "readonly": true, 71 | "ref": true, 72 | "resolveComponent": true, 73 | "shallowReactive": true, 74 | "shallowReadonly": true, 75 | "shallowRef": true, 76 | "toRaw": true, 77 | "toRef": true, 78 | "toRefs": true, 79 | "toValue": true, 80 | "triggerRef": true, 81 | "unref": true, 82 | "useAttrs": true, 83 | "useCssModule": true, 84 | "useCssVars": true, 85 | "useSlots": true, 86 | "watch": true, 87 | "watchEffect": true, 88 | "watchPostEffect": true, 89 | "watchSyncEffect": true 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:vue/vue3-essential', 11 | // eslint-plugin-import 插件, @see https://www.npmjs.com/package/eslint-plugin-import 12 | 'plugin:import/recommended', 13 | // eslint-config-airbnb-base 插件 已经改用 eslint-config-standard 插件 14 | 'standard', 15 | // 1. 接入 prettier 的规则 16 | 'prettier', 17 | 'plugin:prettier/recommended', 18 | './.eslintrc-auto-import.json', 19 | ], 20 | overrides: [ 21 | { 22 | env: { 23 | node: true, 24 | }, 25 | files: ['.eslintrc.{js,cjs}'], 26 | parserOptions: { 27 | sourceType: 'script', 28 | }, 29 | }, 30 | ], 31 | parserOptions: { 32 | ecmaVersion: 'latest', 33 | parser: '@typescript-eslint/parser', 34 | sourceType: 'module', 35 | }, 36 | plugins: [ 37 | '@typescript-eslint', 38 | 'vue', 39 | // 2. 加入 prettier 的 eslint 插件 40 | 'prettier', 41 | // eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript 42 | 'import', 43 | ], 44 | rules: { 45 | // 3. 注意要加上这一句,开启 prettier 自动修复的功能 46 | 'prettier/prettier': 'error', 47 | // turn on errors for missing imports 48 | 'import/no-unresolved': 'off', 49 | // 对后缀的检测,否则 import 一个ts文件也会报错,需要手动添加'.ts', 增加了下面的配置后就不用了 50 | 'import/extensions': [ 51 | 'error', 52 | 'ignorePackages', 53 | { js: 'never', jsx: 'never', ts: 'never', tsx: 'never' }, 54 | ], 55 | // 只允许1个默认导出,关闭,否则不能随意export xxx 56 | 'import/prefer-default-export': ['off'], 57 | 'no-console': ['off'], 58 | // 'no-unused-vars': ['off'], 59 | // '@typescript-eslint/no-unused-vars': ['off'], 60 | // 解决vite.config.ts报错问题 61 | 'import/no-extraneous-dependencies': 'off', 62 | 'no-plusplus': 'off', 63 | 'no-shadow': 'off', 64 | 'vue/multi-word-component-names': 'off', 65 | '@typescript-eslint/no-explicit-any': 'off', 66 | 'no-underscore-dangle': 'off', 67 | 'no-use-before-define': 'off', 68 | 'no-undef': 'off', 69 | 'no-unused-vars': 'off', 70 | 'no-param-reassign': 'off', 71 | '@typescript-eslint/no-unused-vars': 'off', 72 | }, 73 | // eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript 74 | settings: { 75 | 'import/parsers': { 76 | '@typescript-eslint/parser': ['.ts', '.tsx'], 77 | }, 78 | 'import/resolver': { 79 | typescript: {}, 80 | }, 81 | }, 82 | globals: { 83 | $t: true, 84 | uni: true, 85 | UniApp: true, 86 | wx: true, 87 | WechatMiniprogram: true, 88 | getCurrentPages: true, 89 | UniHelper: true, 90 | Page: true, 91 | App: true, 92 | NodeJS: true, 93 | }, 94 | } 95 | -------------------------------------------------------------------------------- /uno.config.ts: -------------------------------------------------------------------------------- 1 | // uno.config.ts 2 | import { 3 | type Preset, 4 | defineConfig, 5 | presetUno, 6 | presetAttributify, 7 | presetIcons, 8 | transformerDirectives, 9 | transformerVariantGroup, 10 | } from 'unocss' 11 | 12 | import { presetApplet, presetRemRpx, transformerAttributify } from 'unocss-applet' 13 | 14 | // @see https://unocss.dev/presets/legacy-compat 15 | import { presetLegacyCompat } from '@unocss/preset-legacy-compat' 16 | 17 | const isMp = process.env?.UNI_PLATFORM?.startsWith('mp') ?? false 18 | 19 | const presets: Preset[] = [] 20 | if (isMp) { 21 | // 使用小程序预设 22 | presets.push(presetApplet(), presetRemRpx()) 23 | } else { 24 | presets.push( 25 | // 非小程序用官方预设 26 | presetUno(), 27 | // 支持css class属性化 28 | presetAttributify(), 29 | ) 30 | } 31 | export default defineConfig({ 32 | presets: [ 33 | ...presets, 34 | // 支持图标,需要搭配图标库,eg: @iconify-json/carbon, 使用 `