Compare commits

..

1 Commits

Author SHA1 Message Date
xiaoxian521
98b97b9f88 release: update 3.9.4 2022-12-05 13:59:54 +08:00
74 changed files with 1368 additions and 1619 deletions

View File

@@ -1,46 +1,3 @@
# 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) # 3.9.4 (2022-12-05)
### ✔️ refactor ### ✔️ refactor
@@ -48,10 +5,6 @@
- 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 🐮 - 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) [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) # 3.9.3 (2022-12-04)
### 🎫 Feat ### 🎫 Feat

View File

@@ -1,46 +1,3 @@
# 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) # 3.9.4 (2022-12-05)
### ✔️ refactor ### ✔️ refactor
@@ -48,10 +5,6 @@
- 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 🐮 - 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) [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) # 3.9.3 (2022-12-04)
### 🎫 Feat ### 🎫 Feat

View File

@@ -1,46 +1,3 @@
# 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) # 3.9.4 (2022-12-05)
### ✔️ refactor ### ✔️ refactor
@@ -48,10 +5,6 @@
- 完全移除了 `vxe-table`,移除后,完整版整体打包大小减少 `1.82MB`,首启动时长基本和精简版持平 🐮 - 完全移除了 `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) [点击此处查看为什么移除?如何自行集成?](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) # 3.9.3 (2022-12-04)
### 🎫 Feat ### 🎫 Feat

View File

@@ -22,7 +22,7 @@
- [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT) - [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq) - [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
## 配套保姆级文档(支持 `PWA` 快速、离线访问) ## 配套文档(支持 `PWA` 快速、离线访问)
- [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc) - [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc)
- [点我查看国外文档站](https://xiaoxian521.github.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) [xiaoxian521](https://github.com/xiaoxian521)、[Ten-K](https://github.com/Ten-K)
## 支持 ## 捐赠
如果您觉得这个项目对您有帮助,可以帮作者买一杯果汁 🍹 表示支持 如果您觉得这个项目对您有帮助,可以帮作者买一杯果汁 🍹 表示支持
@@ -148,7 +148,9 @@ pnpm build
## `QQ` 交流群 ## `QQ` 交流群
[点击去加入](https://yiming_chang.gitee.io/pure-admin-doc/pages/support/#qq-%E4%BA%A4%E6%B5%81%E7%BE%A4) 一群已满,下面是二群,群里严禁`黄``赌``毒``vpn`等违法行为!
<img src="https://yiming_chang.gitee.io/pure-admin-doc/img/support/qq.png" width="150px" height="225px" />
## 许可证 ## 许可证
@@ -156,7 +158,7 @@ pnpm build
[MIT © xiaoxian521-2020](./LICENSE) [MIT © xiaoxian521-2020](./LICENSE)
## 支持 ## 捐赠
非常感谢您们的支持,相信项目会越来越好 :heart: 非常感谢您们的支持,相信项目会越来越好 :heart:

View File

@@ -7,7 +7,7 @@ import { Plugin as importToCDN } from "vite-plugin-cdn-import";
* 注意上面提到的仅限外网使用也不是完全肯定的如果你们公司内网部署的有相关js、css文件也可以将下面配置对应改一下整一套内网版cdn * 注意上面提到的仅限外网使用也不是完全肯定的如果你们公司内网部署的有相关js、css文件也可以将下面配置对应改一下整一套内网版cdn
*/ */
export const cdn = importToCDN({ export const cdn = importToCDN({
//prodUrl解释 name: 对应下面modules的nameversion: 自动读取本地package.json中dependencies依赖中对应包的版本号path: 对应下面modules的path当然也可写完整路径会替换prodUrl //prodUrl解释 name: 对应下面modules的nameversion: 自动读取本地package.json中dependencies依赖中对应包的版本号path: 对应下面modules的path
prodUrl: "https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}", prodUrl: "https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}",
modules: [ modules: [
{ {
@@ -56,6 +56,12 @@ export const cdn = importToCDN({
name: "echarts", name: "echarts",
var: "echarts", var: "echarts",
path: "echarts.min.js" path: "echarts.min.js"
},
{
name: "lodash",
var: "lodash",
// 可写`完整路径`,会替换`prodUrl`
path: "https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"
} }
] ]
}); });

View File

@@ -27,4 +27,9 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
return ret; return ret;
}; };
export { warpperEnv }; /** 获取环境变量 */
const loadEnv = (): ViteEnv => {
return import.meta.env;
};
export { warpperEnv, loadEnv };

View File

@@ -12,10 +12,12 @@ const include = [
"axios", "axios",
"pinia", "pinia",
"swiper", "swiper",
"lodash",
"echarts", "echarts",
"intro.js", "intro.js",
"vue-i18n", "vue-i18n",
"js-cookie", "js-cookie",
"lodash-es",
"cropperjs", "cropperjs",
"jsbarcode", "jsbarcode",
"sortablejs", "sortablejs",
@@ -25,6 +27,8 @@ const include = [
"vue3-danmaku", "vue3-danmaku",
"v-contextmenu", "v-contextmenu",
"vue-pdf-embed", "vue-pdf-embed",
"lodash-unified",
"@ctrl/tinycolor",
"china-area-data", "china-area-data",
"vue-json-pretty", "vue-json-pretty",
"@logicflow/core", "@logicflow/core",
@@ -52,6 +56,7 @@ const include = [
const exclude = [ const exclude = [
"@iconify-icons/ep", "@iconify-icons/ep",
"@iconify-icons/ri", "@iconify-icons/ri",
"@iconify-icons/mdi",
"@pureadmin/theme/dist/browser-utils" "@pureadmin/theme/dist/browser-utils"
]; ];

View File

@@ -6,10 +6,10 @@ import svgLoader from "vite-svg-loader";
import vueJsx from "@vitejs/plugin-vue-jsx"; import vueJsx from "@vitejs/plugin-vue-jsx";
import { viteMockServe } from "vite-plugin-mock"; import { viteMockServe } from "vite-plugin-mock";
import { configCompressPlugin } from "./compress"; import { configCompressPlugin } from "./compress";
import VueI18n from "@intlify/vite-plugin-vue-i18n";
import { visualizer } from "rollup-plugin-visualizer"; import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console"; import removeConsole from "vite-plugin-remove-console";
import themePreprocessorPlugin from "@pureadmin/theme"; import themePreprocessorPlugin from "@pureadmin/theme";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import DefineOptions from "unplugin-vue-define-options/vite"; import DefineOptions from "unplugin-vue-define-options/vite";
import { genScssMultipleScopeVars } from "../src/layout/theme"; import { genScssMultipleScopeVars } from "../src/layout/theme";
@@ -22,7 +22,8 @@ export function getPluginsList(
const lifecycle = process.env.npm_lifecycle_event; const lifecycle = process.env.npm_lifecycle_event;
return [ return [
vue(), vue(),
VueI18nPlugin({ // https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
VueI18n({
runtimeOnly: true, runtimeOnly: true,
compositionOnly: true, compositionOnly: true,
include: [resolve("locales/**")] include: [resolve("locales/**")]
@@ -39,7 +40,14 @@ export function getPluginsList(
themePreprocessorPlugin({ themePreprocessorPlugin({
scss: { scss: {
multipleScopeVars: genScssMultipleScopeVars(), multipleScopeVars: genScssMultipleScopeVars(),
extract: true // 在生产模式是否抽取独立的主题css文件extract为true以下属性有效
extract: true,
// 会选取defaultScopeName对应的主题css文件在html添加link
themeLinkTagId: "head",
// "head"||"head-prepend" || "body" ||"body-prepend"
themeLinkTagInjectTo: "head",
// 是否对抽取的css文件内对应scopeName的权重类名移除
removeCssScopeName: false
} }
}), }),
// svg组件化支持 // svg组件化支持

View File

@@ -1,6 +1,6 @@
{ {
"name": "vue-pure-admin", "name": "vue-pure-admin",
"version": "3.9.7", "version": "3.9.4",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=4096 vite", "dev": "NODE_OPTIONS=--max-old-space-size=4096 vite",
@@ -30,12 +30,13 @@
], ],
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1", "@amap/amap-jsapi-loader": "^1.0.1",
"@ctrl/tinycolor": "^3.4.1",
"@howdyjs/mouse-menu": "^2.0.5", "@howdyjs/mouse-menu": "^2.0.5",
"@logicflow/core": "^1.1.30", "@logicflow/core": "^1.1.30",
"@logicflow/extension": "^1.1.30", "@logicflow/extension": "^1.1.30",
"@pureadmin/descriptions": "^1.1.0", "@pureadmin/descriptions": "^1.1.0",
"@pureadmin/table": "^1.9.0", "@pureadmin/table": "^1.8.3",
"@pureadmin/utils": "^1.8.5", "@pureadmin/utils": "^1.7.4",
"@vueuse/core": "^9.6.0", "@vueuse/core": "^9.6.0",
"@vueuse/motion": "2.0.0-beta.12", "@vueuse/motion": "2.0.0-beta.12",
"@wangeditor/editor": "^5.1.21", "@wangeditor/editor": "^5.1.21",
@@ -47,17 +48,20 @@
"dayjs": "^1.11.6", "dayjs": "^1.11.6",
"echarts": "^5.4.0", "echarts": "^5.4.0",
"el-table-infinite-scroll": "^3.0.1", "el-table-infinite-scroll": "^3.0.1",
"element-plus": "^2.2.27", "element-plus": "^2.2.26",
"element-resize-detector": "^1.2.4", "element-resize-detector": "^1.2.4",
"intro.js": "^6.0.0", "intro.js": "^6.0.0",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"jsbarcode": "^3.11.5", "jsbarcode": "^3.11.5",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lodash-unified": "^1.0.2",
"md-editor-v3": "^2.5.0", "md-editor-v3": "^2.5.0",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path": "^0.12.7", "path": "^0.12.7",
"pinia": "^2.0.28", "pinia": "^2.0.27",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"qs": "^6.11.0", "qs": "^6.11.0",
"responsive-storage": "^2.1.0", "responsive-storage": "^2.1.0",
@@ -71,8 +75,8 @@
"vue-pdf-embed": "^1.1.5", "vue-pdf-embed": "^1.1.5",
"vue-router": "^4.1.6", "vue-router": "^4.1.6",
"vue-types": "^4.2.1", "vue-types": "^4.2.1",
"vue-virtual-scroller": "2.0.0-beta.7", "vue-virtual-scroller": "^2.0.0-alpha.1",
"vue3-danmaku": "^1.2.0", "vue3-danmaku": "^1.1.0",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"xgplayer": "^2.32.1", "xgplayer": "^2.32.1",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
@@ -81,13 +85,16 @@
"@commitlint/cli": "13.1.0", "@commitlint/cli": "13.1.0",
"@commitlint/config-conventional": "13.1.0", "@commitlint/config-conventional": "13.1.0",
"@iconify-icons/ep": "^1.2.7", "@iconify-icons/ep": "^1.2.7",
"@iconify-icons/mdi": "^1.2.8",
"@iconify-icons/ri": "^1.2.3", "@iconify-icons/ri": "^1.2.3",
"@iconify/vue": "^4.0.0", "@iconify/vue": "^4.0.0",
"@intlify/unplugin-vue-i18n": "^0.8.1", "@intlify/vite-plugin-vue-i18n": "^6.0.3",
"@pureadmin/theme": "^3.0.0", "@pureadmin/theme": "^2.4.0",
"@types/element-resize-detector": "1.1.3", "@types/element-resize-detector": "1.1.3",
"@types/intro.js": "^5.1.0", "@types/intro.js": "^5.1.0",
"@types/js-cookie": "^3.0.1", "@types/js-cookie": "^3.0.1",
"@types/lodash": "^4.14.180",
"@types/lodash-es": "^4.17.6",
"@types/mockjs": "^1.0.7", "@types/mockjs": "^1.0.7",
"@types/node": "^18.11.9", "@types/node": "^18.11.9",
"@types/nprogress": "0.2.0", "@types/nprogress": "0.2.0",
@@ -96,8 +103,8 @@
"@types/sortablejs": "^1.15.0", "@types/sortablejs": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0", "@typescript-eslint/parser": "^5.43.0",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^3.2.0",
"@vitejs/plugin-vue-jsx": "^3.0.0", "@vitejs/plugin-vue-jsx": "^2.1.1",
"@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^11.0.2", "@vue/eslint-config-typescript": "^11.0.2",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
@@ -130,7 +137,7 @@
"terser": "^5.15.1", "terser": "^5.15.1",
"typescript": "^4.9.3", "typescript": "^4.9.3",
"unplugin-vue-define-options": "^1.0.0", "unplugin-vue-define-options": "^1.0.0",
"vite": "^4.0.3", "vite": "3.1.8",
"vite-plugin-cdn-import": "^0.3.5", "vite-plugin-cdn-import": "^0.3.5",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^2.9.6", "vite-plugin-mock": "^2.9.6",

1523
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{ {
"Version": "3.9.7", "Version": "3.9.4",
"Title": "PureAdmin", "Title": "PureAdmin",
"FixedHeader": true, "FixedHeader": true,
"HiddenSideBar": false, "HiddenSideBar": false,
@@ -17,7 +17,7 @@
"ShowLogo": true, "ShowLogo": true,
"ShowModel": "smart", "ShowModel": "smart",
"MenuArrowIconNoTransition": true, "MenuArrowIconNoTransition": true,
"CachingAsyncRoutes": false, "CachingAsyncRoutes": true,
"TooltipEffect": "light", "TooltipEffect": "light",
"MapConfigure": { "MapConfigure": {
"amapKey": "97b3248d1553172e81f168cf94ea667e", "amapKey": "97b3248d1553172e81f168cf94ea667e",

View File

@@ -10,11 +10,6 @@ type Result = {
}; };
}; };
type ResultDept = {
success: boolean;
data?: Array<any>;
};
/** 获取用户管理列表 */ /** 获取用户管理列表 */
export const getUserList = (data?: object) => { export const getUserList = (data?: object) => {
return http.request<Result>("post", "/user", { data }); return http.request<Result>("post", "/user", { data });
@@ -27,5 +22,5 @@ export const getRoleList = (data?: object) => {
/** 获取部门管理列表 */ /** 获取部门管理列表 */
export const getDeptList = (data?: object) => { export const getDeptList = (data?: object) => {
return http.request<ResultDept>("post", "/dept", { data }); return http.request<Result>("post", "/dept", { data });
}; };

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { cloneDeep } from "@pureadmin/utils"; import { cloneDeep } from "lodash-unified";
import { IconJson } from "@/components/ReIcon/data"; import { IconJson } from "@/components/ReIcon/data";
import { ref, computed, CSSProperties, toRef, watch } from "vue"; import { ref, computed, CSSProperties, toRef, watch } from "vue";
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined; type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;

View File

@@ -43,3 +43,7 @@ addIcon("setting", Setting);
addIcon("dept", Dept); addIcon("dept", Dept);
addIcon("lollipop", Lollipop); addIcon("lollipop", Lollipop);
addIcon("monitor", Monitor); addIcon("monitor", Monitor);
// 非菜单图标
import RefreshRight from "@iconify-icons/ep/refresh-right";
addIcon("refreshRight", RefreshRight);

View File

@@ -1,5 +0,0 @@
import pureTableBar from "./src/bar";
import { withInstall } from "@pureadmin/utils";
/** 配合 `@pureadmin/table` 实现快速便捷的表格操作 https://github.com/xiaoxian521/pure-admin-table */
export const PureTableBar = withInstall(pureTableBar);

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 441 B

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 163 B

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 235 B

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1011 B

View File

@@ -8,10 +8,11 @@ import {
defineComponent defineComponent
} from "vue"; } from "vue";
import "./index.scss"; import "./index.scss";
import { cloneDeep } from "lodash-unified";
import { isString } from "@pureadmin/utils";
import { propTypes } from "@/utils/propTypes"; import { propTypes } from "@/utils/propTypes";
import { isString, cloneDeep } from "@pureadmin/utils"; import { IconifyIconOffline } from "../../ReIcon";
import QRCode, { QRCodeRenderersOptions } from "qrcode"; import QRCode, { QRCodeRenderersOptions } from "qrcode";
import RefreshRight from "@iconify-icons/ep/refresh-right";
interface QrcodeLogo { interface QrcodeLogo {
src?: string; src?: string;
@@ -96,7 +97,7 @@ export default defineComponent({
width: props.width, width: props.width,
...options ...options
}); });
(unref(wrapRef) as any).src = url; (unref(wrapRef) as HTMLImageElement).src = url;
emit("done", url); emit("done", url);
loading.value = false; loading.value = false;
} }
@@ -244,9 +245,9 @@ export default defineComponent({
onClick={disabledClick} onClick={disabledClick}
> >
<div class="absolute top-[50%] left-[50%] font-bold"> <div class="absolute top-[50%] left-[50%] font-bold">
<iconify-icon-offline <IconifyIconOffline
class="cursor-pointer" class="cursor-pointer"
icon={RefreshRight} icon="refreshRight"
width="30" width="30"
color="var(--el-color-primary)" color="var(--el-color-primary)"
/> />

View File

@@ -0,0 +1,5 @@
import tableProBar from "./src/bar";
import { withInstall } from "@pureadmin/utils";
/** table-crud组件 */
export const TableProBar = withInstall(tableProBar);

View File

@@ -1,25 +1,54 @@
import { delay } from "@pureadmin/utils"; import { defineComponent, ref, computed, PropType } from "vue";
import { useEpThemeStoreHook } from "@/store/modules/epTheme"; import { useEpThemeStoreHook } from "@/store/modules/epTheme";
import { defineComponent, ref, computed, type PropType } from "vue";
import ExpandIcon from "./svg/expand.svg?component"; import UnExpand from "@iconify-icons/mdi/arrow-expand-right";
import RefreshIcon from "./svg/refresh.svg?component"; import { IconifyIconOffline } from "../../ReIcon";
import SettingIcon from "./svg/settings.svg?component"; import Expand from "@iconify-icons/mdi/arrow-expand-down";
import CollapseIcon from "./svg/collapse.svg?component"; import ArrowCollapse from "@iconify-icons/mdi/arrow-collapse-vertical";
import Setting from "@iconify-icons/ri/settings-3-line";
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)"
/>
`;
const props = { const props = {
/** 头部最左边的标题 */ // 头部最左边的标题
title: { title: {
type: String, type: String,
default: "列表" default: "列表"
}, },
/** 对于树形表格如果想启用展开和折叠功能传入当前表格的ref即可 */ // 表格数据
dataList: {
type: Array,
default: () => {
return [];
}
},
// 对于树形表格如果想启用展开和折叠功能传入当前表格的ref即可
tableRef: { tableRef: {
type: Object as PropType<any> type: Object as PropType<any>,
default() {
return {};
}
},
// 是否显示加载动画默认false 不加载
loading: {
type: Boolean,
default: false
} }
}; };
export default defineComponent({ export default defineComponent({
name: "PureTableBar", name: "TableProBar",
props, props,
emits: ["refresh"], emits: ["refresh"],
setup(props, { emit, slots, attrs }) { setup(props, { emit, slots, attrs }) {
@@ -27,7 +56,6 @@ export default defineComponent({
const checkList = ref([]); const checkList = ref([]);
const size = ref("default"); const size = ref("default");
const isExpandAll = ref(true); const isExpandAll = ref(true);
const loading = ref(false);
const getDropdownItemStyle = computed(() => { const getDropdownItemStyle = computed(() => {
return s => { return s => {
@@ -39,26 +67,9 @@ 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() { function onExpand() {
isExpandAll.value = !isExpandAll.value; isExpandAll.value = !isExpandAll.value;
toggleRowExpansionAll(props.tableRef.data, isExpandAll.value); toggleRowExpansionAll(props.dataList, isExpandAll.value);
} }
function toggleRowExpansionAll(data, isExpansion) { function toggleRowExpansionAll(data, isExpansion) {
@@ -77,7 +88,7 @@ export default defineComponent({
style={getDropdownItemStyle.value("large")} style={getDropdownItemStyle.value("large")}
onClick={() => (size.value = "large")} onClick={() => (size.value = "large")}
> >
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item <el-dropdown-item
style={getDropdownItemStyle.value("default")} style={getDropdownItemStyle.value("default")}
@@ -97,8 +108,11 @@ export default defineComponent({
const reference = { const reference = {
reference: () => ( reference: () => (
<SettingIcon <IconifyIconOffline
class={["w-[16px]", iconClass.value]} class="cursor-pointer"
icon={Setting}
width="16"
color="text_color_regular"
onMouseover={e => (buttonRef.value = e.currentTarget)} onMouseover={e => (buttonRef.value = e.currentTarget)}
/> />
) )
@@ -106,7 +120,13 @@ export default defineComponent({
return () => ( return () => (
<> <>
<div {...attrs} class="w-[99/100] mt-6 p-2 bg-bg_color"> <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 class="flex justify-between w-full h-[60px] p-4"> <div class="flex justify-between w-full h-[60px] p-4">
<p class="font-bold truncate">{props.title}</p> <p class="font-bold truncate">{props.title}</p>
<div class="flex items-center justify-around"> <div class="flex items-center justify-around">
@@ -118,32 +138,36 @@ export default defineComponent({
content={isExpandAll.value ? "折叠" : "展开"} content={isExpandAll.value ? "折叠" : "展开"}
placement="top" placement="top"
> >
<ExpandIcon <IconifyIconOffline
class={["w-[16px]", iconClass.value]} class="cursor-pointer"
style={{ icon={isExpandAll.value ? UnExpand : Expand}
transform: isExpandAll.value ? "none" : "rotate(-90deg)" width="16"
}} color="text_color_regular"
onClick={() => onExpand()} onClick={() => onExpand()}
/> />
</el-tooltip> </el-tooltip>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
</> </>
) : null} ) : undefined}
<el-tooltip effect="dark" content="刷新" placement="top"> <el-tooltip effect="dark" content="刷新" placement="top">
<RefreshIcon <IconifyIconOffline
class={[ class="cursor-pointer"
"w-[16px]", icon="refreshRight"
iconClass.value, width="16"
loading.value ? "animate-spin" : "" color="text_color_regular"
]} onClick={() => emit("refresh")}
onClick={() => onReFresh()}
/> />
</el-tooltip> </el-tooltip>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-tooltip effect="dark" content="密度" placement="top"> <el-tooltip effect="dark" content="密度" placement="top">
<el-dropdown v-slots={dropdown} trigger="click"> <el-dropdown v-slots={dropdown} trigger="click">
<CollapseIcon class={["w-[16px]", iconClass.value]} /> <IconifyIconOffline
class="cursor-pointer"
icon={ArrowCollapse}
width="16"
color="text_color_regular"
/>
</el-dropdown> </el-dropdown>
</el-tooltip> </el-tooltip>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
@@ -175,7 +199,11 @@ export default defineComponent({
content="列设置" content="列设置"
/> />
</div> </div>
{slots.default({ size: size.value, checkList: checkList.value })} {props.dataList.length > 0 ? (
slots.default({ size: size.value, checkList: checkList.value })
) : (
<el-empty description="暂无数据" />
)}
</div> </div>
</> </>
); );

View File

@@ -1,8 +1,9 @@
import { App } from "vue"; import { App } from "vue";
import axios from "axios"; import axios from "axios";
import { loadEnv } from "@build/index";
let config: object = {}; let config: object = {};
const { VITE_PUBLIC_PATH } = import.meta.env; const { VITE_PUBLIC_PATH } = loadEnv();
const setConfig = (cfg?: unknown) => { const setConfig = (cfg?: unknown) => {
config = Object.assign(config, cfg); config = Object.assign(config, cfg);

View File

@@ -5,7 +5,7 @@ export const auth: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) { mounted(el: HTMLElement, binding: DirectiveBinding) {
const { value } = binding; const { value } = binding;
if (value) { if (value) {
!hasAuth(value) && el.parentNode?.removeChild(el); !hasAuth(value) && el.parentNode.removeChild(el);
} else { } else {
throw new Error("need auths! Like v-auth=\"['btn.add','btn.edit']\""); throw new Error("need auths! Like v-auth=\"['btn.add','btn.edit']\"");
} }

View File

@@ -70,8 +70,14 @@ notices.value.map(v => (noticesNum.value += v.list.length));
height: 1px; height: 1px;
} }
// 如果上面的 notices 长度大于 3 请注释掉下面代码
:deep(.el-tabs__nav-wrap) { :deep(.el-tabs__nav-wrap) {
padding: 0 36px 0 36px; padding: 0 36px 0 36px;
} }
// 如果上面的 notices 长度大于 3 请注释掉下面代码
:deep(.el-tabs__active-bar) {
margin: 0 36px 0 36px;
}
} }
</style> </style>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { cloneDeep } from "@pureadmin/utils"; import { cloneDeep } from "lodash-unified";
import SearchResult from "./SearchResult.vue"; import SearchResult from "./SearchResult.vue";
import SearchFooter from "./SearchFooter.vue"; import SearchFooter from "./SearchFooter.vue";
import { deleteChildren } from "@/utils/tree"; import { deleteChildren } from "@/utils/tree";

View File

@@ -132,8 +132,8 @@ const multiTagsCacheChange = () => {
/** 清空缓存并返回登录页 */ /** 清空缓存并返回登录页 */
function onReset() { function onReset() {
removeToken(); removeToken();
storageLocal().clear(); storageLocal.clear();
storageSession().clear(); storageSession.clear();
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig(); const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
useAppStoreHook().setLayout(Layout); useAppStoreHook().setLayout(Layout);
setEpThemeColor(EpThemeColor); setEpThemeColor(EpThemeColor);

View File

@@ -144,8 +144,7 @@ function resolvePath(routePath) {
if (httpReg.test(routePath) || httpReg.test(props.basePath)) { if (httpReg.test(routePath) || httpReg.test(props.basePath)) {
return routePath || props.basePath; return routePath || props.basePath;
} else { } else {
// 使用path.posix.resolve替代path.resolve 避免windows环境下使用electron出现盘符问题 return path.resolve(props.basePath, routePath);
return path.posix.resolve(props.basePath, routePath);
} }
} }
</script> </script>

View File

@@ -12,8 +12,7 @@ import { usePermissionStoreHook } from "@/store/modules/permission";
const route = useRoute(); const route = useRoute();
const showLogo = ref( const showLogo = ref(
storageLocal().getItem<StorageConfigs>("responsive-configure")?.showLogo ?? storageLocal.getItem<StorageConfigs>("responsive-configure")?.showLogo ?? true
true
); );
const { routers, device, pureApp, isCollapse, menuSelect, toggleSideBar } = const { routers, device, pureApp, isCollapse, menuSelect, toggleSideBar } =

View File

@@ -4,7 +4,7 @@ import { emitter } from "@/utils/mitt";
import { RouteConfigs } from "../../types"; import { RouteConfigs } from "../../types";
import { useTags } from "../../hooks/useTag"; import { useTags } from "../../hooks/useTag";
import { routerArrays } from "@/layout/types"; import { routerArrays } from "@/layout/types";
import { isEqual, isAllEmpty } from "@pureadmin/utils"; import { isEqual, isEmpty } from "lodash-unified";
import { useSettingStoreHook } from "@/store/modules/settings"; import { useSettingStoreHook } from "@/store/modules/settings";
import { ref, watch, unref, nextTick, onBeforeMount } from "vue"; import { ref, watch, unref, nextTick, onBeforeMount } from "vue";
import { handleAliveRoute, delAliveRoutes } from "@/router/utils"; import { handleAliveRoute, delAliveRoutes } from "@/router/utils";
@@ -349,7 +349,7 @@ function showMenuModel(
const allRoute = multiTags.value; const allRoute = multiTags.value;
const routeLength = multiTags.value.length; const routeLength = multiTags.value.length;
let currentIndex = -1; let currentIndex = -1;
if (isAllEmpty(query)) { if (isEmpty(query)) {
currentIndex = allRoute.findIndex(v => v.path === currentPath); currentIndex = allRoute.findIndex(v => v.path === currentPath);
} else { } else {
currentIndex = allRoute.findIndex(v => isEqual(v.query, query)); currentIndex = allRoute.findIndex(v => isEqual(v.query, query));

View File

@@ -1,7 +1,9 @@
import { ref } from "vue"; import { ref } from "vue";
import { getConfig } from "@/config"; import { getConfig } from "@/config";
import { find } from "lodash-unified";
import { useLayout } from "./useLayout"; import { useLayout } from "./useLayout";
import { themeColorsType } from "../types"; import { themeColorsType } from "../types";
import { TinyColor } from "@ctrl/tinycolor";
import { useGlobal } from "@pureadmin/utils"; import { useGlobal } from "@pureadmin/utils";
import { useEpThemeStoreHook } from "@/store/modules/epTheme"; import { useEpThemeStoreHook } from "@/store/modules/epTheme";
import { import {
@@ -54,27 +56,35 @@ export function useDataThemeChange() {
if (theme === "default" || theme === "light") { if (theme === "default" || theme === "light") {
setEpThemeColor(getConfig().EpThemeColor); setEpThemeColor(getConfig().EpThemeColor);
} else { } else {
const colors = themeColors.value.find(v => v.themeColor === theme); const colors = find(themeColors.value, { themeColor: theme });
setEpThemeColor(colors.color); setEpThemeColor(colors.color);
} }
} }
function setPropertyPrimary(mode: string, i: number, color: string) { /**
document.documentElement.style.setProperty( * @description 自动计算hover和active颜色
`--el-color-primary-${mode}-${i}`, * @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}
dataTheme.value ? darken(color, i / 10) : lighten(color, i / 10) */
); const shadeBgColor = (color: string): string => {
} return new TinyColor(color).shade(10).toString();
};
/** 设置 `element-plus` 主题色 */ /** 设置 `element-plus` 主题色 */
const setEpThemeColor = (color: string) => { const setEpThemeColor = (color: string) => {
useEpThemeStoreHook().setEpThemeColor(color); useEpThemeStoreHook().setEpThemeColor(color);
body.style.setProperty("--el-color-primary-active", shadeBgColor(color));
document.documentElement.style.setProperty("--el-color-primary", color); document.documentElement.style.setProperty("--el-color-primary", color);
for (let i = 1; i <= 2; i++) {
setPropertyPrimary("dark", i, color);
}
for (let i = 1; i <= 9; i++) { for (let i = 1; i <= 9; i++) {
setPropertyPrimary("light", i, color); 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)
);
} }
}; };

View File

@@ -41,13 +41,13 @@ export function useTags() {
/** 显示模式,默认灵动模式 */ /** 显示模式,默认灵动模式 */
const showModel = ref( const showModel = ref(
storageLocal().getItem<StorageConfigs>("responsive-configure")?.showModel || storageLocal.getItem<StorageConfigs>("responsive-configure")?.showModel ||
"smart" "smart"
); );
/** 是否隐藏标签页,默认显示 */ /** 是否隐藏标签页,默认显示 */
const showTags = const showTags =
ref( ref(
storageLocal().getItem<StorageConfigs>("responsive-configure").hideTabs storageLocal.getItem<StorageConfigs>("responsive-configure").hideTabs
) ?? ref("false"); ) ?? ref("false");
const multiTags: any = computed(() => { const multiTags: any = computed(() => {
return useMultiTagsStoreHook().multiTags; return useMultiTagsStoreHook().multiTags;
@@ -195,11 +195,11 @@ export function useTags() {
onMounted(() => { onMounted(() => {
if (!showModel.value) { if (!showModel.value) {
const configure = storageLocal().getItem<StorageConfigs>( const configure = storageLocal.getItem<StorageConfigs>(
"responsive-configure" "responsive-configure"
); );
configure.showModel = "card"; configure.showModel = "card";
storageLocal().setItem("responsive-configure", configure); storageLocal.setItem("responsive-configure", configure);
} }
}); });

View File

@@ -2,7 +2,10 @@
* @description ⚠️:此文件仅供主题插件使用,请不要在此文件中导出别的工具函数(仅在页面加载前运行) * @description ⚠️:此文件仅供主题插件使用,请不要在此文件中导出别的工具函数(仅在页面加载前运行)
*/ */
import { type multipleScopeVarsOptions } from "@pureadmin/theme"; type MultipleScopeVarsItem = {
scopeName: string;
varsContent: string;
};
/** 预设主题色 */ /** 预设主题色 */
const themeColors = { const themeColors = {
@@ -110,8 +113,8 @@ const themeColors = {
/** /**
* @description 将预设主题色处理成主题插件所需格式 * @description 将预设主题色处理成主题插件所需格式
*/ */
export const genScssMultipleScopeVars = (): multipleScopeVarsOptions[] => { export const genScssMultipleScopeVars = (): MultipleScopeVarsItem[] => {
const result = [] as multipleScopeVarsOptions[]; const result = [] as MultipleScopeVarsItem[];
Object.keys(themeColors).forEach(key => { Object.keys(themeColors).forEach(key => {
result.push({ result.push({
scopeName: `layout-theme-${key}`, scopeName: `layout-theme-${key}`,
@@ -126,7 +129,7 @@ export const genScssMultipleScopeVars = (): multipleScopeVarsOptions[] => {
$menuTitleHover: ${themeColors[key].menuTitleHover} !default; $menuTitleHover: ${themeColors[key].menuTitleHover} !default;
$menuActiveBefore: ${themeColors[key].menuActiveBefore} !default; $menuActiveBefore: ${themeColors[key].menuActiveBefore} !default;
` `
} as multipleScopeVarsOptions); } as MultipleScopeVarsItem);
}); });
return result; return result;
}; };

View File

@@ -16,8 +16,6 @@ import PureDescriptions from "@pureadmin/descriptions";
import "./style/reset.scss"; import "./style/reset.scss";
// 导入公共样式 // 导入公共样式
import "./style/index.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 "element-plus/dist/index.css";
// 导入字体图标 // 导入字体图标
import "./assets/iconfont/iconfont.js"; import "./assets/iconfont/iconfont.js";

View File

@@ -63,7 +63,7 @@ export const $t = (key: string) => key;
export const i18n: I18n = createI18n({ export const i18n: I18n = createI18n({
legacy: false, legacy: false,
locale: locale:
storageLocal().getItem<StorageConfigs>("responsive-locale")?.locale ?? "zh", storageLocal.getItem<StorageConfigs>("responsive-locale")?.locale ?? "zh",
fallbackLocale: "en", fallbackLocale: "en",
messages: localesConfigs messages: localesConfigs
}); });

View File

@@ -1,6 +1,7 @@
import "@/utils/sso"; import "@/utils/sso";
import { getConfig } from "@/config"; import { getConfig } from "@/config";
import NProgress from "@/utils/progress"; import NProgress from "@/utils/progress";
import { findIndex } from "lodash-unified";
import { transformI18n } from "@/plugins/i18n"; import { transformI18n } from "@/plugins/i18n";
import { sessionKey, type DataInfo } from "@/utils/auth"; import { sessionKey, type DataInfo } from "@/utils/auth";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
@@ -105,7 +106,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
handleAliveRoute(newMatched); handleAliveRoute(newMatched);
} }
} }
const userInfo = storageSession().getItem<DataInfo<number>>(sessionKey); const userInfo = storageSession.getItem<DataInfo<number>>(sessionKey);
NProgress.start(); NProgress.start();
const externalLink = isUrl(to?.name as string); const externalLink = isUrl(to?.name as string);
if (!externalLink) { if (!externalLink) {
@@ -143,10 +144,14 @@ router.beforeEach((to: toRouteType, _from, next) => {
initRouter().then((router: Router) => { initRouter().then((router: Router) => {
if (!useMultiTagsStoreHook().getMultiTagsCache) { if (!useMultiTagsStoreHook().getMultiTagsCache) {
const { path } = to; const { path } = to;
const route = findRouteByPath( const index = findIndex(remainingRouter, v => {
path, return v.path == path;
router.options.routes[0].children });
); const routes: any =
index === -1
? router.options.routes[0].children
: router.options.routes;
const route = findRouteByPath(path, routes);
// query、params模式路由传参数的标签页不在此处处理 // query、params模式路由传参数的标签页不在此处处理
if (route && route.meta?.title) { if (route && route.meta?.title) {
useMultiTagsStoreHook().handleTags("push", { useMultiTagsStoreHook().handleTags("push", {

View File

@@ -6,7 +6,6 @@ export default {
redirect: "/error/403", redirect: "/error/403",
meta: { meta: {
icon: "informationLine", icon: "informationLine",
// showLink: false,
title: $t("menus.hsabnormal"), title: $t("menus.hsabnormal"),
rank: error rank: error
}, },

View File

@@ -8,18 +8,17 @@ import {
} from "vue-router"; } from "vue-router";
import { router } from "./index"; import { router } from "./index";
import { isProxy, toRaw } from "vue"; import { isProxy, toRaw } from "vue";
import { loadEnv } from "../../build";
import { useTimeoutFn } from "@vueuse/core"; import { useTimeoutFn } from "@vueuse/core";
import { RouteConfigs } from "@/layout/types"; import { RouteConfigs } from "@/layout/types";
import { import {
isString, isString,
cloneDeep,
isAllEmpty,
intersection,
storageSession, storageSession,
isIncludeAllChildren isIncludeAllChildren
} from "@pureadmin/utils"; } from "@pureadmin/utils";
import { getConfig } from "@/config"; import { getConfig } from "@/config";
import { buildHierarchyTree } from "@/utils/tree"; import { buildHierarchyTree } from "@/utils/tree";
import { cloneDeep, intersection } from "lodash-unified";
import { sessionKey, type DataInfo } from "@/utils/auth"; import { sessionKey, type DataInfo } from "@/utils/auth";
import { usePermissionStoreHook } from "@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
const IFrame = () => import("@/layout/frameView.vue"); const IFrame = () => import("@/layout/frameView.vue");
@@ -29,25 +28,19 @@ const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
// 动态路由 // 动态路由
import { getAsyncRoutes } from "@/api/routes"; 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等级升序来排序路由 */ /** 按照路由中meta下的rank等级升序来排序路由 */
function ascending(arr: any[]) { function ascending(arr: any[]) {
arr.forEach((v, index) => { arr.forEach(v => {
// 当rank不存在时根据顺序自动创建首页路由永远在第一位 if (v?.meta?.rank === null) v.meta.rank = undefined;
if (handRank(v)) v.meta.rank = index + 2; if (v?.meta?.rank === 0) {
if (v.name !== "Home" && v.path !== "/") {
console.warn("rank only the home page can be 0");
}
}
}); });
return arr.sort( return arr.sort(
(a: { meta: { rank: number } }, b: { meta: { rank: number } }) => { (a: { meta: { rank: number } }, b: { meta: { rank: number } }) => {
return a?.meta.rank - b?.meta.rank; return a?.meta?.rank - b?.meta?.rank;
} }
); );
} }
@@ -84,7 +77,7 @@ function isOneOfArray(a: Array<string>, b: Array<string>) {
/** 从sessionStorage里取出当前登陆用户的角色roles过滤无权限的菜单 */ /** 从sessionStorage里取出当前登陆用户的角色roles过滤无权限的菜单 */
function filterNoPermissionTree(data: RouteComponent[]) { function filterNoPermissionTree(data: RouteComponent[]) {
const currentRoles = const currentRoles =
storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? []; storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
const newTree = cloneDeep(data).filter((v: any) => const newTree = cloneDeep(data).filter((v: any) =>
isOneOfArray(v.meta?.roles, currentRoles) isOneOfArray(v.meta?.roles, currentRoles)
); );
@@ -196,7 +189,7 @@ function initRouter() {
if (getConfig()?.CachingAsyncRoutes) { if (getConfig()?.CachingAsyncRoutes) {
// 开启动态路由缓存本地sessionStorage // 开启动态路由缓存本地sessionStorage
const key = "async-routes"; const key = "async-routes";
const asyncRouteList = storageSession().getItem(key) as any; const asyncRouteList = storageSession.getItem(key) as any;
if (asyncRouteList && asyncRouteList?.length > 0) { if (asyncRouteList && asyncRouteList?.length > 0) {
return new Promise(resolve => { return new Promise(resolve => {
handleAsyncRoutes(asyncRouteList); handleAsyncRoutes(asyncRouteList);
@@ -206,7 +199,7 @@ function initRouter() {
return new Promise(resolve => { return new Promise(resolve => {
getAsyncRoutes().then(({ data }) => { getAsyncRoutes().then(({ data }) => {
handleAsyncRoutes(cloneDeep(data)); handleAsyncRoutes(cloneDeep(data));
storageSession().setItem(key, data); storageSession.setItem(key, data);
resolve(router); resolve(router);
}); });
}); });
@@ -259,7 +252,7 @@ function formatTwoStageRoutes(routesList: RouteRecordRaw[]) {
children: [] children: []
}); });
} else { } else {
newRoutesList[0]?.children.push({ ...v }); newRoutesList[0].children.push({ ...v });
} }
}); });
return newRoutesList; return newRoutesList;
@@ -323,7 +316,7 @@ function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>) {
/** 获取路由历史模式 https://next.router.vuejs.org/zh/guide/essentials/history-mode.html */ /** 获取路由历史模式 https://next.router.vuejs.org/zh/guide/essentials/history-mode.html */
function getHistoryMode(): RouterHistory { function getHistoryMode(): RouterHistory {
const routerHistory = import.meta.env.VITE_ROUTER_HISTORY; const routerHistory = loadEnv().VITE_ROUTER_HISTORY;
// len为1 代表只有历史模式 为2 代表历史模式中存在base参数 https://next.router.vuejs.org/zh/api/#%E5%8F%82%E6%95%B0-1 // len为1 代表只有历史模式 为2 代表历史模式中存在base参数 https://next.router.vuejs.org/zh/api/#%E5%8F%82%E6%95%B0-1
const historyMode = routerHistory.split(","); const historyMode = routerHistory.split(",");
const leftMode = historyMode[0]; const leftMode = historyMode[0];
@@ -355,7 +348,6 @@ function hasAuth(value: string | Array<string>): boolean {
if (!value) return false; if (!value) return false;
/** 从当前路由的`meta`字段里获取按钮级别的所有自定义`code`值 */ /** 从当前路由的`meta`字段里获取按钮级别的所有自定义`code`值 */
const metaAuths = getAuths(); const metaAuths = getAuths();
if (!metaAuths) return false;
const isAuths = isString(value) const isAuths = isString(value)
? metaAuths.includes(value) ? metaAuths.includes(value)
: isIncludeAllChildren(value, metaAuths); : isIncludeAllChildren(value, metaAuths);

View File

@@ -9,14 +9,14 @@ export const useAppStore = defineStore({
state: (): appType => ({ state: (): appType => ({
sidebar: { sidebar: {
opened: opened:
storageLocal().getItem<StorageConfigs>("responsive-layout") storageLocal.getItem<StorageConfigs>("responsive-layout")
?.sidebarStatus ?? getConfig().SidebarStatus, ?.sidebarStatus ?? getConfig().SidebarStatus,
withoutAnimation: false, withoutAnimation: false,
isClickCollapse: false isClickCollapse: false
}, },
// 这里的layout用于监听容器拖拉后恢复对应的导航模式 // 这里的layout用于监听容器拖拉后恢复对应的导航模式
layout: layout:
storageLocal().getItem<StorageConfigs>("responsive-layout")?.layout ?? storageLocal.getItem<StorageConfigs>("responsive-layout")?.layout ??
getConfig().Layout, getConfig().Layout,
device: deviceDetection() ? "mobile" : "desktop", device: deviceDetection() ? "mobile" : "desktop",
// 作用于 src/views/components/draggable/index.vue 页面,当离开页面并不会销毁 new Swap()sortablejs 官网也没有提供任何销毁的 api // 作用于 src/views/components/draggable/index.vue 页面,当离开页面并不会销毁 new Swap()sortablejs 官网也没有提供任何销毁的 api
@@ -32,8 +32,7 @@ export const useAppStore = defineStore({
}, },
actions: { actions: {
TOGGLE_SIDEBAR(opened?: boolean, resize?: string) { TOGGLE_SIDEBAR(opened?: boolean, resize?: string) {
const layout = const layout = storageLocal.getItem<StorageConfigs>("responsive-layout");
storageLocal().getItem<StorageConfigs>("responsive-layout");
if (opened && resize) { if (opened && resize) {
this.sidebar.withoutAnimation = true; this.sidebar.withoutAnimation = true;
this.sidebar.opened = true; this.sidebar.opened = true;
@@ -48,7 +47,7 @@ export const useAppStore = defineStore({
this.sidebar.isClickCollapse = !this.sidebar.opened; this.sidebar.isClickCollapse = !this.sidebar.opened;
layout.sidebarStatus = this.sidebar.opened; layout.sidebarStatus = this.sidebar.opened;
} }
storageLocal().setItem("responsive-layout", layout); storageLocal.setItem("responsive-layout", layout);
}, },
async toggleSideBar(opened?: boolean, resize?: string) { async toggleSideBar(opened?: boolean, resize?: string) {
await this.TOGGLE_SIDEBAR(opened, resize); await this.TOGGLE_SIDEBAR(opened, resize);

View File

@@ -7,10 +7,10 @@ export const useEpThemeStore = defineStore({
id: "pure-epTheme", id: "pure-epTheme",
state: () => ({ state: () => ({
epThemeColor: epThemeColor:
storageLocal().getItem<StorageConfigs>("responsive-layout") storageLocal.getItem<StorageConfigs>("responsive-layout")?.epThemeColor ??
?.epThemeColor ?? getConfig().EpThemeColor, getConfig().EpThemeColor,
epTheme: epTheme:
storageLocal().getItem<StorageConfigs>("responsive-layout")?.theme ?? storageLocal.getItem<StorageConfigs>("responsive-layout")?.theme ??
getConfig().Theme getConfig().Theme
}), }),
getters: { getters: {
@@ -30,13 +30,12 @@ export const useEpThemeStore = defineStore({
}, },
actions: { actions: {
setEpThemeColor(newColor: string): void { setEpThemeColor(newColor: string): void {
const layout = const layout = storageLocal.getItem<StorageConfigs>("responsive-layout");
storageLocal().getItem<StorageConfigs>("responsive-layout");
this.epTheme = layout?.theme; this.epTheme = layout?.theme;
this.epThemeColor = newColor; this.epThemeColor = newColor;
if (!layout) return; if (!layout) return;
layout.epThemeColor = newColor; layout.epThemeColor = newColor;
storageLocal().setItem("responsive-layout", layout); storageLocal.setItem("responsive-layout", layout);
} }
} }
}); });

View File

@@ -9,13 +9,12 @@ export const useMultiTagsStore = defineStore({
id: "pure-multiTags", id: "pure-multiTags",
state: () => ({ state: () => ({
// 存储标签页信息(路由信息) // 存储标签页信息(路由信息)
multiTags: storageLocal().getItem<StorageConfigs>("responsive-configure") multiTags: storageLocal.getItem<StorageConfigs>("responsive-configure")
?.multiTagsCache ?.multiTagsCache
? storageLocal().getItem<StorageConfigs>("responsive-tags") ? storageLocal.getItem<StorageConfigs>("responsive-tags")
: [...routerArrays], : [...routerArrays],
multiTagsCache: storageLocal().getItem<StorageConfigs>( multiTagsCache: storageLocal.getItem<StorageConfigs>("responsive-configure")
"responsive-configure" ?.multiTagsCache
)?.multiTagsCache
}), }),
getters: { getters: {
getMultiTagsCache() { getMultiTagsCache() {
@@ -26,14 +25,14 @@ export const useMultiTagsStore = defineStore({
multiTagsCacheChange(multiTagsCache: boolean) { multiTagsCacheChange(multiTagsCache: boolean) {
this.multiTagsCache = multiTagsCache; this.multiTagsCache = multiTagsCache;
if (multiTagsCache) { if (multiTagsCache) {
storageLocal().setItem("responsive-tags", this.multiTags); storageLocal.setItem("responsive-tags", this.multiTags);
} else { } else {
storageLocal().removeItem("responsive-tags"); storageLocal.removeItem("responsive-tags");
} }
}, },
tagsCache(multiTags) { tagsCache(multiTags) {
this.getMultiTagsCache && this.getMultiTagsCache &&
storageLocal().setItem("responsive-tags", multiTags); storageLocal.setItem("responsive-tags", multiTags);
}, },
handleTags<T>( handleTags<T>(
mode: string, mode: string,

View File

@@ -14,9 +14,9 @@ export const useUserStore = defineStore({
state: (): userType => ({ state: (): userType => ({
// 用户名 // 用户名
username: 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: "", verifyCode: "",
// 判断登录页面显示哪个组件0登录默认、1手机登录、2二维码登录、3注册、4忘记密码 // 判断登录页面显示哪个组件0登录默认、1手机登录、2二维码登录、3注册、4忘记密码

View File

@@ -1,4 +1,4 @@
@use "element-plus/theme-chalk/src/dark/css-vars.scss" as *; @import "element-plus/theme-chalk/src/dark/css-vars.scss";
/* 暗黑模式适配 */ /* 暗黑模式适配 */
html.dark { html.dark {

View File

@@ -3,6 +3,7 @@
@import "./element-plus.scss"; @import "./element-plus.scss";
@import "./sidebar.scss"; @import "./sidebar.scss";
@import "./dark.scss"; @import "./dark.scss";
@import "./tailwind.css";
/* 自定义全局 CssVar */ /* 自定义全局 CssVar */
:root { :root {

View File

@@ -23,7 +23,7 @@ export function getToken(): DataInfo<number> {
// 此处与`TokenKey`相同,此写法解决初始化时`Cookies`中不存在`TokenKey`报错 // 此处与`TokenKey`相同,此写法解决初始化时`Cookies`中不存在`TokenKey`报错
return Cookies.get(TokenKey) return Cookies.get(TokenKey)
? JSON.parse(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>) { function setSessionKey(username: string, roles: Array<string>) {
useUserStoreHook().SET_USERNAME(username); useUserStoreHook().SET_USERNAME(username);
useUserStoreHook().SET_ROLES(roles); useUserStoreHook().SET_ROLES(roles);
storageSession().setItem(sessionKey, { storageSession.setItem(sessionKey, {
refreshToken, refreshToken,
expires, expires,
username, username,
@@ -60,9 +60,9 @@ export function setToken(data: DataInfo<Date>) {
setSessionKey(username, roles); setSessionKey(username, roles);
} else { } else {
const username = const username =
storageSession().getItem<DataInfo<number>>(sessionKey)?.username ?? ""; storageSession.getItem<DataInfo<number>>(sessionKey)?.username ?? "";
const roles = const roles =
storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? []; storageSession.getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
setSessionKey(username, roles); setSessionKey(username, roles);
} }
} }

View File

@@ -1,5 +1,5 @@
import REGION_DATA from "china-area-data"; import REGION_DATA from "china-area-data";
import { cloneDeep } from "@pureadmin/utils"; import { cloneDeep } from "lodash-unified";
interface ProvinceData { interface ProvinceData {
value: string; value: string;

View File

@@ -1,11 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import { loadEnv } from "@build/index";
defineOptions({ defineOptions({
name: "Button" name: "Button"
}); });
const { VITE_PUBLIC_PATH } = import.meta.env; const { VITE_PUBLIC_PATH } = loadEnv();
const url = ref(`${VITE_PUBLIC_PATH}html/button.html`); const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
</script> </script>

View File

@@ -7,12 +7,8 @@ defineOptions({
</script> </script>
<template> <template>
<div class="w-full h-full text-center"> <div class="back" title="返回上一页" @click="$router.go(-1)">
<h1>业务内容模块</h1> <back class="w-[80px] h-[80px]" />
<p>使用场景需要外嵌平台某个页面不需要展示菜单导航以及额外模块</p>
<div class="back" title="返回上一页" @click="$router.go(-1)">
<back class="w-[80px] h-[80px]" />
</div>
</div> </div>
</template> </template>

View File

@@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { initRouter } from "@/router/utils"; import { initRouter } from "@/router/utils";
import { storageSession } from "@pureadmin/utils";
import { type CSSProperties, ref, computed } from "vue"; import { type CSSProperties, ref, computed } from "vue";
import { useUserStoreHook } from "@/store/modules/user"; import { useUserStoreHook } from "@/store/modules/user";
import { usePermissionStoreHook } from "@/store/modules/permission"; import { usePermissionStoreHook } from "@/store/modules/permission";
@@ -34,7 +33,7 @@ function onChange() {
.loginByUsername({ username: username.value, password: "admin123" }) .loginByUsername({ username: username.value, password: "admin123" })
.then(res => { .then(res => {
if (res.success) { if (res.success) {
storageSession().removeItem("async-routes"); sessionStorage.removeItem("async-routes");
usePermissionStoreHook().clearAllCachePage(); usePermissionStoreHook().clearAllCachePage();
initRouter(); initRouter();
} }

View File

@@ -16,7 +16,7 @@ export const list = [
{ {
key: "page", key: "page",
content: rendContent("page"), content: rendContent("page"),
title: "分页、加载动画、动态列", title: "分页、加载动画",
component: Page component: Page
}, },
{ {

View File

@@ -6,25 +6,19 @@ import type { PaginationProps, LoadingConfig, Align } from "@pureadmin/table";
export function useColumns() { export function useColumns() {
const dataList = ref([]); const dataList = ref([]);
const loading = ref(true); const loading = ref(true);
const hideVal = ref("nohide");
const tableSize = ref("default");
const paginationSmall = ref(false);
const paginationAlign = ref("right"); const paginationAlign = ref("right");
const columns: TableColumnList = [ const columns: TableColumnList = [
{ {
label: "日期", label: "日期",
prop: "date", prop: "date"
hide: () => (hideVal.value === "hideDate" ? true : false)
}, },
{ {
label: "姓名", label: "姓名",
prop: "name", prop: "name"
hide: () => (hideVal.value === "hideName" ? true : false)
}, },
{ {
label: "地址", label: "地址",
prop: "address", prop: "address"
hide: () => (hideVal.value === "hideAddress" ? true : false)
} }
]; ];
@@ -35,8 +29,7 @@ export function useColumns() {
pageSizes: [10, 15, 20], pageSizes: [10, 15, 20],
total: 0, total: 0,
align: "right", align: "right",
background: true, background: true
small: false
}); });
/** 加载动画配置 */ /** 加载动画配置 */
@@ -57,10 +50,6 @@ export function useColumns() {
// background: rgba() // background: rgba()
}); });
function onChange(val) {
pagination.small = val;
}
function onSizeChange(val) { function onSizeChange(val) {
console.log("onSizeChange", val); console.log("onSizeChange", val);
} }
@@ -93,13 +82,9 @@ export function useColumns() {
loading, loading,
columns, columns,
dataList, dataList,
hideVal,
tableSize,
pagination, pagination,
loadingConfig, loadingConfig,
paginationAlign, paginationAlign,
paginationSmall,
onChange,
onSizeChange, onSizeChange,
onCurrentChange onCurrentChange
}; };

View File

@@ -5,13 +5,9 @@ const {
loading, loading,
columns, columns,
dataList, dataList,
hideVal,
tableSize,
pagination, pagination,
loadingConfig, loadingConfig,
paginationAlign, paginationAlign,
paginationSmall,
onChange,
onSizeChange, onSizeChange,
onCurrentChange onCurrentChange
} = useColumns(); } = useColumns();
@@ -19,45 +15,22 @@ const {
<template> <template>
<div> <div>
<el-space class="float-right mb-4"> <el-space class="float-right mb-2">
<p class="text-sm">动态列</p> <p>分页的对齐方式</p>
<el-radio-group v-model="hideVal" size="small"> <el-radio-group v-model="paginationAlign">
<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="right">right</el-radio-button>
<el-radio-button label="center">center</el-radio-button> <el-radio-button label="center">center</el-radio-button>
<el-radio-button label="left">left</el-radio-button> <el-radio-button label="left">left</el-radio-button>
</el-radio-group> </el-radio-group>
</el-space> </el-space>
<pure-table <pure-table
border border
row-key="id" row-key="id"
alignWhole="center" alignWhole="center"
showOverflowTooltip showOverflowTooltip
:size="tableSize"
:loading="loading" :loading="loading"
:loading-config="loadingConfig" :loading-config="loadingConfig"
:height="tableSize === 'small' ? 352 : 440" :height="440"
:data=" :data="
dataList.slice( dataList.slice(
(pagination.currentPage - 1) * pagination.pageSize, (pagination.currentPage - 1) * pagination.pageSize,

View File

@@ -1,3 +1,4 @@
import { IconifyIconOffline } from "@/components/ReIcon";
import ArrowRightSLine from "@iconify-icons/ri/arrow-right-s-line"; import ArrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
import CloseCircleLine from "@iconify-icons/ri/close-circle-line"; import CloseCircleLine from "@iconify-icons/ri/close-circle-line";
@@ -7,7 +8,7 @@ export function useColumns() {
cellRenderer: () => { cellRenderer: () => {
return ( return (
<span class="flex items-center -mt-6"> <span class="flex items-center -mt-6">
<iconify-icon-offline <IconifyIconOffline
icon={CloseCircleLine} icon={CloseCircleLine}
color="#F56C6C" color="#F56C6C"
width="18px" width="18px"
@@ -20,7 +21,7 @@ export function useColumns() {
style="color: var(--el-color-primary)" style="color: var(--el-color-primary)"
> >
<iconify-icon-offline <IconifyIconOffline
icon={ArrowRightSLine} icon={ArrowRightSLine}
color="var(--el-color-primary)" color="var(--el-color-primary)"
width="18px" width="18px"
@@ -35,7 +36,7 @@ export function useColumns() {
cellRenderer: () => { cellRenderer: () => {
return ( return (
<span class="flex items-center -mt-8"> <span class="flex items-center -mt-8">
<iconify-icon-offline <IconifyIconOffline
icon={CloseCircleLine} icon={CloseCircleLine}
color="#F56C6C" color="#F56C6C"
width="18px" width="18px"
@@ -48,7 +49,7 @@ export function useColumns() {
style="color: var(--el-color-primary)" style="color: var(--el-color-primary)"
> >
<iconify-icon-offline <IconifyIconOffline
icon={ArrowRightSLine} icon={ArrowRightSLine}
color="var(--el-color-primary)" color="var(--el-color-primary)"
width="18px" width="18px"

View File

@@ -0,0 +1,64 @@
import dayjs from "dayjs";
export function useColumns() {
const columns: TableColumnList = [
{
type: "selection",
width: 55,
align: "left",
hide: ({ checkList }) => !checkList.includes("勾选列")
},
{
label: "序号",
type: "index",
width: 60,
hide: ({ checkList }) => !checkList.includes("序号列")
},
{
label: "部门名称",
prop: "name",
width: 180,
align: "left"
},
{
label: "排序",
prop: "sort",
width: 60
},
{
label: "状态",
prop: "status",
width: 80,
cellRenderer: ({ row, props }) => (
<el-tag
size={props.size}
type={row.status === 1 ? "danger" : "success"}
effect="plain"
>
{row.status === 0 ? "关闭" : "开启"}
</el-tag>
)
},
{
label: "创建时间",
width: 180,
prop: "createTime",
formatter: ({ createTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "备注",
prop: "remark"
},
{
label: "操作",
fixed: "right",
width: 140,
slot: "operation"
}
];
return {
columns
};
}

View File

@@ -1,114 +0,0 @@
import dayjs from "dayjs";
import { handleTree } from "@/utils/tree";
import { getDeptList } from "@/api/system";
import { reactive, ref, onMounted } from "vue";
export function useDept() {
const form = reactive({
user: "",
status: ""
});
const dataList = ref([]);
const loading = ref(true);
const columns: TableColumnList = [
{
type: "selection",
width: 55,
align: "left",
hide: ({ checkList }) => !checkList.includes("勾选列")
},
{
label: "序号",
type: "index",
minWidth: 70,
hide: ({ checkList }) => !checkList.includes("序号列")
},
{
label: "部门名称",
prop: "name",
width: 180,
align: "left"
},
{
label: "排序",
prop: "sort",
minWidth: 70
},
{
label: "状态",
prop: "status",
minWidth: 100,
cellRenderer: ({ row, props }) => (
<el-tag
size={props.size}
type={row.status === 1 ? "danger" : "success"}
effect="plain"
>
{row.status === 0 ? "关闭" : "开启"}
</el-tag>
)
},
{
label: "创建时间",
minWidth: 200,
prop: "createTime",
formatter: ({ createTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "备注",
prop: "remark",
minWidth: 200
},
{
label: "操作",
fixed: "right",
width: 160,
slot: "operation"
}
];
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
function resetForm(formEl) {
if (!formEl) return;
formEl.resetFields();
onSearch();
}
async function onSearch() {
loading.value = true;
const { data } = await getDeptList();
dataList.value = handleTree(data);
setTimeout(() => {
loading.value = false;
}, 500);
}
onMounted(() => {
onSearch();
});
return {
form,
loading,
columns,
dataList,
onSearch,
resetForm,
handleUpdate,
handleDelete,
handleSelectionChange
};
}

View File

@@ -1,9 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { useColumns } from "./columns";
import { useDept } from "./hook"; import { handleTree } from "@/utils/tree";
import { PureTableBar } from "@/components/RePureTableBar"; import { getDeptList } from "@/api/system";
import { FormInstance } from "element-plus";
import { reactive, ref, onMounted } from "vue";
import { TableProBar } from "@/components/ReTable";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Delete from "@iconify-icons/ep/delete"; import Delete from "@iconify-icons/ep/delete";
import EditPen from "@iconify-icons/ep/edit-pen"; import EditPen from "@iconify-icons/ep/edit-pen";
import Search from "@iconify-icons/ep/search"; import Search from "@iconify-icons/ep/search";
@@ -14,19 +16,47 @@ defineOptions({
name: "Dept" name: "Dept"
}); });
const formRef = ref(); const form = reactive({
user: "",
status: ""
});
const dataList = ref([]);
const loading = ref(true);
const { columns } = useColumns();
const formRef = ref<FormInstance>();
const tableRef = ref(); const tableRef = ref();
const {
form, function handleUpdate(row) {
loading, console.log(row);
columns, }
dataList,
onSearch, function handleDelete(row) {
resetForm, console.log(row);
handleUpdate, }
handleDelete,
handleSelectionChange function handleSelectionChange(val) {
} = useDept(); console.log("handleSelectionChange", val);
}
async function onSearch() {
loading.value = true;
const { data } = await getDeptList();
dataList.value = handleTree(data as any);
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
</script> </script>
<template> <template>
@@ -38,20 +68,10 @@ const {
class="bg-bg_color w-[99/100] pl-8 pt-4" class="bg-bg_color w-[99/100] pl-8 pt-4"
> >
<el-form-item label="部门名称:" prop="user"> <el-form-item label="部门名称:" prop="user">
<el-input <el-input v-model="form.user" placeholder="请输入部门名称" clearable />
v-model="form.user"
placeholder="请输入部门名称"
clearable
class="!w-[200px]"
/>
</el-form-item> </el-form-item>
<el-form-item label="状态:" prop="status"> <el-form-item label="状态:" prop="status">
<el-select <el-select v-model="form.status" placeholder="请选择状态" clearable>
v-model="form.status"
placeholder="请选择状态"
clearable
class="!w-[180px]"
>
<el-option label="开启" value="1" /> <el-option label="开启" value="1" />
<el-option label="关闭" value="0" /> <el-option label="关闭" value="0" />
</el-select> </el-select>
@@ -71,9 +91,11 @@ const {
</el-form-item> </el-form-item>
</el-form> </el-form>
<PureTableBar <TableProBar
title="部门列表" title="部门列表"
:loading="loading"
:tableRef="tableRef?.getTableRef()" :tableRef="tableRef?.getTableRef()"
:dataList="dataList"
@refresh="onSearch" @refresh="onSearch"
> >
<template #buttons> <template #buttons>
@@ -90,7 +112,6 @@ const {
showOverflowTooltip showOverflowTooltip
table-layout="auto" table-layout="auto"
default-expand-all default-expand-all
:loading="loading"
:size="size" :size="size"
:data="dataList" :data="dataList"
:columns="columns" :columns="columns"
@@ -129,6 +150,6 @@ const {
</template> </template>
</pure-table> </pure-table>
</template> </template>
</PureTableBar> </TableProBar>
</div> </div>
</template> </template>

View File

@@ -1,25 +1,11 @@
import { ref } from "vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { message } from "@/utils/message"; import { message } from "@/utils/message";
import { getRoleList } from "@/api/system";
import { ElMessageBox } from "element-plus"; import { ElMessageBox } from "element-plus";
import { type PaginationProps } from "@pureadmin/table";
import { reactive, ref, computed, onMounted } from "vue";
export function useRole() { export function useColumns() {
const form = reactive({
name: "",
code: "",
status: ""
});
const dataList = ref([]);
const loading = ref(true);
const switchLoadMap = ref({}); const switchLoadMap = ref({});
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
currentPage: 1,
background: true
});
const columns: TableColumnList = [ const columns: TableColumnList = [
{ {
type: "selection", type: "selection",
@@ -35,23 +21,19 @@ export function useRole() {
}, },
{ {
label: "角色编号", label: "角色编号",
prop: "id", prop: "id"
minWidth: 100
}, },
{ {
label: "角色名称", label: "角色名称",
prop: "name", prop: "name"
minWidth: 120
}, },
{ {
label: "角色标识", label: "角色标识",
prop: "code", prop: "code"
minWidth: 150
}, },
{ {
label: "角色类型", label: "角色类型",
prop: "type", prop: "type",
minWidth: 150,
cellRenderer: ({ row, props }) => ( cellRenderer: ({ row, props }) => (
<el-tag <el-tag
size={props.size} size={props.size}
@@ -64,12 +46,12 @@ export function useRole() {
}, },
{ {
label: "显示顺序", label: "显示顺序",
prop: "sort", prop: "sort"
minWidth: 100
}, },
{ {
label: "状态", label: "状态",
minWidth: 130, prop: "status",
width: 130,
cellRenderer: scope => ( cellRenderer: scope => (
<el-switch <el-switch
size={scope.props.size === "small" ? "small" : "default"} size={scope.props.size === "small" ? "small" : "default"}
@@ -86,7 +68,7 @@ export function useRole() {
}, },
{ {
label: "创建时间", label: "创建时间",
minWidth: 180, width: 180,
prop: "createTime", prop: "createTime",
formatter: ({ createTime }) => formatter: ({ createTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss") dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
@@ -98,15 +80,6 @@ export function useRole() {
slot: "operation" slot: "operation"
} }
]; ];
const buttonClass = computed(() => {
return [
"!h-[20px]",
"reset-margin",
"!text-gray-500",
"dark:!text-white",
"dark:hover:!text-primary"
];
});
function onChange({ row, index }) { function onChange({ row, index }) {
ElMessageBox.confirm( ElMessageBox.confirm(
@@ -150,59 +123,7 @@ export function useRole() {
}); });
} }
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
async function onSearch() {
loading.value = true;
const { data } = await getRoleList();
dataList.value = data.list;
pagination.total = data.total;
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
return { return {
form, columns
loading,
columns,
dataList,
pagination,
buttonClass,
onSearch,
resetForm,
handleUpdate,
handleDelete,
handleSizeChange,
handleCurrentChange,
handleSelectionChange
}; };
} }

View File

@@ -1,9 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { useColumns } from "./columns";
import { useRole } from "./hook"; import { getRoleList } from "@/api/system";
import { PureTableBar } from "@/components/RePureTableBar"; import { reactive, ref, onMounted } from "vue";
import { type FormInstance } from "element-plus";
import { TableProBar } from "@/components/ReTable";
import { type PaginationProps } from "@pureadmin/table";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Database from "@iconify-icons/ri/database-2-line"; import Database from "@iconify-icons/ri/database-2-line";
import More from "@iconify-icons/ep/more-filled"; import More from "@iconify-icons/ep/more-filled";
import Delete from "@iconify-icons/ep/delete"; import Delete from "@iconify-icons/ep/delete";
@@ -17,22 +19,64 @@ defineOptions({
name: "Role" name: "Role"
}); });
const formRef = ref(); const form = reactive({
const { name: "",
form, code: "",
loading, status: ""
columns, });
dataList,
pagination, const dataList = ref([]);
buttonClass, const loading = ref(true);
onSearch, const { columns } = useColumns();
resetForm,
handleUpdate, const formRef = ref<FormInstance>();
handleDelete,
handleSizeChange, const pagination = reactive<PaginationProps>({
handleCurrentChange, total: 0,
handleSelectionChange pageSize: 10,
} = useRole(); currentPage: 1,
background: true
});
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
async function onSearch() {
loading.value = true;
const { data } = await getRoleList();
dataList.value = data.list;
pagination.total = data.total;
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
</script> </script>
<template> <template>
@@ -44,28 +88,13 @@ const {
class="bg-bg_color w-[99/100] pl-8 pt-4" class="bg-bg_color w-[99/100] pl-8 pt-4"
> >
<el-form-item label="角色名称:" prop="name"> <el-form-item label="角色名称:" prop="name">
<el-input <el-input v-model="form.name" placeholder="请输入角色名称" clearable />
v-model="form.name"
placeholder="请输入角色名称"
clearable
class="!w-[200px]"
/>
</el-form-item> </el-form-item>
<el-form-item label="角色标识:" prop="code"> <el-form-item label="角色标识:" prop="code">
<el-input <el-input v-model="form.code" placeholder="请输入角色标识" clearable />
v-model="form.code"
placeholder="请输入角色标识"
clearable
class="!w-[180px]"
/>
</el-form-item> </el-form-item>
<el-form-item label="状态:" prop="status"> <el-form-item label="状态:" prop="status">
<el-select <el-select v-model="form.status" placeholder="请选择状态" clearable>
v-model="form.status"
placeholder="请选择状态"
clearable
class="!w-[180px]"
>
<el-option label="已开启" value="1" /> <el-option label="已开启" value="1" />
<el-option label="已关闭" value="0" /> <el-option label="已关闭" value="0" />
</el-select> </el-select>
@@ -85,7 +114,12 @@ const {
</el-form-item> </el-form-item>
</el-form> </el-form>
<PureTableBar title="角色列表" @refresh="onSearch"> <TableProBar
title="角色列表"
:loading="loading"
:dataList="dataList"
@refresh="onSearch"
>
<template #buttons> <template #buttons>
<el-button type="primary" :icon="useRenderIcon(AddFill)"> <el-button type="primary" :icon="useRenderIcon(AddFill)">
新增角色 新增角色
@@ -97,7 +131,6 @@ const {
align-whole="center" align-whole="center"
showOverflowTooltip showOverflowTooltip
table-layout="auto" table-layout="auto"
:loading="loading"
:size="size" :size="size"
:data="dataList" :data="dataList"
:columns="columns" :columns="columns"
@@ -118,8 +151,8 @@ const {
link link
type="primary" type="primary"
:size="size" :size="size"
:icon="useRenderIcon(EditPen)"
@click="handleUpdate(row)" @click="handleUpdate(row)"
:icon="useRenderIcon(EditPen)"
> >
修改 修改
</el-button> </el-button>
@@ -139,18 +172,18 @@ const {
</el-popconfirm> </el-popconfirm>
<el-dropdown> <el-dropdown>
<el-button <el-button
class="ml-3 mt-[2px]" class="ml-3"
link link
type="primary" type="primary"
:size="size" :size="size"
:icon="useRenderIcon(More)"
@click="handleUpdate(row)" @click="handleUpdate(row)"
:icon="useRenderIcon(More)"
/> />
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item> <el-dropdown-item>
<el-button <el-button
:class="buttonClass" class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link link
type="primary" type="primary"
:size="size" :size="size"
@@ -161,7 +194,7 @@ const {
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item> <el-dropdown-item>
<el-button <el-button
:class="buttonClass" class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link link
type="primary" type="primary"
:size="size" :size="size"
@@ -176,7 +209,7 @@ const {
</template> </template>
</pure-table> </pure-table>
</template> </template>
</PureTableBar> </TableProBar>
</div> </div>
</template> </template>

View File

@@ -1,25 +1,11 @@
import { ref } from "vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { message } from "@/utils/message"; import { message } from "@/utils/message";
import { getUserList } from "@/api/system";
import { ElMessageBox } from "element-plus"; import { ElMessageBox } from "element-plus";
import { type PaginationProps } from "@pureadmin/table";
import { reactive, ref, computed, onMounted } from "vue";
export function useUser() { export function useColumns() {
const form = reactive({
username: "",
mobile: "",
status: ""
});
const dataList = ref([]);
const loading = ref(true);
const switchLoadMap = ref({}); const switchLoadMap = ref({});
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
currentPage: 1,
background: true
});
const columns: TableColumnList = [ const columns: TableColumnList = [
{ {
type: "selection", type: "selection",
@@ -35,23 +21,19 @@ export function useUser() {
}, },
{ {
label: "用户编号", label: "用户编号",
prop: "id", prop: "id"
minWidth: 130
}, },
{ {
label: "用户名称", label: "用户名称",
prop: "username", prop: "username"
minWidth: 130
}, },
{ {
label: "用户昵称", label: "用户昵称",
prop: "nickname", prop: "nickname"
minWidth: 130
}, },
{ {
label: "性别", label: "性别",
prop: "sex", prop: "sex",
minWidth: 90,
cellRenderer: ({ row, props }) => ( cellRenderer: ({ row, props }) => (
<el-tag <el-tag
size={props.size} size={props.size}
@@ -65,18 +47,16 @@ export function useUser() {
{ {
label: "部门", label: "部门",
prop: "dept", prop: "dept",
minWidth: 90,
formatter: ({ dept }) => dept.name formatter: ({ dept }) => dept.name
}, },
{ {
label: "手机号码", label: "手机号码",
prop: "mobile", prop: "mobile"
minWidth: 90
}, },
{ {
label: "状态", label: "状态",
prop: "status", prop: "status",
minWidth: 90, width: 130,
cellRenderer: scope => ( cellRenderer: scope => (
<el-switch <el-switch
size={scope.props.size === "small" ? "small" : "default"} size={scope.props.size === "small" ? "small" : "default"}
@@ -93,7 +73,7 @@ export function useUser() {
}, },
{ {
label: "创建时间", label: "创建时间",
minWidth: 90, width: 180,
prop: "createTime", prop: "createTime",
formatter: ({ createTime }) => formatter: ({ createTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss") dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
@@ -105,15 +85,6 @@ export function useUser() {
slot: "operation" slot: "operation"
} }
]; ];
const buttonClass = computed(() => {
return [
"!h-[20px]",
"reset-margin",
"!text-gray-500",
"dark:!text-white",
"dark:hover:!text-primary"
];
});
function onChange({ row, index }) { function onChange({ row, index }) {
ElMessageBox.confirm( ElMessageBox.confirm(
@@ -157,59 +128,7 @@ export function useUser() {
}); });
} }
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
async function onSearch() {
loading.value = true;
const { data } = await getUserList();
dataList.value = data.list;
pagination.total = data.total;
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
return { return {
form, columns
loading,
columns,
dataList,
pagination,
buttonClass,
onSearch,
resetForm,
handleUpdate,
handleDelete,
handleSizeChange,
handleCurrentChange,
handleSelectionChange
}; };
} }

View File

@@ -1,8 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue";
import tree from "./tree.vue"; import tree from "./tree.vue";
import { useUser } from "./hook"; import { useColumns } from "./columns";
import { PureTableBar } from "@/components/RePureTableBar"; import { getUserList } from "@/api/system";
import { reactive, ref, onMounted } from "vue";
import { type FormInstance } from "element-plus";
import { TableProBar } from "@/components/ReTable";
import { type PaginationProps } from "@pureadmin/table";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Role from "@iconify-icons/ri/admin-line"; import Role from "@iconify-icons/ri/admin-line";
@@ -18,28 +21,69 @@ defineOptions({
name: "User" name: "User"
}); });
const formRef = ref(); const form = reactive({
const { username: "",
form, mobile: "",
loading, status: ""
columns, });
dataList, const dataList = ref([]);
pagination, const loading = ref(true);
buttonClass, const { columns } = useColumns();
onSearch,
resetForm, const formRef = ref<FormInstance>();
handleUpdate,
handleDelete, const pagination = reactive<PaginationProps>({
handleSizeChange, total: 0,
handleCurrentChange, pageSize: 10,
handleSelectionChange currentPage: 1,
} = useUser(); background: true
});
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
async function onSearch() {
loading.value = true;
const { data } = await getUserList();
dataList.value = data.list;
pagination.total = data.total;
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
</script> </script>
<template> <template>
<div class="main"> <div class="main flex">
<tree class="w-[17%] float-left" /> <tree />
<div class="float-right w-[81%]"> <div class="flex-1 ml-4">
<el-form <el-form
ref="formRef" ref="formRef"
:inline="true" :inline="true"
@@ -51,7 +95,6 @@ const {
v-model="form.username" v-model="form.username"
placeholder="请输入用户名称" placeholder="请输入用户名称"
clearable clearable
class="!w-[160px]"
/> />
</el-form-item> </el-form-item>
<el-form-item label="手机号码:" prop="mobile"> <el-form-item label="手机号码:" prop="mobile">
@@ -59,16 +102,10 @@ const {
v-model="form.mobile" v-model="form.mobile"
placeholder="请输入手机号码" placeholder="请输入手机号码"
clearable clearable
class="!w-[160px]"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态:" prop="status"> <el-form-item label="状态:" prop="status">
<el-select <el-select v-model="form.status" placeholder="请选择" clearable>
v-model="form.status"
placeholder="请选择"
clearable
class="!w-[160px]"
>
<el-option label="已开启" value="1" /> <el-option label="已开启" value="1" />
<el-option label="已关闭" value="0" /> <el-option label="已关闭" value="0" />
</el-select> </el-select>
@@ -88,7 +125,12 @@ const {
</el-form-item> </el-form-item>
</el-form> </el-form>
<PureTableBar title="用户管理" @refresh="onSearch"> <TableProBar
title="用户管理"
:loading="loading"
:dataList="dataList"
@refresh="onSearch"
>
<template #buttons> <template #buttons>
<el-button type="primary" :icon="useRenderIcon(AddFill)"> <el-button type="primary" :icon="useRenderIcon(AddFill)">
新增用户 新增用户
@@ -99,7 +141,6 @@ const {
border border
align-whole="center" align-whole="center"
table-layout="auto" table-layout="auto"
:loading="loading"
:size="size" :size="size"
:data="dataList" :data="dataList"
:columns="columns" :columns="columns"
@@ -141,7 +182,7 @@ const {
</el-popconfirm> </el-popconfirm>
<el-dropdown> <el-dropdown>
<el-button <el-button
class="ml-3 mt-[2px]" class="ml-3"
link link
type="primary" type="primary"
:size="size" :size="size"
@@ -152,7 +193,7 @@ const {
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item> <el-dropdown-item>
<el-button <el-button
:class="buttonClass" class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link link
type="primary" type="primary"
:size="size" :size="size"
@@ -163,7 +204,7 @@ const {
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item> <el-dropdown-item>
<el-button <el-button
:class="buttonClass" class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link link
type="primary" type="primary"
:size="size" :size="size"
@@ -178,7 +219,7 @@ const {
</template> </template>
</pure-table> </pure-table>
</template> </template>
</PureTableBar> </TableProBar>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 163 B

View File

@@ -1 +0,0 @@
<svg width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M4 2H2v20h2v-9h14.17l-5.5 5.5l1.41 1.42L22 12l-7.92-7.92l-1.41 1.42l5.5 5.5H4V2Z"/></svg>

Before

Width:  |  Height:  |  Size: 166 B

View File

@@ -1,17 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { handleTree } from "@/utils/tree"; import { handleTree } from "@/utils/tree";
import type { ElTree } from "element-plus";
import { getDeptList } from "@/api/system"; import { getDeptList } from "@/api/system";
import { useRenderIcon } from "@/components/ReIcon/src/hooks"; import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, computed, watch, onMounted, getCurrentInstance } from "vue"; import { ref, watch, onMounted, getCurrentInstance } from "vue";
import Dept from "@iconify-icons/ri/git-branch-line";
import Reset from "@iconify-icons/ri/restart-line";
import Search from "@iconify-icons/ep/search";
import More2Fill from "@iconify-icons/ri/more-2-fill";
import OfficeBuilding from "@iconify-icons/ep/office-building";
import LocationCompany from "@iconify-icons/ep/add-location"; import LocationCompany from "@iconify-icons/ep/add-location";
import ExpandIcon from "./svg/expand.svg?component"; import UnExpand from "@iconify-icons/mdi/arrow-expand-right";
import UnExpandIcon from "./svg/unexpand.svg?component"; import Expand from "@iconify-icons/mdi/arrow-expand-down";
import More2Fill from "@iconify-icons/ri/more-2-fill";
import Reset from "@iconify-icons/ri/restart-line";
import Dept from "@iconify-icons/ri/git-branch-line";
import OfficeBuilding from "@iconify-icons/ep/office-building";
import Search from "@iconify-icons/ep/search";
interface Tree { interface Tree {
id: number; id: number;
@@ -19,26 +20,17 @@ interface Tree {
highlight?: boolean; highlight?: boolean;
children?: Tree[]; children?: Tree[];
} }
const treeRef = ref();
const treeData = ref([]);
const isExpand = ref(true);
const searchValue = ref("");
const highlightMap = ref({});
const { proxy } = getCurrentInstance();
const defaultProps = { const defaultProps = {
children: "children", children: "children",
label: "name" label: "name"
}; };
const buttonClass = computed(() => {
return [ const treeData = ref([]);
"!h-[20px]", const searchValue = ref("");
"reset-margin", const { proxy } = getCurrentInstance();
"!text-gray-500", const treeRef = ref<InstanceType<typeof ElTree>>();
"dark:!text-white",
"dark:hover:!text-primary" const highlightMap = ref({});
];
});
const filterNode = (value: string, data: Tree) => { const filterNode = (value: string, data: Tree) => {
if (!value) return true; if (!value) return true;
@@ -62,14 +54,13 @@ function nodeClick(value) {
} }
function toggleRowExpansionAll(status) { function toggleRowExpansionAll(status) {
isExpand.value = status;
const nodes = (proxy.$refs["treeRef"] as any).store._getAllNodes(); const nodes = (proxy.$refs["treeRef"] as any).store._getAllNodes();
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
nodes[i].expanded = status; nodes[i].expanded = status;
} }
} }
/** 重置状态(选中状态、搜索框值、树初始化) */ // 重置状态(选中状态、搜索框值、树初始化)
function onReset() { function onReset() {
highlightMap.value = {}; highlightMap.value = {};
searchValue.value = ""; searchValue.value = "";
@@ -82,12 +73,12 @@ watch(searchValue, val => {
onMounted(async () => { onMounted(async () => {
const { data } = await getDeptList(); const { data } = await getDeptList();
treeData.value = handleTree(data); treeData.value = handleTree(data as any);
}); });
</script> </script>
<template> <template>
<div class="h-full min-h-[780px] bg-bg_color overflow-auto"> <div class="max-w-[260px] h-full min-h-[780px] bg-bg_color">
<div class="flex items-center h-[34px]"> <div class="flex items-center h-[34px]">
<p class="flex-1 ml-2 font-bold text-base truncate" title="部门列表"> <p class="flex-1 ml-2 font-bold text-base truncate" title="部门列表">
部门列表 部门列表
@@ -108,7 +99,7 @@ onMounted(async () => {
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>
<el-dropdown :hide-on-click="false"> <el-dropdown>
<IconifyIconOffline <IconifyIconOffline
class="w-[28px] cursor-pointer" class="w-[28px] cursor-pointer"
width="18px" width="18px"
@@ -118,18 +109,29 @@ onMounted(async () => {
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item> <el-dropdown-item>
<el-button <el-button
:class="buttonClass" class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link link
type="primary" type="primary"
:icon="useRenderIcon(isExpand ? ExpandIcon : UnExpandIcon)" :icon="useRenderIcon(Expand)"
@click="toggleRowExpansionAll(isExpand ? false : true)" @click="toggleRowExpansionAll(true)"
> >
{{ isExpand ? "折叠全部" : "展开全部" }} 展开全部
</el-button> </el-button>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item> <el-dropdown-item>
<el-button <el-button
:class="buttonClass" class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link
type="primary"
:icon="useRenderIcon(UnExpand)"
@click="toggleRowExpansionAll(false)"
>
折叠全部
</el-button>
</el-dropdown-item>
<el-dropdown-item>
<el-button
class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link link
type="primary" type="primary"
:icon="useRenderIcon(Reset)" :icon="useRenderIcon(Reset)"

View File

@@ -48,7 +48,7 @@ function onCloseTags() {
<template> <template>
<el-card> <el-card>
<template #header> <template #header>
<div>标签页复用超出限制自动关闭</div> <div>标签页复用超出限制自动关闭使用场景: 动态路由</div>
</template> </template>
<div class="flex flex-wrap items-center"> <div class="flex flex-wrap items-center">
<p>query传参模式</p> <p>query传参模式</p>

View File

@@ -1,3 +1,4 @@
import { IconifyIconOffline } from "@/components/ReIcon";
import TypeIt from "@/components/ReTypeit"; import TypeIt from "@/components/ReTypeit";
import OfficeBuilding from "@iconify-icons/ep/office-building"; import OfficeBuilding from "@iconify-icons/ep/office-building";
import Tickets from "@iconify-icons/ep/tickets"; import Tickets from "@iconify-icons/ep/tickets";
@@ -20,7 +21,7 @@ export function useColumns() {
labelRenderer: () => ( labelRenderer: () => (
<div class="flex items-center"> <div class="flex items-center">
<el-icon> <el-icon>
<iconify-icon-offline icon={User} /> <IconifyIconOffline icon={User} />
</el-icon> </el-icon>
</div> </div>
@@ -31,7 +32,7 @@ export function useColumns() {
labelRenderer: () => ( labelRenderer: () => (
<div class="flex items-center"> <div class="flex items-center">
<el-icon> <el-icon>
<iconify-icon-offline icon={Iphone} /> <IconifyIconOffline icon={Iphone} />
</el-icon> </el-icon>
</div> </div>
@@ -42,7 +43,7 @@ export function useColumns() {
labelRenderer: () => ( labelRenderer: () => (
<div class="flex items-center"> <div class="flex items-center">
<el-icon> <el-icon>
<iconify-icon-offline icon={Location} /> <IconifyIconOffline icon={Location} />
</el-icon> </el-icon>
</div> </div>
@@ -56,7 +57,7 @@ export function useColumns() {
labelRenderer: () => ( labelRenderer: () => (
<div class="flex items-center"> <div class="flex items-center">
<el-icon> <el-icon>
<iconify-icon-offline icon={Tickets} /> <IconifyIconOffline icon={Tickets} />
</el-icon> </el-icon>
</div> </div>
@@ -75,7 +76,7 @@ export function useColumns() {
labelRenderer: () => ( labelRenderer: () => (
<div class="flex items-center"> <div class="flex items-center">
<el-icon> <el-icon>
<iconify-icon-offline icon={OfficeBuilding} /> <IconifyIconOffline icon={OfficeBuilding} />
</el-icon> </el-icon>
</div> </div>
@@ -89,7 +90,7 @@ export function useColumns() {
labelRenderer: () => ( labelRenderer: () => (
<div class="flex items-center"> <div class="flex items-center">
<el-icon> <el-icon>
<iconify-icon-offline icon={Notebook} /> <IconifyIconOffline icon={Notebook} />
</el-icon> </el-icon>
</div> </div>

View File

@@ -9,5 +9,7 @@ declare module "*.scss" {
export default scss; export default scss;
} }
declare module "@pureadmin/theme";
declare module "vue-virtual-scroller"; declare module "vue-virtual-scroller";
declare module "vuedraggable/src/vuedraggable"; declare module "vuedraggable/src/vuedraggable";
declare module "@pureadmin/theme/dist/browser-utils";