mirror of
https://github.com/xiangshu233/vue3-vant4-mobile.git
synced 2025-04-06 03:57:47 +08:00
Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9a4a8f8d17 | ||
|
049873710c | ||
|
19f9558553 | ||
|
d740923819 | ||
|
4f859c205e | ||
|
282e828d8f | ||
|
752b8ee8ca | ||
|
18c7ec1a32 | ||
|
43d53515b3 | ||
|
a3ec4ffce6 | ||
|
0255b23bd5 | ||
|
605b06a663 | ||
|
d2c4fd207b | ||
|
3cbf88638f | ||
|
977aae6d85 | ||
|
302bc7d955 | ||
|
e62d5988e1 | ||
|
8e5979c808 | ||
|
f01aecbf4e | ||
|
b68de1fe36 | ||
|
b8122de915 | ||
|
1ec8606740 | ||
|
10115a5331 | ||
|
facaf8e43c | ||
|
dc0c9797b5 | ||
|
581f72b4c7 | ||
|
3bf611a2e1 | ||
|
5351c56aa1 | ||
|
3b02172ca2 | ||
|
4651004c89 | ||
|
6daba832d5 | ||
|
12aa3ea636 | ||
|
45f87c1275 | ||
|
5de4e41022 | ||
|
d927b13470 | ||
|
630bc1c622 | ||
|
89bd2b2392 | ||
|
f4abc0c6db | ||
|
c75a78316d | ||
|
c9c2243d10 | ||
|
c99a54db58 |
.env.developmentREADME.md
build/vite/plugin
index.htmlpackage.jsonpnpm-lock.yamlpublic
src
App.vue
components
layout
main.tsrouter
settings
store
styles
theme
utils/http/axios
views
dashboard
example
exception
login
message
my
welcome
types
uno.config.tsvercel.jsonvite.config.ts@ -8,7 +8,7 @@ VITE_PUBLIC_PATH = /
|
||||
VITE_USE_MOCK = true
|
||||
|
||||
# 是否删除console
|
||||
VITE_DROP_CONSOLE = true
|
||||
VITE_DROP_CONSOLE = false
|
||||
|
||||
# 跨域代理,可以配置多个,请注意不要换行
|
||||
# VITE_PROXY = [["/appApi","http://localhost:8001"],["/upload","http://localhost:8001/upload"]]
|
||||
|
175
README.md
175
README.md
@ -14,9 +14,13 @@
|
||||
|
||||
<h1 align="center">vue3-vant4-mobile</h1>
|
||||
|
||||
## Stargazers over time
|
||||
|
||||
[](https://starchart.cc/xiangshu233/vue3-vant4-mobile)
|
||||
|
||||
## 介绍
|
||||
|
||||
👋👋👋 Vue3 Vant4 Mobile 使用了最新的 `Vue3.2`、`Vite3`、`Vant4`、`Pinia2`、`TypeScript`、`UnoCSS` 等主流技术开发,集成 `Dark Mode`(暗黑)模式和系统主题色,并且持久化保存,集成 `Mock` 数据,顺便写了登录/注册/找回密码 页面(包括逻辑),只需替换你的 API 即可,另外页面均可以 `<keep-alive>`,随便写了个包含 `NavBar`、`TabBar` 的 Layout,集成了 `Axios`、`useECharts`、`IconSvg`。
|
||||
👋👋👋 Vue3 Vant4 Mobile 使用了最新的 `Vue3.4`、`Vite5`、`Vant4`、`Pinia`、`TypeScript`、`UnoCSS` 等主流技术开发,集成 `Dark Mode`(暗黑)模式和系统主题色,并且持久化保存,集成 `Mock` 数据,顺便写了登录/注册/找回密码 页面(包括逻辑),只需替换你的 API 即可,另外页面均可以 `<keep-alive>`,随便写了个包含 `NavBar`、`TabBar` 的 Layout,集成了 `Axios`、`useECharts`、`IconSvg`。
|
||||
|
||||
项目使用了 [antfu](https://github.com/antfu) 大佬的 [antfu/eslint-config](https://github.com/antfu/eslint-config) 作为代码规范检查工具,摆脱繁琐无聊的 Eslint 配置,配合 `cz-git`、 `lint-staged`、`simple-git-hooks`可对暂存区代码提交校验,代码风格不合格可打断提交,保证多人协作开发时上游 Git 库的干净。
|
||||
|
||||
@ -27,25 +31,25 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022091917.png" width="400" alt="登录页面" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022092004.png" width="400" alt="主控台页(首页)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172041924.png" width="400" alt="主控台页(首页)" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022092015.png" width="400" alt="消息页(图标页)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022092022.png" width="400" alt="我的(我的信息页面)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172042123.png" width="400" alt="消息页(图标页)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172042858.png" width="400" alt="我的(我的信息页面)" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<details>
|
||||
<summary>展开预览暗黑模式下的界面截图。</summary>
|
||||
<summary>展开预览暗黑模式下的界面截图</summary>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022092052.png" width="400" alt="登录页面(暗黑模式)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022092140.png" width="400" alt="主控台页(暗黑模式)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172036432.png" width="400" alt="登录页面(暗黑模式)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172038413.png" width="400" alt="主控台页(暗黑模式)" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221022092224.png" width="400" alt="我的页面(暗黑模式)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2022/10/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20221023152559.png" width="400" alt="主题设置页面(暗黑模式)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172039913.png" width="400" alt="我的页面(暗黑模式)" /></td>
|
||||
<td><img src="https://fastly.jsdelivr.net/gh/xiangshu233/blogAssets/2023/12/202403172040019.png" width="400" alt="主题设置页面(暗黑模式)" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -74,19 +78,42 @@
|
||||
- [TypeScript](https://www.typescriptlang.org/) - 熟悉 `TypeScript` 基本语法
|
||||
- [Vue-Router-Next](https://router.vuejs.org/) - 熟悉 `Vue-Router`基本使用
|
||||
- [ECharts5](https://echarts.apache.org/handbook/zh/get-started/) - 熟悉 `Echarts` 基本使用
|
||||
- [xicons](https://www.xicons.org/#/) - 本项目推荐图标库,当然你也可以使用 `IconSVg`
|
||||
- [postcss-mobile-forever](https://github.com/wswmsword/postcss-mobile-forever) - 了解手机端 `px` 转 `viewport` 插件的作用
|
||||
- [Iconify](https://icones.js.org/) - 本项目推荐图标库,当然你也可以使用 `IconSvg`
|
||||
- [Postcss-Mobile-Forever](https://github.com/wswmsword/postcss-mobile-forever) - 了解手机端 `px` 转 `viewport` 插件的作用
|
||||
- [Lodash-es](https://www.lodashjs.com/) - `JS`高性能工具库
|
||||
- [UnoCSS](https://unocss.dev/) - 原子化 `CSS`,熟悉 `UnoCSS` 基本使用
|
||||
- [Mock.js](https://github.com/nuysoft/Mock) - 了解 `Mockjs` 基本语法
|
||||
- [ES6+](http://es6.ruanyifeng.com/) - 熟悉 `ES6` 基本语法
|
||||
|
||||
## 关于 Icon 的使用
|
||||
|
||||
项目使用 `unocss` 的 `icon` [预设](https://unocss.dev/presets/icons) 作为系统 Icon
|
||||
|
||||
请遵循以下约定使用图标
|
||||
|
||||
- `<prefix><collection>-<icon>`
|
||||
- `<prefix><collection>:<icon>`
|
||||
|
||||
```html
|
||||
<!-- A basic anchor icon from Phosphor icons -->
|
||||
<div class="i-ph-anchor-simple-thin" />
|
||||
<!-- An orange alarm from Material Design Icons -->
|
||||
<div class="i:mdi:alarm" />
|
||||
```
|
||||
|
||||
点击这里获取所有[可用的图标](https://icones.js.org/),找到想要的图标后点击复制 icon name 到 class 里即可
|
||||
|
||||
> [!WARNING]
|
||||
> 记得加 `i-xxx` 前缀,从 icones 复制的 icon name 是没有 `i-` 前缀的
|
||||
>
|
||||
> 更多详细使用请看 https://unocss.dev/presets/icons#icons-preset
|
||||
|
||||
## 环境准备
|
||||
|
||||
本地环境需要安装 [Pnpm](https://www.pnpm.cn/)、[Node.js](http://nodejs.org/) 和 [Git](https://git-scm.com/)
|
||||
|
||||
- 必须使用 [pnpm>=8.6.10](https://www.pnpm.cn/),否则依赖可能安装不上。
|
||||
- [Node.js](http://nodejs.org/) 版本要求`18.x`以上,且不能为`13.x`版本,这里推荐 ` ^20.9.0 || >=21.1.0`。
|
||||
- 推荐使用 [pnpm>=8.15.4](https://www.pnpm.cn/),否则依赖可能安装不上,打包报错等问题。
|
||||
- [Node.js](http://nodejs.org/) 版本要求`20.x`以上,这里推荐 `^20.9.0 || >=21.7.1`
|
||||
|
||||
## VS Code 配套插件
|
||||
|
||||
@ -104,6 +131,58 @@
|
||||
- [Todo Tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree) - 在树视图中显示 TODO、FIXME 等注释标签
|
||||
- [Trailing Spaces](https://marketplace.visualstudio.com/items?itemName=shardulm94.trailing-spaces) - 突出显示尾随空格并立即将其删除
|
||||
|
||||
## VS Code Eslint 支持(自动修复)
|
||||
|
||||
安装 [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
||||
|
||||
将以下设置添加到您的 `.vscode/settings.json` 中:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
// Enable the ESlint flat config support
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
|
||||
// Disable the default formatter, use eslint instead
|
||||
"prettier.enable": false,
|
||||
"editor.formatOnSave": false,
|
||||
|
||||
// Auto fix
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
|
||||
// Silent the stylistic rules in you IDE, but still auto fix them
|
||||
"eslint.rules.customizations": [
|
||||
{ "rule": "style/*", "severity": "off" },
|
||||
{ "rule": "format/*", "severity": "off" },
|
||||
{ "rule": "*-indent", "severity": "off" },
|
||||
{ "rule": "*-spacing", "severity": "off" },
|
||||
{ "rule": "*-spaces", "severity": "off" },
|
||||
{ "rule": "*-order", "severity": "off" },
|
||||
{ "rule": "*-dangle", "severity": "off" },
|
||||
{ "rule": "*-newline", "severity": "off" },
|
||||
{ "rule": "*quotes", "severity": "off" },
|
||||
{ "rule": "*semi", "severity": "off" }
|
||||
],
|
||||
|
||||
// Enable eslint for all supported languages
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"vue",
|
||||
"html",
|
||||
"markdown",
|
||||
"json",
|
||||
"jsonc",
|
||||
"yaml",
|
||||
"toml"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
```bash
|
||||
@ -143,44 +222,52 @@ pnpm build
|
||||
|
||||
### 提交校验
|
||||
|
||||
关于前端工程化 **配置构建代码检查工作流** 不了解的可以看下面这两篇文章了解下
|
||||
> [!TIP]
|
||||
> 关于前端工程化 **配置构建代码检查工作流** 不了解的可以看下面这两篇文章了解下
|
||||
>
|
||||
> [前端工程化配置(上) 构建代码检查工作流](https://xiangshu233.cn/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96%E9%85%8D%E7%BD%AE%EF%BC%88%E4%B8%8A%EF%BC%89%20%E6%9E%84%E5%BB%BA%E4%BB%A3%E7%A0%81%E6%A3%80%E6%9F%A5%E5%B7%A5%E4%BD%9C%E6%B5%81/)
|
||||
>
|
||||
> [前端工程化配置(下) 规范仓库提交记录 commitlint + commitizen + cz-git + 配置](https://xiangshu233.cn/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96%E9%85%8D%E7%BD%AE%EF%BC%88%E4%B8%8B%EF%BC%89%20%E8%A7%84%E8%8C%83%E4%BB%93%E5%BA%93%E6%8F%90%E4%BA%A4%E8%AE%B0%E5%BD%95/)
|
||||
|
||||
[前端工程化配置(上) 构建代码检查工作流](https://xiangshu233.cn/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96%E9%85%8D%E7%BD%AE%EF%BC%88%E4%B8%8A%EF%BC%89%20%E6%9E%84%E5%BB%BA%E4%BB%A3%E7%A0%81%E6%A3%80%E6%9F%A5%E5%B7%A5%E4%BD%9C%E6%B5%81/)
|
||||
|
||||
[前端工程化配置(下) 规范仓库提交记录 commitlint + commitizen + cz-git + 配置](https://xiangshu233.cn/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96%E9%85%8D%E7%BD%AE%EF%BC%88%E4%B8%8B%EF%BC%89%20%E8%A7%84%E8%8C%83%E4%BB%93%E5%BA%93%E6%8F%90%E4%BA%A4%E8%AE%B0%E5%BD%95/)
|
||||
|
||||
代码首次拉下来 `pnpm install` 后 需要执行以下命令来更新 `git hooks`
|
||||
|
||||
```shell
|
||||
# Update ./git/hooks
|
||||
npx simple-git-hooks
|
||||
```
|
||||
> [!IMPORTANT]
|
||||
> 首次 clone 代码 `pnpm install` 后 需要执行以下命令来更新`git hooks`
|
||||
>
|
||||
> ```shell
|
||||
> # Update ./git/hooks
|
||||
> npx simple-git-hooks
|
||||
> ```
|
||||
|
||||
本项目提交规范校验使用 [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) 作为 git hooks,使用 [cz-git](https://github.com/Zhengqbbb/cz-git) 作为 commitlint commitizen。
|
||||
|
||||
代码要想使用 commitlint 规范提交需要在更改的文件 `git add` 后,控制台执行 `cz` 命令开启 cz-git CLI
|
||||
|
||||
若想直接执行 `git commit` 需要满足上面提交规范才能通过校验,否则无法提交
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> ```shell
|
||||
> # Global install commitizen CLI
|
||||
> npm install -g commitizen
|
||||
> ```
|
||||
>
|
||||
> 先全局安装 `commitizen` ,之后更改的代码若想要使用 Commitlint 规范提交需要将文件(放入暂存区) `git add` 后,控制台执行 `cz` 命令开启 cz-git CLI
|
||||
> 。若想直接执行 `git commit` 需要满足上面提交规范才能通过校验,否则将会被 Git Hook 打断提交
|
||||
|
||||
simple-git-hooks 和 husky 都是用于管理 Git 钩子(Git hooks)的工具,但它们有一些区别:
|
||||
|
||||
1. simple-git-hooks:
|
||||
|
||||
- 简介: simple-git-hooks 是一个轻量级的工具,用于管理和运行Git钩子。
|
||||
- 特点:
|
||||
- 提供了简单的配置方式来定义和运行 Gi 钩子。
|
||||
- 适合于小型项目或对 Git 钩子需求不复杂的项目。
|
||||
- 相对较少的功能和配置选项。
|
||||
- 使用场景: 适用于简单的项目或对 Git 钩子管理需求不高的情况。
|
||||
|
||||
2. husky:
|
||||
|
||||
- 简介: husky 是一个功能强大的工具,用于管理 Git 钩子,并且在项目中被广泛使用。
|
||||
- 特点:
|
||||
- 提供了丰富的配置选项和灵活性,可以精细地控制 Git 钩子的行为。
|
||||
- 支持在不同的 Git 钩子事件上运行自定义脚本。
|
||||
- 可以与其他工具(如linters、测试框架等)集成,实现更复杂的工作流。
|
||||
- 使用场景: 适用于需要灵活配置和管理 Git 钩子的项目,尤其是大型或复杂的项目。
|
||||
> simple-git-hooks:
|
||||
>
|
||||
> - 简介: simple-git-hooks 是一个轻量级的工具,用于管理和运行Git钩子。
|
||||
> - 特点:
|
||||
> - 提供了简单的配置方式来定义和运行 Gi 钩子。
|
||||
> - 适合于小型项目或对 Git 钩子需求不复杂的项目。
|
||||
> - 相对较少的功能和配置选项。
|
||||
> - 使用场景: 适用于简单的项目或对 Git 钩子管理需求不高的情况。
|
||||
>
|
||||
> husky:
|
||||
>
|
||||
> - 简介: husky 是一个功能强大的工具,用于管理 Git 钩子,并且在项目中被广泛使用。
|
||||
> - 特点:
|
||||
> - 提供了丰富的配置选项和灵活性,可以精细地控制 Git 钩子的行为。
|
||||
> - 支持在不同的 Git 钩子事件上运行自定义脚本。
|
||||
> - 可以与其他工具(如linters、测试框架等)集成,实现更复杂的工作流。
|
||||
> - 使用场景: 适用于需要灵活配置和管理 Git 钩子的项目,尤其是大型或复杂的项目。
|
||||
|
||||
```json
|
||||
// package.json
|
||||
|
@ -3,7 +3,7 @@ import Components from 'unplugin-vue-components/vite'
|
||||
import { VantResolver } from 'unplugin-vue-components/resolvers'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import UnoCSS from 'unocss/vite'
|
||||
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import { configHtmlPlugin } from './html'
|
||||
import { configMockPlugin } from './mock'
|
||||
import { configCompressPlugin } from './compress'
|
||||
@ -33,10 +33,26 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, prodMock:
|
||||
resolvers: [VantResolver()],
|
||||
types: [],
|
||||
}),
|
||||
]
|
||||
// UnoCSS
|
||||
UnoCSS(),
|
||||
|
||||
// UnoCSS
|
||||
vitePlugins.push(UnoCSS())
|
||||
AutoImport({
|
||||
// targets to transform
|
||||
include: [
|
||||
/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
|
||||
/\.vue$/,
|
||||
/\.vue\?vue/, // .vue
|
||||
],
|
||||
imports: [
|
||||
// presets
|
||||
'vue',
|
||||
'vue-router',
|
||||
'pinia',
|
||||
'@vueuse/core',
|
||||
],
|
||||
dts: 'types/auto-imports.d.ts',
|
||||
}),
|
||||
]
|
||||
|
||||
// 加载 html 插件 vite-plugin-html
|
||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild))
|
||||
|
25
index.html
25
index.html
@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-cmn-Hans" id="htmlRoot" class>
|
||||
<html lang="zh-cmn-Hans" id="htmlRoot">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||
@ -10,23 +10,26 @@
|
||||
<div id="app">
|
||||
<script>
|
||||
;(() => {
|
||||
const { darkMode = 'dark', appTheme = '#5d9dfe' } =
|
||||
JSON.parse(window.localStorage.getItem('DESIGN-SETTING')) || {}
|
||||
|
||||
let htmlRoot = document.getElementById('htmlRoot')
|
||||
const appDesignSetting = window.localStorage.getItem('DESIGN-SETTING')
|
||||
let darkMode =
|
||||
appDesignSetting && JSON.parse(appDesignSetting).darkMode
|
||||
if (htmlRoot && darkMode) {
|
||||
htmlRoot.setAttribute('data-theme', darkMode)
|
||||
darkMode = htmlRoot = null
|
||||
} else {
|
||||
htmlRoot.setAttribute('data-theme', 'light')
|
||||
if (htmlRoot) {
|
||||
htmlRoot.classList.add(darkMode)
|
||||
}
|
||||
|
||||
// 设置主题色变量
|
||||
document.documentElement.style.setProperty(
|
||||
'--app-theme-color',
|
||||
appTheme,
|
||||
)
|
||||
})()
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
html[data-theme='dark'] .first-loading-wrap {
|
||||
html.dark .first-loading-wrap {
|
||||
background-color: #101014;
|
||||
}
|
||||
.first-loading-wrap {
|
||||
@ -61,7 +64,7 @@
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
background-color: #1890ff;
|
||||
background: var(--app-theme-color);
|
||||
border-radius: 100%;
|
||||
transform: scale(0.75);
|
||||
transform-origin: 50% 50%;
|
||||
|
41
package.json
41
package.json
@ -1,24 +1,33 @@
|
||||
{
|
||||
"name": "vue3-vant4-mobile",
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.6.10",
|
||||
"packageManager": "pnpm@9.8.0",
|
||||
"author": {
|
||||
"name": "xiangshu233",
|
||||
"email": "xiangshu233@outlook.com",
|
||||
"url": "https://github.com/xiangshu233"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/xiangshu233/vue3-vant4-mobile.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/xiangshu233/vue3-vant4-mobile/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0",
|
||||
"pnpm": ">=8.6.10"
|
||||
"node": "^20.9.0 || >=21.7.1",
|
||||
"pnpm": ">=8.15.4"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"bootstrap": "pnpm install",
|
||||
"serve": "npm run dev",
|
||||
"dev": "vite",
|
||||
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
|
||||
"dev": "cross-env VITE_CJS_IGNORE_WARNING=true vite dev",
|
||||
"dev:debugcjs": "cross-env VITE_CJS_TRACE=true vite dev",
|
||||
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
|
||||
"build:no-cache": "pnpm clean:cache && npm run build",
|
||||
"report": "cross-env REPORT=true npm run build",
|
||||
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
||||
@ -32,15 +41,13 @@
|
||||
"dependencies": {
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@unocss/reset": "^0.58.5",
|
||||
"@vicons/antd": "^0.12.0",
|
||||
"@vicons/ionicons5": "^0.12.0",
|
||||
"@vicons/utils": "^0.1.4",
|
||||
"@vueuse/core": "^10.7.0",
|
||||
"axios": "^1.4.0",
|
||||
"date-fns": "^3.0.6",
|
||||
"echarts": "^5.4.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persist": "^1.0.0",
|
||||
"qs": "^6.11.2",
|
||||
@ -52,11 +59,14 @@
|
||||
"@antfu/eslint-config": "^2.6.3",
|
||||
"@commitlint/cli": "^18.4.3",
|
||||
"@commitlint/config-conventional": "^18.4.3",
|
||||
"@iconify/json": "^2.2.188",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/mockjs": "^1.0.10",
|
||||
"@types/node": "^20.10.5",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/qs": "^6.9.11",
|
||||
"@unocss/eslint-plugin": "^0.58.4",
|
||||
"@unocss/preset-icons": "^0.58.5",
|
||||
"@unocss/preset-rem-to-px": "^0.58.5",
|
||||
"@unocss/transformer-directives": "^0.58.4",
|
||||
"@unocss/transformer-variant-group": "^0.58.4",
|
||||
@ -74,27 +84,18 @@
|
||||
"only-allow": "^1.2.1",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-html": "^1.5.0",
|
||||
"postcss-less": "^6.0.0",
|
||||
"postcss-mobile-forever": "^4.0.0",
|
||||
"prettier": "^3.2.4",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^4.9.1",
|
||||
"rollup-plugin-visualizer": "^5.11.0",
|
||||
"simple-git-hooks": "^2.9.0",
|
||||
"stylelint": "^16.2.0",
|
||||
"stylelint-config-recommended": "^14.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.5.0",
|
||||
"stylelint-config-standard": "^36.0.0",
|
||||
"stylelint-config-standard-less": "^3.0.1",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"stylelint-prettier": "^5.0.0",
|
||||
"typescript": "^5.3.3",
|
||||
"unocss": "^0.58.5",
|
||||
"unplugin-auto-import": "^0.17.5",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-mock": "^2.9.8",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-tsc": "^1.8.27"
|
||||
|
741
pnpm-lock.yaml
generated
741
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
1
public/_redirects
Normal file
1
public/_redirects
Normal file
@ -0,0 +1 @@
|
||||
/* /index.html 200
|
@ -13,8 +13,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, unref } from 'vue'
|
||||
import { darken, lighten } from '@/utils/index'
|
||||
import { darken, lighten } from '@/utils'
|
||||
import { useRouteStore } from '@/store/modules/route'
|
||||
import { useDesignSetting } from '@/hooks/setting/useDesignSetting'
|
||||
|
||||
|
51
src/components/Logo.vue
Normal file
51
src/components/Logo.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<SvgIcon v-if="designStore.getAppTheme === defaultAppTheme" class="!h-30 !w-30" name="logo" />
|
||||
<svg v-else xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 87 100">
|
||||
<defs>
|
||||
<linearGradient id="gradient23" x1="0" y1="0" x2="0" y2="1" gradientTransform="rotate(-90 .5 .5)">
|
||||
<stop offset="0" :stop-color="hexToRgba(designStore.getAppTheme, 0.3)" stop-opacity="1" />
|
||||
<stop offset="1" :stop-color="hexToRgba(designStore.getAppTheme, 0.8)" stop-opacity="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#gradient23)" d="M 86.45 25.05Q 86.05 25.9 85.5 26.25L 44.9 49.7 44.9 51.75 41.9 51.75 41.9 49.7 1.25 26.25Q 0.9 26.05 0.65 25.55L 0.45 25.1 0.45 75.2 0.5 75.75Q 0.7 76.35 1.1 76.55L 41.75 100 41.85 59.85 44.95 59.85 45.05 100 85.65 76.55Q 86.15 76.2 86.35 75.7L 86.45 75.2 86.45 25.05 Z" />
|
||||
<defs>
|
||||
<linearGradient id="gradient24" x1="0" y1="0" x2="0" y2="1" gradientTransform="rotate(-90 .5 .5)">
|
||||
<stop offset="0" :stop-color="hexToRgba(designStore.getAppTheme, 0.8)" stop-opacity="1" />
|
||||
<stop offset="1" :stop-color="hexToRgba(designStore.getAppTheme, 0.2)" stop-opacity="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#gradient24)" d="M 86.6 25.1Q 86.6 24.4 85.8 23.95L 45.15 0.5Q 44.35 0 43.15 0 42 0 41.2 0.5L 0.85 23.95Q 0 24.4 0 25.1 0 25.75 0.85 26.25L 41.45 49.7Q 42.3 50.15 43.45 50.15 44.65 50.15 45.45 49.7L 85.8 26.25Q 86.6 25.75 86.6 25.1 Z" />
|
||||
<defs>
|
||||
<linearGradient id="gradient25" x1="0" y1="0" x2="0" y2="1" gradientTransform="rotate(-90 .5 .5)">
|
||||
<stop offset="0" :stop-color="hexToRgba(designStore.getAppTheme, 0.4)" stop-opacity="1" />
|
||||
<stop offset="1" :stop-color="hexToRgba(designStore.getAppTheme, 0.9)" stop-opacity="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#gradient25)" d="M 67.9 35.85Q 67.8 36.35 67.5 36.55L 43.25 50.2 43.25 79.3 67.6 65.3Q 67.95 65.1 67.9 64.5L 67.9 35.85 Z" />
|
||||
<defs>
|
||||
<linearGradient id="gradient26" x1="0" y1="0" x2="0" y2="1" gradientTransform="rotate(-90 .5 .5)">
|
||||
<stop offset="0" :stop-color="hexToRgba(designStore.getAppTheme, 0.8)" stop-opacity="1" />
|
||||
<stop offset="1" :stop-color="hexToRgba(designStore.getAppTheme, 0.4)" stop-opacity="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#gradient26)" d="M 19.2 36.55Q 19 36.4 18.9 36.1L 18.8 35.85 18.85 64.85Q 18.9 65.15 19.15 65.3L 43.45 79.3 43.45 50.2 19.2 36.55 Z" />
|
||||
<defs>
|
||||
<linearGradient id="gradient27" x1="0" y1="0" x2="0" y2="1" gradientTransform="rotate(-90 .5 .5)">
|
||||
<stop offset="0" :stop-color="hexToRgba(designStore.getAppTheme, 0.9)" stop-opacity="1" />
|
||||
<stop offset="1" :stop-color="hexToRgba(designStore.getAppTheme, 0.3)" stop-opacity="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#gradient27)" d="M 67.6 35.2L 44.4 21.8Q 43.9 21.55 43.25 21.55 42.55 21.55 42.1 21.8L 19.05 35.2Q 18.6 35.5 18.6 35.9 18.6 36.25 19.05 36.55L 42.25 49.95Q 42.7 50.2 43.4 50.2 44.1 50.2 44.55 49.95L 67.6 36.55Q 68.1 36.25 68.05 35.9 68.05 35.5 67.6 35.2 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||
import { hexToRgba } from '@/utils'
|
||||
import { appThemeList } from '@/settings/designSetting'
|
||||
|
||||
const defaultAppTheme = appThemeList[0]
|
||||
const designStore = useDesignSettingStore()
|
||||
</script>
|
@ -6,7 +6,6 @@
|
||||
|
||||
<script lang="ts">
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SvgIcon',
|
||||
|
@ -17,14 +17,16 @@
|
||||
<component :is="Component" v-else :key="route.fullPath" />
|
||||
</template>
|
||||
</routerView>
|
||||
<van-tabbar placeholder route fixed>
|
||||
<van-tabbar route class="tabbar">
|
||||
<van-tabbar-item
|
||||
v-for="menu in getMenus"
|
||||
:key="menu.name"
|
||||
replace
|
||||
:to="menu.path"
|
||||
:icon="(menu.meta?.icon as string)"
|
||||
>
|
||||
<template #icon>
|
||||
<i :class="menu.meta?.icon" />
|
||||
</template>
|
||||
{{ menu.meta?.title }}
|
||||
</van-tabbar-item>
|
||||
</van-tabbar>
|
||||
@ -55,4 +57,10 @@ const getMenus: ComputedRef<RouteRecordRaw[]> = computed(() =>
|
||||
const getShowHeader = computed(() => !currentRoute.meta.hiddenHeader)
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
<style scoped lang="less">
|
||||
.tabbar {
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'virtual:uno.css'
|
||||
import 'vant/es/toast/style'
|
||||
import 'vant/es/dialog/style'
|
||||
import 'vant/es/notify/style'
|
||||
import 'vant/es/image-preview/style'
|
||||
|
||||
// https://unocss.dev/guide/style-reset#tailwind-compat
|
||||
// 此重置基于 Tailwind 重置,减去按钮的背景颜色覆盖,以避免与 UI 框架发生冲突。请参阅链接的问题。
|
||||
@ -11,7 +13,6 @@ import 'virtual:svg-icons-register'
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router, { setupRouter } from './router'
|
||||
import { updateDarkSign } from './theme'
|
||||
import { setupStore } from '@/store'
|
||||
|
||||
async function bootstrap() {
|
||||
@ -23,11 +24,6 @@ async function bootstrap() {
|
||||
await router.isReady()
|
||||
// 路由准备就绪后挂载APP实例
|
||||
app.mount('#app', true)
|
||||
|
||||
// 根节点挂载 dark 标识
|
||||
const appDesignSetting = window.localStorage.getItem('DESIGN-SETTING')
|
||||
const darkMode = appDesignSetting && JSON.parse(appDesignSetting).darkMode
|
||||
updateDarkSign(darkMode)
|
||||
}
|
||||
|
||||
void bootstrap()
|
||||
|
@ -10,7 +10,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '主控台',
|
||||
icon: 'wap-home',
|
||||
icon: 'i-simple-icons:atlassian',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@ -29,8 +29,8 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
||||
redirect: '/message/index',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '消息',
|
||||
icon: 'chat',
|
||||
title: '图表',
|
||||
icon: 'i-simple-icons:soundcharts',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@ -43,6 +43,26 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/example',
|
||||
name: 'Example',
|
||||
redirect: '/example/index',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '示例',
|
||||
icon: 'i-material-symbols:award-star',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: 'ExamplePage',
|
||||
meta: {
|
||||
keepAlive: false,
|
||||
},
|
||||
component: () => import('@/views/example/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/my',
|
||||
name: 'My',
|
||||
@ -50,7 +70,7 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: '我的',
|
||||
icon: 'manager',
|
||||
icon: 'i-simple-icons:docsify',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@ -79,9 +99,9 @@ const routeModuleList: Array<RouteRecordRaw> = [
|
||||
path: '/editNickname',
|
||||
name: 'EditNickname',
|
||||
meta: {
|
||||
title: '修改昵称',
|
||||
title: '修改昵称(该页面已缓存)',
|
||||
innerPage: true,
|
||||
keepAlive: false,
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('@/views/my/EditNickname.vue'),
|
||||
},
|
||||
|
@ -1,10 +1,14 @@
|
||||
import type { Router } from 'vue-router'
|
||||
import { isNavigationFailure } from 'vue-router'
|
||||
import NProgress from 'nprogress'
|
||||
import { useRouteStoreWidthOut } from '@/store/modules/route'
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user'
|
||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||
import { storage } from '@/utils/Storage'
|
||||
import { PageEnum } from '@/enums/pageEnum'
|
||||
import 'nprogress/nprogress.css'
|
||||
|
||||
NProgress.configure({ parent: '#app' })
|
||||
|
||||
const LOGIN_PATH = PageEnum.BASE_LOGIN
|
||||
|
||||
@ -14,7 +18,7 @@ export function createRouterGuards(router: Router) {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
// to: 即将要进入的目标
|
||||
// from: 当前导航正要离开的路由
|
||||
|
||||
NProgress.start()
|
||||
const userStore = useUserStoreWidthOut()
|
||||
|
||||
if (from.path === LOGIN_PATH && to.name === PageEnum.ERROR_PAGE_NAME) {
|
||||
@ -83,6 +87,7 @@ export function createRouterGuards(router: Router) {
|
||||
}
|
||||
}
|
||||
routeStore.setKeepAliveComponents(keepAliveComponents)
|
||||
NProgress.done()
|
||||
})
|
||||
|
||||
router.onError((error) => {
|
||||
|
@ -37,7 +37,7 @@ export const appThemeList: string[] = [
|
||||
|
||||
const setting: DesignSettingState = {
|
||||
// 深色主题
|
||||
darkMode: 'light',
|
||||
darkMode: 'dark',
|
||||
// 系统主题色
|
||||
appTheme: '#5d9dfe',
|
||||
// 系统内置主题色列表
|
||||
|
@ -1,4 +1,3 @@
|
||||
export const FIRST_VISIT = 'FIRST-VISIT' // 是否首次访问
|
||||
export const ACCESS_TOKEN = 'ACCESS-TOKEN' // 用户token
|
||||
export const CURRENT_USER = 'CURRENT-USER' // 当前用户信息
|
||||
export const DESIGN_SETTING = 'DESIGN-SETTING' // 当前用户主题信息
|
||||
|
@ -10,7 +10,7 @@ html {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
html.dark {
|
||||
&,
|
||||
* {
|
||||
color-scheme: dark !important;
|
||||
@ -22,7 +22,7 @@ html {
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='light'] {
|
||||
html.light {
|
||||
&,
|
||||
* {
|
||||
color-scheme: light !important;
|
||||
@ -69,7 +69,6 @@ a:active {
|
||||
color: rgb(#0000, 0.7);
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-duplicate-selectors */
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
@ -93,24 +92,16 @@ a:hover {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
.xicon {
|
||||
font-size: 18px;
|
||||
|
||||
svg {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
html.light {
|
||||
.my-card {
|
||||
backdrop-filter: blur(10px);
|
||||
background: rgba(255, 255, 255, 70%);
|
||||
}
|
||||
}
|
||||
|
||||
.my-card {
|
||||
backdrop-filter: blur(10px);
|
||||
/* stylelint-disable-next-line color-function-notation */
|
||||
background: rgba(255, 255, 255, 70%);
|
||||
}
|
||||
|
||||
html[data-theme='dark'] {
|
||||
html.dark {
|
||||
.my-card {
|
||||
/* stylelint-disable-next-line color-function-notation */
|
||||
backdrop-filter: blur(10px);
|
||||
background: rgba(30, 30, 30, 70%);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { addClass, hasClass, removeClass } from '@/utils/domUtils'
|
||||
|
||||
/**
|
||||
* html 根标签上挂载 暗/亮 属性标识
|
||||
*/
|
||||
export function updateDarkSign(mode: 'light' | 'dark') {
|
||||
const htmlRoot = document.getElementById('htmlRoot')
|
||||
if (!htmlRoot) {
|
||||
return
|
||||
}
|
||||
const hasDarkClass = hasClass(htmlRoot, 'dark')
|
||||
|
||||
if (mode === 'dark') {
|
||||
htmlRoot.setAttribute('data-theme', 'dark')
|
||||
if (!hasDarkClass) {
|
||||
addClass(htmlRoot, 'dark')
|
||||
}
|
||||
}
|
||||
else {
|
||||
htmlRoot.setAttribute('data-theme', 'light')
|
||||
if (hasDarkClass) {
|
||||
removeClass(htmlRoot, 'dark')
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import axios from 'axios'
|
||||
|
||||
import qs from 'qs'
|
||||
|
||||
import { isFunction } from '@/utils/is/index'
|
||||
import { isFunction } from '@/utils/is'
|
||||
|
||||
// 声明一个 Map 用于存储每个请求的标识 和 取消函数
|
||||
let pendingMap = new Map<string, Canceler>()
|
||||
|
@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="h-screen flex flex-col items-center justify-center p-60px">
|
||||
<div class="wel-box w-full flex flex-col items-center justify-between">
|
||||
<SvgIcon class="logo" :size="130" name="logo" />
|
||||
<Logo class="!h-30 !w-30" />
|
||||
<div class="text-darkBlue dark:text-garyWhite mb-4 mt-12 text-center text-2xl font-black">
|
||||
{{ title }}
|
||||
</div>
|
||||
|
||||
<div class="mb-6 mt-4 w-full">
|
||||
<van-swipe class="h-30" :autoplay="3000" :indicator-color="designStore.appTheme">
|
||||
<van-swipe-item
|
||||
@ -27,10 +26,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||
import SvgIcon from '@/components/SvgIcon.vue'
|
||||
import { useGlobSetting } from '@/hooks/setting'
|
||||
import Logo from '@/components/Logo.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'DashboardPage',
|
||||
@ -47,6 +45,14 @@ const getSwipeText = computed(() => {
|
||||
title: '💡 最新技术栈',
|
||||
details: '基于Vue3、Vant4、Vite、TypeScript、UnoCSS等最新技术栈开发',
|
||||
},
|
||||
{
|
||||
title: '✨ 零配置 ESlint',
|
||||
details: '使用 Git Hook 进行 Lint Commit,规范化提交',
|
||||
},
|
||||
{
|
||||
title: '🌠 使用最新的 <script setup> 语法',
|
||||
details: 'Vue 3.4+ 最新语法',
|
||||
},
|
||||
{
|
||||
title: '⚡️ 轻量快速的热重载',
|
||||
details: '无论应用程序大小如何,都始终极快的模块热重载(HMR)',
|
||||
@ -61,11 +67,11 @@ const getSwipeText = computed(() => {
|
||||
},
|
||||
{
|
||||
title: '📊 内置 useEcharts hooks',
|
||||
details: '满足大部分图表展示,只需要写你的 options',
|
||||
details: '满足大部分图表展示,只需要写你的 Options',
|
||||
},
|
||||
{
|
||||
title: '🥳 完善的登录系统、路由、Axios配置',
|
||||
details: '所有架构已搭建完毕,你可以直接开发你的业务需求',
|
||||
details: '所有基础设施已搭建完毕,你可以直接开发你的业务需求',
|
||||
},
|
||||
]
|
||||
})
|
||||
|
47
src/views/example/index.vue
Normal file
47
src/views/example/index.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div class="my-4">
|
||||
<van-cell-group inset>
|
||||
<van-cell center title="🌓 暗黑模式">
|
||||
<template #right-icon>
|
||||
<i inline-block align-middle i="dark:carbon-moon carbon-sun" />
|
||||
<span class="ml-2">{{ isDark ? 'Dark' : 'Light' }}</span>
|
||||
<span class="mx-2">{{ isDark }}</span>
|
||||
<van-switch v-model="checked" size="22" @click="toggle()" />
|
||||
</template>
|
||||
</van-cell>
|
||||
<template v-for="item in menuItems" :key="item.route">
|
||||
<van-cell :title="item.title" :to="item.route" is-link />
|
||||
</template>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||
|
||||
const designStore = useDesignSettingStore()
|
||||
|
||||
const isDark = useDark({
|
||||
valueDark: 'dark',
|
||||
valueLight: 'light',
|
||||
})
|
||||
|
||||
const checked = ref(isDark.value)
|
||||
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
function toggle() {
|
||||
toggleDark()
|
||||
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
|
||||
}
|
||||
|
||||
const menuItems = [
|
||||
{ title: '🐗 keep-alive', route: '/editNickname' },
|
||||
{ title: '🦘 404 页演示', route: '/404' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div class="page-container flex flex-col justify-center">
|
||||
<div class="text-center">
|
||||
<img src="~@/assets/icons/exception/403.svg" alt="">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<h1 class="text-base text-gray-500">
|
||||
抱歉,你无权访问该页面
|
||||
</h1>
|
||||
<n-button type="info" @click="goHome">
|
||||
回到首页
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
function goHome() {
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.page-container {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
padding: 50px 0;
|
||||
height: 100vh;
|
||||
|
||||
.text-center {
|
||||
h1 {
|
||||
color: #666;
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 350px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -4,9 +4,9 @@
|
||||
<img src="~@/assets/icons/exception/404.svg" alt="">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<h1 class="text-base text-gray-500">
|
||||
<p class="m-4 text-base">
|
||||
抱歉,你访问的页面不存在
|
||||
</h1>
|
||||
</p>
|
||||
<van-button type="primary" @click="goHome">
|
||||
回到首页
|
||||
</van-button>
|
||||
@ -15,8 +15,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
function goHome() {
|
||||
router.push('/')
|
||||
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div class="page-container flex flex-col justify-center">
|
||||
<div class="text-center">
|
||||
<img src="~@/assets/icons/exception/500.svg" alt="">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<h1 class="text-base text-gray-500">
|
||||
抱歉,服务器出错了
|
||||
</h1>
|
||||
<n-button type="info" @click="goHome">
|
||||
回到首页
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
function goHome() {
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.page-container {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
padding: 50px 0;
|
||||
height: 100vh;
|
||||
|
||||
.text-center {
|
||||
h1 {
|
||||
color: #666;
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 350px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -8,9 +8,7 @@
|
||||
:rules="getFormRules.username"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<UserOutlined />
|
||||
</Icon>
|
||||
<i class="i-ph:user-bold mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
@ -22,9 +20,7 @@
|
||||
:rules="getFormRules.mobile"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<MobileOutlined />
|
||||
</Icon>
|
||||
<i class="i-ic:twotone-smartphone mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
@ -37,9 +33,7 @@
|
||||
:rules="getFormRules.sms"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<EditOutlined />
|
||||
</Icon>
|
||||
<i class="i-material-symbols:edit-square-outline-rounded mr-2 text-lg" />
|
||||
</template>
|
||||
<template #button>
|
||||
<van-button size="small" type="primary">
|
||||
@ -70,10 +64,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, unref } from 'vue'
|
||||
import type { FormInstance } from 'vant'
|
||||
import { Icon } from '@vicons/utils'
|
||||
import { EditOutlined, MobileOutlined, UserOutlined } from '@vicons/antd'
|
||||
import { LoginStateEnum, useFormRules, useLoginState } from './useLogin'
|
||||
|
||||
const { handleBackLogin, getLoginState } = useLoginState()
|
||||
|
@ -8,9 +8,7 @@
|
||||
:rules="getFormRules.username"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<UserOutlined />
|
||||
</Icon>
|
||||
<i class="i-ph:user-bold mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field
|
||||
@ -23,17 +21,11 @@
|
||||
@click-right-icon="switchPassType = !switchPassType"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<LockOutlined />
|
||||
</Icon>
|
||||
<i class="i-iconamoon:lock-bold mr-2 text-lg" />
|
||||
</template>
|
||||
<template #right-icon>
|
||||
<Icon v-if="switchPassType">
|
||||
<EyeInvisibleOutlined />
|
||||
</Icon>
|
||||
<Icon v-else>
|
||||
<EyeOutlined />
|
||||
</Icon>
|
||||
<i v-if="switchPassType" class="i-mdi:eye-outline mr-2 text-lg" />
|
||||
<i v-else class="i-mdi:eye-off mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
@ -67,12 +59,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, unref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { showFailToast, showLoadingToast, showSuccessToast } from 'vant'
|
||||
import type { FormInstance } from 'vant'
|
||||
import { Icon } from '@vicons/utils'
|
||||
import { EyeInvisibleOutlined, EyeOutlined, LockOutlined, UserOutlined } from '@vicons/antd'
|
||||
import { LoginStateEnum, useFormRules, useLoginState } from './useLogin'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { ResultEnum } from '@/enums/httpEnum'
|
||||
|
@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<div class="logo enter-y mb-2 mt-8">
|
||||
<SvgIcon class="!h-30 !w-30" name="logo" />
|
||||
<div class="logo enter-y mb-8 mt-8">
|
||||
<Logo class="!h-30 !w-30" name="logo" />
|
||||
</div>
|
||||
<div class="text-darkBlue dark:text-garyWhite enter-y mb-8 text-2xl font-black">
|
||||
<div class="text-darkBlue dark:text-garyWhite enter-y mb-12 text-2xl font-black">
|
||||
{{ title }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Logo from '@/components/Logo.vue'
|
||||
import { useGlobSetting } from '@/hooks/setting'
|
||||
|
||||
const globSetting = useGlobSetting()
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||
import { hexToRgba } from '@/utils/index'
|
||||
import { hexToRgba } from '@/utils'
|
||||
|
||||
const designStore = useDesignSettingStore()
|
||||
</script>
|
||||
|
@ -9,9 +9,7 @@
|
||||
:rules="getFormRules.username"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<UserOutlined />
|
||||
</Icon>
|
||||
<i class="i-ph:user-bold mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
@ -23,9 +21,7 @@
|
||||
:rules="getFormRules.mobile"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<MobileOutlined />
|
||||
</Icon>
|
||||
<i class="i-ic:twotone-smartphone mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
@ -38,9 +34,7 @@
|
||||
:rules="getFormRules.sms"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<EditOutlined />
|
||||
</Icon>
|
||||
<i class="i-material-symbols:edit-square-outline-rounded mr-2 text-lg" />
|
||||
</template>
|
||||
<template #button>
|
||||
<van-button size="small" type="primary">
|
||||
@ -59,17 +53,11 @@
|
||||
@click-right-icon="switchPassType = !switchPassType"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<LockOutlined />
|
||||
</Icon>
|
||||
<i class="i-iconamoon:lock-bold mr-2 text-lg" />
|
||||
</template>
|
||||
<template #right-icon>
|
||||
<Icon v-if="switchPassType">
|
||||
<EyeInvisibleOutlined />
|
||||
</Icon>
|
||||
<Icon v-else>
|
||||
<EyeOutlined />
|
||||
</Icon>
|
||||
<i v-if="switchPassType" class="i-mdi:eye-outline mr-2 text-lg" />
|
||||
<i v-else class="i-mdi:eye-off mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
@ -83,23 +71,17 @@
|
||||
@click-right-icon="switchConfirmPassType = !switchConfirmPassType"
|
||||
>
|
||||
<template #left-icon>
|
||||
<Icon>
|
||||
<LockOutlined />
|
||||
</Icon>
|
||||
<i class="i-iconamoon:lock-bold mr-2 text-lg" />
|
||||
</template>
|
||||
<template #right-icon>
|
||||
<Icon v-if="switchConfirmPassType">
|
||||
<EyeInvisibleOutlined />
|
||||
</Icon>
|
||||
<Icon v-else>
|
||||
<EyeOutlined />
|
||||
</Icon>
|
||||
<i v-if="switchConfirmPassType" class="i-mdi:eye-outline mr-2 text-lg" />
|
||||
<i v-else class="i-mdi:eye-off mr-2 text-lg" />
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field
|
||||
name="policy"
|
||||
class="enter-y items-center px-1 !rounded-md"
|
||||
class="enter-y items-center !rounded-md"
|
||||
:rules="getFormRules.policy"
|
||||
>
|
||||
<template #input>
|
||||
@ -133,17 +115,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, unref } from 'vue'
|
||||
import type { FormInstance } from 'vant'
|
||||
import { Icon } from '@vicons/utils'
|
||||
import {
|
||||
EditOutlined,
|
||||
EyeInvisibleOutlined,
|
||||
EyeOutlined,
|
||||
LockOutlined,
|
||||
MobileOutlined,
|
||||
UserOutlined,
|
||||
} from '@vicons/antd'
|
||||
|
||||
import { LoginStateEnum, useFormRules, useLoginState } from './useLogin'
|
||||
|
||||
const { handleBackLogin, getLoginState } = useLoginState()
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { FieldRule } from 'vant'
|
||||
import { computed, ref, unref } from 'vue'
|
||||
|
||||
export enum LoginStateEnum {
|
||||
LOGIN,
|
||||
|
@ -5,8 +5,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import type { EChartsOption } from 'echarts'
|
||||
import { useECharts } from '@/hooks/web/useECharts'
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import type { EChartsOption } from 'echarts'
|
||||
import { useECharts } from '@/hooks/web/useECharts'
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import type { EChartsOption } from 'echarts'
|
||||
import { useECharts } from '@/hooks/web/useECharts'
|
||||
|
||||
|
@ -34,7 +34,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import NavBar from './components/NavBar.vue'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
|
@ -28,7 +28,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import type { FormInstance } from 'vant'
|
||||
import { showToast } from 'vant'
|
||||
import NavBar from './components/NavBar.vue'
|
||||
|
@ -24,7 +24,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import type { FormInstance } from 'vant'
|
||||
import { showToast } from 'vant'
|
||||
import NavBar from './components/NavBar.vue'
|
||||
|
@ -112,7 +112,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { showToast } from 'vant'
|
||||
import NavBar from './components/NavBar.vue'
|
||||
import UploaderImage from './components/UploaderImage.vue'
|
||||
|
@ -2,11 +2,13 @@
|
||||
<div>
|
||||
<NavBar />
|
||||
<van-divider>主题模式</van-divider>
|
||||
<van-cell center title="暗黑模式">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="getDarkMode" />
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell-group inset>
|
||||
<van-cell center title="暗黑模式">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="getDarkMode" size="22" />
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
|
||||
<van-divider>系统主题色</van-divider>
|
||||
<div flex="~" justify="center">
|
||||
@ -14,8 +16,8 @@
|
||||
<span
|
||||
v-for="(item, index) in designStore.appThemeList"
|
||||
:key="index"
|
||||
h="9"
|
||||
w="9"
|
||||
h="8"
|
||||
w="8"
|
||||
items-center
|
||||
border="2 rounded-md"
|
||||
flex="~"
|
||||
@ -23,32 +25,37 @@
|
||||
:style="{ 'background-color': item }"
|
||||
@click="togTheme(item)"
|
||||
>
|
||||
<Icon v-if="item === designStore.appTheme">
|
||||
<CheckOutlined text="white" />
|
||||
</Icon>
|
||||
<i
|
||||
v-show="item === designStore.appTheme"
|
||||
class="i-ic:sharp-check" text-2xl text-white
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-divider>页面切换动画</van-divider>
|
||||
<van-cell center title="开启动画">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="designStore.isPageAnimate" />
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell-group inset>
|
||||
<van-cell center title="开启动画">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="designStore.isPageAnimate" size="22" />
|
||||
</template>
|
||||
</van-cell>
|
||||
<van-cell center title="动画类型">
|
||||
<van-field
|
||||
v-model="animateState.text"
|
||||
readonly
|
||||
class="!p-0"
|
||||
:disabled="!designStore.isPageAnimate"
|
||||
is-link
|
||||
label-class="font-bold"
|
||||
input-align="right"
|
||||
:center="true"
|
||||
:border="false"
|
||||
@click="openAnimatePick"
|
||||
/>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
|
||||
<van-field
|
||||
v-model="animateState.text"
|
||||
label="动画类型"
|
||||
readonly
|
||||
:disabled="!designStore.isPageAnimate"
|
||||
is-link
|
||||
label-class="font-bold"
|
||||
input-align="right"
|
||||
:center="true"
|
||||
:border="false"
|
||||
@click="openAnimatePick"
|
||||
/>
|
||||
<van-popup v-model:show="animateState.showPicker" position="bottom" round>
|
||||
<van-picker
|
||||
v-model="animateState.value"
|
||||
@ -61,22 +68,25 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive } from 'vue'
|
||||
import { Icon } from '@vicons/utils'
|
||||
import { CheckOutlined } from '@vicons/antd'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import NavBar from './components/NavBar.vue'
|
||||
import { updateDarkSign } from '@/theme'
|
||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||
import { animates as animateOptions } from '@/settings/animateSetting'
|
||||
|
||||
const designStore = useDesignSettingStore()
|
||||
|
||||
const isDark = useDark({
|
||||
valueDark: 'dark',
|
||||
valueLight: 'light',
|
||||
})
|
||||
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
const getDarkMode = computed({
|
||||
get: () => designStore.getDarkMode === 'dark',
|
||||
set: (value) => {
|
||||
const darkMode = value ? 'dark' : 'light'
|
||||
updateDarkSign(darkMode)
|
||||
designStore.setDarkMode(darkMode)
|
||||
get: () => isDark.value,
|
||||
set: () => {
|
||||
toggleDark()
|
||||
designStore.setDarkMode(isDark.value ? 'dark' : 'light')
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -4,9 +4,7 @@
|
||||
{{ getTitle }}
|
||||
</template>
|
||||
<template #left>
|
||||
<Icon>
|
||||
<ChevronBack />
|
||||
</Icon>
|
||||
<i class="i-ic:sharp-arrow-back-ios" text-xl />
|
||||
</template>
|
||||
<template #right>
|
||||
<slot name="right" />
|
||||
@ -15,15 +13,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '@vicons/utils'
|
||||
import { ChevronBack } from '@vicons/ionicons5'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const router = useRouter()
|
||||
const currentRoute = useRoute()
|
||||
|
||||
const getTitle = computed(() => currentRoute.meta.title as string)
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
<style scoped lang="less">
|
||||
</style>
|
||||
|
@ -22,41 +22,31 @@
|
||||
|
||||
<van-cell :border="false" title="个人信息" is-link to="/editUserInfo">
|
||||
<template #icon>
|
||||
<Icon>
|
||||
<IdcardFilled />
|
||||
</Icon>
|
||||
<i class="i-mingcute:idcard-fill mr-2 text-xl" />
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<van-cell :border="false" title="账号与安全" is-link to="/accountSetting">
|
||||
<template #icon>
|
||||
<Icon>
|
||||
<Person />
|
||||
</Icon>
|
||||
<i class="i-material-symbols:account-box mr-2 text-xl" />
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<van-cell :border="false" title="主题设置" is-link to="/themeSetting">
|
||||
<template #icon>
|
||||
<Icon>
|
||||
<ColorPalette />
|
||||
</Icon>
|
||||
<i class="i-material-symbols:palette mr-2 text-xl" />
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<van-cell :border="false" title="隐私政策" is-link>
|
||||
<template #icon>
|
||||
<Icon>
|
||||
<DocumentText />
|
||||
</Icon>
|
||||
<i class="i-material-symbols:list-alt-rounded mr-2 text-xl" />
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
<van-cell :border="false" title="退出登录" is-link @click="showLogoutAction = true">
|
||||
<template #icon>
|
||||
<Icon>
|
||||
<LogOut />
|
||||
</Icon>
|
||||
<i class="i-solar:logout-3-bold mr-2 text-xl" />
|
||||
</template>
|
||||
</van-cell>
|
||||
|
||||
@ -73,10 +63,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { Icon } from '@vicons/utils'
|
||||
import { IdcardFilled } from '@vicons/antd'
|
||||
import { ColorPalette, DocumentText, LogOut, Person } from '@vicons/ionicons5'
|
||||
import { showToast } from 'vant'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
|
||||
@ -102,7 +88,7 @@ const getUserCoverBg = computed(() => {
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.my-bg {
|
||||
.my-bg {
|
||||
clip-path: inset(0 -55% 0 -55% round 0 0 100% 100%);
|
||||
background-size: cover;
|
||||
|
||||
@ -125,9 +111,5 @@ const getUserCoverBg = computed(() => {
|
||||
&:active {
|
||||
background-color: var(--van-cell-active-color);
|
||||
}
|
||||
|
||||
.xicon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,112 +0,0 @@
|
||||
<template>
|
||||
<div class="h-screen flex flex-col items-center justify-center p-8">
|
||||
<!-- <van-cell center title="🌗 暗黑模式">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="getDarkMode" size="18px" />
|
||||
</template>
|
||||
</van-cell> -->
|
||||
<div class="wel-box w-full flex flex-col justify-between">
|
||||
<div class="wel-top">
|
||||
<div class="logo enter-y">
|
||||
<SvgIcon :size="130" name="logo" />
|
||||
</div>
|
||||
<div
|
||||
class="enter-y text-darkBlue dark:text-garyWhite mb-4 mt-12 text-center text-2xl font-black"
|
||||
>
|
||||
欢迎来到 {{ title }}
|
||||
</div>
|
||||
<div class="enter-y mb-6 mt-4 w-full">
|
||||
<van-swipe class="h-30" :autoplay="3000" :indicator-color="designStore.appTheme">
|
||||
<van-swipe-item
|
||||
v-for="(text, index) in getSwipeText"
|
||||
:key="index"
|
||||
class="text-center text-gray-700 leading-relaxed dark:text-gray-400"
|
||||
>
|
||||
<p class="text-lg">
|
||||
{{ text.title }}
|
||||
</p>
|
||||
<p class="text-sm">
|
||||
{{ text.details }}
|
||||
</p>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wel-bottom">
|
||||
<van-button
|
||||
class="enter-y !rounded-md"
|
||||
type="primary"
|
||||
block
|
||||
@click="router.push({ name: 'Login' })"
|
||||
>
|
||||
Let's Get Started
|
||||
</van-button>
|
||||
<a class="enter-y mt-6 text-sm">创建账户?</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useDesignSettingStore } from '@/store/modules/designSetting'
|
||||
import SvgIcon from '@/components/SvgIcon.vue'
|
||||
import { useGlobSetting } from '@/hooks/setting'
|
||||
|
||||
// import { updateDarkSign } from '@/theme'
|
||||
|
||||
// const getDarkMode = computed({
|
||||
// get: () => designStore.getDarkMode === 'dark',
|
||||
// set: (value) => {
|
||||
// const darkMode = value ? 'dark' : 'light'
|
||||
// updateDarkSign(darkMode)
|
||||
// designStore.setDarkMode(darkMode)
|
||||
// },
|
||||
// })
|
||||
|
||||
const designStore = useDesignSettingStore()
|
||||
const globSetting = useGlobSetting()
|
||||
const router = useRouter()
|
||||
|
||||
const { title } = globSetting
|
||||
|
||||
const getSwipeText = computed(() => {
|
||||
return [
|
||||
{
|
||||
title: '💡 最新技术栈',
|
||||
details: '基于Vue3、Vant4、Vite、TypeScript等最新技术栈开发',
|
||||
},
|
||||
{
|
||||
title: '⚡️ 轻量快速的热重载',
|
||||
details: '无论应用程序大小如何,都始终极快的模块热重载(HMR)',
|
||||
},
|
||||
{
|
||||
title: '🔩 主题配置',
|
||||
details: '具备主题配置及黑暗主题适配,且持久化保存',
|
||||
},
|
||||
{
|
||||
title: '🛠️ 丰富的 Vite 插件',
|
||||
details: '集成大部分 Vite 插件,无需繁琐配置,开箱即用',
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.wel-box {
|
||||
min-height: 50vh;
|
||||
max-width: 45vh;
|
||||
min-width: 30vh;
|
||||
.wel-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.wel-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
304
types/auto-imports.d.ts
vendored
Normal file
304
types/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
/* 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 asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const computedAsync: typeof import('@vueuse/core')['computedAsync']
|
||||
const computedEager: typeof import('@vueuse/core')['computedEager']
|
||||
const computedInject: typeof import('@vueuse/core')['computedInject']
|
||||
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
|
||||
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
|
||||
const controlledRef: typeof import('@vueuse/core')['controlledRef']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
||||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
||||
const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
|
||||
const createPinia: typeof import('pinia')['createPinia']
|
||||
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
|
||||
const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
|
||||
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
|
||||
const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
|
||||
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
|
||||
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const defineStore: typeof import('pinia')['defineStore']
|
||||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||
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 ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const injectLocal: typeof import('@vueuse/core')['injectLocal']
|
||||
const isDefined: typeof import('@vueuse/core')['isDefined']
|
||||
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 makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
|
||||
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 onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
||||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
|
||||
const onLongPress: typeof import('@vueuse/core')['onLongPress']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
||||
const reactify: typeof import('@vueuse/core')['reactify']
|
||||
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
|
||||
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
|
||||
const reactivePick: typeof import('@vueuse/core')['reactivePick']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
|
||||
const refDebounced: typeof import('@vueuse/core')['refDebounced']
|
||||
const refDefault: typeof import('@vueuse/core')['refDefault']
|
||||
const refThrottled: typeof import('@vueuse/core')['refThrottled']
|
||||
const refWithControl: typeof import('@vueuse/core')['refWithControl']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
||||
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
||||
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 syncRef: typeof import('@vueuse/core')['syncRef']
|
||||
const syncRefs: typeof import('@vueuse/core')['syncRefs']
|
||||
const templateRef: typeof import('@vueuse/core')['templateRef']
|
||||
const throttledRef: typeof import('@vueuse/core')['throttledRef']
|
||||
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toReactive: typeof import('@vueuse/core')['toReactive']
|
||||
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 tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
|
||||
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
|
||||
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
|
||||
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
|
||||
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const unrefElement: typeof import('@vueuse/core')['unrefElement']
|
||||
const until: typeof import('@vueuse/core')['until']
|
||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
|
||||
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
|
||||
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
|
||||
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
|
||||
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
|
||||
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
|
||||
const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes']
|
||||
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
|
||||
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
|
||||
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
|
||||
const useArraySome: typeof import('@vueuse/core')['useArraySome']
|
||||
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
|
||||
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
|
||||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useBase64: typeof import('@vueuse/core')['useBase64']
|
||||
const useBattery: typeof import('@vueuse/core')['useBattery']
|
||||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
|
||||
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
|
||||
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
|
||||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
|
||||
const useCached: typeof import('@vueuse/core')['useCached']
|
||||
const useClipboard: typeof import('@vueuse/core')['useClipboard']
|
||||
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
|
||||
const useCloned: typeof import('@vueuse/core')['useCloned']
|
||||
const useColorMode: typeof import('@vueuse/core')['useColorMode']
|
||||
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
|
||||
const useCounter: typeof import('@vueuse/core')['useCounter']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVar: typeof import('@vueuse/core')['useCssVar']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
|
||||
const useCycleList: typeof import('@vueuse/core')['useCycleList']
|
||||
const useDark: typeof import('@vueuse/core')['useDark']
|
||||
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
|
||||
const useDebounce: typeof import('@vueuse/core')['useDebounce']
|
||||
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
|
||||
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
|
||||
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
|
||||
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
|
||||
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
|
||||
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
|
||||
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
|
||||
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
|
||||
const useDraggable: typeof import('@vueuse/core')['useDraggable']
|
||||
const useDropZone: typeof import('@vueuse/core')['useDropZone']
|
||||
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
|
||||
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
|
||||
const useElementHover: typeof import('@vueuse/core')['useElementHover']
|
||||
const useElementSize: typeof import('@vueuse/core')['useElementSize']
|
||||
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
|
||||
const useEventBus: typeof import('@vueuse/core')['useEventBus']
|
||||
const useEventListener: typeof import('@vueuse/core')['useEventListener']
|
||||
const useEventSource: typeof import('@vueuse/core')['useEventSource']
|
||||
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
|
||||
const useFavicon: typeof import('@vueuse/core')['useFavicon']
|
||||
const useFetch: typeof import('@vueuse/core')['useFetch']
|
||||
const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
|
||||
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
|
||||
const useFocus: typeof import('@vueuse/core')['useFocus']
|
||||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
||||
const useFps: typeof import('@vueuse/core')['useFps']
|
||||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
||||
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
||||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
||||
const useIdle: typeof import('@vueuse/core')['useIdle']
|
||||
const useImage: typeof import('@vueuse/core')['useImage']
|
||||
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
|
||||
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
|
||||
const useInterval: typeof import('@vueuse/core')['useInterval']
|
||||
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
|
||||
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
|
||||
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
|
||||
const useLink: typeof import('vue-router')['useLink']
|
||||
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
|
||||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
|
||||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
|
||||
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
|
||||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
|
||||
const useMemoize: typeof import('@vueuse/core')['useMemoize']
|
||||
const useMemory: typeof import('@vueuse/core')['useMemory']
|
||||
const useMounted: typeof import('@vueuse/core')['useMounted']
|
||||
const useMouse: typeof import('@vueuse/core')['useMouse']
|
||||
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
|
||||
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
|
||||
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
|
||||
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
|
||||
const useNetwork: typeof import('@vueuse/core')['useNetwork']
|
||||
const useNow: typeof import('@vueuse/core')['useNow']
|
||||
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
|
||||
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
|
||||
const useOnline: typeof import('@vueuse/core')['useOnline']
|
||||
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
|
||||
const useParallax: typeof import('@vueuse/core')['useParallax']
|
||||
const useParentElement: typeof import('@vueuse/core')['useParentElement']
|
||||
const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver']
|
||||
const usePermission: typeof import('@vueuse/core')['usePermission']
|
||||
const usePointer: typeof import('@vueuse/core')['usePointer']
|
||||
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
|
||||
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
|
||||
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
|
||||
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
|
||||
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
|
||||
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
|
||||
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
|
||||
const usePrevious: typeof import('@vueuse/core')['usePrevious']
|
||||
const useRafFn: typeof import('@vueuse/core')['useRafFn']
|
||||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
|
||||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
|
||||
const useRoute: typeof import('vue-router')['useRoute']
|
||||
const useRouter: typeof import('vue-router')['useRouter']
|
||||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
||||
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
||||
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
|
||||
const useScroll: typeof import('@vueuse/core')['useScroll']
|
||||
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
|
||||
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
|
||||
const useShare: typeof import('@vueuse/core')['useShare']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useSorted: typeof import('@vueuse/core')['useSorted']
|
||||
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
|
||||
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
|
||||
const useStepper: typeof import('@vueuse/core')['useStepper']
|
||||
const useStorage: typeof import('@vueuse/core')['useStorage']
|
||||
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
|
||||
const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
|
||||
const useSupported: typeof import('@vueuse/core')['useSupported']
|
||||
const useSwipe: typeof import('@vueuse/core')['useSwipe']
|
||||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
|
||||
const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
|
||||
const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
|
||||
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
|
||||
const useThrottle: typeof import('@vueuse/core')['useThrottle']
|
||||
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
|
||||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
||||
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
|
||||
const useTimeout: typeof import('@vueuse/core')['useTimeout']
|
||||
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
|
||||
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
|
||||
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
|
||||
const useTitle: typeof import('@vueuse/core')['useTitle']
|
||||
const useToNumber: typeof import('@vueuse/core')['useToNumber']
|
||||
const useToString: typeof import('@vueuse/core')['useToString']
|
||||
const useToggle: typeof import('@vueuse/core')['useToggle']
|
||||
const useTransition: typeof import('@vueuse/core')['useTransition']
|
||||
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
|
||||
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
|
||||
const useVModel: typeof import('@vueuse/core')['useVModel']
|
||||
const useVModels: typeof import('@vueuse/core')['useVModels']
|
||||
const useVibrate: typeof import('@vueuse/core')['useVibrate']
|
||||
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
|
||||
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
|
||||
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
|
||||
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
|
||||
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
|
||||
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
|
||||
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
|
||||
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
|
||||
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchArray: typeof import('@vueuse/core')['watchArray']
|
||||
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
|
||||
const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
|
||||
const watchDeep: typeof import('@vueuse/core')['watchDeep']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
|
||||
const watchImmediate: typeof import('@vueuse/core')['watchImmediate']
|
||||
const watchOnce: typeof import('@vueuse/core')['watchOnce']
|
||||
const watchPausable: typeof import('@vueuse/core')['watchPausable']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
|
||||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
||||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
||||
const whenever: typeof import('@vueuse/core')['whenever']
|
||||
}
|
||||
// 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')
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import {
|
||||
defineConfig,
|
||||
presetAttributify,
|
||||
presetIcons,
|
||||
presetTypography,
|
||||
presetUno,
|
||||
presetWebFonts,
|
||||
} from 'unocss'
|
||||
import presetIcons from '@unocss/preset-icons'
|
||||
import presetRemToPx from '@unocss/preset-rem-to-px'
|
||||
import transformerVariantGroup from '@unocss/transformer-variant-group'
|
||||
import transformerDirectives from '@unocss/transformer-directives'
|
||||
@ -26,10 +26,10 @@ export default defineConfig({
|
||||
|
||||
// 图标预设: https://unocss.dev/presets/icons
|
||||
presetIcons({
|
||||
// cdn: 'https://esm.sh/',
|
||||
extraProperties: {
|
||||
'display': 'inline-block',
|
||||
'vertical-align': 'middle',
|
||||
// ...
|
||||
},
|
||||
}),
|
||||
|
||||
@ -68,4 +68,16 @@ export default defineConfig({
|
||||
'text-overflow': 'overflow-hidden whitespace-nowrap text-ellipsis', // 文本溢出显示省略号
|
||||
'text-break': 'whitespace-normal break-all break-words', // 文本溢出换行
|
||||
},
|
||||
|
||||
// 由于 UnoCSS 在构建时工作,这意味着只会生成静态呈现的 icon 并将其发送到你的组件中
|
||||
// 通过模板字符串 :class="menu.meta?.icon" 来动态生成 CSS 类名。
|
||||
// 这个类名是在运行时计算的,UnoCSS 在构建时无法知道 menu.meta?.icon 的具体值,
|
||||
// 因此无法生成对应的 CSS。为了解决这个问题,你可以使用 UnoCSS 的 safelist 选项来指定一些始终需要生成的 CSS 类。
|
||||
// https://unocss.dev/guide/advanced#safelist
|
||||
safelist: [
|
||||
'i-simple-icons:atlassian',
|
||||
'i-simple-icons:soundcharts',
|
||||
'i-simple-icons:docsify',
|
||||
'i-material-symbols:award-star',
|
||||
],
|
||||
})
|
||||
|
8
vercel.json
Normal file
8
vercel.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"destination": "/$1"
|
||||
}
|
||||
]
|
||||
}
|
@ -100,14 +100,14 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
chunkSizeWarningLimit: 2000,
|
||||
// 自定义底层的 Rollup 打包配置
|
||||
rollupOptions: {
|
||||
// 静态资源分类打包
|
||||
// 静态资源分类打包
|
||||
output: {
|
||||
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
|
||||
entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
|
||||
assetFileNames: '[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
|
||||
// 将 node_modules 三方依赖包最小化拆分
|
||||
manualChunks(id) {
|
||||
if (id.includes('node_modules') && !id.includes('@antv')) {
|
||||
if (id.includes('node_modules')) {
|
||||
const paths = id.toString().split('node_modules/')
|
||||
if (paths[2]) {
|
||||
return paths[2].split('/')[0].toString()
|
||||
@ -166,8 +166,6 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
'pinia',
|
||||
'lodash-es',
|
||||
'axios',
|
||||
'@vicons/antd',
|
||||
'@vicons/ionicons5',
|
||||
],
|
||||
// 打包时强制排除的依赖项
|
||||
exclude: [
|
||||
|
Loading…
x
Reference in New Issue
Block a user