├── .editorconfig
├── .env
├── .eslintignore
├── .eslintrc.cjs
├── .gitignore
├── .husky
└── commit-msg
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.mjs
├── .stylelintignore
├── .stylelintrc.mjs
├── .vscode
├── extensions.json
└── settings.json
├── LICENSE
├── README.md
├── manifest.config.ts
├── package.json
├── pages.config.ts
├── pnpm-lock.yaml
├── src
├── App.vue
├── apis
│ ├── index.ts
│ ├── interceptors
│ │ ├── index.ts
│ │ └── response.ts
│ ├── modules
│ │ ├── activity.ts
│ │ ├── index.ts
│ │ └── userInfo.ts
│ └── request
│ │ ├── index.ts
│ │ └── log.ts
├── components
│ ├── AvatarNickname.vue
│ ├── Cell.vue
│ ├── FooterActionsBar.vue
│ ├── FormControl.vue
│ ├── LabelValueBar.vue
│ ├── List.vue
│ ├── SwiperPro.vue
│ ├── TabsPaneList.vue
│ ├── TitleBar.vue
│ ├── Uploader.vue
│ ├── auth
│ │ ├── AuthAvatarButton.vue
│ │ ├── AuthAvatarNicknameDialog.vue
│ │ ├── AuthPhoneNumberButton.vue
│ │ ├── NickNameInput.vue
│ │ └── index.ts
│ ├── dialog
│ │ ├── Dialog.vue
│ │ ├── FormDialog.vue
│ │ └── index.ts
│ ├── index.ts
│ ├── layout
│ │ ├── Layout.vue
│ │ ├── NavBar.vue
│ │ ├── TabBar.vue
│ │ └── index.ts
│ ├── picker
│ │ ├── DateTimePicker.vue
│ │ ├── Picker.vue
│ │ ├── index.ts
│ │ └── type.ts
│ ├── popup
│ │ ├── Popup.vue
│ │ └── index.ts
│ ├── provideComponentOptions.ts
│ └── u-charts
│ │ ├── config-ucharts.js
│ │ ├── u-charts.js
│ │ └── u-charts.vue
├── constants
│ ├── index.ts
│ └── userInfo.ts
├── hooks
│ ├── index.ts
│ ├── pagination
│ │ ├── index.ts
│ │ ├── useListPagination.ts
│ │ └── usePagination.ts
│ ├── share
│ │ └── index.ts
│ └── timer
│ │ └── index.ts
├── main.ts
├── manifest.json
├── pages.json
├── pages
│ ├── home.vue
│ ├── launch.vue
│ ├── list.vue
│ ├── login.vue
│ ├── my.vue
│ └── test.vue
├── routerInterceptor
│ ├── index.ts
│ └── login.ts
├── static
│ └── image
│ │ ├── List
│ │ ├── back-top.png
│ │ └── empty.png
│ │ ├── layout
│ │ └── TabBar
│ │ │ ├── icon1-off.png
│ │ │ ├── icon1-on.png
│ │ │ ├── icon2-off.png
│ │ │ └── icon2-on.png
│ │ ├── mp_wx.svg
│ │ ├── popup
│ │ └── Popup
│ │ │ └── close.png
│ │ ├── share.jpg
│ │ └── uniapp.ico
├── stores
│ ├── activity.ts
│ ├── index.ts
│ ├── tabBar.ts
│ └── userInfo.ts
├── styles
│ ├── funs
│ │ └── index.scss
│ ├── index.scss
│ ├── mixins
│ │ └── index.scss
│ └── variable
│ │ ├── custom.scss
│ │ └── uni.scss
├── subPackages
│ └── webview
│ │ └── pages
│ │ └── webview.vue
├── types
│ ├── authorize.ts
│ ├── dts
│ │ ├── api.d.ts
│ │ ├── components.d.ts
│ │ ├── index.d.ts
│ │ └── pages.d.ts
│ ├── index.ts
│ └── userInfo.ts
└── utils
│ ├── data
│ └── index.ts
│ ├── dateTime
│ └── index.ts
│ ├── env
│ └── index.ts
│ ├── form
│ ├── identityCard.ts
│ └── index.ts
│ ├── index.ts
│ ├── location
│ └── index.ts
│ ├── media
│ └── index.ts
│ ├── miniProgram
│ └── index.ts
│ ├── pages
│ ├── index.ts
│ └── navigate.ts
│ ├── tool
│ └── index.ts
│ ├── url
│ └── index.ts
│ └── userInfo
│ └── index.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
├── types
├── env.d.ts
└── index.d.ts
├── vite.config.ts
└── vite
└── utils.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org 为了兼容不同的编辑器
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 4
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | # 组件目录 默认:components
2 | VITE_COMPONENT_DIR = components
3 |
4 | # 页面目录 默认:pages
5 | VITE_PAGE_DIR = pages
6 |
7 | # `src`下 分包目录 默认:subPackages
8 | VITE_SUB_PACKAGE_DIR = subPackages
9 |
10 | # `VITE_SUB_PACKAGE_DIR`下 分包子目录集合 如果涉及多个子分包,用逗号分隔 默认:webview
11 | VITE_SUB_PACKAGE_CHILD_DIRS = webview
12 |
13 | # 启动页路径 默认:pages/launch
14 | VITE_LAUNCH_PATH = ${VITE_PAGE_DIR}/launch
15 |
16 | # 是否使用启动页 默认:false
17 | # 可以在小程序运行时控制首次显示的页面,使用时注意:
18 | # 1.小程序首页变为`VITE_LAUNCH_PATH`,页面跳转逻辑将在 `launch.vue` 中的 `onLoad` 进行,可根据需求修改
19 | # 2.小程序码路径示例: 目标页面为`a`页面,则路径应该为 `/pages/launch?targetPath=pages/a&test=1`,其中`test=1`会传递给`a`页面
20 | VITE_USE_LAUNCH_PAGE = false
21 |
22 | # 登录页面的路径 默认:pages/login
23 | VITE_LOGIN_PATH = ${VITE_PAGE_DIR}/login
24 |
25 | # 首页路径 默认:pages/home
26 | VITE_HOME_PATH = ${VITE_PAGE_DIR}/home
27 |
28 | # TODO: wx小程序appid
29 | VITE_MP_WX_APPID =
30 |
31 | # 开发环境服务器网址(小程序开发版、体验版用到) 默认:http://xxx.com
32 | VITE_DEV_SERVER_URL = http://jsonplaceholder.typicode.com
33 |
34 | # 生产环境服务器网址(小程序体验版、线上版用到) 默认:http://xxx.com
35 | VITE_PROD_SERVER_URL = http://jsonplaceholder.typicode.com
36 |
37 | # 接口请求基础路径 默认:/api
38 | VITE_API_BASE_PATH = /posts
39 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # 编辑目录和文件
2 | .idea
3 | .DS_Store
4 | .hbuilderx
5 | coverage
6 | *.suo
7 | *.ntvs*
8 | *.njsproj
9 | *.sln
10 | *.sw
11 | *.local
12 |
13 | # Logs文件
14 | logs
15 | *.log*
16 |
17 | # 项目文件
18 | dist
19 | node_modules
20 | src/components/u-charts
21 | src/static/
22 | src/manifest.json
23 | src/pages.json
24 | .*
25 | *-lock.*
26 |
27 | # 不忽略的项目文件
28 | !.vscode
29 | !.prettierrc*
30 | !.stylelintrc*
31 | !.eslintrc*
32 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-07-30 22:17:34
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-07 21:11:19
6 | * @FilePath: /uniapp-mp-wx-template/.eslintrc.cjs
7 | * @Description: eslint配置文件 注意:每次配置文件的更改,建议重启一下vscode,否则可能不会生效
8 | */
9 |
10 | module.exports = {
11 | extends: ["@dyb-dev/eslint-config"]
12 | }
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # 编辑目录和文件
2 | .idea
3 | .DS_Store
4 | coverage
5 | *.suo
6 | *.ntvs*
7 | *.njsproj
8 | *.sln
9 | *.sw?
10 | *.local
11 |
12 | # Logs
13 | logs
14 | *.log*
15 |
16 | # 忽略项目文件
17 | .history
18 | dist
19 | node_modules
20 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | # Git提交时自动效验提交信息
2 | project-cli commit-lint $1
3 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # 默认走淘宝镜像
2 | registry = https://registry.npmmirror.com
3 |
4 | # 私服npm用到,携带@xxx前缀的包名会走http://xxx.com:8080
5 | # @dyb-dev:registry = https://registry.npmjs.org/
6 |
7 | # 将所有的依赖提升到项目的根目录下,解决 @dcloudio/vite-plugin-uni 插件找不到依赖的问题
8 | shamefully-hoist = true
9 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/iron
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # 编辑目录和文件
2 | .idea
3 | .DS_Store
4 | coverage
5 | *.suo
6 | *.ntvs*
7 | *.njsproj
8 | *.sln
9 | *.sw?
10 | *.local
11 |
12 | # Logs
13 | logs
14 | *.log*
15 |
16 | # 忽略项目文件
17 | dist
18 | node_modules
19 | src/static/
20 | src/manifest.json
21 | src/pages.json
22 | .*
23 | *-lock.*
24 |
25 | # 不忽略的项目文件
26 | !.vscode
27 | !.prettierrc*
28 | !.stylelintrc*
29 | !.eslintrc*
30 |
--------------------------------------------------------------------------------
/.prettierrc.mjs:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-02-27 21:21:41
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-08-30 16:47:06
6 | * @FilePath: /vue_pinia_vite/.prettierrc.mjs
7 | * @Description: prettier配置文件 注意:每次配置文件的更改,建议重启一下vscode,否则可能不会生效
8 | */
9 |
10 | import prettierConfig from "@dyb-dev/prettier-config"
11 | export default prettierConfig
12 |
--------------------------------------------------------------------------------
/.stylelintignore:
--------------------------------------------------------------------------------
1 | # 编辑目录和文件
2 | .idea
3 | .DS_Store
4 | coverage
5 | *.suo
6 | *.ntvs*
7 | *.njsproj
8 | *.sln
9 | *.sw?
10 | *.local
11 |
12 | # Logs
13 | logs
14 | *.log*
15 |
16 | # 忽略的项目文件
17 | dist
18 | node_modules
19 | src/static/
20 | types
21 | .*
22 | *-lock.*
23 | *.json
24 | *.yaml
25 | *.md
26 | *.ts
27 | *.d.ts
28 | *.*js
29 |
--------------------------------------------------------------------------------
/.stylelintrc.mjs:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-03-20 16:17:30
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-10 20:13:41
6 | * @FilePath: /uniapp-mp-wx-template/.stylelintrc.mjs
7 | * @Description: stylelint配置文件 注意:每次配置文件的更改,建议重启一下vscode,否则可能不会生效
8 | */
9 |
10 | export default {
11 | extends: ["@dyb-dev/stylelint-config"],
12 | rules: {
13 | // 忽略 `rpx` 单位的报错
14 | "unit-no-unknown": [true, { ignoreUnits: ["rpx"] }],
15 | // 忽略 `rpx` 单位的报错
16 | "declaration-property-value-no-unknown": null
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | // VS Code 会检查当前项目的根目录下是否存在 extensions.json 文件,并根据其中的推荐插件列表向你展示相应的推荐安装提示
2 |
3 | {
4 | "recommendations": [
5 | // Chinese 插件
6 | "ms-ceintl.vscode-language-pack-zh-hans",
7 | // Code Spell Checker 插件
8 | "streetsidesoftware.code-spell-checker",
9 | // Color Info 插件
10 | "bierner.color-info",
11 | // comment tip 插件
12 | "yuechaoxu.vscode-comment-tip",
13 | // CSS Navigation 插件
14 | "pucelle.vscode-css-navigation",
15 | // CSS Peek 插件
16 | "pranaygp.vscode-css-peek",
17 | // dir tree generator 插件
18 | "openmynet.dir-tree-generator",
19 | // Document This 插件
20 | "oouo-diogo-perdigao.docthis",
21 | // EditorConfig for VS Code 插件
22 | "editorconfig.editorconfig",
23 | // Error Lens 插件
24 | "usernamehw.errorlens",
25 | // ESLint 插件
26 | "dbaeumer.vscode-eslint",
27 | // ESLint Chinese Rules 插件
28 | "maggie.eslint-rules-zh-plugin",
29 | // git-commit-plugin 插件
30 | "redjue.git-commit-plugin",
31 | // GitLens 插件
32 | "eamodio.gitlens",
33 | // Image Preview 插件
34 | "kisstkondoros.vscode-gutter-preview",
35 | // Import Cost 插件
36 | "wix.vscode-import-cost",
37 | // JavaScript (ES6) code snippets 插件
38 | "xabikos.javascriptsnippets",
39 | // koroFileHeader 插件
40 | "obkoro1.korofileheader",
41 | // Live Server 插件
42 | "ritwickdey.liveserver",
43 | // Local History 插件
44 | "xyz.local-history",
45 | // markdownlint 插件
46 | "davidanson.vscode-markdownlint",
47 | // Prettier ESLint 插件
48 | "rvest.vs-code-prettier-eslint",
49 | // SCSS IntelliSense 插件
50 | "mrmlnc.vscode-scss",
51 | // Stylelint 插件
52 | "stylelint.vscode-stylelint",
53 | // Template String Converter 插件
54 | "meganrogge.template-string-converter",
55 | // Todo Highlight 插件
56 | "wayou.vscode-todo-highlight",
57 | // Todo Tree 插件
58 | "gruntfuggly.todo-tree",
59 | // uni-app-schemas 插件
60 | "uni-helper.uni-app-schemas-vscode",
61 | // uni-app-snippets 插件
62 | "uni-helper.uni-app-snippets-vscode",
63 | // uni-create-view 插件
64 | "uni-helper.uni-highlight-vscode",
65 | // Var Conversion 插件
66 | "xiaoxintongxue.var-conv",
67 | // Vue - Official 插件
68 | "vue.volar",
69 | // Vue VSCode Snippets 插件
70 | "sdras.vue-vscode-snippets"
71 | ]
72 | }
73 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 dyb-dev
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UniApp-MP-WX-Template
2 |
3 | [](https://zh.wikipedia.org/wiki/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89)
4 |
5 | ## 项目简介
6 |
7 | UniApp-MP-WX-Template 提供了一个用于开发微信小程序的基本模板,该项目基于 [Uniapp](https://uniapp.dcloud.net.cn/) + [Vue3](https://cn.vuejs.org/) + [TS](https://www.typescriptlang.org/) 构建,该模板预配置了一些常用的开发工具和插件,帮助你快速开发微信小程序,为您带来极致的体验。
8 |
9 | ## 功能特点
10 |
11 | - **UniApp 工具链**: 支持自动生成 `pages.json` 和 `manifest.json` 配置文件,自动化处理页面和项目配置文件。
12 | - **TypeScript**: 项目使用 TypeScript 进行开发,集成 `vue-tsc` 插件自动进行 Vue 组件的类型检查,同时支持项目的模块化管理
13 | - **Vue 3 组件库**: 集成了 `nutui-uniapp` 组件库,支持 Vue 3 组件的按需自动导入,支持 TypeScript 类型提示。
14 | - **自定义布局组件**: 内置多个自定义布局组件(如顶部导航栏、底部导航栏),兼容 `pages.json` 配置。
15 | - **网络请求**: 提供 Promise 方式调用 UniApp API,处理网络请求和异步操作更加简洁高效。
16 | - **页面导航**: 内置多种跳转方法封装,支持跳转小程序内部页面、H5 页面和第三方小程序,提供统一的导航接口。
17 | - **登录拦截与路由守卫**: 集成登录拦截器和路由守卫功能,自动处理用户登录状态,确保未登录用户访问受限页面时跳转到登录页面,兼容 `pages.json` 配置。
18 | - **公用 WebView 页面**: 内置的公用 WebView 页面,用于展示 H5 页面或进行 H5 分享功能,兼容 `pages.json` 配置。
19 | - **业务开发**: 内置获取用户手机号、微信头像和昵称的组件,简化了微信授权和用户信息收集的流程。
20 | - **代码风格管理**: 预配置了 ESLint、Stylelint 及 Prettier 工具,集成自定义的 ESLint、Stylelint 规则集,帮助开发者统一代码风格。
21 |
22 | ## 安装与使用
23 |
24 | 你可以使用 npm、pnpm 或 yarn 等包管理器来安装项目依赖。推荐使用 pnpm 作为首选包管理器。在下面的示例中,我们默认使用 pnpm 进行演示:
25 |
26 | ### 环境要求
27 |
28 | - Node.js 版本 >= 18.0.0
29 | - 如果包管理器为 pnpm,版本需 >= 8.15.5
30 |
31 | ### 环境变量配置
32 |
33 | 该模板项目支持通过 `.env` 文件进行环境变量配置,你可以根据实际需要修改 `.env` 中的以下配置项:
34 |
35 | - `VITE_MP_WX_APPID`: 小程序的 AppID,用于微信小程序的配置和相关 API 调用。
36 | - `VITE_PAGE_DIR`: 页面目录,默认值为 `pages`,用于指定项目中主包页面所在的文件夹。
37 | - `VITE_SUB_PACKAGE_DIR`: 分包目录,默认值为 `subPackages`,用于指定 `src` 目录下的分包目录名称。
38 | - `VITE_SUB_PACKAGE_CHILD_DIRS`: 分包子目录集合,默认值为 `webview`,如果项目中存在多个子分包,可以用逗号分隔(例如:`webview,profile,shop`),用于配置分包子目录名称集合。
39 | - `VITE_LAUNCH_PATH`: 启动页路径,默认值为 `pages/launch`,用于指定小程序的启动页面路径。如果 `VITE_USE_LAUNCH_PAGE` 设为 `true`,小程序启动时将默认加载该页面。
40 | - `VITE_USE_LAUNCH_PAGE`: 是否使用启动页,默认值为 `false`。如果设为 `true`,启动页将作为小程序首次展示的页面,并且跳转逻辑将在 `App.vue` 中进行。启动页中可根据逻辑判断用户状态,再决定跳转到登录页或首页。使用时注意:
41 | 1. 设置 `VITE_USE_LAUNCH_PAGE=true` 后,小程序的首页将变为 `VITE_LAUNCH_PATH` 指定的路径。
42 | 2. 小程序码路径的格式为:目标页面为 `a` 页面,则路径应为 `/pages/launch?targetPath=pages/a¶m1=value1`,其中 `targetPath` 参数将指定跳转目标页面,而其他参数(如 `param1=value1`)会传递给目标页面作为查询参数使用。
43 | - `VITE_LOGIN_PATH`: 登录页面的路径,默认值为 `pages/login`,用于指定登录页面的位置。当用户未登录时,自动跳转到该页面进行登录。
44 | - `VITE_HOME_PATH`: 首页路径,默认值为 `pages/home`,用于指定应用程序的首页路径。用户登录成功后将跳转到该路径。
45 | - `VITE_DEV_SERVER_URL`: 开发环境服务器网址(小程序开发版、体验版用到),默认值为 `http://xxxx.com`,用于指定后端 API 的根路径。
46 | - `VITE_PROD_SERVER_URL`: 生产环境服务器网址(小程序体验版、线上版用到),默认值为 `http://xxxx.com`,用于指定后端 API 的根路径。
47 | - `VITE_API_BASE_PATH`: 接口请求基础路径,默认值为 `/test.aspx`,用于配置接口的基础路径,与 `VITE_DEV_SERVER_URL` 或者 `VITE_PROD_SERVER_URL` 结合使用,形成完整的 API 请求路径。
48 |
49 | ### 安装依赖
50 |
51 | ```bash
52 | pnpm install
53 | ```
54 |
55 | ### 本地开发
56 |
57 | ```bash
58 | pnpm dev
59 | ```
60 |
61 | ### 构建产物
62 |
63 | ```bash
64 | pnpm build
65 | ```
66 |
67 | ## 许可证
68 |
69 | 本项目基于 `MIT 许可证` 开源。
70 |
--------------------------------------------------------------------------------
/manifest.config.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 13:57:43
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-19 23:24:28
6 | * @FilePath: /uniapp-mp-wx-template/manifest.config.ts
7 | * @Description: 应用配置文件
8 | */
9 |
10 | import { defineManifestConfig } from "@uni-helper/vite-plugin-uni-manifest"
11 |
12 | import pkg from "./package.json"
13 | import { VITE_ENV } from "./vite.config"
14 |
15 | /** CONST: 获取.env文件的环境变量 */
16 | const { VITE_MP_WX_APPID } = VITE_ENV
17 |
18 | export default defineManifestConfig({
19 | // 应用标题
20 | name: pkg.name,
21 | // 应用的唯一标识符
22 | appid: "",
23 | // 应用的描述
24 | description: pkg.description,
25 | // 应用版本名称
26 | versionName: pkg.version,
27 | // 应用版本号,主要用于应用的内部版本控制
28 | versionCode: "100",
29 | // 是否自动转换 px 单位 默认: true
30 | transformPx: false,
31 | // uni 统计配置项
32 | uniStatistics: {
33 | // 是否启用统计 默认: true
34 | enable: false
35 | },
36 |
37 | /* 小程序特有相关 */
38 | "mp-weixin": {
39 | // 微信小程序的应用 ID
40 | appid: VITE_MP_WX_APPID,
41 | // 是否使用自定义组件
42 | usingComponents: true,
43 | // 是否开启小程序按需注入特性
44 | lazyCodeLoading: "requiredComponents",
45 | // 合并组件虚拟节点外层属性(目前仅支持 style、class 属性)
46 | mergeVirtualHostAttributes: true,
47 | // 微信小程序的优化配置
48 | optimization: {
49 | // 是否开启分包优化
50 | subPackages: true
51 | },
52 | // 微信小程序的相关设置
53 | setting: {
54 | // 是否启用 URL 校验
55 | urlCheck: false,
56 | // 是否ES6 转 ES5
57 | es6: true,
58 | // 上传代码时样式是否自动补全
59 | postcss: true,
60 | // 上传代码时是否自动压缩
61 | minified: true,
62 | // 预览及真机调试时包体积上限是否调整为4M,默认: true
63 | bigPackageSizeSupport: true
64 | }
65 | }
66 | })
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniapp-mp-wx-template",
3 | "version": "1.1.5",
4 | "description": "基于`uni-app + vue3 + ts`搭建的微信小程序模板",
5 | "author": "dyb-dev",
6 | "license": "MIT",
7 | "private": true,
8 | "main": "./src/main.ts",
9 | "scripts": {
10 | "prepare": "husky",
11 | "dev": "uni -p mp-weixin",
12 | "build": "npm run ts-check && npm run build-only",
13 | "build-only": "uni build -p mp-weixin",
14 | "ts-check": "vue-tsc --build --force",
15 | "release": "project-cli release"
16 | },
17 | "engines": {
18 | "node": ">=18.0.0",
19 | "pnpm": ">=8.15.5"
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/dyb-dev/uniapp-mp-wx-template"
24 | },
25 | "homepage": "https://github.com/dyb-dev/uniapp-mp-wx-template",
26 | "bugs": {
27 | "url": "https://github.com/dyb-dev/uniapp-mp-wx-template/issues",
28 | "directory": "https://github.com/dyb-dev/uniapp-mp-wx-template"
29 | },
30 | "devDependencies": {
31 | "@dcloudio/types": "^3.4.14",
32 | "@dcloudio/vite-plugin-uni": "3.0.0-4040520250104002",
33 | "@dyb-dev/eslint-config": "^0.1.3",
34 | "@dyb-dev/prettier-config": "^0.0.5",
35 | "@dyb-dev/project-cli": "^0.0.9",
36 | "@dyb-dev/stylelint-config": "^0.0.5",
37 | "@dyb-dev/ts-config": "^0.0.7",
38 | "@uni-helper/uni-app-types": "1.0.0-alpha.4",
39 | "@uni-helper/vite-plugin-uni-components": "^0.1.0",
40 | "@uni-helper/vite-plugin-uni-manifest": "^0.2.7",
41 | "@uni-helper/vite-plugin-uni-pages": "^0.2.28",
42 | "eslint": "^8.57.1",
43 | "husky": "^9.1.6",
44 | "miniprogram-api-typings": "^4.0.1",
45 | "prettier": "^3.3.3",
46 | "prettier-eslint": "^16.3.0",
47 | "sass": "1.64.2",
48 | "stylelint": "^16.10.0",
49 | "typescript": "^5.6.3",
50 | "vite": "^5.2.8",
51 | "vue-tsc": "^2.1.6"
52 | },
53 | "dependencies": {
54 | "@dcloudio/uni-app": "3.0.0-4040520250104002",
55 | "@dcloudio/uni-components": "3.0.0-4040520250104002",
56 | "@dcloudio/uni-mp-weixin": "3.0.0-4040520250104002",
57 | "@qiun/uni-ucharts": "2.5.0-20230101",
58 | "@uni-helper/uni-network": "^0.19.3",
59 | "@uni-helper/uni-promises": "^0.2.1",
60 | "@vueuse/core": "^9.13.0",
61 | "dayjs": "^1.11.13",
62 | "mp-html": "^2.5.0",
63 | "nutui-uniapp": "^1.8.1",
64 | "pinia": "^2.2.4",
65 | "pinia-plugin-persistedstate": "^4.1.1",
66 | "query-string": "^9.1.1",
67 | "vue": "^3.5.13"
68 | }
69 | }
--------------------------------------------------------------------------------
/pages.config.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 13:57:47
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-11-30 13:12:20
6 | * @FilePath: /uniapp-mp-wx-template/pages.config.ts
7 | * @Description: 页面配置文件
8 | */
9 |
10 | import { defineUniPages } from "@uni-helper/vite-plugin-uni-pages"
11 |
12 | import { VITE_ENV } from "./vite.config"
13 |
14 | /** CONST: 获取.env文件的环境变量 */
15 | const { VITE_PAGE_DIR, VITE_LAUNCH_PATH, VITE_HOME_PATH, VITE_LOGIN_PATH, VITE_SUB_PACKAGE_DIR } = VITE_ENV
16 |
17 | export default defineUniPages({
18 | // 全局配置
19 | globalStyle: {
20 | // 默认使用自定义导航栏
21 | navigationStyle: "custom",
22 | // 默认设置状态栏前景颜色为`black`,解决状态栏不可见的问题
23 | navigationBarTextStyle: "black",
24 | // 默认设置导航栏背景颜色为白色 解决在 `webview` 中不支持自定义导航栏的问题,因此设置保持与自定义导航栏一致的背景颜色
25 | navigationBarBackgroundColor: "#ffffff",
26 | // 默认页面(page元素)为白色背景,解决系统暗黑主题下页面背景与导航栏背景不一致的问题
27 | backgroundColor: "#ffffff",
28 | // 默认禁用页面滑动,解决ios与安卓默认行为不一致的问题
29 | disableScroll: true
30 | },
31 | // 页面配置
32 | pages: [
33 | {
34 | path: VITE_LAUNCH_PATH
35 | },
36 | {
37 | path: VITE_LOGIN_PATH,
38 | style: {
39 | navigationBarTitleText: "登录"
40 | }
41 | },
42 | {
43 | path: VITE_HOME_PATH,
44 | style: {
45 | navigationBarTitleText: "首页"
46 | }
47 | },
48 | {
49 | path: `${VITE_PAGE_DIR}/list`,
50 | style: {
51 | navigationBarTitleText: "列表"
52 | }
53 | },
54 | {
55 | path: `${VITE_PAGE_DIR}/my`,
56 | style: {
57 | navigationBarTitleText: "我的"
58 | },
59 | // 标识该页面是需要先登录
60 | needLogin: true
61 | },
62 | {
63 | path: `${VITE_PAGE_DIR}/test`,
64 | style: {
65 | navigationBarTitleText: "测试",
66 | // 允许滑动
67 | disableScroll: false,
68 | // 开启下拉刷新
69 | enablePullDownRefresh: true
70 | },
71 | // 标识该页面是需要先登录
72 | needLogin: true
73 | }
74 | ],
75 | // wx开发工具页面测试配置
76 | condition: {
77 | current: 0,
78 | list: [
79 | {
80 | name: "启动页",
81 | path: VITE_LAUNCH_PATH,
82 | query: `targetPath=/${VITE_PAGE_DIR}/test&test=测试启动参数`
83 | },
84 | {
85 | name: "首页",
86 | path: VITE_HOME_PATH,
87 | query: "test=首页"
88 | },
89 | {
90 | name: "我的",
91 | path: `${VITE_PAGE_DIR}/my`
92 | },
93 | {
94 | name: "测试",
95 | path: `${VITE_PAGE_DIR}/test`
96 | }
97 | ]
98 | },
99 | // TabBar页面配置
100 | tabBar: {
101 | // 默认使用自定义TabBar
102 | custom: true,
103 | // 默认颜色
104 | color: "#7d7e80",
105 | // 选中颜色
106 | selectedColor: "#29d446",
107 | // tabBar 项列表
108 | list: [
109 | {
110 | pagePath: VITE_HOME_PATH,
111 | text: "首页",
112 | iconfont: {
113 | text: "home",
114 | selectedText: "home"
115 | }
116 | },
117 | {
118 | pagePath: `${VITE_PAGE_DIR}/list`,
119 | text: "列表",
120 | iconfont: {
121 | text: "dongdong",
122 | selectedText: "dongdong"
123 | }
124 | },
125 | {
126 | pagePath: `${VITE_PAGE_DIR}/my`,
127 | text: "我的",
128 | iconfont: {
129 | text: "my",
130 | selectedText: "my"
131 | }
132 | }
133 | ]
134 | },
135 |
136 | // 分包配置
137 | subPackages: [
138 | {
139 | root: `${VITE_SUB_PACKAGE_DIR}/webview`,
140 | pages: [
141 | {
142 | path: `${VITE_SUB_PACKAGE_DIR}/webview/${VITE_PAGE_DIR}/webview`
143 | }
144 | ]
145 | }
146 | ],
147 | // 分包预加载配置
148 | preloadRule: {
149 | [VITE_HOME_PATH]: {
150 | packages: [`${VITE_SUB_PACKAGE_DIR}/webview`]
151 | }
152 | }
153 | })
154 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
51 |
52 |
56 |
--------------------------------------------------------------------------------
/src/apis/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-08 20:34:09
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 23:29:52
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/index.ts
7 | * @Description: 接口模块
8 | */
9 |
10 | /** 导出接口模块 */
11 | export * from "./modules"
12 |
13 | import { un } from "@uni-helper/uni-network"
14 |
15 | import { getCurrentServerUrl, isDevEnv } from "@/utils"
16 |
17 | import { setupApiInterceptor } from "./interceptors"
18 | import { setGlobalTestRequestConfig } from "./request"
19 |
20 | /**
21 | * FUN: 设置接口配置
22 | *
23 | * @author dyb-dev
24 | * @date 08/10/2024/ 20:47:43
25 | */
26 | const setupApi = () => {
27 |
28 | // 设置请求基础路径
29 | un.defaults.baseUrl = getCurrentServerUrl() + __PROJECT_INFO__.env.VITE_API_BASE_PATH
30 |
31 | // 设置接口拦截器
32 | setupApiInterceptor()
33 |
34 | // 设置全局测试请求配置
35 | setGlobalTestRequestConfig({
36 | test: isDevEnv() && true,
37 | testDelay: 500
38 | })
39 |
40 | }
41 |
42 | export { setupApi }
43 |
--------------------------------------------------------------------------------
/src/apis/interceptors/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-17 16:16:56
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:55:54
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/interceptors/index.ts
7 | * @Description: Api 拦截器模块
8 | */
9 |
10 | import { setupResponseInterceptor } from "./response"
11 |
12 | /**
13 | * FUN: 设置接口拦截器
14 | *
15 | * @author dyb-dev
16 | * @date 17/10/2024/ 16:17:31
17 | */
18 | const setupApiInterceptor = () => {
19 |
20 | setupResponseInterceptor()
21 |
22 | }
23 |
24 | export { setupApiInterceptor }
25 |
--------------------------------------------------------------------------------
/src/apis/interceptors/response.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:54:48
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:55:25
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/interceptors/response.ts
7 | * @Description: 响应拦截器模块
8 | */
9 |
10 | import { un } from "@uni-helper/uni-network"
11 |
12 | /**
13 | * FUN: 设置响应拦截器
14 | *
15 | * @author dyb-dev
16 | * @date 21/02/2025/ 21:55:38
17 | */
18 | const setupResponseInterceptor = () => {
19 |
20 | // 设置响应拦截器
21 | un.interceptors.response.use(
22 | response => {
23 |
24 | response.success = response.errMsg?.includes("request:fail") ? false : true
25 | response.message = response.errMsg || (response.success ? "请求成功" : "请求失败")
26 | return response
27 |
28 | },
29 | undefined,
30 | { synchronous: true }
31 | )
32 |
33 | }
34 |
35 | export { setupResponseInterceptor }
36 |
--------------------------------------------------------------------------------
/src/apis/modules/activity.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-08 21:22:48
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 22:48:25
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/modules/activity.ts
7 | * @Description: 本次活动接口模块
8 | */
9 |
10 | import un from "@uni-helper/uni-network"
11 |
12 | import { sendRequest } from "../request"
13 |
14 | import type { UnResponse } from "@uni-helper/uni-network"
15 |
16 | /** 获取用户信息的结果数据 */
17 | interface IGetUserInfoApiResultData {
18 | /** 内容 */
19 | body: string
20 | /** id */
21 | id: number
22 | /** 标题 */
23 | title: string
24 | /** 用户唯一标识 */
25 | userId: number
26 | }
27 |
28 | /**
29 | * FUN: 获取用户信息
30 | *
31 | * @author dyb-dev
32 | * @date 21/02/2025/ 22:46:30
33 | * @param {TModifyProperties, "test">} [testRequestConfig] 测试请求配置
34 | * @returns {*} {Promise>} 结果数据
35 | */
36 | const getUserInfoApi = async(
37 | testRequestConfig?: TModifyProperties, "test">
38 | ): Promise> => {
39 |
40 | return sendRequest({
41 | url: "/1",
42 | requestFn: un.get,
43 | testRequestConfig
44 | })
45 |
46 | }
47 |
48 | /** 获取id的参数 */
49 | interface IGetIdApiParams {
50 | /** 用户唯一标识 */
51 | userId: number
52 | }
53 |
54 | /** 获取id的结果数据 */
55 | interface IGetIdApiResultData {
56 | /** id */
57 | id: number
58 | }
59 |
60 | /**
61 | * FUN: 获取id
62 | *
63 | * @author dyb-dev
64 | * @date 21/02/2025/ 22:48:09
65 | * @param {IGetIdApiParams} params 参数
66 | * @param {TModifyProperties, "test">} [testRequestConfig] 测试请求配置
67 | * @returns {*} {Promise>} 结果数据
68 | */
69 | const getIdApi = async(
70 | params: IGetIdApiParams,
71 | testRequestConfig?: TModifyProperties, "test">
72 | ): Promise> => {
73 |
74 | return sendRequest({
75 | url: "",
76 | params,
77 | testRequestConfig
78 | })
79 |
80 | }
81 |
82 | export type { IGetUserInfoApiResultData, IGetIdApiParams, IGetIdApiResultData }
83 |
84 | export { getUserInfoApi, getIdApi }
85 |
--------------------------------------------------------------------------------
/src/apis/modules/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:56:51
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:56:56
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/modules/index.ts
7 | * @Description: 接口模块
8 | */
9 |
10 | /** 导出本次活动相关接口 */
11 | export * from "./activity"
12 | /** 导出用户信息相关接口 */
13 | export * from "./userInfo"
14 |
--------------------------------------------------------------------------------
/src/apis/modules/userInfo.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-09 15:23:42
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 23:06:02
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/modules/userInfo.ts
7 | * @Description: 用户信息相关接口
8 | */
9 |
10 | import { sendRequest } from "../request"
11 |
12 | import type { UnResponse } from "@uni-helper/uni-network"
13 |
14 | /** 登录的参数 */
15 | interface ILoginApiParams {
16 | /**
17 | * 用户登录凭证(有效期五分钟)。开发者需要在开发者服务器后台调用 [code2Session](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html),使用 code 换取 openid、unionid、session_key 等信息
18 | */
19 | code: string
20 | }
21 |
22 | /** 登录的结果数据 */
23 | interface ILoginApiResultData {
24 | /** 用户在我们系统中的加密用户代码 */
25 | userId: string
26 | /** 由微信生成的用户在开放平台的唯一标识符 */
27 | unionId: string
28 | /** 由微信生成的用户在本小程序唯一标识 */
29 | openId: string
30 | /** 昵称 */
31 | nickName: string
32 | /** 头像 */
33 | avatarUrl: string
34 | /** 绑定手机号 */
35 | phoneNumber: string
36 | }
37 |
38 | /**
39 | * FUN: 登录
40 | *
41 | * @author dyb-dev
42 | * @date 21/02/2025/ 22:49:58
43 | * @param {ILoginApiParams} params 参数
44 | * @param {TModifyProperties, "test">} [testRequestConfig] 测试请求配置
45 | * @returns {*} {Promise>} 结果数据
46 | */
47 | const loginApi = async(
48 | params: ILoginApiParams,
49 | testRequestConfig?: TModifyProperties, "test">
50 | ): Promise> => {
51 |
52 | return sendRequest({
53 | url: "",
54 | params,
55 | testRequestConfig
56 | })
57 |
58 | }
59 |
60 | /** 获取手机号的参数 */
61 | interface IGetPhoneNumberApiParams {
62 | /** 授权手机号code */
63 | code: string
64 | }
65 |
66 | /** 获取手机号的结果数据 */
67 | interface IGetPhoneNumberApiResultData {
68 | /** 手机号 */
69 | phoneNumber: string
70 | }
71 |
72 | /**
73 | * FUN: 获取手机号
74 | *
75 | * @author dyb-dev
76 | * @date 21/02/2025/ 22:54:45
77 | * @param {IGetPhoneNumberApiParams} params 参数
78 | * @param {TModifyProperties, "test">} [testRequestConfig] 测试请求配置
79 | * @returns {*} {Promise>} 结果数据
80 | */
81 | const getPhoneNumberApi = async(
82 | params: IGetPhoneNumberApiParams,
83 | testRequestConfig?: TModifyProperties, "test">
84 | ): Promise> => {
85 |
86 | return sendRequest({
87 | url: "",
88 | params,
89 | testRequestConfig
90 | })
91 |
92 | }
93 |
94 | /** 上传头像的参数 */
95 | interface IUploadAvatarApiParams {
96 | /** 头像url */
97 | avatarUrl: string
98 | }
99 |
100 | /**
101 | * FUN: 上传头像
102 | *
103 | * @author dyb-dev
104 | * @date 21/02/2025/ 23:03:54
105 | * @param {IUploadAvatarApiParams} params 参数
106 | * @param {TModifyProperties} [testRequestConfig] 测试请求配置
107 | * @returns {*} {Promise} 上传头像结果
108 | */
109 | const uploadAvatarApi = async(
110 | params: IUploadAvatarApiParams,
111 | testRequestConfig?: TModifyProperties
112 | ): Promise => {
113 |
114 | return sendRequest({
115 | url: "",
116 | params,
117 | testRequestConfig
118 | })
119 |
120 | }
121 |
122 | /** 上传用户信息的参数 */
123 | interface IUploadUserInfoApiParams {
124 | /** 头像url */
125 | avatarUrl: string
126 | /** 昵称 */
127 | nickName: string
128 | }
129 |
130 | /**
131 | * FUN: 上传用户信息
132 | *
133 | * @author dyb-dev
134 | * @date 21/02/2025/ 23:05:52
135 | * @param {IUploadUserInfoApiParams} params 参数
136 | * @param {TModifyProperties} [testRequestConfig] 测试请求配置
137 | * @returns {*} {Promise} 上传用户信息结果
138 | */
139 | const uploadUserInfoApi = async(
140 | params: IUploadUserInfoApiParams,
141 | testRequestConfig?: TModifyProperties
142 | ): Promise => {
143 |
144 | return sendRequest({
145 | url: "",
146 | params,
147 | testRequestConfig
148 | })
149 |
150 | }
151 |
152 | export type {
153 | IGetPhoneNumberApiParams,
154 | IGetPhoneNumberApiResultData,
155 | IUploadAvatarApiParams,
156 | IUploadUserInfoApiParams,
157 | ILoginApiParams,
158 | ILoginApiResultData
159 | }
160 |
161 | export { getPhoneNumberApi, uploadAvatarApi, uploadUserInfoApi, loginApi }
162 |
--------------------------------------------------------------------------------
/src/apis/request/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:58:00
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 22:37:49
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/request/index.ts
7 | * @Description: 封装请求模块
8 | */
9 |
10 | import un from "@uni-helper/uni-network"
11 |
12 | import { delay, isDevEnv } from "@/utils"
13 |
14 | import { ERequestLogType, requestLog } from "./log"
15 |
16 | import type { UnResponse } from "@uni-helper/uni-network"
17 |
18 | /** LET: 全局测试请求配置 */
19 | let _globalTestRequestConfig: Omit = {
20 | test: isDevEnv() && true,
21 | testDelay: 500
22 | }
23 |
24 | /**
25 | * FUN: 设置全局测试请求配置
26 | *
27 | * @author dyb-dev
28 | * @date 21/02/2025/ 19:50:27
29 | * @param {Omit} config 测试请求配置
30 | */
31 | const setGlobalTestRequestConfig = (config: Omit) => {
32 |
33 | _globalTestRequestConfig = config
34 |
35 | }
36 |
37 | /** LET: 全局请求id,用于进行日志输出 */
38 | let _globalRequestId = 0
39 |
40 | /** 发送请求选项 */
41 | interface ISendRequestOptions, P extends Record = Record> {
42 | /** 请求地址 */
43 | url: string
44 | /** 请求参数 */
45 | params?: P
46 | /** 发送 http 请求函数 默认 axios.post 方法 */
47 | requestFn?: (url: string, params?: P) => Promise>
48 | /** 测试请求配置 */
49 | testRequestConfig?: TModifyProperties, "test">
50 | }
51 |
52 | /**
53 | * FUN: 发送请求
54 | *
55 | * @author dyb-dev
56 | * @date 21/02/2025/ 14:18:09
57 | * @template T
58 | * @template P
59 | * @param {ISendRequestOptions} options 选项
60 | * @returns {*} {Promise>} 请求结果
61 | */
62 | const sendRequest = async , P extends Record = Record>(
63 | options: ISendRequestOptions
64 | ): Promise> => {
65 |
66 | _globalRequestId++
67 | // 当前请求id
68 | const _currentRequestId = _globalRequestId
69 |
70 | const { url, params = {}, requestFn = un.post, testRequestConfig } = options
71 |
72 | // 是否使用测试模式
73 | if (testRequestConfig?.test ?? _globalTestRequestConfig.test) {
74 |
75 | // 输出测试请求参数日志
76 | requestLog({
77 | type: ERequestLogType.TEST_REQUEST_PARAMS,
78 | url,
79 | requestId: _currentRequestId,
80 | data: params
81 | })
82 |
83 | // 测试请求配置
84 | // eslint-disable-next-line prefer-const
85 | let { testResult, testDelay = _globalTestRequestConfig.testDelay ?? 0 } = testRequestConfig ?? {}
86 |
87 | // 如果测试数据未提供,则返回测试失败
88 | if (!testResult) {
89 |
90 | testResult = {
91 | success: false,
92 | message: "测试数据未提供"
93 | }
94 |
95 | // 输出测试请求结果日志
96 | requestLog({
97 | type: ERequestLogType.TEST_REQUEST_RESULT_FAIL,
98 | url,
99 | requestId: _currentRequestId,
100 | data: testResult
101 | })
102 |
103 | return testResult
104 |
105 | }
106 |
107 | // 模拟请求延迟
108 | await delay(testDelay)
109 |
110 | // 确定日志类型
111 | const _requestLogType = testResult.success
112 | ? ERequestLogType.TEST_REQUEST_RESULT_SUCCESS
113 | : ERequestLogType.TEST_REQUEST_RESULT_FAIL
114 |
115 | // 输出测试请求结果日志
116 | requestLog({
117 | type: _requestLogType,
118 | url,
119 | requestId: _currentRequestId,
120 | data: testResult
121 | })
122 |
123 | return testResult
124 |
125 | }
126 |
127 | try {
128 |
129 | // 输出真实请求参数日志
130 | requestLog({
131 | type: ERequestLogType.REQUEST_PARAMS,
132 | url,
133 | requestId: _currentRequestId,
134 | data: params
135 | })
136 |
137 | // 发送请求
138 | const _result = await requestFn(url, params)
139 |
140 | // 确定日志类型
141 | const _requestLogType = _result.success ? ERequestLogType.REQUEST_RESULT_SUCCESS : ERequestLogType.REQUEST_RESULT_FAIL
142 |
143 | requestLog({
144 | type: _requestLogType,
145 | url,
146 | requestId: _currentRequestId,
147 | data: _result
148 | })
149 |
150 | return _result
151 |
152 | }
153 | catch (error) {
154 |
155 | const _result = {
156 | success: false,
157 | message: "请求失败"
158 | }
159 |
160 | requestLog({
161 | type: ERequestLogType.REQUEST_RESULT_FAIL,
162 | url,
163 | requestId: _currentRequestId,
164 | data: _result
165 | })
166 |
167 | return _result
168 |
169 | }
170 |
171 | }
172 |
173 | export type { ISendRequestOptions }
174 |
175 | export { setGlobalTestRequestConfig, sendRequest }
176 |
--------------------------------------------------------------------------------
/src/apis/request/log.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:57:45
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:57:50
6 | * @FilePath: /uniapp-mp-wx-template/src/apis/request/log.ts
7 | * @Description: 请求日志模块
8 | */
9 |
10 | import { isAbsoluteUrl, isDevEnv, isEnableDebug, trimUrlSlashes } from "@/utils"
11 |
12 | /** 请求日志类型枚举 */
13 | enum ERequestLogType {
14 | /** 测试请求参数 */
15 | TEST_REQUEST_PARAMS,
16 | /** 测试请求结果, 测试成功 */
17 | TEST_REQUEST_RESULT_SUCCESS,
18 | /** 测试请求结果, 测试失败 or 没有测试数据 */
19 | TEST_REQUEST_RESULT_FAIL,
20 | /** 真实请求参数 */
21 | REQUEST_PARAMS,
22 | /** 真实请求结果, 接口调用成功 */
23 | REQUEST_RESULT_SUCCESS,
24 | /** 真实请求结果, 接口调用失败 */
25 | REQUEST_RESULT_FAIL
26 | }
27 |
28 | /** 请求日志配置的类型 */
29 | interface IRequestLogConfig {
30 | /** 样式字符串 */
31 | style: string
32 | /** 描述 */
33 | description: string
34 | }
35 |
36 | /** CONST: 请求日志配置列表 */
37 | const REQUEST_LOG_CONFIG_LIST: Record = {
38 | [ERequestLogType.TEST_REQUEST_PARAMS]: {
39 | style: "color: #fff; background-color: #747474; padding: 5px 10px;",
40 | description: "测试请求参数"
41 | },
42 | [ERequestLogType.TEST_REQUEST_RESULT_SUCCESS]: {
43 | style: "color: #fff; background-color: #9d9d9d; padding: 5px 10px;",
44 | description: "测试请求成功"
45 | },
46 | [ERequestLogType.TEST_REQUEST_RESULT_FAIL]: {
47 | style: "color: #fff; background-color: #ff7781; padding: 5px 10px;",
48 | description: "测试请求失败"
49 | },
50 | [ERequestLogType.REQUEST_PARAMS]: {
51 | style: "color: #fff; background-color: #0078fe; padding: 5px 10px;",
52 | description: "请求参数"
53 | },
54 | [ERequestLogType.REQUEST_RESULT_SUCCESS]: {
55 | style: "color: #fff; background-color: #2da000; padding: 5px 10px;",
56 | description: "请求成功"
57 | },
58 | [ERequestLogType.REQUEST_RESULT_FAIL]: {
59 | style: "color: #fff; background-color: #fe003c; padding: 5px 10px;",
60 | description: "请求失败"
61 | }
62 | }
63 |
64 | /** 输出请求日志选项 */
65 | interface IRequestLogOptions {
66 | /** 请求日志类型 */
67 | type: ERequestLogType
68 | /** 请求地址 */
69 | url: string
70 | /** 请求id */
71 | requestId: number
72 | /** 请求日志数据 */
73 | data: Record
74 | }
75 |
76 | /**
77 | * FUN: 请求日志
78 | *
79 | * @author dyb-dev
80 | * @date 21/02/2025/ 18:32:32
81 | * @param {IRequestLogOptions} option 请求日志选项
82 | */
83 | const requestLog = (option: IRequestLogOptions) => {
84 |
85 | // 如果不是开发环境且不启用调试模式,则不输出请求日志
86 | if (!isDevEnv() && !isEnableDebug()) {
87 |
88 | return
89 |
90 | }
91 |
92 | let url = option.url
93 |
94 | // 如果不是绝对路径,则拼接基础 API 路径
95 | if (!isAbsoluteUrl(url)) {
96 |
97 | url = trimUrlSlashes(url)
98 | url = `${__PROJECT_INFO__.env.VITE_API_BASE_PATH}${url && `/${url}`}`
99 |
100 | }
101 |
102 | // 输出请求日志选项
103 | const { type, requestId, data } = option
104 | // 获取请求日志配置
105 | const { description, style } = REQUEST_LOG_CONFIG_LIST[type]
106 |
107 | console.log(`\n %c${requestId} ${description} :>>`, style, url, "\n", data)
108 |
109 | }
110 |
111 | export { ERequestLogType, requestLog }
112 |
--------------------------------------------------------------------------------
/src/components/AvatarNickname.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
79 |
80 |
90 |
91 |
92 |
99 |
105 |
114 | {{ props.nickname }}
115 |
116 |
117 |
118 |
119 |
149 |
--------------------------------------------------------------------------------
/src/components/Cell.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
138 |
139 |
151 |
152 |
153 |
163 |
164 |
172 |
173 |
174 |
175 | {{ props.title }}
176 |
177 |
178 |
179 |
187 |
188 |
189 |
190 |
211 |
--------------------------------------------------------------------------------
/src/components/FooterActionsBar.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
152 |
153 |
163 |
164 |
165 |
212 |
213 |
214 |
247 |
--------------------------------------------------------------------------------
/src/components/LabelValueBar.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
90 |
91 |
103 |
104 |
105 |
112 |
120 | {{ props.label }}
121 |
122 |
123 |
132 | {{ props.value }}
133 |
134 |
135 |
136 |
137 |
156 |
--------------------------------------------------------------------------------
/src/components/TabsPaneList.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
178 |
179 |
191 |
192 |
193 |
200 |
207 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
260 |
--------------------------------------------------------------------------------
/src/components/TitleBar.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
54 |
55 |
66 |
67 |
68 |
69 |
77 |
78 |
86 | {{ props.desc }}
87 |
88 |
89 | 查看更多
90 |
91 |
92 |
93 |
116 |
--------------------------------------------------------------------------------
/src/components/auth/AuthAvatarButton.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
135 |
136 |
147 |
148 |
149 |
155 |
156 |
157 |
179 |
--------------------------------------------------------------------------------
/src/components/auth/AuthPhoneNumberButton.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
85 |
86 |
97 |
98 |
99 |
100 |
101 |
102 |
124 |
--------------------------------------------------------------------------------
/src/components/auth/NickNameInput.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
167 |
168 |
180 |
181 |
182 |
194 |
195 |
--------------------------------------------------------------------------------
/src/components/auth/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-31 01:55:52
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-07 20:18:17
6 | * @FilePath: /uniapp-mp-wx-template/src/components/auth/index.ts
7 | * @Description: 用户信息组件相关工具函数
8 | */
9 |
10 | /** 导出授权头像按钮组件类型 */
11 | export type * from "./AuthAvatarButton.vue"
12 | /** 导出授权头像昵称对话框类型 */
13 | export type * from "./AuthAvatarNicknameDialog.vue"
14 | /** 导出授权手机号按钮组件类型 */
15 | export type * from "./AuthPhoneNumberButton.vue"
16 | /** 导出昵称输入框组件类型 */
17 | export type * from "./NickNameInput.vue"
18 |
19 | import { providerComponentOptions } from "@/components"
20 |
21 | import type {
22 | IAuthAvatarNicknameDialogOptions,
23 | TAuthAvatarNicknameDialogUnmountParam,
24 | TAuthAvatarNicknameDialogCustomKey
25 | } from "./AuthAvatarNicknameDialog.vue"
26 |
27 | /** 显示授权头像昵称对话框的结果 */
28 | type TShowAuthAvatarNicknameDialogResult = TAuthAvatarNicknameDialogUnmountParam
29 |
30 | /**
31 | * 使用授权头像昵称对话框
32 | *
33 | * @author dyb-dev
34 | * @date 29/10/2024/ 22:10:25
35 | * @param {TAuthAvatarNicknameDialogCustomKey} [customKey='__AUTH_AVATAR_NICKNAME_DIALOG__'] - 授权头像昵称对话框唯一标识key 默认: `__AUTH_AVATAR_NICKNAME_DIALOG__`
36 | * @returns {*} {TUseAuthAvatarNicknameDialog} - 授权头像昵称对话框相关函数
37 | */
38 | const useAuthAvatarNicknameDialog = (customKey: string = "") => {
39 |
40 | const _customKey: TAuthAvatarNicknameDialogCustomKey = `__AUTH_AVATAR_NICKNAME_DIALOG__${customKey}`
41 | const _options = providerComponentOptions(_customKey)
42 |
43 | /**
44 | * 显示授权头像昵称对话框
45 | *
46 | * @author dyb-dev
47 | * @date 30/10/2024/ 23:00:06
48 | * @returns {*} {Promise} - 显示授权头像昵称对话框的结果
49 | */
50 | const showAuthAvatarNicknameDialog = (): Promise => {
51 |
52 | return new Promise(resolve => {
53 |
54 | _options.value = {
55 | show: true,
56 | unmount: (...args: TShowAuthAvatarNicknameDialogResult) => resolve(args)
57 | }
58 |
59 | })
60 |
61 | }
62 | return {
63 | showAuthAvatarNicknameDialog
64 | }
65 |
66 | }
67 |
68 | export type { TShowAuthAvatarNicknameDialogResult }
69 |
70 | export { useAuthAvatarNicknameDialog }
71 |
--------------------------------------------------------------------------------
/src/components/dialog/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-11-26 15:44:43
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-07 19:36:39
6 | * @FilePath: /uniapp-mp-wx-template/src/components/dialog/index.ts
7 | * @Description: 对话框组件相关工具函数
8 | */
9 |
10 | /** 导出对话框类型 */
11 | export type * from "./Dialog.vue"
12 | /** 导出表单对话框类型 */
13 | export type * from "./FormDialog.vue"
14 |
15 | import { providerComponentOptions } from "@/components"
16 |
17 | import type { IDialogOptions, TDialogCustomKey, TDialogUnmountParam } from "./Dialog.vue"
18 | import type { IFormDialogOptions, TFormDialogCustomKey, TFormDialogUnmountParam } from "./FormDialog.vue"
19 | import type { TFilteredDefaultOptions } from "@/components"
20 |
21 | /** 显示对话框的选项 */
22 | type TShowDialogOptions = TFilteredDefaultOptions
23 |
24 | /** 显示对话框的结果 */
25 | type TShowDialogResult = TDialogUnmountParam
26 |
27 | /**
28 | * 使用对话框
29 | *
30 | * @author dyb-dev
31 | * @date 29/10/2024/ 22:10:25
32 | * @param {TDialogCustomKey} [customKey='__DIALOG__'] - 对话框唯一标识key 默认: `__DIALOG__`
33 | * @returns {*} {TUseDialog} - 对话框相关函数
34 | */
35 | const useDialog = (customKey: string = "") => {
36 |
37 | const _customKey: TDialogCustomKey = `__DIALOG__${customKey}`
38 | const _options = providerComponentOptions(_customKey)
39 |
40 | /**
41 | * 显示对话框
42 | *
43 | * @author dyb-dev
44 | * @date 29/10/2024/ 22:05:36
45 | * @param {TShowDialogOptions} options - 对话框选项
46 | * @returns {*} {Promise} - 显示对话框的结果
47 | */
48 | const showDialog = (options: TShowDialogOptions): Promise => {
49 |
50 | return new Promise(resolve => {
51 |
52 | _options.value = {
53 | ...options,
54 | show: true,
55 | unmount: (...args: TShowDialogResult) => resolve(args)
56 | }
57 |
58 | })
59 |
60 | }
61 | return {
62 | showDialog
63 | }
64 |
65 | }
66 |
67 | /** 显示表单对话框的选项 */
68 | type TShowFormDialogOptions> = TFilteredDefaultOptions>
69 |
70 | /** 显示表单对话框的结果 */
71 | type TShowFormDialogResult> = TFormDialogUnmountParam
72 |
73 | /**
74 | * 使用表单对话框
75 | *
76 | * @author dyb-dev
77 | * @date 29/10/2024/ 22:10:25
78 | * @param {TFormDialogCustomKey} [customKey='__FORM_DIALOG__'] - 表单对话框唯一标识key 默认: `__FORM_DIALOG__`
79 | * @returns {*} {TUseFormDialog} - 表单对话框相关函数
80 | */
81 | const useFormDialog = (customKey: string = "") => {
82 |
83 | const _customKey: TFormDialogCustomKey = `__FORM_DIALOG__${customKey}`
84 | const _options = providerComponentOptions>>(_customKey)
85 |
86 | /**
87 | * 显示表单对话框
88 | *
89 | * @author dyb-dev
90 | * @date 29/10/2024/ 22:05:36
91 | * @param {TShowFormDialogOptions} options - 表单对话框选项
92 | * @returns {*} {Promise>} - 显示表单对话框的结果
93 | */
94 | const showFormDialog = >(
95 | options: TShowFormDialogOptions
96 | ): Promise> => {
97 |
98 | return new Promise(resolve => {
99 |
100 | _options.value = {
101 | ...options,
102 | show: true,
103 | unmount: (...args: TShowFormDialogResult) => resolve(args)
104 | } as IFormDialogOptions>
105 |
106 | })
107 |
108 | }
109 | return {
110 | showFormDialog
111 | }
112 |
113 | }
114 |
115 | export type { TShowDialogOptions, TShowDialogResult, TShowFormDialogOptions }
116 |
117 | export { useDialog, useFormDialog }
118 |
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-01 22:46:34
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-07 21:25:21
6 | * @FilePath: /uniapp-mp-wx-template/src/components/index.ts
7 | * @Description: 组件模块
8 | */
9 |
10 | /** 导出选择器组件相关工具函数 */
11 | export * from "./picker"
12 | /** 导出弹窗组件相关工具函数 */
13 | export * from "./popup"
14 | /** 导出对话框组件相关工具函数 */
15 | export * from "./dialog"
16 | /** 导出用户信息组件相关工具函数 */
17 | export * from "./auth"
18 | /** 导出提供组件选项相关工具函数 */
19 | export * from "./provideComponentOptions"
20 | /** 导出标签&值栏组件 */
21 | export * from "./LabelValueBar.vue"
22 | /** 导出列表组件 */
23 | export * from "./List.vue"
24 | /** 导出表单控件组件 */
25 | export * from "./FormControl.vue"
26 | /** 导出头像昵称组件 */
27 | export * from "./AvatarNickname.vue"
28 | /** 导出单元格组件 */
29 | export * from "./Cell.vue"
30 | /** 导出标签&值栏组件 */
31 | export * from "./LabelValueBar.vue"
32 | /** 导出选项卡面板列表组件 */
33 | export * from "./TabsPaneList.vue"
34 | /** 导出上传文件组件 */
35 | export * from "./Uploader.vue"
36 | /** 导出轮播组件 */
37 | export * from "./SwiperPro.vue"
38 | /** 导出底部操作栏组件 */
39 | export * from "./FooterActionsBar.vue"
40 |
--------------------------------------------------------------------------------
/src/components/layout/Layout.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
152 |
153 |
164 |
165 |
166 |
167 | emits('click-nav-bar-left-icon', clickLeftIconType)"
172 | @click-title="emits('click-nav-bar-title')"
173 | >
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
191 |
192 |
193 |
194 | emits('click-tab-bar-item', item, index)"
201 | />
202 |
203 |
204 |
205 |
206 |
207 |
208 |
234 |
--------------------------------------------------------------------------------
/src/components/layout/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-12-07 19:36:59
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-07 19:37:08
6 | * @FilePath: /uniapp-mp-wx-template/src/components/layout/index.ts
7 | * @Description: 导入相关组件类型
8 | */
9 |
10 | /** 导出页面布局容器类型 */
11 | export type * from "./Layout.vue"
12 | /** 导出顶部导航栏类型 */
13 | export type * from "./NavBar.vue"
14 | /** 导出底部导航栏类型 */
15 | export type * from "./TabBar.vue"
16 |
--------------------------------------------------------------------------------
/src/components/picker/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-11-04 19:51:37
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-07 19:38:42
6 | * @FilePath: /uniapp-mp-wx-template/src/components/picker/index.ts
7 | * @Description: 选择器组件模块
8 | */
9 |
10 | /** 导出选择器组件公共类型 */
11 | export type * from "./type"
12 | /** 导出自定义选择器类型 */
13 | export type * from "./Picker.vue"
14 | /** 导出日期时间选择器类型 */
15 | export type * from "./DateTimePicker.vue"
16 |
17 | import { providerComponentOptions } from "@/components"
18 |
19 | import type { IDateTimePickerOptions, TDateTimePickerCustomKey, TShowDateTimePickerResult } from "./DateTimePicker.vue"
20 | import type { IPickerOptions, TPickerCustomKey } from "./Picker.vue"
21 | import type { TShowPickerBaseResult } from "./type"
22 | import type { TFilteredDefaultOptions } from "@/components"
23 |
24 | /** 显示选择器的选项 */
25 | type TShowPickerOptions = TFilteredDefaultOptions
26 |
27 | /**
28 | * 使用选择器
29 | *
30 | * @author dyb-dev
31 | * @date 04/11/2024/ 21:12:53
32 | * @param {string} [customKey=""] - 弹窗唯一标识key 默认: `__PICKER__`
33 | * @returns {*} {TUsePicker} - 选择器相关函数
34 | */
35 | const usePicker = (customKey: string = "") => {
36 |
37 | const _customKey: TPickerCustomKey = `__PICKER__${customKey}`
38 | const _options = providerComponentOptions(_customKey)
39 |
40 | /**
41 | * 显示选择器
42 | *
43 | * @author dyb-dev
44 | * @date 04/11/2024/ 21:13:25
45 | * @param {TShowPickerOptions} options - 选择器选项
46 | * @returns {*} {Promise} - 显示选择器的结果
47 | */
48 | const showPicker = (options: TShowPickerOptions): Promise => {
49 |
50 | return new Promise(resolve => {
51 |
52 | _options.value = {
53 | ...options,
54 | show: true,
55 | unmount: (...args: TShowPickerBaseResult) => resolve(args)
56 | }
57 |
58 | })
59 |
60 | }
61 | return {
62 | showPicker
63 | }
64 |
65 | }
66 |
67 | /** 显示日期时间选择器的选项 */
68 | type TShowDateTimePickerOptions = TFilteredDefaultOptions
69 |
70 | /**
71 | * 使用日期时间选择器
72 | *
73 | * @author dyb-dev
74 | * @date 04/11/2024/ 21:12:53
75 | * @param {string} [customKey=""] - 弹窗唯一标识key 默认: `__DATE_TIME_PICKER__`
76 | * @returns {*} {TUseDateTimePicker} - 日期时间选择器相关函数
77 | */
78 | const useDateTimePicker = (customKey: string = "") => {
79 |
80 | const _customKey: TDateTimePickerCustomKey = `__DATE_TIME_PICKER__${customKey}`
81 | const _options = providerComponentOptions(_customKey)
82 |
83 | /**
84 | * 显示日期时间选择器
85 | *
86 | * @author dyb-dev
87 | * @date 04/11/2024/ 21:13:25
88 | * @param {TShowDateTimePickerOptions} options - 日期时间选择器选项
89 | * @returns {*} {Promise} - 显示日期时间选择器的结果
90 | */
91 | const showDateTimePicker = (options?: TShowDateTimePickerOptions): Promise => {
92 |
93 | return new Promise(resolve => {
94 |
95 | _options.value = {
96 | ...options,
97 | show: true,
98 | unmount: (...args: TShowDateTimePickerResult) => resolve(args)
99 | }
100 |
101 | })
102 |
103 | }
104 | return {
105 | showDateTimePicker
106 | }
107 |
108 | }
109 |
110 | export type { TShowPickerOptions, TShowDateTimePickerOptions }
111 |
112 | export { usePicker, useDateTimePicker }
113 |
--------------------------------------------------------------------------------
/src/components/picker/type.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-11-04 20:02:48
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-11-04 20:06:35
6 | * @FilePath: /uniapp-mp-wx-template/src/components/picker/type.ts
7 | * @Description: 选择器组件公共类型
8 | */
9 |
10 | import type { PickerBaseEvent } from "nutui-uniapp"
11 |
12 | /** 选择器组件 基础动作类型 */
13 | type TPickerBaseActionType = "click-cancel-button" | "click-confirm-button"
14 |
15 | /** 选择器组件 基础选择结果类型 */
16 | type TPickerBaseSelectedResult = PickerBaseEvent & {
17 | /** 动作类型 */
18 | actionType: TPickerBaseActionType
19 | }
20 |
21 | /** 选择器组件 函数式调用时组件卸载回调参数 基础类型 */
22 | type TPickerBaseUnmountParam = [TPickerBaseSelectedResult]
23 |
24 | /** 选择器组件 函数式调用时基础结果类型 */
25 | type TShowPickerBaseResult = TPickerBaseUnmountParam
26 |
27 | export type { TPickerBaseActionType, TPickerBaseSelectedResult, TPickerBaseUnmountParam, TShowPickerBaseResult }
28 |
--------------------------------------------------------------------------------
/src/components/popup/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-30 20:56:29
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-07 19:39:52
6 | * @FilePath: /uniapp-mp-wx-template/src/components/popup/index.ts
7 | * @Description: 弹窗组件相关工具函数
8 | */
9 |
10 | /** 导出基础弹窗类型 */
11 | export type * from "./Popup.vue"
12 |
13 | import { providerComponentOptions } from "@/components"
14 |
15 | import type { IPopupOptions, TPopupUnmountParam, TPopupCustomKey } from "./Popup.vue"
16 | import type { TFilteredDefaultOptions } from "@/components"
17 |
18 | /** 显示弹窗的选项 */
19 | type TShowPopupOptions = TFilteredDefaultOptions
20 |
21 | /** 显示弹窗的结果 */
22 | type TShowPopupResult = TPopupUnmountParam
23 |
24 | /**
25 | * 使用弹窗
26 | *
27 | * @author dyb-dev
28 | * @date 29/10/2024/ 22:10:25
29 | * @param {TPopupCustomKey} [customKey='__POPUP__'] - 弹窗唯一标识key 默认: `__POPUP__`
30 | * @returns {*} {TUsePopup} - 弹窗相关函数
31 | */
32 | const usePopup = (customKey: string = "") => {
33 |
34 | const _customKey: TPopupCustomKey = `__POPUP__${customKey}`
35 | const _options = providerComponentOptions(_customKey)
36 |
37 | /**
38 | * 显示弹窗
39 | *
40 | * @author dyb-dev
41 | * @date 29/10/2024/ 22:05:36
42 | * @param {TShowPopupOptions} options - 弹窗选项
43 | * @returns {*} {Promise} - 显示弹窗的结果
44 | */
45 | const showPopup = (options: TShowPopupOptions): Promise => {
46 |
47 | return new Promise(resolve => {
48 |
49 | _options.value = {
50 | ...options,
51 | show: true,
52 | unmount: (...args: TShowPopupResult) => resolve(args)
53 | }
54 |
55 | })
56 |
57 | }
58 | return {
59 | showPopup
60 | }
61 |
62 | }
63 |
64 | export type { TShowPopupOptions, TShowPopupResult }
65 |
66 | export { usePopup }
67 |
--------------------------------------------------------------------------------
/src/components/provideComponentOptions.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-30 00:22:30
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-30 21:38:41
6 | * @FilePath: /uniapp-mp-wx-template/src/components/provideComponentOptions.ts
7 | * @Description: 提供组件选项相关工具函数
8 | */
9 |
10 | import { provide, ref } from "vue"
11 |
12 | import type { Ref } from "vue"
13 |
14 | /**
15 | * 默认选项接口
16 | */
17 | interface IDefaultOptions {
18 | /** 是否显示 */
19 | show: boolean
20 | /** 组件唯一标识key */
21 | customKey: string
22 | /** 卸载组件回调 */
23 | unmount: (...args: any[]) => void
24 | }
25 |
26 | /**
27 | * 用于过滤掉默认选项的类型工具
28 | *
29 | * @template Target - 目标类型
30 | */
31 | type TFilteredDefaultOptions = Omit>
32 |
33 | /**
34 | * 提供组件选项
35 | *
36 | * @author dyb-dev
37 | * @date 29/10/2024/ 21:55:37
38 | * @param {Key} customKey - 组件唯一标识key
39 | * @returns {*} {Ref} - 组件选项
40 | */
41 | const providerComponentOptions = = Record>(
42 | customKey: Key
43 | ): Ref => {
44 |
45 | const _options = ref({}) as Ref
46 |
47 | provide(customKey, _options as any)
48 |
49 | return _options
50 |
51 | }
52 |
53 | export type { IDefaultOptions, TFilteredDefaultOptions }
54 |
55 | export { providerComponentOptions }
56 |
--------------------------------------------------------------------------------
/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-06 23:32:48
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:01:42
6 | * @FilePath: /uniapp-mp-wx-template/src/constants/index.ts
7 | * @Description: 常量模块
8 | */
9 |
10 | /** 导出用户信息常量模块 */
11 | export * from "./userInfo"
12 |
--------------------------------------------------------------------------------
/src/constants/userInfo.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:01:57
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:02:04
6 | * @FilePath: /uniapp-mp-wx-template/src/constants/userInfo.ts
7 | * @Description: 用户信息常量模块
8 | */
9 |
10 | import { ECertificatesType, EGenderType } from "@/types"
11 |
12 | /** CONST: 性别配置列表 */
13 | const GENDER_CONFIG_LIST = [
14 | { type: EGenderType.Man, desc: "男" },
15 | { type: EGenderType.Woman, desc: "女" }
16 | ]
17 |
18 | /** CONST: 证件配置列表 */
19 | const CERTIFICATE_CONFIG_LIST = [
20 | { type: ECertificatesType.IdCard, desc: "身份证" },
21 | { type: ECertificatesType.MilitaryCard, desc: "军人证" },
22 | { type: ECertificatesType.Passport, desc: "护照" },
23 | { type: ECertificatesType.BirthCertificate, desc: "出生证" },
24 | { type: ECertificatesType.HkMoTwPass, desc: "港澳台通行证" },
25 | { type: ECertificatesType.SoldierCard, desc: "士兵证" },
26 | { type: ECertificatesType.PoliceCard, desc: "警官证" },
27 | { type: ECertificatesType.HkMoTwResidentPermit, desc: "港澳台居民居住证" },
28 | { type: ECertificatesType.ForeignerPermanentResidentIdCard, desc: "外国人永久居留身份证" },
29 | { type: ECertificatesType.ResidentAccountBook, desc: "居民户口薄" }
30 | ]
31 |
32 | export { GENDER_CONFIG_LIST, CERTIFICATE_CONFIG_LIST }
33 |
--------------------------------------------------------------------------------
/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-08 12:02:08
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-05-28 23:47:42
6 | * @FilePath: /uniapp-mp-wx-template/src/hooks/index.ts
7 | * @Description: hook模块
8 | */
9 |
10 | /** 导出分页相关hook */
11 | export * from "./pagination"
12 | /** 导出分享相关hook */
13 | export * from "./share"
14 | /** 导出时间控制相关hooks函数 */
15 | export * from "./timer"
16 |
--------------------------------------------------------------------------------
/src/hooks/pagination/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-11-16 02:11:23
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-11-16 02:11:32
6 | * @FilePath: /uniapp-mp-wx-template/src/hooks/pagination/index.ts
7 | * @Description: 分页hooks模块
8 | */
9 |
10 | // 导出分页器
11 | export * from "./usePagination"
12 | // 导出列表分页器
13 | export * from "./useListPagination"
14 |
--------------------------------------------------------------------------------
/src/hooks/pagination/useListPagination.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-11-16 02:11:23
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-11-19 15:19:20
6 | * @FilePath: /uniapp-mp-wx-template/src/hooks/pagination/useListPagination.ts
7 | * @Description: 列表分页器
8 | */
9 |
10 | import { usePagination } from "./usePagination"
11 |
12 | import type { IUsePaginationOptions, IUsePaginationReturn, TPaginationDataItem } from "./usePagination"
13 |
14 | /** 列表分页配置,继承自 IUsePaginationOptions */
15 | interface IUseListPaginationOptions
16 | extends Omit, "usePreviousDataOnFail"> {}
17 |
18 | /** 列表分页返回结果,继承自 IUsePaginationReturn */
19 | interface IUseListPaginationReturn extends Omit, "refresh" | "prev"> {
20 | /** 清空所有数据并刷新首页 */
21 | clearRefresh: () => Promise
22 | /** 清空所有数据并初始化分页器 */
23 | clearInitialize: () => Promise
24 | }
25 |
26 | /**
27 | * 列表分页器
28 | *
29 | * @author dyb-dev
30 | * @date 05/09/2024/ 14:19:07
31 | * @template T 列表分页数据类型
32 | * @param {IUseListPaginationOptions} options 列表分页配置
33 | * @returns {*} {IUseListPaginationReturn} 列表分页返回结果
34 | */
35 | const useListPagination = (options: IUseListPaginationOptions): IUseListPaginationReturn => {
36 |
37 | // 调用 usePagination 并传入参数
38 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
39 | const { refresh, prev, ..._pagination } = usePagination(options)
40 |
41 | /**
42 | * 清空重置分页数据和状态
43 | *
44 | * @author dyb-dev
45 | * @date 16/11/2024/ 00:53:21
46 | */
47 | const _clear = () => {
48 |
49 | _pagination.currentTotalDataMap.value.clear()
50 | _pagination.totalSize.value = 0
51 | _pagination.initialized.value = false
52 |
53 | }
54 |
55 | /**
56 | * 清空所有数据并初始化分页器
57 | *
58 | * @author dyb-dev
59 | * @date 16/11/2024/ 00:53:54
60 | */
61 | const clearInitialize = async() => {
62 |
63 | try {
64 |
65 | _clear()
66 | await _pagination.load(1)
67 |
68 | }
69 | catch (error) {
70 |
71 | throw `clearInitialize() ${error}`
72 |
73 | }
74 |
75 | }
76 |
77 | /**
78 | * 清空所有数据并刷新首页
79 | *
80 | * @author dyb-dev
81 | * @date 06/09/2024/ 22:24:56
82 | */
83 | const clearRefresh = async() => {
84 |
85 | try {
86 |
87 | _clear()
88 | await refresh(1)
89 |
90 | }
91 | catch (error) {
92 |
93 | throw `clearRefresh() ${error}`
94 |
95 | }
96 |
97 | }
98 |
99 | /**
100 | * 列表分页的下一页逻辑
101 | *
102 | * @author dyb
103 | * @date 05/09/2024/ 13:16:57
104 | */
105 | const next = async() => {
106 |
107 | try {
108 |
109 | const { initialized, currentLoadStatus, currentPage, finished } = _pagination
110 |
111 | if (!initialized.value) {
112 |
113 | console.warn("next() 初始化未完成取消执行下一页,开始执行初始化操作")
114 | await clearInitialize()
115 | return
116 |
117 | }
118 | if (finished.value) {
119 |
120 | console.warn(`next() 已经加载完所有数据,无法执行下一页 currentPage: ${currentPage.value}`)
121 | return
122 |
123 | }
124 | if (currentLoadStatus.value === "loading") {
125 |
126 | console.warn(
127 | `next() 当前页码数据正在加载中,取消执行下一页 currentPage: ${currentPage.value} currentLoadStatus: ${currentLoadStatus.value}`
128 | )
129 | return
130 |
131 | }
132 | if (currentLoadStatus.value === "fail") {
133 |
134 | console.warn(
135 | `next() 当前页码数据加载失败,取消执行下一页,开始重新加载当前页数据 currentPage: ${currentPage.value} currentLoadStatus: ${currentLoadStatus.value}`
136 | )
137 |
138 | // 加载失败,重新加载当前页码数据
139 | await _pagination.load()
140 | return
141 |
142 | }
143 | await _pagination.next()
144 |
145 | }
146 | catch (error) {
147 |
148 | throw `next() ${error}`
149 |
150 | }
151 |
152 | }
153 |
154 | return {
155 | ..._pagination,
156 | clearInitialize,
157 | clearRefresh,
158 | next
159 | }
160 |
161 | }
162 |
163 | export type { IUseListPaginationOptions, IUseListPaginationReturn }
164 |
165 | export { useListPagination }
166 |
--------------------------------------------------------------------------------
/src/hooks/share/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-30 12:28:29
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-30 12:28:45
6 | * @FilePath: /uniapp-mp-wx-template/src/hooks/share/index.ts
7 | * @Description: 分享相关hook
8 | */
9 |
10 | import { useUserInfoStoreWithOut } from "@/stores"
11 | import { setUrlQueryValue } from "@/utils"
12 |
13 | /** 分享配置 */
14 | interface IShareConfig extends Page.CustomShareContent {
15 | /**
16 | * 转发路径,必须是以 / 开头的完整路径。默认值:当前页面 path
17 | */
18 | path?: NavigateToOptions["url"]
19 | /**
20 | * 邀请用户ID
21 | */
22 | inviteUserId?: string
23 | /**
24 | * 来源
25 | */
26 | source?: string
27 | }
28 |
29 | /** CONST: 默认分享配置 */
30 | const DEFAULT_SHARE_CONFIG: IShareConfig = {
31 | title: "祝您前程似锦,未来可期!",
32 | imageUrl: "/static/image/share.jpg"
33 | }
34 |
35 | // HOOKS: 使用用户信息Store
36 | const { userInfoStoreState } = useUserInfoStoreWithOut()
37 |
38 | /**
39 | * FUN: 使用分享
40 | *
41 | * @author dyb-dev
42 | * @date 30/10/2024/ 12:29:17
43 | * @param {IShareConfig} [shareConfig] 分享配置
44 | * @returns {*} {Page.CustomShareContent} 分享配置
45 | */
46 | const useShare = (shareConfig?: IShareConfig): Page.CustomShareContent => {
47 |
48 | /** 当前分享配置 */
49 | const _shareConfig = { ...DEFAULT_SHARE_CONFIG, ...shareConfig }
50 |
51 | let _path = _shareConfig.path || "/" + __PROJECT_INFO__.env.VITE_HOME_PATH
52 |
53 | /** 邀请用户ID */
54 | const _inviteUserId = _shareConfig.inviteUserId ?? userInfoStoreState.userId
55 | if (_inviteUserId) {
56 |
57 | _path = setUrlQueryValue(_path, "inviteUserId", _inviteUserId)
58 | delete _shareConfig.inviteUserId
59 |
60 | }
61 |
62 | // 来源
63 | const _source = _shareConfig.source ?? "share"
64 | if (_source) {
65 |
66 | _path = setUrlQueryValue(_path, "source", _source)
67 | delete _shareConfig.source
68 |
69 | }
70 |
71 | _shareConfig.path = _path as NavigateToOptions["url"]
72 |
73 | return _shareConfig
74 |
75 | }
76 |
77 | export { useShare }
78 |
--------------------------------------------------------------------------------
/src/hooks/timer/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-05-28 23:47:05
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-05-28 23:47:15
6 | * @FilePath: /uniapp-mp-wx-template/src/hooks/timer/index.ts
7 | * @Description: 时间控制相关hooks函数
8 | */
9 |
10 | /** 使用轮询器返回值 */
11 | export interface IUsePollingReturn {
12 | /** 开始轮询 */
13 | start: () => void
14 | /** 停止轮询 */
15 | stop: () => void
16 | }
17 |
18 | /**
19 | * FUN: 使用轮询器
20 | *
21 | * @author dyb-dev
22 | * @date 28/05/2025/ 23:01:57
23 | * @param {(() => boolean | void | Promise)} callback 回调函数
24 | * @param {number} [interval=1000] 轮询间隔,默认为 1000ms
25 | * @returns {*} {IUsePollingReturn} 返回值
26 | */
27 | export const usePolling = (
28 | callback: () => boolean | void | Promise,
29 | interval: number = 1000
30 | ): IUsePollingReturn => {
31 |
32 | /** 轮询器 */
33 | let _timer: TTimeoutId
34 | /** 是否轮询中 */
35 | let _polling: boolean = false
36 |
37 | /** 启动轮询 */
38 | const start = () => {
39 |
40 | // 如果已经在轮询中,不重复启动
41 | if (_polling) {
42 |
43 | return
44 |
45 | }
46 |
47 | _polling = true
48 |
49 | const _poll = async() => {
50 |
51 | try {
52 |
53 | // 执行回调函数,判断是否需要继续轮询
54 | const _isStop = await callback()
55 |
56 | if (!_isStop) {
57 |
58 | // 如果不需要停止,继续轮询
59 | _timer = setTimeout(() => {
60 |
61 | _poll()
62 |
63 | }, interval)
64 | return
65 |
66 | }
67 |
68 | stop()
69 |
70 | }
71 | catch (error) {
72 |
73 | stop()
74 | console.error("usePolling()", error)
75 |
76 | }
77 |
78 | }
79 |
80 | _poll()
81 |
82 | }
83 |
84 | /** 停止轮询 */
85 | const stop = () => {
86 |
87 | clearTimeout(_timer)
88 | _polling = false
89 |
90 | }
91 |
92 | return { start, stop }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 20:10:08
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:43:32
6 | * @FilePath: /uniapp-mp-wx-template/src/main.ts
7 | * @Description: 程序入口文件
8 | */
9 |
10 | import { createSSRApp } from "vue"
11 |
12 | import App from "@/App.vue"
13 | import { setupRouterInterceptor } from "@/routerInterceptor"
14 | import { store } from "@/stores"
15 |
16 | import { setupApi } from "./apis"
17 |
18 | export function createApp() {
19 |
20 | const app = createSSRApp(App)
21 | // 使用商店
22 | app.use(store)
23 | // 初始化接口配置
24 | setupApi()
25 | // 初始化路由拦截器
26 | setupRouterInterceptor()
27 |
28 | return {
29 | app
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniapp-mp-wx-template",
3 | "appid": "",
4 | "description": "基于`uni-app + vue3 + ts`搭建的微信小程序模板",
5 | "versionName": "1.1.5",
6 | "versionCode": "100",
7 | "transformPx": false,
8 | "app-plus": {
9 | "usingComponents": true,
10 | "nvueStyleCompiler": "uni-app",
11 | "compilerVersion": 3,
12 | "splashscreen": {
13 | "alwaysShowBeforeRender": true,
14 | "waiting": true,
15 | "autoclose": true,
16 | "delay": 0
17 | },
18 | "modules": {},
19 | "distribute": {
20 | "android": {
21 | "permissions": []
22 | },
23 | "ios": {},
24 | "sdkConfigs": {}
25 | }
26 | },
27 | "quickapp": {},
28 | "mp-weixin": {
29 | "appid": "",
30 | "setting": {
31 | "urlCheck": false,
32 | "es6": true,
33 | "postcss": true,
34 | "minified": true,
35 | "bigPackageSizeSupport": true
36 | },
37 | "usingComponents": true,
38 | "lazyCodeLoading": "requiredComponents",
39 | "mergeVirtualHostAttributes": true,
40 | "optimization": {
41 | "subPackages": true
42 | }
43 | },
44 | "mp-alipay": {
45 | "usingComponents": true
46 | },
47 | "mp-baidu": {
48 | "usingComponents": true
49 | },
50 | "mp-toutiao": {
51 | "usingComponents": true
52 | },
53 | "uniStatistics": {
54 | "enable": false
55 | },
56 | "vueVersion": "3"
57 | }
--------------------------------------------------------------------------------
/src/pages.json:
--------------------------------------------------------------------------------
1 | {
2 | "globalStyle": {
3 | "navigationStyle": "custom",
4 | "navigationBarTextStyle": "black",
5 | "navigationBarBackgroundColor": "#ffffff",
6 | "backgroundColor": "#ffffff",
7 | "disableScroll": true
8 | },
9 | "pages": [
10 | {
11 | "path": "pages/home",
12 | "type": "home",
13 | "style": {
14 | "navigationBarTitleText": "首页"
15 | }
16 | },
17 | {
18 | "path": "pages/launch",
19 | "type": "page",
20 | "style": {}
21 | },
22 | {
23 | "path": "pages/list",
24 | "type": "page",
25 | "style": {
26 | "navigationBarTitleText": "列表"
27 | }
28 | },
29 | {
30 | "path": "pages/login",
31 | "type": "page",
32 | "style": {
33 | "navigationBarTitleText": "登录"
34 | }
35 | },
36 | {
37 | "path": "pages/my",
38 | "type": "page",
39 | "style": {
40 | "navigationBarTitleText": "我的"
41 | },
42 | "needLogin": true
43 | },
44 | {
45 | "path": "pages/test",
46 | "type": "page",
47 | "style": {
48 | "navigationBarTitleText": "测试",
49 | "disableScroll": false,
50 | "enablePullDownRefresh": true
51 | },
52 | "needLogin": true
53 | }
54 | ],
55 | "condition": {
56 | "current": 0,
57 | "list": [
58 | {
59 | "name": "启动页",
60 | "path": "pages/launch",
61 | "query": "targetPath=/pages/test&test=测试启动参数"
62 | },
63 | {
64 | "name": "首页",
65 | "path": "pages/home",
66 | "query": "test=首页"
67 | },
68 | {
69 | "name": "我的",
70 | "path": "pages/my"
71 | },
72 | {
73 | "name": "测试",
74 | "path": "pages/test"
75 | }
76 | ]
77 | },
78 | "tabBar": {
79 | "custom": true,
80 | "color": "#7d7e80",
81 | "selectedColor": "#29d446",
82 | "list": [
83 | {
84 | "pagePath": "pages/home",
85 | "text": "首页",
86 | "iconfont": {
87 | "text": "home",
88 | "selectedText": "home"
89 | }
90 | },
91 | {
92 | "pagePath": "pages/list",
93 | "text": "列表",
94 | "iconfont": {
95 | "text": "dongdong",
96 | "selectedText": "dongdong"
97 | }
98 | },
99 | {
100 | "pagePath": "pages/my",
101 | "text": "我的",
102 | "iconfont": {
103 | "text": "my",
104 | "selectedText": "my"
105 | }
106 | }
107 | ]
108 | },
109 | "subPackages": [
110 | {
111 | "root": "subPackages/webview",
112 | "pages": [
113 | {
114 | "path": "pages/webview",
115 | "type": "page",
116 | "style": {}
117 | }
118 | ]
119 | }
120 | ],
121 | "preloadRule": {
122 | "pages/home": {
123 | "packages": [
124 | "subPackages/webview"
125 | ]
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/pages/home.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | Hello World!
62 |
63 |
64 | 跳转测试页面
65 | 跳转webview页面
66 |
67 |
68 |
69 |
70 |
71 |
93 |
--------------------------------------------------------------------------------
/src/pages/launch.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
81 |
82 |
83 |
84 |
85 | 正在启动...
86 |
87 |
88 |
89 |
107 |
--------------------------------------------------------------------------------
/src/pages/list.vue:
--------------------------------------------------------------------------------
1 |
9 |
66 |
67 |
68 |
69 |
70 |
71 |
77 | {{ item }}
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/src/pages/login.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
130 |
131 |
132 |
133 |
134 |
135 |
144 |
145 |
153 |
154 | 获取验证码
155 |
156 |
157 |
158 |
166 |
167 | 登录
174 |
175 |
176 |
177 |
178 |
179 |
204 |
--------------------------------------------------------------------------------
/src/pages/my.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | {{ userInfoStoreState.nickName }}
31 |
32 | 授权头像昵称
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
52 |
--------------------------------------------------------------------------------
/src/pages/test.vue:
--------------------------------------------------------------------------------
1 |
93 |
94 |
95 |
96 |
97 | 这是一个测试页面,⬇️下拉页面刷新
98 |
99 |
100 | 获取userId
101 | userId: {{ userId }}
102 |
103 |
104 |
105 | 获取id
106 | id: {{ id }}
107 |
108 |
109 |
110 |
111 |
112 |
126 |
--------------------------------------------------------------------------------
/src/routerInterceptor/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 14:01:47
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:41:43
6 | * @FilePath: /uniapp-mp-wx-template/src/routerInterceptor/index.ts
7 | * @Description: 路由拦截器模块
8 | */
9 |
10 | import queryString from "query-string"
11 |
12 | import { setupLoginPreInterceptor } from "./login"
13 |
14 | /**
15 | * 路由Invoke参数
16 | */
17 | interface IRouterInvokeParams {
18 | /** url 调用除了`uni.navigateBack`方法时才有此参数 */
19 | url?: string
20 | /** 返回层级 调用`uni.navigateBack`方法时才有此参数 */
21 | delta?: number
22 | }
23 |
24 | /**
25 | * 路由前置拦截器参数
26 | */
27 | interface IRouterPreInterceptorParams {
28 | /** 目标路径 */
29 | path: string
30 | /** 目标路由参数 */
31 | query: Record
32 | /** 返回层级 */
33 | delta: number
34 | }
35 |
36 | /** 路由前置拦截器函数 */
37 | type TRouterPreInterceptor = (params: IRouterPreInterceptorParams) => boolean
38 |
39 | /**
40 | * FUN: 设置路由拦截器
41 | *
42 | * @author dyb-dev
43 | * @date 02/10/2024/ 15:03:56
44 | */
45 | const setupRouterInterceptor = () => {
46 |
47 | const _options: UniNamespace.InterceptorOptions = {
48 | // 前置拦截器
49 | invoke({ url = "", delta = 0 }: IRouterInvokeParams) {
50 |
51 | /** url解析结果 */
52 | const _parseResult = queryString.parseUrl(url)
53 | /** 路由前置拦截器参数 */
54 | const _params: IRouterPreInterceptorParams = {
55 | path: _parseResult.url,
56 | query: _parseResult.query,
57 | delta
58 | }
59 |
60 | /** 是否继续执行 */
61 | let isNext = true
62 |
63 | isNext = setupLoginPreInterceptor(_params)
64 |
65 | return isNext
66 |
67 | }
68 | // 后置拦截器(一般用不到)
69 | // returnValue() {
70 |
71 | // }
72 | }
73 |
74 | uni.addInterceptor("navigateTo", _options)
75 | uni.addInterceptor("redirectTo", _options)
76 | uni.addInterceptor("reLaunch", _options)
77 | uni.addInterceptor("switchTab", _options)
78 | uni.addInterceptor("navigateBack", _options)
79 |
80 | }
81 |
82 | export { setupRouterInterceptor }
83 |
84 | export type { IRouterPreInterceptorParams, TRouterPreInterceptor }
85 |
--------------------------------------------------------------------------------
/src/routerInterceptor/login.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-02 14:51:37
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-11 17:10:45
6 | * @FilePath: /uniapp-mp-wx-template/src/interceptors/router/login.ts
7 | * @Description: 登录拦截器模块
8 | */
9 |
10 | import { useUserInfoStoreWithOut } from "@/stores"
11 | import { getPageConfig, navigateToLogin } from "@/utils"
12 |
13 | import type { TRouterPreInterceptor } from "."
14 |
15 | /** CONST: 用户信息Store */
16 | const { userInfoStoreState } = useUserInfoStoreWithOut()
17 |
18 | /**
19 | * FUN: 设置登录前置拦截器
20 | *
21 | * @author dyb-dev
22 | * @date 02/10/2024/ 14:54:31
23 | * @param {string} url - 路由路径
24 | * @returns {*} 是否继续执行
25 | */
26 | const setupLoginPreInterceptor: TRouterPreInterceptor = ({ path, query }) => {
27 |
28 | // 如果是没有登录且需要登录的页面,跳转到登录页
29 | if (!userInfoStoreState.isLogin && getPageConfig(path)?.needLogin) {
30 |
31 | navigateToLogin({
32 | redirectPath: path as NavigateToOptions["url"],
33 | query,
34 | findBackDelta: false
35 | })
36 | return false
37 |
38 | }
39 |
40 | return true
41 |
42 | }
43 |
44 | export { setupLoginPreInterceptor }
45 |
--------------------------------------------------------------------------------
/src/static/image/List/back-top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/List/back-top.png
--------------------------------------------------------------------------------
/src/static/image/List/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/List/empty.png
--------------------------------------------------------------------------------
/src/static/image/layout/TabBar/icon1-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/layout/TabBar/icon1-off.png
--------------------------------------------------------------------------------
/src/static/image/layout/TabBar/icon1-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/layout/TabBar/icon1-on.png
--------------------------------------------------------------------------------
/src/static/image/layout/TabBar/icon2-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/layout/TabBar/icon2-off.png
--------------------------------------------------------------------------------
/src/static/image/layout/TabBar/icon2-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/layout/TabBar/icon2-on.png
--------------------------------------------------------------------------------
/src/static/image/mp_wx.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/static/image/popup/Popup/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/popup/Popup/close.png
--------------------------------------------------------------------------------
/src/static/image/share.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/share.jpg
--------------------------------------------------------------------------------
/src/static/image/uniapp.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyb-dev/uniapp-mp-wx-template/2aa2f2cb1ef032b8013e9e830b9f5f6777647877/src/static/image/uniapp.ico
--------------------------------------------------------------------------------
/src/stores/activity.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 21:40:38
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-13 21:24:10
6 | * @FilePath: /uniapp-mp-wx-template/src/stores/activity.ts
7 | * @Description: 活动状态管理
8 | */
9 |
10 | import { defineStore } from "pinia"
11 | import { reactive } from "vue"
12 |
13 | import { store } from "."
14 |
15 | /** Store 状态类型 */
16 | interface IActivityStoreState {
17 | count: number
18 | }
19 |
20 | /** Store 实例 */
21 | const useActivityStore = defineStore(
22 | "ActivityStore",
23 | () => {
24 |
25 | /** Store 状态 */
26 | const activityStoreState = reactive({
27 | count: 0
28 | })
29 |
30 | return { activityStoreState }
31 |
32 | }
33 | // {
34 | // // 配置持久化状态,如果不需要可以删除掉 或 设置为false
35 | // persist: {
36 | // // 指定需要持久化的状态
37 | // pick: ['state.count']
38 | // }
39 | // }
40 | )
41 |
42 | /**
43 | * FUN: 使用状态管理
44 | * - 在没有Vue组件上下文的情况下使用
45 | *
46 | * @author dyb-dev
47 | * @date 15/09/2024/ 23:53:35
48 | * @returns store实例
49 | */
50 | const useActivityStoreWithOut = () => {
51 |
52 | return useActivityStore(store)
53 |
54 | }
55 |
56 | export { useActivityStore, useActivityStoreWithOut }
57 |
--------------------------------------------------------------------------------
/src/stores/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 21:26:18
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-15 13:51:26
6 | * @FilePath: /uniapp-mp-wx-template/src/stores/index.ts
7 | * @Description: store模块
8 | */
9 |
10 | export * from "./activity"
11 | export * from "./tabBar"
12 | export * from "./userInfo"
13 |
14 | import { createPinia } from "pinia"
15 | import { createPersistedState } from "pinia-plugin-persistedstate"
16 |
17 | /** store 实例 */
18 | const store = createPinia()
19 |
20 | // 使用全局持久化状态插件
21 | store.use(
22 | createPersistedState({
23 | // 设置全局存储键名 默认: store名称
24 | key: id => `persisted_${id}`,
25 | // 设置全局存储方式 默认: localStorage
26 | storage: {
27 | getItem: uni.getStorageSync,
28 | setItem: uni.setStorageSync
29 | }
30 | })
31 | )
32 |
33 | export { store }
34 |
--------------------------------------------------------------------------------
/src/stores/tabBar.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 21:49:17
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-13 21:24:32
6 | * @FilePath: /uniapp-mp-wx-template/src/stores/tabBar.ts
7 | * @Description: TabBar状态管理
8 | */
9 |
10 | import { defineStore } from "pinia"
11 | import { reactive } from "vue"
12 |
13 | import pagesJson from "@/pages.json"
14 | import { getCurrentPagePath } from "@/utils"
15 |
16 | import type { TTabBarItem } from "@/components/layout/TabBar.vue"
17 | import type { TabBarItem } from "@uni-helper/vite-plugin-uni-pages"
18 |
19 | import { store } from "."
20 |
21 | /** Store 状态类型 */
22 | type TTabBarStoreState = {
23 | /** 当前TabBar索引 */
24 | currentIndex: number
25 | /** TabBar 列表 */
26 | list: TTabBarItem[]
27 | }
28 |
29 | /** Store 实例 */
30 | const useTabBarStore = defineStore("TabBarStore", () => {
31 |
32 | /** Store State */
33 | const tabBarStoreState = reactive({
34 | currentIndex: 0,
35 | list:
36 | // @ts-ignore
37 | pagesJson?.tabBar?.list.map((item: TabBarItem) => {
38 |
39 | return {
40 | ...item,
41 | // 优先级: 图标 > 图片路径
42 | // @ts-ignore
43 | icon: item?.iconfont?.text || item?.iconPath || "",
44 | // @ts-ignore
45 | selectedIcon: item?.iconfont?.selectedText || item?.selectedIconPath || "",
46 | classPrefix: "nut-icon",
47 | fontClassName: "nutui-iconfont",
48 | showDot: false,
49 | dotValue: 0
50 | } as TTabBarItem
51 |
52 | }) || []
53 | })
54 |
55 | /**
56 | * FUN: 获取指定 TabBarItem
57 | *
58 | * @author dyb-dev
59 | * @date 25/09/2024/ 17:41:06
60 | * @param {string} pagePath 页面路径
61 | * @returns {*} TabBarItem配置
62 | */
63 | const getTabBarItem = (pagePath: string) => tabBarStoreState.list.find(item => item.pagePath === pagePath)
64 |
65 | /**
66 | * FUN: 获取当前 TabBarItem
67 | *
68 | * @author dyb-dev
69 | * @date 25/09/2024/ 17:41:55
70 | * @returns {*} 当前TabBarItem配置
71 | */
72 | const getCurrentTabBarItem = () => getTabBarItem(getCurrentPagePath())
73 |
74 | /**
75 | * FUN: 获取 TabBar 索引
76 | *
77 | * @author dyb-dev
78 | * @date 09/10/2024/ 12:29:36
79 | * @param {string} pagePath 页面路径
80 | * @returns {*} TabBar 索引
81 | */
82 | const getTabBarIndex = (pagePath: string) => tabBarStoreState.list.findIndex(item => item.pagePath === pagePath)
83 |
84 | /**
85 | * FUN: 获取当前 TabBar 索引
86 | *
87 | * @author dyb-dev
88 | * @date 25/09/2024/ 17:42:12
89 | * @returns {*} 当前 TabBar 索引
90 | */
91 | const getCurrentTabBarIndex = () => getTabBarIndex(getCurrentPagePath())
92 |
93 | /**
94 | * FUN: 更新当前 TabBar 索引
95 | *
96 | * @author dyb-dev
97 | * @date 09/10/2024/ 12:34:31
98 | */
99 | const updateCurrentTabBarIndex = () => {
100 |
101 | /** 获取当前TabBar索引 */
102 | const _currentTabBarIndex = getCurrentTabBarIndex()
103 | // 只有在当前TabBar索引大于等于0时才会设置
104 | if (_currentTabBarIndex >= 0) {
105 |
106 | tabBarStoreState.currentIndex = _currentTabBarIndex
107 |
108 | }
109 |
110 | }
111 |
112 | return {
113 | tabBarStoreState,
114 | getTabBarItem,
115 | getCurrentTabBarItem,
116 | getTabBarIndex,
117 | getCurrentTabBarIndex,
118 | updateCurrentTabBarIndex
119 | }
120 |
121 | })
122 |
123 | /**
124 | * 使用状态管理
125 | * - 在没有Vue组件上下文的情况下使用
126 | *
127 | * @author dyb-dev
128 | * @date 15/09/2024/ 23:53:35
129 | * @returns store实例
130 | */
131 | const useTabBarStoreWithOut = () => {
132 |
133 | return useTabBarStore(store)
134 |
135 | }
136 |
137 | export { useTabBarStore, useTabBarStoreWithOut }
138 |
--------------------------------------------------------------------------------
/src/stores/userInfo.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-06 14:42:41
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 23:06:25
6 | * @FilePath: /uniapp-mp-wx-template/src/stores/userInfo.ts
7 | * @Description: 用户信息状态管理
8 | */
9 |
10 | import { defineStore } from "pinia"
11 | import { reactive } from "vue"
12 |
13 | import { getPhoneNumberApi, loginApi, uploadAvatarApi, uploadUserInfoApi } from "@/apis"
14 |
15 | import type { IGetPhoneNumberApiParams, IUploadAvatarApiParams, IUploadUserInfoApiParams } from "@/apis"
16 |
17 | import { store } from "."
18 |
19 | /** Store 状态类型 */
20 | interface IUserInfoStoreState {
21 | /**
22 | * 是否登录成功
23 | */
24 | isLogin: boolean
25 | /**
26 | * 用户在我们系统中的加密用户代码
27 | */
28 | userId: string
29 | /**
30 | * 由微信生成的用户在开放平台的唯一标识符
31 | */
32 | unionId: string
33 | /**
34 | * 由微信生成的用户在本小程序唯一标识
35 | */
36 | openId: string
37 | /**
38 | * 用户的微信昵称
39 | */
40 | nickName: string
41 | /**
42 | * 用户的微信头像
43 | */
44 | avatarUrl: string
45 | /**
46 | * 用户的微信绑定手机号(不带区号的手机号)
47 | */
48 | phoneNumber: string
49 | }
50 |
51 | /** Store 实例 */
52 | const useUserInfoStore = defineStore("UserInfoStore", () => {
53 |
54 | /** Store 状态 */
55 | const userInfoStoreState = reactive({
56 | isLogin: false,
57 |
58 | userId: "",
59 | unionId: "",
60 | openId: "",
61 |
62 | nickName: "",
63 | avatarUrl: "",
64 | phoneNumber: ""
65 | })
66 |
67 | /**
68 | * FUN: 微信登录
69 | *
70 | * @author dyb-dev
71 | * @date 09/10/2024/ 17:02:42
72 | * @returns {*} 微信登录结果
73 | */
74 | const wxLogin = (): Promise => {
75 |
76 | return new Promise(resolve => {
77 |
78 | wx.login({
79 | success: res => resolve(res),
80 | fail: err => resolve(err)
81 | })
82 |
83 | })
84 |
85 | }
86 |
87 | /**
88 | * FUN: 登录
89 | *
90 | * @author dyb-dev
91 | * @date 09/10/2024/ 17:02:57
92 | */
93 | const login = async() => {
94 |
95 | try {
96 |
97 | uni.showLoading({ title: "正在登录...", mask: true })
98 |
99 | const _wxLoginResult = await wxLogin()
100 |
101 | // @ts-ignore
102 | const _code = _wxLoginResult?.code || ""
103 |
104 | // 如果没有code
105 | if (!_code) {
106 |
107 | throw _wxLoginResult.errMsg
108 |
109 | }
110 |
111 | const _loginApiResult = await loginApi(
112 | { code: _code },
113 | {
114 | testResult: {
115 | success: true,
116 | message: "登录成功",
117 | data: {
118 | userId: "userId",
119 | unionId: "unionId",
120 | openId: "openId",
121 | nickName: "xxx",
122 | avatarUrl:
123 | "https://img12.360buyimg.com/imagetools/jfs/t1/196430/38/8105/14329/60c806a4Ed506298a/e6de9fb7b8490f38.png",
124 | phoneNumber: "111111111"
125 | }
126 | }
127 | }
128 | )
129 |
130 | uni.hideLoading()
131 |
132 | // 如果登录失败
133 | if (!_loginApiResult.success || !_loginApiResult.data) {
134 |
135 | throw _loginApiResult.message
136 |
137 | }
138 |
139 | const {
140 | data: { userId = "", unionId = "", openId = "", nickName = "", avatarUrl = "", phoneNumber = "" }
141 | } = _loginApiResult
142 |
143 | userInfoStoreState.userId = userId
144 | userInfoStoreState.unionId = unionId
145 | userInfoStoreState.openId = openId
146 | userInfoStoreState.nickName = nickName
147 | userInfoStoreState.avatarUrl = avatarUrl
148 | userInfoStoreState.phoneNumber = phoneNumber
149 |
150 | userInfoStoreState.isLogin = true
151 |
152 | }
153 | catch (error) {
154 |
155 | uni.hideLoading()
156 | console.error("login()", error)
157 |
158 | uni.showModal({
159 | title: "提示",
160 | content: "登录失败,请稍后重试!",
161 | showCancel: false
162 | })
163 |
164 | }
165 |
166 | }
167 |
168 | /**
169 | * FUN: 获取手机号
170 | *
171 | * @author dyb-dev
172 | * @date 09/10/2024/ 20:22:11
173 | * @param {IGetPhoneNumberApiParams} params 参数
174 | * @returns {*} 获取手机号结果
175 | */
176 | const getPhoneNumber = async(params: IGetPhoneNumberApiParams) => {
177 |
178 | const _result = await getPhoneNumberApi(params, {
179 | testResult: {
180 | success: true,
181 | message: "获取手机号成功",
182 | data: {
183 | phoneNumber: "111111111"
184 | }
185 | }
186 | })
187 |
188 | // 如果获取成功
189 | if (_result.success && _result.data?.phoneNumber) {
190 |
191 | userInfoStoreState.phoneNumber = _result.data.phoneNumber
192 |
193 | }
194 |
195 | return _result
196 |
197 | }
198 |
199 | /**
200 | * FUN: 上传头像
201 | *
202 | * @author dyb-dev
203 | * @date 09/10/2024/ 20:33:52
204 | * @param {IUploadAvatarApiParams} params 参数
205 | * @returns {*} 上传头像结果
206 | */
207 | const uploadAvatar = async(params: IUploadAvatarApiParams) => {
208 |
209 | const _result = await uploadAvatarApi(params, {
210 | testResult: {
211 | success: true,
212 | message: "上传头像成功"
213 | }
214 | })
215 |
216 | // 如果上传头像成功
217 | if (_result.success) {
218 |
219 | userInfoStoreState.avatarUrl = params.avatarUrl
220 |
221 | }
222 |
223 | return _result
224 |
225 | }
226 |
227 | /**
228 | * FUN: 上传用户信息
229 | *
230 | * @author dyb-dev
231 | * @date 09/10/2024/ 20:39:29
232 | * @param {IUploadUserInfoApiParams} params 参数
233 | * @returns {*} 上传用户信息结果
234 | */
235 | const uploadUserInfo = async(params: IUploadUserInfoApiParams) => {
236 |
237 | const _result = await uploadUserInfoApi(params, {
238 | testResult: {
239 | success: true,
240 | message: "上传用户信息成功"
241 | }
242 | })
243 |
244 | // 如果上传用户信息成功
245 | if (_result.success) {
246 |
247 | userInfoStoreState.avatarUrl = params.avatarUrl
248 | userInfoStoreState.nickName = params.nickName
249 |
250 | }
251 |
252 | return _result
253 |
254 | }
255 |
256 | return { userInfoStoreState, login, getPhoneNumber, uploadAvatar, uploadUserInfo }
257 |
258 | })
259 |
260 | /**
261 | * FUN: 使用状态管理
262 | * - 在没有Vue组件上下文的情况下使用
263 | *
264 | * @author dyb-dev
265 | * @date 15/09/2024/ 23:53:35
266 | * @returns store实例
267 | */
268 | const useUserInfoStoreWithOut = () => {
269 |
270 | return useUserInfoStore(store)
271 |
272 | }
273 |
274 | export { useUserInfoStore, useUserInfoStoreWithOut }
275 |
--------------------------------------------------------------------------------
/src/styles/funs/index.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-09-14 17:54:48
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-24 13:31:24
6 | * @FilePath: /uniapp-mp-wx-template/src/styles/funs/index.scss
7 | * @Description: scss全局函数文件
8 | */
9 |
10 | /** 必须写在顶部 */
11 | @use "sass:list";
12 | @use "sass:color";
13 |
14 | /**
15 | FUN: 创建不同方向的文本阴影函数
16 | $color - 阴影颜色
17 | $long - 阴影长度 可传 正负 数字控制阴影方向
18 | $direction - 阴影方向 "horizontal" | "vertical" | "all"
19 | $fade-step - 颜色透明度递减步长
20 | */
21 | @function create-directional-text-shadow-fun($color: #0ebeff, $long: 50, $direction: "all", $fade-step: 0.02) {
22 | $current-color: $color;
23 | $val: 0 0 $current-color;
24 | $shadow-values: (#{$val});
25 |
26 | @for $i from 1 through $long {
27 | $current-color: fade-out($current-color, $fade-step);
28 |
29 | @if $direction == "horizontal" {
30 | $val: #{$i}px 0 #{$current-color};
31 | } @else if $direction == "vertical" {
32 | $val: 0 #{$i}px #{$current-color};
33 | } @else {
34 | $val: #{$i}px #{$i}px #{$current-color};
35 | }
36 |
37 | /* stylelint-disable-next-line order/order */
38 | $shadow-values: list.append($shadow-values, $val, comma);
39 | }
40 |
41 | @return $shadow-values;
42 | }
43 |
44 | /**
45 | FUN: 创建具有递增模糊半径的文本阴影函数
46 | $color - 阴影颜色
47 | $iterations - 迭代次数
48 | $increment - 模糊半径递增值
49 | */
50 | @function create-text-shadow-fun($color: #0ebeff, $iterations: 5, $increment: 5px) {
51 | $shadow-values: ();
52 | $current-radius: "0px";
53 |
54 | @for $i from 1 through $iterations {
55 | $current-radius: $increment * $i;
56 | $shadow-values: list.append($shadow-values, 0 0 $current-radius $color, comma);
57 | }
58 |
59 | @return $shadow-values;
60 | }
61 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-09-14 17:54:09
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-08 20:38:11
6 | * @FilePath: /uniapp-mp-wx-template/src/styles/index.scss
7 | * @Description: scss模块
8 | */
9 |
--------------------------------------------------------------------------------
/src/styles/mixins/index.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-09-14 17:54:48
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-03-25 01:24:26
6 | * @FilePath: /uniapp-mp-wx-template/src/styles/mixins/index.scss
7 | * @Description: scss全局混合文件
8 | */
9 |
10 | /** 必须写在顶部 */
11 | @use "sass:list";
12 |
13 | /**
14 | 开启滚动
15 | $direction - 滚动方向 "x" | "y"
16 | */
17 | @mixin open-scroll-mixin($direction: "y") {
18 | @if $direction == "x" {
19 | overflow-x: auto;
20 | -webkit-overflow-scrolling: touch;
21 | } @else if $direction == "y" {
22 | overflow-y: auto;
23 | -webkit-overflow-scrolling: touch;
24 | }
25 | }
26 |
27 | /** 隐藏滚动条 */
28 | @mixin hide-scroll-bar-mixin {
29 | &::-webkit-scrollbar {
30 | display: none;
31 | width: 0;
32 | height: 0;
33 | color: transparent;
34 | }
35 | }
36 |
37 | /** 文本支持 \n 换行 */
38 | @mixin rich-text-mixin() {
39 | white-space: pre-wrap;
40 | word-break: break-word;
41 | }
42 |
43 | /**
44 | * 文本溢出省略号效果
45 | * 根据行数设置单行或多行文本的溢出显示省略号效果。
46 | *
47 | * $rows - 行数
48 | * - 当 $rows > 1 时,显示多行文本,并在超过指定行数时截断显示省略号。
49 | * - 当 $rows <= 1 时,显示单行文本,并在超出宽度时显示省略号。
50 | */
51 | @mixin text-ellipsis-mixin($rows: 1) {
52 | text-overflow: ellipsis;
53 | @if $rows > 1 {
54 | display: -webkit-box;
55 | -webkit-box-orient: vertical;
56 | -webkit-line-clamp: $rows;
57 | overflow: hidden;
58 | } @else {
59 | overflow: hidden;
60 | white-space: nowrap;
61 | }
62 | }
63 |
64 | /**
65 | 高亮闪烁动画文本效果
66 | $sub-class-name - 子类名
67 | $sub-class-count - 子类数量
68 | $font-highlight-color - 高亮颜色
69 | $shadow-color - 阴影颜色
70 | $animation-duration - 动画持续时间
71 | $delay-step - 延迟步长
72 | */
73 | @mixin text-flicker-animation-mixin(
74 | $sub-class-name,
75 | $sub-class-count,
76 | $font-highlight-color: #fff,
77 | $shadow-color: #42fff6,
78 | $animation-duration: 1s,
79 | $delay-step: 0.2s
80 | ) {
81 | $shadow-intensity: (5px, 10px, 20px, 50px);
82 |
83 | @for $i from 1 through $sub-class-count {
84 | .#{$sub-class-name}-#{$i} {
85 | animation-delay: $delay-step * $i;
86 | }
87 | }
88 |
89 | @keyframes flicker {
90 | 0% {
91 | color: inherit;
92 | }
93 |
94 | 5%,
95 | 15%,
96 | 25%,
97 | 30%,
98 | 100% {
99 | color: $font-highlight-color;
100 | text-shadow:
101 | 0 0 list.nth($shadow-intensity, 1) $shadow-color,
102 | 0 0 list.nth($shadow-intensity, 2) $shadow-color,
103 | 0 0 list.nth($shadow-intensity, 3) $shadow-color,
104 | 0 0 list.nth($shadow-intensity, 4) $shadow-color;
105 | }
106 |
107 | 10%,
108 | 20% {
109 | color: inherit;
110 | text-shadow: none;
111 | }
112 | }
113 |
114 | .#{$sub-class-name} {
115 | animation: flicker $animation-duration linear forwards;
116 | }
117 | }
118 |
119 | /** 文本遮罩 */
120 | @mixin text-clip-mixin {
121 | color: transparent;
122 | background-clip: text;
123 | }
124 |
125 | /**
126 | 渐变背景 + 色相旋转动画的文本效果
127 | $animation-duration - 动画持续时间
128 | */
129 | @mixin text-gradient-effect-mixin($animation-duration: 5s) {
130 | background-image: linear-gradient(45deg, #009688, yellowgreen, pink, #03a9f4, #9c27b0, #8bc34a);
131 | animation: hue-rotate $animation-duration infinite;
132 | @include text-clip-mixin;
133 |
134 | @keyframes hue-rotate {
135 | 100% {
136 | filter: hue-rotate(360deg);
137 | }
138 | }
139 | }
140 |
141 | /**
142 | 动态线性渐变背景滑动文本效果
143 | $highlight-color - 高亮颜色
144 | $animation-duration - 动画持续时间
145 | $background-color - 背景颜色 (注意: 实际展现效果其实是文字颜色)
146 | */
147 | @mixin text-shine-mixin($highlight-color: white, $animation-duration: 5s, $background-color: transparent) {
148 | color: transparent;
149 | background-color: $background-color;
150 | background-image: linear-gradient(
151 | 125deg,
152 | transparent 0%,
153 | transparent 10%,
154 | $highlight-color 20%,
155 | transparent 30%,
156 | transparent 100%
157 | );
158 | background-repeat: no-repeat;
159 | background-position: 100% 0;
160 |
161 | /** 注意: 当background-size设置的百分比大于或者小于100%时,有多余的空间移动了,background-position才会有效 */
162 | background-size: 150% 100%;
163 | background-clip: text;
164 | animation: shine $animation-duration infinite linear;
165 |
166 | @keyframes shine {
167 | 0% {
168 | background-position: 100% 0;
169 | }
170 |
171 | 100% {
172 | background-position: -200% 0;
173 | }
174 | }
175 | }
176 |
177 | /**
178 | 创建具有遮罩效果的背景
179 | @param {Length} $width - 容器的宽度
180 | @param {Length} $height - 容器的高度
181 | @param {String} $bg-image1 - 背景图片1的路径
182 | @param {String} $bg-image2 - 背景图片2的路径
183 | */
184 | @mixin background-mask-mixin($width, $height, $bg-image1, $bg-image2) {
185 | position: relative;
186 | width: $width;
187 | height: $height;
188 | background: url(#{$bg-image1}) no-repeat center/cover;
189 |
190 | &::before {
191 | position: absolute;
192 | inset: 0;
193 | background: url(#{$bg-image2}) no-repeat center/cover;
194 | content: "";
195 | mask: linear-gradient(45deg, #000 40%, transparent 60%);
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/styles/variable/custom.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-09-14 17:54:18
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-09-19 16:34:08
6 | * @FilePath: /uni-app/src/styles/variable/custom.scss
7 | * @Description: scss全局变量文件
8 | */
9 |
--------------------------------------------------------------------------------
/src/styles/variable/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: #fff;
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: #555; /* 二级标题颜色 */
74 | $uni-font-size-subtitle: 18px;
75 | $uni-color-paragraph: #3f536e; /* 文章段落颜色 */
76 | $uni-font-size-paragraph: 15px;
77 |
--------------------------------------------------------------------------------
/src/subPackages/webview/pages/webview.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/src/types/authorize.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-08 12:04:14
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-08 12:04:22
6 | * @FilePath: /uniapp-mp-wx-template/src/types/authorize.ts
7 | * @Description: 授权类型模块
8 | */
9 |
10 | /** 授权错误码 */
11 | enum EAuthErrorCode {
12 | /** 拒绝授权 */
13 | DENIED = 1,
14 | /** 未登录 */
15 | NOT_LOGGED_IN,
16 | /** 接口调用失败 */
17 | API_FAILED
18 | }
19 |
20 | /** 授权错误回调参数 */
21 | interface IAuthErrorOptions {
22 | /** 授权错误码 */
23 | code: EAuthErrorCode
24 | /** 授权错误信息 */
25 | message: string
26 | }
27 |
28 | export type { IAuthErrorOptions }
29 |
30 | export { EAuthErrorCode }
31 |
--------------------------------------------------------------------------------
/src/types/dts/api.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-17 16:21:11
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 22:09:54
6 | * @FilePath: /uniapp-mp-wx-template/src/types/dts/api.d.ts
7 | * @Description: api 类型声明补充文件
8 | */
9 |
10 | import type { UnResponse } from "@uni-helper/uni-network"
11 |
12 | declare module "@uni-helper/uni-network" {
13 | interface UnResponse {
14 | /** 请求是否成功 */
15 | success: boolean
16 | /** 结果描述信息 */
17 | message: string
18 | }
19 | }
20 |
21 | declare global {
22 | /** 测试请求配置 */
23 | interface ITestRequestConfig = Record> {
24 | /** 是否启用测试模式 */
25 | test: boolean
26 | /** 测试模式下请求延迟时间 单位: 毫秒 */
27 | testDelay?: number
28 | /** 测试模式下请求结果 */
29 | testResult: TModifyProperties, "success" | "message" | "data">, "data">
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/types/dts/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // Generated by vite-plugin-uni-components
5 | // Read more: https://github.com/vuejs/core/pull/3399
6 | export {}
7 |
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | AuthAvatarButton: typeof import('./../../components/auth/AuthAvatarButton.vue')['default']
11 | AuthAvatarNicknameDialog: typeof import('./../../components/auth/AuthAvatarNicknameDialog.vue')['default']
12 | AuthPhoneNumberButton: typeof import('./../../components/auth/AuthPhoneNumberButton.vue')['default']
13 | AvatarNickname: typeof import('./../../components/AvatarNickname.vue')['default']
14 | Cell: typeof import('./../../components/Cell.vue')['default']
15 | DateTimePicker: typeof import('./../../components/picker/DateTimePicker.vue')['default']
16 | Dialog: typeof import('./../../components/dialog/Dialog.vue')['default']
17 | FooterActionsBar: typeof import('./../../components/FooterActionsBar.vue')['default']
18 | FormControl: typeof import('./../../components/FormControl.vue')['default']
19 | FormDialog: typeof import('./../../components/dialog/FormDialog.vue')['default']
20 | LabelValueBar: typeof import('./../../components/LabelValueBar.vue')['default']
21 | Layout: typeof import('./../../components/layout/Layout.vue')['default']
22 | List: typeof import('./../../components/List.vue')['default']
23 | NavBar: typeof import('./../../components/layout/NavBar.vue')['default']
24 | NickNameInput: typeof import('./../../components/auth/NickNameInput.vue')['default']
25 | NutAnimate: typeof import('nutui-uniapp/components/animate/animate.vue')['default']
26 | NutAvatar: typeof import('nutui-uniapp/components/avatar/avatar.vue')['default']
27 | NutBadge: typeof import('nutui-uniapp/components/badge/badge.vue')['default']
28 | NutButton: typeof import('nutui-uniapp/components/button/button.vue')['default']
29 | NutConfigProvider: typeof import('nutui-uniapp/components/configprovider/configprovider.vue')['default']
30 | NutIcon: typeof import('nutui-uniapp/components/icon/icon.vue')['default']
31 | NutInput: typeof import('nutui-uniapp/components/input/input.vue')['default']
32 | NutPopup: typeof import('nutui-uniapp/components/popup/popup.vue')['default']
33 | NutSwiper: typeof import('nutui-uniapp/components/swiper/swiper.vue')['default']
34 | NutSwiperItem: typeof import('nutui-uniapp/components/swiperitem/swiperitem.vue')['default']
35 | NutTabPane: typeof import('nutui-uniapp/components/tabpane/tabpane.vue')['default']
36 | NutTabs: typeof import('nutui-uniapp/components/tabs/tabs.vue')['default']
37 | NutTextarea: typeof import('nutui-uniapp/components/textarea/textarea.vue')['default']
38 | NutUploader: typeof import('nutui-uniapp/components/uploader/uploader.vue')['default']
39 | Picker: typeof import('./../../components/picker/Picker.vue')['default']
40 | Popup: typeof import('./../../components/popup/Popup.vue')['default']
41 | SwiperPro: typeof import('./../../components/SwiperPro.vue')['default']
42 | TabBar: typeof import('./../../components/layout/TabBar.vue')['default']
43 | TabsPaneList: typeof import('./../../components/TabsPaneList.vue')['default']
44 | TitleBar: typeof import('./../../components/TitleBar.vue')['default']
45 | UCharts: typeof import('./../../components/u-charts/u-charts.vue')['default']
46 | Uploader: typeof import('./../../components/Uploader.vue')['default']
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/types/dts/index.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 14:03:54
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-05 20:37:42
6 | * @FilePath: /uniapp-mp-wx-template/src/types/dts/index.d.ts
7 | * @Description: 全局类型声明补充文件
8 | */
9 |
--------------------------------------------------------------------------------
/src/types/dts/pages.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // Generated by vite-plugin-uni-pages
5 |
6 | interface NavigateToOptions {
7 | url: "/pages/home" |
8 | "/pages/launch" |
9 | "/pages/list" |
10 | "/pages/login" |
11 | "/pages/my" |
12 | "/pages/test" |
13 | "/subPackages/webview/pages/webview";
14 | }
15 | interface RedirectToOptions extends NavigateToOptions {}
16 |
17 | interface SwitchTabOptions {
18 | url: "/pages/home" | "/pages/list" | "/pages/my"
19 | }
20 |
21 | type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;
22 |
23 | declare interface Uni {
24 | navigateTo(options: UniNamespace.NavigateToOptions & NavigateToOptions): void;
25 | redirectTo(options: UniNamespace.RedirectToOptions & RedirectToOptions): void;
26 | switchTab(options: UniNamespace.SwitchTabOptions & SwitchTabOptions): void;
27 | reLaunch(options: UniNamespace.ReLaunchOptions & ReLaunchOptions): void;
28 | }
29 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-08 11:50:30
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:02:57
6 | * @FilePath: /uniapp-mp-wx-template/src/types/index.ts
7 | * @Description: 类型模块
8 | */
9 |
10 | /** 导出授权类型模块 */
11 | export * from "./authorize"
12 | /** 导出用户信息类型模块 */
13 | export * from "./userInfo"
14 |
--------------------------------------------------------------------------------
/src/types/userInfo.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:02:41
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:02:46
6 | * @FilePath: /uniapp-mp-wx-template/src/types/userInfo.ts
7 | * @Description: 用户信息类型模块
8 | */
9 |
10 | /** 性别类型枚举 */
11 | enum EGenderType {
12 | /** 男 */
13 | Man = 1,
14 | /** 女 */
15 | Woman = 2
16 | }
17 |
18 | /** 证件类型枚举 */
19 | enum ECertificatesType {
20 | /** 身份证 */
21 | IdCard = 1,
22 | /** 军人证 */
23 | MilitaryCard,
24 | /** 护照 */
25 | Passport,
26 | /** 出生证 */
27 | BirthCertificate,
28 | /** 港澳台通行证 */
29 | HkMoTwPass,
30 | /** 士兵证 */
31 | SoldierCard,
32 | /** 警官证 */
33 | PoliceCard,
34 | /** 港澳台居民居住证 */
35 | HkMoTwResidentPermit,
36 | /** 外国人永久居留身份证 */
37 | ForeignerPermanentResidentIdCard,
38 | /** 居民户口薄 */
39 | ResidentAccountBook
40 | }
41 |
42 | export { EGenderType, ECertificatesType }
43 |
--------------------------------------------------------------------------------
/src/utils/dateTime/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:11:50
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:12:00
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/dateTime/index.ts
7 | * @Description: 日期时间相关工具函数
8 | */
9 |
10 | /**
11 | * FUN: 延迟函数
12 | *
13 | * @author dyb-dev
14 | * @date 19/02/2025/ 15:55:58
15 | * @param {number} ms - 延迟时间(毫秒)
16 | * @returns {*} {Promise} - 返回一个 Promise 对象
17 | */
18 | const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
19 |
20 | export { delay }
21 |
--------------------------------------------------------------------------------
/src/utils/env/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-09 22:15:17
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:23:01
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/env/index.ts
7 | * @Description: 环境相关工具函数
8 | */
9 |
10 | import { getEnvVersion } from "@/utils"
11 |
12 | /** CONST: 设备信息 */
13 | let systemInfo: UniApp.GetSystemInfoResult
14 |
15 | /**
16 | * FUN: 获取系统信息
17 | *
18 | * @author dyb-dev
19 | * @date 06/10/2024/ 23:13:50
20 | * @param {boolean} [isForceRefresh=false] 是否强制刷新
21 | * @returns {*} {UniApp.GetSystemInfoResult} 系统信息
22 | */
23 | const getSystemInfo = (isForceRefresh = false) => {
24 |
25 | // 如果已经获取过系统信息,且不是强制刷新,则直接返回
26 | if (systemInfo && !isForceRefresh) {
27 |
28 | return systemInfo
29 |
30 | }
31 |
32 | try {
33 |
34 | systemInfo = uni.getSystemInfoSync()
35 |
36 | }
37 | catch (error) {
38 |
39 | console.error("getSystemInfo()", error)
40 |
41 | }
42 |
43 | return systemInfo
44 |
45 | }
46 |
47 | /**
48 | * FUN: 是否为开发者工具
49 | *
50 | * @author dyb-dev
51 | * @date 06/10/2024/ 23:15:36
52 | * @returns {*} {boolean} 是否为开发者工具
53 | */
54 | const isDevTool = (): boolean => getSystemInfo()?.platform === "devtools"
55 |
56 | /**
57 | * FUN: 是否启用调试
58 | *
59 | * @author dyb-dev
60 | * @date 09/10/2024/ 22:02:43
61 | * @returns {*} {boolean} 是否启用调试
62 | */
63 | const isEnableDebug = (): boolean => isDevTool() ? true : getSystemInfo()?.enableDebug ?? false
64 |
65 | /**
66 | * FUN: 是否为开发环境
67 | *
68 | * @author dyb-dev
69 | * @date 09/10/2024/ 17:34:47
70 | * @returns {*} {boolean} 是否为开发环境
71 | */
72 | const isDevEnv = (): boolean => __PROJECT_INFO__.env.VITE_USER_NODE_ENV === "development"
73 |
74 | /**
75 | * FUN: 获取当前服务器网址
76 | * - 小程序开发版和体验版 默认: `VITE_DEV_SERVER_URL`
77 | * - 小程序正式版 默认: `VITE_PROD_SERVER_URL`
78 | *
79 | * @author dyb-dev
80 | * @date 01/11/2024/ 20:34:09
81 | * @returns {*} {string} 当前服务器网址
82 | */
83 | const getCurrentServerUrl = (): string => {
84 |
85 | const { VITE_DEV_SERVER_URL, VITE_PROD_SERVER_URL } = __PROJECT_INFO__.env
86 | return getEnvVersion() === "release" ? VITE_PROD_SERVER_URL : VITE_DEV_SERVER_URL
87 |
88 | }
89 |
90 | export { getSystemInfo, isDevTool, isEnableDebug, isDevEnv, getCurrentServerUrl }
91 |
--------------------------------------------------------------------------------
/src/utils/form/identityCard.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:13:29
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:13:44
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/form/identityCard.ts
7 | * @Description: 身份证相关工具函数
8 | */
9 |
10 | /**
11 | * FUN: 是否为有效的省、直辖市代码
12 | *
13 | * @author dyb-dev
14 | * @date 15/10/2024/ 16:34:48
15 | * @param {string} identityCardNumber - 身份证号码
16 | * @returns {*} {boolean} 是否为有效的省、直辖市代码
17 | */
18 | const _isProvinceCode = (identityCardNumber: string): boolean => {
19 |
20 | /** CONST: 省、直辖市代码表映射 */
21 | const provinceCodeMap: Record = {
22 | 11: "北京",
23 | 12: "天津",
24 | 13: "河北",
25 | 14: "山西",
26 | 15: "内蒙古",
27 | 21: "辽宁",
28 | 22: "吉林",
29 | 23: "黑龙江",
30 | 31: "上海",
31 | 32: "江苏",
32 | 33: "浙江",
33 | 34: "安徽",
34 | 35: "福建",
35 | 36: "江西",
36 | 37: "山东",
37 | 41: "河南",
38 | 42: "湖北",
39 | 43: "湖南",
40 | 44: "广东",
41 | 45: "广西",
42 | 46: "海南",
43 | 50: "重庆",
44 | 51: "四川",
45 | 52: "贵州",
46 | 53: "云南",
47 | 54: "西藏",
48 | 61: "陕西",
49 | 62: "甘肃",
50 | 63: "青海",
51 | 64: "宁夏",
52 | 65: "新疆",
53 | 71: "台湾",
54 | 81: "香港",
55 | 82: "澳门",
56 | 91: "国外"
57 | }
58 |
59 | const _addressCode = identityCardNumber.substring(0, 6)
60 | const _check = /^[1-9]\d{5}$/.test(_addressCode)
61 | if (!_check) {
62 |
63 | return false
64 |
65 | }
66 |
67 | return !!provinceCodeMap[parseInt(_addressCode.substring(0, 2))]
68 |
69 | }
70 |
71 | /**
72 | * FUN: 是否为有效的生日
73 | *
74 | * @author dyb-dev
75 | * @date 15/10/2024/ 16:41:44
76 | * @param {string} identityCardNumber - 身份证号码
77 | * @returns {*} {boolean} 是否为有效的生日
78 | */
79 | const _isBirthday = (identityCardNumber: string): boolean => {
80 |
81 | // 生日代码
82 | const _birDay = identityCardNumber.substring(6, 14)
83 | const _check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(_birDay)
84 | if (!_check) {
85 |
86 | return false
87 |
88 | }
89 | const _year = parseInt(_birDay.substring(0, 4))
90 | const _month = parseInt(_birDay.substring(4, 6))
91 | const _day = parseInt(_birDay.substring(6))
92 | const _date = new Date(_year, _month - 1, _day)
93 |
94 | // 生日大于当前日期时
95 | if (_date > new Date()) {
96 |
97 | return false
98 |
99 | }
100 | return _date.getFullYear() === _year && _date.getMonth() === _month - 1 && _date.getDate() === _day
101 |
102 | }
103 |
104 | /**
105 | * FUN: 是否为有效的校验位
106 | *
107 | * @author dyb-dev
108 | * @date 15/10/2024/ 16:57:06
109 | * @param {string} identityCardNumber - 身份证号码
110 | * @returns {*} {boolean} 是否为有效的校验位
111 | */
112 | const _isParityBit = (identityCardNumber: string): boolean => {
113 |
114 | /** CONST: 每位加权因子 */
115 | const powers = ["7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"]
116 | /** CONST: 第18位校检码 */
117 | const parityBit = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]
118 |
119 | // 18位身份证需要验证最后一位校验位
120 | const _parityBit = identityCardNumber.charAt(17).toUpperCase()
121 |
122 | // 加权因子
123 | let _power = 0
124 | for (let i = 0; i < 17; i++) {
125 |
126 | _power += parseInt(identityCardNumber.charAt(i)) * parseInt(powers[i])
127 |
128 | }
129 |
130 | return _parityBit === parityBit[_power % 11]
131 |
132 | }
133 |
134 | /**
135 | * FUN: 是否为有效的身份证号码
136 | *
137 | * @author dyb-dev
138 | * @date 15/10/2024/ 16:59:56
139 | * @param {string} identityCardNumber - 身份证号码
140 | * @returns {*} {boolean} 是否为有效的身份证号码
141 | */
142 | const isIdentityCard = (identityCardNumber: string): boolean => {
143 |
144 | const _check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test(
145 | identityCardNumber
146 | )
147 | return _check && _isProvinceCode(identityCardNumber) && _isBirthday(identityCardNumber) && _isParityBit(identityCardNumber)
148 |
149 | }
150 |
151 | export { isIdentityCard }
152 |
--------------------------------------------------------------------------------
/src/utils/form/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:13:29
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:13:37
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/form/index.ts
7 | * @Description: 表单相关工具函数
8 | */
9 |
10 | /** 导出身份证相关工具函数 */
11 | export * from "./identityCard"
12 |
13 | /**
14 | * FUN: 是否为手机号
15 | *
16 | * @author dyb-dev
17 | * @date 14/10/2024/ 15:34:16
18 | * @param {string} phone - 手机号
19 | * @returns {*} {boolean} - 是否为手机号
20 | */
21 | const isPhoneNumber = (phone: string): boolean => /^1[3456789]\d{9}$/.test(phone)
22 |
23 | /**
24 | * FUN: 是否为邮箱
25 | *
26 | * @author dyb-dev
27 | * @date 14/10/2024/ 15:35:02
28 | * @param {string} email - 邮箱
29 | * @returns {*} {boolean} - 是否为邮箱
30 | */
31 | const isEmail = (email: string): boolean => /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(email)
32 |
33 | export { isPhoneNumber, isEmail }
34 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 20:37:15
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:25:53
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/index.ts
7 | * @Description: 工具函数模块
8 | */
9 |
10 | /** 导出数据处理相关工具函数 */
11 | export * from "./data"
12 | /** 导出日期时间相关工具函数 */
13 | export * from "./dateTime"
14 | /** 导出环境相关工具函数 */
15 | export * from "./env"
16 | /** 导出表单相关工具函数 */
17 | export * from "./form"
18 | /** 导出媒体相关工具函数 */
19 | export * from "./media"
20 | /** 导出位置相关工具函数 */
21 | export * from "./location"
22 | /** 导出小程序相关工具函数 */
23 | export * from "./miniProgram"
24 | /** 导出页面相关工具函数 */
25 | export * from "./pages"
26 | /** 导出工具相关工具函数 */
27 | export * from "./tool"
28 | /** 导出url相关工具函数 */
29 | export * from "./url"
30 | /** 导出用户信息相关工具函数 */
31 | export * from "./userInfo"
32 |
--------------------------------------------------------------------------------
/src/utils/location/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:14:28
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:14:35
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/location/index.ts
7 | * @Description: 位置相关工具函数
8 | */
9 |
10 | /** 位置 */
11 | interface ILocation {
12 | /** 纬度 */
13 | latitude: number
14 | /** 经度 */
15 | longitude: number
16 | }
17 |
18 | /**
19 | * FUN: 计算两个位置之间的距离
20 | *
21 | * @author dyb-dev
22 | * @date 15/10/2024/ 14:59:41
23 | * @param {ILocation} startLocation 起始位置
24 | * @param {ILocation} endLocation 结束位置
25 | * @returns {*} {number} 两个坐标之间的距离 (单位: 米)
26 | */
27 | const calculateDistanceBetweenLocations = (startLocation: ILocation, endLocation: ILocation): number => {
28 |
29 | // 解构起始位置的纬度和经度
30 | const { latitude: startLatitude, longitude: startLongitude } = startLocation
31 | // 解构结束位置的纬度和经度
32 | const { latitude: endLatitude, longitude: endLongitude } = endLocation
33 |
34 | /** 地球半径, 单位: 米 */
35 | const _earthRadius = 6378136.49
36 |
37 | // 角度转换为弧度的函数
38 | const _rad = (d: number) => d * Math.PI / 180.0
39 |
40 | // 将起始和结束的纬度转换为弧度
41 | const _startRadLat = _rad(startLatitude)
42 | const _endRadLat = _rad(endLatitude)
43 |
44 | // 计算纬度之差的弧度
45 | const _latitudeDifference = _startRadLat - _endRadLat
46 | // 计算经度之差的弧度
47 | const _longitudeDifference = _rad(startLongitude) - _rad(endLongitude)
48 |
49 | // 计算 sin(纬度差/2) 的平方
50 | const _sinLatDiffSquared = Math.pow(Math.sin(_latitudeDifference / 2), 2)
51 |
52 | // 计算 cos(起始纬度) * cos(结束纬度)
53 | const _cosLatProduct = Math.cos(_startRadLat) * Math.cos(_endRadLat)
54 |
55 | // 计算 sin(经度差/2) 的平方
56 | const _sinLongDiffSquared = Math.pow(Math.sin(_longitudeDifference / 2), 2)
57 |
58 | // 计算 Haversine 公式的核心值,即 (sin(纬度差/2))^2 + cos(起始纬度) * cos(结束纬度) * (sin(经度差/2))^2
59 | const _haversineCore = _sinLatDiffSquared + _cosLatProduct * _sinLongDiffSquared
60 |
61 | // 计算两个点之间的弧度距离
62 | const _angularDistance = 2 * Math.asin(Math.sqrt(_haversineCore))
63 |
64 | // 将弧度距离转换为米
65 | let _distance = _angularDistance * _earthRadius
66 |
67 | // 对结果进行四舍五入到最接近的整数
68 | _distance = Math.round(_distance * 10000) / 10000
69 |
70 | // 返回以米为单位的距离,结果为整数
71 | return parseFloat(_distance.toFixed(0))
72 |
73 | }
74 |
75 | export type { ILocation }
76 |
77 | export { calculateDistanceBetweenLocations }
78 |
--------------------------------------------------------------------------------
/src/utils/media/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-06 15:04:04
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:25:40
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/media/index.ts
7 | * @Description: 媒体相关工具函数
8 | */
9 |
10 | /** CONST: 常见的图片扩展名 */
11 | const IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"]
12 |
13 | /**
14 | * FUN: 是否为有效的图片路径
15 | * - 支持网络在线地址、绝对路径、相对路径或根目录文件,并忽略查询参数
16 | *
17 | * @author dyb-dev
18 | * @date 23/09/2024/ 11:31:25
19 | * @param {string} str 图片路径
20 | * @returns {*} {boolean} 是否为图片路径
21 | */
22 | const isImagePath = (str: string): boolean => {
23 |
24 | // 动态生成正则表达式来匹配图片扩展名
25 | const _pattern = new RegExp(`^(https?:\\/\\/|\\/|[^\\s]*\\/)?[^\\s]+\\.(${IMAGE_EXTENSIONS.join("|")})(\\?.*)?$`, "i")
26 |
27 | // 首先验证是否符合路径规则
28 | if (!_pattern.test(str)) {
29 |
30 | return false
31 |
32 | }
33 |
34 | // 提取文件扩展名并验证是否为图片扩展名
35 | const _extension = str.split(".").pop()?.split("?")[0].toLowerCase() || ""
36 |
37 | // 检查提取到的扩展名是否在 IMAGE_EXTENSIONS 中
38 | return IMAGE_EXTENSIONS.includes(_extension)
39 |
40 | }
41 |
42 | export { isImagePath }
43 |
--------------------------------------------------------------------------------
/src/utils/miniProgram/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-09 22:19:06
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-02 20:20:29
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/miniProgram/index.ts
7 | * @Description: 小程序相关工具函数
8 | */
9 |
10 | import pagesJson from "@/pages.json"
11 |
12 | /** CONST: 设备信息 */
13 | let accountInfo: UniApp.AccountInfo
14 |
15 | /**
16 | * FUN: 获取账号信息
17 | *
18 | * @author dyb-dev
19 | * @date 09/10/2024/ 22:23:47
20 | * @param {boolean} [isForceRefresh=false] 是否强制刷新
21 | * @returns {*} 账号信息
22 | */
23 | const getAccountInfo = (isForceRefresh: boolean = false): UniApp.AccountInfo => {
24 |
25 | // 如果已经获取过系统信息,且不是强制刷新,则直接返回
26 | if (accountInfo && !isForceRefresh) {
27 |
28 | return accountInfo
29 |
30 | }
31 |
32 | try {
33 |
34 | accountInfo = uni.getAccountInfoSync()
35 |
36 | }
37 | catch (error) {
38 |
39 | console.error("getAccountInfo()", error)
40 |
41 | }
42 |
43 | return accountInfo
44 |
45 | }
46 |
47 | /**
48 | * FUN: 获取小程序环境版本
49 | * - 开发版: develop
50 | * - 体验版: trial
51 | * - 正式版: release
52 | *
53 | * @author dyb-dev
54 | * @date 01/11/2024/ 20:34:23
55 | * @returns {*} {string} 小程序环境版本
56 | */
57 | const getEnvVersion = () => getAccountInfo()?.miniProgram.envVersion
58 |
59 | /**
60 | * FUN: 获取小程序线上版本
61 | * - 线上小程序版本号(仅在正式版小程序上支持)
62 | *
63 | * @author dyb-dev
64 | * @date 09/10/2024/ 22:23:41
65 | * @returns {*} {string} 小程序线上版本
66 | */
67 | const getOnlineVersion = (): string => getAccountInfo()?.miniProgram.version
68 |
69 | /** LET: 胶囊按钮区域 */
70 | let capsuleBoundingClientRect: UniApp.GetMenuButtonBoundingClientRectRes | null = null
71 |
72 | /**
73 | * FUN: 获取胶囊按钮区域
74 | *
75 | * @author dyb-dev
76 | * @date 02/12/2024/ 20:21:12
77 | * @param {boolean} [isForceRefresh=false] 是否强制刷新
78 | * @returns {*} {(UniApp.GetMenuButtonBoundingClientRectRes | null)} 胶囊按钮区域
79 | */
80 | const getCapsuleBoundingClientRect = (isForceRefresh = false): UniApp.GetMenuButtonBoundingClientRectRes | null => {
81 |
82 | // @ts-ignore 是否开启 自定义导航栏
83 | const _isCustomNavigationBar = pagesJson?.globalStyle?.navigationStyle === "custom"
84 |
85 | // 如果没有开启自定义导航栏, 进行警告提示
86 | !_isCustomNavigationBar && console.warn("getCapsuleBoundingClientRect() 未开启自定义导航栏, 不需要获取菜单按钮区域")
87 |
88 | // 如果已经获取过系统信息,且不是强制刷新,则直接返回
89 | if (capsuleBoundingClientRect && !isForceRefresh) {
90 |
91 | return capsuleBoundingClientRect
92 |
93 | }
94 |
95 | try {
96 |
97 | capsuleBoundingClientRect = uni.getMenuButtonBoundingClientRect()
98 |
99 | }
100 | catch (error) {
101 |
102 | console.error("getCapsuleBoundingClientRect()", error)
103 |
104 | }
105 |
106 | return capsuleBoundingClientRect
107 |
108 | }
109 |
110 | export { getAccountInfo, getEnvVersion, getOnlineVersion, getCapsuleBoundingClientRect }
111 |
--------------------------------------------------------------------------------
/src/utils/pages/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 20:49:07
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-10 11:29:40
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/pages/index.ts
7 | * @Description: 页面相关工具函数
8 | */
9 |
10 | /** 导出页面跳转相关工具函数 */
11 | export * from "./navigate"
12 |
13 | import queryString from "query-string"
14 |
15 | import pagesJson from "@/pages.json"
16 |
17 | import { trimUrlSlashes } from "../url"
18 |
19 | import type { PageMetaDatum } from "@uni-helper/vite-plugin-uni-pages"
20 |
21 | /**
22 | * FUN: 获取当前页面实例
23 | * - 确保在页面 onLoad 之后调用
24 | * - 不要在 App.onLaunch 或者 App.onShow 的时候调用 getCurrentPages(),此时 page 还没有生成
25 | *
26 | * @author dyb-dev
27 | * @date 05/10/2024/ 20:54:47
28 | * @export
29 | * @returns {*} 当前页面实例
30 | */
31 | const getCurrentPageInstance = () => {
32 |
33 | const _pages = getCurrentPages() as WechatMiniprogram.Page.Instance<
34 | WechatMiniprogram.IAnyObject,
35 | WechatMiniprogram.IAnyObject
36 | >[]
37 | return _pages[_pages.length - 1]
38 |
39 | }
40 |
41 | /**
42 | * FUN: 获取当前页面的路径
43 | * - 确保在页面 onLoad 之后调用
44 | * - 不要在 App.onLaunch 或者 App.onShow 的时候调用 getCurrentPages(),此时 page 还没有生成
45 | * - H5 平台不支持这种方式获取
46 | *
47 | * @author dyb-dev
48 | * @date 05/10/2024/ 21:09:23
49 | * @returns {*} 当前页面路径
50 | */
51 | const getCurrentPagePath = () => getCurrentPageInstance().route
52 |
53 | /**
54 | * FUN: 获取当前页面的完整路径
55 | * - 确保在页面 onLoad 之后调用
56 | * - 不要在 App.onLaunch 或者 App.onShow 的时候调用 getCurrentPages(),此时 page 还没有生成
57 | * - H5 平台不支持这种方式获取
58 | *
59 | * @author dyb-dev
60 | * @date 05/10/2024/ 21:11:26
61 | * @returns {*} 当前页面完整路径
62 | */
63 | const getCurrentPageFullPath = () => `${getCurrentPagePath()}?${getCurrentPageSearch()}`
64 |
65 | /**
66 | * FUN: 获取当前页面的 query 参数
67 | * - 确保在页面 onLoad 之后调用
68 | * - 不要在 App.onLaunch 或者 App.onShow 的时候调用 getCurrentPages(),此时 page 还没有生成
69 | * - H5 平台不支持这种方式获取
70 | *
71 | * @author dyb-dev
72 | * @date 05/10/2024/ 21:03:56
73 | * @returns {*} 当前页面的 query 参数
74 | */
75 | const getCurrentPageQuery = () => getCurrentPageInstance()?.options || {}
76 |
77 | /**
78 | * FUN: 获取当前页面的 search 参数
79 | * - 确保在页面 onLoad 之后调用
80 | * - 不要在 App.onLaunch 或者 App.onShow 的时候调用 getCurrentPages(),此时 page 还没有生成
81 | * - H5 平台不支持这种方式获取
82 | *
83 | * @author dyb-dev
84 | * @date 05/10/2024/ 21:07:28
85 | * @returns {*} 当前页面 search 参数
86 | */
87 | const getCurrentPageSearch = () => queryString.stringify(getCurrentPageQuery(), { encode: false })
88 |
89 | const { VITE_SUB_PACKAGE_DIR, VITE_PAGE_DIR } = __PROJECT_INFO__.env
90 |
91 | /** CONST: 分包页面路径正则表达式 */
92 | const SUB_PACKAGE_PAGE_PATH_REGEX = new RegExp(`^(${VITE_SUB_PACKAGE_DIR}(?:\\/[^\\/]+)*)\\/((${VITE_PAGE_DIR}\\/.*))`)
93 |
94 | /**
95 | * FUN: 获取页面配置
96 | * - `pagePath`示例: "pages/home" 或 "subPackages/webview/pages/webview"
97 | *
98 | * @author dyb-dev
99 | * @date 06/10/2024/ 15:00:21
100 | * @param {string} pagePath 页面路径
101 | * @returns {*} 页面配置
102 | */
103 | const getPageConfig = (pagePath: string): PageMetaDatum | void => {
104 |
105 | // 如果路径开头携带斜杠,则去除开头的斜杠
106 | pagePath = trimUrlSlashes(pagePath, { trimStart: true })
107 |
108 | // 匹配分包页面并提取结果
109 | const _result = pagePath.match(SUB_PACKAGE_PAGE_PATH_REGEX)
110 |
111 | // 如果匹配分包页面结果为空,则尝试匹配主包页面
112 | if (!_result) {
113 |
114 | return pagesJson?.pages.find((item: PageMetaDatum) => item.path === pagePath)
115 |
116 | }
117 |
118 | /** 分包根路径 */
119 | const _subPackagesRootPath = _result[1] || ""
120 | /** 分包页面路径 */
121 | const _subPackagesPagePath = _result[2] || ""
122 |
123 | /** 分包配置 */
124 | const _subPackageConfig = pagesJson?.subPackages.find(item => item.root === _subPackagesRootPath)
125 |
126 | return _subPackageConfig?.pages.find((item: PageMetaDatum) => item.path === _subPackagesPagePath)
127 |
128 | }
129 |
130 | /**
131 | * FUN: 获取当前页面配置
132 | *
133 | * @author dyb-dev
134 | * @date 06/10/2024/ 15:01:07
135 | * @returns {*} 当前页面配置
136 | */
137 | const getCurrentPageConfig = (): PageMetaDatum | void => getPageConfig(getCurrentPagePath())
138 |
139 | export {
140 | getCurrentPageInstance,
141 | getCurrentPagePath,
142 | getCurrentPageFullPath,
143 | getCurrentPageQuery,
144 | getCurrentPageSearch,
145 | getPageConfig,
146 | getCurrentPageConfig
147 | }
148 |
--------------------------------------------------------------------------------
/src/utils/tool/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-11-16 02:16:21
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-11-16 02:16:23
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/tool/index.ts
7 | * @Description: 基础相关工具函数
8 | */
9 |
10 | /** 任意函数类型声明 */
11 | type TFuncType = (...args: any[]) => void
12 |
13 | /**
14 | * 创建防抖函数
15 | *
16 | * @author dyb-dev
17 | * @date 18/08/2024/ 17:04:51
18 | * @param {TFuncType} fn - 需要防抖的函数
19 | * @param {number} wait - 防抖时间
20 | * @param {boolean} [immediate=false] - 是否立即执行
21 | * @returns {*} {TFuncType} - 防抖函数
22 | */
23 | const debounce = (fn: TFuncType, wait: number, immediate = false): TFuncType => {
24 |
25 | let _timeout: ReturnType | undefined
26 |
27 | return (...args: any[]) => {
28 |
29 | const _this = this
30 |
31 | // 延迟执行函数
32 | const later = function() {
33 |
34 | _timeout = undefined
35 | if (!immediate) {
36 |
37 | fn.apply(_this, args)
38 |
39 | }
40 |
41 | }
42 |
43 | if (immediate) {
44 |
45 | fn.apply(_this, args)
46 |
47 | }
48 | else {
49 |
50 | clearTimeout(_timeout)
51 | _timeout = setTimeout(later, wait)
52 |
53 | }
54 |
55 | }
56 |
57 | }
58 |
59 | export { debounce }
60 |
--------------------------------------------------------------------------------
/src/utils/url/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 21:14:00
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 15:51:02
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/url/index.ts
7 | * @Description: url相关工具函数
8 | */
9 |
10 | import queryString from "query-string"
11 |
12 | import { getCurrentServerUrl } from "@/utils"
13 |
14 | /**
15 | * FUN: 获取基础 URL(去除查询参数)
16 | *
17 | * @author dyb-dev
18 | * @date 10/10/2024/ 11:36:50
19 | * @param {string} url - 完整的 URL 字符串
20 | * @returns {*} {string} - 去除查询参数后的基础 URL
21 | */
22 | const getBaseUrl = (url: string): string => queryString.parseUrl(url).url
23 |
24 | /**
25 | * FUN: 获取 url 的 查询参数对象
26 | *
27 | * @author dyb-dev
28 | * @date 14/07/2023/ 15:16:25
29 | * @param {string} url 需要解析的 URL
30 | * @returns {queryString.ParsedQuery} query对象
31 | */
32 | const getUrlQuery = (url: string): queryString.ParsedQuery => queryString.parseUrl(url).query
33 |
34 | /**
35 | * FUN: 根据 key 从 url 的 查询参数对象 中获取单个参数值
36 | *
37 | * @author dyb-dev
38 | * @date 14/07/2023/ 15:28:49
39 | * @param {string} [url] 需要解析的 URL
40 | * @param {string} key query 的 key
41 | * @returns {string} query 的 value
42 | */
43 | const getUrlQueryValue = (url: string, key: string): string => (getUrlQuery(url)[key] as string) || ""
44 |
45 | /**
46 | * FUN: 设置或更新 从 url 的 查询参数对象 中的指定参数,并返回更新后的 URL 字符串
47 | *
48 | * @author dyb-dev
49 | * @date 14/07/2023/ 16:06:14
50 | * @param {string} [url] 需要解析的 URL
51 | * @param {string} key 需要 设置或更新 参数 的 key
52 | * @param {string} value 需要 设置或更新 参数 的 value
53 | * @param {queryString.StringifyOptions} [options] stringifyUrl 的 options
54 | * @returns {string} 设置或更新后的 url
55 | */
56 | const setUrlQueryValue = (url: string, key: string, value: string, options?: queryString.StringifyOptions): string => {
57 |
58 | const _query = getUrlQuery(url)
59 |
60 | _query[key] = value
61 |
62 | return queryString.stringifyUrl({ url: url, query: _query }, options)
63 |
64 | }
65 |
66 | /**
67 | * FUN: 合并 URL 的查询参数,并返回更新后的 URL 字符串
68 | *
69 | * @author dyb-dev
70 | * @date 14/07/2023/ 16:10:39
71 | * @param {string} [url] 完整的 URL 字符串
72 | * @param {queryString.ParsedQuery} obj 需要合并到 URL 中的查询参数对象
73 | * @param {queryString.StringifyOptions} [options] stringifyUrl 的 options
74 | * @returns {string} 更新后的 URL 字符串
75 | */
76 | const mergeUrlQuery = (url: string, obj: queryString.ParsedQuery, options?: queryString.StringifyOptions): string => {
77 |
78 | const _query = getUrlQuery(url)
79 |
80 | Object.assign(_query, obj)
81 |
82 | return queryString.stringifyUrl({ url: url, query: _query }, options)
83 |
84 | }
85 |
86 | /**
87 | * FUN: 判断路径是否为绝对路径
88 | * - 匹配以 `协议` | `域名` | `端口号` 开头的路径
89 | *
90 | * @author dyb-dev
91 | * @date 15/10/2024/ 22:26:21
92 | * @param {string} path - 路径
93 | * @returns {*} {boolean} - 是否为绝对路径
94 | */
95 | const isAbsoluteUrl = (path: string): boolean => /^(https?:\/\/|:\/\/|[a-zA-Z0-9.-]+:\d+|:\d+)/.test(path)
96 |
97 | /** 相对路径转换为绝对路径的选项 */
98 | interface IToAbsoluteUrlOptions {
99 | /** 相对 URL 路径 */
100 | relativePath: string
101 | /**
102 | * 网址的协议、域名、端口号组成的字符串 默认: `getCurrentServerUrl()`
103 | */
104 | urlOrigin?: string
105 | /** 基础路径 默认: '' */
106 | basePath?: string
107 | /** 版本号 默认: `__PROJECT_INFO__.version` */
108 | version?: string
109 | }
110 |
111 | /**
112 | * FUN: 将相对 Url 路径转换为绝对 Url 路径
113 | *
114 | * @author dyb-dev
115 | * @date 15/10/2024/ 11:43:52
116 | * @param {IToAbsoluteUrlOptions} options - 选项
117 | * @returns {*} {string} - 绝对路径
118 | */
119 | const toAbsoluteUrl = (options: IToAbsoluteUrlOptions): string => {
120 |
121 | const { relativePath, urlOrigin = getCurrentServerUrl(), basePath = "", version = __PROJECT_INFO__.version } = options
122 |
123 | if (!relativePath || typeof relativePath !== "string" || isAbsoluteUrl(relativePath)) {
124 |
125 | console.error("toAbsoluteUrl() relativePath:", relativePath)
126 | return relativePath
127 |
128 | }
129 |
130 | const _urlOrigin = trimUrlSlashes(urlOrigin, { trimStart: false })
131 | const _basePath = trimUrlSlashes(basePath)
132 | const _relativePath = trimUrlSlashes(relativePath, { trimEnd: false })
133 |
134 | const _tempList = []
135 | _urlOrigin && _tempList.push(_urlOrigin)
136 | _basePath && _tempList.push(_basePath)
137 | _relativePath && _tempList.push(_relativePath)
138 |
139 | const _url = _tempList.join("/")
140 |
141 | if (!version) {
142 |
143 | return _url
144 |
145 | }
146 |
147 | return setUrlQueryValue(_url, "version", version, {})
148 |
149 | }
150 |
151 | /**
152 | * FUN: 根据选项移除 URL 的首尾斜杠
153 | *
154 | * @author dyb-dev
155 | * @date 23/07/2024/ 20:28:05
156 | * @param {string} url - 需要处理的 URL
157 | * @param {object} [options={}] - 配置项
158 | * @param {boolean} [options.trimStart=true] - 是否移除开头的斜杠
159 | * @param {boolean} [options.trimEnd=true] - 是否移除结尾的斜杠
160 | * @returns {string} - 处理后的url
161 | */
162 | const trimUrlSlashes = (url: string, options: { trimStart?: boolean; trimEnd?: boolean } = {}): string => {
163 |
164 | const { trimStart = true, trimEnd = true } = options
165 |
166 | let _url = url
167 | if (trimStart) {
168 |
169 | _url = _url.replace(/^\//, "")
170 |
171 | }
172 | if (trimEnd) {
173 |
174 | _url = _url.replace(/\/$/, "")
175 |
176 | }
177 | return _url
178 |
179 | }
180 |
181 | export {
182 | trimUrlSlashes,
183 | getBaseUrl,
184 | getUrlQuery,
185 | getUrlQueryValue,
186 | setUrlQueryValue,
187 | mergeUrlQuery,
188 | isAbsoluteUrl,
189 | toAbsoluteUrl
190 | }
191 |
--------------------------------------------------------------------------------
/src/utils/userInfo/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2025-02-21 21:15:36
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-21 21:15:51
6 | * @FilePath: /uniapp-mp-wx-template/src/utils/userInfo/index.ts
7 | * @Description: 用户信息相关工具函数
8 | */
9 |
10 | import { CERTIFICATE_CONFIG_LIST, GENDER_CONFIG_LIST } from "@/constants"
11 | import { isIdentityCard } from "@/utils"
12 |
13 | import { ECertificatesType, EGenderType } from "@/types"
14 |
15 | /**
16 | * FUN: 获取性别描述
17 | *
18 | * @author dyb-dev
19 | * @date 15/10/2024/ 15:17:06
20 | * @param {EGenderType} genderType - 性别类型
21 | * @returns {*} {string} - 性别字符串 如果未知性别,返回空字符串
22 | */
23 | const getGenderDesc = (genderType: EGenderType): string => GENDER_CONFIG_LIST.find(item => item.type === genderType)?.desc || ""
24 |
25 | /**
26 | * FUN: 获取证件描述
27 | *
28 | * @author dyb-dev
29 | * @date 16/10/2024/ 22:44:22
30 | * @param {ECertificatesType} certificateType - 证件类型
31 | * @returns {*} {string} - 证件描述字符串,如果未知证件,返回空字符串
32 | */
33 | const getCertificateDesc = (certificateType: ECertificatesType): string =>
34 | CERTIFICATE_CONFIG_LIST.find(item => item.type === certificateType)?.desc || ""
35 |
36 | /**
37 | * FUN: 通过身份证号码获取性别
38 | *
39 | * @author dyb-dev
40 | * @date 15/10/2024/ 21:37:45
41 | * @param {string} identityCardNumber - 身份证号码
42 | * @returns {*} {string} - 返回性别字符串,如果身份证无效,返回空字符串
43 | */
44 | const getGenderFromIdentityCard = (identityCardNumber: string): string => {
45 |
46 | // 检查身份证号码是否合法
47 | if (!isIdentityCard(identityCardNumber)) {
48 |
49 | console.error("getGenderFromIdentityCard() 身份证号码无效 identityCardNumber:", identityCardNumber)
50 | return ""
51 |
52 | }
53 |
54 | // 提取性别信息,身份证号码的倒数第二位表示性别,奇数为男,偶数为女
55 | const _genderCode = identityCardNumber.charAt(16)
56 |
57 | const _gender = parseInt(_genderCode, 10) % 2 === 1 ? EGenderType.Man : EGenderType.Woman
58 |
59 | return getGenderDesc(_gender)
60 |
61 | }
62 |
63 | /**
64 | * FUN: 通过身份证号码获取生日
65 | *
66 | * @author dyb-dev
67 | * @date 15/10/2024/ 21:38:14
68 | * @param {string} identityCardNumber - 身份证号码
69 | * @returns {*} {string} - 返回生日字符串,格式为 YYYY/MM/DD,如果身份证无效,返回空字符串
70 | */
71 | const getBirthdayFromIdentityCard = (identityCardNumber: string): string => {
72 |
73 | // 检查身份证号码是否合法
74 | if (!isIdentityCard(identityCardNumber)) {
75 |
76 | console.error("getBirthdayFromIdentityCard() 身份证号码无效 identityCardNumber:", identityCardNumber)
77 | return ""
78 |
79 | }
80 |
81 | // 提取生日信息,身份证号码的第7位到第14位是生日
82 | const _birthYear = identityCardNumber.substring(6, 10)
83 | const _birthMonth = identityCardNumber.substring(10, 12)
84 | const _birthDay = identityCardNumber.substring(12, 14)
85 |
86 | return `${_birthYear}/${_birthMonth}/${_birthDay}`
87 |
88 | }
89 |
90 | export { getGenderDesc, getCertificateDesc, getGenderFromIdentityCard, getBirthdayFromIdentityCard }
91 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 13:56:46
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2025-02-10 20:16:33
6 | * @FilePath: /uniapp-mp-wx-template/tsconfig.app.json
7 | * @Description: app环境ts配置
8 | */
9 |
10 | {
11 | "extends": "@dyb-dev/ts-config/vue",
12 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*.ts", "types/**/*.d.ts"],
13 | "exclude": ["node_modules", "**/node_modules", ".history"],
14 | "compilerOptions": {
15 | // 指定要包含的库
16 | "lib": ["ESNext", "DOM", "DOM.Iterable"],
17 | // 指定要包含的类型定义文件
18 | "types": ["@dyb-dev/ts-config/types", "@uni-helper/uni-app-types", "miniprogram-api-typings"],
19 | // 指定用于存储 TypeScript 编译器在增量编译模式下生成的编译信息的文件路径,以便下次编译时可以使用
20 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
21 | // 设置基础路径,解决模块导入路径问题
22 | "baseUrl": "./",
23 | // 配置路径映射,简化模块导入路径
24 | "paths": {
25 | "@/*": ["./src/*"],
26 | "nutui-uniapp/components/*.vue": [""]
27 | }
28 | },
29 | // Volar(Vue 3 的 TypeScript 支持插件)相关的配置项
30 | "vueCompilerOptions": {
31 | // 扩展模板组件的类型检查 例如: view、text组件
32 | "plugins": ["@uni-helper/uni-app-types/volar-plugin"]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 13:56:46
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-05 20:18:25
6 | * @FilePath: /uniapp-mp-wx-template/tsconfig.json
7 | * @Description: ts配置文件
8 | */
9 |
10 | {
11 | // 主项目本身不包含任何要编译的文件,文件编译由 `references` 引用的子项目控制
12 | "files": [],
13 | // 引用其他 TypeScript 项目,支持项目间的模块化开发和增量编译
14 | "references": [
15 | {
16 | "path": "./tsconfig.app.json"
17 | },
18 | {
19 | "path": "./tsconfig.node.json"
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 13:56:46
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-06 13:58:45
6 | * @FilePath: /uniapp-mp-wx-template/tsconfig.node.json
7 | * @Description: node环境ts配置
8 | */
9 |
10 | {
11 | "extends": "@dyb-dev/ts-config/node",
12 | "include": [
13 | "manifest.config.ts",
14 | "pages.config.ts",
15 | "vite.config.ts",
16 | "vite/**/*.ts",
17 | "vite/**/*.d.ts",
18 | "types/**/*.ts",
19 | "types/**/*.d.ts"
20 | ],
21 | "exclude": ["node_modules", "**/node_modules", ".history"],
22 | "compilerOptions": {
23 | // 指定要包含的类型定义文件
24 | "types": ["vite/client", "@dyb-dev/ts-config/types"],
25 | // 指定用于存储 TypeScript 编译器在增量编译模式下生成的编译信息的文件路径,以便下次编译时可以使用
26 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
27 | // 指定生成的模块代码
28 | "module": "ESNext",
29 | // 指定模块解析策略,支持现代打包工具
30 | "moduleResolution": "Bundler"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/types/env.d.ts:
--------------------------------------------------------------------------------
1 | /** vite环境变量 */
2 | interface ImportMetaEnv {
3 | // CONST: 共用
4 | /** 组件目录 默认:components */
5 | readonly VITE_COMPONENT_DIR: string
6 | /** 页面目录 默认:pages */
7 | readonly VITE_PAGE_DIR: string
8 | /** `src`下 分包目录 默认:subPackages */
9 | readonly VITE_SUB_PACKAGE_DIR: string
10 | /** `VITE_SUB_PACKAGE_DIR`下 分包子目录集合 如果涉及多个子分包,用逗号分隔 默认:webview */
11 | readonly VITE_SUB_PACKAGE_CHILD_DIRS: string
12 | /** 启动页路径 默认:pages/launch */
13 | readonly VITE_LAUNCH_PATH: string
14 | /**
15 | * 是否使用启动页 默认:false
16 | * - 可以在小程序运行时控制首次显示的页面,使用时注意:
17 | * - 小程序首页变为`VITE_LAUNCH_PATH`,页面跳转逻辑将在`App.vue`中进行,可根据需求修改
18 | * - 小程序码路径示例: 目标页面为`a`页面,则路径应该为 `/pages/launch?targetPath=pages/a&test=1`,其中`test=1`会传递给`a`页面
19 | */
20 | readonly VITE_USE_LAUNCH_PAGE: string
21 | /** 登录页面的路径 默认:pages/login */
22 | readonly VITE_LOGIN_PATH: string
23 | /** 首页路径 默认:pages/home */
24 | readonly VITE_HOME_PATH: string
25 | /** 开发环境服务器网址(小程序开发版、体验版用到) 默认:http://xxx.com */
26 | readonly VITE_DEV_SERVER_URL: string
27 | /** 生产环境服务器网址(小程序体验版、线上版用到) 默认:http://xxx.com */
28 | readonly VITE_PROD_SERVER_URL: string
29 | /** 接口请求基础路径 默认:/api */
30 | readonly VITE_API_BASE_PATH: string
31 | /**
32 | * 用户 node 环境
33 | * - development: 开发环境
34 | * - production: 生产环境
35 | */
36 | readonly VITE_USER_NODE_ENV: "development" | "production"
37 |
38 | // CONST: wx小程序相关
39 | /** wx小程序appid */
40 | readonly VITE_MP_WX_APPID: string
41 | }
42 |
43 | /** 扩展 ImportMeta 接口 */
44 | interface ImportMeta {
45 | readonly env: ImportMetaEnv
46 | }
47 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-08-02 22:58:16
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-09-30 14:50:05
6 | * @FilePath: /vue_pinia_vite/types/index.d.ts
7 | * @Description: app 和 node 共有的环境类型定义模块
8 | */
9 |
10 | /** 项目信息(全局) */
11 | declare interface IProjectInfo {
12 | /** 项目版本 */
13 | version: string
14 | /** 项目最后构建时间 */
15 | lastBuildTime: string
16 | /** 环境变量信息 */
17 | env: ImportMetaEnv
18 | /** `package.json`信息 */
19 | pkg: {
20 | /** 包名 */
21 | name: string
22 | /** 包版本 */
23 | version: string
24 | /** 生产依赖 */
25 | dependencies: Record
26 | }
27 | }
28 |
29 | /** 项目信息(全局) */
30 | declare const __PROJECT_INFO__: IProjectInfo
31 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-05 13:56:39
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-12-05 17:44:23
6 | * @FilePath: /uniapp-mp-wx-template/vite.config.ts
7 | * @Description: vite配置文件
8 | */
9 |
10 | import { resolve } from "node:path"
11 |
12 | import Uni from "@dcloudio/vite-plugin-uni"
13 | import UniHelperComponents from "@uni-helper/vite-plugin-uni-components"
14 | import UniHelperManifest from "@uni-helper/vite-plugin-uni-manifest"
15 | import UniHelperPages from "@uni-helper/vite-plugin-uni-pages"
16 | import { NutResolver } from "nutui-uniapp"
17 | import { defineConfig, loadEnv } from "vite"
18 |
19 | import { generateProjectInfo } from "./vite/utils"
20 |
21 | /** CONST: 项目根目录 */
22 | const projectRootDir = process.cwd()
23 |
24 | /** CONST: 获取.env文件的环境变量 */
25 | export const VITE_ENV = loadEnv(process.env.NODE_ENV as string, projectRootDir) as ImportMetaEnv
26 |
27 | /** CONST: 项目信息 */
28 | const __PROJECT_INFO__ = generateProjectInfo(VITE_ENV)
29 |
30 | const {
31 | VITE_COMPONENT_DIR,
32 | VITE_PAGE_DIR,
33 | VITE_LAUNCH_PATH,
34 | VITE_USE_LAUNCH_PAGE,
35 | VITE_HOME_PATH,
36 | VITE_SUB_PACKAGE_DIR,
37 | VITE_SUB_PACKAGE_CHILD_DIRS
38 | } = VITE_ENV
39 |
40 | /** CONST: 分包子目录路径列表 */
41 | const subPackageChildDirPathList = VITE_SUB_PACKAGE_CHILD_DIRS.split(",").map(item => `src/${VITE_SUB_PACKAGE_DIR}/${item}`)
42 |
43 | export default defineConfig(async() => {
44 |
45 | return {
46 | plugins: [
47 | // 使用 `pages.config.ts` 文件来编写生成 `pages.json` 文件,注意: 生成的 `pages.json` 文件不要更改
48 | UniHelperPages({
49 | // .d.ts文件输出路径 默认: 根目录
50 | dts: `src/types/dts/${VITE_PAGE_DIR}.d.ts`,
51 | // 扫描的页面目录 默认: src/pages
52 | dir: `src/${VITE_PAGE_DIR}`,
53 | // 首页路径 默认: pages/index
54 | homePage: VITE_USE_LAUNCH_PAGE === "true" ? VITE_LAUNCH_PATH : VITE_HOME_PATH,
55 | // subPackages 扫描的目录 默认: src/pages-sub
56 | subPackages: subPackageChildDirPathList,
57 | // 排除的文件,相对于 dir 和 subPackages
58 | exclude: [`**/${VITE_COMPONENT_DIR}/**/*.*`]
59 | }),
60 |
61 | // 使用 `manifest.config.ts` 来编写生成 `manifest.json` 文件,注意: 生成的 `manifest.json` 文件不要更改
62 | UniHelperManifest(),
63 |
64 | // 组件自动导入插件
65 | UniHelperComponents({
66 | // 组件 扫描的目录 默认: src/components
67 | dirs: [`src/${VITE_COMPONENT_DIR}`, ...subPackageChildDirPathList.map(item => `${item}/${VITE_COMPONENT_DIR}`)],
68 | // .d.ts文件输出路径
69 | dts: resolve(projectRootDir, `./src/types/dts/${VITE_COMPONENT_DIR}.d.ts`),
70 | // 自定义自动导入逻辑
71 | resolvers: [NutResolver()]
72 | }),
73 |
74 | // 核心插件,能够在 `uni-app` 中使用 `vite` 来构建项目
75 | // 注意: 部分插件需要在 `Uni()` 的前面,这是因为其他插件代码最终会被 `Uni()` 做处理
76 | Uni()
77 | ],
78 |
79 | build: {
80 | // js兼容目标 默认:modules
81 | target: "es6",
82 | // css兼容目标 默认:与 build.target 一致
83 | cssTarget: ["chrome61"]
84 | },
85 |
86 | resolve: {
87 | // 设置路径别名
88 | alias: {
89 | "@": resolve(projectRootDir, "./src")
90 | },
91 | // 导入时想要省略的扩展名集合
92 | extensions: [".js", ".ts", ".jsx", ".tsx", ".json", ".mjs", ".mts", ".cjs", ".cts"]
93 | },
94 |
95 | // 定义变量,编译时会将使用的地方替换为硬编码的形式
96 | define: {
97 | __PROJECT_INFO__: JSON.stringify(__PROJECT_INFO__)
98 | },
99 |
100 | css: {
101 | preprocessorOptions: {
102 | // scss全局文件
103 | scss: {
104 | additionalData: `
105 | @use "${projectRootDir}/src/styles/variable/uni.scss" as *;
106 | @use "${projectRootDir}/src/styles/variable/custom.scss" as *;
107 | @use "${projectRootDir}/src/styles/mixins/index.scss" as *;
108 | @use "${projectRootDir}/src/styles/funs/index.scss" as *;
109 | @import "nutui-uniapp/styles/variables.scss";
110 | `
111 | }
112 | }
113 | },
114 |
115 | json: {
116 | // 是否支持从 .json 文件中进行按名导入,示例:import { name } from './package.json';
117 | namedExports: false,
118 | // 开启则会禁用按名导入,导入的 JSON 会被转换为 export default JSON.parse("...") 会比转译成对象字面量性能更好,
119 | stringify: true
120 | }
121 | }
122 |
123 | })
124 |
--------------------------------------------------------------------------------
/vite/utils.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: dyb-dev
3 | * @Date: 2024-10-06 13:52:21
4 | * @LastEditors: dyb-dev
5 | * @LastEditTime: 2024-10-06 23:39:46
6 | * @FilePath: /uniapp-mp-wx-template/vite/utils.ts
7 | * @Description: vite配置工具函数
8 | */
9 |
10 | import dayjs from "dayjs"
11 |
12 | import pkg from "../package.json"
13 |
14 | /**
15 | * FUN: 生成项目信息
16 | *
17 | * @author dyb-dev
18 | * @date 30/09/2024/ 15:00:27
19 | * @param {ImportMetaEnv} env - 环境变量
20 | * @returns {*} {IProjectInfo}
21 | */
22 | const generateProjectInfo = (env: ImportMetaEnv): IProjectInfo => {
23 |
24 | const { name, version, dependencies } = pkg
25 | const _dayObj = dayjs()
26 | const _projectVersion = _dayObj.format("YYYYMMDDHHmmss")
27 | const _lastBuildTime = _dayObj.format("YYYY-MM-DD HH:mm:ss")
28 |
29 | const _projectInfo: IProjectInfo = {
30 | version: _projectVersion,
31 | lastBuildTime: _lastBuildTime,
32 | env,
33 | pkg: { name, version, dependencies }
34 | }
35 |
36 | return _projectInfo
37 |
38 | }
39 |
40 | export { generateProjectInfo }
41 |
--------------------------------------------------------------------------------