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 VITE_PORT = 8848

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
public public
dist dist
*.d.ts *.d.ts
/src/assets
package.json package.json
.eslintrc.js .eslintrc.js
.prettierrc.js .prettierrc.js
@@ -8,3 +9,5 @@ commitlint.config.js
postcss.config.js postcss.config.js
tailwind.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) # 3.6.3 (2022-11-01)
### 🎫 Feat ### 🎫 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 `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 - 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 [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) - Add project files, language analysis tool [cloc](https://www.npmjs.com/package/cloc)
- Added landing page internationalization - Added landing page internationalization
@@ -267,7 +312,6 @@
- Optimize the tab page to bring a better interactive experience - Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization - Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter - 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) # 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) # 3.6.3 (2022-11-01)
### 🎫 Feat ### 🎫 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 `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 - 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 [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) - Add project files, language analysis tool [cloc](https://www.npmjs.com/package/cloc)
- Added landing page internationalization - Added landing page internationalization
@@ -267,7 +312,6 @@
- Optimize the tab page to bring a better interactive experience - Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization - Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter - 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) # 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) # 3.6.3 (2022-11-01)
### 🎫 Feat ### 🎫 Feat
@@ -68,7 +113,7 @@
### ✔️ refactor ### ✔️ 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 ### 🐞 Bug fixes
@@ -106,7 +151,7 @@
-`element-plus``Table` 二次封装到[@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table),提供灵活的配置项并集成到平台里 -`element-plus``Table` 二次封装到[@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table),提供灵活的配置项并集成到平台里
-`element-plus``Descriptions` 二次封装到[@pureadmin/descriptions](https://github.com/xiaoxian521/pure-admin-descriptions),提供灵活的配置项并集成到平台里 -`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: 自定义名称})` - 添加[unplugin-vue-define-options](https://www.npmjs.com/package/unplugin-vue-define-options)插件,页面可直接写 `defineOptions({name: 自定义名称})`
- 添加项目文件、语言分析工具 [cloc](https://www.npmjs.com/package/cloc) - 添加项目文件、语言分析工具 [cloc](https://www.npmjs.com/package/cloc)
- 添加登录页国际化 - 添加登录页国际化
@@ -267,7 +312,6 @@
- 优化标签页,带来更好的交互体验 - 优化标签页,带来更好的交互体验
- 路由 title 支持直接写中文,可脱离国际化 - 路由 title 支持直接写中文,可脱离国际化
- 路由历史模式从 env 读取并支持 base 参数 - 路由历史模式从 env 读取并支持 base 参数
- 打包后的文件提供传统浏览器兼容性支持,配置 VITE_LEGACY 为 true
# 2.6.0(2021-11-10) # 2.6.0(2021-11-10)

View File

@@ -8,18 +8,17 @@
## Introduction ## 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 ## 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) - [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 the domestic documentation site](https://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](https://xiaoxian521.github.io/pure-admin-doc)
- [Click me to view foreign document site 2](https://pure-admin-doc.vercel.app)
## Thin version (offering non-internationalized and internationalized versions) ## 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) - [Click Watch Tauri](https://github.com/xiaoxian521/tauri-pure-admin)
## Electron
- [Click Watch Electron](https://github.com/xiaoxian521/electron-pure-admin)
## Preview ## Preview
- [Click me to view the domestic preview station](http://yiming_chang.gitee.io/vue-pure-admin) - [Click me to view the domestic preview station](https://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 site](https://xiaoxian521.github.io/vue-pure-admin)
- [Click me to view foreign preview station 2](https://vue-pure-admin.vercel.app)
- PC - PC
<p align="center"> <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) - [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
## 配套文档 ## 配套文档(支持 `PWA` 快速、离线访问)
- [点我查看国内文档站](http://yiming_chang.gitee.io/pure-admin-doc) - [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
- [点我查看国外文档站 1](https://xiaoxian521.github.io/pure-admin-doc) - [点我查看国外文档站](https://xiaoxian521.github.io/pure-admin-doc)
- [点我查看国外文档站 2](https://pure-admin-doc.vercel.app)
## 精简版(提供非国际化、国际化两个版本选择) ## 精简版(提供非国际化、国际化两个版本选择)
@@ -30,11 +29,14 @@ vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3
- [点我查看 Tauri 版](https://github.com/xiaoxian521/tauri-pure-admin) - [点我查看 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) - [点我查看国内预览站](https://yiming_chang.gitee.io/vue-pure-admin)
- [点我查看国外预览站 1](https://xiaoxian521.github.io/vue-pure-admin) - [点我查看国外预览站](https://xiaoxian521.github.io/vue-pure-admin)
- [点我查看国外预览站 2](https://vue-pure-admin.vercel.app)
- PC 端 - PC 端
<p align="center"> <p align="center">
@@ -146,7 +148,7 @@ pnpm build
一群已满,下面是二群,群里严禁`黄``赌``毒``vpn`等违法行为! 一群已满,下面是二群,群里严禁`黄``赌``毒``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 warpperEnv = (envConf: Recordable): ViteEnv => {
/** 此处为默认值,无需修改 */ /** 此处为默认值 */
const ret: ViteEnv = { const ret: ViteEnv = {
VITE_PORT: 8848, VITE_PORT: 8848,
VITE_PUBLIC_PATH: "", VITE_PUBLIC_PATH: "",
VITE_PROXY_DOMAIN: "",
VITE_PROXY_DOMAIN_REAL: "",
VITE_ROUTER_HISTORY: "", VITE_ROUTER_HISTORY: "",
VITE_LEGACY: false,
VITE_CDN: false, VITE_CDN: false,
VITE_COMPRESSION: "none" VITE_COMPRESSION: "none"
}; };
@@ -30,14 +27,9 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
return ret; return ret;
}; };
/** 跨域代理重写 */ /** 获取环境变量 */
const regExps = (value: string, reg: string): string => {
return value.replace(new RegExp(`^${reg}`, "g"), "");
};
/** 环境变量 */
const loadEnv = (): ViteEnv => { const loadEnv = (): ViteEnv => {
return import.meta.env; 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 vue from "@vitejs/plugin-vue";
import { viteBuildInfo } from "./info"; import { viteBuildInfo } from "./info";
import svgLoader from "vite-svg-loader"; import svgLoader from "vite-svg-loader";
import legacy from "@vitejs/plugin-legacy";
import vueJsx from "@vitejs/plugin-vue-jsx"; import vueJsx from "@vitejs/plugin-vue-jsx";
import VueMacros from "unplugin-vue-macros/vite";
import { viteMockServe } from "vite-plugin-mock"; import { viteMockServe } from "vite-plugin-mock";
import { configCompressPlugin } from "./compress"; import { configCompressPlugin } from "./compress";
import VueI18n from "@intlify/vite-plugin-vue-i18n"; import VueI18n from "@intlify/vite-plugin-vue-i18n";
import { visualizer } from "rollup-plugin-visualizer"; import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console"; import removeConsole from "vite-plugin-remove-console";
import themePreprocessorPlugin from "@pureadmin/theme"; import themePreprocessorPlugin from "@pureadmin/theme";
import DefineOptions from "unplugin-vue-define-options/vite";
import { genScssMultipleScopeVars } from "../src/layout/theme"; import { genScssMultipleScopeVars } from "../src/layout/theme";
export function getPluginsList( export function getPluginsList(
command: string, command: string,
VITE_LEGACY: boolean,
VITE_CDN: boolean, VITE_CDN: boolean,
VITE_COMPRESSION: ViteCompression VITE_COMPRESSION: ViteCompression
) { ) {
@@ -34,7 +32,7 @@ export function getPluginsList(
vueJsx(), vueJsx(),
VITE_CDN ? cdn : null, VITE_CDN ? cdn : null,
configCompressPlugin(VITE_COMPRESSION), configCompressPlugin(VITE_COMPRESSION),
DefineOptions(), VueMacros(),
// 线上环境删除console // 线上环境删除console
removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }), removeConsole({ external: ["src/assets/iconfont/iconfont.js"] }),
viteBuildInfo(), viteBuildInfo(),
@@ -65,13 +63,6 @@ export function getPluginsList(
`, `,
logger: false logger: false
}), }),
// 是否为打包后的文件提供传统浏览器兼容性支持
VITE_LEGACY
? legacy({
targets: ["ie >= 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
})
: null,
// 打包分析 // 打包分析
lifecycle === "report" lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" }) ? visualizer({ open: true, brotliSize: true, filename: "report.html" })

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,21 +16,21 @@ const props = defineProps({
}); });
const emit = defineEmits<{ (e: "update:modelValue", v: string) }>(); const emit = defineEmits<{ (e: "update:modelValue", v: string) }>();
let visible = ref(false); const visible = ref(false);
let inputValue = toRef(props, "modelValue"); const inputValue = toRef(props, "modelValue");
let iconList = ref(IconJson); const iconList = ref(IconJson);
let icon = ref("add-location"); const icon = ref("add-location");
let currentActiveType = ref("ep:"); const currentActiveType = ref("ep:");
// 深拷贝图标数据,前端做搜索 // 深拷贝图标数据,前端做搜索
let copyIconList = cloneDeep(iconList.value); const copyIconList = cloneDeep(iconList.value);
let pageSize = ref(96); const pageSize = ref(96);
let currentPage = ref(1); const currentPage = ref(1);
// 搜索条件 // 搜索条件
let filterValue = ref(""); const filterValue = ref("");
let tabsList = [ const tabsList = [
{ {
label: "Element Plus", label: "Element Plus",
name: "ep:" name: "ep:"
@@ -45,7 +45,7 @@ let tabsList = [
} }
]; ];
let pageList = computed(() => { const pageList = computed(() => {
if (currentPage.value === 1) { if (currentPage.value === 1) {
return copyIconList[currentActiveType.value] return copyIconList[currentActiveType.value]
.filter(v => v.includes(filterValue.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"; 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 icon 必传 图标
* @param attrs 可选 iconType 属性 * @param attrs 可选 iconType 属性
* @returns Component * @returns Component
@@ -34,11 +35,12 @@ export function useRenderIcon(icon: any, attrs?: iconType): Component {
// svg // svg
return icon; return icon;
} else { } else {
// 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之
return defineComponent({ return defineComponent({
name: "Icon", name: "Icon",
render() { render() {
const IconifyIcon = const IconifyIcon =
attrs && attrs["online"] ? IconifyIconOnline : IconifyIconOffline; icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline;
return h(IconifyIcon, { return h(IconifyIcon, {
icon: icon, icon: icon,
...attrs ...attrs

View File

@@ -29,6 +29,10 @@ import Refresh from "@iconify-icons/ep/refresh";
import EditPen from "@iconify-icons/ep/edit-pen"; import EditPen from "@iconify-icons/ep/edit-pen";
import Delete from "@iconify-icons/ep/delete"; import Delete from "@iconify-icons/ep/delete";
import More from "@iconify-icons/ep/more-filled"; 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("check", Check);
addIcon("menu", Menu); addIcon("menu", Menu);
addIcon("home-filled", HomeFilled); addIcon("home-filled", HomeFilled);
@@ -56,6 +60,10 @@ addIcon("refresh", Refresh);
addIcon("edits", EditPen); addIcon("edits", EditPen);
addIcon("delete", Delete); addIcon("delete", Delete);
addIcon("more", More); addIcon("more", More);
addIcon("ep-arrow-down", EpArrowDown);
addIcon("ep-arrow-up", ArrowUp);
addIcon("ep-arrow-right", ArrowRight);
addIcon("ep-arrow-left", ArrowLeft);
// remixicon // remixicon
import ArrowRightSLine from "@iconify-icons/ri/arrow-right-s-line"; 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"; import LocationCompany from "@iconify-icons/carbon/location-company";
addIcon("location-company", LocationCompany); 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({ export default defineComponent({
name: "IconifyIconOffline", name: "IconifyIconOffline",
components: { IconifyIcon }, components: { IconifyIcon },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
<script lang="ts" setup> <script setup lang="ts">
import { computed } from "vue"; import { computed } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useEpThemeStoreHook } from "@/store/modules/epTheme"; 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 { SearchModal } from "./components";
import { useBoolean } from "../../hooks/useBoolean"; import { useBoolean } from "../../hooks/useBoolean";
const { bool: show, toggle } = useBoolean(); const { bool: show, toggle } = useBoolean();

View File

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

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { isEqual } from "lodash-unified"; import { isEqual } from "@pureadmin/utils";
import { transformI18n } from "@/plugins/i18n"; import { transformI18n } from "@/plugins/i18n";
import { ref, watch, onMounted, toRaw } from "vue"; import { ref, watch, onMounted, toRaw } from "vue";
import { getParentPaths, findRouteByPath } from "@/router/utils"; 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"; import globalization from "@/assets/svg/globalization.svg?component";
const menuRef = ref(); const menuRef = ref();
let defaultActive = ref(null); const defaultActive = ref(null);
const { t, route, locale, translationCh, translationEn } = const { t, route, locale, translationCh, translationEn } =
useTranslationLang(menuRef); useTranslationLang(menuRef);

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import path from "path"; import path from "path";
import { getConfig } from "@/config";
import { childrenType } from "../../types"; import { childrenType } from "../../types";
import { useNav } from "@/layout/hooks/useNav"; import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "@/plugins/i18n"; 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); const onlyOneChild: childrenType = ref(null);
// 存放菜单是否存在showTooltip属性标识 // 存放菜单是否存在showTooltip属性标识
const hoverMenuMap = new WeakMap(); const hoverMenuMap = new WeakMap();
@@ -212,7 +217,15 @@ function resolvePath(routePath) {
</el-menu-item> </el-menu-item>
</template> </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> <template #title>
<div v-if="toRaw(props.item.meta.icon)" class="sub-menu-icon"> <div v-if="toRaw(props.item.meta.icon)" class="sub-menu-icon">
<component <component

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
import { $t } from "@/plugins/i18n"; import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index"; import type { RouteConfigsTable } from "/#/index";
const IFrame = () => import("@/layout/frameView.vue");
const formDesignRouter: RouteConfigsTable = { const formDesignRouter: RouteConfigsTable = {
path: "/formDesign", path: "/formDesign",
@@ -13,9 +14,11 @@ const formDesignRouter: RouteConfigsTable = {
{ {
path: "/formDesign/index", path: "/formDesign/index",
name: "FormDesign", name: "FormDesign",
component: () => import("@/views/form-design/index.vue"), component: IFrame,
meta: { 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: { meta: {
title: $t("menus.hsmenus"), title: $t("menus.hsmenus"),
icon: "histogram", icon: "histogram",
rank: 6 rank: 7
}, },
children: [ children: [
{ {

View File

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

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

View File

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

View File

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

View File

@@ -129,7 +129,7 @@ html.dark {
color: var(--el-text-color-primary); color: var(--el-text-color-primary);
} }
.vxe-button.type--button.size--medium:hover { .vxe-button.type--button:hover {
background: var(--el-color-primary) !important; 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 */ /* element-plus */
.el-table__cell { .el-table__cell {
background: var(--el-bg-color); background: var(--el-bg-color);

View File

@@ -20,7 +20,8 @@
filter: invert(80%); 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 { .vxe-pager .vxe-pager--num-btn:not(.is--disabled).is--active {
color: #fff !important; color: #fff !important;
} }

View File

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

View File

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

View File

@@ -40,16 +40,3 @@
.breadcrumb-leave-active { .breadcrumb-leave-active {
position: absolute; 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) - [npm](https://www.npmjs.com/package/@pureadmin/utils)
- [文档代码地址](https://github.com/xiaoxian521/pure-admin-utils-docs) - [文档代码地址](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>) { export function setToken(data: DataInfo<Date>) {
let expires = 0; let expires = 0;
const { accessToken, refreshToken } = data; 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 }); const cookieString = JSON.stringify({ accessToken, expires });
expires > 0 expires > 0
@@ -59,8 +59,10 @@ export function setToken(data: DataInfo<Date>) {
const { username, roles } = data; const { username, roles } = data;
setSessionKey(username, roles); setSessionKey(username, roles);
} else { } else {
const { username, roles } = const username =
storageSession.getItem<DataInfo<number>>(sessionKey); storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "";
const roles =
storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
setSessionKey(username, 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"; } from "./types.d";
import { stringify } from "qs"; import { stringify } from "qs";
import NProgress from "../progress"; import NProgress from "../progress";
// import { loadEnv } from "@build/index";
import { getToken, formatToken } from "@/utils/auth"; import { getToken, formatToken } from "@/utils/auth";
import { useUserStoreHook } from "@/store/modules/user"; 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 // 相关配置请参考www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = { 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, timeout: 10000,
headers: { headers: {
Accept: "application/json, text/plain, */*", 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" name: "Download"
}); });
let base64 = const base64 =
"data:image/png;base64,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"; "data:image/png;base64,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";
function down() { function down() {
axios 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" responseType: "blob"
}) })
.then(({ data }) => { .then(({ data }) => {
@@ -34,7 +34,7 @@ function down() {
<el-button <el-button
@click=" @click="
downloadByOnlineUrl( downloadByOnlineUrl(
'https://xiaoxian521.github.io/pure-admin-utils-docs/logo.png', 'https://xiaoxian521.github.io/pure-admin-doc/img/pure.png',
'test-url.png' 'test-url.png'
) )
" "

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -77,7 +77,7 @@ const options = [
]; ];
function onPrint() { 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; Print(el).toPrint;
} }

View File

@@ -2,7 +2,6 @@
import "swiper/css"; import "swiper/css";
import "swiper/css/navigation"; import "swiper/css/navigation";
import "swiper/css/pagination"; import "swiper/css/pagination";
import type { SwiperOptions } from "swiper";
import { Swiper, SwiperSlide } from "swiper/vue"; import { Swiper, SwiperSlide } from "swiper/vue";
import SwiperCore, { Autoplay, Navigation, Pagination } from "swiper"; import SwiperCore, { Autoplay, Navigation, Pagination } from "swiper";
@@ -10,27 +9,9 @@ defineOptions({
name: "Swiper" 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]); SwiperCore.use([Autoplay, Navigation, Pagination]);
const swiperExample: SwiperExample[] = [ const swiperExample: any[] = [
{ id: 0, label: "Default", options: {} }, { id: 0, label: "Default", options: {} },
{ {
id: 1, id: 1,
@@ -119,7 +100,7 @@ const swiperExample: SwiperExample[] = [
</template> </template>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col v-for="item in swiperExample" :key="item.id" :span="12"> <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 v-bind="item.options">
<swiper-slide v-for="i in 5" :key="i"> <swiper-slide v-for="i in 5" :key="i">
<div <div

View File

@@ -1,21 +1,43 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, onMounted, nextTick, onBeforeUnmount } from "vue";
import { useWatermark } from "@pureadmin/utils"; import { useWatermark } from "@pureadmin/utils";
defineOptions({ defineOptions({
name: "WaterMark" name: "WaterMark"
}); });
let color = ref("#409EFF"); const local = ref();
let value = ref("vue-pure-admin"); const preventLocal = ref();
const color = ref("#409EFF");
const value = ref("vue-pure-admin");
const { setWatermark, clear } = useWatermark(); 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> </script>
<template> <template>
<el-card> <el-card>
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<span class="font-medium">页面水印功能</span> <span class="font-medium">
页面水印功能将平台主题改为亮白色观察水印效果更明显哦
</span>
</div> </div>
</template> </template>
<span> 请输入要创建水印的值</span> <span> 请输入要创建水印的值</span>
@@ -29,10 +51,132 @@ const { setWatermark, clear } = useWatermark();
<el-color-picker v-model="color" show-alpha /> <el-color-picker v-model="color" show-alpha />
<br /> <br />
<el-button @click="setWatermark(value, { fillStyle: color })"> <el-button @click="setWatermark(value, { fillStyle: color })">
创建 创建整页水印
</el-button> </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> </el-card>
</template> </template>
<style scoped></style>

View File

@@ -18,7 +18,10 @@ export function useColumns() {
label: "文档地址", label: "文档地址",
cellRenderer: () => { cellRenderer: () => {
return ( 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> <span style="color: var(--el-color-primary)"></span>
</a> </a>
); );
@@ -28,7 +31,10 @@ export function useColumns() {
label: "预览地址", label: "预览地址",
cellRenderer: () => { cellRenderer: () => {
return ( 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> <span style="color: var(--el-color-primary)"></span>
</a> </a>
); );

View File

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

View File

@@ -19,432 +19,7 @@ const customDanmus = [
} }
]; ];
// 弹幕来自b站首页 const danmus = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
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 getDanmuData = () => { const getDanmuData = () => {
return danmus.map((text, index) => { return danmus.map((text, index) => {

View File

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

View File

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

View File

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

View File

@@ -15,10 +15,10 @@ defineOptions({
name: "FlowChart" name: "FlowChart"
}); });
let lf = ref(null); const lf = ref(null);
let graphData = ref(null); const graphData = ref(null);
let dataVisible = ref<boolean>(false); const dataVisible = ref<boolean>(false);
let config = ref({ const config = ref({
grid: true, grid: true,
background: { background: {
color: "#f7f9ff" color: "#f7f9ff"
@@ -27,7 +27,7 @@ let config = ref({
enabled: true enabled: true
} }
}); });
let nodeList = BpmnNode; const nodeList = BpmnNode;
function initLf() { function initLf() {
// 画布配置 // 画布配置
@@ -94,7 +94,7 @@ onMounted(() => {
<div id="LF-Turbo" /> <div id="LF-Turbo" />
<!-- 数据查看面板 --> <!-- 数据查看面板 -->
<el-dialog <el-dialog
customClass="flow-dialog" class="flow-dialog"
title="数据" title="数据"
v-model="dataVisible" v-model="dataVisible"
width="50%" 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"> <script setup lang="ts">
import Driver from "driver.js"; import intro from "intro.js";
import "driver.js/dist/driver.min.css"; import "intro.js/minified/introjs.min.css";
defineOptions({ defineOptions({
name: "Guide" 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 = () => { const guide = () => {
driver.defineSteps(steps); intro()
driver.start(); .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> </script>
@@ -69,20 +49,8 @@ const guide = () => {
</span> </span>
</div> </div>
</template> </template>
<el-button <el-button type="primary" class="mt-[10px]" @click="guide">
type="primary"
style="margin-top: 10px"
@click.prevent.stop="guide"
>
打开引导页 打开引导页
</el-button> </el-button>
</el-card> </el-card>
</template> </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 ? "已启用" : "已停用" }} {{ product.isSetup ? "已启用" : "已停用" }}
</el-tag> </el-tag>
<el-dropdown <el-dropdown trigger="click" :disabled="!product.isSetup">
trigger="click"
:disabled="!product.isSetup"
max-height="2"
>
<IconifyIconOffline icon="more-vertical" class="text-[24px]" /> <IconifyIconOffline icon="more-vertical" class="text-[24px]" />
<template #dropdown> <template #dropdown>
<el-dropdown-menu :disabled="!product.isSetup"> <el-dropdown-menu :disabled="!product.isSetup">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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