init
22
.editorconfig
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 告诉EditorConfig插件,这是根文件,不用继续往上查找
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# 匹配全部文件
|
||||||
|
[*]
|
||||||
|
# 设置字符集
|
||||||
|
charset = utf-8
|
||||||
|
# 缩进风格,可选space、tab
|
||||||
|
indent_style = space
|
||||||
|
# 缩进的空格数
|
||||||
|
indent_size = 2
|
||||||
|
# 结尾换行符,可选lf、cr、crlf
|
||||||
|
end_of_line = lf
|
||||||
|
# 在文件结尾插入新行
|
||||||
|
insert_final_newline = true
|
||||||
|
# 删除一行中的前后空格
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# 匹配md结尾的文件
|
||||||
|
[*.md]
|
||||||
|
insert_final_newline = false
|
||||||
|
trim_trailing_whitespace = false
|
14
.env.development
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE='uniapp-vue3-project'
|
||||||
|
|
||||||
|
# 开发环境配置
|
||||||
|
VITE_APP_ENV='development'
|
||||||
|
|
||||||
|
# 接口地址
|
||||||
|
VITE_APP_BASE_API='/api'
|
||||||
|
|
||||||
|
# 删除console
|
||||||
|
VITE_DROP_CONSOLE=false
|
||||||
|
|
||||||
|
# 是否开启Mock
|
||||||
|
VITE_USE_MOCK=true
|
11
.env.production
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE='uniapp-vue3-project'
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV='production'
|
||||||
|
|
||||||
|
# 接口地址
|
||||||
|
VITE_APP_BASE_API='/'
|
||||||
|
|
||||||
|
# 删除console
|
||||||
|
VITE_DROP_CONSOLE=true
|
11
.env.test
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE='uniapp-vue3-project'
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV='production'
|
||||||
|
|
||||||
|
# 接口地址
|
||||||
|
VITE_APP_BASE_API='/'
|
||||||
|
|
||||||
|
# 删除console
|
||||||
|
VITE_DROP_CONSOLE=true
|
138
.gitignore
vendored
@ -1,132 +1,28 @@
|
|||||||
# ---> Node
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
node_modules
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
.DS_Store
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
|
||||||
.env
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
dist
|
||||||
|
*.local
|
||||||
|
|
||||||
# Gatsby files
|
# Editor directories and files
|
||||||
.cache/
|
.idea
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
*.suo
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
*.ntvs*
|
||||||
# public
|
*.njsproj
|
||||||
|
*.sln
|
||||||
# vuepress build output
|
*.sw?
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
|
||||||
.temp
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
|
||||||
.docusaurus
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
||||||
|
#user
|
||||||
|
.hbuilderx
|
||||||
|
unpackage
|
||||||
|
# pnpm-lock.yaml
|
||||||
|
yarn.lock
|
||||||
|
package-lock.json
|
||||||
|
2
.npmrc
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
registry=https://registry.npmmirror.com/
|
||||||
|
shamefully-hoist=true
|
10
.prettierrc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"eslintIntegration": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"semi": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"printWidth": 120,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
182
README.md
@ -1,2 +1,182 @@
|
|||||||
# suke-mp
|
### 使用uniapp+vite+vue3+uview-plus3.0 搭建的微信小程序快速开发模版
|
||||||
|
|
||||||
|
使用uniapp+vite+vue3+typescript+uview-plus3.0 搭建的H5和微信小程序快速开发模版
|
||||||
|
|
||||||
|
[uview-plus官方文档](https://uiadmin.net/uview-plus/)
|
||||||
|
|
||||||
|
本项目集众多项目的优点,打造最适合团队协作开发的项目模板。
|
||||||
|
|
||||||
|
在线预览地址:[https://oyjt.github.io/uniapp-vue3-template/](https://oyjt.github.io/uniapp-vue3-template/)
|
||||||
|
|
||||||
|
### 特性
|
||||||
|
|
||||||
|
- [x] 集成uview-plus3.0 ui库
|
||||||
|
- [x] 支持多环境打包构建
|
||||||
|
- [x] 使用pinia状态管理
|
||||||
|
- [x] 封装网络请求,并支持Typescript
|
||||||
|
- [x] 支持路径别名
|
||||||
|
- [x] 支持自动加载组件和API
|
||||||
|
- [x] 自动校验git提交代码格式
|
||||||
|
- [x] 集成ESLint、StyleLint、EditorConfig代码格式规范
|
||||||
|
- [x] Typescript支持
|
||||||
|
- [x] 集成UnoCSS
|
||||||
|
- [x] 集成z-paging下拉刷新功能
|
||||||
|
- [x] 添加页面跳转拦截,登录权限校验
|
||||||
|
- [x] 支持token无痛刷新
|
||||||
|
- [x] 支持持续集成
|
||||||
|
- [x] 项目分包
|
||||||
|
|
||||||
|
### 目录结构
|
||||||
|
项目中采用目前最新的技术方案来实现,目录结构清晰。
|
||||||
|
```
|
||||||
|
uniapp-vue3-project
|
||||||
|
├ build vite插件统一管理
|
||||||
|
│ ├ vite
|
||||||
|
│ └ constant.ts
|
||||||
|
├ scripts 一些脚本
|
||||||
|
│ └ verifyCommit.js
|
||||||
|
├ src
|
||||||
|
│ ├ api 接口管理
|
||||||
|
│ ├ components 公共组件
|
||||||
|
│ ├ hooks 常用hooks封装
|
||||||
|
│ ├ pages 页面管理
|
||||||
|
│ ├ static 静态资源
|
||||||
|
│ ├ store 状态管理
|
||||||
|
│ ├ utils 一些工具
|
||||||
|
│ ├ App.vue
|
||||||
|
│ ├ main.ts
|
||||||
|
│ ├ manifest.json
|
||||||
|
│ ├ pages.json
|
||||||
|
│ ├ permission.ts 页面访问权限控制
|
||||||
|
│ └ uni.scss
|
||||||
|
├ types 全局typescript类型文件
|
||||||
|
│ ├ auto-imports.d.ts
|
||||||
|
│ ├ components.d.ts
|
||||||
|
│ ├ global.d.ts
|
||||||
|
│ └ module.d.ts
|
||||||
|
├ README.md
|
||||||
|
├ eslint.config.js
|
||||||
|
├ index.html
|
||||||
|
├ package.json
|
||||||
|
├ pnpm-lock.yaml
|
||||||
|
├ tsconfig.json
|
||||||
|
├ uno.config.ts
|
||||||
|
└ vite.config.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
#### vite插件管理
|
||||||
|
```
|
||||||
|
build
|
||||||
|
├ vite
|
||||||
|
│ ├ plugins
|
||||||
|
│ │ ├ autoImport.ts 自动导入api
|
||||||
|
│ │ ├ component.ts 自动导入组件
|
||||||
|
│ │ ├ imagemin.ts 图片压缩
|
||||||
|
│ │ ├ index.ts 入口文件
|
||||||
|
│ │ └ unocss.ts unocss插件
|
||||||
|
│ └ proxy.ts 跨域代理配置
|
||||||
|
└ constant.ts 一些常量
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 接口管理
|
||||||
|
```
|
||||||
|
api
|
||||||
|
├ common 通用api
|
||||||
|
│ ├ index.ts
|
||||||
|
│ └ types.ts
|
||||||
|
├ user 用户相关api
|
||||||
|
│ ├ index.ts
|
||||||
|
│ └ types.ts
|
||||||
|
└ index.ts 入口文件
|
||||||
|
```
|
||||||
|
|
||||||
|
#### hooks管理
|
||||||
|
```
|
||||||
|
hooks
|
||||||
|
├ use-clipboard 剪切板
|
||||||
|
│ └ index.ts
|
||||||
|
├ use-loading loading
|
||||||
|
│ └ index.ts
|
||||||
|
├ use-modal 模态框
|
||||||
|
│ └ index.ts
|
||||||
|
├ use-share 分享
|
||||||
|
│ └ index.ts
|
||||||
|
└ index.ts 入口文件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 页面管理
|
||||||
|
```
|
||||||
|
pages
|
||||||
|
├ common 公共页面(分包common)
|
||||||
|
│ ├ login
|
||||||
|
│ │ └ index.vue
|
||||||
|
│ └ webview
|
||||||
|
│ └ index.vue
|
||||||
|
└ tab 主页面(主包)
|
||||||
|
├ home
|
||||||
|
│ └ index.vue
|
||||||
|
├ list
|
||||||
|
│ └ index.vue
|
||||||
|
└ user
|
||||||
|
└ index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 状态管理
|
||||||
|
```
|
||||||
|
store
|
||||||
|
├ modules
|
||||||
|
│ ├ app app状态
|
||||||
|
│ │ ├ index.ts
|
||||||
|
│ │ └ types.ts
|
||||||
|
│ └ user 用户状态
|
||||||
|
│ ├ index.ts
|
||||||
|
│ └ types.ts
|
||||||
|
└ index.ts 入口文件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 工具方法
|
||||||
|
```
|
||||||
|
utils
|
||||||
|
├ auth token相关方法
|
||||||
|
│ └ index.ts
|
||||||
|
├ common 通用方法
|
||||||
|
│ └ index.ts
|
||||||
|
├ modals 弹窗相关方法
|
||||||
|
│ └ index.ts
|
||||||
|
├ request 网络请求相关方法
|
||||||
|
│ ├ index.ts
|
||||||
|
│ ├ interceptors.ts
|
||||||
|
│ ├ status.ts
|
||||||
|
│ └ type.ts
|
||||||
|
└ index.ts 入口文件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用方法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装依赖
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# 启动H5
|
||||||
|
pnpm dev:h5
|
||||||
|
|
||||||
|
# 启动微信小程序
|
||||||
|
pnpm dev:mp-weixin
|
||||||
|
```
|
||||||
|
|
||||||
|
### 发布
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 构建测试环境
|
||||||
|
pnpm build:h5
|
||||||
|
pnpm build:mp-weixin
|
||||||
|
|
||||||
|
# 构建生产环境
|
||||||
|
pnpm build:h5-prod
|
||||||
|
pnpm build:mp-weixin-prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码提交
|
||||||
|
```bash
|
||||||
|
pnpm cz
|
||||||
|
```
|
15
build/constant.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* @name Config
|
||||||
|
* @description 项目配置
|
||||||
|
*/
|
||||||
|
|
||||||
|
// prefix
|
||||||
|
export const API_PREFIX = '/api';
|
||||||
|
|
||||||
|
// serve
|
||||||
|
export const API_BASE_URL = '/api';
|
||||||
|
export const API_TARGET_URL = 'http://localhost:8080';
|
||||||
|
|
||||||
|
// mock
|
||||||
|
export const MOCK_API_BASE_URL = '/mock/api';
|
||||||
|
export const MOCK_API_TARGET_URL = 'http://localhost:3000';
|
13
build/vite/plugins/autoImport.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @name AutoImportDeps
|
||||||
|
* @description 按需加载,自动引入
|
||||||
|
*/
|
||||||
|
import AutoImport from 'unplugin-auto-import/vite';
|
||||||
|
|
||||||
|
export const AutoImportDeps = () => {
|
||||||
|
return AutoImport({
|
||||||
|
imports: ['vue', 'uni-app', 'pinia'],
|
||||||
|
dts: 'types/auto-imports.d.ts',
|
||||||
|
vueTemplate: true,
|
||||||
|
});
|
||||||
|
};
|
11
build/vite/plugins/component.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* @name AutoRegistryComponents
|
||||||
|
* @description 按需加载,自动引入
|
||||||
|
*/
|
||||||
|
import Components from 'unplugin-vue-components/vite';
|
||||||
|
|
||||||
|
export const AutoRegistryComponents = () => {
|
||||||
|
return Components({
|
||||||
|
dts: 'types/components.d.ts',
|
||||||
|
});
|
||||||
|
};
|
36
build/vite/plugins/imagemin.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* @name ConfigImageminPlugin
|
||||||
|
* @description 图片压缩配置
|
||||||
|
*/
|
||||||
|
import viteImagemin from 'vite-plugin-imagemin';
|
||||||
|
|
||||||
|
export const ConfigImageminPlugin = () => {
|
||||||
|
const plugin = viteImagemin({
|
||||||
|
gifsicle: {
|
||||||
|
optimizationLevel: 7,
|
||||||
|
interlaced: false,
|
||||||
|
},
|
||||||
|
mozjpeg: {
|
||||||
|
quality: 20,
|
||||||
|
},
|
||||||
|
optipng: {
|
||||||
|
optimizationLevel: 7,
|
||||||
|
},
|
||||||
|
pngquant: {
|
||||||
|
quality: [0.8, 0.9],
|
||||||
|
speed: 4,
|
||||||
|
},
|
||||||
|
svgo: {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
name: 'removeViewBox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'removeEmptyAttrs',
|
||||||
|
active: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return plugin;
|
||||||
|
};
|
30
build/vite/plugins/index.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* @name createVitePlugins
|
||||||
|
* @description 封装plugins数组统一调用
|
||||||
|
*/
|
||||||
|
import type { PluginOption } from 'vite';
|
||||||
|
import uniPlugin from '@dcloudio/vite-plugin-uni';
|
||||||
|
import { AutoImportDeps } from './autoImport';
|
||||||
|
import { AutoRegistryComponents } from './component';
|
||||||
|
import { ConfigUnoCSSPlugin } from './unocss';
|
||||||
|
import { ConfigImageminPlugin } from './imagemin';
|
||||||
|
|
||||||
|
export default function createVitePlugins(isBuild: boolean) {
|
||||||
|
const vitePlugins: (PluginOption | PluginOption[])[] = [
|
||||||
|
// UnoCSS配置
|
||||||
|
ConfigUnoCSSPlugin(),
|
||||||
|
// 自动按需引入依赖
|
||||||
|
AutoImportDeps(),
|
||||||
|
// 自动按需引入组件(注意:需注册至 uni 之前,否则不会生效)
|
||||||
|
AutoRegistryComponents(),
|
||||||
|
// uni支持
|
||||||
|
uniPlugin(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isBuild) {
|
||||||
|
// vite-plugin-imagemin
|
||||||
|
vitePlugins.push(ConfigImageminPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return vitePlugins;
|
||||||
|
}
|
9
build/vite/plugins/unocss.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @name ConfigUnoCSSPlugin
|
||||||
|
* @description UnoCSS相关配置
|
||||||
|
*/
|
||||||
|
import UnoCSS from 'unocss/vite';
|
||||||
|
|
||||||
|
export const ConfigUnoCSSPlugin = () => {
|
||||||
|
return UnoCSS();
|
||||||
|
};
|
21
build/vite/proxy.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import type { ProxyOptions } from 'vite';
|
||||||
|
import { API_BASE_URL, API_TARGET_URL, MOCK_API_BASE_URL, MOCK_API_TARGET_URL } from '../constant';
|
||||||
|
|
||||||
|
type ProxyTargetList = Record<string, ProxyOptions>;
|
||||||
|
|
||||||
|
const init: ProxyTargetList = {
|
||||||
|
// test
|
||||||
|
[API_BASE_URL]: {
|
||||||
|
target: API_TARGET_URL,
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: path => path.replace(new RegExp(`^${API_BASE_URL}`), ''),
|
||||||
|
},
|
||||||
|
// mock
|
||||||
|
[MOCK_API_BASE_URL]: {
|
||||||
|
target: MOCK_API_TARGET_URL,
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: path => path.replace(new RegExp(`^${MOCK_API_BASE_URL}`), '/api'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default init;
|
58
cz.config.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/** @type {import('cz-git').CommitizenGitOptions} */
|
||||||
|
module.exports = {
|
||||||
|
"alias": { "fd": "docs: fix typos" },
|
||||||
|
"messages": {
|
||||||
|
"type": "选择你要提交的类型 :",
|
||||||
|
"scope": "选择一个提交范围(可选):",
|
||||||
|
"customScope": "请输入自定义的提交范围 :",
|
||||||
|
"subject": "填写简短精炼的变更描述 :\n",
|
||||||
|
"body": "填写更加详细的变更描述(可选)。使用 '|' 换行 :\n",
|
||||||
|
"breaking": "列举非兼容性重大的变更(可选)。使用 '|' 换行 :\n",
|
||||||
|
"footerPrefixesSelect": "选择关联issue前缀(可选):",
|
||||||
|
"customFooterPrefix": "输入自定义issue前缀 :",
|
||||||
|
"footer": "列举关联issue (可选) 例如: #31, #I3244 :\n",
|
||||||
|
"confirmCommit": "是否提交或修改commit ?"
|
||||||
|
},
|
||||||
|
"types": [
|
||||||
|
{ "value": "feat", "name": "feat: 新增功能 | A new feature", "emoji": ":sparkles:" },
|
||||||
|
{ "value": "fix", "name": "fix: 修复缺陷 | A bug fix", "emoji": ":bug:" },
|
||||||
|
{ "value": "docs", "name": "docs: 文档更新 | Documentation only changes", "emoji": ":memo:" },
|
||||||
|
{ "value": "style", "name": "style: 代码格式 | Changes that do not affect the meaning of the code", "emoji": ":lipstick:" },
|
||||||
|
{ "value": "refactor", "name": "refactor: 代码重构 | A code change that neither fixes a bug nor adds a feature", "emoji": ":recycle:" },
|
||||||
|
{ "value": "perf", "name": "perf: 性能提升 | A code change that improves performance", "emoji": ":zap:" },
|
||||||
|
{ "value": "test", "name": "test: 测试相关 | Adding missing tests or correcting existing tests", "emoji": ":white_check_mark:" },
|
||||||
|
{ "value": "build", "name": "build: 构建相关 | Changes that affect the build system or external dependencies", "emoji": ":package:" },
|
||||||
|
{ "value": "ci", "name": "ci: 持续集成 | Changes to our CI configuration files and scripts", "emoji": ":ferris_wheel:" },
|
||||||
|
{ "value": "chore", "name": "chore: 其他修改 | Other changes that don't modify src or test files", "emoji": ":hammer:" },
|
||||||
|
{ "value": "revert", "name": "revert: 回退代码 | Reverts a previous commit", "emoji": ":rewind:" }
|
||||||
|
],
|
||||||
|
"useEmoji": false,
|
||||||
|
"emojiAlign": "center",
|
||||||
|
"useAI": false,
|
||||||
|
"aiNumber": 1,
|
||||||
|
"themeColorCode": "",
|
||||||
|
"scopes": [],
|
||||||
|
"allowCustomScopes": true,
|
||||||
|
"allowEmptyScopes": true,
|
||||||
|
"customScopesAlign": "bottom",
|
||||||
|
"customScopesAlias": "custom",
|
||||||
|
"emptyScopesAlias": "empty",
|
||||||
|
"upperCaseSubject": false,
|
||||||
|
"markBreakingChangeMode": false,
|
||||||
|
"allowBreakingChanges": ["feat", "fix"],
|
||||||
|
"breaklineNumber": 100,
|
||||||
|
"breaklineChar": "|",
|
||||||
|
"skipQuestions": [],
|
||||||
|
"issuePrefixes": [{ "value": "closed", "name": "closed: 标记 ISSUES 已完成" }],
|
||||||
|
"customIssuePrefixAlign": "top",
|
||||||
|
"emptyIssuePrefixAlias": "skip",
|
||||||
|
"customIssuePrefixAlias": "custom",
|
||||||
|
"allowCustomIssuePrefix": true,
|
||||||
|
"allowEmptyIssuePrefix": true,
|
||||||
|
"confirmColorize": true,
|
||||||
|
"minSubjectLength": 0,
|
||||||
|
"defaultBody": "",
|
||||||
|
"defaultIssues": "",
|
||||||
|
"defaultScope": "",
|
||||||
|
"defaultSubject": ""
|
||||||
|
}
|
44
deploy.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
const fs = require( 'fs');
|
||||||
|
// @ts-ignore
|
||||||
|
const ci = require ('miniprogram-ci');
|
||||||
|
// @ts-ignore
|
||||||
|
const path = require ('path');
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const envType = process.argv[process.argv.length - 1]; // 获取传入的环境变量名称
|
||||||
|
|
||||||
|
const WX_DESC = envType == 'production' ? '正式环境' : '测试环境' // 备注
|
||||||
|
|
||||||
|
; // @ts-ignore
|
||||||
|
(async () => {
|
||||||
|
// @ts-ignore
|
||||||
|
const manifest = path.resolve(__dirname, './src/manifest.json')
|
||||||
|
// @ts-ignore
|
||||||
|
const manifestConfig = JSON.parse(fs.readFileSync(manifest).toString())
|
||||||
|
const appId = manifestConfig['mp-weixin'].appid
|
||||||
|
const versionName = manifestConfig.versionName || '1.0.0'
|
||||||
|
|
||||||
|
const project = new ci.Project({
|
||||||
|
appid: appId,
|
||||||
|
type: 'miniProgram',
|
||||||
|
// @ts-ignore
|
||||||
|
projectPath: path.join(__dirname, './dist/build/mp-weixin'), // 获取打包的路径
|
||||||
|
// @ts-ignore
|
||||||
|
privateKeyPath: path.join(__dirname, `./keys/private.${appId}.key`), // 你要上传的小程序APPid
|
||||||
|
ignores: ['node_modules/**/*'],
|
||||||
|
})
|
||||||
|
await ci.upload({
|
||||||
|
project,
|
||||||
|
version: versionName,
|
||||||
|
desc: WX_DESC,
|
||||||
|
robot: 1,
|
||||||
|
setting: {
|
||||||
|
es7: true,
|
||||||
|
minifyJS: true, // 压缩 JS 代码
|
||||||
|
minify: true // 压缩所有代码,对应小程序开发者工具的 "压缩代码"
|
||||||
|
},
|
||||||
|
// @ts-ignore
|
||||||
|
onProgressUpdate: console.log,
|
||||||
|
})
|
||||||
|
})()
|
34
eslint.config.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const antfu = require('@antfu/eslint-config').default
|
||||||
|
const unocss = require('@unocss/eslint-plugin').default
|
||||||
|
|
||||||
|
module.exports = antfu(
|
||||||
|
{
|
||||||
|
ignores: ['uni_modules'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.vue'],
|
||||||
|
rules: {
|
||||||
|
'vue/block-order': [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"order": ["template", "script", "style"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
// 需要尾随逗号
|
||||||
|
// "comma-dangle": ["error", "always"]
|
||||||
|
// 允许console
|
||||||
|
"no-console": "off",
|
||||||
|
// 需要尾随分号
|
||||||
|
"semi": ["error", "always"],
|
||||||
|
// 分号位置
|
||||||
|
"style/semi": "off",
|
||||||
|
// 块内的空行
|
||||||
|
"padded-blocks": ["error", "never"]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
unocss,
|
||||||
|
)
|
20
index.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script>
|
||||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||||
|
CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||||
|
</script>
|
||||||
|
<title></title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"><!--app-html--></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
27
keys/private.wx6cbc9f8ba0a7d1c6.key
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAtAuySwDuVUqiKAgtB8yhmDXMbFtgSZQiC4FtahrqAxcwcett
|
||||||
|
khfncnldZZGMUtK3dM/xA5YaKe18vish3qbymwc+863r2NKIFtWhWIglXDuutGgT
|
||||||
|
U9/IqCnh4Dx8Owlw5/EzbvHSXj1/uzwuAVO6cxkkEvz9mxYixuB3YCd8yKQ5rLnu
|
||||||
|
EwNf063fI+jDVUBeyEejSZJ0pi3OzWdXJOjS9UYv2bAYOfJluGucfDXMbfdz8euy
|
||||||
|
T8WRCPJp4X2QoQU5WcSxWnvRSllwAfposZTIcu/msXm77QwoYqCHvJ2suGzL+SXa
|
||||||
|
c73wQB289dXqHbYmSa7bPmTmOEyCPYao0oIh8wIDAQABAoIBACfpb9ywmCTQJqI5
|
||||||
|
LcJM2oWjZ22d0/p7nBBw4JBk5vtIaLTYO7HnGqeFv+6EFVdG3uRGNGdXHvWsb7q4
|
||||||
|
VQnGeIFlWc8q/t1RzllBgkLd62pG0LOtXpt5QEIHBstunRt5PE4uafhuIvRBLc+T
|
||||||
|
x58DsJFTQWv0KUP35D2yBMSL/F19qqF6oe43kYbAei8w608XXKOT/rODdk1Ie3yx
|
||||||
|
AOgM4DvTqcSdqL/SDJ6r8xoplDNk4l+QYCJ9z7JodnJfU5OQVWw8WFWRg3jP9k/S
|
||||||
|
DsojcusTs1s14X8V3/TbR1vVW6g4Q5QnNFozHaKRZAD9DuBStrL02hgAq7oXdg+g
|
||||||
|
IoMR+AECgYEA7VVuOWwt2aWXks9aPpOVs9knMdrpxbO1nE/B2JECICElFtL8xwUi
|
||||||
|
BxWcM++wJNtKTAjJfpnFGZkyHfmnB8V0itGIz1lCZTs/yraJqaLxQdbHjEnCoCRq
|
||||||
|
tl1751hsBS15XFDskKHGFZj0wv9nq3I0wUoMjhsRV+Lopq+uHCodcgMCgYEAwjTO
|
||||||
|
dwh/0cTjiGOV8iX9WdM0I3wnYfcAgDbxGKNyZNw8oQ52vzTn1VG+LcxMcy+OUq/a
|
||||||
|
B/XBjkUI4WyHfK7zM6rhlQB8pWR3i+yPyLXJ69oRQwYAeHQzgZ6Z+sSsusHcG/wN
|
||||||
|
J/Z9EqiWQK/tZsBXQxDpHqxwz9Xl1BlL0xX9BVECgYBHKsr2pR3KmgEtoMfq486M
|
||||||
|
M52xMXfQNOdMjA4QpssAX3ADvBjYhQ2DGlPQrxsesjNBQZFKSUn1Nx70JhyUE/2y
|
||||||
|
csqXgqiKOo4Sd1IocBfwKjuEMcoOw1zMepPg937MvqoZqJqHdDs11rvujS/FFWYE
|
||||||
|
X/QL2MoGlKA2+482GtrhiQKBgQCTt8jnn45hx2nuXxk5w42umkiJSTFHgbJe0+uU
|
||||||
|
+xXTA/YV50OJcrt4daG7gi8QWjbeTCYCcfrUtUvo8z0nKIeSYEMPq/wjbYTE6J4B
|
||||||
|
Y8z/2bHRkiofdPuMd0/V/20G7Nf4bUKwh/tgit0mvOpNgrWdLKq1CyMP4znal5cm
|
||||||
|
Kw520QKBgB+I8yfp/E01ruSccdgRH3WMGStuHhSxcQ8WWD9oFdOn+klxr8h4al3+
|
||||||
|
Ibo6SJkKmwg2/IEsuc52qZPH5594XfQ7HxfVf9RVwdR96epRqah/cHofIVCX1wQB
|
||||||
|
CCirZNNiBe2hQxDyAHn492a6dzcjMojDN5JS+Yt071CB0Tph7+2c
|
||||||
|
-----END RSA PRIVATE KEY-----
|
76
package.json
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"name": "uniapp-vue3-project",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "uni -p mp-weixin",
|
||||||
|
"build:test": "uni build --mode test -p mp-weixin",
|
||||||
|
"build:prod": "uni build --mode production -p mp-weixin",
|
||||||
|
"deploy:test": "uni build --mode test -p mp-weixin && node deploy.ts test",
|
||||||
|
"deploy:prod": "uni build --mode production -p mp-weixin && node deploy.ts production",
|
||||||
|
"type-check": "vue-tsc --noEmit",
|
||||||
|
"eslint": "eslint --fix",
|
||||||
|
"stylelint": "stylelint \"src/**/*.(vue|scss|css)\" --fix",
|
||||||
|
"cz": "git add . && npx czg",
|
||||||
|
"postinstall": "simple-git-hooks"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dcloudio/uni-app": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-app-plus": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-components": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-h5": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-mp-weixin": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001",
|
||||||
|
"pinia": "2.0.36",
|
||||||
|
"uview-plus": "^3.1.38",
|
||||||
|
"vue": "3.2.47",
|
||||||
|
"vue-i18n": "^9.1.9",
|
||||||
|
"z-paging": "^2.6.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@antfu/eslint-config": "1.1.0",
|
||||||
|
"@dcloudio/types": "^3.4.3",
|
||||||
|
"@dcloudio/uni-automator": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-cli-shared": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/uni-stacktracey": "3.0.0-3090920231225001",
|
||||||
|
"@dcloudio/vite-plugin-uni": "3.0.0-3090920231225001",
|
||||||
|
"@types/node": "^20.8.10",
|
||||||
|
"@typescript-eslint/parser": "^6.10.0",
|
||||||
|
"@uni-helper/uni-app-types": "^0.5.9",
|
||||||
|
"@unocss/eslint-plugin": "^0.57.2",
|
||||||
|
"@vue/runtime-core": "^3.2.45",
|
||||||
|
"@vue/tsconfig": "^0.4.0",
|
||||||
|
"czg": "^1.7.1",
|
||||||
|
"eslint": "^8.53.0",
|
||||||
|
"lint-staged": "^15.0.2",
|
||||||
|
"miniprogram-ci": "^1.9.8",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"postcss-html": "^1.5.0",
|
||||||
|
"postcss-scss": "^4.0.9",
|
||||||
|
"sass": "^1.69.5",
|
||||||
|
"simple-git-hooks": "^2.9.0",
|
||||||
|
"stylelint": "^15.11.0",
|
||||||
|
"stylelint-config-recess-order": "^4.3.0",
|
||||||
|
"stylelint-config-standard": "^34.0.0",
|
||||||
|
"stylelint-config-standard-vue": "^1.0.0",
|
||||||
|
"stylelint-order": "^6.0.3",
|
||||||
|
"typescript": "^5.2.2",
|
||||||
|
"unocss": "^0.57.2",
|
||||||
|
"unocss-applet": "^0.7.7",
|
||||||
|
"unplugin-auto-import": "^0.16.7",
|
||||||
|
"unplugin-vue-components": "^0.25.2",
|
||||||
|
"vite": "^4.5.2",
|
||||||
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
|
"vue-tsc": "^1.8.22"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"src/**/*.{js,jsx,ts,tsx}": "eslint --fix",
|
||||||
|
"*.{scss,less,style,html}": "stylelint --fix",
|
||||||
|
"*.vue": [
|
||||||
|
"stylelint --fix"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"simple-git-hooks": {
|
||||||
|
"commit-msg": "node scripts/verifyCommit.js"
|
||||||
|
}
|
||||||
|
}
|
14956
pnpm-lock.yaml
Normal file
19
scripts/verifyCommit.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const path = require('node:path');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const pc = require('picocolors');
|
||||||
|
|
||||||
|
const msgPath = path.resolve('.git/COMMIT_EDITMSG');
|
||||||
|
const msg = fs.readFileSync(msgPath, 'utf-8').trim();
|
||||||
|
|
||||||
|
const commitRE =
|
||||||
|
/^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/;
|
||||||
|
|
||||||
|
if(!commitRE.test(msg)) {
|
||||||
|
console.log();
|
||||||
|
console.error(
|
||||||
|
` ${pc.bgRed(pc.white(' ERROR '))} ${pc.red('Git提交信息不符合规范!')}\n\n${pc.green(
|
||||||
|
'推荐使用命令 npm run cz 生成符合规范的Git提交信息'
|
||||||
|
)}\n`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
22
src/App.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { mpUpdate } from '@/utils';
|
||||||
|
|
||||||
|
onLaunch(() => {
|
||||||
|
console.log('App Launch');
|
||||||
|
// #ifdef MP
|
||||||
|
mpUpdate();
|
||||||
|
// #endif
|
||||||
|
});
|
||||||
|
onShow(() => {
|
||||||
|
console.log('App Show');
|
||||||
|
});
|
||||||
|
onHide(() => {
|
||||||
|
console.log('App Hide');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
/* 每个页面公共css */
|
||||||
|
@import 'uview-plus/index.scss';
|
||||||
|
@import '@/static/styles/common.scss';
|
||||||
|
</style>
|
17
src/api/common/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 通用接口
|
||||||
|
*/
|
||||||
|
import type { SendCodeParams, SendCodeResult, UploadImageResult } from './types';
|
||||||
|
import { post, upload } from '@/utils/request';
|
||||||
|
|
||||||
|
enum URL {
|
||||||
|
upload = '/common/upload',
|
||||||
|
sendCode = '/sendCode',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片上传
|
||||||
|
export const uploadImage = (imagePath: string) =>
|
||||||
|
upload<UploadImageResult>({ url: URL.upload, filePath: imagePath, name: 'file' });
|
||||||
|
|
||||||
|
// 发送验证码
|
||||||
|
export const sendCode = (data: SendCodeParams) => post<SendCodeResult>({ url: URL.sendCode, data });
|
13
src/api/common/types.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export interface UploadImageResult {
|
||||||
|
file: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SendCodeParams {
|
||||||
|
phone: number;
|
||||||
|
code: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SendCodeResult {
|
||||||
|
code: number;
|
||||||
|
}
|
4
src/api/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import * as CommonApi from './common';
|
||||||
|
import * as UserApi from './user';
|
||||||
|
|
||||||
|
export { CommonApi, UserApi };
|
18
src/api/user/index.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 用户信息相关接口
|
||||||
|
*/
|
||||||
|
import type { LoginByCodeParams, LoginParams, LoginResult } from './types';
|
||||||
|
import { get, post } from '@/utils/request';
|
||||||
|
import type { UserState } from '@/store/modules/user/types';
|
||||||
|
|
||||||
|
enum URL {
|
||||||
|
login = '/user/login',
|
||||||
|
loginByCode = '/user/loginByCode',
|
||||||
|
logout = '/user/logout',
|
||||||
|
profile = '/user/profile',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getUserProfile = () => get<UserState>({ url: URL.profile });
|
||||||
|
export const login = (data: LoginParams) => post<LoginResult>({ url: URL.login, data });
|
||||||
|
export const loginByCode = (data: LoginByCodeParams) => post<any>({ url: URL.loginByCode, data });
|
||||||
|
export const logout = () => post<any>({ url: URL.logout });
|
15
src/api/user/types.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export interface LoginParams {
|
||||||
|
phone: string;
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginByCodeParams {
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginResult {
|
||||||
|
token: string;
|
||||||
|
user_id: number;
|
||||||
|
user_name: string;
|
||||||
|
avatar: string;
|
||||||
|
}
|
103
src/components/page-nav/page-nav.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<view class="nav-wrap">
|
||||||
|
<view class="nav-title">
|
||||||
|
<u--image :show-loading="true" src="./static/logo.png" width="70px" height="70px" />
|
||||||
|
<view class="nav-info">
|
||||||
|
<view class="nav-info__title">
|
||||||
|
<text class="nav-info__title__text">uview-plus3</text>
|
||||||
|
</view>
|
||||||
|
<text class="nav-slogan">多平台快速开发的UI框架</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<text class="nav-desc">{{ desc }}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'PageNav',
|
||||||
|
props: {
|
||||||
|
desc: String,
|
||||||
|
title: String,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-wrap {
|
||||||
|
position: relative;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-info {
|
||||||
|
margin-left: 15px;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
font-size: 25px;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
color: $u-main-color;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__jump {
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $u-primary;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-slogan {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-desc {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-content-color;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
6
src/hooks/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import useShare from './use-share';
|
||||||
|
import useLoading from './use-loading';
|
||||||
|
import useModal from './use-modal';
|
||||||
|
import useClipboard from './use-clipboard';
|
||||||
|
|
||||||
|
export { useShare, useLoading, useModal, useClipboard };
|
33
src/hooks/use-clipboard/index.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 剪切板
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface SetClipboardDataOptions {
|
||||||
|
data: string;
|
||||||
|
showToast?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useClipboard() {
|
||||||
|
const setClipboardData = ({ data, showToast = true }: SetClipboardDataOptions) => {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
uni.setClipboardData({
|
||||||
|
data,
|
||||||
|
showToast,
|
||||||
|
success: ({ data }) => resolve(data),
|
||||||
|
fail: error => reject(error),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const getClipboardData = () => {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
uni.getClipboardData({
|
||||||
|
success: ({ data }) => resolve(data),
|
||||||
|
fail: error => reject(error),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
setClipboardData,
|
||||||
|
getClipboardData,
|
||||||
|
};
|
||||||
|
}
|
19
src/hooks/use-loading/index.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* loading 提示框
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default function useLoading() {
|
||||||
|
const showLoading = (content = '加载中') => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: content,
|
||||||
|
mask: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const hideLoading = () => {
|
||||||
|
uni.hideLoading();
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
showLoading,
|
||||||
|
hideLoading,
|
||||||
|
};
|
||||||
|
}
|
21
src/hooks/use-modal/index.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Dialog 提示框
|
||||||
|
*/
|
||||||
|
export default function useModal() {
|
||||||
|
const showModal = (content: string, options: UniApp.ShowModalOptions) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '温馨提示',
|
||||||
|
content,
|
||||||
|
showCancel: false,
|
||||||
|
confirmColor: '#1677FF',
|
||||||
|
success: res => resolve(res),
|
||||||
|
fail: () => reject(new Error('Alert 调用失败 !')),
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
showModal,
|
||||||
|
}
|
||||||
|
}
|
32
src/hooks/use-share/index.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 小程序分享
|
||||||
|
*/
|
||||||
|
interface UseShareOptions {
|
||||||
|
title?: string;
|
||||||
|
path?: string;
|
||||||
|
query?: string;
|
||||||
|
imageUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useShare(options?: UseShareOptions) {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const title = options?.title ?? '';
|
||||||
|
const path = options?.path ?? '';
|
||||||
|
const query = options?.query ?? '';
|
||||||
|
const imageUrl = options?.imageUrl ?? '';
|
||||||
|
onShareAppMessage(() => {
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
path: path ? `${path}${query ? `?${query}` : ''}` : '',
|
||||||
|
imageUrl,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
onShareTimeline(() => {
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
query: options?.query ?? '',
|
||||||
|
imageUrl,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
}
|
32
src/main.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { createSSRApp } from 'vue';
|
||||||
|
|
||||||
|
// 引入UnoCSS
|
||||||
|
import 'uno.css';
|
||||||
|
|
||||||
|
// 引入uview-plus
|
||||||
|
import uviewPlus from 'uview-plus';
|
||||||
|
import App from '@/App.vue';
|
||||||
|
|
||||||
|
// 引入状态管理
|
||||||
|
import setupStore from '@/store';
|
||||||
|
|
||||||
|
// 引入请求封装
|
||||||
|
import setupRequest from '@/utils/request';
|
||||||
|
|
||||||
|
// 权限管理
|
||||||
|
import '@/permission';
|
||||||
|
|
||||||
|
// #ifdef VUE3
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App);
|
||||||
|
app.use(uviewPlus);
|
||||||
|
// 状态管理
|
||||||
|
setupStore(app);
|
||||||
|
// 网络请求
|
||||||
|
setupRequest();
|
||||||
|
|
||||||
|
return {
|
||||||
|
app,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// #endif
|
47
src/manifest.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "SUKE-MP",
|
||||||
|
"appid": "",
|
||||||
|
"description": "",
|
||||||
|
"versionName": "1.0.0",
|
||||||
|
"versionCode": "100",
|
||||||
|
"transformPx": false,
|
||||||
|
/* 5+App特有相关 */
|
||||||
|
"app-plus":
|
||||||
|
{
|
||||||
|
"usingComponents": true,
|
||||||
|
"nvueStyleCompiler": "uni-app",
|
||||||
|
"compilerVersion": 3,
|
||||||
|
"splashscreen":
|
||||||
|
{
|
||||||
|
"alwaysShowBeforeRender": true,
|
||||||
|
"waiting": true,
|
||||||
|
"autoclose": true,
|
||||||
|
"delay": 0
|
||||||
|
},
|
||||||
|
/* 模块配置 */
|
||||||
|
"modules": {}
|
||||||
|
},
|
||||||
|
/* 小程序特有相关 */
|
||||||
|
"mp-weixin":
|
||||||
|
{
|
||||||
|
"appid": "wx67a750d0ceed4d88",
|
||||||
|
"setting":
|
||||||
|
{
|
||||||
|
"urlCheck": false
|
||||||
|
},
|
||||||
|
"usingComponents": true
|
||||||
|
},
|
||||||
|
"uniStatistics":
|
||||||
|
{
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"vueVersion": "3",
|
||||||
|
"h5":
|
||||||
|
{
|
||||||
|
"router":
|
||||||
|
{
|
||||||
|
"mode": "hash",
|
||||||
|
"base": "/uniapp-vue3-template/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
src/pages.json
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
{
|
||||||
|
"easycom": {
|
||||||
|
"custom": {
|
||||||
|
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||||
|
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||||
|
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||||
|
"^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "pages/home/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "首页"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/qrcode/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "支付码"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mall/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "商城"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mine/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subPackages": [
|
||||||
|
{
|
||||||
|
"root": "pages/common",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "login/index",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "webview/index",
|
||||||
|
"navigationBarTitleText": "网页"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preloadRule": {
|
||||||
|
"pages/home/index": {
|
||||||
|
"network": "all",
|
||||||
|
"packages": [
|
||||||
|
"pages/common"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tabBar": {
|
||||||
|
"color": "#ABABAB",
|
||||||
|
"selectedColor": "#333333",
|
||||||
|
"borderStyle": "black",
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"pagePath": "pages/home/index",
|
||||||
|
"iconPath": "static/images/ic_tab_home_normal.png",
|
||||||
|
"selectedIconPath": "static/images/ic_tab_home_active.png",
|
||||||
|
"text": "首页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/qrcode/index",
|
||||||
|
"iconPath": "static/images/ic_tab_qrcode_normal.png",
|
||||||
|
"selectedIconPath": "static/images/ic_tab_qrcode_active.png",
|
||||||
|
"text": "支付码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/mall/index",
|
||||||
|
"iconPath": "static/images/ic_tab_mall_normal.png",
|
||||||
|
"selectedIconPath": "static/images/ic_tab_mall_active.png",
|
||||||
|
"text": "商城"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/mine/index",
|
||||||
|
"iconPath": "static/images/ic_tab_mine_normal.png",
|
||||||
|
"selectedIconPath": "static/images/ic_tab_mine_active.png",
|
||||||
|
"text": "我的"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"globalStyle": {
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"navigationBarTitleText": "uni-app",
|
||||||
|
"navigationBarBackgroundColor": "#F8F8F8",
|
||||||
|
"backgroundColor": "#F8F8F8"
|
||||||
|
}
|
||||||
|
}
|
167
src/pages/common/login/index.vue
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="login-form-wrap">
|
||||||
|
<view class="title">
|
||||||
|
欢迎登录
|
||||||
|
</view>
|
||||||
|
<input v-model="tel" class="u-border-bottom" type="number" placeholder="请输入手机号">
|
||||||
|
<view class="u-border-bottom my-40rpx flex">
|
||||||
|
<input v-model="code" class="flex-1" type="number" placeholder="请输入验证码">
|
||||||
|
<view>
|
||||||
|
<u-code ref="uCodeRef" @change="codeChange" />
|
||||||
|
<u-button :text="tips" type="success" size="mini" @click="getCode" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button :style="[inputStyle]" class="login-btn" @tap="submit">
|
||||||
|
登录
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<view class="alternative">
|
||||||
|
<view class="password">
|
||||||
|
密码登录
|
||||||
|
</view>
|
||||||
|
<view class="issue">
|
||||||
|
遇到问题
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="login-type-wrap">
|
||||||
|
<view class="item wechat">
|
||||||
|
<view class="icon">
|
||||||
|
<u-icon size="35" name="weixin-fill" color="rgb(83,194,64)" />
|
||||||
|
</view>
|
||||||
|
微信
|
||||||
|
</view>
|
||||||
|
<view class="item QQ">
|
||||||
|
<view class="icon">
|
||||||
|
<u-icon size="35" name="qq-fill" color="rgb(17,183,233)" />
|
||||||
|
</view>
|
||||||
|
QQ
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="hint">
|
||||||
|
登录代表同意
|
||||||
|
<text class="link">
|
||||||
|
用户协议、隐私政策,
|
||||||
|
</text>
|
||||||
|
并授权使用您的账号信息(如昵称、头像、收获地址)以便您统一管理
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import uCode from 'uview-plus/components/u-code/u-code.vue';
|
||||||
|
import { setToken } from '@/utils/auth';
|
||||||
|
|
||||||
|
const tel = ref<string>('18502811111');
|
||||||
|
const code = ref<string>('1234');
|
||||||
|
const tips = ref<string>();
|
||||||
|
const uCodeRef = ref<InstanceType<typeof uCode> | null>(null);
|
||||||
|
|
||||||
|
const inputStyle = computed<CSSStyleDeclaration>(() => {
|
||||||
|
const style = {} as CSSStyleDeclaration;
|
||||||
|
if (tel.value && code.value) {
|
||||||
|
style.color = '#fff';
|
||||||
|
style.backgroundColor = uni.$u.color.warning;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
});
|
||||||
|
|
||||||
|
function codeChange(text: string) {
|
||||||
|
tips.value = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCode() {
|
||||||
|
if (uCodeRef.value?.canGetCode) {
|
||||||
|
// 模拟向后端请求验证码
|
||||||
|
uni.showLoading({
|
||||||
|
title: '正在获取验证码',
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.$u.toast('验证码已发送');
|
||||||
|
// 通知验证码组件内部开始倒计时
|
||||||
|
uCodeRef.value?.start();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uni.$u.toast('倒计时结束后再发送');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
if (uni.$u.test.mobile(tel.value)) {
|
||||||
|
setToken('1234567890');
|
||||||
|
uni.reLaunch({ url: '/pages/home/index' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-form-wrap {
|
||||||
|
margin: 80rpx auto 0;
|
||||||
|
width: 600rpx;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 100rpx;
|
||||||
|
font-size: 60rpx;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding-bottom: 6rpx;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
margin-bottom: 60rpx;
|
||||||
|
color: $u-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
padding: 12rpx 0;
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
background-color: rgb(253 243 208);
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alternative {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 30rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-type-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 350rpx 150rpx 150rpx;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
padding: 20rpx 40rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: $u-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
12
src/pages/common/webview/index.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<web-view class="h-full" :src="url" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const url = ref<string>('');
|
||||||
|
|
||||||
|
onLoad((params: any) => {
|
||||||
|
if (params.url)
|
||||||
|
url.value = params.url;
|
||||||
|
});
|
||||||
|
</script>
|
18
src/pages/home/index.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<view class='flex flex-col items-center justify-center'>
|
||||||
|
<swiper class='swiper'>
|
||||||
|
<swiper-item v-for='(item, index) in bannerList' :key='index'>
|
||||||
|
<image :src='item' mode='aspectFill' />
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts'>
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
|
const store = useUserStore();
|
||||||
|
|
||||||
|
const bannerList = ref<string[]>(['1', '2', '3', '4']);
|
||||||
|
console.log('store.user_name', store.user_name);
|
||||||
|
</script>
|
25
src/pages/mall/index.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<view class="flex flex-col items-center justify-center">
|
||||||
|
<image
|
||||||
|
class="mb-50rpx mt-200rpx h-200rpx w-200rpx"
|
||||||
|
src="@/static/images/logo.png"
|
||||||
|
width="200rpx"
|
||||||
|
height="200rpx"
|
||||||
|
/>
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<text class="font-size-36rpx color-gray-700">
|
||||||
|
{{ title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
|
const title = ref<string>();
|
||||||
|
title.value = import.meta.env.VITE_APP_TITLE;
|
||||||
|
|
||||||
|
const store = useUserStore();
|
||||||
|
console.log('store.user_name', store.user_name);
|
||||||
|
</script>
|
25
src/pages/mine/index.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<view class="flex flex-col items-center justify-center">
|
||||||
|
<image
|
||||||
|
class="mb-50rpx mt-200rpx h-200rpx w-200rpx"
|
||||||
|
src="@/static/images/logo.png"
|
||||||
|
width="200rpx"
|
||||||
|
height="200rpx"
|
||||||
|
/>
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<text class="font-size-36rpx color-gray-700">
|
||||||
|
{{ title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
|
const title = ref<string>();
|
||||||
|
title.value = import.meta.env.VITE_APP_TITLE;
|
||||||
|
|
||||||
|
const store = useUserStore();
|
||||||
|
console.log('store.user_name', store.user_name);
|
||||||
|
</script>
|
25
src/pages/qrcode/index.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<view class="flex flex-col items-center justify-center">
|
||||||
|
<image
|
||||||
|
class="mb-50rpx mt-200rpx h-200rpx w-200rpx"
|
||||||
|
src="@/static/images/logo.png"
|
||||||
|
width="200rpx"
|
||||||
|
height="200rpx"
|
||||||
|
/>
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<text class="font-size-36rpx color-gray-700">
|
||||||
|
{{ title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
|
const title = ref<string>();
|
||||||
|
title.value = import.meta.env.VITE_APP_TITLE;
|
||||||
|
|
||||||
|
const store = useUserStore();
|
||||||
|
console.log('store.user_name', store.user_name);
|
||||||
|
</script>
|
37
src/permission.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { getToken } from '@/utils/auth';
|
||||||
|
|
||||||
|
// 登录页面
|
||||||
|
const loginPage = '/pages/common/login/index';
|
||||||
|
// 页面白名单
|
||||||
|
const whiteList = ['/', '/pages/common/login/index', '/pages/home/index'];
|
||||||
|
|
||||||
|
// 检查地址白名单
|
||||||
|
function checkWhite(url: string) {
|
||||||
|
const path = url.split('?')[0];
|
||||||
|
return whiteList.includes(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面跳转验证拦截器
|
||||||
|
const list = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'];
|
||||||
|
list.forEach((item) => {
|
||||||
|
uni.addInterceptor(item, {
|
||||||
|
invoke(to) {
|
||||||
|
if (getToken()) {
|
||||||
|
if (to.url === loginPage)
|
||||||
|
uni.reLaunch({ url: '/' });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (checkWhite(to.url))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
uni.reLaunch({ url: loginPage });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.log(err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
BIN
src/static/images/ic_tab_home_active.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src/static/images/ic_tab_home_normal.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src/static/images/ic_tab_mall_active.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
src/static/images/ic_tab_mall_normal.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/static/images/ic_tab_mine_active.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
src/static/images/ic_tab_mine_normal.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/static/images/ic_tab_qrcode_active.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src/static/images/ic_tab_qrcode_normal.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
src/static/images/logo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
4
src/static/styles/common.scss
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
page {
|
||||||
|
font-size: 28rpx;
|
||||||
|
background-color: #f9f9f8;
|
||||||
|
}
|
20
src/store/index.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { App } from 'vue';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
|
||||||
|
// 导入子模块
|
||||||
|
import useAppStore from './modules/app';
|
||||||
|
import useUserStore from './modules/user';
|
||||||
|
|
||||||
|
// import piniaPersist from 'pinia-plugin-persist-uni';
|
||||||
|
|
||||||
|
// 安装pinia状态管理插件
|
||||||
|
function setupStore(app: App) {
|
||||||
|
const store = createPinia();
|
||||||
|
// store.use(piniaPersist);
|
||||||
|
|
||||||
|
app.use(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出模块
|
||||||
|
export { useAppStore, useUserStore };
|
||||||
|
export default setupStore;
|
58
src/store/modules/app/index.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import type { AppState } from './types';
|
||||||
|
|
||||||
|
const useAppStore = defineStore('app', {
|
||||||
|
state: (): AppState => ({
|
||||||
|
systemInfo: {} as UniApp.GetSystemInfoResult,
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
getSystemInfo(): UniApp.GetSystemInfoResult {
|
||||||
|
return this.systemInfo;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setSystemInfo(info: UniApp.GetSystemInfoResult) {
|
||||||
|
this.systemInfo = info;
|
||||||
|
},
|
||||||
|
initSystemInfo() {
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: (res: UniApp.GetSystemInfoResult) => {
|
||||||
|
this.setSystemInfo(res);
|
||||||
|
},
|
||||||
|
fail: (err: any) => {
|
||||||
|
console.error(err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
checkUpdate() {
|
||||||
|
const updateManager = uni.getUpdateManager();
|
||||||
|
updateManager.onCheckForUpdate((res: UniApp.OnCheckForUpdateResult) => {
|
||||||
|
// 请求完新版本信息的回调
|
||||||
|
|
||||||
|
console.log(res.hasUpdate);
|
||||||
|
});
|
||||||
|
updateManager.onUpdateReady(() => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '更新提示',
|
||||||
|
content: '新版本已经准备好,是否重启应用?',
|
||||||
|
success(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||||
|
updateManager.applyUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
updateManager.onUpdateFailed((res: any) => {
|
||||||
|
console.error(res);
|
||||||
|
// 新的版本下载失败
|
||||||
|
uni.showToast({
|
||||||
|
title: '更新失败',
|
||||||
|
icon: 'error',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useAppStore;
|
3
src/store/modules/app/types.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface AppState {
|
||||||
|
systemInfo: UniApp.GetSystemInfoResult;
|
||||||
|
}
|
82
src/store/modules/user/index.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import type { UserState, providerType } from './types';
|
||||||
|
import {
|
||||||
|
getUserProfile,
|
||||||
|
loginByCode,
|
||||||
|
login as userLogin,
|
||||||
|
logout as userLogout,
|
||||||
|
} from '@/api/user/index';
|
||||||
|
import { clearToken, setToken } from '@/utils/auth';
|
||||||
|
import type { LoginParams } from '@/api/user/types';
|
||||||
|
|
||||||
|
const useUserStore = defineStore('user', {
|
||||||
|
state: (): UserState => ({
|
||||||
|
user_id: '',
|
||||||
|
user_name: '江阳小道',
|
||||||
|
avatar: '',
|
||||||
|
token: '',
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
userInfo(state: UserState): UserState {
|
||||||
|
return { ...state };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
// 设置用户的信息
|
||||||
|
setInfo(partial: Partial<UserState>) {
|
||||||
|
this.$patch(partial);
|
||||||
|
},
|
||||||
|
// 重置用户信息
|
||||||
|
resetInfo() {
|
||||||
|
this.$reset();
|
||||||
|
},
|
||||||
|
// 获取用户信息
|
||||||
|
async info() {
|
||||||
|
const result = await getUserProfile();
|
||||||
|
this.setInfo(result);
|
||||||
|
},
|
||||||
|
// 异步登录并存储token
|
||||||
|
login(loginForm: LoginParams) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const result = await userLogin(loginForm);
|
||||||
|
const token = result?.token;
|
||||||
|
if (token) {
|
||||||
|
setToken(token);
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// Logout
|
||||||
|
async logout() {
|
||||||
|
await userLogout();
|
||||||
|
this.resetInfo();
|
||||||
|
clearToken();
|
||||||
|
},
|
||||||
|
// 小程序授权登录
|
||||||
|
authLogin(provider: providerType = 'weixin') {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.login({
|
||||||
|
provider,
|
||||||
|
success: async (result: UniApp.LoginRes) => {
|
||||||
|
if (result.code) {
|
||||||
|
const res = await loginByCode({ code: result.code });
|
||||||
|
resolve(res);
|
||||||
|
} else {
|
||||||
|
reject(new Error(result.errMsg));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err: any) => {
|
||||||
|
console.error(`login error: ${err}`);
|
||||||
|
reject(err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useUserStore;
|
16
src/store/modules/user/types.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export type RoleType = '' | '*' | 'user';
|
||||||
|
export interface UserState {
|
||||||
|
user_id?: string;
|
||||||
|
user_name?: string;
|
||||||
|
avatar?: string;
|
||||||
|
token?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type providerType =
|
||||||
|
| 'weixin'
|
||||||
|
| 'qq'
|
||||||
|
| 'sinaweibo'
|
||||||
|
| 'xiaomi'
|
||||||
|
| 'apple'
|
||||||
|
| 'univerify'
|
||||||
|
| undefined;
|
1
src/uni.scss
Normal file
@ -0,0 +1 @@
|
|||||||
|
@import 'uview-plus/theme.scss';
|
15
src/utils/auth/index.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const TokenKey = 'admin-token';
|
||||||
|
const TokenPrefix = 'Bearer ';
|
||||||
|
function isLogin() {
|
||||||
|
return !!uni.getStorageSync(TokenKey);
|
||||||
|
}
|
||||||
|
function getToken() {
|
||||||
|
return uni.getStorageSync(TokenKey);
|
||||||
|
}
|
||||||
|
function setToken(token: string) {
|
||||||
|
uni.setStorageSync(TokenKey, token);
|
||||||
|
}
|
||||||
|
function clearToken() {
|
||||||
|
uni.removeStorageSync(TokenKey);
|
||||||
|
}
|
||||||
|
export { TokenPrefix, isLogin, getToken, setToken, clearToken };
|
28
src/utils/common/index.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 小程序更新检测
|
||||||
|
export function mpUpdate() {
|
||||||
|
const updateManager = uni.getUpdateManager();
|
||||||
|
updateManager.onCheckForUpdate((res) => {
|
||||||
|
// 请求完新版本信息的回调
|
||||||
|
console.log(res.hasUpdate);
|
||||||
|
});
|
||||||
|
updateManager.onUpdateReady(() => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '更新提示',
|
||||||
|
content: '检测到新版本,是否下载新版本并重启小程序?',
|
||||||
|
success(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||||
|
updateManager.applyUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
updateManager.onUpdateFailed(() => {
|
||||||
|
// 新的版本下载失败
|
||||||
|
uni.showModal({
|
||||||
|
title: '已经有新版本了哟~',
|
||||||
|
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
|
||||||
|
showCancel: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
4
src/utils/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './auth';
|
||||||
|
export * from './common';
|
||||||
|
export * from './modals';
|
||||||
|
export * from './request';
|
81
src/utils/modals/index.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
interface IShowToastOptions {
|
||||||
|
title?: string
|
||||||
|
icon?: 'success' | 'loading' | 'error' | 'none'
|
||||||
|
image?: string
|
||||||
|
duration?: number
|
||||||
|
position?: 'top' | 'center' | 'bottom'
|
||||||
|
mask?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILoadingOptions {
|
||||||
|
show?: (content?: string) => void
|
||||||
|
hide?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IShowModalOptions {
|
||||||
|
title?: string
|
||||||
|
content?: string
|
||||||
|
showCancel?: boolean
|
||||||
|
cancelText?: string
|
||||||
|
cancelColor?: string
|
||||||
|
confirmText?: string
|
||||||
|
confirmColor?: string
|
||||||
|
editable?: boolean
|
||||||
|
placeholderText?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轻提示
|
||||||
|
* @param {string} content 提示内容
|
||||||
|
* @param {object} option 配置
|
||||||
|
*/
|
||||||
|
export function Toast(content: string, option: IShowToastOptions = {}) {
|
||||||
|
uni.showToast({
|
||||||
|
title: content,
|
||||||
|
icon: 'none',
|
||||||
|
mask: true,
|
||||||
|
duration: 1500,
|
||||||
|
...option,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loading 提示框
|
||||||
|
* @param {string} content 提示内容
|
||||||
|
*/
|
||||||
|
export const Loading: ILoadingOptions = {
|
||||||
|
show: (content = '加载中') => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: content,
|
||||||
|
mask: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
hide: () => {
|
||||||
|
uni.hideLoading();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog 提示框
|
||||||
|
* @param {string} content 提示内容
|
||||||
|
* @param {object} option 配置
|
||||||
|
*/
|
||||||
|
export function Dialog(content: string, option: IShowModalOptions = {}) {
|
||||||
|
option.showCancel = false;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '温馨提示',
|
||||||
|
content,
|
||||||
|
showCancel: false,
|
||||||
|
confirmColor: '#1677FF',
|
||||||
|
success(res) {
|
||||||
|
if (res.confirm)
|
||||||
|
resolve(res);
|
||||||
|
},
|
||||||
|
fail() {
|
||||||
|
reject(new Error('Alert 调用失败 !'));
|
||||||
|
},
|
||||||
|
...option,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
42
src/utils/request/index.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 引入配置
|
||||||
|
import type { HttpRequestConfig } from 'uview-plus/libs/luch-request/index';
|
||||||
|
import { requestInterceptors, responseInterceptors } from './interceptors';
|
||||||
|
import type { IResponse } from './type';
|
||||||
|
|
||||||
|
// 引入拦截器配置
|
||||||
|
export function setupRequest() {
|
||||||
|
uni.$u.http.setConfig((defaultConfig: HttpRequestConfig) => {
|
||||||
|
/* defaultConfig 为默认全局配置 */
|
||||||
|
defaultConfig.baseURL = import.meta.env.VITE_APP_BASE_API;
|
||||||
|
return defaultConfig;
|
||||||
|
});
|
||||||
|
requestInterceptors();
|
||||||
|
responseInterceptors();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function request<T = any>(config: HttpRequestConfig): Promise<T> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
uni.$u.http.request(config).then((res: IResponse) => {
|
||||||
|
const { result } = res;
|
||||||
|
resolve(result as T);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get<T = any>(config: HttpRequestConfig): Promise<T> {
|
||||||
|
return request({ ...config, method: 'GET' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function post<T = any>(config: HttpRequestConfig): Promise<T> {
|
||||||
|
return request({ ...config, method: 'POST' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function upload<T = any>(config: HttpRequestConfig): Promise<T> {
|
||||||
|
return request({ ...config, method: 'UPLOAD' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function download<T = any>(config: HttpRequestConfig): Promise<T> {
|
||||||
|
return request({ ...config, method: 'DOWNLOAD' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default setupRequest;
|
104
src/utils/request/interceptors.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import type {
|
||||||
|
HttpError,
|
||||||
|
HttpRequestConfig,
|
||||||
|
HttpResponse,
|
||||||
|
} from 'uview-plus/libs/luch-request/index';
|
||||||
|
import { showMessage } from './status';
|
||||||
|
import { getToken } from '@/utils/auth';
|
||||||
|
import useUserStore from '@/store/modules/user';
|
||||||
|
|
||||||
|
// 是否正在刷新token的标记
|
||||||
|
let isRefreshing: boolean = false;
|
||||||
|
// 重试队列,每一项将是一个待执行的函数形式
|
||||||
|
let requestQueue: (() => void)[] = [];
|
||||||
|
|
||||||
|
function requestInterceptors() {
|
||||||
|
/**
|
||||||
|
* 请求拦截
|
||||||
|
* @param {Object} http
|
||||||
|
*/
|
||||||
|
uni.$u.http.interceptors.request.use(
|
||||||
|
(config: HttpRequestConfig) => {
|
||||||
|
// 可使用async await 做异步操作
|
||||||
|
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
|
||||||
|
config.data = config.data || {};
|
||||||
|
// token设置
|
||||||
|
const token = getToken();
|
||||||
|
if (token && config.header) {
|
||||||
|
config.header.token = token;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(
|
||||||
|
config: any, // 可使用async await 做异步操作
|
||||||
|
) => Promise.reject(config),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function responseInterceptors() {
|
||||||
|
/**
|
||||||
|
* 响应拦截
|
||||||
|
* @param {Object} http
|
||||||
|
*/
|
||||||
|
uni.$u.http.interceptors.response.use(
|
||||||
|
async (response: HttpResponse) => {
|
||||||
|
/* 对响应成功做点什么 可使用async await 做异步操作 */
|
||||||
|
const data = response.data;
|
||||||
|
// 配置参数
|
||||||
|
const config = response.config;
|
||||||
|
// 自定义参数
|
||||||
|
const custom = config?.custom;
|
||||||
|
|
||||||
|
// 请求成功则返回结果
|
||||||
|
if (data.code === 200) {
|
||||||
|
return data || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录状态失效,重新登录
|
||||||
|
if (data.code === 401) {
|
||||||
|
// 是否在获取token中,防止重复获取
|
||||||
|
if (!isRefreshing) {
|
||||||
|
// 修改登录状态为true
|
||||||
|
isRefreshing = true;
|
||||||
|
await useUserStore().authLogin();
|
||||||
|
// 登录完成之后,开始执行队列请求
|
||||||
|
requestQueue.forEach(cb => cb());
|
||||||
|
// 重试完了清空这个队列
|
||||||
|
requestQueue = [];
|
||||||
|
isRefreshing = false;
|
||||||
|
// 重新执行本次请求
|
||||||
|
return uni.$u.http.request(config);
|
||||||
|
} else {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
// 将resolve放进队列,用一个函数形式来保存,等登录后直接执行
|
||||||
|
requestQueue.push(() => {
|
||||||
|
resolve(uni.$u.http.request(config));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
|
||||||
|
if (custom?.toast !== false) {
|
||||||
|
uni.$u.toast(data.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要catch返回,则进行reject
|
||||||
|
if (custom?.catch) {
|
||||||
|
return Promise.reject(data);
|
||||||
|
} else {
|
||||||
|
// 否则返回一个pending中的promise
|
||||||
|
return new Promise(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(response: HttpError) => {
|
||||||
|
if (response.statusCode) {
|
||||||
|
// 请求已发出,但是不在2xx的范围
|
||||||
|
showMessage(response.statusCode);
|
||||||
|
return Promise.reject(response.data);
|
||||||
|
}
|
||||||
|
showMessage('网络连接异常,请稍后再试!');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { requestInterceptors, responseInterceptors };
|
41
src/utils/request/status.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
export const showMessage = (status: number | string): string => {
|
||||||
|
let message = '';
|
||||||
|
switch (status) {
|
||||||
|
case 400:
|
||||||
|
message = '请求错误(400)';
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
message = '未授权,请重新登录(401)';
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
message = '拒绝访问(403)';
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
message = '请求出错(404)';
|
||||||
|
break;
|
||||||
|
case 408:
|
||||||
|
message = '请求超时(408)';
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
message = '服务器错误(500)';
|
||||||
|
break;
|
||||||
|
case 501:
|
||||||
|
message = '服务未实现(501)';
|
||||||
|
break;
|
||||||
|
case 502:
|
||||||
|
message = '网络错误(502)';
|
||||||
|
break;
|
||||||
|
case 503:
|
||||||
|
message = '服务不可用(503)';
|
||||||
|
break;
|
||||||
|
case 504:
|
||||||
|
message = '网络超时(504)';
|
||||||
|
break;
|
||||||
|
case 505:
|
||||||
|
message = 'HTTP版本不受支持(505)';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = `连接出错(${status})!`;
|
||||||
|
}
|
||||||
|
return `${message},请检查网络或联系管理员!`;
|
||||||
|
};
|
7
src/utils/request/type.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// 返回res.data的interface
|
||||||
|
export interface IResponse<T = any> {
|
||||||
|
code: number | string;
|
||||||
|
result: T;
|
||||||
|
message: string;
|
||||||
|
status: string | number;
|
||||||
|
}
|
116
stylelint.config.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
module.exports = {
|
||||||
|
"extends": ["stylelint-config-standard", "stylelint-config-standard-vue"],
|
||||||
|
"plugins": ["stylelint-order"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["**/*.(scss|css|vue|html)"],
|
||||||
|
"customSyntax": "postcss-scss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["**/*.(html|vue)"],
|
||||||
|
"customSyntax": "postcss-html"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ignoreFiles": [
|
||||||
|
"**/*.js",
|
||||||
|
"**/*.jsx",
|
||||||
|
"**/*.tsx",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.json",
|
||||||
|
"**/*.md",
|
||||||
|
"**/*.yaml",
|
||||||
|
"dist/*",
|
||||||
|
"uni_modules/*"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"import-notation": "string",
|
||||||
|
"unit-no-unknown": [true, { "ignoreUnits": ["rpx"] }],
|
||||||
|
"no-descending-specificity": null,
|
||||||
|
"selector-pseudo-element-no-unknown": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignorePseudoElements": ["v-deep"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selector-pseudo-class-no-unknown": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignorePseudoClasses": ["deep"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selector-type-no-unknown": [true, { "ignoreTypes": ["page", "radio", "checkbox", "scroll-view"] }],
|
||||||
|
"order/properties-order": [
|
||||||
|
"position",
|
||||||
|
"top",
|
||||||
|
"right",
|
||||||
|
"bottom",
|
||||||
|
"left",
|
||||||
|
"z-index",
|
||||||
|
"display",
|
||||||
|
"justify-content",
|
||||||
|
"align-items",
|
||||||
|
"float",
|
||||||
|
"clear",
|
||||||
|
"overflow",
|
||||||
|
"overflow-x",
|
||||||
|
"overflow-y",
|
||||||
|
"padding",
|
||||||
|
"padding-top",
|
||||||
|
"padding-right",
|
||||||
|
"padding-bottom",
|
||||||
|
"padding-left",
|
||||||
|
"margin",
|
||||||
|
"margin-top",
|
||||||
|
"margin-right",
|
||||||
|
"margin-bottom",
|
||||||
|
"margin-left",
|
||||||
|
"width",
|
||||||
|
"min-width",
|
||||||
|
"max-width",
|
||||||
|
"height",
|
||||||
|
"min-height",
|
||||||
|
"max-height",
|
||||||
|
"font-size",
|
||||||
|
"font-family",
|
||||||
|
"text-align",
|
||||||
|
"text-justify",
|
||||||
|
"text-indent",
|
||||||
|
"text-overflow",
|
||||||
|
"text-decoration",
|
||||||
|
"white-space",
|
||||||
|
"color",
|
||||||
|
"background",
|
||||||
|
"background-position",
|
||||||
|
"background-repeat",
|
||||||
|
"background-size",
|
||||||
|
"background-color",
|
||||||
|
"background-clip",
|
||||||
|
"border",
|
||||||
|
"border-style",
|
||||||
|
"border-width",
|
||||||
|
"border-color",
|
||||||
|
"border-top-style",
|
||||||
|
"border-top-width",
|
||||||
|
"border-top-color",
|
||||||
|
"border-right-style",
|
||||||
|
"border-right-width",
|
||||||
|
"border-right-color",
|
||||||
|
"border-bottom-style",
|
||||||
|
"border-bottom-width",
|
||||||
|
"border-bottom-color",
|
||||||
|
"border-left-style",
|
||||||
|
"border-left-width",
|
||||||
|
"border-left-color",
|
||||||
|
"border-radius",
|
||||||
|
"opacity",
|
||||||
|
"filter",
|
||||||
|
"list-style",
|
||||||
|
"outline",
|
||||||
|
"visibility",
|
||||||
|
"box-shadow",
|
||||||
|
"text-shadow",
|
||||||
|
"resize",
|
||||||
|
"transition"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
37
tsconfig.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"module": "ESNext",
|
||||||
|
"target": "es2016",
|
||||||
|
"lib": ["DOM", "ESNext"],
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
},
|
||||||
|
"types": ["@dcloudio/types", "@uni-helper/uni-app-types"]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
"types/**/*.d.ts",
|
||||||
|
"types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": ["dist", "node_modules", "uni_modules"],
|
||||||
|
// uni-app Component type prompt
|
||||||
|
"vueCompilerOptions": {
|
||||||
|
"nativeTags": ["block", "component", "template", "slot"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
288
types/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
// Generated by unplugin-auto-import
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||||
|
const computed: typeof import('vue')['computed']
|
||||||
|
const createApp: typeof import('vue')['createApp']
|
||||||
|
const createPinia: typeof import('pinia')['createPinia']
|
||||||
|
const customRef: typeof import('vue')['customRef']
|
||||||
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||||
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
|
const defineStore: typeof import('pinia')['defineStore']
|
||||||
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
|
const getActivePinia: typeof import('pinia')['getActivePinia']
|
||||||
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||||
|
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||||
|
const h: typeof import('vue')['h']
|
||||||
|
const inject: typeof import('vue')['inject']
|
||||||
|
const isProxy: typeof import('vue')['isProxy']
|
||||||
|
const isReactive: typeof import('vue')['isReactive']
|
||||||
|
const isReadonly: typeof import('vue')['isReadonly']
|
||||||
|
const isRef: typeof import('vue')['isRef']
|
||||||
|
const mapActions: typeof import('pinia')['mapActions']
|
||||||
|
const mapGetters: typeof import('pinia')['mapGetters']
|
||||||
|
const mapState: typeof import('pinia')['mapState']
|
||||||
|
const mapStores: typeof import('pinia')['mapStores']
|
||||||
|
const mapWritableState: typeof import('pinia')['mapWritableState']
|
||||||
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
|
const onActivated: typeof import('vue')['onActivated']
|
||||||
|
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
|
||||||
|
const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
|
||||||
|
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||||
|
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||||
|
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||||
|
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||||
|
const onError: typeof import('@dcloudio/uni-app')['onError']
|
||||||
|
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||||
|
const onHide: typeof import('@dcloudio/uni-app')['onHide']
|
||||||
|
const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
|
||||||
|
const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
|
||||||
|
const onMounted: typeof import('vue')['onMounted']
|
||||||
|
const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
|
||||||
|
const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
|
||||||
|
const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
|
||||||
|
const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
|
||||||
|
const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
|
||||||
|
const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
|
||||||
|
const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
|
||||||
|
const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
|
||||||
|
const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
|
||||||
|
const onReady: typeof import('@dcloudio/uni-app')['onReady']
|
||||||
|
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||||
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||||
|
const onResize: typeof import('@dcloudio/uni-app')['onResize']
|
||||||
|
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||||
|
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||||
|
const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
|
||||||
|
const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
|
||||||
|
const onShow: typeof import('@dcloudio/uni-app')['onShow']
|
||||||
|
const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
|
||||||
|
const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
|
||||||
|
const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
|
||||||
|
const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
|
||||||
|
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||||
|
const onUpdated: typeof import('vue')['onUpdated']
|
||||||
|
const provide: typeof import('vue')['provide']
|
||||||
|
const reactive: typeof import('vue')['reactive']
|
||||||
|
const readonly: typeof import('vue')['readonly']
|
||||||
|
const ref: typeof import('vue')['ref']
|
||||||
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
|
const setActivePinia: typeof import('pinia')['setActivePinia']
|
||||||
|
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
||||||
|
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||||
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
|
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||||
|
const toRaw: typeof import('vue')['toRaw']
|
||||||
|
const toRef: typeof import('vue')['toRef']
|
||||||
|
const toRefs: typeof import('vue')['toRefs']
|
||||||
|
const toValue: typeof import('vue')['toValue']
|
||||||
|
const triggerRef: typeof import('vue')['triggerRef']
|
||||||
|
const unref: typeof import('vue')['unref']
|
||||||
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
|
const useSlots: typeof import('vue')['useSlots']
|
||||||
|
const watch: typeof import('vue')['watch']
|
||||||
|
const watchEffect: typeof import('vue')['watchEffect']
|
||||||
|
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||||
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||||
|
}
|
||||||
|
// for type re-export
|
||||||
|
declare global {
|
||||||
|
// @ts-ignore
|
||||||
|
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
||||||
|
import('vue')
|
||||||
|
}
|
||||||
|
// for vue template auto import
|
||||||
|
import { UnwrapRef } from 'vue'
|
||||||
|
declare module 'vue' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||||
|
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
||||||
|
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||||
|
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||||
|
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
|
||||||
|
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||||
|
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||||
|
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||||
|
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
||||||
|
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||||
|
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
|
||||||
|
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||||
|
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||||
|
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||||
|
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||||
|
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||||
|
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||||
|
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||||
|
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||||
|
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
||||||
|
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
||||||
|
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
||||||
|
readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
|
||||||
|
readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
|
||||||
|
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||||
|
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||||
|
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||||
|
readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
|
||||||
|
readonly onBackPress: UnwrapRef<typeof import('@dcloudio/uni-app')['onBackPress']>
|
||||||
|
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||||
|
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||||
|
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||||
|
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||||
|
readonly onError: UnwrapRef<typeof import('@dcloudio/uni-app')['onError']>
|
||||||
|
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||||
|
readonly onHide: UnwrapRef<typeof import('@dcloudio/uni-app')['onHide']>
|
||||||
|
readonly onLaunch: UnwrapRef<typeof import('@dcloudio/uni-app')['onLaunch']>
|
||||||
|
readonly onLoad: UnwrapRef<typeof import('@dcloudio/uni-app')['onLoad']>
|
||||||
|
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||||
|
readonly onNavigationBarButtonTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']>
|
||||||
|
readonly onNavigationBarSearchInputChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']>
|
||||||
|
readonly onNavigationBarSearchInputClicked: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']>
|
||||||
|
readonly onNavigationBarSearchInputConfirmed: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']>
|
||||||
|
readonly onNavigationBarSearchInputFocusChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']>
|
||||||
|
readonly onPageNotFound: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageNotFound']>
|
||||||
|
readonly onPageScroll: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageScroll']>
|
||||||
|
readonly onPullDownRefresh: UnwrapRef<typeof import('@dcloudio/uni-app')['onPullDownRefresh']>
|
||||||
|
readonly onReachBottom: UnwrapRef<typeof import('@dcloudio/uni-app')['onReachBottom']>
|
||||||
|
readonly onReady: UnwrapRef<typeof import('@dcloudio/uni-app')['onReady']>
|
||||||
|
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||||
|
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||||
|
readonly onResize: UnwrapRef<typeof import('@dcloudio/uni-app')['onResize']>
|
||||||
|
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||||
|
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||||
|
readonly onShareAppMessage: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareAppMessage']>
|
||||||
|
readonly onShareTimeline: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareTimeline']>
|
||||||
|
readonly onShow: UnwrapRef<typeof import('@dcloudio/uni-app')['onShow']>
|
||||||
|
readonly onTabItemTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onTabItemTap']>
|
||||||
|
readonly onThemeChange: UnwrapRef<typeof import('@dcloudio/uni-app')['onThemeChange']>
|
||||||
|
readonly onUnhandledRejection: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnhandledRejection']>
|
||||||
|
readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']>
|
||||||
|
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||||
|
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||||
|
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||||
|
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||||
|
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||||
|
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||||
|
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||||
|
readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
|
||||||
|
readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
|
||||||
|
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||||
|
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||||
|
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||||
|
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||||
|
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||||
|
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||||
|
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||||
|
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||||
|
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||||
|
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||||
|
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||||
|
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||||
|
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||||
|
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||||
|
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||||
|
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||||
|
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||||
|
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declare module '@vue/runtime-core' {
|
||||||
|
interface ComponentCustomProperties {
|
||||||
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||||
|
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
||||||
|
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||||
|
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||||
|
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
|
||||||
|
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||||
|
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||||
|
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||||
|
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
|
||||||
|
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||||
|
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
|
||||||
|
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||||
|
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||||
|
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||||
|
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||||
|
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||||
|
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||||
|
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||||
|
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||||
|
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
|
||||||
|
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
|
||||||
|
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
|
||||||
|
readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
|
||||||
|
readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
|
||||||
|
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||||
|
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||||
|
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||||
|
readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
|
||||||
|
readonly onBackPress: UnwrapRef<typeof import('@dcloudio/uni-app')['onBackPress']>
|
||||||
|
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||||
|
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||||
|
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||||
|
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||||
|
readonly onError: UnwrapRef<typeof import('@dcloudio/uni-app')['onError']>
|
||||||
|
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||||
|
readonly onHide: UnwrapRef<typeof import('@dcloudio/uni-app')['onHide']>
|
||||||
|
readonly onLaunch: UnwrapRef<typeof import('@dcloudio/uni-app')['onLaunch']>
|
||||||
|
readonly onLoad: UnwrapRef<typeof import('@dcloudio/uni-app')['onLoad']>
|
||||||
|
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||||
|
readonly onNavigationBarButtonTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']>
|
||||||
|
readonly onNavigationBarSearchInputChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']>
|
||||||
|
readonly onNavigationBarSearchInputClicked: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']>
|
||||||
|
readonly onNavigationBarSearchInputConfirmed: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']>
|
||||||
|
readonly onNavigationBarSearchInputFocusChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']>
|
||||||
|
readonly onPageNotFound: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageNotFound']>
|
||||||
|
readonly onPageScroll: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageScroll']>
|
||||||
|
readonly onPullDownRefresh: UnwrapRef<typeof import('@dcloudio/uni-app')['onPullDownRefresh']>
|
||||||
|
readonly onReachBottom: UnwrapRef<typeof import('@dcloudio/uni-app')['onReachBottom']>
|
||||||
|
readonly onReady: UnwrapRef<typeof import('@dcloudio/uni-app')['onReady']>
|
||||||
|
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||||
|
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||||
|
readonly onResize: UnwrapRef<typeof import('@dcloudio/uni-app')['onResize']>
|
||||||
|
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||||
|
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||||
|
readonly onShareAppMessage: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareAppMessage']>
|
||||||
|
readonly onShareTimeline: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareTimeline']>
|
||||||
|
readonly onShow: UnwrapRef<typeof import('@dcloudio/uni-app')['onShow']>
|
||||||
|
readonly onTabItemTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onTabItemTap']>
|
||||||
|
readonly onThemeChange: UnwrapRef<typeof import('@dcloudio/uni-app')['onThemeChange']>
|
||||||
|
readonly onUnhandledRejection: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnhandledRejection']>
|
||||||
|
readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']>
|
||||||
|
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||||
|
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||||
|
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||||
|
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||||
|
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||||
|
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||||
|
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||||
|
readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
|
||||||
|
readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
|
||||||
|
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||||
|
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||||
|
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||||
|
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||||
|
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||||
|
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||||
|
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||||
|
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||||
|
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||||
|
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||||
|
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||||
|
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||||
|
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||||
|
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||||
|
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||||
|
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||||
|
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||||
|
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||||
|
}
|
||||||
|
}
|
14
types/components.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
export {}
|
||||||
|
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
PageNav: typeof import('./../src/components/page-nav/page-nav.vue')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
}
|
||||||
|
}
|
27
types/global.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { VNodeChild } from 'vue';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// vue
|
||||||
|
declare type VueNode = VNodeChild | JSX.Element;
|
||||||
|
|
||||||
|
declare type TimeoutHandle = ReturnType<typeof setTimeout>;
|
||||||
|
declare type IntervalHandle = ReturnType<typeof setInterval>;
|
||||||
|
|
||||||
|
interface ImportMetaEnv extends ViteEnv {
|
||||||
|
__: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface ViteEnv {
|
||||||
|
VITE_APP_TITLE?: string;
|
||||||
|
VITE_APP_BASE_API: string;
|
||||||
|
VITE_DROP_CONSOLE: Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare function parseInt(s: string | number, radix?: number): number;
|
||||||
|
|
||||||
|
declare function parseFloat(string: string | number): number;
|
||||||
|
|
||||||
|
declare interface Uni {
|
||||||
|
$u: any
|
||||||
|
}
|
||||||
|
}
|
10
types/module.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare module '*.vue' {
|
||||||
|
import { DefineComponent } from 'vue';
|
||||||
|
const component: DefineComponent<{}, {}, any>;
|
||||||
|
export default component;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'uview-plus';
|
||||||
|
declare module 'uview-plus/libs/mixin/mpShare.js';
|
57
uno.config.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import type { Preset, SourceCodeTransformer } from 'unocss';
|
||||||
|
import {
|
||||||
|
defineConfig,
|
||||||
|
presetAttributify,
|
||||||
|
presetUno,
|
||||||
|
transformerDirectives,
|
||||||
|
transformerVariantGroup,
|
||||||
|
} from 'unocss';
|
||||||
|
import {
|
||||||
|
presetApplet,
|
||||||
|
presetRemRpx,
|
||||||
|
transformerApplet,
|
||||||
|
transformerAttributify,
|
||||||
|
} from 'unocss-applet';
|
||||||
|
|
||||||
|
// eslint-disable-next-line n/prefer-global/process
|
||||||
|
const isApplet = process.env?.UNI_PLATFORM?.startsWith('mp-') ?? false;
|
||||||
|
const presets: Preset[] = [];
|
||||||
|
const transformers: SourceCodeTransformer[] = [];
|
||||||
|
|
||||||
|
if (isApplet) {
|
||||||
|
/**
|
||||||
|
* UnoCSS Applet
|
||||||
|
* @see https://github.com/unocss-applet/unocss-applet
|
||||||
|
*/
|
||||||
|
presets.push(presetApplet());
|
||||||
|
presets.push(presetRemRpx()); // 如果需要使用 rem 转 rpx 单位,需要启用此插件
|
||||||
|
transformers.push(transformerAttributify({ ignoreAttributes: ['block'] }));
|
||||||
|
transformers.push(transformerApplet());
|
||||||
|
} else {
|
||||||
|
presets.push(presetUno());
|
||||||
|
presets.push(presetAttributify());
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
presets,
|
||||||
|
/**
|
||||||
|
* 自定义快捷语句
|
||||||
|
* @see https://github.com/unocss/unocss#shortcuts
|
||||||
|
*/
|
||||||
|
shortcuts: [
|
||||||
|
['center', 'flex justify-center items-center'],
|
||||||
|
[
|
||||||
|
'btn',
|
||||||
|
'px-4 py-1 rounded inline-block bg-teal-600 text-white cursor-pointer hover:bg-teal-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'icon-btn',
|
||||||
|
'text-[0.9em] inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600 !outline-none',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
transformers: [
|
||||||
|
transformerDirectives(), // 启用 @apply 功能
|
||||||
|
transformerVariantGroup(), // 启用 () 分组功能
|
||||||
|
...transformers,
|
||||||
|
],
|
||||||
|
});
|
27
vite.config.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { resolve } from 'node:path';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import type { UserConfig } from 'vite';
|
||||||
|
import createVitePlugins from './build/vite/plugins';
|
||||||
|
import proxy from './build/vite/proxy';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig((): UserConfig => {
|
||||||
|
const isBuild = process.env.NODE_ENV === 'production';
|
||||||
|
return {
|
||||||
|
resolve: {
|
||||||
|
// https://cn.vitejs.dev/config/#resolve-alias
|
||||||
|
alias: {
|
||||||
|
// 设置别名
|
||||||
|
'@': resolve(__dirname, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// vite 相关配置
|
||||||
|
server: {
|
||||||
|
port: 8080,
|
||||||
|
host: true,
|
||||||
|
open: true,
|
||||||
|
proxy,
|
||||||
|
},
|
||||||
|
plugins: createVitePlugins(isBuild),
|
||||||
|
};
|
||||||
|
});
|