commit 9061da3a292dc2fca753540f2455a8cb15a00ebd Author: 奏 <1978476055@qq.com> Date: Fri Oct 18 18:09:15 2024 +0800 1 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fccdb00 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# .editorconfig 文件 +root = true + +[*] # 表示所有文件适用 +charset = utf-8 # 设置文件字符集为 utf-8 +indent_style = space # 缩进风格(tab | space) +indent_size = 2 # 缩进大小 +end_of_line = lf # 控制换行类型(lf | cr | crlf) +trim_trailing_whitespace = true # 去除行首的任意空白字符 +insert_final_newline = true # 始终在文件末尾插入一个新行 + +[*.md] # 表示仅 md 文件适用以下规则 +max_line_length = off # 关闭最大行长度限制 +trim_trailing_whitespace = false # 关闭末尾空格修剪 + +[*.json] +insert_final_newline = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..690dffc --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +uni_modules/ diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json new file mode 100644 index 0000000..be77d70 --- /dev/null +++ b/.eslintrc-auto-import.json @@ -0,0 +1,91 @@ +{ + "globals": { + "Component": true, + "ComponentPublicInstance": true, + "ComputedRef": true, + "EffectScope": true, + "ExtractDefaultPropTypes": true, + "ExtractPropTypes": true, + "ExtractPublicPropTypes": true, + "InjectionKey": true, + "PropType": true, + "Ref": true, + "VNode": true, + "WritableComputedRef": true, + "computed": true, + "createApp": true, + "customRef": true, + "defineAsyncComponent": true, + "defineComponent": true, + "effectScope": true, + "getCurrentInstance": true, + "getCurrentScope": true, + "h": true, + "inject": true, + "isProxy": true, + "isReactive": true, + "isReadonly": true, + "isRef": true, + "markRaw": true, + "nextTick": true, + "onActivated": true, + "onAddToFavorites": true, + "onBackPress": true, + "onBeforeMount": true, + "onBeforeUnmount": true, + "onBeforeUpdate": true, + "onDeactivated": true, + "onError": true, + "onErrorCaptured": true, + "onHide": true, + "onLaunch": true, + "onLoad": true, + "onMounted": true, + "onNavigationBarButtonTap": true, + "onNavigationBarSearchInputChanged": true, + "onNavigationBarSearchInputClicked": true, + "onNavigationBarSearchInputConfirmed": true, + "onNavigationBarSearchInputFocusChanged": true, + "onPageNotFound": true, + "onPageScroll": true, + "onPullDownRefresh": true, + "onReachBottom": true, + "onReady": true, + "onRenderTracked": true, + "onRenderTriggered": true, + "onResize": true, + "onScopeDispose": true, + "onServerPrefetch": true, + "onShareAppMessage": true, + "onShareTimeline": true, + "onShow": true, + "onTabItemTap": true, + "onThemeChange": true, + "onUnhandledRejection": true, + "onUnload": true, + "onUnmounted": true, + "onUpdated": true, + "provide": true, + "reactive": true, + "readonly": true, + "ref": true, + "resolveComponent": true, + "shallowReactive": true, + "shallowReadonly": true, + "shallowRef": true, + "toRaw": true, + "toRef": true, + "toRefs": true, + "toValue": true, + "triggerRef": true, + "unref": true, + "useAttrs": true, + "useCssModule": true, + "useCssVars": true, + "useSlots": true, + "watch": true, + "watchEffect": true, + "watchPostEffect": true, + "watchSyncEffect": true + } +} diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..2371f0b --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,94 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:vue/vue3-essential', + // eslint-plugin-import 插件, @see https://www.npmjs.com/package/eslint-plugin-import + 'plugin:import/recommended', + // eslint-config-airbnb-base 插件 已经改用 eslint-config-standard 插件 + 'standard', + // 1. 接入 prettier 的规则 + 'prettier', + 'plugin:prettier/recommended', + './.eslintrc-auto-import.json', + ], + overrides: [ + { + env: { + node: true, + }, + files: ['.eslintrc.{js,cjs}'], + parserOptions: { + sourceType: 'script', + }, + }, + ], + parserOptions: { + ecmaVersion: 'latest', + parser: '@typescript-eslint/parser', + sourceType: 'module', + }, + plugins: [ + '@typescript-eslint', + 'vue', + // 2. 加入 prettier 的 eslint 插件 + 'prettier', + // eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript + 'import', + ], + rules: { + // 3. 注意要加上这一句,开启 prettier 自动修复的功能 + 'prettier/prettier': 'error', + // turn on errors for missing imports + 'import/no-unresolved': 'off', + // 对后缀的检测,否则 import 一个ts文件也会报错,需要手动添加'.ts', 增加了下面的配置后就不用了 + 'import/extensions': [ + 'error', + 'ignorePackages', + { js: 'never', jsx: 'never', ts: 'never', tsx: 'never' }, + ], + // 只允许1个默认导出,关闭,否则不能随意export xxx + 'import/prefer-default-export': ['off'], + 'no-console': ['off'], + // 'no-unused-vars': ['off'], + // '@typescript-eslint/no-unused-vars': ['off'], + // 解决vite.config.ts报错问题 + 'import/no-extraneous-dependencies': 'off', + 'no-plusplus': 'off', + 'no-shadow': 'off', + 'vue/multi-word-component-names': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'no-underscore-dangle': 'off', + 'no-use-before-define': 'off', + 'no-undef': 'off', + 'no-unused-vars': 'off', + 'no-param-reassign': 'off', + '@typescript-eslint/no-unused-vars': 'off', + }, + // eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + typescript: {}, + }, + }, + globals: { + $t: true, + uni: true, + UniApp: true, + wx: true, + WechatMiniprogram: true, + getCurrentPages: true, + UniHelper: true, + Page: true, + App: true, + NodeJS: true, + }, +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e02747a --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +*.local + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.hbuilderx + +.stylelintcache + +# unplugin-auto-import 生成的类型文件 +# auto-import.d.ts +# vite-plugin-uni-pages 生成的类型文件 +uni-pages.d.ts +# 插件生成的文件 +pages.json +manifest.json + +# lock 文件还是不要了,我主要的版本写死就好了 +pnpm-lock.yaml +package-lock.json + +# TIPS:如果某些文件已经加入了版本管理,现在重新加入 .gitignore 是不生效的,需要执行下面的操作 +# `git rm -r --cached .` 然后提交 commit 即可。 + +# git rm -r --cached file1 file2 ## 针对某些文件 +# git rm -r --cached dir1 dir2 ## 针对某些文件夹 +# git rm -r --cached . ## 针对所有文件 diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..7241764 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx --no-install commitlint --edit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..fc7c89d --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx --no-install -- lint-staged diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..356a656 --- /dev/null +++ b/.npmrc @@ -0,0 +1,6 @@ +# registry = https://registry.npmjs.org +registry = https://registry.npmmirror.com + +strict-peer-dependencies=false +auto-install-peers=true +shamefully-hoist=true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..4917b0e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +# unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用 +auto-import.d.ts diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000..3986355 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,19 @@ +// @see https://prettier.io/docs/en/options +module.exports = { + singleQuote: true, + printWidth: 100, + tabWidth: 2, + useTabs: false, + semi: false, + trailingComma: 'all', + endOfLine: 'auto', + htmlWhitespaceSensitivity: 'ignore', + overrides: [ + { + files: '*.json', + options: { + trailingComma: 'none', + }, + }, + ], +} diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..2025d99 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1 @@ +uni_modules/ \ No newline at end of file diff --git a/.stylelintrc.cjs b/.stylelintrc.cjs new file mode 100644 index 0000000..2cb661a --- /dev/null +++ b/.stylelintrc.cjs @@ -0,0 +1,57 @@ +// .stylelintrc.cjs + +module.exports = { + root: true, + extends: [ + // stylelint-config-standard 替换成了更宽松的 stylelint-config-recommended + 'stylelint-config-recommended', + // stylelint-config-standard-scss 替换成了更宽松的 stylelint-config-recommended-scss + 'stylelint-config-recommended-scss', + 'stylelint-config-recommended-vue/scss', + 'stylelint-config-html/vue', + 'stylelint-config-recess-order', + ], + plugins: ['stylelint-prettier'], + overrides: [ + // 扫描 .vue/html 文件中的\n", + ], + }, + "Print unibest style": { + "scope": "vue", + "prefix": "st", + "body": ["\n"], + }, + "Print unibest script": { + "scope": "vue", + "prefix": "sc", + "body": ["\n"], + }, + "Print unibest template": { + "scope": "vue", + "prefix": "te", + "body": ["\n"], + }, +} diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..d77f902 --- /dev/null +++ b/App.vue @@ -0,0 +1,17 @@ + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9c3438e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 菲鸽 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b31703 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +

