Compare commits

..

38 Commits

Author SHA1 Message Date
xiaoxian521
90a61a1000 release: update 3.7.1 2022-11-22 01:00:04 +08:00
xiaoxian521
ad34c7b891 fix: 修复在未开启标签页缓存时退出登录,可能存在标签页未重置的问题 2022-11-22 00:52:30 +08:00
xiaoxian521
c5b107eab9 chore: update 2022-11-22 00:25:28 +08:00
xiaoxian521
a8c59c5c36 release: update 3.7.0 2022-11-21 17:14:22 +08:00
xiaoxian521
0d4d3a301b fix: 优化单点登录 2022-11-21 16:44:31 +08:00
xiaoxian521
b10c3eb1bb feat: 添加前端单点登录 2022-11-21 16:22:17 +08:00
RealityBoy
9b62d6ef1e feat: add ample demos to @pureadmin/table (#379)
* feat: add ample demos to @pureadmin/table
2022-11-21 11:42:33 +08:00
xiaoxian521
8ff242ea45 docs: update README.md 2022-11-18 22:40:32 +08:00
xiaoxian521
867ef87a34 chore: use intro.js replace driver.js 2022-11-18 19:54:08 +08:00
xiaoxian521
2235d9d7a8 chore: 删除 @vitejs/plugin-legacyvue3 无法通过任何工具使其支持ie 2022-11-17 22:11:13 +08:00
clovelll
5c82fdcd0f fix: 卡片列表页编辑菜单高度问题 (#376)
Co-authored-by: chenanrong <chenanrong@kezaihui.com>
2022-11-17 19:21:02 +08:00
xiaoxian521
641355083c feat: 兼容引入某个库导致 global is not defined 报错 2022-11-17 18:54:09 +08:00
xiaoxian521
cadd611559 perf: 补充注释 2022-11-17 18:12:03 +08:00
xiaoxian521
fb734f3394 chore: 删除 httpREADME.md,看文档 http请求 即可 2022-11-17 15:48:03 +08:00
xiaoxian521
e4a87e2138 perf: 优化环境变量注释 2022-11-17 15:44:11 +08:00
xiaoxian521
12db42892d chore: 规范menuArrowIconNoTransition 写法 2022-11-17 15:29:12 +08:00
xiaoxian521
13a0db0180 perf: 删除已废弃的 $baseUrl 2022-11-17 14:59:36 +08:00
xiaoxian521
facb09d779 fix: 页内菜单带参互相跳转,标签没有选中高亮 2022-11-16 17:30:24 +08:00
xiaoxian521
617f8e936c chore: update 2022-11-16 12:03:34 +08:00
xiaoxian521
6e48ad79a7 feat: 优化菜单,添加 menuArrowIconNoTransition 全局配置 2022-11-16 11:59:59 +08:00
xiaoxian521
3984ab19c9 docs: update 2022-11-16 01:34:19 +08:00
xiaoxian521
49a9259f2e perf: 规范script setup写法 2022-11-16 00:40:13 +08:00
xiaoxian521
867bbad1be docs: update README 2022-11-14 12:09:10 +08:00
xiaoxian521
ead4318163 feat: 丰富水印功能页面 2022-11-13 13:15:01 +08:00
xiaoxian521
bfa9203883 chore: update dependencies 2022-11-12 17:48:05 +08:00
xiaoxian521
4f5f18f61c perf: update 2022-11-12 09:55:20 +08:00
xiaoxian521
df71c7f75c chore: update dependencies 2022-11-11 03:36:18 +08:00
xiaoxian521
c4839aa5f4 chore: 更换表单设计器组件 2022-11-10 13:00:48 +08:00
xiaoxian521
c19fbb1473 release: update 3.6.4 2022-11-10 12:17:05 +08:00
xiaoxian521
3cdebf4ee9 style: 删除多余样式(请务必删除) 2022-11-10 12:11:16 +08:00
xiaoxian521
2bb433c3cd perf: 将baseURL和全局环境代理删除,可直接在vite.config.ts编写,即方便又支持多个代理地址 2022-11-10 11:47:07 +08:00
xiaoxian521
731e9b2f57 chore: update 2022-11-09 01:17:19 +08:00
xiaoxian521
b606fa454d perf: 优化路由守卫 2022-11-08 18:14:33 +08:00
xiaoxian521
c6bd3f11b6 chore: update devDependencies 2022-11-08 13:52:59 +08:00
xiaoxian521
d11398274a feat: 菜单图标 icon 支持使用在线图标 2022-11-08 12:05:07 +08:00
xiaoxian521
b2081b3481 perf: 优化代码 2022-11-08 01:30:04 +08:00
xiaoxian521
f5b7ee5a81 docs: update 2022-11-08 00:48:16 +08:00
xiaoxian521
20a1293a55 style: vxe-button color in hover 2022-11-02 22:48:35 +08:00
149 changed files with 3950 additions and 2270 deletions

2
.env
View File

@@ -1,2 +1,2 @@
# 项目本地运行端口号
# 平台本地运行端口号
VITE_PORT = 8848

View File

@@ -1,14 +1,8 @@
# 项目本地运行端口号
# 平台本地运行端口号
VITE_PORT = 8848
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH = /
# 开发环境代理
VITE_PROXY_DOMAIN = /api
# 开发环境路由历史模式
# 开发环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 开发环境后端地址
VITE_PROXY_DOMAIN_REAL = "http://127.0.0.1:3000"

View File

@@ -1,15 +1,9 @@
# 线上环境项目打包路径
# 线上环境平台打包路径
VITE_PUBLIC_PATH = /
# 线上环境路由历史模式
# 线上环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 线上环境后端地址
VITE_PROXY_DOMAIN_REAL = ""
# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = false

View File

@@ -4,19 +4,13 @@ NODE_ENV=production
VITE_PUBLIC_PATH = /
# 线上环境路由历史模式
# 预发布环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 线上环境后端地址
VITE_PROXY_DOMAIN_REAL = ""
# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = false
VITE_CDN = true
# 是否启用gzip压缩或brotli压缩分两种情况删除原始文件和不删除原始文件
# 压缩时不删除原始文件的配置gzip、brotli、both同时开启 gzip 与 brotli 压缩、none不开启压缩默认
# 压缩时删除原始文件的配置gzip-clear、brotli-clear、both-clear同时开启 gzip 与 brotli 压缩、none不开启压缩默认
VITE_COMPRESSION = "none"
VITE_COMPRESSION = "both-clear"

View File

@@ -1,10 +1,13 @@
public
dist
*.d.ts
/src/assets
package.json
.eslintrc.js
.prettierrc.js
commitlint.config.js
postcss.config.js
tailwind.config.js
stylelint.config.js
stylelint.config.js
src/components/ReSplitPane/iconfont
src/components/ReFlowChart/src/assets/iconfont

View File

@@ -1,3 +1,48 @@
# 3.7.1 (2022-11-22)
### 🔥 hotfix
- Fixed the problem that the tab page may not be reset when logging out when the tab page cache is not turned on
# 3.7.0 (2022-11-21)
### ✔️ refactor
- Replace `driver.js` with `intro.js`
### 🎫 Feat
- Add front-end single sign-on, test address https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
- Add more examples for [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/serverConfig.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
- Replacement form designer component demo
### 🐞 Bug fixes
- Repair the in-page menu with parameters to jump to each other, the label is not selected and highlighted
### 🍏 Perf
- Removed deprecated `$baseUrl`
- Compatible importing a certain library leads to `global is not defined` error, importing `src/utils/globalPolyfills.ts` file into `src/main.ts` can solve the problem
- Remove `@vitejs/plugin-legacy`, `vue3` cannot make it support `ie` through any tool
# 3.6.4 (2022-11-10)
### 🎫 Feat
- Menu icon `icon` supports using online icons
### 🐞 Bug fixes
- Fixed `vxe-button` font color issue after mouse overlay and some other style issues
### 🍏 Perf
- Optimize the routing guard, if you have logged in and there is login information, you cannot jump to the routing whitelist, but continue to stay on the current page
- Removed `baseURL` and global environment proxy, and can be written directly in `vite.config.ts`, which is convenient and supports multiple proxy addresses
# 3.6.3 (2022-11-01)
### 🎫 Feat
@@ -106,7 +151,7 @@
- Secondary encapsulation of `Table` of `element-plus` into [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table), providing flexible configuration items and integrating into the platform
- Secondary encapsulation of `Descriptions` of `element-plus` into [@pureadmin/descriptions](https://github.com/xiaoxian521/pure-admin-descriptions), providing flexible configuration items and integrating into the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils-docs.vercel.app/), and delete the code concentrated in this library to reduce the size of the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils.netlify.app), and delete the code concentrated in this library to reduce the size of the platform
- Add [unplugin-vue-define-options](https://www.npmjs.com/package/unplugin-vue-define-options) plugin, the page can directly write `defineOptions({name: custom name})`
- Add project files, language analysis tool [cloc](https://www.npmjs.com/package/cloc)
- Added landing page internationalization
@@ -267,7 +312,6 @@
- Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter
- Packaged files provide traditional browser compatibility support, configure VITE_LEGACY to true
# 2.6.0(2021-11-10)

View File

@@ -1,3 +1,48 @@
# 3.7.1 (2022-11-22)
### 🔥 hotfix
- Fixed the problem that the tab page may not be reset when logging out when the tab page cache is not turned on
# 3.7.0 (2022-11-21)
### ✔️ refactor
- Replace `driver.js` with `intro.js`
### 🎫 Feat
- Add front-end single sign-on, test address https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
- Add more examples for [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/serverConfig.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
- Replacement form designer component demo
### 🐞 Bug fixes
- Repair the in-page menu with parameters to jump to each other, the label is not selected and highlighted
### 🍏 Perf
- Removed deprecated `$baseUrl`
- Compatible importing a certain library leads to `global is not defined` error, importing `src/utils/globalPolyfills.ts` file into `src/main.ts` can solve the problem
- Remove `@vitejs/plugin-legacy`, `vue3` cannot make it support `ie` through any tool
# 3.6.4 (2022-11-10)
### 🎫 Feat
- Menu icon `icon` supports using online icons
### 🐞 Bug fixes
- Fixed `vxe-button` font color issue after mouse overlay and some other style issues
### 🍏 Perf
- Optimize the routing guard, if you have logged in and there is login information, you cannot jump to the routing whitelist, but continue to stay on the current page
- Removed `baseURL` and global environment proxy, and can be written directly in `vite.config.ts`, which is convenient and supports multiple proxy addresses
# 3.6.3 (2022-11-01)
### 🎫 Feat
@@ -106,7 +151,7 @@
- Secondary encapsulation of `Table` of `element-plus` into [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table), providing flexible configuration items and integrating into the platform
- Secondary encapsulation of `Descriptions` of `element-plus` into [@pureadmin/descriptions](https://github.com/xiaoxian521/pure-admin-descriptions), providing flexible configuration items and integrating into the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils-docs.vercel.app/), and delete the code concentrated in this library to reduce the size of the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils.netlify.app), and delete the code concentrated in this library to reduce the size of the platform
- Add [unplugin-vue-define-options](https://www.npmjs.com/package/unplugin-vue-define-options) plugin, the page can directly write `defineOptions({name: custom name})`
- Add project files, language analysis tool [cloc](https://www.npmjs.com/package/cloc)
- Added landing page internationalization
@@ -267,7 +312,6 @@
- Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter
- Packaged files provide traditional browser compatibility support, configure VITE_LEGACY to true
# 2.6.0(2021-11-10)

View File

@@ -1,3 +1,48 @@
# 3.7.1 (2022-11-22)
### 🔥 hotfix
- 修复在未开启标签页缓存时退出登录,可能存在标签页未重置的问题
# 3.7.0 (2022-11-21)
### ✔️ refactor
- 使用 `intro.js` 替换 `driver.js`
### 🎫 Feat
- 添加前端单点登录,测试地址 https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
- 为 [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table) 添加更多的示例和 `element-plus` 的 [table](https://element-plus.org/zh-CN/component/table.html) 示例保持一致
- 丰富水印功能页面(支持自定义各种颜色、阴影、文字、额外属性、设置不可删除水印以及给指定元素设置水印)
- 优化菜单,添加 `MenuArrowIconNoTransition` 全局配置,在 `public/serverConfig.json` 中配置即可,对于出现左侧菜单模式,菜单展开卡顿的可设置 `MenuArrowIconNoTransition: true` 即可解决
- 更换表单设计器组件演示
### 🐞 Bug fixes
- 修复页内菜单带参互相跳转,标签没有选中高亮
### 🍏 Perf
- 删除已废弃的 `$baseUrl`
- 兼容引入某个库导致 `global is not defined` 报错,将 `src/utils/globalPolyfills.ts` 文件引入 `src/main.ts` 即可解决
- 删除 `@vitejs/plugin-legacy``vue3` 无法通过任何工具使其支持 `ie`
# 3.6.4 (2022-11-10)
### 🎫 Feat
- 菜单图标 `icon` 支持使用在线图标
### 🐞 Bug fixes
- 修复 `vxe-button` 鼠标覆盖后字体颜色问题以及一些别的样式问题
### 🍏 Perf
- 优化路由守卫,如果已经登录并存在登录信息后不能跳转到路由白名单,而是继续保持在当前页面
-`baseURL` 和全局环境代理删除,可直接在 `vite.config.ts` 编写,即方便又支持多个代理地址
# 3.6.3 (2022-11-01)
### 🎫 Feat
@@ -68,7 +113,7 @@
### ✔️ refactor
- 使用 `tailwindcss` 替换 `unocss`,新增 `tailwindcss` [使用文档](http://yiming_chang.gitee.io/pure-admin-doc/pages/39156f/)
- 使用 `tailwindcss` 替换 `unocss`,新增 `tailwindcss` [使用文档](https://yiming_chang.gitee.io/pure-admin-doc/pages/tailwindcss/)
### 🐞 Bug fixes
@@ -106,7 +151,7 @@
-`element-plus``Table` 二次封装到[@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table),提供灵活的配置项并集成到平台里
-`element-plus``Descriptions` 二次封装到[@pureadmin/descriptions](https://github.com/xiaoxian521/pure-admin-descriptions),提供灵活的配置项并集成到平台里
- 将平台的大部分工具以及 hooks 都集中到[@pureadmin/utils](https://pure-admin-utils-docs.vercel.app/),并删除集中到这个库里的代码,减少平台体积
- 将平台的大部分工具以及 `hooks` 都集中到[@pureadmin/utils](https://pure-admin-utils.netlify.app),并删除集中到这个库里的代码,减少平台体积
- 添加[unplugin-vue-define-options](https://www.npmjs.com/package/unplugin-vue-define-options)插件,页面可直接写 `defineOptions({name: 自定义名称})`
- 添加项目文件、语言分析工具 [cloc](https://www.npmjs.com/package/cloc)
- 添加登录页国际化
@@ -267,7 +312,6 @@
- 优化标签页,带来更好的交互体验
- 路由 title 支持直接写中文,可脱离国际化
- 路由历史模式从 env 读取并支持 base 参数
- 打包后的文件提供传统浏览器兼容性支持,配置 VITE_LEGACY 为 true
# 2.6.0(2021-11-10)

View File

@@ -8,18 +8,17 @@
## Introduction
vue-pure-admin is a free and open source middle and back-end template. Using the latest `vue3` `vite2` `Element-Plus` `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.
`vue-pure-admin` is an open source free and out-of-the-box middle and background management system template. Developed using the latest mainstream technologies such as `Vue3`, `Vite`, `Element-Plus`, `TypeScript`, `Pinia`, `Tailwindcss`
## Supporting Video
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1534y1S7HV)
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1kg411v7QT)
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
## Docs
## Docs (support `PWA` fast, offline access)
- [Click me to view the domestic documentation site](http://yiming_chang.gitee.io/pure-admin-doc)
- [Click me to view foreign document site 1](https://xiaoxian521.github.io/pure-admin-doc)
- [Click me to view foreign document site 2](https://pure-admin-doc.vercel.app)
- [Click me to view the domestic documentation site](https://yiming_chang.gitee.io/pure-admin-doc)
- [Click me to view foreign document site](https://xiaoxian521.github.io/pure-admin-doc)
## Thin version (offering non-internationalized and internationalized versions)
@@ -30,11 +29,14 @@ vue-pure-admin is a free and open source middle and back-end template. Using the
- [Click Watch Tauri](https://github.com/xiaoxian521/tauri-pure-admin)
## Electron
- [Click Watch Electron](https://github.com/xiaoxian521/electron-pure-admin)
## Preview
- [Click me to view the domestic preview station](http://yiming_chang.gitee.io/vue-pure-admin)
- [Click me to view foreign preview site 1](https://xiaoxian521.github.io/vue-pure-admin)
- [Click me to view foreign preview station 2](https://vue-pure-admin.vercel.app)
- [Click me to view the domestic preview station](https://yiming_chang.gitee.io/vue-pure-admin)
- [Click me to view foreign preview site](https://xiaoxian521.github.io/vue-pure-admin)
- PC
<p align="center">

View File

@@ -8,18 +8,17 @@
## 简介
vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3` `vite2` `Element-Plus` `TypeScript`等主流技术开发,开箱即用的中后台前端解决方案,也可用于学习参考。
`vue-pure-admin` 是一款开源免费且开箱即用的中后台管理系统模版。使用了最新的 `Vue3``Vite``Element-Plus``TypeScript``Pinia``Tailwindcss` 等主流技术开发
## 配套视频
- [点我查看教程](https://www.bilibili.com/video/BV1534y1S7HV)
- [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
## 配套文档
## 配套文档(支持 `PWA` 快速、离线访问)
- [点我查看国内文档站](http://yiming_chang.gitee.io/pure-admin-doc)
- [点我查看国外文档站 1](https://xiaoxian521.github.io/pure-admin-doc)
- [点我查看国外文档站 2](https://pure-admin-doc.vercel.app)
- [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
- [点我查看国外文档站](https://xiaoxian521.github.io/pure-admin-doc)
## 精简版(提供非国际化、国际化两个版本选择)
@@ -30,11 +29,14 @@ vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3
- [点我查看 Tauri 版](https://github.com/xiaoxian521/tauri-pure-admin)
## Electron 版
- [点我查看 Electron 版](https://github.com/xiaoxian521/electron-pure-admin)
## 预览
- [点我查看国内预览站](http://yiming_chang.gitee.io/vue-pure-admin)
- [点我查看国外预览站 1](https://xiaoxian521.github.io/vue-pure-admin)
- [点我查看国外预览站 2](https://vue-pure-admin.vercel.app)
- [点我查看国内预览站](https://yiming_chang.gitee.io/vue-pure-admin)
- [点我查看国外预览站](https://xiaoxian521.github.io/vue-pure-admin)
- PC 端
<p align="center">
@@ -146,7 +148,7 @@ pnpm build
一群已满,下面是二群,群里严禁`黄``赌``毒``vpn`等违法行为!
<img src="http://yiming_chang.gitee.io/pure-admin-doc/img/support/qq.png" width="150px" height="225px" />
<img src="https://yiming_chang.gitee.io/pure-admin-doc/img/support/qq.png" width="150px" height="225px" />
## 许可证

View File

@@ -1,13 +1,10 @@
/** 处理环境变量 */
const warpperEnv = (envConf: Recordable): ViteEnv => {
/** 此处为默认值,无需修改 */
/** 此处为默认值 */
const ret: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_PROXY_DOMAIN: "",
VITE_PROXY_DOMAIN_REAL: "",
VITE_ROUTER_HISTORY: "",
VITE_LEGACY: false,
VITE_CDN: false,
VITE_COMPRESSION: "none"
};
@@ -30,14 +27,9 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
return ret;
};
/** 跨域代理重写 */
const regExps = (value: string, reg: string): string => {
return value.replace(new RegExp(`^${reg}`, "g"), "");
};
/** 环境变量 */
/** 获取环境变量 */
const loadEnv = (): ViteEnv => {
return import.meta.env;
};
export { warpperEnv, regExps, loadEnv };
export { warpperEnv, loadEnv };

View File

@@ -3,20 +3,18 @@ import { resolve } from "path";
import vue from "@vitejs/plugin-vue";
import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader";
import legacy from "@vitejs/plugin-legacy";
import vueJsx from "@vitejs/plugin-vue-jsx";
import VueMacros from "unplugin-vue-macros/vite";
import { viteMockServe } from "vite-plugin-mock";
import { configCompressPlugin } from "./compress";
import VueI18n from "@intlify/vite-plugin-vue-i18n";
import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import themePreprocessorPlugin from "@pureadmin/theme";
import DefineOptions from "unplugin-vue-define-options/vite";
import { genScssMultipleScopeVars } from "../src/layout/theme";
export function getPluginsList(
command: string,
VITE_LEGACY: boolean,
VITE_CDN: boolean,
VITE_COMPRESSION: ViteCompression
) {
@@ -34,7 +32,7 @@ export function getPluginsList(
vueJsx(),
VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION),
DefineOptions(),
VueMacros(),
// 线上环境删除console
removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),
viteBuildInfo(),
@@ -65,13 +63,6 @@ export function getPluginsList(
`,
logger: false
}),
// 是否为打包后的文件提供传统浏览器兼容性支持
VITE_LEGACY
? legacy({
targets: ["ie >= 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
})
: null,
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" })

View File

@@ -89,7 +89,7 @@ const frameRouter = {
meta: {
icon: "monitor",
title: "menus.hsExternalPage",
rank: 7
rank: 8
},
children: [
{
@@ -97,13 +97,13 @@ const frameRouter = {
name: "FramePure",
meta: {
title: "menus.hsPureDocument",
frameSrc: "http://yiming_chang.gitee.io/pure-admin-doc",
frameSrc: "https://yiming_chang.gitee.io/pure-admin-doc",
roles: ["admin", "common"]
}
},
{
path: "/external",
name: "http://yiming_chang.gitee.io/pure-admin-doc",
name: "https://yiming_chang.gitee.io/pure-admin-doc",
meta: {
title: "menus.externalLink",
roles: ["admin", "common"]
@@ -137,6 +137,7 @@ const tabsRouter = {
roles: ["admin", "common"]
}
},
// query 传参模式
{
path: "/tabs/query-detail",
name: "TabQueryDetail",
@@ -146,11 +147,13 @@ const tabsRouter = {
roles: ["admin", "common"]
}
},
// params 传参模式
{
path: "/tabs/params-detail/:id",
component: "params-detail",
name: "TabParamsDetail",
meta: {
// 不在menu菜单中显示
showLink: false,
roles: ["admin", "common"]
}

View File

@@ -1,6 +1,6 @@
{
"name": "vue-pure-admin",
"version": "3.6.3",
"version": "3.7.1",
"private": true,
"scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
@@ -30,15 +30,14 @@
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@ctrl/tinycolor": "^3.4.1",
"@logicflow/core": "^1.1.24",
"@logicflow/extension": "^1.1.24",
"@logicflow/core": "^1.1.30",
"@logicflow/extension": "^1.1.30",
"@pureadmin/components": "^1.1.0",
"@pureadmin/descriptions": "^1.1.0",
"@pureadmin/table": "^1.2.0",
"@pureadmin/utils": "^1.1.5",
"@vueuse/core": "^9.4.0",
"@vueuse/motion": "^2.0.0-beta.12",
"@vueuse/shared": "^9.4.0",
"@pureadmin/table": "^1.6.0",
"@pureadmin/utils": "^1.6.7",
"@vueuse/core": "^9.5.0",
"@vueuse/motion": "2.0.0-beta.12",
"@wangeditor/editor": "^5.1.21",
"@wangeditor/editor-for-vue": "^5.1.12",
"animate.css": "^4.1.1",
@@ -46,11 +45,11 @@
"china-area-data": "^5.0.1",
"cropperjs": "^1.5.12",
"dayjs": "^1.11.5",
"driver.js": "^0.9.8",
"echarts": "^5.4.0",
"el-table-infinite-scroll": "^3.0.1",
"element-plus": "^2.2.18",
"element-resize-detector": "^1.2.3",
"element-plus": "^2.2.22",
"element-resize-detector": "^1.2.4",
"intro.js": "^6.0.0",
"js-cookie": "^3.0.1",
"jsbarcode": "^3.11.5",
"lodash": "^4.17.21",
@@ -60,7 +59,7 @@
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"pinia": "^2.0.23",
"pinia": "^2.0.24",
"qrcode": "^1.5.1",
"qs": "^6.11.0",
"resize-observer-polyfill": "^1.5.1",
@@ -69,8 +68,7 @@
"swiper": "^8.4.4",
"typeit": "^8.7.0",
"v-contextmenu": "3.0.0",
"vue": "^3.2.40",
"vue-form-create2": "^1.2.8",
"vue": "^3.2.45",
"vue-i18n": "^9.2.2",
"vue-json-pretty": "^2.2.2",
"vue-pdf-embed": "^1.1.4",
@@ -96,65 +94,65 @@
"@iconify-icons/mdi": "^1.2.8",
"@iconify-icons/ri": "^1.2.3",
"@iconify-icons/uil": "^1.2.2",
"@iconify/vue": "^3.2.1",
"@iconify/vue": "^4.0.0",
"@intlify/vite-plugin-vue-i18n": "^6.0.3",
"@pureadmin/theme": "^2.4.0",
"@types/element-resize-detector": "1.1.3",
"@types/intro.js": "^5.1.0",
"@types/js-cookie": "^3.0.1",
"@types/lodash": "^4.14.180",
"@types/lodash-es": "^4.17.6",
"@types/mockjs": "1.0.3",
"@types/node": "14.14.14",
"@types/mockjs": "^1.0.7",
"@types/node": "^18.11.9",
"@types/nprogress": "0.2.0",
"@types/qrcode": "^1.4.2",
"@types/qs": "^6.9.7",
"@types/sortablejs": "^1.13.0",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"@vitejs/plugin-legacy": "^2.2.0",
"@vitejs/plugin-vue": "^3.1.2",
"@vitejs/plugin-vue-jsx": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
"@vitejs/plugin-vue": "^3.2.0",
"@vitejs/plugin-vue-jsx": "^2.1.1",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"@vue/runtime-core": "^3.2.40",
"autoprefixer": "^10.4.12",
"@vue/eslint-config-typescript": "^11.0.2",
"@vue/runtime-core": "^3.2.45",
"autoprefixer": "^10.4.13",
"cloc": "^2.10.0",
"cssnano": "^5.1.13",
"cssnano": "^5.1.14",
"eslint": "^8.8.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.4.1",
"eslint-plugin-vue": "^9.7.0",
"font-awesome": "^4.7.0",
"husky": "^7.0.4",
"lint-staged": "11.1.2",
"picocolors": "^1.0.0",
"postcss": "^8.4.17",
"postcss": "^8.4.18",
"postcss-html": "^1.5.0",
"postcss-import": "^15.0.0",
"postcss-scss": "^4.0.5",
"prettier": "^2.5.1",
"pretty-quick": "3.1.1",
"rimraf": "3.0.2",
"rollup-plugin-visualizer": "^5.8.2",
"sass": "^1.53.0",
"sass-loader": "^13.0.2",
"rollup-plugin-visualizer": "^5.8.3",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"stylelint": "^14.3.0",
"stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended": "^6.0.0",
"stylelint-config-standard": "^24.0.0",
"stylelint-config-recommended": "^9.0.0",
"stylelint-config-standard": "^29.0.0",
"stylelint-order": "^5.0.0",
"tailwindcss": "^3.2.1",
"terser": "^5.15.0",
"typescript": "^4.7.4",
"unplugin-vue-define-options": "0.7.3",
"vite": "^3.1.8",
"tailwindcss": "^3.2.4",
"terser": "^5.15.1",
"typescript": "^4.9.3",
"unplugin-vue-macros": "^0.16.3",
"vite": "3.1.8",
"vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-remove-console": "^1.1.0",
"vite-plugin-remove-console": "^1.3.0",
"vite-svg-loader": "^3.6.0",
"vue-eslint-parser": "^8.2.0",
"vue-tsc": "^0.40.13"
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.0.9"
},
"pnpm": {
"peerDependencyRules": {

2492
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{
"Version": "3.6.3",
"Version": "3.7.1",
"Title": "PureAdmin",
"FixedHeader": true,
"HiddenSideBar": false,
@@ -16,6 +16,7 @@
"EpThemeColor": "#409EFF",
"ShowLogo": true,
"ShowModel": "smart",
"MenuArrowIconNoTransition": false,
"MapConfigure": {
"amapKey": "97b3248d1553172e81f168cf94ea667e",
"options": {

View File

@@ -1,4 +1,4 @@
import { http } from "../utils/http";
import { http } from "@/utils/http";
type Result = {
success: boolean;

View File

@@ -1,4 +1,4 @@
import { http } from "../utils/http";
import { http } from "@/utils/http";
type Result = {
success: boolean;

View File

@@ -1,4 +1,4 @@
import { http } from "../utils/http";
import { http } from "@/utils/http";
type Result = {
success: boolean;

View File

@@ -1,4 +1,4 @@
import { http } from "../utils/http";
import { http } from "@/utils/http";
type Result = {
success: boolean;

View File

@@ -1,4 +1,4 @@
import { http } from "../utils/http";
import { http } from "@/utils/http";
export type UserResult = {
success: boolean;

View File

@@ -8,7 +8,6 @@ import {
computed,
PropType
} from "vue";
import { templateRef } from "@vueuse/core";
import { useAttrs } from "@pureadmin/utils";
import Cropper from "cropperjs";
@@ -78,7 +77,7 @@ export default defineComponent({
props,
setup(props) {
const cropper: any = ref<Nullable<Cropper>>(null);
const imgElRef = templateRef<HTMLImageElement | null>("imgElRef", null);
const imgElRef = ref();
const isReady = ref<boolean>(false);

View File

@@ -1,22 +1,21 @@
<script setup lang="ts">
import { ref, unref, nextTick, onUnmounted } from "vue";
import { templateRef } from "@vueuse/core";
import flippers from "./filpper";
let timer = ref(null);
let flipObjs = ref([]);
const timer = ref(null);
const flipObjs = ref([]);
const flipperHour1 = templateRef<HTMLElement | null>("flipperHour1", null);
const flipperHour2 = templateRef<HTMLElement | null>("flipperHour2", null);
const flipperMinute1 = templateRef<HTMLElement | null>("flipperMinute1", null);
const flipperMinute2 = templateRef<HTMLElement | null>("flipperMinute2", null);
const flipperSecond1 = templateRef<HTMLElement | null>("flipperSecond1", null);
const flipperSecond2 = templateRef<HTMLElement | null>("flipperSecond2", null);
const flipperHour1 = ref();
const flipperHour2 = ref();
const flipperMinute1 = ref();
const flipperMinute2 = ref();
const flipperSecond1 = ref();
const flipperSecond2 = ref();
// 初始化数字
const init = () => {
let now = new Date();
let nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss");
const now = new Date();
const nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss");
for (let i = 0; i < flipObjs.value.length; i++) {
flipObjs?.value[i]?.setFront(nowTimeStr[i]);
}
@@ -26,9 +25,9 @@ const init = () => {
const run = () => {
timer.value = setInterval(() => {
// 获取当前时间
let now = new Date();
let nowTimeStr = formatDate(new Date(now.getTime() - 1000), "hhiiss");
let nextTimeStr = formatDate(now, "hhiiss");
const now = new Date();
const nowTimeStr = formatDate(new Date(now.getTime() - 1000), "hhiiss");
const nextTimeStr = formatDate(now, "hhiiss");
for (let i = 0; i < flipObjs.value.length; i++) {
if (nowTimeStr[i] === nextTimeStr[i]) {
continue;
@@ -52,17 +51,17 @@ const formatDate = (date: Date, dateFormat: string) => {
);
}
// 格式化月、日、时、分、秒
let o = {
const o = {
"m+": date.getMonth() + 1,
"d+": date.getDate(),
"h+": date.getHours(),
"i+": date.getMinutes(),
"s+": date.getSeconds()
};
for (let k in o) {
for (const k in o) {
if (new RegExp(`(${k})`).test(dateFormat)) {
// 取出对应的值
let str = o[k] + "";
const str = o[k] + "";
/* 根据设置的格式,输出对应的字符
* 例如: 早上8时hh => 08h => 8
* 但是,当数字>=10时无论格式为一位还是多位不做截取这是与年份格式化不一致的地方

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { ref, unref, onMounted } from "vue";
import { templateRef } from "@vueuse/core";
import { LogicFlow } from "@logicflow/core";
interface Props {
@@ -16,11 +15,11 @@ const emit = defineEmits<{
(e: "catData"): void;
}>();
const controlButton3 = templateRef<HTMLElement | any>("controlButton3", null);
const controlButton4 = templateRef<HTMLElement | any>("controlButton4", null);
const controlButton3 = ref();
const controlButton4 = ref();
let focusIndex = ref<Number>(-1);
let titleLists = ref([
const focusIndex = ref<Number>(-1);
const titleLists = ref([
{
icon: "icon-zoom-out-hs",
text: "缩小",
@@ -68,7 +67,7 @@ let titleLists = ref([
const onControl = (item, key) => {
["zoom", "zoom", "resetZoom", "undo", "redo", "getSnapshot"].forEach(
(v, i) => {
let domControl = props.lf;
const domControl = props.lf;
if (key === 1) {
domControl.zoom(true);
}

View File

@@ -18,7 +18,7 @@ const props = withDefaults(defineProps<Props>(), {
nodeList: null
});
let properties = ref({
const properties = ref({
a: "efrwe",
b: "wewe"
});

View File

@@ -3,7 +3,7 @@ import iconifyIconOnline from "./src/iconifyIconOnline";
import iconSelect from "./src/Select.vue";
import fontIcon from "./src/iconfont";
/** 离线图标组件 */
/** 本地图标组件 */
const IconifyIconOffline = iconifyIconOffline;
/** 在线图标组件 */
const IconifyIconOnline = iconifyIconOnline;

View File

@@ -16,21 +16,21 @@ const props = defineProps({
});
const emit = defineEmits<{ (e: "update:modelValue", v: string) }>();
let visible = ref(false);
let inputValue = toRef(props, "modelValue");
let iconList = ref(IconJson);
let icon = ref("add-location");
let currentActiveType = ref("ep:");
const visible = ref(false);
const inputValue = toRef(props, "modelValue");
const iconList = ref(IconJson);
const icon = ref("add-location");
const currentActiveType = ref("ep:");
// 深拷贝图标数据,前端做搜索
let copyIconList = cloneDeep(iconList.value);
const copyIconList = cloneDeep(iconList.value);
let pageSize = ref(96);
let currentPage = ref(1);
const pageSize = ref(96);
const currentPage = ref(1);
// 搜索条件
let filterValue = ref("");
const filterValue = ref("");
let tabsList = [
const tabsList = [
{
label: "Element Plus",
name: "ep:"
@@ -45,7 +45,7 @@ let tabsList = [
}
];
let pageList = computed(() => {
const pageList = computed(() => {
if (currentPage.value === 1) {
return copyIconList[currentActiveType.value]
.filter(v => v.includes(filterValue.value))

View File

@@ -3,7 +3,8 @@ import { h, defineComponent, Component } from "vue";
import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
/**
* 支持fontawesome4、5+、iconfont、remixicon、element-plus的icons、自定义svg
* 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
* @see 点击查看文档图标篇 {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/icon/}
* @param icon 必传 图标
* @param attrs 可选 iconType 属性
* @returns Component
@@ -34,11 +35,12 @@ export function useRenderIcon(icon: any, attrs?: iconType): Component {
// svg
return icon;
} else {
// 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之
return defineComponent({
name: "Icon",
render() {
const IconifyIcon =
attrs && attrs["online"] ? IconifyIconOnline : IconifyIconOffline;
icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline;
return h(IconifyIcon, {
icon: icon,
...attrs

View File

@@ -29,6 +29,10 @@ import Refresh from "@iconify-icons/ep/refresh";
import EditPen from "@iconify-icons/ep/edit-pen";
import Delete from "@iconify-icons/ep/delete";
import More from "@iconify-icons/ep/more-filled";
import EpArrowDown from "@iconify-icons/ep/arrow-down";
import ArrowUp from "@iconify-icons/ep/arrow-up";
import ArrowRight from "@iconify-icons/ep/arrow-right";
import ArrowLeft from "@iconify-icons/ep/arrow-left";
addIcon("check", Check);
addIcon("menu", Menu);
addIcon("home-filled", HomeFilled);
@@ -56,6 +60,10 @@ addIcon("refresh", Refresh);
addIcon("edits", EditPen);
addIcon("delete", Delete);
addIcon("more", More);
addIcon("ep-arrow-down", EpArrowDown);
addIcon("ep-arrow-up", ArrowUp);
addIcon("ep-arrow-right", ArrowRight);
addIcon("ep-arrow-left", ArrowLeft);
// remixicon
import ArrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
@@ -161,7 +169,7 @@ addIcon("unExpand", UnExpand);
import LocationCompany from "@iconify-icons/carbon/location-company";
addIcon("location-company", LocationCompany);
// Iconify Icon在Vue里离线使用用于内网环境https://docs.iconify.design/icon-components/vue/offline.html
// Iconify Icon在Vue里本地使用用于内网环境https://docs.iconify.design/icon-components/vue/offline.html
export default defineComponent({
name: "IconifyIconOffline",
components: { IconifyIcon },

View File

@@ -11,7 +11,6 @@ export interface iconType {
horizontalAlign?: boolean;
verticalAlign?: boolean;
align?: string;
online?: boolean;
onLoad?: Function;
includes?: Function;

View File

@@ -39,8 +39,8 @@ const complete = (): void => {
onBeforeMount(() => {
if (!instance) return;
let { MapConfigure } = instance.appContext.config.globalProperties.$config;
let { options } = MapConfigure;
const { MapConfigure } = instance.appContext.config.globalProperties.$config;
const { options } = MapConfigure;
AMapLoader.load({
key: MapConfigure.amapKey,
@@ -67,10 +67,10 @@ onBeforeMount(() => {
gridSize: 80,
maxZoom: 14,
renderMarker(ctx) {
let { marker, data } = ctx;
const { marker, data } = ctx;
if (Array.isArray(data) && data[0]) {
var { driver, plateNumber, orientation } = data[0];
var content = `<img style="transform: scale(1) rotate(${
const { driver, plateNumber, orientation } = data[0];
const content = `<img style="transform: scale(1) rotate(${
360 - Number(orientation)
}deg);" src='${car}' />`;
marker.setContent(content);
@@ -93,7 +93,7 @@ onBeforeMount(() => {
// 获取模拟车辆信息
mapJson()
.then(({ data }) => {
let points: object = data.map(v => {
const points: object = data.map(v => {
return {
lnglat: [v.lng, v.lat],
...v

View File

@@ -28,16 +28,16 @@ const emit = defineEmits<{
(e: "scrollEnd"): void;
}>();
let xPos = ref<number>(0);
let yPos = ref<number>(0);
let delay = ref<number>(0);
let height = ref<number>(0);
const xPos = ref<number>(0);
const yPos = ref<number>(0);
const delay = ref<number>(0);
const height = ref<number>(0);
// 外容器宽度
let width = ref<number>(0);
const width = ref<number>(0);
// 内容实际宽度
let realBoxWidth = ref<number>(0);
let realBoxHeight = ref<number>(0);
let copyHtml = ref("");
const realBoxWidth = ref<number>(0);
const realBoxHeight = ref<number>(0);
const copyHtml = ref("");
// single 单步滚动的定时器
let singleWaitTime = null;
// move动画的animationFrame定时器
@@ -52,7 +52,7 @@ let isHover = false;
let ease = "ease-in";
// eslint-disable-next-line vue/no-setup-props-destructure
let { classOption } = props;
const { classOption } = props;
if (classOption["key"] === undefined) {
classOption["key"] = 0;
@@ -68,15 +68,15 @@ const realBox = templateRef<HTMLElement | null>(
null
);
let leftSwitchState = computed(() => {
const leftSwitchState = computed(() => {
return unref(xPos) < 0;
});
let rightSwitchState = computed(() => {
const rightSwitchState = computed(() => {
return Math.abs(unref(xPos)) < unref(realBoxWidth) - unref(width);
});
let defaultOption = computed(() => {
const defaultOption = computed(() => {
return {
//步长
step: 1,
@@ -105,7 +105,7 @@ let defaultOption = computed(() => {
};
});
let options = computed(() => {
const options = computed(() => {
// @ts-expect-error
return copyObj({}, unref(defaultOption), classOption);
});
@@ -114,11 +114,11 @@ const leftSwitchClass = computed(() => {
return unref(leftSwitchState) ? "" : unref(options).switchDisabledClass;
});
let rightSwitchClass = computed(() => {
const rightSwitchClass = computed(() => {
return unref(rightSwitchState) ? "" : unref(options).switchDisabledClass;
});
let leftSwitch = computed((): CSSProperties => {
const leftSwitch = computed((): CSSProperties => {
return {
position: "absolute",
margin: `${unref(height) / 2}px 0 0 -${unref(options).switchOffset}px`,
@@ -126,7 +126,7 @@ let leftSwitch = computed((): CSSProperties => {
};
});
let rightSwitch = computed((): CSSProperties => {
const rightSwitch = computed((): CSSProperties => {
return {
position: "absolute",
margin: `${unref(height) / 2}px 0 0 ${
@@ -136,19 +136,19 @@ let rightSwitch = computed((): CSSProperties => {
};
});
let isHorizontal = computed(() => {
const isHorizontal = computed(() => {
return (
unref(options).direction !== "bottom" && unref(options).direction !== "top"
);
});
let float = computed((): CSSProperties => {
const float = computed((): CSSProperties => {
return unref(isHorizontal)
? { float: "left", overflow: "hidden" }
: { overflow: "hidden" };
});
let pos = computed(() => {
const pos = computed(() => {
return {
transform: `translate(${unref(xPos)}px,${unref(yPos)}px)`,
transition: `all ${ease} ${unref(delay)}ms`,
@@ -156,45 +156,45 @@ let pos = computed(() => {
};
});
let navigation = computed(() => {
const navigation = computed(() => {
return unref(options).navigation;
});
let autoPlay = computed(() => {
const autoPlay = computed(() => {
if (unref(navigation)) return false;
return unref(options).autoPlay;
});
let scrollSwitch = computed(() => {
const scrollSwitch = computed(() => {
// 从 props 解构出来的 属性 不再具有响应性.
return (props.data as any).length >= unref(options).limitMoveNum;
});
let hoverStopSwitch = computed(() => {
const hoverStopSwitch = computed(() => {
return unref(options).hoverStop && unref(autoPlay) && unref(scrollSwitch);
});
let canTouchScroll = computed(() => {
const canTouchScroll = computed(() => {
return unref(options).openTouch;
});
let baseFontSize = computed(() => {
const baseFontSize = computed(() => {
return unref(options).isSingleRemUnit
? parseInt(window.getComputedStyle(document.documentElement, null).fontSize)
: 1;
});
let realSingleStopWidth = computed(() => {
const realSingleStopWidth = computed(() => {
return unref(options).singleWidth * unref(baseFontSize);
});
let realSingleStopHeight = computed(() => {
const realSingleStopHeight = computed(() => {
return unref(options).singleHeight * unref(baseFontSize);
});
let step = computed(() => {
const step = computed(() => {
let singleStep;
let step = unref(options).step;
const step = unref(options).step;
if (unref(isHorizontal)) {
singleStep = unref(realSingleStopWidth);
} else {
@@ -275,7 +275,7 @@ function touchMove(e) {
return;
const touch = e.targetTouches[0];
const { direction } = unref(options);
let endPos = {
const endPos = {
x: touch.pageX - startPos.x,
y: touch.pageY - startPos.y
};
@@ -300,18 +300,19 @@ function touchMove(e) {
function touchEnd() {
if (!unref(canTouchScroll)) return;
let timer;
// eslint-disable-next-line prefer-const
let timer: any;
const direction = unref(options).direction;
delay.value = 50;
if (direction === "top") {
if (unref(yPos) > 0) yPos.value = 0;
} else if (direction === "bottom") {
let h = (unref(realBoxHeight) / 2) * -1;
const h = (unref(realBoxHeight) / 2) * -1;
if (unref(yPos) < h) yPos.value = h;
} else if (direction === "left") {
if (unref(xPos) > 0) xPos.value = 0;
} else if (direction === "right") {
let w = unref(realBoxWidth) * -1;
const w = unref(realBoxWidth) * -1;
if (unref(xPos) < w) xPos.value = w;
}
if (timer) clearTimeout(timer);
@@ -339,7 +340,7 @@ function scrollMove() {
const h = unref(realBoxHeight) / 2;
//宽度
const w = unref(realBoxWidth) / 2;
let { direction, waitTime } = unref(options);
const { direction, waitTime } = unref(options);
if (direction === "top") {
// 上
if (Math.abs(unref(yPos)) >= h) {

View File

@@ -31,7 +31,6 @@ const getConfig = (key?: string): ServerConfigs => {
export const getServerConfig = async (app: App): Promise<undefined> => {
app.config.globalProperties.$config = getConfig();
return axios({
baseURL: "",
method: "get",
url: `${VITE_PUBLIC_PATH}serverConfig.json`
})
@@ -44,8 +43,6 @@ export const getServerConfig = async (app: App): Promise<undefined> => {
// 设置全局配置
setConfig($config);
}
// 设置全局baseURL
app.config.globalProperties.$baseUrl = $config.baseURL;
return $config;
})
.catch(() => {

View File

@@ -2,14 +2,14 @@
import { ref } from "vue";
import { noticesData } from "./data";
import NoticeList from "./noticeList.vue";
import { templateRef } from "@vueuse/core";
import { Tabs, TabPane } from "@pureadmin/components";
const dropdownDom = templateRef<ElRef | null>("dropdownDom", null);
const activeName = ref(noticesData[0].name);
const dropdownDom = ref();
const activeKey = ref(noticesData[0].key);
const notices = ref(noticesData);
let noticesNum = ref(0);
const noticesNum = ref(0);
notices.value.forEach(notice => {
noticesNum.value += notice.list.length;
});
@@ -33,7 +33,8 @@ function tabClick() {
<Tabs
centered
class="dropdown-tabs"
v-model:activeName="activeName"
:tabBarStyle="{ marginLeft: notices?.length > 4 ? '8px' : '0' }"
v-model:activeKey="activeKey"
@tabClick="tabClick"
>
<template v-for="item in notices" :key="item.key">

View File

@@ -24,11 +24,11 @@ function hoverTitle() {
function hoverDescription(event, description) {
// currentWidth 为文本在页面中所占的宽度创建标签加入到页面获取currentWidth ,最后在移除
let tempTag = document.createElement("span");
const tempTag = document.createElement("span");
tempTag.innerText = description;
tempTag.className = "getDescriptionWidth";
document.querySelector("body").appendChild(tempTag);
let currentWidth = (
const currentWidth = (
document.querySelector(".getDescriptionWidth") as HTMLSpanElement
).offsetWidth;
document.querySelector(".getDescriptionWidth").remove();

View File

@@ -3,7 +3,7 @@ import { ref } from "vue";
import { onClickOutside } from "@vueuse/core";
import { emitter } from "@/utils/mitt";
let show = ref<Boolean>(false);
const show = ref<Boolean>(false);
const target = ref(null);
onClickOutside(target, (event: any) => {
if (event.clientX > target.value.offsetLeft) return;
@@ -21,7 +21,7 @@ emitter.on("openPanel", () => {
<div ref="target" class="right-panel bg-bg_color">
<div class="right-panel-items">
<div class="project-configuration">
<h3 class="dark:text-white">项目配置</h3>
<h4 class="dark:text-white">项目配置</h4>
<span title="关闭配置">
<IconifyIconOffline
class="dark:text-white"

View File

@@ -16,7 +16,7 @@
</div>
</template>
<script lang="ts" setup>
<script setup lang="ts">
import mdiKeyboardEsc from "@/assets/svg/keyboard_esc.svg?component";
import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
</script>

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script setup lang="ts">
import { useRouter } from "vue-router";
import { cloneDeep } from "lodash-unified";
import SearchResult from "./SearchResult.vue";

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script setup lang="ts">
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import { useEpThemeStoreHook } from "@/store/modules/epTheme";

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script setup lang="ts">
import { SearchModal } from "./components";
import { useBoolean } from "../../hooks/useBoolean";
const { bool: show, toggle } = useBoolean();

View File

@@ -13,7 +13,6 @@ import { useRouter } from "vue-router";
import panel from "../panel/index.vue";
import { emitter } from "@/utils/mitt";
import { resetRouter } from "@/router";
import { templateRef } from "@vueuse/core";
import { removeToken } from "@/utils/auth";
import { routerArrays } from "@/layout/types";
import { useNav } from "@/layout/hooks/useNav";
@@ -38,9 +37,9 @@ const { isDark } = useDark();
const { isSelect } = useCssModule();
const { $storage } = useGlobal<GlobalPropertiesApi>();
const mixRef = templateRef<HTMLElement | null>("mixRef", null);
const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
const mixRef = ref();
const verticalRef = ref();
const horizontalRef = ref();
const {
body,
@@ -54,8 +53,8 @@ const {
/* body添加layout属性作用于src/style/sidebar.scss */
if (unref(layoutTheme)) {
let layout = unref(layoutTheme).layout;
let theme = unref(layoutTheme).theme;
const layout = unref(layoutTheme).layout;
const theme = unref(layoutTheme).theme;
toggleTheme({
scopeName: `layout-theme-${theme}`
});
@@ -119,13 +118,13 @@ const weekChange = (value): void => {
};
const tagsChange = () => {
let showVal = settings.tabsVal;
const showVal = settings.tabsVal;
storageConfigureChange("hideTabs", showVal);
emitter.emit("tagViewsChange", showVal as unknown as string);
};
const multiTagsCacheChange = () => {
let multiTagsCache = settings.multiTagsCache;
const multiTagsCache = settings.multiTagsCache;
storageConfigureChange("multiTagsCache", multiTagsCache);
useMultiTagsStoreHook().multiTagsCacheChange(multiTagsCache);
};

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { isEqual } from "lodash-unified";
import { isEqual } from "@pureadmin/utils";
import { transformI18n } from "@/plugins/i18n";
import { ref, watch, onMounted, toRaw } from "vue";
import { getParentPaths, findRouteByPath } from "@/router/utils";

View File

@@ -11,7 +11,7 @@ import { usePermissionStoreHook } from "@/store/modules/permission";
import globalization from "@/assets/svg/globalization.svg?component";
const menuRef = ref();
let defaultActive = ref(null);
const defaultActive = ref(null);
const { t, route, locale, translationCh, translationEn } =
useTranslationLang(menuRef);

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import path from "path";
import { getConfig } from "@/config";
import { childrenType } from "../../types";
import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "@/plugins/i18n";
@@ -76,6 +77,10 @@ const getSpanStyle = computed(() => {
};
});
const expandCloseIcon = computed(() => {
return getConfig()?.MenuArrowIconNoTransition ? "expand-close-icon" : "";
});
const onlyOneChild: childrenType = ref(null);
// 存放菜单是否存在showTooltip属性标识
const hoverMenuMap = new WeakMap();
@@ -212,7 +217,15 @@ function resolvePath(routePath) {
</el-menu-item>
</template>
<el-sub-menu v-else ref="subMenu" :index="resolvePath(props.item.path)">
<el-sub-menu
v-else
ref="subMenu"
:index="resolvePath(props.item.path)"
v-bind:[expandCloseIcon]="useRenderIcon('ep-arrow-down')"
:expand-open-icon="useRenderIcon('ep-arrow-up')"
:collapse-close-icon="useRenderIcon('ep-arrow-right')"
:collapse-open-icon="useRenderIcon('ep-arrow-left')"
>
<template #title>
<div v-if="toRaw(props.item.meta.icon)" class="sub-menu-icon">
<component

View File

@@ -19,7 +19,7 @@ const showLogo = ref(
const { routers, device, pureApp, isCollapse, menuSelect, toggleSideBar } =
useNav();
let subMenuData = ref([]);
const subMenuData = ref([]);
const menuData = computed(() => {
return pureApp.layout === "mix" && device.value !== "mobile"

View File

@@ -42,7 +42,7 @@ const {
const tabDom = ref();
const containerDom = ref();
const scrollbarDom = ref();
let isShowArrow = ref(false);
const isShowArrow = ref(false);
const { isFullscreen, toggle } = useFullscreen();
const dynamicTagView = () => {
@@ -129,7 +129,7 @@ function dynamicRouteTag(value: string, parentPath: string): void {
function concatPath(arr: object[], value: string, parentPath: string) {
if (!hasValue) {
arr.forEach((arrItem: any) => {
let pathConcat = parentPath + arrItem.path;
const pathConcat = parentPath + arrItem.path;
if (arrItem.path === value || pathConcat === value) {
useMultiTagsStoreHook().handleTags("push", {
path: value,
@@ -160,7 +160,7 @@ function onFresh() {
function deleteDynamicTag(obj: any, current: any, tag?: string) {
// 存放被删除的缓存路由
let delAliveRouteList = [];
let valueIndex: number = multiTags.value.findIndex((item: any) => {
const valueIndex: number = multiTags.value.findIndex((item: any) => {
if (item.query) {
if (item.path === obj.path) {
return item.query === obj.query;
@@ -199,7 +199,7 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
// 从当前匹配到的路径中删除
spliceRoute(valueIndex, 1);
}
let newRoute = useMultiTagsStoreHook().handleTags("slice");
const newRoute = useMultiTagsStoreHook().handleTags("slice");
if (current === route.path) {
// 删除缓存路由
tag
@@ -339,8 +339,8 @@ function showMenuModel(
query: object = {},
refresh = false
) {
let allRoute = multiTags.value;
let routeLength = multiTags.value.length;
const allRoute = multiTags.value;
const routeLength = multiTags.value.length;
let currentIndex = -1;
if (isEmpty(query)) {
currentIndex = allRoute.findIndex(v => v.path === currentPath);

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import { ref, unref, onMounted, nextTick } from "vue";

View File

@@ -69,7 +69,7 @@ export function useDataThemeChange() {
return new TinyColor(color).shade(10).toString();
};
/** 设置ep主题色 */
/** 设置 `element-plus` 主题色 */
const setEpThemeColor = (color: string) => {
useEpThemeStoreHook().setEpThemeColor(color);
body.style.setProperty("--el-color-primary-active", shadeBgColor(color));

View File

@@ -1,4 +1,5 @@
import { computed } from "vue";
import { storeToRefs } from "pinia";
import { getConfig } from "@/config";
import { useRouter } from "vue-router";
import { emitter } from "@/utils/mitt";
@@ -10,12 +11,14 @@ import { useAppStoreHook } from "@/store/modules/app";
import { i18nChangeLanguage } from "@wangeditor/editor";
import { useUserStoreHook } from "@/store/modules/user";
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
import { usePermissionStoreHook } from "@/store/modules/permission";
const errorInfo = "当前路由配置不正确,请检查配置";
export function useNav() {
const pureApp = useAppStoreHook();
const routers = useRouter().options.routes;
const { wholeMenus } = storeToRefs(usePermissionStoreHook());
/** 用户名 */
const username = computed(() => {
@@ -99,6 +102,7 @@ export function useNav() {
}
function menuSelect(indexPath: string, routers): void {
if (wholeMenus.value.length === 0) return;
if (isRemaining(indexPath)) return;
let parentPath = "";
const parentPathIndex = indexPath.lastIndexOf("/");

View File

@@ -9,11 +9,11 @@ import {
getCurrentInstance
} from "vue";
import { tagsViewsType } from "../types";
import { isEqual } from "lodash-unified";
import type { StorageConfigs } from "/#/index";
import { useEventListener } from "@vueuse/core";
import { useRoute, useRouter } from "vue-router";
import { transformI18n, $t } from "@/plugins/i18n";
import { isEqual, isBoolean } from "@pureadmin/utils";
import { useSettingStoreHook } from "@/store/modules/settings";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { storageLocal, toggleClass, hasClass } from "@pureadmin/utils";
@@ -106,15 +106,14 @@ export function useTags() {
]);
function conditionHandle(item, previous, next) {
if (
Object.keys(route.query).length === 0 &&
Object.keys(route.params).length === 0
) {
return route.path === item.path ? previous : next;
} else if (Object.keys(route.query).length > 0) {
return isEqual(route.query, item.query) ? previous : next;
if (isBoolean(route?.meta?.showLink) && route?.meta?.showLink === false) {
if (Object.keys(route.query).length > 0) {
return isEqual(route.query, item.query) ? previous : next;
} else {
return isEqual(route.params, item.params) ? previous : next;
}
} else {
return isEqual(route.params, item.params) ? previous : next;
return route.path === item.path ? previous : next;
}
}

View File

@@ -70,7 +70,7 @@ let isAutoCloseSidebar = true;
// 监听容器
emitter.on("resize", ({ detail }) => {
if (isMobile) return;
let { width } = detail;
const { width } = detail;
width <= 760 ? setTheme("vertical") : setTheme(useAppStoreHook().layout);
/** width app-wrapper类容器宽度
* 0 < width <= 760 隐藏侧边栏

View File

@@ -20,7 +20,6 @@ const themeColors = {
menuHover: "#4091f7",
subMenuBg: "#0f0303",
subMenuActiveBg: "#4091f7",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#002140",
menuTitleHover: "#fff",
@@ -33,7 +32,6 @@ const themeColors = {
menuHover: "#e0ebf6",
subMenuBg: "#fff",
subMenuActiveBg: "#e0ebf6",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#fff",
menuTitleHover: "#000",
@@ -46,7 +44,6 @@ const themeColors = {
menuHover: "#e13c39",
subMenuBg: "#000",
subMenuActiveBg: "#e13c39",
navTextColor: "#red",
menuText: "rgb(254 254 254 / 65.1%)",
sidebarLogo: "#42090c",
menuTitleHover: "#fff",
@@ -59,7 +56,6 @@ const themeColors = {
menuHover: "#e85f33",
subMenuBg: "#0f0603",
subMenuActiveBg: "#e85f33",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#441708",
menuTitleHover: "#fff",
@@ -72,7 +68,6 @@ const themeColors = {
menuHover: "#f6da4d",
subMenuBg: "#0f0603",
subMenuActiveBg: "#f6da4d",
navTextColor: "#fff",
menuText: "rgb(254 254 254 / 65%)",
sidebarLogo: "#443b05",
menuTitleHover: "#fff",
@@ -85,7 +80,6 @@ const themeColors = {
menuHover: "#59bfc1",
subMenuBg: "#000",
subMenuActiveBg: "#59bfc1",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#053434",
menuTitleHover: "#fff",
@@ -98,7 +92,6 @@ const themeColors = {
menuHover: "#60ac80",
subMenuBg: "#000",
subMenuActiveBg: "#60ac80",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#112f21",
menuTitleHover: "#fff",
@@ -111,7 +104,6 @@ const themeColors = {
menuHover: "#d84493",
subMenuBg: "#000",
subMenuActiveBg: "#d84493",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#3f0d29",
menuTitleHover: "#fff",
@@ -124,7 +116,6 @@ const themeColors = {
menuHover: "#693ac9",
subMenuBg: "#000",
subMenuActiveBg: "#693ac9",
navTextColor: "#7a80b4",
menuText: "#7a80b4",
sidebarLogo: "#1f0c38",
menuTitleHover: "#fff",
@@ -147,7 +138,6 @@ export const genScssMultipleScopeVars = (): MultipleScopeVarsItem[] => {
$menuHover: ${themeColors[key].menuHover} !default;
$subMenuBg: ${themeColors[key].subMenuBg} !default;
$subMenuActiveBg: ${themeColors[key].subMenuActiveBg} !default;
$navTextColor: ${themeColors[key].navTextColor} !default;
$menuText: ${themeColors[key].menuText} !default;
$sidebarLogo: ${themeColors[key].sidebarLogo} !default;
$menuTitleHover: ${themeColors[key].menuTitleHover} !default;

View File

@@ -1,3 +1,4 @@
import "@/utils/sso";
import { getConfig } from "@/config";
import { toRouteType } from "./types";
import NProgress from "@/utils/progress";
@@ -33,6 +34,7 @@ import pptRouter from "./modules/ppt";
import homeRouter from "./modules/home";
import ableRouter from "./modules/able";
import listRouter from "./modules/list";
import tableRouter from "./modules/table";
import aboutRouter from "./modules/about";
import errorRouter from "./modules/error";
import guideRouter from "./modules/guide";
@@ -50,6 +52,7 @@ const routes = [
homeRouter,
ableRouter,
listRouter,
tableRouter,
aboutRouter,
errorRouter,
guideRouter,
@@ -134,6 +137,10 @@ router.beforeEach((to: toRouteType, _from, next) => {
else document.title = transformI18n(item.meta.title);
});
}
/** 如果已经登录并存在登录信息后不能跳转到路由白名单,而是继续保持在当前页面 */
function toCorrectRoute() {
whiteList.includes(to.fullPath) ? next(_from.fullPath) : next();
}
if (userInfo) {
// 无权限跳转403页面
if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
@@ -145,7 +152,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
openLink(to?.name as string);
NProgress.done();
} else {
next();
toCorrectRoute();
}
} else {
// 刷新
@@ -175,7 +182,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
}
router.push(to.fullPath);
});
next();
toCorrectRoute();
}
} else {
if (to.path !== "/login") {

View File

@@ -7,7 +7,7 @@ const ableRouter: RouteConfigsTable = {
meta: {
icon: "ubuntu-fill",
title: $t("menus.hsAble"),
rank: 4
rank: 5
},
children: [
{

View File

@@ -7,7 +7,7 @@ const componentsRouter: RouteConfigsTable = {
meta: {
icon: "menu",
title: $t("menus.hscomponents"),
rank: 5
rank: 6
},
children: [
{

View File

@@ -1,5 +1,6 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
const IFrame = () => import("@/layout/frameView.vue");
const formDesignRouter: RouteConfigsTable = {
path: "/formDesign",
@@ -13,9 +14,11 @@ const formDesignRouter: RouteConfigsTable = {
{
path: "/formDesign/index",
name: "FormDesign",
component: () => import("@/views/form-design/index.vue"),
component: IFrame,
meta: {
title: $t("menus.hsFormDesign")
title: $t("menus.hsFormDesign"),
frameSrc:
"https://haixin-fang.github.io/starfish-vue3-lowcode/playground/index.html#/"
}
}
]

View File

@@ -7,7 +7,7 @@ const nestedRouter: RouteConfigsTable = {
meta: {
title: $t("menus.hsmenus"),
icon: "histogram",
rank: 6
rank: 7
},
children: [
{

View File

@@ -17,11 +17,7 @@ const pptRouter: RouteConfigsTable = {
meta: {
title: "PPT",
frameSrc: "https://pipipi-pikachu.github.io/PPTist/",
frameLoading: false,
extraIcon: {
svg: true,
name: "team-iconxinpin"
}
frameLoading: false
}
}
]

View File

@@ -0,0 +1,27 @@
import type { RouteConfigsTable } from "/#/index";
const flowChartRouter: RouteConfigsTable = {
path: "/pure-table",
redirect: "/pure-table/index",
meta: {
icon: "mdi:table-large",
title: "pure-admin-table",
rank: 4
},
children: [
{
path: "/pure-table/index",
name: "PureTable",
component: () => import("@/views/pure-table/index.vue"),
meta: {
title: "pure-admin-table",
extraIcon: {
svg: true,
name: "team-iconxinpin"
}
}
}
]
};
export default flowChartRouter;

View File

@@ -76,7 +76,7 @@ function isOneOfArray(a: Array<string>, b: Array<string>) {
/** 从sessionStorage里取出当前登陆用户的角色roles过滤无权限的菜单 */
function filterNoPermissionTree(data: RouteComponent[]) {
const currentRoles =
storageSession.getItem<DataInfo<number>>(sessionKey).roles ?? [];
storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
const newTree = cloneDeep(data).filter((v: any) =>
isOneOfArray(v.meta?.roles, currentRoles)
);

View File

@@ -1,6 +1,6 @@
import { defineStore } from "pinia";
import { store } from "@/store";
import { isEqual } from "lodash-unified";
import { isEqual } from "@pureadmin/utils";
import type { StorageConfigs } from "/#/index";
import { routerArrays } from "@/layout/types";
import { multiType, positionType } from "./types";
@@ -11,11 +11,11 @@ export const useMultiTagsStore = defineStore({
state: () => ({
// 存储标签页信息(路由信息)
multiTags: storageLocal.getItem<StorageConfigs>("responsive-configure")
.multiTagsCache
?.multiTagsCache
? storageLocal.getItem<StorageConfigs>("responsive-tags")
: [...routerArrays],
multiTagsCache: storageLocal.getItem<StorageConfigs>("responsive-configure")
.multiTagsCache
?.multiTagsCache
}),
getters: {
getMultiTagsCache() {

View File

@@ -59,9 +59,9 @@ export const useUserStore = defineStore({
this.username = "";
this.roles = [];
removeToken();
router.push("/login");
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
resetRouter();
router.push("/login");
},
/** 刷新`token` */
async handRefreshToken(data) {

View File

@@ -129,7 +129,7 @@ html.dark {
color: var(--el-text-color-primary);
}
.vxe-button.type--button.size--medium:hover {
.vxe-button.type--button:hover {
background: var(--el-color-primary) !important;
}
@@ -170,6 +170,12 @@ html.dark {
}
}
/* intro.js */
.introjs-tooltip-title,
.introjs-tooltiptext {
color: var(--el-color-primary);
}
/* element-plus */
.el-table__cell {
background: var(--el-bg-color);

View File

@@ -20,7 +20,8 @@
filter: invert(80%);
}
/* 重置 vxe-table 中 pager 样式 */
/* 重置 vxe-table 样式 */
.vxe-button.type--button.theme--primary:hover,
.vxe-pager .vxe-pager--num-btn:not(.is--disabled).is--active {
color: #fff !important;
}

View File

@@ -44,16 +44,6 @@ abbr:where([title]) {
text-decoration: underline dotted;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
text-decoration: inherit;

View File

@@ -68,10 +68,6 @@
}
}
.el-popper.is-light {
border: none !important;
}
.sidebar-container {
/* 展开动画 */
transition: width var(--pure-transition-duration);
@@ -233,11 +229,9 @@
.search-container,
/* 告警 */
.dropdown-badge,
/* 全屏 */
.screen-full,
/* 国际化 */
.globalization,
/* 登录 */
/* 用户 */
.el-dropdown-link,
/* 设置 */
.set-icon {
@@ -587,11 +581,9 @@ body[layout="vertical"] {
.search-container,
/* 告警 */
.dropdown-badge,
/* 全屏 */
.screen-full,
/* 国际化 */
.globalization,
/* 登录 */
/* 用户 */
.el-dropdown-link,
/* 设置 */
.set-icon {

View File

@@ -40,16 +40,3 @@
.breadcrumb-leave-active {
position: absolute;
}
/**
* @description 重置el-menu的展开收起动画时长
* @see {@link https://github.com/element-plus/element-plus/issues/4509#issuecomment-980165001}
*/
.outer-most .el-collapse-transition-leave-active,
.outer-most .el-collapse-transition-enter-active {
transition: 0.12s all ease-in-out !important;
}
.horizontal-collapse-transition {
transition: var(--pure-transition-duration) all !important;
}

View File

@@ -1,5 +1,5 @@
### 注意
- `vue-pure-admin``3.3.0` 版本之后(不包括 `3.3.0` 版本),大部分工具和 `hooks` 都集成到了[@pureadmin/utils](https://xiaoxian521.github.io/pure-admin-utils-docs/)
- `vue-pure-admin``3.3.0` 版本之后(不包括 `3.3.0` 版本),大部分工具和 `hooks` 都集成到了 [@pureadmin/utils](https://pure-admin-utils.netlify.app/)
- [npm](https://www.npmjs.com/package/@pureadmin/utils)
- [文档代码地址](https://github.com/xiaoxian521/pure-admin-utils-docs)

View File

@@ -35,7 +35,7 @@ export function getToken(): DataInfo<number> {
export function setToken(data: DataInfo<Date>) {
let expires = 0;
const { accessToken, refreshToken } = data;
expires = new Date(data.expires).getTime();
expires = new Date(data.expires).getTime(); // 如果后端直接设置时间戳将此处代码改为expires = data.expires然后把上面的DataInfo<Date>改成DataInfo<number>即可
const cookieString = JSON.stringify({ accessToken, expires });
expires > 0
@@ -59,8 +59,10 @@ export function setToken(data: DataInfo<Date>) {
const { username, roles } = data;
setSessionKey(username, roles);
} else {
const { username, roles } =
storageSession.getItem<DataInfo<number>>(sessionKey);
const username =
storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "";
const roles =
storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
setSessionKey(username, roles);
}
}

View File

@@ -0,0 +1,7 @@
// 如果项目出现 `global is not defined` 报错,可能是您引入某个库的问题,比如 aws-sdk-js https://github.com/aws/aws-sdk-js
// 解决办法就是将该文件引入 src/main.ts 即可 import "@/utils/globalPolyfills";
if (typeof (window as any).global === "undefined") {
(window as any).global = window;
}
export {};

View File

@@ -1,25 +0,0 @@
## 用法
### Get 请求
```
import { http } from "@/utils/http";
// params传参
http.request('get', '/xxx', { params: param });
// url拼接传参
http.request('get', '/xxx?message=' + msg);
```
### Post 请求
```
import { http } from "@/utils/http";
// params传参
http.request('post', '/xxx', { params: param });
// data传参
http.request('post', '/xxx', { data: param });
```

View File

@@ -11,21 +11,12 @@ import {
} from "./types.d";
import { stringify } from "qs";
import NProgress from "../progress";
// import { loadEnv } from "@build/index";
import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user";
// 加载环境变量 VITE_PROXY_DOMAIN开发环境 VITE_PROXY_DOMAIN_REAL打包后的线上环境
// const { VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL } = loadEnv();
// 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
// baseURL:
// process.env.NODE_ENV === "production"
// ? VITE_PROXY_DOMAIN_REAL
// : VITE_PROXY_DOMAIN,
// 当前使用mock模拟请求将baseURL制空如果你的环境用到了http请求请删除下面的baseURL启用上面的baseURL并将第14行、19行代码注释取消
baseURL: "",
// 请求超时时间
timeout: 10000,
headers: {
Accept: "application/json, text/plain, */*",

59
src/utils/sso.ts Normal file
View File

@@ -0,0 +1,59 @@
import { removeToken, setToken, type DataInfo } from "./auth";
import { subBefore, getQueryMap } from "@pureadmin/utils";
/**
* 简版前端单点登录,根据实际业务自行编写,平台启动后本地可以跳后面这个链接进行测试 http://localhost:8848/#/permission/page/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
* 划重点:
* 判断是否为单点登录,不为则直接返回不再进行任何逻辑处理,下面是单点登录后的逻辑处理
* 1.清空本地旧信息;
* 2.获取url中的重要参数信息然后通过 setToken 保存在本地;
* 3.删除不需要显示在 url 的参数
* 4.使用 window.location.replace 跳转正确页面
*/
(function () {
// 获取 url 中的参数
const params = getQueryMap(location.href) as DataInfo<Date>;
const must = ["username", "roles", "accessToken"];
const mustLength = must.length;
if (Object.keys(params).length !== mustLength) return;
// url 参数满足 must 里的全部值,才判定为单点登录,避免非单点登录时刷新页面无限循环
let sso = [];
let start = 0;
while (start < mustLength) {
if (Object.keys(params).includes(must[start]) && sso.length <= mustLength) {
sso.push(must[start]);
} else {
sso = [];
}
start++;
}
if (sso.length === mustLength) {
// 判定为单点登录
// 清空本地旧信息
removeToken();
// 保存新信息到本地
setToken(params);
// 删除不需要显示在 url 的参数
delete params["roles"];
delete params["accessToken"];
const newUrl = `${location.origin}${location.pathname}${subBefore(
location.hash,
"?"
)}?${JSON.stringify(params)
.replace(/["{}]/g, "")
.replace(/:/g, "=")
.replace(/,/g, "&")}`;
// 替换历史记录项
window.location.replace(newUrl);
} else {
return;
}
})();

View File

@@ -11,12 +11,12 @@ defineOptions({
name: "Download"
});
let base64 =
const base64 =
"data:image/png;base64,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";
function down() {
axios
.get("https://xiaoxian521.github.io/pure-admin-utils-docs/logo.png", {
.get("https://xiaoxian521.github.io/pure-admin-doc/img/pure.png", {
responseType: "blob"
})
.then(({ data }) => {
@@ -34,7 +34,7 @@ function down() {
<el-button
@click="
downloadByOnlineUrl(
'https://xiaoxian521.github.io/pure-admin-utils-docs/logo.png',
'https://xiaoxian521.github.io/pure-admin-doc/img/pure.png',
'test-url.png'
)
"

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script setup lang="ts">
import { utils, writeFile } from "xlsx";
defineOptions({

View File

@@ -6,7 +6,7 @@ defineOptions({
name: "IconSelect"
});
let icon = ref("ep:add-location");
const icon = ref("ep:add-location");
</script>
<template>

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup>
<script setup lang="ts">
import { ref } from "vue";
import { default as vElTableInfiniteScroll } from "el-table-infinite-scroll";

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed } from "vue";
import { cloneDeep } from "lodash-unified";
import { clone } from "@pureadmin/utils";
import { transformI18n } from "@/plugins/i18n";
import ElTreeLine from "@/components/ReTreeLine";
import { extractPathList, deleteChildren } from "@pureadmin/utils";
@@ -10,12 +10,12 @@ defineOptions({
name: "LineTree"
});
let menusTree = cloneDeep(usePermissionStoreHook().wholeMenus);
let menusData = computed(() => {
const menusTree = clone(usePermissionStoreHook().wholeMenus, true);
const menusData = computed(() => {
return deleteChildren(menusTree);
});
let expandedKeys = extractPathList(menusData.value);
let dataProps = {
const expandedKeys = extractPathList(menusData.value);
const dataProps = {
value: "uniqueId",
children: "children"
};

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { cloneDeep } from "lodash-unified";
import { clone } from "@pureadmin/utils";
import type { ElTreeV2 } from "element-plus";
import { transformI18n } from "@/plugins/i18n";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
@@ -19,18 +19,18 @@ interface treeNode extends TreeNode {
}
const query = ref("");
let dataProps = ref({
const dataProps = ref({
value: "uniqueId",
children: "children"
});
const treeRef = ref<InstanceType<typeof ElTreeV2>>();
let menusTree = cloneDeep(usePermissionStoreHook().wholeMenus);
const menusTree = clone(usePermissionStoreHook().wholeMenus, true);
let menusData = computed(() => {
const menusData = computed(() => {
return deleteChildren(menusTree);
});
let expandedKeys = extractPathList(menusData.value);
const expandedKeys = extractPathList(menusData.value);
const onQueryChanged = (query: string) => {
(treeRef as any).value!.filter(query);

View File

@@ -1,24 +1,19 @@
<script setup lang="ts">
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import VuePdfEmbed, {
type VuePdfEmbedMethods,
type VuePdfEmbedData
} from "vue-pdf-embed";
import VuePdfEmbed from "vue-pdf-embed";
defineOptions({
name: "Pdf"
});
interface pdfRefType extends VuePdfEmbedData, VuePdfEmbedMethods {}
const { t } = useI18n();
const pdfRef = ref<pdfRefType>();
let pageCount = ref(1);
let loading = ref(true);
let currentPage = ref(1);
let currentRotation = ref(0);
let showAllPages = ref(false);
const pdfRef = ref<any>();
const pageCount = ref(1);
const loading = ref(true);
const currentPage = ref(1);
const currentRotation = ref(0);
const showAllPages = ref(false);
const rotations = [0, 90, 180, 270];
const source =

View File

@@ -77,7 +77,7 @@ const options = [
];
function onPrint() {
let el = options.filter(v => v.value === value.value)[0]?.el;
const el = options.filter(v => v.value === value.value)[0]?.el;
Print(el).toPrint;
}

View File

@@ -2,7 +2,6 @@
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
import type { SwiperOptions } from "swiper";
import { Swiper, SwiperSlide } from "swiper/vue";
import SwiperCore, { Autoplay, Navigation, Pagination } from "swiper";
@@ -10,27 +9,9 @@ defineOptions({
name: "Swiper"
});
type SwiperExampleOptions = Pick<
SwiperOptions,
| "navigation"
| "pagination"
| "scrollbar"
| "slidesPerView"
| "slidesPerGroup"
| "spaceBetween"
| "direction"
| "loop"
| "loopFillGroupWithBlank"
| "autoplay"
>;
interface SwiperExample {
id: number;
label: string;
options: Partial<SwiperExampleOptions>;
}
SwiperCore.use([Autoplay, Navigation, Pagination]);
const swiperExample: SwiperExample[] = [
const swiperExample: any[] = [
{ id: 0, label: "Default", options: {} },
{
id: 1,
@@ -119,7 +100,7 @@ const swiperExample: SwiperExample[] = [
</template>
<el-row :gutter="10">
<el-col v-for="item in swiperExample" :key="item.id" :span="12">
<h3 class="py-[24px] text-[24px] font-bold">{{ item.label }}</h3>
<h6 class="py-[24px] text-[24px] font-bold">{{ item.label }}</h6>
<swiper v-bind="item.options">
<swiper-slide v-for="i in 5" :key="i">
<div

View File

@@ -1,21 +1,43 @@
<script setup lang="ts">
import { ref } from "vue";
import { ref, onMounted, nextTick, onBeforeUnmount } from "vue";
import { useWatermark } from "@pureadmin/utils";
defineOptions({
name: "WaterMark"
});
let color = ref("#409EFF");
let value = ref("vue-pure-admin");
const local = ref();
const preventLocal = ref();
const color = ref("#409EFF");
const value = ref("vue-pure-admin");
const { setWatermark, clear } = useWatermark();
const { setWatermark: setLocalWatermark, clear: clearLocal } =
useWatermark(local);
const { setWatermark: setPreventLocalWatermark } = useWatermark(preventLocal);
onMounted(() => {
nextTick(() => {
setPreventLocalWatermark("无法删除的水印", {
forever: true,
width: 187,
height: 80
});
});
});
onBeforeUnmount(() => {
// 在离开该页面时清除整页水印
clear();
});
</script>
<template>
<el-card>
<template #header>
<div class="card-header">
<span class="font-medium">页面水印功能</span>
<span class="font-medium">
页面水印功能将平台主题改为亮白色观察水印效果更明显哦
</span>
</div>
</template>
<span> 请输入要创建水印的值</span>
@@ -29,10 +51,132 @@ const { setWatermark, clear } = useWatermark();
<el-color-picker v-model="color" show-alpha />
<br />
<el-button @click="setWatermark(value, { fillStyle: color })">
创建
创建整页水印
</el-button>
<el-button @click="clear">清除</el-button>
<el-button
@click="
setWatermark(value, {
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
]
})
"
>
创建整页渐变水印
</el-button>
<el-button
@click="
setWatermark(value, {
rotate: 0,
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
]
})
"
>
创建整页渐变且水平90度的水印
</el-button>
<el-button
@click="
setWatermark(value, {
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
],
shadowConfig: [20]
})
"
>
创建整页渐变且有阴影的水印
</el-button>
<el-button
@click="
setWatermark(value, {
globalAlpha: 0.15, // 值越低越透明
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
]
})
"
>
创建整页高透明渐变水印
</el-button>
<el-button @click="clear">清除整页水印</el-button>
<div
ref="local"
class="mt-4 mb-4 w-[1080px] h-[400px] border-dotted border-2 border-sky-500"
/>
<el-button
@click="
setLocalWatermark('局部水印', {
fillStyle: color,
width: 140,
height: 60
})
"
>
创建局部水印
</el-button>
<el-button
@click="
setLocalWatermark('局部水印', {
width: 140,
height: 60,
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
]
})
"
>
创建局部渐变水印
</el-button>
<el-button
@click="
setLocalWatermark('局部水印', {
width: 140,
height: 56.5,
rotate: 0,
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
]
})
"
>
创建局部渐变且水平90度的水印
</el-button>
<el-button
@click="
setLocalWatermark('局部水印', {
width: 140,
height: 56.5,
gradient: [
{ value: 0, color: 'magenta' },
{ value: 0.5, color: 'blue' },
{ value: 1.0, color: 'red' }
],
shadowConfig: [20]
})
"
>
创建局部渐变且有阴影的水印
</el-button>
<el-button @click="clearLocal">清除局部水印</el-button>
<div
ref="preventLocal"
class="mt-4 mb-4 w-[1080px] h-[400px] border-dotted border-2 border-indigo-500"
/>
</el-card>
</template>
<style scoped></style>

View File

@@ -18,7 +18,10 @@ export function useColumns() {
label: "文档地址",
cellRenderer: () => {
return (
<a href="http://yiming_chang.gitee.io/pure-admin-doc" target="_blank">
<a
href="https://yiming_chang.gitee.io/pure-admin-doc"
target="_blank"
>
<span style="color: var(--el-color-primary)"></span>
</a>
);
@@ -28,7 +31,10 @@ export function useColumns() {
label: "预览地址",
cellRenderer: () => {
return (
<a href="http://yiming_chang.gitee.io/vue-pure-admin" target="_blank">
<a
href="https://yiming_chang.gitee.io/vue-pure-admin"
target="_blank"
>
<span style="color: var(--el-color-primary)"></span>
</a>
);

View File

@@ -7,14 +7,14 @@ defineOptions({
name: "Cropping"
});
let refCropper = ref();
let info = ref<object>(null);
let cropperImg = ref<string>("");
const refCropper = ref();
const info = ref<object>(null);
const cropperImg = ref<string>("");
const onCropper = (): void => {
nextTick(() => {
refCropper.value.cropper.getCroppedCanvas().toBlob(blob => {
let fileReader: FileReader = new FileReader();
const fileReader: FileReader = new FileReader();
fileReader.onloadend = (e: ProgressEvent) => {
cropperImg.value = (e.target as any).result;
info.value = refCropper.value.cropper.getData();

View File

@@ -19,432 +19,7 @@ const customDanmus = [
}
];
// 弹幕来自b站首页
const danmus = [
"草",
"高技术力",
"汤姆逊波纹疾走…啊哒哒哒哒哒哒……",
"此曲一出,非死即伤",
"这播放量不应该啊",
"牛皮!",
"全 文 背 诵",
"ohhhhhhh",
"NICE",
"草这死亡姿势",
"日常迫害团长",
"溜了溜了",
"火钳刘明",
"真实",
"汤姆逊波纹疾走",
"不 要 停 下 来 啊",
"泥 给 路 打 油",
"停下来了",
"草",
"完全一致",
"你怎么还没有被禁赛",
"6P41波纹疾走!!!",
"牛逼",
"草",
"草",
"cccccccc",
"人才不火系列",
"双厨狂喜",
"双厨曝炸",
"火钳留名",
"火钳留名",
"牛逼啊",
"草",
"草",
"要素过多",
"火钳刘明",
"高技术力suki",
"bo良ki影觉得很赞",
"你们的下一句话是名场面",
"Niiice",
"太草了",
"哈哈哈哈",
"火钳刘明",
"6p41疾走",
"袭击妈妈",
"占戈哥欠走己",
"又看jojo又玩r6的人恐怕太少了吧",
"好活当赏",
"要素过多",
"动作也太流畅了吧",
"世界名画",
"好活,当赏",
"全程高能",
"新人都是怪物.jpg",
"我的人质啊",
"袭击妈妈锁孔看她",
"完全不会画画(大嘘)",
"好活",
"爆头 2333333",
"把队友杀了的屑",
"动作指导:奥尔加",
"草",
"要素过多",
"噗",
"让你玩手机",
"6啊",
"我负责救人质",
"三厨狂喜",
"三厨狂喜",
"万能日语",
"耶———————格——————————",
"6P41波纹疾走",
"“哦”踩点还行",
"火钳刘明。",
"哎地唉洗",
"这枪不是m249啊等等叫什么来的",
"火钳刘明",
"光棍节, 。去过",
"炸死队友哈哈哈",
"火钳刘明",
"火钳刘明",
"cao",
"火钳刘明",
"提前Niiiiiiiice",
"火钳刘明",
"神仙UP",
"又被爆头了",
"6p41疾走",
"好活",
"人质好好笑啊",
"不要停下来啊",
"好活啊!!",
"6P41波纹疾走 换成AK是不是更爽",
"恭喜你发现宝藏",
"恭喜你发现宝藏",
"恭喜你发现宝藏",
"前方高能",
"封禁30分钟",
"火钳刘明",
"该赏",
"我靠,就冲着高帧数,投币了",
"不 要 停 下 来 啊(指你给路)",
"卧槽 无情",
"草",
"ADS草",
"世界线收束",
"火钳刘明",
"人质:给我把抢我跟他拼了",
"小车灵魂",
"卧槽这帧数",
"jojoの奇妙转场",
"niiiiiiice",
"好活",
"要素过多",
"6p41",
"TK*3移除对战",
"这场景布置有弹丸那味儿了",
"草",
"草",
"不要让战斗停下来",
"火钳留名",
"炸死俩盾哈哈",
"太草了,",
"万能日语",
"伪渲染(确信)",
"要素过多",
"火钳刘明",
"卧槽",
"炸死队友",
"危",
"这才是真正的高技术力",
"高技术力suki",
"火钳刘明",
"欺负我不懂日语系列",
"我打我自己",
"帧数爆炸",
"危",
"危",
"要素过多",
"巨真实这小车",
"牛逼",
"帧数高的吓人",
"5v5→3v3",
"我都是俄式救援",
"niiiiiiiiiiiice",
"别啊!",
"尼给路嗒呦",
"目测会火",
"双厨狂喜",
"人质已解救(脱)",
"哈哈哈哈哈",
"要素过多",
"nb",
"杀了两个队友不就被踢出去了吗",
"这是新人?",
"没毛病",
"一甲fuze",
"要素过多",
"大————头————",
"人————质————",
"这是组长吗?",
"不是M249是PKP",
"卡其脱离太",
"等等JOJO是你",
"我就是又看JOJO又玩r6",
"二乔??????",
"这也太流畅了吧",
"这tm能出番了这帧数和技术",
"kpm波纹疾走",
"大制作",
"太草了",
"耶——格——",
"高技术力",
"精神小车",
"左轮庸医",
"袭击人质,锁孔看他",
"奈~~斯 屑队友被杀✓",
"惨 盾兵 惨",
"打敌人误伤不算",
"不要停下来啊! (指解救人质)",
"嘴巴被贴胶还能说话的人质是鉴",
"哈哈哈哈哈哈哈哈哈",
"一局11杀",
"二乔同款姿势 哈哈",
"耶格!",
"看",
"鉴作无误",
"双出狂喜",
"为什么不是中文",
"经典咚咚咚………三声雷,带你飞",
"要素过多",
"jojo",
"三厨狂喜",
"我也是又看又玩",
"我都听到lisalisa了doge",
"你给路打油",
"确实质量很高啊",
"NICE",
"银魂?",
"火钳刘明",
"我就是又看jojo又玩R61631小时你有什么事吗",
"哟西哟西",
"要素过多",
"我也是看JOJO玩r6",
"nokk",
"800小时r6加二刷jojo在此",
"好活",
"jojo",
"fuze the hostage",
"不要停下来!!!!!",
"pkppkp波纹疾走",
"新人都是怪物吗?",
"23333333",
"我先来,首页通知书",
"咚咚咚放这里。。。",
"火钳刘明",
"火钳刘明",
"火钳刘明",
"队友都炸",
"nice",
"哈哈哈哈",
"人质:危!",
"危",
"火钳刘明",
"人质 卒",
"你币有了",
"打投组",
"恭喜首頁通知書!",
"要素溢出",
"HOSTAGE KIA",
"233",
"是无托版的PKP",
"666",
"hostage KIA",
"tk哈哈哈",
"要素过多",
"这个肌肉我可以惹",
"6的飞起",
"jo风",
"混入了奇怪的东西",
"草",
"袭击妈妈,锁孔看她",
"哈哈哈哈哈哈",
"",
"草",
"牛逼",
"高技术力啊",
"opp",
"X",
"组长!",
"草(中日双语)",
"哈哈哈哈哈哈",
"-500",
".",
"看封面识内容系列",
"草",
"首页通知书",
"要素过多",
"但是不会画画",
"草",
"不要停下来啊!",
"梅开三度",
"四回啊四回",
"高帧好评",
"人质已解脱",
"草",
"强",
"好活!",
"好流畅",
"草",
"666",
"好活儿当赏",
"新人都是怪物系列",
"高技术力",
"niiiiiiiiiiiiiiice",
"人质危",
"哈哈哈哈",
"带制作,三连了",
"鉴作",
"咚咚咚",
"咚咚咚咚棒棒棒棒",
"要素过多",
"不应该是打中耳机吗",
"高技术力",
"完了",
"彩虹六号牛批",
"口罩都有荒木线,佛了",
"哈哈哈",
"要素爆炸",
"高技术力",
"cao caocaocaocao",
"哈哈哈哈哈哈哈",
"等等2乔这里说的是30分钟",
"首页通知书",
"海 岸 线",
"pkp波纹疾走",
"耶————————格————————",
"人 质 凶 手 -500",
"队友WDNMD",
"jojo",
"点进来之前我以为是fuze饮料。。",
"要素过多",
"绝了",
"要素过多",
"灭 霸",
"新人都是魔鬼",
"帧数爆炸",
"Cluster Charge activated",
"要素过多",
"Hostage KIAMission failed",
"人质已解脱。。。",
"开 幕 雷 击",
"哈哈哈哈",
"ADS草死了",
"+0",
"牛批牛批",
"拜见大神",
"阿虚",
"这帧数,感觉在看动漫",
"卡其脱离太",
"双厨狂喜",
"问问",
"不要停下来啊!!!!!",
"h",
"不要停下来啊",
"要真30分钟都不用结束回合了都开始第二局游戏了",
"这也太强了",
"。。。。。。。。。。。。",
"hoho",
"要素过多",
"哈哈哈哈哈哈哈哈哈哈哈哈哈哈",
"哈哈哈哈哈哈哈哈哈哈",
".00",
"哈哈",
"万能的日语",
"首页通知书",
"我卡了?",
"hhhhh",
"大盾闪盾好惨",
"哈哈哈哈哈哈哈哈哈",
"草",
"要素太多受不了哈哈哈哈哈哈哈",
"火钳刘明",
"首页通知书",
"lisalisa",
"这是什么蛇皮操作,看不懂",
"敌 我 不 分",
"草",
"666",
"哈哈哈哈啊哈哈哈",
"完全一致",
"要素过多",
"你又双叒叕发现了新的宝藏",
"火钳刘明",
"2333",
"高 技 术 力",
"三梗合一",
"四梗合一",
"火钳刘明",
"杀2个队友不是直接飞了吗",
"首页通知书",
"海岸线",
"是延迟",
"好活当赏",
"这个我遇到过fuze就是我人质敌人队友都被我杀掉了被老外骂并被踢了",
"草素过多",
"人质—— 再不能起",
"必须三联",
"开始吟唱",
"不要停下来啊",
"草",
"",
"tab+shift",
"帧数高的和动画一样",
"wwwwwwwwwwww",
"好强",
"23333333",
"好活当赏",
"此曲一出",
"要素过载",
"火钳刘明",
"要素过载",
"好活!!!!",
"开始吟唱",
"我听得懂咋办,在线等,很急",
"哇哇哇好高清",
".",
"医 学 奇 迹",
"jo里jo气的",
"jojo画风",
"哈哈哈哈哈哈",
"俄式反恐",
"别拦我老子把3个ADS都丢他脸上",
"-500",
"万 能 日 语",
"666",
"人质杀手",
"做的真的棒。",
"我NM笑疯",
"双厨狂喜",
"玛撒卡!这是袭击妈妈配音?",
"nice",
"jojo!",
"JO小鬼来力",
"真实",
"我又玩R6又看JOJO",
"完 全 不 会 画 画",
"秀儿",
"是系统自动踢人的,老外来不及踢你",
"6p41波纹疾走",
"火钳刘明",
"lisalisa",
"盾——兵——(悲)",
"就是没有汤姆逊,汤姆逊波纹疾走!!",
"要素过多",
"。。。。??",
"组长你怎么了组长",
"UP:我 完 全 不 会 画 画",
"再来亿遍",
"泥给路带呦~",
"哈哈哈哈哈哈哈哈哈",
"哈哈哈哈哈哈哈哈哈",
"火钳刘明"
];
const danmus = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
const getDanmuData = () => {
return danmus.map((text, index) => {

View File

@@ -8,7 +8,7 @@ defineOptions({
name: "Draggable"
});
let gridLists = ref<Array<Object>>([
const gridLists = ref<Array<Object>>([
{ grid: "cn", num: 1 },
{ grid: "cn", num: 2 },
{ grid: "cn", num: 3 },
@@ -20,14 +20,14 @@ let gridLists = ref<Array<Object>>([
{ grid: "cn", num: 9 }
]);
let lists = ref<Array<Object>>([
const lists = ref<Array<Object>>([
{ people: "cn", id: 1, name: "www.itxst.com" },
{ people: "cn", id: 2, name: "www.baidu.com" },
{ people: "cn", id: 3, name: "www.taobao.com" },
{ people: "cn", id: 4, name: "www.google.com" }
]);
let cutLists = ref([
const cutLists = ref([
{ people: "cn", id: 1, name: "cut1" },
{ people: "cn", id: 2, name: "cut2" },
{ people: "cn", id: 3, name: "cut3" },

View File

@@ -1,15 +1,14 @@
<script setup lang="ts">
import { ref, reactive, unref } from "vue";
import { templateRef } from "@vueuse/core";
import SeamlessScroll from "@/components/ReSeamlessScroll";
defineOptions({
name: "SeamlessScroll"
});
const scroll = templateRef<ElRef | null>("scroll", null);
const scroll = ref();
let listData = ref([
const listData = ref([
{
title: "无缝滚动第一行无缝滚动第一行!!!!!!!!!!"
},
@@ -39,7 +38,7 @@ let listData = ref([
}
]);
let classOption = reactive({
const classOption = reactive({
direction: "top"
});

View File

@@ -6,8 +6,8 @@ defineOptions({
name: "Selector"
});
let selectRange = ref<string>("");
let dataLists = ref([
const selectRange = ref<string>("");
const dataLists = ref([
{
title: "基本使用",
echo: [],
@@ -39,7 +39,7 @@ const selectedVal = ({ left, right }): void => {
@selectedVal="selectedVal"
:disabled="item.disabled"
/>
<h4 v-if="!item.disabled">选中范围{{ selectRange }}</h4>
<h4 class="mt-3" v-if="!item.disabled">选中范围{{ selectRange }}</h4>
</el-card>
</div>
</template>

View File

@@ -15,10 +15,10 @@ defineOptions({
name: "FlowChart"
});
let lf = ref(null);
let graphData = ref(null);
let dataVisible = ref<boolean>(false);
let config = ref({
const lf = ref(null);
const graphData = ref(null);
const dataVisible = ref<boolean>(false);
const config = ref({
grid: true,
background: {
color: "#f7f9ff"
@@ -27,7 +27,7 @@ let config = ref({
enabled: true
}
});
let nodeList = BpmnNode;
const nodeList = BpmnNode;
function initLf() {
// 画布配置
@@ -94,7 +94,7 @@ onMounted(() => {
<div id="LF-Turbo" />
<!-- 数据查看面板 -->
<el-dialog
customClass="flow-dialog"
class="flow-dialog"
title="数据"
v-model="dataVisible"
width="50%"

View File

@@ -1,30 +0,0 @@
<script setup lang="ts">
import { ref, onBeforeMount } from "vue";
import { useLoader } from "@pureadmin/utils";
import { ElDesignForm } from "vue-form-create2";
defineOptions({
name: "FormDesign"
});
const loading = ref(true);
const { loadScript } = useLoader();
onBeforeMount(() => {
loadScript({
src: "https://unpkg.com/ace-builds/src-noconflict/ace.js"
}).then(message => {
if (message === "success") loading.value = false;
});
});
</script>
<template>
<ElDesignForm v-loading="loading" style="height: 100vh" class="design-form" />
</template>
<style lang="scss" scoped>
.main-content {
margin: 0 !important;
}
</style>

View File

@@ -1,62 +1,42 @@
<script setup lang="ts">
import Driver from "driver.js";
import "driver.js/dist/driver.min.css";
import intro from "intro.js";
import "intro.js/minified/introjs.min.css";
defineOptions({
name: "Guide"
});
const steps = [
{
element: "#header-notice",
popover: {
title: "消息通知",
description: "你可以在这里查看管理员发送的消息",
position: "left"
}
},
{
element: "#header-translation",
popover: {
title: "国际化",
description: "你可以在这里进行语言切换",
position: "left"
}
},
{
element: ".set-icon",
popover: {
title: "项目配置",
description: "你可以在这里查看项目配置",
position: "left"
}
},
{
element: ".tags-view",
popover: {
title: "多标签页",
description: "这里是你访问过的页面的历史",
position: "buttom"
}
}
];
const driver = new Driver({
className: "scoped-class",
animate: true,
opacity: 0.75,
padding: 0,
allowClose: true,
overlayClickNext: false,
doneBtnText: "完成",
closeBtnText: "关闭",
nextBtnText: "下一步",
prevBtnText: "上一步"
});
const guide = () => {
driver.defineSteps(steps);
driver.start();
intro()
.setOptions({
steps: [
{
element: document.querySelector("#header-notice"),
title: "消息通知",
intro: "您可以在这里查看管理员发送的消息",
position: "left"
},
{
element: document.querySelector("#header-translation"),
title: "国际化",
intro: "您可以在这里进行语言切换",
position: "left"
},
{
element: document.querySelector(".set-icon"),
title: "项目配置",
intro: "您可以在这里查看项目配置",
position: "left"
},
{
element: document.querySelector(".tags-view"),
title: "多标签页",
intro: "这里是您访问过的页面的历史",
position: "bottom"
}
]
})
.start();
};
</script>
@@ -69,20 +49,8 @@ const guide = () => {
</span>
</div>
</template>
<el-button
type="primary"
style="margin-top: 10px"
@click.prevent.stop="guide"
>
<el-button type="primary" class="mt-[10px]" @click="guide">
打开引导页
</el-button>
</el-card>
</template>
<style>
div#driver-highlighted-element-stage,
div#driver-page-overlay {
background: transparent !important;
outline: 5000px solid rgba(0, 0, 0, 0.75);
}
</style>

View File

@@ -63,11 +63,7 @@ const cardLogoClass = computed(() => [
>
{{ product.isSetup ? "已启用" : "已停用" }}
</el-tag>
<el-dropdown
trigger="click"
:disabled="!product.isSetup"
max-height="2"
>
<el-dropdown trigger="click" :disabled="!product.isSetup">
<IconifyIconOffline icon="more-vertical" class="text-[24px]" />
<template #dropdown>
<el-dropdown-menu :disabled="!product.isSetup">

View File

@@ -62,9 +62,7 @@ function onBack() {
clearable
v-model="ruleForm.verifyCode"
:placeholder="t('login.smsVerifyCode')"
:prefix-icon="
useRenderIcon('ri:shield-keyhole-line', { online: true })
"
:prefix-icon="useRenderIcon('ri:shield-keyhole-line')"
/>
<el-button
:disabled="isDisabled"

View File

@@ -110,9 +110,7 @@ function onBack() {
clearable
v-model="ruleForm.verifyCode"
:placeholder="t('login.smsVerifyCode')"
:prefix-icon="
useRenderIcon('ri:shield-keyhole-line', { online: true })
"
:prefix-icon="useRenderIcon('ri:shield-keyhole-line')"
/>
<el-button
:disabled="isDisabled"

View File

@@ -83,9 +83,7 @@ function onBack() {
clearable
v-model="ruleForm.verifyCode"
:placeholder="t('login.smsVerifyCode')"
:prefix-icon="
useRenderIcon('ri:shield-keyhole-line', { online: true })
"
:prefix-icon="useRenderIcon('ri:shield-keyhole-line')"
/>
<el-button
:disabled="isDisabled"

View File

@@ -67,7 +67,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
await formEl.validate((valid, fields) => {
if (valid) {
useUserStoreHook()
.loginByUsername({ username: ruleForm.username })
.loginByUsername({ username: ruleForm.username, password: "admin123" })
.then(res => {
if (res.success) {
// 获取后端路由
@@ -207,9 +207,7 @@ watch(imgCode, value => {
clearable
v-model="ruleForm.verifyCode"
:placeholder="t('login.verifyCode')"
:prefix-icon="
useRenderIcon('ri:shield-keyhole-line', { online: true })
"
:prefix-icon="useRenderIcon('ri:shield-keyhole-line')"
>
<template v-slot:append>
<ReImageVerify v-model:code="imgCode" />

View File

@@ -1,5 +1,5 @@
import type { FormInstance, FormItemProp } from "element-plus";
import { cloneDeep } from "lodash-unified";
import { clone } from "@pureadmin/utils";
import { ref } from "vue";
const isDisabled = ref(false);
@@ -13,7 +13,7 @@ export const useVerifyCode = () => {
time = 60
) => {
if (!formEl) return;
const initTime = cloneDeep(time);
const initTime = clone(time, true);
await formEl.validateField(props, isValid => {
if (isValid) {
clearInterval(timer.value);

View File

@@ -6,7 +6,7 @@ defineOptions({
name: "Menu1-1"
});
let input = ref("");
const input = ref("");
const { t } = useI18n();
</script>

View File

@@ -6,7 +6,7 @@ defineOptions({
name: "Menu1-2-1"
});
let input = ref("");
const input = ref("");
const { t } = useI18n();
</script>

Some files were not shown because too many files have changed in this diff Show More