Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30209f62a9 | ||
|
|
1081506d10 | ||
|
|
590d6bf607 | ||
|
|
3365b99d3d | ||
|
|
31707cebf7 | ||
|
|
dac3ea3c21 | ||
|
|
01a32988c1 | ||
|
|
2e2c306097 | ||
|
|
d36d5b09c5 | ||
|
|
923f09db5b | ||
|
|
66fdfebb5e | ||
|
|
e032f9a6a7 | ||
|
|
4d68d6a220 | ||
|
|
2338dcab1f | ||
|
|
60e33f3782 | ||
|
|
3933f34883 | ||
|
|
49dabd6b36 | ||
|
|
6d697ee19c | ||
|
|
2206b9a9ae | ||
|
|
1419df10d2 | ||
|
|
7987a18c70 | ||
|
|
152a2f8f56 | ||
|
|
3629a66535 | ||
|
|
95940312a9 | ||
|
|
f13faf0788 | ||
|
|
8e2b174e09 | ||
|
|
b5839d6398 | ||
|
|
b14f41c8d7 | ||
|
|
9ab3fd19ef | ||
|
|
fa5c97ffa4 | ||
|
|
b4a566b2bf | ||
|
|
c84c447f3e | ||
|
|
53c715873c | ||
|
|
c80818d792 | ||
|
|
17936d476c | ||
|
|
1ef6ce70db | ||
|
|
d5d7dd8e57 | ||
|
|
1a39d0962e | ||
|
|
86b77c2877 | ||
|
|
cf8e5897fb | ||
|
|
f1e6ddff18 | ||
|
|
059a704f53 | ||
|
|
4c29bcc49a | ||
|
|
47960bbaf9 | ||
|
|
b2ec77275d |
@@ -1,3 +1,95 @@
|
||||
# 3.9.7 (2022-12-26)
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Use `path.posix.resolve` instead of `path.resolve` to avoid drive letter problems when using `electron` in `windows` environment
|
||||
- By default, the `CachingAsyncRoutes` dynamic routing cache is turned off locally, making it easier to debug in the development environment. It is not necessary to clear the local cached dynamic routing every time you modify the dynamic routing. It is recommended to enable it in the production environment
|
||||
|
||||
# 3.9.6 (2022-12-19)
|
||||
|
||||
### 🎫 Chores
|
||||
|
||||
- Upgrade `vite4` version
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fix the problem that `hmr` of `vite` is slow due to the wrong way of importing `tailwind.css`
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Update [@pureadmin/theme](https://github.com/pure-admin/pure-admin-theme) to the latest version, bringing more friendly type hints
|
||||
- Optimize [PureTableBar](https://github.com/xiaoxian521/vue-pure-admin/tree/main/src/components/RePureTableBar) component
|
||||
- Optimize the business code of the system management page to bring better code reference
|
||||
|
||||
# 3.9.5 (2022-12-13)
|
||||
|
||||
### ✔️ refactor
|
||||
|
||||
- completely removed `lodash` and its related libraries
|
||||
[Click here to see Why Removed? How to integrate it yourself? ](https://yiming_chang.gitee.io/pure-admin-doc/pages/FAQ/#%E5%B9%B3%E5%8F%B0%E5%9C%A8-v3-9-5-%E7 %89%88%E6%9C%AC%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E4%BA%86-lodash-%E5%92%8C% E5%85%B6%E7%9B%B8%E5%85%B3%E5%BA%93-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%A7%BB%E9 %99%A4-%E5%A6%82%E4%BD%95%E8%87%AA%E8%A1%8C%E9%9B%86%E6%88%90)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `@pureadmin/table` table dynamic column example
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fix dynamic route `rank` issue
|
||||
- Fix dark theme styling issues
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- optimize the route `rank`, when `rank` does not exist, it will be created automatically according to the order, the home page route will always be the first
|
||||
|
||||
# 3.9.4 (2022-12-05)
|
||||
|
||||
### ✔️ refactor
|
||||
|
||||
- Completely removed `vxe-table`, after removal, the overall package size of the full version is reduced by `1.82MB`, and the initial startup time is basically the same as the lite version 🐮
|
||||
[Click here to see Why Removed? How to integrate it yourself?](https://xiaoxian521.github.io/pure-admin-doc/pages/FAQ/#%E5%B9%B3%E5%8F%B0%E5%9C%A8-v3-9-4-%E7%89%88%E6%9C%AC%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E4%BA%86-vxe-table-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%A7%BB%E9%99%A4-%E5%A6%82%E4%BD%95%E8%87%AA%E8%A1%8C%E9%9B%86%E6%88%90)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `@pureadmin/table` table selector (single select, multiple select) example
|
||||
|
||||
# 3.9.3 (2022-12-04)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `@pureadmin/table` pagination and loading animation example
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fixed the problem that the refresh page would be blank due to changes in dynamic routes stored in local storage after enabling `CachingAsyncRoutes`
|
||||
- Fixed `Tooltip` displayed abnormally after the menu is collapsed
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Expand the use of local icons, the first launch of the full version reduces `13` requests again
|
||||
- When the menu loading is slow, add `loading` animation to optimize user experience
|
||||
- Theme initialization is placed in `onBeforeMount` to avoid flashing of the initialization page
|
||||
|
||||
# 3.9.2 (2022-12-03)
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Global coverage of `el-dialog`, `el-drawer`, `el-message-box`, `el-notification` components of `element-plus`The style of the close icon in the upper right corner makes it more vivid [specific modification Code record](https://github.com/xiaoxian521/vue-pure-admin/commit/c80818d792276666aaea4b18413a0f08777f2ed1)
|
||||
- The packaging output information is compatible with different packaging output paths
|
||||
- Optimize some animations
|
||||
|
||||
# 3.9.1 (2022-12-02)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `CachingAsyncRoutes` whether to enable dynamic route cache local global configuration, default `true`
|
||||
- Add `TooltipEffect` global configuration, you can configure the `effect` attribute of all `el-tooltip` on the platform body, the default `light`, does not affect the business code
|
||||
- Add directory, menu text exceeds display `Tooltip` text prompt demo
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Optimize `initRouter` method, compatible with `sso` scenario
|
||||
- Breadcrumb animation style optimization
|
||||
|
||||
# 3.9.0 (2022-11-30)
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
92
CHANGELOG.md
@@ -1,3 +1,95 @@
|
||||
# 3.9.7 (2022-12-26)
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Use `path.posix.resolve` instead of `path.resolve` to avoid drive letter problems when using `electron` in `windows` environment
|
||||
- By default, the `CachingAsyncRoutes` dynamic routing cache is turned off locally, making it easier to debug in the development environment. It is not necessary to clear the local cached dynamic routing every time you modify the dynamic routing. It is recommended to enable it in the production environment
|
||||
|
||||
# 3.9.6 (2022-12-19)
|
||||
|
||||
### 🎫 Chores
|
||||
|
||||
- Upgrade `vite4` version
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fix the problem that `hmr` of `vite` is slow due to the wrong way of importing `tailwind.css`
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Update [@pureadmin/theme](https://github.com/pure-admin/pure-admin-theme) to the latest version, bringing more friendly type hints
|
||||
- Optimize [PureTableBar](https://github.com/xiaoxian521/vue-pure-admin/tree/main/src/components/RePureTableBar) component
|
||||
- Optimize the business code of the system management page to bring better code reference
|
||||
|
||||
# 3.9.5 (2022-12-13)
|
||||
|
||||
### ✔️ refactor
|
||||
|
||||
- completely removed `lodash` and its related libraries
|
||||
[Click here to see Why Removed? How to integrate it yourself? ](https://yiming_chang.gitee.io/pure-admin-doc/pages/FAQ/#%E5%B9%B3%E5%8F%B0%E5%9C%A8-v3-9-5-%E7 %89%88%E6%9C%AC%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E4%BA%86-lodash-%E5%92%8C% E5%85%B6%E7%9B%B8%E5%85%B3%E5%BA%93-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%A7%BB%E9 %99%A4-%E5%A6%82%E4%BD%95%E8%87%AA%E8%A1%8C%E9%9B%86%E6%88%90)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `@pureadmin/table` table dynamic column example
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fix dynamic route `rank` issue
|
||||
- Fix dark theme styling issues
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- optimize the route `rank`, when `rank` does not exist, it will be created automatically according to the order, the home page route will always be the first
|
||||
|
||||
# 3.9.4 (2022-12-05)
|
||||
|
||||
### ✔️ refactor
|
||||
|
||||
- Completely removed `vxe-table`, after removal, the overall package size of the full version is reduced by `1.82MB`, and the initial startup time is basically the same as the lite version 🐮
|
||||
[Click here to see Why Removed? How to integrate it yourself?](https://xiaoxian521.github.io/pure-admin-doc/pages/FAQ/#%E5%B9%B3%E5%8F%B0%E5%9C%A8-v3-9-4-%E7%89%88%E6%9C%AC%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E4%BA%86-vxe-table-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%A7%BB%E9%99%A4-%E5%A6%82%E4%BD%95%E8%87%AA%E8%A1%8C%E9%9B%86%E6%88%90)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `@pureadmin/table` table selector (single select, multiple select) example
|
||||
|
||||
# 3.9.3 (2022-12-04)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `@pureadmin/table` pagination and loading animation example
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fixed the problem that the refresh page would be blank due to changes in dynamic routes stored in local storage after enabling `CachingAsyncRoutes`
|
||||
- Fixed `Tooltip` displayed abnormally after the menu is collapsed
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Expand the use of local icons, the first launch of the full version reduces `13` requests again
|
||||
- When the menu loading is slow, add `loading` animation to optimize user experience
|
||||
- Theme initialization is placed in `onBeforeMount` to avoid flashing of the initialization page
|
||||
|
||||
# 3.9.2 (2022-12-03)
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Global coverage of `el-dialog`, `el-drawer`, `el-message-box`, `el-notification` components of `element-plus`The style of the close icon in the upper right corner makes it more vivid [specific modification Code record](https://github.com/xiaoxian521/vue-pure-admin/commit/c80818d792276666aaea4b18413a0f08777f2ed1)
|
||||
- The packaging output information is compatible with different packaging output paths
|
||||
- Optimize some animations
|
||||
|
||||
# 3.9.1 (2022-12-02)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- Add `CachingAsyncRoutes` whether to enable dynamic route cache local global configuration, default `true`
|
||||
- Add `TooltipEffect` global configuration, you can configure the `effect` attribute of all `el-tooltip` on the platform body, the default `light`, does not affect the business code
|
||||
- Add directory, menu text exceeds display `Tooltip` text prompt demo
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- Optimize `initRouter` method, compatible with `sso` scenario
|
||||
- Breadcrumb animation style optimization
|
||||
|
||||
# 3.9.0 (2022-11-30)
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
@@ -1,3 +1,95 @@
|
||||
# 3.9.7 (2022-12-26)
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- 使用 `path.posix.resolve` 替代 `path.resolve` 避免 `windows` 环境下使用 `electron` 出现盘符问题
|
||||
- 默认关闭 `CachingAsyncRoutes` 动态路由缓存本地,使其在开发环境下调试更方便,不用每次修改动态路由都要先清空本地缓存的动态路由,更推荐在生产环境开启
|
||||
|
||||
# 3.9.6 (2022-12-19)
|
||||
|
||||
### 🎫 Chores
|
||||
|
||||
- 升级 `vite4` 版本
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- 修复 `tailwind.css` 错误的引入方式导致 `vite` 的 `hmr` 慢的问题
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- 更新 [@pureadmin/theme](https://github.com/pure-admin/pure-admin-theme) 至最新版,带来更友好的类型提示
|
||||
- 优化 [PureTableBar](https://github.com/xiaoxian521/vue-pure-admin/tree/main/src/components/RePureTableBar) 组件
|
||||
- 优化系统管理页面业务代码,带来更好的代码参考
|
||||
|
||||
# 3.9.5 (2022-12-13)
|
||||
|
||||
### ✔️ refactor
|
||||
|
||||
- 完全移除了 `lodash` 和其相关库
|
||||
[点击此处查看为什么移除?如何自行集成?](https://yiming_chang.gitee.io/pure-admin-doc/pages/FAQ/#%E5%B9%B3%E5%8F%B0%E5%9C%A8-v3-9-5-%E7%89%88%E6%9C%AC%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E4%BA%86-lodash-%E5%92%8C%E5%85%B6%E7%9B%B8%E5%85%B3%E5%BA%93-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%A7%BB%E9%99%A4-%E5%A6%82%E4%BD%95%E8%87%AA%E8%A1%8C%E9%9B%86%E6%88%90)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- 添加 `@pureadmin/table` 表格动态列示例
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- 修复动态路由 `rank` 问题
|
||||
- 修复暗黑主题样式问题
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- 优化路由 `rank` ,当 `rank` 不存在时,根据顺序自动创建,首页路由永远在第一位
|
||||
|
||||
# 3.9.4 (2022-12-05)
|
||||
|
||||
### ✔️ refactor
|
||||
|
||||
- 完全移除了 `vxe-table`,移除后,完整版整体打包大小减少 `1.82MB`,首启动时长基本和精简版持平 🐮
|
||||
[点击此处查看为什么移除?如何自行集成?](https://yiming_chang.gitee.io/pure-admin-doc/pages/FAQ/#%E5%B9%B3%E5%8F%B0%E5%9C%A8-v3-9-4-%E7%89%88%E6%9C%AC%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E4%BA%86-vxe-table-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%A7%BB%E9%99%A4-%E5%A6%82%E4%BD%95%E8%87%AA%E8%A1%8C%E9%9B%86%E6%88%90)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- 添加 `@pureadmin/table` 表格选择器(单选、多选)示例
|
||||
|
||||
# 3.9.3 (2022-12-04)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- 添加 `@pureadmin/table` 分页和加载动画示例
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- 修复开启 `CachingAsyncRoutes` 后,存入本地存储的动态路由改变造成刷新页面空白的问题
|
||||
- 修复菜单折叠后 `Tooltip` 显示异常
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- 扩展本地图标使用方式,完整版首启动再次减少 `13` 个请求
|
||||
- 当菜单加载慢时,添加 `loading` 动画,优化用户体验
|
||||
- 主题初始化放在 `onBeforeMount` 里,避免初始化页面闪烁
|
||||
|
||||
# 3.9.2 (2022-12-03)
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- 全局覆盖 `element-plus` 的 `el-dialog`、`el-drawer`、`el-message-box`、`el-notification` 组件右上角关闭图标的样式,使其表现更鲜明 [具体代码修改记录](https://github.com/xiaoxian521/vue-pure-admin/commit/c80818d792276666aaea4b18413a0f08777f2ed1)
|
||||
- 打包输出信息兼容不同打包输出路径
|
||||
- 优化一些动画
|
||||
|
||||
# 3.9.1 (2022-12-02)
|
||||
|
||||
### 🎫 Feat
|
||||
|
||||
- 添加 `CachingAsyncRoutes` 是否开启动态路由缓存本地的全局配置,默认 `true`
|
||||
- 添加 `TooltipEffect` 全局配置,可配置平台主体所有 `el-tooltip` 的 `effect` 属性,默认 `light`,不影响业务代码
|
||||
- 添加目录、菜单文字超出显示 `Tooltip` 文字提示演示
|
||||
|
||||
### 🍏 Perf
|
||||
|
||||
- 优化 `initRouter` 方法,兼容 `sso` 场景
|
||||
- 面包屑动画样式优化
|
||||
|
||||
# 3.9.0 (2022-11-30)
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
10
README.md
@@ -22,7 +22,7 @@
|
||||
- [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
|
||||
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
|
||||
|
||||
## 配套文档(支持 `PWA` 快速、离线访问)
|
||||
## 配套保姆级文档(支持 `PWA` 快速、离线访问)
|
||||
|
||||
- [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
|
||||
- [点我查看国外文档站](https://xiaoxian521.github.io/pure-admin-doc)
|
||||
@@ -140,7 +140,7 @@ pnpm build
|
||||
|
||||
[xiaoxian521](https://github.com/xiaoxian521)、[Ten-K](https://github.com/Ten-K)
|
||||
|
||||
## 捐赠
|
||||
## 支持
|
||||
|
||||
如果您觉得这个项目对您有帮助,可以帮作者买一杯果汁 🍹 表示支持
|
||||
|
||||
@@ -148,9 +148,7 @@ pnpm build
|
||||
|
||||
## `QQ` 交流群
|
||||
|
||||
一群已满,下面是二群,群里严禁`黄`、`赌`、`毒`、`vpn`等违法行为!
|
||||
|
||||
<img src="https://yiming_chang.gitee.io/pure-admin-doc/img/support/qq.png" width="150px" height="225px" />
|
||||
[点击去加入](https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4)
|
||||
|
||||
## 许可证
|
||||
|
||||
@@ -158,7 +156,7 @@ pnpm build
|
||||
|
||||
[MIT © xiaoxian521-2020](./LICENSE)
|
||||
|
||||
## 捐赠者
|
||||
## 支持者
|
||||
|
||||
非常感谢您们的支持,相信项目会越来越好 :heart:
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Plugin as importToCDN } from "vite-plugin-cdn-import";
|
||||
* 注意:上面提到的仅限外网使用也不是完全肯定的,如果你们公司内网部署的有相关js、css文件,也可以将下面配置对应改一下,整一套内网版cdn
|
||||
*/
|
||||
export const cdn = importToCDN({
|
||||
//(prodUrl解释: name: 对应下面modules的name,version: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path)
|
||||
//(prodUrl解释: name: 对应下面modules的name,version: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path,当然也可写完整路径,会替换prodUrl)
|
||||
prodUrl: "https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}",
|
||||
modules: [
|
||||
{
|
||||
@@ -56,12 +56,6 @@ export const cdn = importToCDN({
|
||||
name: "echarts",
|
||||
var: "echarts",
|
||||
path: "echarts.min.js"
|
||||
},
|
||||
{
|
||||
name: "lodash",
|
||||
var: "lodash",
|
||||
// 可写`完整路径`,会替换`prodUrl`
|
||||
path: "https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -27,9 +27,4 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
|
||||
return ret;
|
||||
};
|
||||
|
||||
/** 获取环境变量 */
|
||||
const loadEnv = (): ViteEnv => {
|
||||
return import.meta.env;
|
||||
};
|
||||
|
||||
export { warpperEnv, loadEnv };
|
||||
export { warpperEnv };
|
||||
|
||||
@@ -9,10 +9,12 @@ export function viteBuildInfo(): Plugin {
|
||||
let config: { command: string };
|
||||
let startTime: Dayjs;
|
||||
let endTime: Dayjs;
|
||||
let outDir: string;
|
||||
return {
|
||||
name: "vite:buildInfo",
|
||||
configResolved(resolvedConfig: { command: string }) {
|
||||
configResolved(resolvedConfig) {
|
||||
config = resolvedConfig;
|
||||
outDir = resolvedConfig.build?.outDir ?? "dist";
|
||||
},
|
||||
buildStart() {
|
||||
console.log(
|
||||
@@ -32,6 +34,7 @@ export function viteBuildInfo(): Plugin {
|
||||
if (config.command === "build") {
|
||||
endTime = dayjs(new Date());
|
||||
getPackageSize({
|
||||
folder: outDir,
|
||||
callback: (size: string) => {
|
||||
console.log(
|
||||
bold(
|
||||
|
||||
@@ -12,14 +12,10 @@ const include = [
|
||||
"axios",
|
||||
"pinia",
|
||||
"swiper",
|
||||
"lodash",
|
||||
"echarts",
|
||||
"intro.js",
|
||||
"vue-i18n",
|
||||
"xe-utils",
|
||||
"vxe-table",
|
||||
"js-cookie",
|
||||
"lodash-es",
|
||||
"cropperjs",
|
||||
"jsbarcode",
|
||||
"sortablejs",
|
||||
@@ -29,8 +25,6 @@ const include = [
|
||||
"vue3-danmaku",
|
||||
"v-contextmenu",
|
||||
"vue-pdf-embed",
|
||||
"lodash-unified",
|
||||
"@ctrl/tinycolor",
|
||||
"china-area-data",
|
||||
"vue-json-pretty",
|
||||
"@logicflow/core",
|
||||
@@ -58,7 +52,6 @@ const include = [
|
||||
const exclude = [
|
||||
"@iconify-icons/ep",
|
||||
"@iconify-icons/ri",
|
||||
"@iconify-icons/mdi",
|
||||
"@pureadmin/theme/dist/browser-utils"
|
||||
];
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import svgLoader from "vite-svg-loader";
|
||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||
import { viteMockServe } from "vite-plugin-mock";
|
||||
import { configCompressPlugin } from "./compress";
|
||||
import VueI18n from "@intlify/vite-plugin-vue-i18n";
|
||||
import { visualizer } from "rollup-plugin-visualizer";
|
||||
import removeConsole from "vite-plugin-remove-console";
|
||||
import themePreprocessorPlugin from "@pureadmin/theme";
|
||||
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
||||
import DefineOptions from "unplugin-vue-define-options/vite";
|
||||
import { genScssMultipleScopeVars } from "../src/layout/theme";
|
||||
|
||||
@@ -22,8 +22,7 @@ export function getPluginsList(
|
||||
const lifecycle = process.env.npm_lifecycle_event;
|
||||
return [
|
||||
vue(),
|
||||
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
|
||||
VueI18n({
|
||||
VueI18nPlugin({
|
||||
runtimeOnly: true,
|
||||
compositionOnly: true,
|
||||
include: [resolve("locales/**")]
|
||||
@@ -40,14 +39,7 @@ export function getPluginsList(
|
||||
themePreprocessorPlugin({
|
||||
scss: {
|
||||
multipleScopeVars: genScssMultipleScopeVars(),
|
||||
// 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
|
||||
extract: true,
|
||||
// 会选取defaultScopeName对应的主题css文件在html添加link
|
||||
themeLinkTagId: "head",
|
||||
// "head"||"head-prepend" || "body" ||"body-prepend"
|
||||
themeLinkTagInjectTo: "head",
|
||||
// 是否对抽取的css文件内对应scopeName的权重类名移除
|
||||
removeCssScopeName: false
|
||||
extract: true
|
||||
}
|
||||
}),
|
||||
// svg组件化支持
|
||||
|
||||
@@ -28,7 +28,6 @@ menus:
|
||||
hsempty: Empty Page
|
||||
hssysManagement: System Manage
|
||||
hsUser: User Manage
|
||||
hsDict: Dict Manage
|
||||
hsRole: Role Manage
|
||||
hsDept: Dept Manage
|
||||
hseditor: Editor
|
||||
@@ -101,6 +100,8 @@ menus:
|
||||
hsPureTableBase: Base Usage
|
||||
hsPureTableHigh: High Usage
|
||||
hsTree: Big Data Tree
|
||||
hsMenuoverflow: Menu Overflow Show Tooltip Text
|
||||
hsChildMenuoverflow: Child Menu Overflow Show Tooltip Text
|
||||
status:
|
||||
hsLoad: Loading...
|
||||
login:
|
||||
|
||||
@@ -28,7 +28,6 @@ menus:
|
||||
hsempty: 无Layout页
|
||||
hssysManagement: 系统管理
|
||||
hsUser: 用户管理
|
||||
hsDict: 字典管理
|
||||
hsRole: 角色管理
|
||||
hsDept: 部门管理
|
||||
hseditor: 编辑器
|
||||
@@ -99,8 +98,10 @@ menus:
|
||||
hsInfiniteScroll: 表格无限滚动
|
||||
hsdanmaku: 弹幕组件
|
||||
hsPureTableBase: 基础用法(23个示例)
|
||||
hsPureTableHigh: 高级用法(8个示例)
|
||||
hsPureTableHigh: 高级用法(10个示例)
|
||||
hsTree: 大数据树业务组件
|
||||
hsMenuoverflow: 目录超出显示 Tooltip 文字提示
|
||||
hsChildMenuoverflow: 菜单超出显示 Tooltip 文字提示
|
||||
status:
|
||||
hsLoad: 加载中...
|
||||
login:
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
import { MockMethod } from "vite-plugin-mock";
|
||||
import { system, permission, frame, tabs } from "@/router/enums";
|
||||
|
||||
import FlUser from "@iconify-icons/ri/admin-line";
|
||||
import Role from "@iconify-icons/ri/admin-fill";
|
||||
import Dict from "@iconify-icons/ri/git-repository-line";
|
||||
import Setting from "@iconify-icons/ri/settings-3-line";
|
||||
import Dept from "@iconify-icons/ri/git-branch-line";
|
||||
import Lollipop from "@iconify-icons/ep/lollipop";
|
||||
import Monitor from "@iconify-icons/ep/monitor";
|
||||
|
||||
/**
|
||||
* roles:页面级别权限,这里模拟二种 "admin"、"common"
|
||||
* admin:管理员角色
|
||||
@@ -19,7 +11,7 @@ import Monitor from "@iconify-icons/ep/monitor";
|
||||
const systemRouter = {
|
||||
path: "/system",
|
||||
meta: {
|
||||
icon: Setting,
|
||||
icon: "setting",
|
||||
title: "menus.hssysManagement",
|
||||
rank: system
|
||||
},
|
||||
@@ -28,7 +20,7 @@ const systemRouter = {
|
||||
path: "/system/user/index",
|
||||
name: "User",
|
||||
meta: {
|
||||
icon: FlUser,
|
||||
icon: "flUser",
|
||||
title: "menus.hsUser",
|
||||
roles: ["admin"]
|
||||
}
|
||||
@@ -37,7 +29,7 @@ const systemRouter = {
|
||||
path: "/system/role/index",
|
||||
name: "Role",
|
||||
meta: {
|
||||
icon: Role,
|
||||
icon: "role",
|
||||
title: "menus.hsRole",
|
||||
roles: ["admin"]
|
||||
}
|
||||
@@ -46,21 +38,10 @@ const systemRouter = {
|
||||
path: "/system/dept/index",
|
||||
name: "Dept",
|
||||
meta: {
|
||||
icon: Dept,
|
||||
icon: "dept",
|
||||
title: "menus.hsDept",
|
||||
roles: ["admin"]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/system/dict",
|
||||
component: "/system/dict/index",
|
||||
name: "Dict",
|
||||
meta: {
|
||||
icon: Dict,
|
||||
title: "menus.hsDict",
|
||||
keepAlive: true,
|
||||
roles: ["admin"]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -69,7 +50,7 @@ const permissionRouter = {
|
||||
path: "/permission",
|
||||
meta: {
|
||||
title: "menus.permission",
|
||||
icon: Lollipop,
|
||||
icon: "lollipop",
|
||||
rank: permission
|
||||
},
|
||||
children: [
|
||||
@@ -96,7 +77,7 @@ const permissionRouter = {
|
||||
const frameRouter = {
|
||||
path: "/iframe",
|
||||
meta: {
|
||||
icon: Monitor,
|
||||
icon: "monitor",
|
||||
title: "menus.hsExternalPage",
|
||||
rank: frame
|
||||
},
|
||||
|
||||
42
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-pure-admin",
|
||||
"version": "3.9.0",
|
||||
"version": "3.9.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
|
||||
@@ -30,13 +30,12 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||
"@ctrl/tinycolor": "^3.4.1",
|
||||
"@howdyjs/mouse-menu": "^2.0.5",
|
||||
"@logicflow/core": "^1.1.30",
|
||||
"@logicflow/extension": "^1.1.30",
|
||||
"@pureadmin/descriptions": "^1.1.0",
|
||||
"@pureadmin/table": "^1.8.0",
|
||||
"@pureadmin/utils": "^1.7.1",
|
||||
"@pureadmin/table": "^1.9.0",
|
||||
"@pureadmin/utils": "^1.8.5",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"@vueuse/motion": "2.0.0-beta.12",
|
||||
"@wangeditor/editor": "^5.1.21",
|
||||
@@ -48,38 +47,33 @@
|
||||
"dayjs": "^1.11.6",
|
||||
"echarts": "^5.4.0",
|
||||
"el-table-infinite-scroll": "^3.0.1",
|
||||
"element-plus": "^2.2.25",
|
||||
"element-plus": "^2.2.27",
|
||||
"element-resize-detector": "^1.2.4",
|
||||
"intro.js": "^6.0.0",
|
||||
"js-cookie": "^3.0.1",
|
||||
"jsbarcode": "^3.11.5",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash-unified": "^1.0.2",
|
||||
"md-editor-v3": "^2.4.2",
|
||||
"md-editor-v3": "^2.5.0",
|
||||
"mitt": "^3.0.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path": "^0.12.7",
|
||||
"pinia": "^2.0.26",
|
||||
"pinia": "^2.0.28",
|
||||
"qrcode": "^1.5.1",
|
||||
"qs": "^6.11.0",
|
||||
"responsive-storage": "^2.1.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"swiper": "^8.4.4",
|
||||
"swiper": "^8.4.5",
|
||||
"typeit": "^8.7.0",
|
||||
"v-contextmenu": "3.0.0",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-json-pretty": "^2.2.2",
|
||||
"vue-pdf-embed": "^1.1.4",
|
||||
"vue-json-pretty": "^2.2.3",
|
||||
"vue-pdf-embed": "^1.1.5",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-types": "^4.2.1",
|
||||
"vue-virtual-scroller": "^2.0.0-alpha.1",
|
||||
"vue3-danmaku": "^1.0.0",
|
||||
"vue-virtual-scroller": "2.0.0-beta.7",
|
||||
"vue3-danmaku": "^1.2.0",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vxe-table": "^4.3.6",
|
||||
"xe-utils": "^3.5.7",
|
||||
"xgplayer": "^2.32.1",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
@@ -87,16 +81,13 @@
|
||||
"@commitlint/cli": "13.1.0",
|
||||
"@commitlint/config-conventional": "13.1.0",
|
||||
"@iconify-icons/ep": "^1.2.7",
|
||||
"@iconify-icons/mdi": "^1.2.8",
|
||||
"@iconify-icons/ri": "^1.2.3",
|
||||
"@iconify/vue": "^4.0.0",
|
||||
"@intlify/vite-plugin-vue-i18n": "^6.0.3",
|
||||
"@pureadmin/theme": "^2.4.0",
|
||||
"@intlify/unplugin-vue-i18n": "^0.8.1",
|
||||
"@pureadmin/theme": "^3.0.0",
|
||||
"@types/element-resize-detector": "1.1.3",
|
||||
"@types/intro.js": "^5.1.0",
|
||||
"@types/js-cookie": "^3.0.1",
|
||||
"@types/lodash": "^4.14.180",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/mockjs": "^1.0.7",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/nprogress": "0.2.0",
|
||||
@@ -105,8 +96,8 @@
|
||||
"@types/sortablejs": "^1.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||
"@typescript-eslint/parser": "^5.43.0",
|
||||
"@vitejs/plugin-vue": "^3.2.0",
|
||||
"@vitejs/plugin-vue-jsx": "^2.1.1",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"autoprefixer": "^10.4.13",
|
||||
@@ -115,7 +106,6 @@
|
||||
"eslint": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^9.7.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "11.1.2",
|
||||
"picocolors": "^1.0.0",
|
||||
@@ -140,7 +130,7 @@
|
||||
"terser": "^5.15.1",
|
||||
"typescript": "^4.9.3",
|
||||
"unplugin-vue-define-options": "^1.0.0",
|
||||
"vite": "3.1.8",
|
||||
"vite": "^4.0.3",
|
||||
"vite-plugin-cdn-import": "^0.3.5",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
|
||||
1565
pnpm-lock.yaml
generated
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Version": "3.9.0",
|
||||
"Version": "3.9.7",
|
||||
"Title": "PureAdmin",
|
||||
"FixedHeader": true,
|
||||
"HiddenSideBar": false,
|
||||
@@ -17,6 +17,8 @@
|
||||
"ShowLogo": true,
|
||||
"ShowModel": "smart",
|
||||
"MenuArrowIconNoTransition": true,
|
||||
"CachingAsyncRoutes": false,
|
||||
"TooltipEffect": "light",
|
||||
"MapConfigure": {
|
||||
"amapKey": "97b3248d1553172e81f168cf94ea667e",
|
||||
"options": {
|
||||
|
||||
@@ -10,6 +10,11 @@ type Result = {
|
||||
};
|
||||
};
|
||||
|
||||
type ResultDept = {
|
||||
success: boolean;
|
||||
data?: Array<any>;
|
||||
};
|
||||
|
||||
/** 获取用户管理列表 */
|
||||
export const getUserList = (data?: object) => {
|
||||
return http.request<Result>("post", "/user", { data });
|
||||
@@ -22,5 +27,5 @@ export const getRoleList = (data?: object) => {
|
||||
|
||||
/** 获取部门管理列表 */
|
||||
export const getDeptList = (data?: object) => {
|
||||
return http.request<Result>("post", "/dept", { data });
|
||||
return http.request<ResultDept>("post", "/dept", { data });
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 40 KiB |
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { cloneDeep } from "lodash-unified";
|
||||
import { cloneDeep } from "@pureadmin/utils";
|
||||
import { IconJson } from "@/components/ReIcon/data";
|
||||
import { ref, computed, CSSProperties, toRef, watch } from "vue";
|
||||
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;
|
||||
|
||||
45
src/components/ReIcon/src/offlineIcon.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { addIcon } from "@iconify/vue/dist/offline";
|
||||
|
||||
/**
|
||||
* 这里存放本地图标,在 src/layout/index.vue 文件中加载,避免在首启动加载
|
||||
*/
|
||||
|
||||
// 本地菜单图标,后端在路由的icon中返回对应的图标字符串并且前端在此处使用addIcon添加即可渲染菜单图标
|
||||
import UbuntuFill from "@iconify-icons/ri/ubuntu-fill";
|
||||
import Menu from "@iconify-icons/ep/menu";
|
||||
import Edit from "@iconify-icons/ep/edit";
|
||||
import InformationLine from "@iconify-icons/ri/information-line";
|
||||
import SetUp from "@iconify-icons/ep/set-up";
|
||||
import TerminalWindowLine from "@iconify-icons/ri/terminal-window-line";
|
||||
import Guide from "@iconify-icons/ep/guide";
|
||||
import HomeFilled from "@iconify-icons/ep/home-filled";
|
||||
import Card from "@iconify-icons/ri/bank-card-line";
|
||||
import ListCheck from "@iconify-icons/ri/list-check";
|
||||
import Histogram from "@iconify-icons/ep/histogram";
|
||||
import Ppt from "@iconify-icons/ri/file-ppt-2-line";
|
||||
import CheckboxCircleLine from "@iconify-icons/ri/checkbox-circle-line";
|
||||
import FlUser from "@iconify-icons/ri/admin-line";
|
||||
import Role from "@iconify-icons/ri/admin-fill";
|
||||
import Setting from "@iconify-icons/ri/settings-3-line";
|
||||
import Dept from "@iconify-icons/ri/git-branch-line";
|
||||
import Lollipop from "@iconify-icons/ep/lollipop";
|
||||
import Monitor from "@iconify-icons/ep/monitor";
|
||||
addIcon("ubuntuFill", UbuntuFill);
|
||||
addIcon("menu", Menu);
|
||||
addIcon("edit", Edit);
|
||||
addIcon("informationLine", InformationLine);
|
||||
addIcon("setUp", SetUp);
|
||||
addIcon("terminalWindowLine", TerminalWindowLine);
|
||||
addIcon("guide", Guide);
|
||||
addIcon("homeFilled", HomeFilled);
|
||||
addIcon("card", Card);
|
||||
addIcon("listCheck", ListCheck);
|
||||
addIcon("histogram", Histogram);
|
||||
addIcon("ppt", Ppt);
|
||||
addIcon("checkboxCircleLine", CheckboxCircleLine);
|
||||
addIcon("flUser", FlUser);
|
||||
addIcon("role", Role);
|
||||
addIcon("setting", Setting);
|
||||
addIcon("dept", Dept);
|
||||
addIcon("lollipop", Lollipop);
|
||||
addIcon("monitor", Monitor);
|
||||
5
src/components/RePureTableBar/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import pureTableBar from "./src/bar";
|
||||
import { withInstall } from "@pureadmin/utils";
|
||||
|
||||
/** 配合 `@pureadmin/table` 实现快速便捷的表格操作 https://github.com/xiaoxian521/pure-admin-table */
|
||||
export const PureTableBar = withInstall(pureTableBar);
|
||||
@@ -1,55 +1,25 @@
|
||||
import { defineComponent, ref, computed, PropType } from "vue";
|
||||
import { delay } from "@pureadmin/utils";
|
||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
|
||||
|
||||
import UnExpand from "@iconify-icons/mdi/arrow-expand-right";
|
||||
import { IconifyIconOffline } from "../../ReIcon";
|
||||
import Expand from "@iconify-icons/mdi/arrow-expand-down";
|
||||
import ArrowCollapse from "@iconify-icons/mdi/arrow-collapse-vertical";
|
||||
import Setting from "@iconify-icons/ri/settings-3-line";
|
||||
import RefreshRight from "@iconify-icons/ep/refresh-right";
|
||||
|
||||
export const loadingSvg = `
|
||||
<path class="path" d="
|
||||
M 30 15
|
||||
L 28 17
|
||||
M 25.61 25.61
|
||||
A 15 15, 0, 0, 1, 15 30
|
||||
A 15 15, 0, 1, 1, 27.99 7.5
|
||||
L 15 15
|
||||
"
|
||||
style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"
|
||||
/>
|
||||
`;
|
||||
import { defineComponent, ref, computed, type PropType } from "vue";
|
||||
import ExpandIcon from "./svg/expand.svg?component";
|
||||
import RefreshIcon from "./svg/refresh.svg?component";
|
||||
import SettingIcon from "./svg/settings.svg?component";
|
||||
import CollapseIcon from "./svg/collapse.svg?component";
|
||||
|
||||
const props = {
|
||||
// 头部最左边的标题
|
||||
/** 头部最左边的标题 */
|
||||
title: {
|
||||
type: String,
|
||||
default: "列表"
|
||||
},
|
||||
// 表格数据
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// 对于树形表格,如果想启用展开和折叠功能,传入当前表格的ref即可
|
||||
/** 对于树形表格,如果想启用展开和折叠功能,传入当前表格的ref即可 */
|
||||
tableRef: {
|
||||
type: Object as PropType<any>,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
// 是否显示加载动画,默认false 不加载
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
type: Object as PropType<any>
|
||||
}
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: "TableProBar",
|
||||
name: "PureTableBar",
|
||||
props,
|
||||
emits: ["refresh"],
|
||||
setup(props, { emit, slots, attrs }) {
|
||||
@@ -57,6 +27,7 @@ export default defineComponent({
|
||||
const checkList = ref([]);
|
||||
const size = ref("default");
|
||||
const isExpandAll = ref(true);
|
||||
const loading = ref(false);
|
||||
|
||||
const getDropdownItemStyle = computed(() => {
|
||||
return s => {
|
||||
@@ -68,9 +39,26 @@ export default defineComponent({
|
||||
};
|
||||
});
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return [
|
||||
"text-black",
|
||||
"dark:text-white",
|
||||
"duration-100",
|
||||
"hover:!text-primary",
|
||||
"cursor-pointer",
|
||||
"outline-none"
|
||||
];
|
||||
});
|
||||
|
||||
function onReFresh() {
|
||||
loading.value = true;
|
||||
emit("refresh");
|
||||
delay(500).then(() => (loading.value = false));
|
||||
}
|
||||
|
||||
function onExpand() {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
toggleRowExpansionAll(props.dataList, isExpandAll.value);
|
||||
toggleRowExpansionAll(props.tableRef.data, isExpandAll.value);
|
||||
}
|
||||
|
||||
function toggleRowExpansionAll(data, isExpansion) {
|
||||
@@ -89,7 +77,7 @@ export default defineComponent({
|
||||
style={getDropdownItemStyle.value("large")}
|
||||
onClick={() => (size.value = "large")}
|
||||
>
|
||||
松散
|
||||
宽松
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
style={getDropdownItemStyle.value("default")}
|
||||
@@ -109,11 +97,8 @@ export default defineComponent({
|
||||
|
||||
const reference = {
|
||||
reference: () => (
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer"
|
||||
icon={Setting}
|
||||
width="16"
|
||||
color="text_color_regular"
|
||||
<SettingIcon
|
||||
class={["w-[16px]", iconClass.value]}
|
||||
onMouseover={e => (buttonRef.value = e.currentTarget)}
|
||||
/>
|
||||
)
|
||||
@@ -121,13 +106,7 @@ export default defineComponent({
|
||||
|
||||
return () => (
|
||||
<>
|
||||
<div
|
||||
{...attrs}
|
||||
class="w-[99/100] mt-6 p-2 bg-bg_color"
|
||||
v-loading={props.loading}
|
||||
element-loading-svg={loadingSvg}
|
||||
element-loading-svg-view-box="-10, -10, 50, 50"
|
||||
>
|
||||
<div {...attrs} class="w-[99/100] mt-6 p-2 bg-bg_color">
|
||||
<div class="flex justify-between w-full h-[60px] p-4">
|
||||
<p class="font-bold truncate">{props.title}</p>
|
||||
<div class="flex items-center justify-around">
|
||||
@@ -139,36 +118,32 @@ export default defineComponent({
|
||||
content={isExpandAll.value ? "折叠" : "展开"}
|
||||
placement="top"
|
||||
>
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer"
|
||||
icon={isExpandAll.value ? UnExpand : Expand}
|
||||
width="16"
|
||||
color="text_color_regular"
|
||||
<ExpandIcon
|
||||
class={["w-[16px]", iconClass.value]}
|
||||
style={{
|
||||
transform: isExpandAll.value ? "none" : "rotate(-90deg)"
|
||||
}}
|
||||
onClick={() => onExpand()}
|
||||
/>
|
||||
</el-tooltip>
|
||||
<el-divider direction="vertical" />
|
||||
</>
|
||||
) : undefined}
|
||||
) : null}
|
||||
<el-tooltip effect="dark" content="刷新" placement="top">
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer"
|
||||
icon={RefreshRight}
|
||||
width="16"
|
||||
color="text_color_regular"
|
||||
onClick={() => emit("refresh")}
|
||||
<RefreshIcon
|
||||
class={[
|
||||
"w-[16px]",
|
||||
iconClass.value,
|
||||
loading.value ? "animate-spin" : ""
|
||||
]}
|
||||
onClick={() => onReFresh()}
|
||||
/>
|
||||
</el-tooltip>
|
||||
<el-divider direction="vertical" />
|
||||
|
||||
<el-tooltip effect="dark" content="密度" placement="top">
|
||||
<el-dropdown v-slots={dropdown} trigger="click">
|
||||
<IconifyIconOffline
|
||||
class="cursor-pointer"
|
||||
icon={ArrowCollapse}
|
||||
width="16"
|
||||
color="text_color_regular"
|
||||
/>
|
||||
<CollapseIcon class={["w-[16px]", iconClass.value]} />
|
||||
</el-dropdown>
|
||||
</el-tooltip>
|
||||
<el-divider direction="vertical" />
|
||||
@@ -200,11 +175,7 @@ export default defineComponent({
|
||||
content="列设置"
|
||||
/>
|
||||
</div>
|
||||
{props.dataList.length > 0 ? (
|
||||
slots.default({ size: size.value, checkList: checkList.value })
|
||||
) : (
|
||||
<el-empty description="暂无数据" />
|
||||
)}
|
||||
{slots.default({ size: size.value, checkList: checkList.value })}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
1
src/components/RePureTableBar/src/svg/collapse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M13.79 10.21a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42l-2.5-2.5a1 1 0 0 0-.33-.21 1 1 0 0 0-.76 0 1 1 0 0 0-.33.21l-2.5 2.5a1 1 0 0 0 1.42 1.42l.79-.8v5.18l-.79-.8a1 1 0 0 0-1.42 1.42l2.5 2.5a1 1 0 0 0 .33.21.94.94 0 0 0 .76 0 1 1 0 0 0 .33-.21l2.5-2.5a1 1 0 0 0-1.42-1.42l-.79.8V9.41ZM7 4h10a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2Zm10 16H7a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2Z"/></svg>
|
||||
|
After Width: | Height: | Size: 441 B |
1
src/components/RePureTableBar/src/svg/expand.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M22 4V2H2v2h9v14.17l-5.5-5.5-1.42 1.41L12 22l7.92-7.92-1.42-1.41-5.5 5.5V4h9Z"/></svg>
|
||||
|
After Width: | Height: | Size: 163 B |
1
src/components/RePureTableBar/src/svg/refresh.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 11A8.1 8.1 0 0 0 4.5 9M4 5v4h4m-4 4a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"/></svg>
|
||||
|
After Width: | Height: | Size: 235 B |
1
src/components/RePureTableBar/src/svg/settings.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M3.34 17a10.018 10.018 0 0 1-.978-2.326 3 3 0 0 0 .002-5.347A9.99 9.99 0 0 1 4.865 4.99a3 3 0 0 0 4.631-2.674 9.99 9.99 0 0 1 5.007.002 3 3 0 0 0 4.632 2.672A9.99 9.99 0 0 1 20.66 7c.433.749.757 1.53.978 2.326a3 3 0 0 0-.002 5.347 9.99 9.99 0 0 1-2.501 4.337 3 3 0 0 0-4.631 2.674 9.99 9.99 0 0 1-5.007-.002 3 3 0 0 0-4.632-2.672A10.018 10.018 0 0 1 3.34 17zm5.66.196a4.993 4.993 0 0 1 2.25 2.77c.499.047 1 .048 1.499.001A4.993 4.993 0 0 1 15 17.197a4.993 4.993 0 0 1 3.525-.565c.29-.408.54-.843.748-1.298A4.993 4.993 0 0 1 18 12c0-1.26.47-2.437 1.273-3.334a8.126 8.126 0 0 0-.75-1.298A4.993 4.993 0 0 1 15 6.804a4.993 4.993 0 0 1-2.25-2.77c-.499-.047-1-.048-1.499-.001A4.993 4.993 0 0 1 9 6.803a4.993 4.993 0 0 1-3.525.565 7.99 7.99 0 0 0-.748 1.298A4.993 4.993 0 0 1 6 12a4.99 4.99 0 0 1-1.273 3.334 8.126 8.126 0 0 0 .75 1.298A4.993 4.993 0 0 1 9 17.196zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg>
|
||||
|
After Width: | Height: | Size: 1011 B |
@@ -8,10 +8,8 @@ import {
|
||||
defineComponent
|
||||
} from "vue";
|
||||
import "./index.scss";
|
||||
import { cloneDeep } from "lodash-unified";
|
||||
import { isString } from "@pureadmin/utils";
|
||||
import { propTypes } from "@/utils/propTypes";
|
||||
import { IconifyIconOffline } from "../../ReIcon";
|
||||
import { isString, cloneDeep } from "@pureadmin/utils";
|
||||
import QRCode, { QRCodeRenderersOptions } from "qrcode";
|
||||
import RefreshRight from "@iconify-icons/ep/refresh-right";
|
||||
|
||||
@@ -98,7 +96,7 @@ export default defineComponent({
|
||||
width: props.width,
|
||||
...options
|
||||
});
|
||||
(unref(wrapRef) as HTMLImageElement).src = url;
|
||||
(unref(wrapRef) as any).src = url;
|
||||
emit("done", url);
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -246,7 +244,7 @@ export default defineComponent({
|
||||
onClick={disabledClick}
|
||||
>
|
||||
<div class="absolute top-[50%] left-[50%] font-bold">
|
||||
<IconifyIconOffline
|
||||
<iconify-icon-offline
|
||||
class="cursor-pointer"
|
||||
icon={RefreshRight}
|
||||
width="30"
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import tableProBar from "./src/bar";
|
||||
import { withInstall } from "@pureadmin/utils";
|
||||
|
||||
/** table-crud组件 */
|
||||
export const TableProBar = withInstall(tableProBar);
|
||||
@@ -1,9 +1,8 @@
|
||||
import { App } from "vue";
|
||||
import axios from "axios";
|
||||
import { loadEnv } from "@build/index";
|
||||
|
||||
let config: object = {};
|
||||
const { VITE_PUBLIC_PATH } = loadEnv();
|
||||
const { VITE_PUBLIC_PATH } = import.meta.env;
|
||||
|
||||
const setConfig = (cfg?: unknown) => {
|
||||
config = Object.assign(config, cfg);
|
||||
|
||||
@@ -5,7 +5,7 @@ export const auth: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
const { value } = binding;
|
||||
if (value) {
|
||||
!hasAuth(value) && el.parentNode.removeChild(el);
|
||||
!hasAuth(value) && el.parentNode?.removeChild(el);
|
||||
} else {
|
||||
throw new Error("need auths! Like v-auth=\"['btn.add','btn.edit']\"");
|
||||
}
|
||||
|
||||
@@ -70,14 +70,8 @@ notices.value.map(v => (noticesNum.value += v.list.length));
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
// 如果上面的 notices 长度大于 3 请注释掉下面代码
|
||||
:deep(.el-tabs__nav-wrap) {
|
||||
padding: 0 36px 0 36px;
|
||||
}
|
||||
|
||||
// 如果上面的 notices 长度大于 3 请注释掉下面代码
|
||||
:deep(.el-tabs__active-bar) {
|
||||
margin: 0 36px 0 36px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ListItem } from "./data";
|
||||
import { ref, PropType, nextTick } from "vue";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
|
||||
const props = defineProps({
|
||||
noticeItem: {
|
||||
@@ -13,6 +14,7 @@ const titleRef = ref(null);
|
||||
const titleTooltip = ref(false);
|
||||
const descriptionRef = ref(null);
|
||||
const descriptionTooltip = ref(false);
|
||||
const { tooltipEffect } = useNav();
|
||||
|
||||
function hoverTitle() {
|
||||
nextTick(() => {
|
||||
@@ -57,6 +59,7 @@ function hoverDescription(event, description) {
|
||||
<div class="notice-text-title text-[#000000d9] dark:text-white">
|
||||
<el-tooltip
|
||||
popper-class="notice-title-popper"
|
||||
:effect="tooltipEffect"
|
||||
:disabled="!titleTooltip"
|
||||
:content="props.noticeItem.title"
|
||||
placement="top-start"
|
||||
@@ -81,6 +84,7 @@ function hoverDescription(event, description) {
|
||||
|
||||
<el-tooltip
|
||||
popper-class="notice-title-popper"
|
||||
:effect="tooltipEffect"
|
||||
:disabled="!descriptionTooltip"
|
||||
:content="props.noticeItem.description"
|
||||
placement="top-start"
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { onClickOutside } from "@vueuse/core";
|
||||
import { ref, computed } from "vue";
|
||||
import { emitter } from "@/utils/mitt";
|
||||
import { onClickOutside } from "@vueuse/core";
|
||||
import Close from "@iconify-icons/ep/close";
|
||||
|
||||
const show = ref<Boolean>(false);
|
||||
const target = ref(null);
|
||||
const show = ref<Boolean>(false);
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return [
|
||||
"mr-[20px]",
|
||||
"outline-none",
|
||||
"width-[20px]",
|
||||
"height-[20px]",
|
||||
"rounded-[4px]",
|
||||
"cursor-pointer",
|
||||
"transition-colors",
|
||||
"hover:bg-[#0000000f]",
|
||||
"dark:hover:bg-[#ffffff1f]",
|
||||
"dark:hover:text-[#ffffffd9]"
|
||||
];
|
||||
});
|
||||
|
||||
onClickOutside(target, (event: any) => {
|
||||
if (event.clientX > target.value.offsetLeft) return;
|
||||
show.value = false;
|
||||
@@ -23,9 +39,11 @@ emitter.on("openPanel", () => {
|
||||
<div class="right-panel-items">
|
||||
<div class="project-configuration">
|
||||
<h4 class="dark:text-white">项目配置</h4>
|
||||
<span title="关闭配置">
|
||||
<span title="关闭配置" :class="iconClass">
|
||||
<IconifyIconOffline
|
||||
class="dark:text-white"
|
||||
width="20px"
|
||||
height="20px"
|
||||
:icon="Close"
|
||||
@click="show = !show"
|
||||
/>
|
||||
@@ -69,7 +87,6 @@ emitter.on("openPanel", () => {
|
||||
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
|
||||
transform: translate(100%);
|
||||
// background: #fff;
|
||||
z-index: 40000;
|
||||
}
|
||||
|
||||
@@ -125,16 +142,6 @@ emitter.on("openPanel", () => {
|
||||
align-items: center;
|
||||
top: 15px;
|
||||
margin-left: 10px;
|
||||
|
||||
svg {
|
||||
font-size: 20px;
|
||||
margin-right: 20px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-divider--horizontal) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import { cloneDeep } from "lodash-unified";
|
||||
import { cloneDeep } from "@pureadmin/utils";
|
||||
import SearchResult from "./SearchResult.vue";
|
||||
import SearchFooter from "./SearchFooter.vue";
|
||||
import { deleteChildren } from "@/utils/tree";
|
||||
|
||||
@@ -6,8 +6,15 @@ import {
|
||||
reactive,
|
||||
computed,
|
||||
nextTick,
|
||||
useCssModule
|
||||
onBeforeMount
|
||||
} from "vue";
|
||||
import {
|
||||
useDark,
|
||||
debounce,
|
||||
useGlobal,
|
||||
storageLocal,
|
||||
storageSession
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { useRouter } from "vue-router";
|
||||
import panel from "../panel/index.vue";
|
||||
@@ -17,16 +24,9 @@ import { removeToken } from "@/utils/auth";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
import { useAppStoreHook } from "@/store/modules/app";
|
||||
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
|
||||
import {
|
||||
useDark,
|
||||
debounce,
|
||||
useGlobal,
|
||||
storageLocal,
|
||||
storageSession
|
||||
} from "@pureadmin/utils";
|
||||
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
|
||||
|
||||
import dayIcon from "@/assets/svg/day.svg?component";
|
||||
import darkIcon from "@/assets/svg/dark.svg?component";
|
||||
@@ -34,9 +34,8 @@ import Check from "@iconify-icons/ep/check";
|
||||
import Logout from "@iconify-icons/ri/logout-circle-r-line";
|
||||
|
||||
const router = useRouter();
|
||||
const { device } = useNav();
|
||||
const { isDark } = useDark();
|
||||
const { isSelect } = useCssModule();
|
||||
const { device, tooltipEffect } = useNav();
|
||||
const { $storage } = useGlobal<GlobalPropertiesApi>();
|
||||
|
||||
const mixRef = ref();
|
||||
@@ -133,8 +132,8 @@ const multiTagsCacheChange = () => {
|
||||
/** 清空缓存并返回登录页 */
|
||||
function onReset() {
|
||||
removeToken();
|
||||
storageLocal.clear();
|
||||
storageSession.clear();
|
||||
storageLocal().clear();
|
||||
storageSession().clear();
|
||||
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
|
||||
useAppStoreHook().setLayout(Layout);
|
||||
setEpThemeColor(EpThemeColor);
|
||||
@@ -161,30 +160,10 @@ function logoChange() {
|
||||
|
||||
function setFalse(Doms): any {
|
||||
Doms.forEach(v => {
|
||||
toggleClass(false, isSelect, unref(v));
|
||||
toggleClass(false, "is-select", unref(v));
|
||||
});
|
||||
}
|
||||
|
||||
watch($storage, ({ layout }) => {
|
||||
switch (layout["layout"]) {
|
||||
case "vertical":
|
||||
toggleClass(true, isSelect, unref(verticalRef));
|
||||
debounce(setFalse([horizontalRef]), 50);
|
||||
debounce(setFalse([mixRef]), 50);
|
||||
break;
|
||||
case "horizontal":
|
||||
toggleClass(true, isSelect, unref(horizontalRef));
|
||||
debounce(setFalse([verticalRef]), 50);
|
||||
debounce(setFalse([mixRef]), 50);
|
||||
break;
|
||||
case "mix":
|
||||
toggleClass(true, isSelect, unref(mixRef));
|
||||
debounce(setFalse([verticalRef]), 50);
|
||||
debounce(setFalse([horizontalRef]), 50);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
/** 主题色 激活选择项 */
|
||||
const getThemeColor = computed(() => {
|
||||
return current => {
|
||||
@@ -218,14 +197,36 @@ function setLayoutModel(layout: string) {
|
||||
useAppStoreHook().setLayout(layout);
|
||||
}
|
||||
|
||||
/* 初始化项目配置 */
|
||||
nextTick(() => {
|
||||
settings.greyVal &&
|
||||
document.querySelector("html")?.setAttribute("class", "html-grey");
|
||||
settings.weakVal &&
|
||||
document.querySelector("html")?.setAttribute("class", "html-weakness");
|
||||
settings.tabsVal && tagsChange();
|
||||
watch($storage, ({ layout }) => {
|
||||
switch (layout["layout"]) {
|
||||
case "vertical":
|
||||
toggleClass(true, "is-select", unref(verticalRef));
|
||||
debounce(setFalse([horizontalRef]), 50);
|
||||
debounce(setFalse([mixRef]), 50);
|
||||
break;
|
||||
case "horizontal":
|
||||
toggleClass(true, "is-select", unref(horizontalRef));
|
||||
debounce(setFalse([verticalRef]), 50);
|
||||
debounce(setFalse([mixRef]), 50);
|
||||
break;
|
||||
case "mix":
|
||||
toggleClass(true, "is-select", unref(mixRef));
|
||||
debounce(setFalse([verticalRef]), 50);
|
||||
debounce(setFalse([horizontalRef]), 50);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
dataThemeChange();
|
||||
/* 初始化项目配置 */
|
||||
nextTick(() => {
|
||||
settings.greyVal &&
|
||||
document.querySelector("html")?.setAttribute("class", "html-grey");
|
||||
settings.weakVal &&
|
||||
document.querySelector("html")?.setAttribute("class", "html-weakness");
|
||||
settings.tabsVal && tagsChange();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -243,9 +244,15 @@ nextTick(() => {
|
||||
|
||||
<el-divider>导航栏模式</el-divider>
|
||||
<ul class="pure-theme">
|
||||
<el-tooltip class="item" content="左侧模式" placement="bottom">
|
||||
<el-tooltip
|
||||
:effect="tooltipEffect"
|
||||
class="item"
|
||||
content="左侧模式"
|
||||
placement="bottom"
|
||||
popper-class="pure-tooltip"
|
||||
>
|
||||
<li
|
||||
:class="layoutTheme.layout === 'vertical' ? $style.isSelect : ''"
|
||||
:class="layoutTheme.layout === 'vertical' ? 'is-select' : ''"
|
||||
ref="verticalRef"
|
||||
@click="setLayoutModel('vertical')"
|
||||
>
|
||||
@@ -256,12 +263,14 @@ nextTick(() => {
|
||||
|
||||
<el-tooltip
|
||||
v-if="device !== 'mobile'"
|
||||
:effect="tooltipEffect"
|
||||
class="item"
|
||||
content="顶部模式"
|
||||
placement="bottom"
|
||||
popper-class="pure-tooltip"
|
||||
>
|
||||
<li
|
||||
:class="layoutTheme.layout === 'horizontal' ? $style.isSelect : ''"
|
||||
:class="layoutTheme.layout === 'horizontal' ? 'is-select' : ''"
|
||||
ref="horizontalRef"
|
||||
@click="setLayoutModel('horizontal')"
|
||||
>
|
||||
@@ -272,12 +281,14 @@ nextTick(() => {
|
||||
|
||||
<el-tooltip
|
||||
v-if="device !== 'mobile'"
|
||||
:effect="tooltipEffect"
|
||||
class="item"
|
||||
content="混合模式"
|
||||
placement="bottom"
|
||||
popper-class="pure-tooltip"
|
||||
>
|
||||
<li
|
||||
:class="layoutTheme.layout === 'mix' ? $style.isSelect : ''"
|
||||
:class="layoutTheme.layout === 'mix' ? 'is-select' : ''"
|
||||
ref="mixRef"
|
||||
@click="setLayoutModel('mix')"
|
||||
>
|
||||
@@ -392,13 +403,16 @@ nextTick(() => {
|
||||
</panel>
|
||||
</template>
|
||||
|
||||
<style scoped module>
|
||||
.isSelect {
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-divider__text) {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.is-select {
|
||||
border: 2px solid var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.setting {
|
||||
width: 100%;
|
||||
|
||||
@@ -410,11 +424,6 @@ nextTick(() => {
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-divider__text) {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.pure-datatheme {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
|
||||
@@ -97,8 +97,12 @@ watch(
|
||||
|
||||
<template>
|
||||
<el-breadcrumb class="!leading-[50px] select-none" separator="/">
|
||||
<transition-group appear name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="item in levelList" :key="item.path">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item
|
||||
class="!inline !items-stretch"
|
||||
v-for="item in levelList"
|
||||
:key="item.path"
|
||||
>
|
||||
<a @click.prevent="handleLink(item)">
|
||||
{{ transformI18n(item.meta.title) }}
|
||||
</a>
|
||||
|
||||
@@ -41,7 +41,10 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="horizontal-header">
|
||||
<div
|
||||
v-loading="usePermissionStoreHook().wholeMenus.length === 0"
|
||||
class="horizontal-header"
|
||||
>
|
||||
<div class="horizontal-header-left" @click="backHome">
|
||||
<FontIcon icon="team-iconlogo" svg style="width: 35px; height: 35px" />
|
||||
<h4>{{ title }}</h4>
|
||||
@@ -129,6 +132,10 @@ watch(
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-loading-mask) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.translation {
|
||||
::v-deep(.el-dropdown-menu__item) {
|
||||
padding: 5px 40px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useDark } from "@pureadmin/utils";
|
||||
import { ref, computed } from "vue";
|
||||
import { useNav } from "@/layout/hooks/useNav";
|
||||
import MenuFold from "@iconify-icons/ri/menu-fold-fill";
|
||||
import MenuUnfold from "@iconify-icons/ri/menu-unfold-fill";
|
||||
|
||||
interface Props {
|
||||
isActive: boolean;
|
||||
@@ -10,7 +10,25 @@ interface Props {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
isActive: false
|
||||
});
|
||||
const { isDark } = useDark();
|
||||
|
||||
const visible = ref(false);
|
||||
const { tooltipEffect } = useNav();
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return [
|
||||
"ml-4",
|
||||
"mb-1",
|
||||
"w-[16px]",
|
||||
"h-[16px]",
|
||||
"inline-block",
|
||||
"align-middle",
|
||||
"text-primary",
|
||||
"cursor-pointer",
|
||||
"duration-[360ms]",
|
||||
"hover:text-primary",
|
||||
"dark:hover:!text-white"
|
||||
];
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "toggleClick"): void;
|
||||
@@ -25,13 +43,17 @@ const toggleClick = () => {
|
||||
<div class="container">
|
||||
<el-tooltip
|
||||
placement="right"
|
||||
:effect="isDark ? 'dark' : 'light'"
|
||||
:visible="visible"
|
||||
:effect="tooltipEffect"
|
||||
:content="props.isActive ? '点击折叠' : '点击展开'"
|
||||
>
|
||||
<IconifyIconOffline
|
||||
:icon="props.isActive ? MenuFold : MenuUnfold"
|
||||
class="cursor-pointer inline-block align-middle text-primary hover:text-primary dark:hover:!text-white w-[16px] h-[16px] ml-4 mb-1"
|
||||
:icon="MenuFold"
|
||||
:class="iconClass"
|
||||
:style="{ transform: props.isActive ? 'none' : 'rotateY(180deg)' }"
|
||||
@click="toggleClick"
|
||||
@mouseenter="visible = true"
|
||||
@mouseleave="visible = false"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +58,11 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="device !== 'mobile'" class="horizontal-header">
|
||||
<div
|
||||
v-if="device !== 'mobile'"
|
||||
class="horizontal-header"
|
||||
v-loading="usePermissionStoreHook().wholeMenus.length === 0"
|
||||
>
|
||||
<el-menu
|
||||
router
|
||||
ref="menuRef"
|
||||
@@ -161,6 +165,10 @@ watch(
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-loading-mask) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.translation {
|
||||
::v-deep(.el-dropdown-menu__item) {
|
||||
padding: 5px 40px;
|
||||
|
||||
@@ -12,7 +12,7 @@ import EpArrowDown from "@iconify-icons/ep/arrow-down";
|
||||
import ArrowLeft from "@iconify-icons/ep/arrow-left";
|
||||
import ArrowRight from "@iconify-icons/ep/arrow-right";
|
||||
|
||||
const { layout, isCollapse } = useNav();
|
||||
const { layout, isCollapse, tooltipEffect } = useNav();
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
@@ -144,7 +144,8 @@ function resolvePath(routePath) {
|
||||
if (httpReg.test(routePath) || httpReg.test(props.basePath)) {
|
||||
return routePath || props.basePath;
|
||||
} else {
|
||||
return path.resolve(props.basePath, routePath);
|
||||
// 使用path.posix.resolve替代path.resolve 避免windows环境下使用electron出现盘符问题
|
||||
return path.posix.resolve(props.basePath, routePath);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -201,6 +202,7 @@ function resolvePath(routePath) {
|
||||
<el-tooltip
|
||||
v-else
|
||||
placement="top"
|
||||
:effect="tooltipEffect"
|
||||
:offset="-10"
|
||||
:disabled="!onlyOneChild.showTooltip"
|
||||
>
|
||||
@@ -246,8 +248,9 @@ function resolvePath(routePath) {
|
||||
<el-tooltip
|
||||
v-else
|
||||
placement="top"
|
||||
:effect="tooltipEffect"
|
||||
:offset="-10"
|
||||
:disabled="!isCollapse || !props.item.showTooltip"
|
||||
:disabled="!props.item.showTooltip"
|
||||
>
|
||||
<template #content>
|
||||
{{ transformI18n(props.item.meta.title) }}
|
||||
|
||||
@@ -12,7 +12,8 @@ import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
|
||||
const route = useRoute();
|
||||
const showLogo = ref(
|
||||
storageLocal.getItem<StorageConfigs>("responsive-configure")?.showLogo ?? true
|
||||
storageLocal().getItem<StorageConfigs>("responsive-configure")?.showLogo ??
|
||||
true
|
||||
);
|
||||
|
||||
const { routers, device, pureApp, isCollapse, menuSelect, toggleSideBar } =
|
||||
@@ -59,7 +60,10 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="['sidebar-container', showLogo ? 'has-logo' : '']">
|
||||
<div
|
||||
v-loading="menuData.length === 0"
|
||||
:class="['sidebar-container', showLogo ? 'has-logo' : '']"
|
||||
>
|
||||
<Logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar
|
||||
wrap-class="scrollbar-wrapper"
|
||||
@@ -91,3 +95,9 @@ watch(
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-loading-mask) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { emitter } from "@/utils/mitt";
|
||||
import { RouteConfigs } from "../../types";
|
||||
import { useTags } from "../../hooks/useTag";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { isEqual, isEmpty } from "lodash-unified";
|
||||
import { isEqual, isAllEmpty } from "@pureadmin/utils";
|
||||
import { useSettingStoreHook } from "@/store/modules/settings";
|
||||
import { ref, watch, unref, nextTick, onBeforeMount } from "vue";
|
||||
import { handleAliveRoute, delAliveRoutes } from "@/router/utils";
|
||||
@@ -349,7 +349,7 @@ function showMenuModel(
|
||||
const allRoute = multiTags.value;
|
||||
const routeLength = multiTags.value.length;
|
||||
let currentIndex = -1;
|
||||
if (isEmpty(query)) {
|
||||
if (isAllEmpty(query)) {
|
||||
currentIndex = allRoute.findIndex(v => v.path === currentPath);
|
||||
} else {
|
||||
currentIndex = allRoute.findIndex(v => isEqual(v.query, query));
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { ref } from "vue";
|
||||
import { getConfig } from "@/config";
|
||||
import { find } from "lodash-unified";
|
||||
import { useLayout } from "./useLayout";
|
||||
import { themeColorsType } from "../types";
|
||||
import { TinyColor } from "@ctrl/tinycolor";
|
||||
import { useGlobal } from "@pureadmin/utils";
|
||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
|
||||
import {
|
||||
@@ -56,35 +54,27 @@ export function useDataThemeChange() {
|
||||
if (theme === "default" || theme === "light") {
|
||||
setEpThemeColor(getConfig().EpThemeColor);
|
||||
} else {
|
||||
const colors = find(themeColors.value, { themeColor: theme });
|
||||
const colors = themeColors.value.find(v => v.themeColor === theme);
|
||||
setEpThemeColor(colors.color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 自动计算hover和active颜色
|
||||
* @see {@link https://element-plus.org/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2}
|
||||
*/
|
||||
const shadeBgColor = (color: string): string => {
|
||||
return new TinyColor(color).shade(10).toString();
|
||||
};
|
||||
function setPropertyPrimary(mode: string, i: number, color: string) {
|
||||
document.documentElement.style.setProperty(
|
||||
`--el-color-primary-${mode}-${i}`,
|
||||
dataTheme.value ? darken(color, i / 10) : lighten(color, i / 10)
|
||||
);
|
||||
}
|
||||
|
||||
/** 设置 `element-plus` 主题色 */
|
||||
const setEpThemeColor = (color: string) => {
|
||||
useEpThemeStoreHook().setEpThemeColor(color);
|
||||
body.style.setProperty("--el-color-primary-active", shadeBgColor(color));
|
||||
document.documentElement.style.setProperty("--el-color-primary", color);
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
document.documentElement.style.setProperty(
|
||||
`--el-color-primary-light-${i}`,
|
||||
lighten(color, i / 10)
|
||||
);
|
||||
}
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
document.documentElement.style.setProperty(
|
||||
`--el-color-primary-dark-${i}`,
|
||||
darken(color, i / 10)
|
||||
);
|
||||
setPropertyPrimary("dark", i, color);
|
||||
}
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
setPropertyPrimary("light", i, color);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ export function useNav() {
|
||||
const pureApp = useAppStoreHook();
|
||||
const routers = useRouter().options.routes;
|
||||
const { wholeMenus } = storeToRefs(usePermissionStoreHook());
|
||||
/** 平台`layout`中所有`el-tooltip`的`effect`配置,默认`light` */
|
||||
const tooltipEffect = getConfig()?.TooltipEffect ?? "light";
|
||||
|
||||
/** 用户名 */
|
||||
const username = computed(() => {
|
||||
@@ -153,6 +155,7 @@ export function useNav() {
|
||||
pureApp,
|
||||
username,
|
||||
avatarsStyle,
|
||||
tooltipEffect,
|
||||
getDropdownItemStyle,
|
||||
getDropdownItemClass
|
||||
};
|
||||
|
||||
@@ -41,13 +41,13 @@ export function useTags() {
|
||||
|
||||
/** 显示模式,默认灵动模式 */
|
||||
const showModel = ref(
|
||||
storageLocal.getItem<StorageConfigs>("responsive-configure")?.showModel ||
|
||||
storageLocal().getItem<StorageConfigs>("responsive-configure")?.showModel ||
|
||||
"smart"
|
||||
);
|
||||
/** 是否隐藏标签页,默认显示 */
|
||||
const showTags =
|
||||
ref(
|
||||
storageLocal.getItem<StorageConfigs>("responsive-configure").hideTabs
|
||||
storageLocal().getItem<StorageConfigs>("responsive-configure").hideTabs
|
||||
) ?? ref("false");
|
||||
const multiTags: any = computed(() => {
|
||||
return useMultiTagsStoreHook().multiTags;
|
||||
@@ -195,11 +195,11 @@ export function useTags() {
|
||||
|
||||
onMounted(() => {
|
||||
if (!showModel.value) {
|
||||
const configure = storageLocal.getItem<StorageConfigs>(
|
||||
const configure = storageLocal().getItem<StorageConfigs>(
|
||||
"responsive-configure"
|
||||
);
|
||||
configure.showModel = "card";
|
||||
storageLocal.setItem("responsive-configure", configure);
|
||||
storageLocal().setItem("responsive-configure", configure);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import "animate.css";
|
||||
// 引入 src/components/ReIcon/src/offlineIcon.ts 文件中所有使用addIcon添加过的本地图标
|
||||
import "@/components/ReIcon/src/offlineIcon";
|
||||
import { setType } from "./types";
|
||||
import { emitter } from "@/utils/mitt";
|
||||
import { useLayout } from "./hooks/useLayout";
|
||||
|
||||
@@ -2,19 +2,11 @@
|
||||
* @description ⚠️:此文件仅供主题插件使用,请不要在此文件中导出别的工具函数(仅在页面加载前运行)
|
||||
*/
|
||||
|
||||
import { EpThemeColor } from "../../../public/serverConfig.json";
|
||||
import { type multipleScopeVarsOptions } from "@pureadmin/theme";
|
||||
|
||||
type MultipleScopeVarsItem = {
|
||||
scopeName: string;
|
||||
varsContent: string;
|
||||
};
|
||||
|
||||
/** 将vxe默认主题色和ep默认主题色保持一致 */
|
||||
const vxeColor = EpThemeColor;
|
||||
/** 预设主题色 */
|
||||
const themeColors = {
|
||||
default: {
|
||||
vxeColor,
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#001529",
|
||||
menuHover: "#4091f7",
|
||||
@@ -26,7 +18,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#4091f7"
|
||||
},
|
||||
light: {
|
||||
vxeColor,
|
||||
subMenuActiveText: "#409eff",
|
||||
menuBg: "#fff",
|
||||
menuHover: "#e0ebf6",
|
||||
@@ -38,7 +29,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#4091f7"
|
||||
},
|
||||
dusk: {
|
||||
vxeColor: "#f5222d",
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#2a0608",
|
||||
menuHover: "#e13c39",
|
||||
@@ -50,7 +40,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#e13c39"
|
||||
},
|
||||
volcano: {
|
||||
vxeColor: "#fa541c",
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#2b0e05",
|
||||
menuHover: "#e85f33",
|
||||
@@ -62,7 +51,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#e85f33"
|
||||
},
|
||||
yellow: {
|
||||
vxeColor: "#fadb14",
|
||||
subMenuActiveText: "#d25f00",
|
||||
menuBg: "#2b2503",
|
||||
menuHover: "#f6da4d",
|
||||
@@ -74,7 +62,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#f6da4d"
|
||||
},
|
||||
mingQing: {
|
||||
vxeColor: "#13c2c2",
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#032121",
|
||||
menuHover: "#59bfc1",
|
||||
@@ -86,7 +73,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#59bfc1"
|
||||
},
|
||||
auroraGreen: {
|
||||
vxeColor: "#52c41a",
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#0b1e15",
|
||||
menuHover: "#60ac80",
|
||||
@@ -98,7 +84,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#60ac80"
|
||||
},
|
||||
pink: {
|
||||
vxeColor: "#eb2f96",
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#28081a",
|
||||
menuHover: "#d84493",
|
||||
@@ -110,7 +95,6 @@ const themeColors = {
|
||||
menuActiveBefore: "#d84493"
|
||||
},
|
||||
saucePurple: {
|
||||
vxeColor: "#722ed1",
|
||||
subMenuActiveText: "#fff",
|
||||
menuBg: "#130824",
|
||||
menuHover: "#693ac9",
|
||||
@@ -126,13 +110,12 @@ const themeColors = {
|
||||
/**
|
||||
* @description 将预设主题色处理成主题插件所需格式
|
||||
*/
|
||||
export const genScssMultipleScopeVars = (): MultipleScopeVarsItem[] => {
|
||||
const result = [] as MultipleScopeVarsItem[];
|
||||
export const genScssMultipleScopeVars = (): multipleScopeVarsOptions[] => {
|
||||
const result = [] as multipleScopeVarsOptions[];
|
||||
Object.keys(themeColors).forEach(key => {
|
||||
result.push({
|
||||
scopeName: `layout-theme-${key}`,
|
||||
varsContent: `
|
||||
$vxe-primary-color: ${themeColors[key].vxeColor} !default;
|
||||
$subMenuActiveText: ${themeColors[key].subMenuActiveText} !default;
|
||||
$menuBg: ${themeColors[key].menuBg} !default;
|
||||
$menuHover: ${themeColors[key].menuHover} !default;
|
||||
@@ -143,7 +126,7 @@ export const genScssMultipleScopeVars = (): MultipleScopeVarsItem[] => {
|
||||
$menuTitleHover: ${themeColors[key].menuTitleHover} !default;
|
||||
$menuActiveBefore: ${themeColors[key].menuActiveBefore} !default;
|
||||
`
|
||||
} as MultipleScopeVarsItem);
|
||||
} as multipleScopeVarsOptions);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { IconifyIcon } from "@iconify/vue";
|
||||
import HomeFilled from "@iconify-icons/ep/home-filled";
|
||||
|
||||
export const routerArrays: Array<RouteConfigs> = [
|
||||
{
|
||||
@@ -7,7 +6,7 @@ export const routerArrays: Array<RouteConfigs> = [
|
||||
parentPath: "/",
|
||||
meta: {
|
||||
title: "menus.hshome",
|
||||
icon: HomeFilled
|
||||
icon: "homeFilled"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -7,7 +7,6 @@ import { getServerConfig } from "./config";
|
||||
import { createApp, Directive } from "vue";
|
||||
import { MotionPlugin } from "@vueuse/motion";
|
||||
import { useEcharts } from "@/plugins/echarts";
|
||||
import { useTable } from "@/plugins/vxe-table";
|
||||
import { injectResponsiveStorage } from "@/utils/responsive";
|
||||
|
||||
import Table from "@pureadmin/table";
|
||||
@@ -17,6 +16,8 @@ import PureDescriptions from "@pureadmin/descriptions";
|
||||
import "./style/reset.scss";
|
||||
// 导入公共样式
|
||||
import "./style/index.scss";
|
||||
// 一定要在main.ts中导入tailwind.css,防止vite每次hmr都会请求src/style/index.scss整体css文件导致热更新慢的问题
|
||||
import "./style/tailwind.css";
|
||||
import "element-plus/dist/index.css";
|
||||
// 导入字体图标
|
||||
import "./assets/iconfont/iconfont.js";
|
||||
@@ -55,7 +56,6 @@ getServerConfig(app).then(async config => {
|
||||
.use(ElementPlus)
|
||||
.use(Table)
|
||||
.use(PureDescriptions)
|
||||
.use(useTable)
|
||||
.use(useEcharts);
|
||||
app.mount("#app");
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ export const $t = (key: string) => key;
|
||||
export const i18n: I18n = createI18n({
|
||||
legacy: false,
|
||||
locale:
|
||||
storageLocal.getItem<StorageConfigs>("responsive-locale")?.locale ?? "zh",
|
||||
storageLocal().getItem<StorageConfigs>("responsive-locale")?.locale ?? "zh",
|
||||
fallbackLocale: "en",
|
||||
messages: localesConfigs
|
||||
});
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
@import "vxe-table/styles/variable.scss";
|
||||
@import "vxe-table/styles/modules.scss";
|
||||
|
||||
i {
|
||||
border-color: initial;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import "xe-utils";
|
||||
import "./index.scss";
|
||||
import XEUtils from "xe-utils";
|
||||
import { App, unref } from "vue";
|
||||
import { i18n } from "@/plugins/i18n";
|
||||
import "font-awesome/css/font-awesome.min.css";
|
||||
import zh from "vxe-table/lib/locale/lang/zh-CN";
|
||||
import en from "vxe-table/lib/locale/lang/en-US";
|
||||
|
||||
import {
|
||||
// 核心
|
||||
VXETable,
|
||||
// 表格功能
|
||||
Icon,
|
||||
Filter,
|
||||
Edit,
|
||||
Menu,
|
||||
Export,
|
||||
Keyboard,
|
||||
Validator,
|
||||
// 可选组件
|
||||
Column,
|
||||
Colgroup,
|
||||
Grid,
|
||||
Tooltip,
|
||||
Toolbar,
|
||||
Pager,
|
||||
Form,
|
||||
FormItem,
|
||||
FormGather,
|
||||
Checkbox,
|
||||
CheckboxGroup,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
RadioButton,
|
||||
Switch,
|
||||
Input,
|
||||
Select,
|
||||
Optgroup,
|
||||
Option,
|
||||
Textarea,
|
||||
Button,
|
||||
Modal,
|
||||
List,
|
||||
Pulldown,
|
||||
// 表格
|
||||
Table
|
||||
} from "vxe-table";
|
||||
|
||||
// 全局默认参数
|
||||
VXETable.setup({
|
||||
size: "medium",
|
||||
version: 0,
|
||||
zIndex: 1002,
|
||||
table: {
|
||||
// 自动监听父元素的变化去重新计算表格
|
||||
autoResize: true,
|
||||
// 鼠标移到行是否要高亮显示
|
||||
highlightHoverRow: true
|
||||
},
|
||||
input: {
|
||||
clearable: true
|
||||
},
|
||||
i18n: (key, args) => {
|
||||
return unref(i18n.global.locale) === "zh"
|
||||
? XEUtils.toFormatString(XEUtils.get(zh, key), args)
|
||||
: XEUtils.toFormatString(XEUtils.get(en, key), args);
|
||||
},
|
||||
translate(key) {
|
||||
const NAMESPACED = ["el.", "buttons."];
|
||||
if (key && NAMESPACED.findIndex(v => key.includes(v)) !== -1) {
|
||||
return i18n.global.t.call(i18n.global.locale, key);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
export function useTable(app: App) {
|
||||
app
|
||||
.use(Icon)
|
||||
.use(Filter)
|
||||
.use(Edit)
|
||||
.use(Menu)
|
||||
.use(Export)
|
||||
.use(Keyboard)
|
||||
.use(Validator)
|
||||
// 可选组件
|
||||
.use(Column)
|
||||
.use(Colgroup)
|
||||
.use(Grid)
|
||||
.use(Tooltip)
|
||||
.use(Toolbar)
|
||||
.use(Pager)
|
||||
.use(Form)
|
||||
.use(FormItem)
|
||||
.use(FormGather)
|
||||
.use(Checkbox)
|
||||
.use(CheckboxGroup)
|
||||
.use(Radio)
|
||||
.use(RadioGroup)
|
||||
.use(RadioButton)
|
||||
.use(Switch)
|
||||
.use(Input)
|
||||
.use(Select)
|
||||
.use(Optgroup)
|
||||
.use(Option)
|
||||
.use(Textarea)
|
||||
.use(Button)
|
||||
.use(Modal)
|
||||
.use(List)
|
||||
.use(Pulldown)
|
||||
// 安装表格
|
||||
.use(Table);
|
||||
}
|
||||
@@ -4,16 +4,16 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以
|
||||
doc = 1,
|
||||
utils = 2,
|
||||
table = 3,
|
||||
tree = 4,
|
||||
components = 5,
|
||||
able = 6,
|
||||
frame = 7,
|
||||
nested = 8,
|
||||
result = 9,
|
||||
error = 10,
|
||||
list = 11,
|
||||
permission = 12,
|
||||
system = 13,
|
||||
components = 4,
|
||||
able = 5,
|
||||
frame = 6,
|
||||
nested = 7,
|
||||
result = 8,
|
||||
error = 9,
|
||||
list = 10,
|
||||
permission = 11,
|
||||
system = 12,
|
||||
menuoverflow = 13,
|
||||
tabs = 14,
|
||||
formdesign = 15,
|
||||
flowchart = 16,
|
||||
@@ -27,7 +27,6 @@ export {
|
||||
doc,
|
||||
utils,
|
||||
table,
|
||||
tree,
|
||||
components,
|
||||
able,
|
||||
frame,
|
||||
@@ -37,6 +36,7 @@ export {
|
||||
list,
|
||||
permission,
|
||||
system,
|
||||
menuoverflow,
|
||||
tabs,
|
||||
formdesign,
|
||||
flowchart,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import "@/utils/sso";
|
||||
import { getConfig } from "@/config";
|
||||
import NProgress from "@/utils/progress";
|
||||
import { findIndex } from "lodash-unified";
|
||||
import { transformI18n } from "@/plugins/i18n";
|
||||
import { sessionKey, type DataInfo } from "@/utils/auth";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
@@ -106,7 +105,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
||||
handleAliveRoute(newMatched);
|
||||
}
|
||||
}
|
||||
const userInfo = storageSession.getItem<DataInfo<number>>(sessionKey);
|
||||
const userInfo = storageSession().getItem<DataInfo<number>>(sessionKey);
|
||||
NProgress.start();
|
||||
const externalLink = isUrl(to?.name as string);
|
||||
if (!externalLink) {
|
||||
@@ -144,14 +143,10 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
||||
initRouter().then((router: Router) => {
|
||||
if (!useMultiTagsStoreHook().getMultiTagsCache) {
|
||||
const { path } = to;
|
||||
const index = findIndex(remainingRouter, v => {
|
||||
return v.path == path;
|
||||
});
|
||||
const routes: any =
|
||||
index === -1
|
||||
? router.options.routes[0].children
|
||||
: router.options.routes;
|
||||
const route = findRouteByPath(path, routes);
|
||||
const route = findRouteByPath(
|
||||
path,
|
||||
router.options.routes[0].children
|
||||
);
|
||||
// query、params模式路由传参数的标签页不在此处处理
|
||||
if (route && route.meta?.title) {
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { able } from "@/router/enums";
|
||||
import UbuntuFill from "@iconify-icons/ri/ubuntu-fill";
|
||||
|
||||
export default {
|
||||
path: "/able",
|
||||
redirect: "/able/watermark",
|
||||
meta: {
|
||||
icon: UbuntuFill,
|
||||
icon: "ubuntuFill",
|
||||
title: $t("menus.hsAble"),
|
||||
rank: able
|
||||
},
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { components } from "@/router/enums";
|
||||
import Menu from "@iconify-icons/ep/menu";
|
||||
|
||||
export default {
|
||||
path: "/components",
|
||||
redirect: "/components/video",
|
||||
meta: {
|
||||
icon: Menu,
|
||||
icon: "menu",
|
||||
title: $t("menus.hscomponents"),
|
||||
rank: components
|
||||
},
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { editor } from "@/router/enums";
|
||||
import Edit from "@iconify-icons/ep/edit";
|
||||
|
||||
export default {
|
||||
path: "/editor",
|
||||
redirect: "/editor/index",
|
||||
meta: {
|
||||
icon: Edit,
|
||||
icon: "edit",
|
||||
title: $t("menus.hseditor"),
|
||||
rank: editor
|
||||
},
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { error } from "@/router/enums";
|
||||
import InformationLine from "@iconify-icons/ri/information-line";
|
||||
|
||||
export default {
|
||||
path: "/error",
|
||||
redirect: "/error/403",
|
||||
meta: {
|
||||
icon: InformationLine,
|
||||
icon: "informationLine",
|
||||
// showLink: false,
|
||||
title: $t("menus.hsabnormal"),
|
||||
rank: error
|
||||
},
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { flowchart } from "@/router/enums";
|
||||
import SetUp from "@iconify-icons/ep/set-up";
|
||||
|
||||
export default {
|
||||
path: "/flowChart",
|
||||
redirect: "/flowChart/index",
|
||||
meta: {
|
||||
icon: SetUp,
|
||||
icon: "setUp",
|
||||
title: $t("menus.hsflowChart"),
|
||||
rank: flowchart
|
||||
},
|
||||
|
||||
@@ -2,13 +2,11 @@ import { $t } from "@/plugins/i18n";
|
||||
import { formdesign } from "@/router/enums";
|
||||
const IFrame = () => import("@/layout/frameView.vue");
|
||||
|
||||
import TerminalWindowLine from "@iconify-icons/ri/terminal-window-line";
|
||||
|
||||
export default {
|
||||
path: "/formDesign",
|
||||
redirect: "/formDesign/index",
|
||||
meta: {
|
||||
icon: TerminalWindowLine,
|
||||
icon: "terminalWindowLine",
|
||||
title: $t("menus.hsFormDesign"),
|
||||
rank: formdesign
|
||||
},
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { guide } from "@/router/enums";
|
||||
import Guide from "@iconify-icons/ep/guide";
|
||||
|
||||
export default {
|
||||
path: "/guide",
|
||||
redirect: "/guide/index",
|
||||
meta: {
|
||||
icon: Guide,
|
||||
icon: "guide",
|
||||
title: $t("menus.hsguide"),
|
||||
rank: guide
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { home } from "@/router/enums";
|
||||
const Layout = () => import("@/layout/index.vue");
|
||||
import HomeFilled from "@iconify-icons/ep/home-filled";
|
||||
|
||||
export default {
|
||||
path: "/",
|
||||
@@ -9,7 +8,7 @@ export default {
|
||||
component: Layout,
|
||||
redirect: "/welcome",
|
||||
meta: {
|
||||
icon: HomeFilled,
|
||||
icon: "homeFilled",
|
||||
title: $t("menus.hshome"),
|
||||
rank: home
|
||||
},
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { list } from "@/router/enums";
|
||||
import ListCheck from "@iconify-icons/ri/list-check";
|
||||
import Card from "@iconify-icons/ri/bank-card-line";
|
||||
|
||||
export default {
|
||||
path: "/list",
|
||||
redirect: "/list/card",
|
||||
meta: {
|
||||
icon: ListCheck,
|
||||
icon: "listCheck",
|
||||
title: $t("menus.hsList"),
|
||||
rank: list
|
||||
},
|
||||
@@ -17,7 +15,7 @@ export default {
|
||||
name: "ListCard",
|
||||
component: () => import("@/views/list/card/index.vue"),
|
||||
meta: {
|
||||
icon: Card,
|
||||
icon: "card",
|
||||
title: $t("menus.hsListCard"),
|
||||
showParent: true
|
||||
}
|
||||
|
||||
22
src/router/modules/menuoverflow.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { menuoverflow } from "@/router/enums";
|
||||
|
||||
export default {
|
||||
path: "/menuoverflow",
|
||||
redirect: "/menuoverflow/index",
|
||||
meta: {
|
||||
title: $t("menus.hsMenuoverflow"),
|
||||
rank: menuoverflow
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/menuoverflow/index",
|
||||
name: "MenuOverflow",
|
||||
component: () => import("@/views/menuoverflow/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsChildMenuoverflow"),
|
||||
showParent: true
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
@@ -1,13 +1,12 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { nested } from "@/router/enums";
|
||||
import Histogram from "@iconify-icons/ep/histogram";
|
||||
|
||||
export default {
|
||||
path: "/nested",
|
||||
redirect: "/nested/menu1/menu1-1",
|
||||
meta: {
|
||||
title: $t("menus.hsmenus"),
|
||||
icon: Histogram,
|
||||
icon: "histogram",
|
||||
rank: nested
|
||||
},
|
||||
children: [
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { ppt } from "@/router/enums";
|
||||
const IFrame = () => import("@/layout/frameView.vue");
|
||||
import Ppt from "@iconify-icons/ri/file-ppt-2-line";
|
||||
|
||||
export default {
|
||||
path: "/ppt",
|
||||
redirect: "/ppt/index",
|
||||
meta: {
|
||||
icon: Ppt,
|
||||
icon: "ppt",
|
||||
title: "PPT",
|
||||
rank: ppt
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
const Layout = () => import("@/layout/index.vue");
|
||||
import HomeFilled from "@iconify-icons/ep/home-filled";
|
||||
|
||||
export default [
|
||||
{
|
||||
@@ -17,7 +16,7 @@ export default [
|
||||
path: "/redirect",
|
||||
component: Layout,
|
||||
meta: {
|
||||
icon: HomeFilled,
|
||||
icon: "homeFilled",
|
||||
title: $t("menus.hshome"),
|
||||
showLink: false,
|
||||
rank: 102
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { result } from "@/router/enums";
|
||||
import CheckboxCircleLine from "@iconify-icons/ri/checkbox-circle-line";
|
||||
|
||||
export default {
|
||||
path: "/result",
|
||||
redirect: "/result/success",
|
||||
meta: {
|
||||
icon: CheckboxCircleLine,
|
||||
icon: "checkboxCircleLine",
|
||||
title: $t("menus.hsResult"),
|
||||
rank: result
|
||||
},
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { tree } from "@/router/enums";
|
||||
import hot from "@/assets/svg/hot.svg?component";
|
||||
|
||||
export default {
|
||||
path: "/tree",
|
||||
redirect: "/tree/index",
|
||||
meta: {
|
||||
icon: hot,
|
||||
title: $t("menus.hsTree"),
|
||||
rank: tree
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/tree/index",
|
||||
name: "Tree",
|
||||
component: () => import("@/views/tree/index.vue"),
|
||||
meta: {
|
||||
title: $t("menus.hsTree")
|
||||
}
|
||||
}
|
||||
]
|
||||
} as RouteConfigsTable;
|
||||
@@ -8,16 +8,18 @@ import {
|
||||
} from "vue-router";
|
||||
import { router } from "./index";
|
||||
import { isProxy, toRaw } from "vue";
|
||||
import { loadEnv } from "../../build";
|
||||
import { useTimeoutFn } from "@vueuse/core";
|
||||
import { RouteConfigs } from "@/layout/types";
|
||||
import {
|
||||
isString,
|
||||
cloneDeep,
|
||||
isAllEmpty,
|
||||
intersection,
|
||||
storageSession,
|
||||
isIncludeAllChildren
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import { cloneDeep, intersection } from "lodash-unified";
|
||||
import { sessionKey, type DataInfo } from "@/utils/auth";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
const IFrame = () => import("@/layout/frameView.vue");
|
||||
@@ -27,19 +29,25 @@ const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
|
||||
// 动态路由
|
||||
import { getAsyncRoutes } from "@/api/routes";
|
||||
|
||||
function handRank(routeInfo: any) {
|
||||
const { name, path, parentId, meta } = routeInfo;
|
||||
return isAllEmpty(parentId)
|
||||
? isAllEmpty(meta?.rank) ||
|
||||
(meta?.rank === 0 && name !== "Home" && path !== "/")
|
||||
? true
|
||||
: false
|
||||
: false;
|
||||
}
|
||||
|
||||
/** 按照路由中meta下的rank等级升序来排序路由 */
|
||||
function ascending(arr: any[]) {
|
||||
arr.forEach(v => {
|
||||
if (v?.meta?.rank === null) v.meta.rank = undefined;
|
||||
if (v?.meta?.rank === 0) {
|
||||
if (v.name !== "Home" && v.path !== "/") {
|
||||
console.warn("rank only the home page can be 0");
|
||||
}
|
||||
}
|
||||
arr.forEach((v, index) => {
|
||||
// 当rank不存在时,根据顺序自动创建,首页路由永远在第一位
|
||||
if (handRank(v)) v.meta.rank = index + 2;
|
||||
});
|
||||
return arr.sort(
|
||||
(a: { meta: { rank: number } }, b: { meta: { rank: number } }) => {
|
||||
return a?.meta?.rank - b?.meta?.rank;
|
||||
return a?.meta.rank - b?.meta.rank;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -76,7 +84,7 @@ function isOneOfArray(a: Array<string>, b: Array<string>) {
|
||||
/** 从sessionStorage里取出当前登陆用户的角色roles,过滤无权限的菜单 */
|
||||
function filterNoPermissionTree(data: RouteComponent[]) {
|
||||
const currentRoles =
|
||||
storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
const newTree = cloneDeep(data).filter((v: any) =>
|
||||
isOneOfArray(v.meta?.roles, currentRoles)
|
||||
);
|
||||
@@ -151,42 +159,66 @@ function addPathMatch() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化路由 */
|
||||
function initRouter() {
|
||||
return new Promise(resolve => {
|
||||
getAsyncRoutes().then(({ data }) => {
|
||||
if (data.length === 0) {
|
||||
usePermissionStoreHook().handleWholeMenus(data);
|
||||
resolve(router);
|
||||
} else {
|
||||
formatFlatteningRoutes(addAsyncRoutes(data)).map(
|
||||
(v: RouteRecordRaw) => {
|
||||
// 防止重复添加路由
|
||||
if (
|
||||
router.options.routes[0].children.findIndex(
|
||||
value => value.path === v.path
|
||||
) !== -1
|
||||
) {
|
||||
return;
|
||||
} else {
|
||||
// 切记将路由push到routes后还需要使用addRoute,这样路由才能正常跳转
|
||||
router.options.routes[0].children.push(v);
|
||||
// 最终路由进行升序
|
||||
ascending(router.options.routes[0].children);
|
||||
if (!router.hasRoute(v?.name)) router.addRoute(v);
|
||||
const flattenRouters: any = router
|
||||
.getRoutes()
|
||||
.find(n => n.path === "/");
|
||||
router.addRoute(flattenRouters);
|
||||
}
|
||||
resolve(router);
|
||||
}
|
||||
);
|
||||
usePermissionStoreHook().handleWholeMenus(data);
|
||||
/** 处理动态路由(后端返回的路由) */
|
||||
function handleAsyncRoutes(routeList) {
|
||||
if (routeList.length === 0) {
|
||||
usePermissionStoreHook().handleWholeMenus(routeList);
|
||||
} else {
|
||||
formatFlatteningRoutes(addAsyncRoutes(routeList)).map(
|
||||
(v: RouteRecordRaw) => {
|
||||
// 防止重复添加路由
|
||||
if (
|
||||
router.options.routes[0].children.findIndex(
|
||||
value => value.path === v.path
|
||||
) !== -1
|
||||
) {
|
||||
return;
|
||||
} else {
|
||||
// 切记将路由push到routes后还需要使用addRoute,这样路由才能正常跳转
|
||||
router.options.routes[0].children.push(v);
|
||||
// 最终路由进行升序
|
||||
ascending(router.options.routes[0].children);
|
||||
if (!router.hasRoute(v?.name)) router.addRoute(v);
|
||||
const flattenRouters: any = router
|
||||
.getRoutes()
|
||||
.find(n => n.path === "/");
|
||||
router.addRoute(flattenRouters);
|
||||
}
|
||||
}
|
||||
addPathMatch();
|
||||
);
|
||||
usePermissionStoreHook().handleWholeMenus(routeList);
|
||||
}
|
||||
addPathMatch();
|
||||
}
|
||||
|
||||
/** 初始化路由(`new Promise` 写法防止在异步请求中造成无限循环)*/
|
||||
function initRouter() {
|
||||
if (getConfig()?.CachingAsyncRoutes) {
|
||||
// 开启动态路由缓存本地sessionStorage
|
||||
const key = "async-routes";
|
||||
const asyncRouteList = storageSession().getItem(key) as any;
|
||||
if (asyncRouteList && asyncRouteList?.length > 0) {
|
||||
return new Promise(resolve => {
|
||||
handleAsyncRoutes(asyncRouteList);
|
||||
resolve(router);
|
||||
});
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
getAsyncRoutes().then(({ data }) => {
|
||||
handleAsyncRoutes(cloneDeep(data));
|
||||
storageSession().setItem(key, data);
|
||||
resolve(router);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
getAsyncRoutes().then(({ data }) => {
|
||||
handleAsyncRoutes(cloneDeep(data));
|
||||
resolve(router);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +259,7 @@ function formatTwoStageRoutes(routesList: RouteRecordRaw[]) {
|
||||
children: []
|
||||
});
|
||||
} else {
|
||||
newRoutesList[0].children.push({ ...v });
|
||||
newRoutesList[0]?.children.push({ ...v });
|
||||
}
|
||||
});
|
||||
return newRoutesList;
|
||||
@@ -291,7 +323,7 @@ function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>) {
|
||||
|
||||
/** 获取路由历史模式 https://next.router.vuejs.org/zh/guide/essentials/history-mode.html */
|
||||
function getHistoryMode(): RouterHistory {
|
||||
const routerHistory = loadEnv().VITE_ROUTER_HISTORY;
|
||||
const routerHistory = import.meta.env.VITE_ROUTER_HISTORY;
|
||||
// len为1 代表只有历史模式 为2 代表历史模式中存在base参数 https://next.router.vuejs.org/zh/api/#%E5%8F%82%E6%95%B0-1
|
||||
const historyMode = routerHistory.split(",");
|
||||
const leftMode = historyMode[0];
|
||||
@@ -323,6 +355,7 @@ function hasAuth(value: string | Array<string>): boolean {
|
||||
if (!value) return false;
|
||||
/** 从当前路由的`meta`字段里获取按钮级别的所有自定义`code`值 */
|
||||
const metaAuths = getAuths();
|
||||
if (!metaAuths) return false;
|
||||
const isAuths = isString(value)
|
||||
? metaAuths.includes(value)
|
||||
: isIncludeAllChildren(value, metaAuths);
|
||||
|
||||
@@ -9,14 +9,14 @@ export const useAppStore = defineStore({
|
||||
state: (): appType => ({
|
||||
sidebar: {
|
||||
opened:
|
||||
storageLocal.getItem<StorageConfigs>("responsive-layout")
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")
|
||||
?.sidebarStatus ?? getConfig().SidebarStatus,
|
||||
withoutAnimation: false,
|
||||
isClickCollapse: false
|
||||
},
|
||||
// 这里的layout用于监听容器拖拉后恢复对应的导航模式
|
||||
layout:
|
||||
storageLocal.getItem<StorageConfigs>("responsive-layout")?.layout ??
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")?.layout ??
|
||||
getConfig().Layout,
|
||||
device: deviceDetection() ? "mobile" : "desktop",
|
||||
// 作用于 src/views/components/draggable/index.vue 页面,当离开页面并不会销毁 new Swap(),sortablejs 官网也没有提供任何销毁的 api
|
||||
@@ -32,7 +32,8 @@ export const useAppStore = defineStore({
|
||||
},
|
||||
actions: {
|
||||
TOGGLE_SIDEBAR(opened?: boolean, resize?: string) {
|
||||
const layout = storageLocal.getItem<StorageConfigs>("responsive-layout");
|
||||
const layout =
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout");
|
||||
if (opened && resize) {
|
||||
this.sidebar.withoutAnimation = true;
|
||||
this.sidebar.opened = true;
|
||||
@@ -47,7 +48,7 @@ export const useAppStore = defineStore({
|
||||
this.sidebar.isClickCollapse = !this.sidebar.opened;
|
||||
layout.sidebarStatus = this.sidebar.opened;
|
||||
}
|
||||
storageLocal.setItem("responsive-layout", layout);
|
||||
storageLocal().setItem("responsive-layout", layout);
|
||||
},
|
||||
async toggleSideBar(opened?: boolean, resize?: string) {
|
||||
await this.TOGGLE_SIDEBAR(opened, resize);
|
||||
|
||||
@@ -7,10 +7,10 @@ export const useEpThemeStore = defineStore({
|
||||
id: "pure-epTheme",
|
||||
state: () => ({
|
||||
epThemeColor:
|
||||
storageLocal.getItem<StorageConfigs>("responsive-layout")?.epThemeColor ??
|
||||
getConfig().EpThemeColor,
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")
|
||||
?.epThemeColor ?? getConfig().EpThemeColor,
|
||||
epTheme:
|
||||
storageLocal.getItem<StorageConfigs>("responsive-layout")?.theme ??
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout")?.theme ??
|
||||
getConfig().Theme
|
||||
}),
|
||||
getters: {
|
||||
@@ -30,12 +30,13 @@ export const useEpThemeStore = defineStore({
|
||||
},
|
||||
actions: {
|
||||
setEpThemeColor(newColor: string): void {
|
||||
const layout = storageLocal.getItem<StorageConfigs>("responsive-layout");
|
||||
const layout =
|
||||
storageLocal().getItem<StorageConfigs>("responsive-layout");
|
||||
this.epTheme = layout?.theme;
|
||||
this.epThemeColor = newColor;
|
||||
if (!layout) return;
|
||||
layout.epThemeColor = newColor;
|
||||
storageLocal.setItem("responsive-layout", layout);
|
||||
storageLocal().setItem("responsive-layout", layout);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,12 +9,13 @@ export const useMultiTagsStore = defineStore({
|
||||
id: "pure-multiTags",
|
||||
state: () => ({
|
||||
// 存储标签页信息(路由信息)
|
||||
multiTags: storageLocal.getItem<StorageConfigs>("responsive-configure")
|
||||
multiTags: storageLocal().getItem<StorageConfigs>("responsive-configure")
|
||||
?.multiTagsCache
|
||||
? storageLocal.getItem<StorageConfigs>("responsive-tags")
|
||||
? storageLocal().getItem<StorageConfigs>("responsive-tags")
|
||||
: [...routerArrays],
|
||||
multiTagsCache: storageLocal.getItem<StorageConfigs>("responsive-configure")
|
||||
?.multiTagsCache
|
||||
multiTagsCache: storageLocal().getItem<StorageConfigs>(
|
||||
"responsive-configure"
|
||||
)?.multiTagsCache
|
||||
}),
|
||||
getters: {
|
||||
getMultiTagsCache() {
|
||||
@@ -25,14 +26,14 @@ export const useMultiTagsStore = defineStore({
|
||||
multiTagsCacheChange(multiTagsCache: boolean) {
|
||||
this.multiTagsCache = multiTagsCache;
|
||||
if (multiTagsCache) {
|
||||
storageLocal.setItem("responsive-tags", this.multiTags);
|
||||
storageLocal().setItem("responsive-tags", this.multiTags);
|
||||
} else {
|
||||
storageLocal.removeItem("responsive-tags");
|
||||
storageLocal().removeItem("responsive-tags");
|
||||
}
|
||||
},
|
||||
tagsCache(multiTags) {
|
||||
this.getMultiTagsCache &&
|
||||
storageLocal.setItem("responsive-tags", multiTags);
|
||||
storageLocal().setItem("responsive-tags", multiTags);
|
||||
},
|
||||
handleTags<T>(
|
||||
mode: string,
|
||||
|
||||
@@ -14,9 +14,9 @@ export const useUserStore = defineStore({
|
||||
state: (): userType => ({
|
||||
// 用户名
|
||||
username:
|
||||
storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "",
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.username ?? "",
|
||||
// 页面级别权限
|
||||
roles: storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [],
|
||||
roles: storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? [],
|
||||
// 前端生成的验证码(按实际需求替换)
|
||||
verifyCode: "",
|
||||
// 判断登录页面显示哪个组件(0:登录(默认)、1:手机登录、2:二维码登录、3:注册、4:忘记密码)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "element-plus/theme-chalk/src/dark/css-vars.scss";
|
||||
@use "element-plus/theme-chalk/src/dark/css-vars.scss" as *;
|
||||
|
||||
/* 暗黑模式适配 */
|
||||
html.dark {
|
||||
@@ -41,97 +41,6 @@ html.dark {
|
||||
}
|
||||
}
|
||||
|
||||
/* vxe-table */
|
||||
.vxe-table--header-wrapper,
|
||||
.vxe-table--body-wrapper {
|
||||
color: var(--el-text-color-primary);
|
||||
background: var(--el-bg-color) !important;
|
||||
}
|
||||
|
||||
.vxe-table--render-default.border--full .vxe-header--column,
|
||||
.vxe-table--render-default.border--full .vxe-body--column,
|
||||
.vxe-table--render-default.border--full .vxe-footer--column {
|
||||
background-image: linear-gradient(
|
||||
var(--el-border-color-lighter),
|
||||
var(--el-border-color-lighter)
|
||||
),
|
||||
linear-gradient(
|
||||
var(--el-border-color-lighter),
|
||||
var(--el-border-color-lighter)
|
||||
);
|
||||
}
|
||||
|
||||
/* 表头 */
|
||||
.vxe-table--header-wrapper {
|
||||
background: #262727 !important;
|
||||
}
|
||||
|
||||
.vxe-table--render-wrapper,
|
||||
.vxe-table--main-wrapper {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.vxe-pager.is--perfect,
|
||||
.vxe-table--render-default .vxe-table--border-line {
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
.vxe-table--header-border-line {
|
||||
border-bottom: 1px solid var(--el-border-color-lighter) !important;
|
||||
}
|
||||
|
||||
.vxe-body--row.row--hover,
|
||||
.vxe-pager {
|
||||
background-color: #262727;
|
||||
}
|
||||
|
||||
.vxe-input--inner,
|
||||
.vxe-pager .vxe-pager--jump-prev,
|
||||
.vxe-pager .vxe-pager--prev-btn,
|
||||
.vxe-pager .vxe-pager--next-btn,
|
||||
.vxe-pager .vxe-pager--jump-next,
|
||||
.vxe-pager .vxe-pager--num-btn,
|
||||
.vxe-pager .vxe-pager--jump .vxe-pager--goto {
|
||||
background-color: transparent;
|
||||
color: var(--el-text-color-primary);
|
||||
// outline: none !important;
|
||||
}
|
||||
|
||||
.vxe-select-option--wrapper {
|
||||
background: var(--el-bg-color) !important;
|
||||
}
|
||||
|
||||
.vxe-select-option:not(.is--disabled).is--hover {
|
||||
background: var(--el-color-primary-light-6) !important;
|
||||
}
|
||||
|
||||
.vxe-modal--wrapper.type--modal .vxe-modal--box,
|
||||
.vxe-modal--wrapper.type--alert .vxe-modal--box,
|
||||
.vxe-modal--wrapper.type--confirm .vxe-modal--box,
|
||||
.vxe-form {
|
||||
background: var(--el-bg-color) !important;
|
||||
}
|
||||
|
||||
.vxe-modal--box,
|
||||
.vxe-modal--header {
|
||||
border: none;
|
||||
background: var(--el-bg-color) !important;
|
||||
}
|
||||
|
||||
.vxe-modal--title,
|
||||
.vxe-button--content,
|
||||
.vxe-modal--header-title {
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.vxe-button.type--button:hover {
|
||||
background: var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
.vxe-button {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* 项目配置面板 */
|
||||
.right-panel-items {
|
||||
.el-divider__text {
|
||||
@@ -187,6 +96,19 @@ html.dark {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 全局覆盖element-plus的el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标的样式,表现更鲜明 */
|
||||
.el-icon {
|
||||
&.el-dialog__close,
|
||||
&.el-drawer__close,
|
||||
&.el-message-box__close,
|
||||
&.el-notification__closeBtn {
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,非暗黑模式在 src/style/element-plus.scss 文件进行了适配 */
|
||||
.pure-message {
|
||||
background-image: initial !important;
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* 自定义 tooltip 的类名 */
|
||||
.pure-tooltip {
|
||||
// 右侧操作面板right-panel类名的z-index为40000,tooltip需要大于它才能显示
|
||||
z-index: 41000 !important;
|
||||
}
|
||||
|
||||
/* nprogress 适配 element-plus 的主题色 */
|
||||
#nprogress {
|
||||
& .bar {
|
||||
@@ -63,6 +69,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 全局覆盖element-plus的el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标的样式,表现更鲜明 */
|
||||
.el-dialog__headerbtn,
|
||||
.el-message-box__headerbtn {
|
||||
&:hover {
|
||||
.el-dialog__close {
|
||||
color: var(--el-color-info) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-icon {
|
||||
&.el-dialog__close,
|
||||
&.el-drawer__close,
|
||||
&.el-message-box__close,
|
||||
&.el-notification__closeBtn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s, color 0.2s;
|
||||
&:hover {
|
||||
color: rgba(0, 0, 0, 0.88) !important;
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,暗黑模式在 src/style/dark.scss 文件进行了适配 */
|
||||
.pure-message {
|
||||
border-width: 0 !important;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
@import "./element-plus.scss";
|
||||
@import "./sidebar.scss";
|
||||
@import "./dark.scss";
|
||||
@import "./tailwind.css";
|
||||
|
||||
/* 自定义全局 CssVar */
|
||||
:root {
|
||||
@@ -19,9 +18,3 @@
|
||||
.html-weakness {
|
||||
filter: invert(80%);
|
||||
}
|
||||
|
||||
/* 重置 vxe-table 样式 */
|
||||
.vxe-button.type--button.theme--primary:hover,
|
||||
.vxe-pager .vxe-pager--num-btn:not(.is--disabled).is--active {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,12 @@
|
||||
}
|
||||
|
||||
/* breadcrumb transition */
|
||||
.breadcrumb-enter-active,
|
||||
.breadcrumb-enter-active {
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
transition: all 0.5s;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.breadcrumb-enter-from,
|
||||
|
||||
@@ -23,7 +23,7 @@ export function getToken(): DataInfo<number> {
|
||||
// 此处与`TokenKey`相同,此写法解决初始化时`Cookies`中不存在`TokenKey`报错
|
||||
return Cookies.get(TokenKey)
|
||||
? JSON.parse(Cookies.get(TokenKey))
|
||||
: storageSession.getItem(sessionKey);
|
||||
: storageSession().getItem(sessionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ export function setToken(data: DataInfo<Date>) {
|
||||
function setSessionKey(username: string, roles: Array<string>) {
|
||||
useUserStoreHook().SET_USERNAME(username);
|
||||
useUserStoreHook().SET_ROLES(roles);
|
||||
storageSession.setItem(sessionKey, {
|
||||
storageSession().setItem(sessionKey, {
|
||||
refreshToken,
|
||||
expires,
|
||||
username,
|
||||
@@ -60,9 +60,9 @@ export function setToken(data: DataInfo<Date>) {
|
||||
setSessionKey(username, roles);
|
||||
} else {
|
||||
const username =
|
||||
storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "";
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.username ?? "";
|
||||
const roles =
|
||||
storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
setSessionKey(username, roles);
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export function setToken(data: DataInfo<Date>) {
|
||||
/** 删除`token`以及key值为`user-info`的session信息 */
|
||||
export function removeToken() {
|
||||
Cookies.remove(TokenKey);
|
||||
sessionStorage.removeItem(sessionKey);
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
/** 格式化token(jwt格式) */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import REGION_DATA from "china-area-data";
|
||||
import { cloneDeep } from "lodash-unified";
|
||||
import { cloneDeep } from "@pureadmin/utils";
|
||||
|
||||
interface ProvinceData {
|
||||
value: string;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import Print from "@/utils/print";
|
||||
import { reactive, ref } from "vue";
|
||||
import { VxeTablePropTypes } from "vxe-table";
|
||||
import Line from "../welcome/components/Line.vue";
|
||||
|
||||
defineOptions({
|
||||
@@ -14,43 +13,6 @@ interface User {
|
||||
address: string;
|
||||
}
|
||||
|
||||
const demo1 = reactive({
|
||||
tableData: [
|
||||
{
|
||||
id: 10001,
|
||||
name: "Test1",
|
||||
role: "Develop",
|
||||
sex: "Man",
|
||||
age: 28,
|
||||
address: "test abc"
|
||||
},
|
||||
{
|
||||
id: 10002,
|
||||
name: "Test2",
|
||||
role: "Test",
|
||||
sex: "Women",
|
||||
age: 22,
|
||||
address: "Guangzhou"
|
||||
},
|
||||
{
|
||||
id: 10003,
|
||||
name: "Test3",
|
||||
role: "PM",
|
||||
sex: "Man",
|
||||
age: 32,
|
||||
address: "Shanghai"
|
||||
},
|
||||
{
|
||||
id: 10004,
|
||||
name: "Test4",
|
||||
role: "Designer",
|
||||
sex: "Women",
|
||||
age: 24,
|
||||
address: "Shanghai"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const value = ref("1");
|
||||
|
||||
const options = [
|
||||
@@ -59,11 +21,6 @@ const options = [
|
||||
el: ".el-table",
|
||||
label: "Element-Plus Table"
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
el: ".vxe-table",
|
||||
label: "Vxe Table"
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
el: ".echart",
|
||||
@@ -81,38 +38,6 @@ function onPrint() {
|
||||
Print(el).toPrint;
|
||||
}
|
||||
|
||||
const headerCellStyle: VxeTablePropTypes.HeaderCellStyle = ({ column }) => {
|
||||
if (column.property === "name") {
|
||||
return {
|
||||
backgroundColor: "#f60",
|
||||
color: "#ffffff"
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const rowStyle: VxeTablePropTypes.RowStyle = ({ rowIndex }) => {
|
||||
if ([2, 3, 5].includes(rowIndex)) {
|
||||
return {
|
||||
backgroundColor: "red",
|
||||
color: "#ffffff"
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const cellStyle: VxeTablePropTypes.CellStyle = ({ row, column }) => {
|
||||
if (column.property === "sex") {
|
||||
if (row.sex >= "1") {
|
||||
return {
|
||||
backgroundColor: "#187"
|
||||
};
|
||||
} else if (row.age === 26) {
|
||||
return {
|
||||
backgroundColor: "#2db7f5"
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const tableRowClassName = ({ rowIndex }: { row: User; rowIndex: number }) => {
|
||||
if (rowIndex === 1) {
|
||||
return "warning-row";
|
||||
@@ -205,45 +130,6 @@ const tableData: User[] = [
|
||||
</el-table>
|
||||
</el-col>
|
||||
|
||||
<el-col
|
||||
:xs="22"
|
||||
:sm="22"
|
||||
:md="11"
|
||||
:lg="11"
|
||||
:xl="11"
|
||||
style="margin: 10px; border: 0.01rem solid var(--el-color-primary)"
|
||||
v-motion
|
||||
:initial="{
|
||||
opacity: 0,
|
||||
y: 100
|
||||
}"
|
||||
:enter="{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 200
|
||||
}
|
||||
}"
|
||||
>
|
||||
<p class="font-medium pt-1">Vxe Table</p>
|
||||
<vxe-table
|
||||
class="vxe-table"
|
||||
border
|
||||
style="margin: 40px auto"
|
||||
:header-cell-style="headerCellStyle"
|
||||
:row-style="rowStyle"
|
||||
:cell-style="cellStyle"
|
||||
:data="demo1.tableData"
|
||||
>
|
||||
<vxe-column type="seq" width="60" />
|
||||
<vxe-column field="name" title="Name" />
|
||||
<vxe-column field="sex" title="Sex" />
|
||||
<vxe-column field="age" title="Age" />
|
||||
<vxe-column field="attr1" title="Attr1" />
|
||||
<vxe-column field="address" title="Address" show-overflow />
|
||||
</vxe-table>
|
||||
</el-col>
|
||||
|
||||
<el-col
|
||||
:xs="22"
|
||||
:sm="22"
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { loadEnv } from "@build/index";
|
||||
|
||||
defineOptions({
|
||||
name: "Button"
|
||||
});
|
||||
|
||||
const { VITE_PUBLIC_PATH } = loadEnv();
|
||||
const { VITE_PUBLIC_PATH } = import.meta.env;
|
||||
|
||||
const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
|
||||
</script>
|
||||
@@ -21,9 +20,3 @@ const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
|
||||
<iframe :src="url" frameborder="0" class="iframe w-full h-[60vh]" />
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iframe {
|
||||
filter: invert(0.9) hue-rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,8 +7,12 @@ defineOptions({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="back" title="返回上一页" @click="$router.go(-1)">
|
||||
<back class="w-[80px] h-[80px]" />
|
||||
<div class="w-full h-full text-center">
|
||||
<h1>业务内容模块</h1>
|
||||
<p>使用场景:需要外嵌平台某个页面,不需要展示菜单导航以及额外模块</p>
|
||||
<div class="back" title="返回上一页" @click="$router.go(-1)">
|
||||
<back class="w-[80px] h-[80px]" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
9
src/views/menuoverflow/index.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "MenuOverflow"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>目录、菜单文字超出显示 Tooltip 文字提示</div>
|
||||
</template>
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { initRouter } from "@/router/utils";
|
||||
import { storageSession } from "@pureadmin/utils";
|
||||
import { type CSSProperties, ref, computed } from "vue";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
@@ -33,6 +34,7 @@ function onChange() {
|
||||
.loginByUsername({ username: username.value, password: "admin123" })
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
storageSession().removeItem("async-routes");
|
||||
usePermissionStoreHook().clearAllCachePage();
|
||||
initRouter();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Page from "./page/index.vue";
|
||||
import RowDrag from "./drag/row/index.vue";
|
||||
import ColumnDrag from "./drag/column/index.vue";
|
||||
import Contextmenu from "./contextmenu/index.vue";
|
||||
@@ -6,11 +7,24 @@ import Edit from "./edit/index.vue";
|
||||
import Watermark from "./watermark/index.vue";
|
||||
import Print from "./prints/index.vue";
|
||||
import Echarts from "./echarts/index.vue";
|
||||
import TableSelect from "./table-select/index.vue";
|
||||
|
||||
const rendContent = (val: string) =>
|
||||
`代码位置:src/views/pure-table/high/${val}/index.vue`;
|
||||
|
||||
export const list = [
|
||||
{
|
||||
key: "page",
|
||||
content: rendContent("page"),
|
||||
title: "分页、加载动画、动态列",
|
||||
component: Page
|
||||
},
|
||||
{
|
||||
key: "tableSelect",
|
||||
content: rendContent("table-select"),
|
||||
title: "表格选择器",
|
||||
component: TableSelect
|
||||
},
|
||||
{
|
||||
key: "rowDrag",
|
||||
content: rendContent("drag/row"),
|
||||
|
||||
106
src/views/pure-table/high/page/columns.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { tableData } from "../data";
|
||||
import { clone, delay } from "@pureadmin/utils";
|
||||
import { ref, onMounted, reactive, watchEffect } from "vue";
|
||||
import type { PaginationProps, LoadingConfig, Align } from "@pureadmin/table";
|
||||
|
||||
export function useColumns() {
|
||||
const dataList = ref([]);
|
||||
const loading = ref(true);
|
||||
const hideVal = ref("nohide");
|
||||
const tableSize = ref("default");
|
||||
const paginationSmall = ref(false);
|
||||
const paginationAlign = ref("right");
|
||||
const columns: TableColumnList = [
|
||||
{
|
||||
label: "日期",
|
||||
prop: "date",
|
||||
hide: () => (hideVal.value === "hideDate" ? true : false)
|
||||
},
|
||||
{
|
||||
label: "姓名",
|
||||
prop: "name",
|
||||
hide: () => (hideVal.value === "hideName" ? true : false)
|
||||
},
|
||||
{
|
||||
label: "地址",
|
||||
prop: "address",
|
||||
hide: () => (hideVal.value === "hideAddress" ? true : false)
|
||||
}
|
||||
];
|
||||
|
||||
/** 分页配置 */
|
||||
const pagination = reactive<PaginationProps>({
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
pageSizes: [10, 15, 20],
|
||||
total: 0,
|
||||
align: "right",
|
||||
background: true,
|
||||
small: false
|
||||
});
|
||||
|
||||
/** 加载动画配置 */
|
||||
const loadingConfig = reactive<LoadingConfig>({
|
||||
text: "正在加载第一页...",
|
||||
viewBox: "-10, -10, 50, 50",
|
||||
spinner: `
|
||||
<path class="path" d="
|
||||
M 30 15
|
||||
L 28 17
|
||||
M 25.61 25.61
|
||||
A 15 15, 0, 0, 1, 15 30
|
||||
A 15 15, 0, 1, 1, 27.99 7.5
|
||||
L 15 15
|
||||
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
|
||||
`
|
||||
// svg: "",
|
||||
// background: rgba()
|
||||
});
|
||||
|
||||
function onChange(val) {
|
||||
pagination.small = val;
|
||||
}
|
||||
|
||||
function onSizeChange(val) {
|
||||
console.log("onSizeChange", val);
|
||||
}
|
||||
|
||||
function onCurrentChange(val) {
|
||||
loadingConfig.text = `正在加载第${val}页...`;
|
||||
loading.value = true;
|
||||
delay(600).then(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
pagination.align = paginationAlign.value as Align;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
delay(600).then(() => {
|
||||
const newList = [];
|
||||
Array.from({ length: 6 }).forEach(() => {
|
||||
newList.push(clone(tableData, true));
|
||||
});
|
||||
dataList.value = newList.flat(Infinity);
|
||||
pagination.total = dataList.value.length;
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
loading,
|
||||
columns,
|
||||
dataList,
|
||||
hideVal,
|
||||
tableSize,
|
||||
pagination,
|
||||
loadingConfig,
|
||||
paginationAlign,
|
||||
paginationSmall,
|
||||
onChange,
|
||||
onSizeChange,
|
||||
onCurrentChange
|
||||
};
|
||||
}
|
||||
73
src/views/pure-table/high/page/index.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import { useColumns } from "./columns";
|
||||
|
||||
const {
|
||||
loading,
|
||||
columns,
|
||||
dataList,
|
||||
hideVal,
|
||||
tableSize,
|
||||
pagination,
|
||||
loadingConfig,
|
||||
paginationAlign,
|
||||
paginationSmall,
|
||||
onChange,
|
||||
onSizeChange,
|
||||
onCurrentChange
|
||||
} = useColumns();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-space class="float-right mb-4">
|
||||
<p class="text-sm">动态列:</p>
|
||||
<el-radio-group v-model="hideVal" size="small">
|
||||
<el-radio-button label="nohide">不隐藏</el-radio-button>
|
||||
<el-radio-button label="hideDate">隐藏日期</el-radio-button>
|
||||
<el-radio-button label="hideName">隐藏姓名</el-radio-button>
|
||||
<el-radio-button label="hideAddress">隐藏地址</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-divider direction="vertical" />
|
||||
<p class="text-sm">表格大小:</p>
|
||||
<el-radio-group v-model="tableSize" size="small">
|
||||
<el-radio-button label="large">large</el-radio-button>
|
||||
<el-radio-button label="default">default</el-radio-button>
|
||||
<el-radio-button label="small">small</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-divider direction="vertical" />
|
||||
<p class="text-sm">分页大小:</p>
|
||||
<el-radio-group v-model="paginationSmall" size="small" @change="onChange">
|
||||
<el-radio-button :label="false">no small</el-radio-button>
|
||||
<el-radio-button :label="true">small</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-divider direction="vertical" />
|
||||
<p class="text-sm">分页的对齐方式:</p>
|
||||
<el-radio-group v-model="paginationAlign" size="small">
|
||||
<el-radio-button label="right">right</el-radio-button>
|
||||
<el-radio-button label="center">center</el-radio-button>
|
||||
<el-radio-button label="left">left</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-space>
|
||||
|
||||
<pure-table
|
||||
border
|
||||
row-key="id"
|
||||
alignWhole="center"
|
||||
showOverflowTooltip
|
||||
:size="tableSize"
|
||||
:loading="loading"
|
||||
:loading-config="loadingConfig"
|
||||
:height="tableSize === 'small' ? 352 : 440"
|
||||
:data="
|
||||
dataList.slice(
|
||||
(pagination.currentPage - 1) * pagination.pageSize,
|
||||
pagination.currentPage * pagination.pageSize
|
||||
)
|
||||
"
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
@size-change="onSizeChange"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
20
src/views/pure-table/high/table-select/index.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import radioSelectTable from "./radio/index.vue";
|
||||
import multipleSelectTable from "./multiple/index.vue";
|
||||
|
||||
const model = ref("radio");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-space>
|
||||
<el-radio-group v-model="model">
|
||||
<el-radio-button label="radio">单选</el-radio-button>
|
||||
<el-radio-button label="multiple">多选</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-divider direction="vertical" />
|
||||
<component
|
||||
:is="model === 'radio' ? radioSelectTable : multipleSelectTable"
|
||||
/>
|
||||
</el-space>
|
||||
</template>
|
||||
74
src/views/pure-table/high/table-select/multiple/columns.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { tableDataEdit } from "../../data";
|
||||
import { ref, reactive, type Ref } from "vue";
|
||||
import type { PaginationProps } from "@pureadmin/table";
|
||||
|
||||
export function useColumns(selectRef: Ref, tableRef: Ref) {
|
||||
const selectValue = ref([]);
|
||||
const columns: TableColumnList = [
|
||||
{
|
||||
type: "selection",
|
||||
align: "left"
|
||||
},
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
label: "日期",
|
||||
prop: "date"
|
||||
},
|
||||
{
|
||||
label: "姓名",
|
||||
prop: "name"
|
||||
},
|
||||
{
|
||||
label: "地址",
|
||||
prop: "address"
|
||||
}
|
||||
];
|
||||
|
||||
/** 分页配置 */
|
||||
const pagination = reactive<PaginationProps>({
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
layout: "prev, pager, next",
|
||||
total: tableDataEdit.length,
|
||||
background: true,
|
||||
small: true
|
||||
});
|
||||
|
||||
const handleSelectionChange = val => {
|
||||
const arr = [];
|
||||
val.forEach(v => {
|
||||
arr.push(v.name);
|
||||
});
|
||||
selectValue.value = arr;
|
||||
};
|
||||
|
||||
const removeTag = val => {
|
||||
// TODO optimize el-select add formatter
|
||||
const { toggleRowSelection } = tableRef.value.getTableRef();
|
||||
toggleRowSelection(tableDataEdit.filter(v => v.name === val)[0], false);
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
const { clearSelection } = tableRef.value.getTableRef();
|
||||
clearSelection();
|
||||
};
|
||||
|
||||
const onSure = () => {
|
||||
selectRef.value.blur();
|
||||
};
|
||||
|
||||
return {
|
||||
columns,
|
||||
pagination,
|
||||
selectValue,
|
||||
tableDataEdit,
|
||||
onSure,
|
||||
onClear,
|
||||
removeTag,
|
||||
handleSelectionChange
|
||||
};
|
||||
}
|
||||
65
src/views/pure-table/high/table-select/multiple/index.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useColumns } from "./columns";
|
||||
|
||||
const selectRef = ref();
|
||||
const tableRef = ref();
|
||||
const {
|
||||
columns,
|
||||
pagination,
|
||||
selectValue,
|
||||
tableDataEdit,
|
||||
onClear,
|
||||
onSure,
|
||||
removeTag,
|
||||
handleSelectionChange
|
||||
} = useColumns(selectRef, tableRef);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-select
|
||||
class="w-[160px]"
|
||||
ref="selectRef"
|
||||
v-model="selectValue"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
@remove-tag="removeTag"
|
||||
@clear="onClear"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="w-[600px] m-4">
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
height="355"
|
||||
row-key="id"
|
||||
:header-cell-style="{
|
||||
background: '#f5f7fa',
|
||||
color: '#303133'
|
||||
}"
|
||||
:data="
|
||||
tableDataEdit.slice(
|
||||
(pagination.currentPage - 1) * pagination.pageSize,
|
||||
pagination.currentPage * pagination.pageSize
|
||||
)
|
||||
"
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
@selection-change="handleSelectionChange"
|
||||
/>
|
||||
<el-button
|
||||
class="absolute bottom-[17px]"
|
||||
type="primary"
|
||||
size="small"
|
||||
text
|
||||
bg
|
||||
@click="onSure"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-select>
|
||||
</template>
|
||||
61
src/views/pure-table/high/table-select/radio/columns.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { message } from "@/utils/message";
|
||||
import { tableDataEdit } from "../../data";
|
||||
import { ref, reactive, type Ref } from "vue";
|
||||
import type { PaginationProps } from "@pureadmin/table";
|
||||
|
||||
export function useColumns(selectRef: Ref) {
|
||||
const selectValue = ref("");
|
||||
const columns: TableColumnList = [
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id",
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
label: "日期",
|
||||
prop: "date"
|
||||
},
|
||||
{
|
||||
label: "姓名",
|
||||
prop: "name"
|
||||
},
|
||||
{
|
||||
label: "地址",
|
||||
prop: "address"
|
||||
}
|
||||
];
|
||||
|
||||
/** 分页配置 */
|
||||
const pagination = reactive<PaginationProps>({
|
||||
pageSize: 5,
|
||||
currentPage: 1,
|
||||
layout: "prev, pager, next",
|
||||
total: tableDataEdit.length,
|
||||
background: true,
|
||||
small: true
|
||||
});
|
||||
|
||||
/** 高亮当前选中行 */
|
||||
function rowStyle({ row: { name } }) {
|
||||
return {
|
||||
cursor: "pointer",
|
||||
background: name === selectValue.value ? "#f5f7fa" : ""
|
||||
};
|
||||
}
|
||||
|
||||
/** 行点击 */
|
||||
function onRowClick(row) {
|
||||
selectValue.value = row.name;
|
||||
selectRef.value.blur();
|
||||
message(`当前选中行的数据为:${JSON.stringify(row)}`, { type: "success" });
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
pagination,
|
||||
selectValue,
|
||||
tableDataEdit,
|
||||
rowStyle,
|
||||
onRowClick
|
||||
};
|
||||
}
|
||||
46
src/views/pure-table/high/table-select/radio/index.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useColumns } from "./columns";
|
||||
|
||||
const selectRef = ref();
|
||||
const {
|
||||
columns,
|
||||
pagination,
|
||||
selectValue,
|
||||
tableDataEdit,
|
||||
rowStyle,
|
||||
onRowClick
|
||||
} = useColumns(selectRef);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-select
|
||||
ref="selectRef"
|
||||
v-model="selectValue"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
>
|
||||
<template #empty>
|
||||
<div class="w-[600px] m-4">
|
||||
<pure-table
|
||||
height="355"
|
||||
row-key="id"
|
||||
:header-cell-style="{
|
||||
background: '#f5f7fa',
|
||||
color: '#303133'
|
||||
}"
|
||||
:row-style="rowStyle"
|
||||
:data="
|
||||
tableDataEdit.slice(
|
||||
(pagination.currentPage - 1) * pagination.pageSize,
|
||||
pagination.currentPage * pagination.pageSize
|
||||
)
|
||||
"
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
@row-click="onRowClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-select>
|
||||
</template>
|
||||
@@ -1,4 +1,3 @@
|
||||
import { IconifyIconOffline } from "@/components/ReIcon";
|
||||
import ArrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
|
||||
import CloseCircleLine from "@iconify-icons/ri/close-circle-line";
|
||||
|
||||
@@ -8,7 +7,7 @@ export function useColumns() {
|
||||
cellRenderer: () => {
|
||||
return (
|
||||
<span class="flex items-center -mt-6">
|
||||
<IconifyIconOffline
|
||||
<iconify-icon-offline
|
||||
icon={CloseCircleLine}
|
||||
color="#F56C6C"
|
||||
width="18px"
|
||||
@@ -21,7 +20,7 @@ export function useColumns() {
|
||||
style="color: var(--el-color-primary)"
|
||||
>
|
||||
立即解冻
|
||||
<IconifyIconOffline
|
||||
<iconify-icon-offline
|
||||
icon={ArrowRightSLine}
|
||||
color="var(--el-color-primary)"
|
||||
width="18px"
|
||||
@@ -36,7 +35,7 @@ export function useColumns() {
|
||||
cellRenderer: () => {
|
||||
return (
|
||||
<span class="flex items-center -mt-8">
|
||||
<IconifyIconOffline
|
||||
<iconify-icon-offline
|
||||
icon={CloseCircleLine}
|
||||
color="#F56C6C"
|
||||
width="18px"
|
||||
@@ -49,7 +48,7 @@ export function useColumns() {
|
||||
style="color: var(--el-color-primary)"
|
||||
>
|
||||
立即升级
|
||||
<IconifyIconOffline
|
||||
<iconify-icon-offline
|
||||
icon={ArrowRightSLine}
|
||||
color="var(--el-color-primary)"
|
||||
width="18px"
|
||||
|
||||