+ + + +

+ +

+ unibest - 最好的 uniapp 跨端解决方案 +

+ +
+ +[![GitHub Repo stars](https://img.shields.io/github/stars/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest) +[![GitHub forks](https://img.shields.io/github/forks/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest) +[![star](https://gitee.com/codercup/unibest/badge/star.svg?theme=dark)](https://gitee.com/codercup/unibest/stargazers) +[![fork](https://gitee.com/codercup/unibest/badge/fork.svg?theme=dark)](https://gitee.com/codercup/unibest/members) +![node version](https://img.shields.io/badge/node-%3E%3D18-green) +![pnpm version](https://img.shields.io/badge/pnpm-%3E%3D7.30-green) +![GitHub package.json version (subfolder of monorepo)](https://img.shields.io/github/package-json/v/codercup/unibest) +![GitHub License](https://img.shields.io/github/license/codercup/unibest) + +
+ +`unibest` 是一个 uniapp 跨端解决方案,由 `uniapp` + `Vue3` + `Ts` + `Vite4` + `UnoCss` + `VSCode`(可选 `webstorm`) 实现。它使用了最新的前端技术栈,可以通过命令行方式运行 `web`、`小程序` 和 `App`,同时也支持 `HBuilderX` 运行,当前版本为 `HBuilderX` 运行版本。如需通过命令行运行,请安装命令行版(unibest)。 + +`unibest` 内置了 `约定式路由`、`layout布局`、`请求封装`、`请求拦截`、`登录拦截`、`UnoCSS`、`i18n多语言` 等基础功能,提供了 `代码提示`、`自动格式化`、`统一配置`、`代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验 ( `unibest 的由来`)。 + +![](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png) + +

+ 📱 在线预览 + | + 📖 阅读文档 +

+ +## ✨ 特性 + +- ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [esbuild](https://github.com/evanw/esbuild) - 就是快! +- 🔥 最新语法 - ` diff --git a/components/fly-header/fly-header.vue b/components/fly-header/fly-header.vue new file mode 100644 index 0000000..9e34a4b --- /dev/null +++ b/components/fly-header/fly-header.vue @@ -0,0 +1,3 @@ + diff --git a/components/fly-login/README.md b/components/fly-login/README.md new file mode 100644 index 0000000..c931549 --- /dev/null +++ b/components/fly-login/README.md @@ -0,0 +1,7 @@ +# fly-login + +点击“点击显示微信头像”按钮后,出现的半屏登录弹窗,可以在任意页面引入。 + +仿“掘金小册”小程序。 + +![掘金小册登录](screenshot.png) diff --git a/components/fly-login/defaultAvatar.png b/components/fly-login/defaultAvatar.png new file mode 100644 index 0000000..e69596a Binary files /dev/null and b/components/fly-login/defaultAvatar.png differ diff --git a/components/fly-login/fly-login.vue b/components/fly-login/fly-login.vue new file mode 100644 index 0000000..8a6dc1f --- /dev/null +++ b/components/fly-login/fly-login.vue @@ -0,0 +1,120 @@ + + + + diff --git a/components/fly-login/screenshot.png b/components/fly-login/screenshot.png new file mode 100644 index 0000000..7ca7a26 Binary files /dev/null and b/components/fly-login/screenshot.png differ diff --git a/components/fly-navbar/README.md b/components/fly-navbar/README.md new file mode 100644 index 0000000..cd5cf97 --- /dev/null +++ b/components/fly-navbar/README.md @@ -0,0 +1,3 @@ +# fly-navbar + +建议本导航栏组件在设置 `"navigationStyle": "custom"` 的页面使用,目前支持微信小程序的页面滚动动画。 diff --git a/components/fly-navbar/fly-navbar.vue b/components/fly-navbar/fly-navbar.vue new file mode 100644 index 0000000..5636cb4 --- /dev/null +++ b/components/fly-navbar/fly-navbar.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..fa8c7d8 --- /dev/null +++ b/env.d.ts @@ -0,0 +1,21 @@ +/// +/// + +declare module '*.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 +} + +interface ImportMetaEnv { + readonly VITE_APP_TITLE: string + readonly VITE_SERVER_PORT: string + readonly VITE_SERVER_BASEURL: string + readonly VITE_DELETE_CONSOLE: string + // 更多环境变量... +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/env/.env b/env/.env new file mode 100644 index 0000000..d1bbf28 --- /dev/null +++ b/env/.env @@ -0,0 +1,18 @@ +VITE_APP_TITLE = 'unibest' +VITE_APP_PORT = 9000 + +# github actions 部署地址根路径,用在 manifest.config.ts 里面的 h5.router.base +VITE_APP_PUBLIC_BASE=/ + +# TODO: 记得修改 +VITE_UNI_APPID = 'H5871D791' +VITE_WX_APPID = 'wxa2abb91f64032a2b' + +# fallback lacale:en, zh-Hans, zh-Hant 等 +# 必须要在 lacale 文件夹中配置对应的 json 文件!!! +# 参考文档如下 +# https://uniapp.dcloud.net.cn/tutorial/i18n.html +# https://uniapp.dcloud.net.cn/api/ui/locale.html#onlocalechange 打开页面后最下面的注意事项 +VITE_FALLBACK_LOCALE = 'zh-Hans' + +VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run' diff --git a/env/.env.development b/env/.env.development new file mode 100644 index 0000000..dd0a1f2 --- /dev/null +++ b/env/.env.development @@ -0,0 +1,6 @@ +# 变量必须以 VITE_ 为前缀才能暴露给外部读取 +NODE_ENV = 'development' +# 是否去除console 和 debugger +VITE_DELETE_CONSOLE = false + +# VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run' diff --git a/env/.env.production b/env/.env.production new file mode 100644 index 0000000..94b3031 --- /dev/null +++ b/env/.env.production @@ -0,0 +1,6 @@ +# 变量必须以 VITE_ 为前缀才能暴露给外部读取 +NODE_ENV = 'development' +# 是否去除console 和 debugger +VITE_DELETE_CONSOLE = true + +# VITE_SERVER_BASEURL = 'https://xxx.com' diff --git a/env/.env.test b/env/.env.test new file mode 100644 index 0000000..a0dcad1 --- /dev/null +++ b/env/.env.test @@ -0,0 +1,6 @@ +# 变量必须以 VITE_ 为前缀才能暴露给外部读取 +NODE_ENV = 'development' +# 是否去除console 和 debugger +VITE_DELETE_CONSOLE = false + +# VITE_SERVER_BASEURL = 'https://xxx.com' diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..47c577c Binary files /dev/null and b/favicon.ico differ diff --git a/hooks/.gitkeep b/hooks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hooks/useNavbarWeixin.ts b/hooks/useNavbarWeixin.ts new file mode 100644 index 0000000..73e12da --- /dev/null +++ b/hooks/useNavbarWeixin.ts @@ -0,0 +1,62 @@ +import { onReady } from '@dcloudio/uni-app' +import { getIsTabbar, getArrElementByIdx } from '@/utils/index' + +export default () => { + // 获取页面栈 + const pages = getCurrentPages() + const isTabbar = getIsTabbar() + + // 页面滚动到底部时的操作,通常用于加载更多数据 + const onScrollToLower = () => {} + // 获取屏幕边界到安全区域距离 + const { safeAreaInsets } = uni.getSystemInfoSync() + + // #ifdef MP-WEIXIN + // 基于小程序的 Page 类型扩展 uni-app 的 Page + type PageInstance = Page.PageInstance & WechatMiniprogram.Page.InstanceMethods + // 获取当前页面实例,数组最后一项 + const pageInstance = getArrElementByIdx(getCurrentPages(), -1) as PageInstance + + // 页面渲染完毕,绑定动画效果 + onReady(() => { + // 动画效果,导航栏背景色 + pageInstance.animate( + '.fly-navbar', + [{ backgroundColor: 'transparent' }, { backgroundColor: '#f8f8f8' }], + 1000, + { + scrollSource: '#scroller', + timeRange: 1000, + startScrollOffset: 0, + endScrollOffset: 50, + }, + ) + // 动画效果,导航栏标题 + pageInstance.animate( + '.fly-navbar .title', + [{ color: 'transparent' }, { color: '#000' }], + 1000, + { + scrollSource: '#scroller', + timeRange: 1000, + startScrollOffset: 0, + endScrollOffset: 50, + }, + ) + // 动画效果,导航栏返回按钮 + pageInstance.animate('.fly-navbar .left-icon', [{ color: '#fff' }, { color: '#000' }], 1000, { + scrollSource: '#scroller', + timeRange: 1000, + startScrollOffset: 0, + endScrollOffset: 50, + }) + }) + // #endif + + return { + pages, + isTabbar, + onScrollToLower, + safeAreaInsets, + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..3a000ae --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/interceptors/index.ts b/interceptors/index.ts new file mode 100644 index 0000000..477545a --- /dev/null +++ b/interceptors/index.ts @@ -0,0 +1,2 @@ +export { routeInterceptor } from './route' +export { requestInterceptor } from './request' diff --git a/interceptors/request.ts b/interceptors/request.ts new file mode 100644 index 0000000..8e18f62 --- /dev/null +++ b/interceptors/request.ts @@ -0,0 +1,53 @@ +/* eslint-disable no-param-reassign */ +import qs from 'qs' +import { useUserStore } from '@/store' + +export type CustomRequestOptions = UniApp.RequestOptions & { + query?: Record +} & IUniUploadFileOptions // 添加uni.uploadFile参数类型 + +// 请求基地址 +const baseURL = import.meta.env.VITE_SERVER_BASEURL + +// 拦截器配置 +const httpInterceptor = { + // 拦截前触发 + invoke(options: CustomRequestOptions) { + // 接口请求支持通过 query 参数配置 queryString + if (options.query) { + const queryStr = qs.stringify(options.query) + if (options.url.includes('?')) { + options.url += `&${queryStr}` + } else { + options.url += `?${queryStr}` + } + } + + // 1. 非 http 开头需拼接地址 + if (!options.url.startsWith('http')) { + options.url = baseURL + options.url + } + // 2. 请求超时 + options.timeout = 10000 // 10s + // 3. 添加小程序端请求头标识 + options.header = { + platform: 'mp-weixin', // 可选值与 uniapp 定义的平台一致,告诉后台来源 + ...options.header, + } + // 4. 添加 token 请求头标识 + const userStore = useUserStore() + const { token } = userStore.userInfo as unknown as IUserInfo + if (token) { + options.header.Authorization = `Bearer ${token}` + } + }, +} + +export const requestInterceptor = { + install() { + // 拦截 request 请求 + uni.addInterceptor('request', httpInterceptor) + // 拦截 uploadFile 文件上传 + uni.addInterceptor('uploadFile', httpInterceptor) + }, +} diff --git a/interceptors/route.ts b/interceptors/route.ts new file mode 100644 index 0000000..e103bee --- /dev/null +++ b/interceptors/route.ts @@ -0,0 +1,54 @@ +/** + * by 菲鸽 on 2024-03-06 + * 路由拦截,通常也是登录拦截 + * 可以设置路由白名单,或者黑名单,看业务需要选哪一个 + * 我这里应为大部分都可以随便进入,所以使用黑名单 + */ +import { useUserStore } from '@/store' +import { getNeedLoginPages, needLoginPages as _needLoginPages } from '@/utils' + +// TODO Check +const loginRoute = '/pages/login/index' + +const isLogined = () => { + const userStore = useUserStore() + return userStore.isLogined +} + +const isDev = import.meta.env.DEV + +// 黑名单登录拦截器 - (适用于大部分页面不需要登录,少部分页面需要登录) +const navigateToInterceptor = { + // 注意,这里的url是 '/' 开头的,如 '/pages/index/index',跟 'pages.json' 里面的 path 不同 + invoke({ url }: { url: string }) { + console.log(url) // /pages/route-interceptor/index?name=feige&age=30 + const path = url.split('?')[0] + let needLoginPages: string[] = [] + // 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好 + if (isDev) { + needLoginPages = getNeedLoginPages() + } else { + needLoginPages = _needLoginPages + } + console.log(needLoginPages.includes(path)) + + if (needLoginPages.includes(path)) { + const isLogin = isLogined() + if (isLogin) { + return true + } + const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}` + uni.navigateTo({ url: redirectRoute }) + return false + } + return true + }, +} + +export const routeInterceptor = { + install() { + uni.addInterceptor('navigateTo', navigateToInterceptor) + uni.addInterceptor('reLaunch', navigateToInterceptor) + uni.addInterceptor('redirectTo', navigateToInterceptor) + }, +} diff --git a/layouts/default.vue b/layouts/default.vue new file mode 100644 index 0000000..2e4a040 --- /dev/null +++ b/layouts/default.vue @@ -0,0 +1,12 @@ + + + diff --git a/layouts/demo.vue b/layouts/demo.vue new file mode 100644 index 0000000..2de39ab --- /dev/null +++ b/layouts/demo.vue @@ -0,0 +1,5 @@ + diff --git a/main.js b/main.js new file mode 100644 index 0000000..b057799 --- /dev/null +++ b/main.js @@ -0,0 +1,15 @@ +import { createSSRApp } from 'vue' +import App from './App.vue' +import store from './store' +import { routeInterceptor, requestInterceptor } from './interceptors' +import 'virtual:uno.css' + +export function createApp() { + const app = createSSRApp(App) + app.use(store) + app.use(routeInterceptor) + app.use(requestInterceptor) + return { + app, + } +} diff --git a/manifest.config.ts b/manifest.config.ts new file mode 100644 index 0000000..25af925 --- /dev/null +++ b/manifest.config.ts @@ -0,0 +1,103 @@ +// manifest.config.ts +import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest' +import path from 'node:path' +import { loadEnv } from 'vite' + +// 获取环境变量的范例 +const env = loadEnv(process.env.NODE_ENV!, path.resolve(process.env.VITE_ROOT_DIR, 'env')) +// console.log(env) +const { + VITE_APP_TITLE, + VITE_UNI_APPID, + VITE_WX_APPID, + VITE_APP_PUBLIC_BASE, + VITE_FALLBACK_LOCALE, +} = 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: { + router: { + base: VITE_APP_PUBLIC_BASE, + }, + }, + /* 5+App特有相关 */ + 'app-plus': { + usingComponents: true, + nvueStyleCompiler: 'uni-app', + compilerVersion: 3, + splashscreen: { + alwaysShowBeforeRender: true, + waiting: true, + autoclose: true, + delay: 0, + }, + /* 模块配置 */ + modules: {}, + /* 应用发布信息 */ + distribute: { + /* android打包配置 */ + android: { + minSdkVersion: 30, + targetSdkVersion: 30, + abiFilters: ['armeabi-v7a', 'arm64-v8a'], + permissions: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], + }, + /* ios打包配置 */ + ios: {}, + /* SDK配置 */ + sdkConfigs: {}, + /* 图标配置 */ + icons: { + android: {}, + ios: {}, + }, + }, + }, + /* 快应用特有相关 */ + quickapp: {}, + /* 小程序特有相关 */ + 'mp-weixin': { + appid: VITE_WX_APPID, + setting: { + urlCheck: false, + }, + usingComponents: true, + // __usePrivacyCheck__: true, + }, + 'mp-alipay': { + usingComponents: true, + }, + 'mp-baidu': { + usingComponents: true, + }, + 'mp-toutiao': { + usingComponents: true, + }, + uniStatistics: { + enable: false, + }, + vueVersion: '3', +}) diff --git a/package.json b/package.json new file mode 100644 index 0000000..c2cdf19 --- /dev/null +++ b/package.json @@ -0,0 +1,97 @@ +{ + "name": "my-project", + "version": "0.2.0", + "description": "unibest - 最好的 uniapp 开发模板, HBX 版本", + "main": "main.js", + "author": { + "name": "codercup", + "zhName": "菲鸽", + "email": "1020103647@qq.com", + "github": "https://github.com/codercup", + "gitee": "https://gitee.com/codercup" + }, + "license": "MIT", + "repository": "https://github.com/codercup/unibest-hbx", + "repository-gitee": "https://gitee.com/codercup/unibest-hbx", + "bugs": { + "url": "https://github.com/codercup/unibest-hbx/issues" + }, + "homepage": "https://codercup.github.io/unibest-hbx/", + "engines": { + "node": ">=18", + "pnpm": ">=7.30" + }, + "scripts": { + "prepare": "node ./shell/postinstall.js & git init && husky install" + }, + "lint-staged": { + "**/*.{html,vue,ts,cjs,json,md}": [ + "prettier --write" + ], + "**/*.{vue,js,ts,jsx,tsx}": [ + "eslint --fix" + ], + "**/*.{vue,css,scss,html}": [ + "stylelint --fix" + ] + }, + "resolutions": { + "bin-wrapper": "npm:bin-wrapper-china" + }, + "dependencies": { + "dayjs": "^1.11.11", + "pinia": "2.0.36", + "pinia-plugin-persistedstate": "^3.2.1", + "qs": "6.5.3", + "vue": "3.4.21", + "wot-design-uni": "^1.2.20" + }, + "devDependencies": { + "@commitlint/cli": "^19.3.0", + "@commitlint/config-conventional": "^19.2.2", + "@dcloudio/types": "^3.4.8", + "@dcloudio/vite-plugin-uni": "3.0.0-4010520240507001", + "@iconify-json/carbon": "^1.1.33", + "@types/node": "^20.12.12", + "@types/wechat-miniprogram": "^3.4.7", + "@typescript-eslint/eslint-plugin": "^7.9.0", + "@typescript-eslint/parser": "^7.9.0", + "@uni-helper/uni-app-types": "^0.5.13", + "@uni-helper/uni-ui-types": "^0.5.14", + "@uni-helper/vite-plugin-uni-layouts": "^0.1.8", + "@uni-helper/vite-plugin-uni-manifest": "^0.2.6", + "@uni-helper/vite-plugin-uni-pages": "^0.2.20", + "@uni-helper/vite-plugin-uni-platform": "^0.0.4", + "@unocss/preset-legacy-compat": "^0.59.4", + "@vitejs/plugin-vue": "^5.0.4", + "autoprefixer": "^10.4.19", + "commitlint": "^19.3.0", + "esbuild": "0.20.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-vue": "^9.26.0", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "postcss": "^8.4.38", + "postcss-html": "^1.7.0", + "postcss-scss": "^4.0.9", + "sass": "^1.77.2", + "stylelint": "^16.5.0", + "stylelint-config-html": "^1.1.0", + "stylelint-config-recess-order": "^5.0.1", + "stylelint-config-recommended": "^14.0.0", + "stylelint-config-recommended-scss": "^14.0.0", + "stylelint-config-recommended-vue": "^1.5.0", + "stylelint-prettier": "^5.0.0", + "terser": "^5.31.0", + "unocss": "^0.58.9", + "unocss-applet": "^0.7.8", + "unplugin-auto-import": "^0.17.6", + "vite": "5.2.8", + "vite-plugin-restart": "^0.4.0" + } +} \ No newline at end of file diff --git a/pages-sub/demo.vue b/pages-sub/demo.vue new file mode 100644 index 0000000..6126ddc --- /dev/null +++ b/pages-sub/demo.vue @@ -0,0 +1,20 @@ + +{ + style: { navigationBarTitleText: '分包页面 标题' }, +} + + + + + + + diff --git a/pages.config.ts b/pages.config.ts new file mode 100644 index 0000000..32c8bf9 --- /dev/null +++ b/pages.config.ts @@ -0,0 +1,45 @@ +import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages' + +export default defineUniPages({ + globalStyle: { + navigationStyle: 'default', + navigationBarTitleText: 'unibest', + navigationBarBackgroundColor: '#f8f8f8', + navigationBarTextStyle: 'black', + backgroundColor: '#FFFFFF', + h5: { + navigationStyle: 'custom', + }, + }, + easycom: { + autoscan: true, + custom: { + '^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue', + '^layout-(.*)-uni': '@/layouts/$1.vue', + }, + }, + tabBar: { + color: '#999999', + selectedColor: '#018d71', + backgroundColor: '#F8F8F8', + borderStyle: 'black', + height: '50px', + fontSize: '10px', + iconWidth: '24px', + spacing: '3px', + list: [ + { + iconPath: 'static/tabbar/home.png', + selectedIconPath: 'static/tabbar/homeHL.png', + pagePath: 'pages/index/index', + text: '首页', + }, + { + iconPath: 'static/tabbar/example.png', + selectedIconPath: 'static/tabbar/exampleHL.png', + pagePath: 'pages/index/about', + text: '关于', + }, + ], + }, +}) diff --git a/pages/index/about.vue b/pages/index/about.vue new file mode 100644 index 0000000..038ca88 --- /dev/null +++ b/pages/index/about.vue @@ -0,0 +1,37 @@ + +{ + layout: 'default', + style: { + navigationBarTitleText: '关于', + }, +} + + + + + + + diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..ca27cdf --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,75 @@ + + +{ + style: { + navigationStyle: 'custom', + navigationBarTitleText: '首页', + }, +} + + + + + + diff --git a/service/foo.d.ts b/service/foo.d.ts new file mode 100644 index 0000000..81bc41a --- /dev/null +++ b/service/foo.d.ts @@ -0,0 +1,4 @@ +export interface IFooItem { + id: string + name: string +} diff --git a/service/foo.ts b/service/foo.ts new file mode 100644 index 0000000..57cf584 --- /dev/null +++ b/service/foo.ts @@ -0,0 +1,32 @@ +import { http, uniFileUpload } from '@/utils/http' +import type { IFooItem } from './foo.d' + +export { IFooItem } + +/** get 请求 */ +export const getFooAPI = (name: string) => { + return http({ + url: `/foo`, + method: 'GET', + query: { name }, + }) +} + +/** get 请求 */ +export const postFooAPI = (name: string) => { + return http({ + url: `/foo`, + method: 'POST', + query: { name }, // post 请求也支持 query + data: { name }, + }) +} + +// 文件上传 +export const fileUpload = (data: IUniUploadFileOptions) => { + return uniFileUpload({ + url: `/foo/upload`, + method: 'POST', + ...data, + }) +} diff --git a/shell/postinstall.js b/shell/postinstall.js new file mode 100644 index 0000000..0aba101 --- /dev/null +++ b/shell/postinstall.js @@ -0,0 +1,47 @@ +/** + * 本文件会在依赖包安装时执行,用以生成 `src/manifest.json` + * 如果不存在 `src/manifest.json` 会运行报错,提示找不到 `src/manifest.json` + * 如果中途自己删除了 'src/manifest.json' 文件,记得手动执行本文件,可以右键 `Run Code` 快速执行 + * + * 本文件是为了兼容 window 系统才生成的 + */ + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const fs = require('fs') + +const filePath = './manifest.json' + +if (fs.existsSync(filePath)) { + // console.log(`${filePath}存在`) +} else { + // console.log(`${filePath}不存在,需要创建`) + fs.writeFile(filePath, '{"vueVersion": "3"}\n', {}, () => { + // console.log(`${filePath}已经成功创建,并写入{}`) + }) +} + +const filePath2 = './pages.json' +if (fs.existsSync(filePath2)) { + // console.log(`${filePath}存在`) +} else { + // console.log(`${filePath}不存在,需要创建`) + fs.writeFile( + filePath2, + `{ + "pages": [ + { + "path": "pages/index/index", + "type": "home", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "首页" + } + } + ] +}\n`, + {}, + () => { + // console.log(`${filePath}已经成功创建,并写入{}`) + }, + ) +} diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..b5771e2 Binary files /dev/null and b/static/logo.png differ diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 0000000..eaee669 --- /dev/null +++ b/static/logo.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + diff --git a/static/tabbar/example.png b/static/tabbar/example.png new file mode 100644 index 0000000..fd1e942 Binary files /dev/null and b/static/tabbar/example.png differ diff --git a/static/tabbar/exampleHL.png b/static/tabbar/exampleHL.png new file mode 100644 index 0000000..7501011 Binary files /dev/null and b/static/tabbar/exampleHL.png differ diff --git a/static/tabbar/home.png b/static/tabbar/home.png new file mode 100644 index 0000000..8f82e21 Binary files /dev/null and b/static/tabbar/home.png differ diff --git a/static/tabbar/homeHL.png b/static/tabbar/homeHL.png new file mode 100644 index 0000000..26d3761 Binary files /dev/null and b/static/tabbar/homeHL.png differ diff --git a/static/tabbar/personal.png b/static/tabbar/personal.png new file mode 100644 index 0000000..0a569a2 Binary files /dev/null and b/static/tabbar/personal.png differ diff --git a/static/tabbar/personalHL.png b/static/tabbar/personalHL.png new file mode 100644 index 0000000..8c3e66e Binary files /dev/null and b/static/tabbar/personalHL.png differ diff --git a/store/count.ts b/store/count.ts new file mode 100644 index 0000000..946ccd7 --- /dev/null +++ b/store/count.ts @@ -0,0 +1,28 @@ +// src/store/useCountStore.ts +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useCountStore = defineStore( + 'count', + () => { + const count = ref(0) + const increment = () => { + count.value++ + } + const decrement = () => { + count.value-- + } + const reset = () => { + count.value = 0 + } + return { + count, + decrement, + increment, + reset, + } + }, + { + persist: true, + }, +) diff --git a/store/index.ts b/store/index.ts new file mode 100644 index 0000000..93bd4d4 --- /dev/null +++ b/store/index.ts @@ -0,0 +1,18 @@ +import { createPinia } from 'pinia' +import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化 + +const store = createPinia() +store.use( + createPersistedState({ + storage: { + getItem: uni.getStorageSync, + setItem: uni.setStorageSync, + }, + }), +) + +export default store + +// 模块统一导出 +export * from './user' +export * from './count' diff --git a/store/user.ts b/store/user.ts new file mode 100644 index 0000000..a94351c --- /dev/null +++ b/store/user.ts @@ -0,0 +1,34 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' + +const initState = { nickname: '', avatar: '' } + +export const useUserStore = defineStore( + 'user', + () => { + const userInfo = ref({ ...initState }) + + const setUserInfo = (val: IUserInfo) => { + userInfo.value = val + } + + const clearUserInfo = () => { + userInfo.value = { ...initState } + } + const reset = () => { + userInfo.value = { ...initState } + } + const isLogined = computed(() => !!userInfo.value.token) + + return { + userInfo, + setUserInfo, + clearUserInfo, + isLogined, + reset, + } + }, + { + persist: true, + }, +) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9f7f9bc --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,41 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "noImplicitThis": true, + "allowSyntheticDefaultImports": true, + "allowJs": true, + "sourceMap": true, + "baseUrl": ".", + "paths": { + "@/*": ["./*"] + }, + "outDir": "dist", + "lib": ["esnext", "dom"], + "types": [ + "@dcloudio/types", + "@types/wechat-miniprogram", + "@uni-helper/uni-app-types", + "@uni-helper/uni-ui-types", + "wot-design-uni/global.d.ts" + ] + }, + "vueCompilerOptions": { + "target": 3, + "nativeTags": ["block", "template", "component", "slot"] + }, + "exclude": ["node_modules"], + "include": [ + "./**/*.ts", + "./**/*.js", + "./**/*.d.ts", + "./**/*.tsx", + "./**/*.jsx", + "./**/*.vue", + "./**/*.json", + "main.js" + ] +} diff --git a/types/auto-import.d.ts b/types/auto-import.d.ts new file mode 100644 index 0000000..f5405c5 --- /dev/null +++ b/types/auto-import.d.ts @@ -0,0 +1,257 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const effectScope: typeof import('vue')['effectScope'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites'] + const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onError: typeof import('@dcloudio/uni-app')['onError'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onHide: typeof import('@dcloudio/uni-app')['onHide'] + const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch'] + const onLoad: typeof import('@dcloudio/uni-app')['onLoad'] + const onMounted: typeof import('vue')['onMounted'] + const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap'] + const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged'] + const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked'] + const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed'] + const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged'] + const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound'] + const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll'] + const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh'] + const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom'] + const onReady: typeof import('@dcloudio/uni-app')['onReady'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onResize: typeof import('@dcloudio/uni-app')['onResize'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage'] + const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline'] + const onShow: typeof import('@dcloudio/uni-app')['onShow'] + const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap'] + const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange'] + const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection'] + const onUnload: typeof import('@dcloudio/uni-app')['onUnload'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useNavbarWeixin: typeof import('../hooks/useNavbarWeixin')['default'] + const useSlots: typeof import('vue')['useSlots'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue' + import('vue') +} +// for vue template auto import +import { UnwrapRef } from 'vue' +declare module 'vue' { + interface GlobalComponents {} + interface ComponentCustomProperties { + readonly EffectScope: UnwrapRef + readonly computed: UnwrapRef + readonly createApp: UnwrapRef + readonly customRef: UnwrapRef + readonly defineAsyncComponent: UnwrapRef + readonly defineComponent: UnwrapRef + readonly effectScope: UnwrapRef + readonly getCurrentInstance: UnwrapRef + readonly getCurrentScope: UnwrapRef + readonly h: UnwrapRef + readonly inject: UnwrapRef + readonly isProxy: UnwrapRef + readonly isReactive: UnwrapRef + readonly isReadonly: UnwrapRef + readonly isRef: UnwrapRef + readonly markRaw: UnwrapRef + readonly nextTick: UnwrapRef + readonly onActivated: UnwrapRef + readonly onAddToFavorites: UnwrapRef + readonly onBackPress: UnwrapRef + readonly onBeforeMount: UnwrapRef + readonly onBeforeUnmount: UnwrapRef + readonly onBeforeUpdate: UnwrapRef + readonly onDeactivated: UnwrapRef + readonly onError: UnwrapRef + readonly onErrorCaptured: UnwrapRef + readonly onHide: UnwrapRef + readonly onLaunch: UnwrapRef + readonly onLoad: UnwrapRef + readonly onMounted: UnwrapRef + readonly onNavigationBarButtonTap: UnwrapRef + readonly onNavigationBarSearchInputChanged: UnwrapRef + readonly onNavigationBarSearchInputClicked: UnwrapRef + readonly onNavigationBarSearchInputConfirmed: UnwrapRef + readonly onNavigationBarSearchInputFocusChanged: UnwrapRef + readonly onPageNotFound: UnwrapRef + readonly onPageScroll: UnwrapRef + readonly onPullDownRefresh: UnwrapRef + readonly onReachBottom: UnwrapRef + readonly onReady: UnwrapRef + readonly onRenderTracked: UnwrapRef + readonly onRenderTriggered: UnwrapRef + readonly onResize: UnwrapRef + readonly onScopeDispose: UnwrapRef + readonly onServerPrefetch: UnwrapRef + readonly onShareAppMessage: UnwrapRef + readonly onShareTimeline: UnwrapRef + readonly onShow: UnwrapRef + readonly onTabItemTap: UnwrapRef + readonly onThemeChange: UnwrapRef + readonly onUnhandledRejection: UnwrapRef + readonly onUnload: UnwrapRef + readonly onUnmounted: UnwrapRef + readonly onUpdated: UnwrapRef + readonly provide: UnwrapRef + readonly reactive: UnwrapRef + readonly readonly: UnwrapRef + readonly ref: UnwrapRef + readonly resolveComponent: UnwrapRef + readonly shallowReactive: UnwrapRef + readonly shallowReadonly: UnwrapRef + readonly shallowRef: UnwrapRef + readonly toRaw: UnwrapRef + readonly toRef: UnwrapRef + readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef + readonly triggerRef: UnwrapRef + readonly unref: UnwrapRef + readonly useAttrs: UnwrapRef + readonly useCssModule: UnwrapRef + readonly useCssVars: UnwrapRef + readonly useNavbarWeixin: UnwrapRef + readonly useSlots: UnwrapRef + readonly watch: UnwrapRef + readonly watchEffect: UnwrapRef + readonly watchPostEffect: UnwrapRef + readonly watchSyncEffect: UnwrapRef + } +} +declare module '@vue/runtime-core' { + interface GlobalComponents {} + interface ComponentCustomProperties { + readonly EffectScope: UnwrapRef + readonly computed: UnwrapRef + readonly createApp: UnwrapRef + readonly customRef: UnwrapRef + readonly defineAsyncComponent: UnwrapRef + readonly defineComponent: UnwrapRef + readonly effectScope: UnwrapRef + readonly getCurrentInstance: UnwrapRef + readonly getCurrentScope: UnwrapRef + readonly h: UnwrapRef + readonly inject: UnwrapRef + readonly isProxy: UnwrapRef + readonly isReactive: UnwrapRef + readonly isReadonly: UnwrapRef + readonly isRef: UnwrapRef + readonly markRaw: UnwrapRef + readonly nextTick: UnwrapRef + readonly onActivated: UnwrapRef + readonly onAddToFavorites: UnwrapRef + readonly onBackPress: UnwrapRef + readonly onBeforeMount: UnwrapRef + readonly onBeforeUnmount: UnwrapRef + readonly onBeforeUpdate: UnwrapRef + readonly onDeactivated: UnwrapRef + readonly onError: UnwrapRef + readonly onErrorCaptured: UnwrapRef + readonly onHide: UnwrapRef + readonly onLaunch: UnwrapRef + readonly onLoad: UnwrapRef + readonly onMounted: UnwrapRef + readonly onNavigationBarButtonTap: UnwrapRef + readonly onNavigationBarSearchInputChanged: UnwrapRef + readonly onNavigationBarSearchInputClicked: UnwrapRef + readonly onNavigationBarSearchInputConfirmed: UnwrapRef + readonly onNavigationBarSearchInputFocusChanged: UnwrapRef + readonly onPageNotFound: UnwrapRef + readonly onPageScroll: UnwrapRef + readonly onPullDownRefresh: UnwrapRef + readonly onReachBottom: UnwrapRef + readonly onReady: UnwrapRef + readonly onRenderTracked: UnwrapRef + readonly onRenderTriggered: UnwrapRef + readonly onResize: UnwrapRef + readonly onScopeDispose: UnwrapRef + readonly onServerPrefetch: UnwrapRef + readonly onShareAppMessage: UnwrapRef + readonly onShareTimeline: UnwrapRef + readonly onShow: UnwrapRef + readonly onTabItemTap: UnwrapRef + readonly onThemeChange: UnwrapRef + readonly onUnhandledRejection: UnwrapRef + readonly onUnload: UnwrapRef + readonly onUnmounted: UnwrapRef + readonly onUpdated: UnwrapRef + readonly provide: UnwrapRef + readonly reactive: UnwrapRef + readonly readonly: UnwrapRef + readonly ref: UnwrapRef + readonly resolveComponent: UnwrapRef + readonly shallowReactive: UnwrapRef + readonly shallowReadonly: UnwrapRef + readonly shallowRef: UnwrapRef + readonly toRaw: UnwrapRef + readonly toRef: UnwrapRef + readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef + readonly triggerRef: UnwrapRef + readonly unref: UnwrapRef + readonly useAttrs: UnwrapRef + readonly useCssModule: UnwrapRef + readonly useCssVars: UnwrapRef + readonly useNavbarWeixin: UnwrapRef + readonly useSlots: UnwrapRef + readonly watch: UnwrapRef + readonly watchEffect: UnwrapRef + readonly watchPostEffect: UnwrapRef + readonly watchSyncEffect: UnwrapRef + } +} diff --git a/typing.ts b/typing.ts new file mode 100644 index 0000000..c0cb8ee --- /dev/null +++ b/typing.ts @@ -0,0 +1,31 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +// 全局要用的类型放到这里 + +type IResData = { + code: number + msg: string + result: T +} + +// uni.uploadFile文件上传参数 +type IUniUploadFileOptions = { + file?: File + files?: UniApp.UploadFileOptionFiles[] + filePath?: string + name?: string + formData?: any +} + +type IUserInfo = { + nickname?: string + avatar?: string + /** 微信的 openid,非微信没有这个字段 */ + openid?: string + token?: string +} + +enum TestEnum { + A = 'a', + B = 'b', +} diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..6c5bb60 --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color: #333; //基本色 +$uni-text-color-inverse: #fff; //反色 +$uni-text-color-grey: #999; //辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable: #c0c0c0; + +/* 背景颜色 */ +$uni-bg-color: #ffffff; +$uni-bg-color-grey: #f8f8f8; +$uni-bg-color-hover: #f1f1f1; //点击状态颜色 +$uni-bg-color-mask: rgba(0, 0, 0, 0.4); //遮罩颜色 + +/* 边框颜色 */ +$uni-border-color: #c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm: 12px; +$uni-font-size-base: 14px; +$uni-font-size-lg: 16px; + +/* 图片尺寸 */ +$uni-img-size-sm: 20px; +$uni-img-size-base: 26px; +$uni-img-size-lg: 40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2c405a; // 文章标题颜色 +$uni-font-size-title: 20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle: 26px; +$uni-color-paragraph: #3f536e; // 文章段落颜色 +$uni-font-size-paragraph: 15px; diff --git a/uno.config.ts b/uno.config.ts new file mode 100644 index 0000000..0fc1288 --- /dev/null +++ b/uno.config.ts @@ -0,0 +1,96 @@ +// uno.config.ts +import { + type Preset, + defineConfig, + presetUno, + presetAttributify, + presetIcons, + transformerDirectives, + transformerVariantGroup, +} from 'unocss' + +import { presetApplet, presetRemRpx, transformerAttributify } from 'unocss-applet' + +// @see https://unocss.dev/presets/legacy-compat +import { presetLegacyCompat } from '@unocss/preset-legacy-compat' + +const isMp = process.env?.UNI_PLATFORM?.startsWith('mp') ?? false + +const presets: Preset[] = [] +if (isMp) { + // 使用小程序预设 + presets.push(presetApplet(), presetRemRpx()) +} else { + presets.push( + // 非小程序用官方预设 + presetUno(), + // 支持css class属性化 + presetAttributify(), + ) +} +export default defineConfig({ + presets: [ + ...presets, + // 支持图标,需要搭配图标库,eg: @iconify-json/carbon, 使用 `