Merge branch 'main' into gitee
							
								
								
									
										2
									
								
								.github/ISSUE_TEMPLATE/bug_report.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -32,7 +32,7 @@ body:
 | 
				
			|||||||
      label: 验证 (Verify)
 | 
					      label: 验证 (Verify)
 | 
				
			||||||
      description: 在提交问题之前,请确保您执行以下操作 (Before submitting an issue, please ensure you do the following)
 | 
					      description: 在提交问题之前,请确保您执行以下操作 (Before submitting an issue, please ensure you do the following)
 | 
				
			||||||
      options:
 | 
					      options:
 | 
				
			||||||
        - label: 是否仔细阅读过 [文档](https://yiming_chang.gitee.io/pure-admin-doc/) (Have you read [documentation](https://yiming_chang.gitee.io/pure-admin-doc/) carefully)
 | 
					        - label: 是否仔细阅读过 [文档](https://pure-admin.github.io/pure-admin-doc/) (Have you read [documentation](https://pure-admin.github.io/pure-admin-doc/) carefully)
 | 
				
			||||||
          required: true
 | 
					          required: true
 | 
				
			||||||
        - label: 检查是否存在相同或类似的问题 [issues](https://github.com/pure-admin/vue-pure-admin/issues) (Check for the same or similar [issues](https://github.com/pure-admin/vue-pure-admin/issues))
 | 
					        - label: 检查是否存在相同或类似的问题 [issues](https://github.com/pure-admin/vue-pure-admin/issues) (Check for the same or similar [issues](https://github.com/pure-admin/vue-pure-admin/issues))
 | 
				
			||||||
          required: true
 | 
					          required: true
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										42
									
								
								.github/workflows/pages.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					name: Build and Deploy
 | 
				
			||||||
 | 
					permissions:
 | 
				
			||||||
 | 
					  contents: write
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - main
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  deploy:
 | 
				
			||||||
 | 
					    concurrency: ci-${{ github.ref }}
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout 🛎️
 | 
				
			||||||
 | 
					        uses: actions/checkout@v4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Install Node.js
 | 
				
			||||||
 | 
					        uses: actions/setup-node@v4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          node-version: 20
 | 
				
			||||||
 | 
					          registry-url: https://registry.npmjs.com/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - uses: pnpm/action-setup@v3
 | 
				
			||||||
 | 
					        name: Install pnpm
 | 
				
			||||||
 | 
					        id: pnpm-install
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          version: 8.6.10
 | 
				
			||||||
 | 
					          run_install: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Deploy 🔧
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          pnpm install --no-frozen-lockfile
 | 
				
			||||||
 | 
					          sed -i "s#VITE_PUBLIC_PATH = /#VITE_PUBLIC_PATH = /vue-pure-admin/#g" $(pwd)/.env.production
 | 
				
			||||||
 | 
					          pnpm build
 | 
				
			||||||
 | 
					          cd dist
 | 
				
			||||||
 | 
					          touch README.md .nojekyll
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Deploy 🚀
 | 
				
			||||||
 | 
					        uses: JamesIves/github-pages-deploy-action@v4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          folder: dist
 | 
				
			||||||
 | 
					          clean: true
 | 
				
			||||||
@ -379,7 +379,7 @@ Totally `ESM` version
 | 
				
			|||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- completely removed `lodash` and its related libraries
 | 
					- 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)
 | 
					  [Click here to see Why Removed? How to integrate it yourself? ](https://pure-admin.github.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
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -399,7 +399,7 @@ Totally `ESM` version
 | 
				
			|||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Completely removed `vxe-table`, after removal, the overall package size of the full version is reduced by `1.82MB`, and the initial startup time is basically the same as the lite version 🐮
 | 
					- 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://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)
 | 
					  [Click here to see Why Removed? How to integrate it yourself?](https://pure-admin.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
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -511,7 +511,7 @@ Totally `ESM` version
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### 🎫 Feat
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Add front-end single sign-on, test address https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
 | 
					- Add front-end single sign-on, test address https://pure-admin.github.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
 | 
				
			||||||
- Add more examples for [@pureadmin/table](https://github.com/pure-admin/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
 | 
					- Add more examples for [@pureadmin/table](https://github.com/pure-admin/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
 | 
				
			||||||
- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
 | 
					- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
 | 
				
			||||||
- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/platform-config.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
 | 
					- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/platform-config.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
 | 
				
			||||||
@ -612,7 +612,7 @@ Totally `ESM` version
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Replace `unocss` with `tailwindcss`, add `tailwindcss` [documentation](https://yiming_chang.gitee.io/pure-admin-doc/pages/tailwindcss/)
 | 
					- Replace `unocss` with `tailwindcss`, add `tailwindcss` [documentation](https://pure-admin.github.io/pure-admin-doc/pages/tailwindcss/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 🐞 Bug fixes
 | 
					### 🐞 Bug fixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -379,7 +379,7 @@ Totally `ESM` version
 | 
				
			|||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- completely removed `lodash` and its related libraries
 | 
					- 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)
 | 
					  [Click here to see Why Removed? How to integrate it yourself? ](https://pure-admin.github.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
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -399,7 +399,7 @@ Totally `ESM` version
 | 
				
			|||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Completely removed `vxe-table`, after removal, the overall package size of the full version is reduced by `1.82MB`, and the initial startup time is basically the same as the lite version 🐮
 | 
					- 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://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)
 | 
					  [Click here to see Why Removed? How to integrate it yourself?](https://pure-admin.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
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -511,7 +511,7 @@ Totally `ESM` version
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### 🎫 Feat
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Add front-end single sign-on, test address https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
 | 
					- Add front-end single sign-on, test address https://pure-admin.github.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
 | 
				
			||||||
- Add more examples for [@pureadmin/table](https://github.com/pure-admin/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
 | 
					- Add more examples for [@pureadmin/table](https://github.com/pure-admin/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
 | 
				
			||||||
- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
 | 
					- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
 | 
				
			||||||
- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/platform-config.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
 | 
					- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/platform-config.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
 | 
				
			||||||
@ -612,7 +612,7 @@ Totally `ESM` version
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Replace `unocss` with `tailwindcss`, add `tailwindcss` [documentation](https://yiming_chang.gitee.io/pure-admin-doc/pages/tailwindcss/)
 | 
					- Replace `unocss` with `tailwindcss`, add `tailwindcss` [documentation](https://pure-admin.github.io/pure-admin-doc/pages/tailwindcss/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 🐞 Bug fixes
 | 
					### 🐞 Bug fixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -378,7 +378,7 @@
 | 
				
			|||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- 完全移除了 `lodash` 和其相关库
 | 
					- 完全移除了 `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)
 | 
					  [点击此处查看为什么移除?如何自行集成?](https://pure-admin.github.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
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -398,7 +398,7 @@
 | 
				
			|||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- 完全移除了 `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://pure-admin.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
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -510,7 +510,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### 🎫 Feat
 | 
					### 🎫 Feat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- 添加前端单点登录,测试地址 https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
 | 
					- 添加前端单点登录,测试地址 https://pure-admin.github.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
 | 
				
			||||||
- 为 [@pureadmin/table](https://github.com/pure-admin/pure-admin-table) 添加更多的示例和 `element-plus` 的 [table](https://element-plus.org/zh-CN/component/table.html) 示例保持一致
 | 
					- 为 [@pureadmin/table](https://github.com/pure-admin/pure-admin-table) 添加更多的示例和 `element-plus` 的 [table](https://element-plus.org/zh-CN/component/table.html) 示例保持一致
 | 
				
			||||||
- 丰富水印功能页面(支持自定义各种颜色、阴影、文字、额外属性、设置不可删除水印以及给指定元素设置水印)
 | 
					- 丰富水印功能页面(支持自定义各种颜色、阴影、文字、额外属性、设置不可删除水印以及给指定元素设置水印)
 | 
				
			||||||
- 优化菜单,添加 `MenuArrowIconNoTransition` 全局配置,在 `public/platform-config.json` 中配置即可,对于出现左侧菜单模式,菜单展开卡顿的可设置 `MenuArrowIconNoTransition: true` 即可解决
 | 
					- 优化菜单,添加 `MenuArrowIconNoTransition` 全局配置,在 `public/platform-config.json` 中配置即可,对于出现左侧菜单模式,菜单展开卡顿的可设置 `MenuArrowIconNoTransition: true` 即可解决
 | 
				
			||||||
@ -611,7 +611,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### ✔️ refactor
 | 
					### ✔️ refactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- 使用 `tailwindcss` 替换 `unocss`,新增 `tailwindcss` [使用文档](https://yiming_chang.gitee.io/pure-admin-doc/pages/tailwindcss/)
 | 
					- 使用 `tailwindcss` 替换 `unocss`,新增 `tailwindcss` [使用文档](https://pure-admin.github.io/pure-admin-doc/pages/tailwindcss/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 🐞 Bug fixes
 | 
					### 🐞 Bug fixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -30,12 +30,12 @@ The simplified version is based on the shelf extracted from [vue-pure-admin](htt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Nanny-level documents
 | 
					## Nanny-level documents
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Click me to view vue-pure-admin documentation](https://yiming_chang.gitee.io/pure-admin-doc)  
 | 
					[Click me to view vue-pure-admin documentation](https://pure-admin.github.io/pure-admin-doc)  
 | 
				
			||||||
[Click me to view @pureadmin/utils documentation](https://pure-admin-utils.netlify.app)
 | 
					[Click me to view @pureadmin/utils documentation](https://pure-admin-utils.netlify.app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Quality service, software outsourcing, sponsorship support
 | 
					## Quality service, software outsourcing, sponsorship support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Click me for details](https://yiming_chang.gitee.io/pure-admin-doc/pages/service/)
 | 
					[Click me for details](https://pure-admin.github.io/pure-admin-doc/pages/service/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Tauri
 | 
					## Tauri
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -47,7 +47,7 @@ The simplified version is based on the shelf extracted from [vue-pure-admin](htt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Preview
 | 
					## Preview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[preview station](https://yiming_chang.gitee.io/vue-pure-admin)
 | 
					[preview station](https://pure-admin.github.io/vue-pure-admin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`PC`
 | 
					`PC`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -31,12 +31,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## 配套保姆级文档
 | 
					## 配套保姆级文档
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[点我查看 vue-pure-admin 文档](https://yiming_chang.gitee.io/pure-admin-doc)  
 | 
					[点我查看 vue-pure-admin 文档](https://pure-admin.github.io/pure-admin-doc)  
 | 
				
			||||||
[点我查看 @pureadmin/utils 文档](https://pure-admin-utils.netlify.app)
 | 
					[点我查看 @pureadmin/utils 文档](https://pure-admin-utils.netlify.app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 优质服务、软件外包、赞助支持
 | 
					## 优质服务、软件外包、赞助支持
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[点我查看详情](https://yiming_chang.gitee.io/pure-admin-doc/pages/service/)
 | 
					[点我查看详情](https://pure-admin.github.io/pure-admin-doc/pages/service/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## `Tauri` 版本
 | 
					## `Tauri` 版本
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,7 +48,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## 预览
 | 
					## 预览
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[点我查看预览](https://yiming_chang.gitee.io/vue-pure-admin)
 | 
					[点我查看预览](https://pure-admin.github.io/vue-pure-admin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`PC` 端
 | 
					`PC` 端
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import boxen, { type Options as BoxenOptions } from "boxen";
 | 
				
			|||||||
dayjs.extend(duration);
 | 
					dayjs.extend(duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const welcomeMessage = gradientString("cyan", "magenta").multiline(
 | 
					const welcomeMessage = gradientString("cyan", "magenta").multiline(
 | 
				
			||||||
  `您好! 欢迎使用 pure-admin 开源项目\n我们为您精心准备了下面两个贴心的保姆级文档\nhttps://yiming_chang.gitee.io/pure-admin-doc\nhttps://pure-admin-utils.netlify.app`
 | 
					  `您好! 欢迎使用 pure-admin 开源项目\n我们为您精心准备了下面两个贴心的保姆级文档\nhttps://pure-admin.github.io/pure-admin-doc\nhttps://pure-admin-utils.netlify.app`
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const boxenOptions: BoxenOptions = {
 | 
					const boxenOptions: BoxenOptions = {
 | 
				
			||||||
 | 
				
			|||||||
@ -182,7 +182,12 @@ menus:
 | 
				
			|||||||
  pureChildMenuOverflow: Child Menu Overflow Show Tooltip Text
 | 
					  pureChildMenuOverflow: Child Menu Overflow Show Tooltip Text
 | 
				
			||||||
status:
 | 
					status:
 | 
				
			||||||
  pureLoad: Loading...
 | 
					  pureLoad: Loading...
 | 
				
			||||||
 | 
					  pureMessage: Message
 | 
				
			||||||
 | 
					  pureNotify: Notify
 | 
				
			||||||
 | 
					  pureTodo: Todo
 | 
				
			||||||
  pureNoMessage: No Message
 | 
					  pureNoMessage: No Message
 | 
				
			||||||
 | 
					  pureNoNotify: No Notify
 | 
				
			||||||
 | 
					  pureNoTodo: No Todo
 | 
				
			||||||
login:
 | 
					login:
 | 
				
			||||||
  pureUsername: Username
 | 
					  pureUsername: Username
 | 
				
			||||||
  purePassword: Password
 | 
					  purePassword: Password
 | 
				
			||||||
 | 
				
			|||||||
@ -182,7 +182,12 @@ menus:
 | 
				
			|||||||
  pureChildMenuOverflow: 菜单超出显示 Tooltip 文字提示
 | 
					  pureChildMenuOverflow: 菜单超出显示 Tooltip 文字提示
 | 
				
			||||||
status:
 | 
					status:
 | 
				
			||||||
  pureLoad: 加载中...
 | 
					  pureLoad: 加载中...
 | 
				
			||||||
 | 
					  pureMessage: 消息
 | 
				
			||||||
 | 
					  pureNotify: 通知
 | 
				
			||||||
 | 
					  pureTodo: 待办
 | 
				
			||||||
  pureNoMessage: 暂无消息
 | 
					  pureNoMessage: 暂无消息
 | 
				
			||||||
 | 
					  pureNoNotify: 暂无通知
 | 
				
			||||||
 | 
					  pureNoTodo: 暂无待办
 | 
				
			||||||
login:
 | 
					login:
 | 
				
			||||||
  pureUsername: 账号
 | 
					  pureUsername: 账号
 | 
				
			||||||
  purePassword: 密码
 | 
					  purePassword: 密码
 | 
				
			||||||
 | 
				
			|||||||
@ -154,7 +154,7 @@ const frameRouter = {
 | 
				
			|||||||
      children: [
 | 
					      children: [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          path: "/external",
 | 
					          path: "/external",
 | 
				
			||||||
          name: "https://yiming_chang.gitee.io/pure-admin-doc",
 | 
					          name: "https://pure-admin.github.io/pure-admin-doc",
 | 
				
			||||||
          meta: {
 | 
					          meta: {
 | 
				
			||||||
            title: "menus.pureExternalLink",
 | 
					            title: "menus.pureExternalLink",
 | 
				
			||||||
            roles: ["admin", "common"]
 | 
					            roles: ["admin", "common"]
 | 
				
			||||||
 | 
				
			|||||||
@ -430,7 +430,7 @@ export default defineFakeRoute([
 | 
				
			|||||||
            id: 102,
 | 
					            id: 102,
 | 
				
			||||||
            menuType: 2,
 | 
					            menuType: 2,
 | 
				
			||||||
            title: "menus.pureExternalLink",
 | 
					            title: "menus.pureExternalLink",
 | 
				
			||||||
            name: "https://yiming_chang.gitee.io/pure-admin-doc",
 | 
					            name: "https://pure-admin.github.io/pure-admin-doc",
 | 
				
			||||||
            path: "/external",
 | 
					            path: "/external",
 | 
				
			||||||
            component: "",
 | 
					            component: "",
 | 
				
			||||||
            rank: null,
 | 
					            rank: null,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										32
									
								
								package.json
									
									
									
									
									
								
							
							
						
						@ -56,7 +56,7 @@
 | 
				
			|||||||
    "@pureadmin/table": "^3.1.2",
 | 
					    "@pureadmin/table": "^3.1.2",
 | 
				
			||||||
    "@pureadmin/utils": "^2.4.7",
 | 
					    "@pureadmin/utils": "^2.4.7",
 | 
				
			||||||
    "@vue-flow/background": "^1.3.0",
 | 
					    "@vue-flow/background": "^1.3.0",
 | 
				
			||||||
    "@vue-flow/core": "^1.33.5",
 | 
					    "@vue-flow/core": "^1.33.6",
 | 
				
			||||||
    "@vueuse/core": "^10.9.0",
 | 
					    "@vueuse/core": "^10.9.0",
 | 
				
			||||||
    "@vueuse/motion": "^2.1.0",
 | 
					    "@vueuse/motion": "^2.1.0",
 | 
				
			||||||
    "@wangeditor/editor": "^5.1.23",
 | 
					    "@wangeditor/editor": "^5.1.23",
 | 
				
			||||||
@ -66,10 +66,10 @@
 | 
				
			|||||||
    "axios": "^1.6.8",
 | 
					    "axios": "^1.6.8",
 | 
				
			||||||
    "china-area-data": "^5.0.1",
 | 
					    "china-area-data": "^5.0.1",
 | 
				
			||||||
    "cropperjs": "^1.6.2",
 | 
					    "cropperjs": "^1.6.2",
 | 
				
			||||||
    "dayjs": "^1.11.10",
 | 
					    "dayjs": "^1.11.11",
 | 
				
			||||||
    "echarts": "^5.5.0",
 | 
					    "echarts": "^5.5.0",
 | 
				
			||||||
    "el-table-infinite-scroll": "^3.0.3",
 | 
					    "el-table-infinite-scroll": "^3.0.3",
 | 
				
			||||||
    "element-plus": "^2.7.1",
 | 
					    "element-plus": "2.7.1",
 | 
				
			||||||
    "intro.js": "^7.2.0",
 | 
					    "intro.js": "^7.2.0",
 | 
				
			||||||
    "js-cookie": "^3.0.5",
 | 
					    "js-cookie": "^3.0.5",
 | 
				
			||||||
    "jsbarcode": "^3.11.6",
 | 
					    "jsbarcode": "^3.11.6",
 | 
				
			||||||
@ -80,7 +80,7 @@
 | 
				
			|||||||
    "nprogress": "^0.2.0",
 | 
					    "nprogress": "^0.2.0",
 | 
				
			||||||
    "path": "^0.12.7",
 | 
					    "path": "^0.12.7",
 | 
				
			||||||
    "pinia": "^2.1.7",
 | 
					    "pinia": "^2.1.7",
 | 
				
			||||||
    "pinyin-pro": "^3.20.2",
 | 
					    "pinyin-pro": "^3.20.3",
 | 
				
			||||||
    "plus-pro-components": "^0.0.11",
 | 
					    "plus-pro-components": "^0.0.11",
 | 
				
			||||||
    "qrcode": "^1.5.3",
 | 
					    "qrcode": "^1.5.3",
 | 
				
			||||||
    "qs": "^6.12.1",
 | 
					    "qs": "^6.12.1",
 | 
				
			||||||
@ -91,21 +91,21 @@
 | 
				
			|||||||
    "v-contextmenu": "^3.2.0",
 | 
					    "v-contextmenu": "^3.2.0",
 | 
				
			||||||
    "v3-infinite-loading": "^1.3.1",
 | 
					    "v3-infinite-loading": "^1.3.1",
 | 
				
			||||||
    "version-rocket": "^1.7.1",
 | 
					    "version-rocket": "^1.7.1",
 | 
				
			||||||
    "vue": "^3.4.25",
 | 
					    "vue": "^3.4.26",
 | 
				
			||||||
    "vue-i18n": "^9.13.1",
 | 
					    "vue-i18n": "^9.13.1",
 | 
				
			||||||
    "vue-json-pretty": "^2.4.0",
 | 
					    "vue-json-pretty": "^2.4.0",
 | 
				
			||||||
    "vue-pdf-embed": "^2.0.3",
 | 
					    "vue-pdf-embed": "^2.0.3",
 | 
				
			||||||
    "vue-router": "^4.3.2",
 | 
					    "vue-router": "^4.3.2",
 | 
				
			||||||
    "vue-tippy": "^6.4.1",
 | 
					    "vue-tippy": "^6.4.1",
 | 
				
			||||||
    "vue-types": "^5.1.1",
 | 
					    "vue-types": "^5.1.2",
 | 
				
			||||||
    "vue-virtual-scroller": "2.0.0-beta.8",
 | 
					    "vue-virtual-scroller": "2.0.0-beta.8",
 | 
				
			||||||
    "vue-waterfall-plugin-next": "^2.4.3",
 | 
					    "vue-waterfall-plugin-next": "^2.4.3",
 | 
				
			||||||
    "vue3-danmaku": "^1.6.0",
 | 
					    "vue3-danmaku": "^1.6.0",
 | 
				
			||||||
    "vue3-puzzle-vcode": "^1.1.7",
 | 
					    "vue3-puzzle-vcode": "^1.1.7",
 | 
				
			||||||
    "vuedraggable": "^4.1.0",
 | 
					    "vuedraggable": "^4.1.0",
 | 
				
			||||||
    "vxe-table": "^4.6.3",
 | 
					    "vxe-table": "^4.6.8",
 | 
				
			||||||
    "wavesurfer.js": "^7.7.11",
 | 
					    "wavesurfer.js": "^7.7.12",
 | 
				
			||||||
    "xgplayer": "^3.0.16",
 | 
					    "xgplayer": "^3.0.17",
 | 
				
			||||||
    "xlsx": "^0.18.5"
 | 
					    "xlsx": "^0.18.5"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
@ -123,18 +123,18 @@
 | 
				
			|||||||
    "@types/gradient-string": "^1.1.6",
 | 
					    "@types/gradient-string": "^1.1.6",
 | 
				
			||||||
    "@types/intro.js": "^5.1.5",
 | 
					    "@types/intro.js": "^5.1.5",
 | 
				
			||||||
    "@types/js-cookie": "^3.0.6",
 | 
					    "@types/js-cookie": "^3.0.6",
 | 
				
			||||||
    "@types/node": "^20.12.7",
 | 
					    "@types/node": "^20.12.8",
 | 
				
			||||||
    "@types/nprogress": "^0.2.3",
 | 
					    "@types/nprogress": "^0.2.3",
 | 
				
			||||||
    "@types/qrcode": "^1.5.5",
 | 
					    "@types/qrcode": "^1.5.5",
 | 
				
			||||||
    "@types/qs": "^6.9.15",
 | 
					    "@types/qs": "^6.9.15",
 | 
				
			||||||
    "@types/sortablejs": "^1.15.8",
 | 
					    "@types/sortablejs": "^1.15.8",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^7.7.1",
 | 
					    "@typescript-eslint/eslint-plugin": "^7.8.0",
 | 
				
			||||||
    "@typescript-eslint/parser": "^7.7.1",
 | 
					    "@typescript-eslint/parser": "^7.8.0",
 | 
				
			||||||
    "@vitejs/plugin-vue": "^5.0.4",
 | 
					    "@vitejs/plugin-vue": "^5.0.4",
 | 
				
			||||||
    "@vitejs/plugin-vue-jsx": "^3.1.0",
 | 
					    "@vitejs/plugin-vue-jsx": "^3.1.0",
 | 
				
			||||||
    "autoprefixer": "^10.4.19",
 | 
					    "autoprefixer": "^10.4.19",
 | 
				
			||||||
    "boxen": "^7.1.1",
 | 
					    "boxen": "^7.1.1",
 | 
				
			||||||
    "cssnano": "^7.0.0",
 | 
					    "cssnano": "^7.0.1",
 | 
				
			||||||
    "dagre": "^0.8.5",
 | 
					    "dagre": "^0.8.5",
 | 
				
			||||||
    "eslint": "^9.1.1",
 | 
					    "eslint": "^9.1.1",
 | 
				
			||||||
    "eslint-config-prettier": "^9.1.0",
 | 
					    "eslint-config-prettier": "^9.1.0",
 | 
				
			||||||
@ -151,8 +151,8 @@
 | 
				
			|||||||
    "prettier": "^3.2.5",
 | 
					    "prettier": "^3.2.5",
 | 
				
			||||||
    "rimraf": "^5.0.5",
 | 
					    "rimraf": "^5.0.5",
 | 
				
			||||||
    "rollup-plugin-visualizer": "^5.12.0",
 | 
					    "rollup-plugin-visualizer": "^5.12.0",
 | 
				
			||||||
    "sass": "^1.75.0",
 | 
					    "sass": "^1.76.0",
 | 
				
			||||||
    "stylelint": "^16.4.0",
 | 
					    "stylelint": "^16.5.0",
 | 
				
			||||||
    "stylelint-config-recess-order": "^5.0.1",
 | 
					    "stylelint-config-recess-order": "^5.0.1",
 | 
				
			||||||
    "stylelint-config-recommended-vue": "^1.5.0",
 | 
					    "stylelint-config-recommended-vue": "^1.5.0",
 | 
				
			||||||
    "stylelint-config-standard-scss": "^13.1.0",
 | 
					    "stylelint-config-standard-scss": "^13.1.0",
 | 
				
			||||||
@ -160,7 +160,7 @@
 | 
				
			|||||||
    "svgo": "^3.2.0",
 | 
					    "svgo": "^3.2.0",
 | 
				
			||||||
    "tailwindcss": "^3.4.3",
 | 
					    "tailwindcss": "^3.4.3",
 | 
				
			||||||
    "typescript": "^5.4.5",
 | 
					    "typescript": "^5.4.5",
 | 
				
			||||||
    "vite": "^5.2.10",
 | 
					    "vite": "^5.2.11",
 | 
				
			||||||
    "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-fake-server": "^2.1.1",
 | 
					    "vite-plugin-fake-server": "^2.1.1",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1280
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						| 
		 Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 439 B  | 
| 
		 Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B  | 
| 
		 Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 161 B  | 
| 
		 Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B  | 
| 
		 Before Width: | Height: | Size: 840 B After Width: | Height: | Size: 840 B  | 
@ -7,7 +7,7 @@ defineOptions({
 | 
				
			|||||||
  name: "ReAnimateSelector"
 | 
					  name: "ReAnimateSelector"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					defineProps({
 | 
				
			||||||
  placeholder: {
 | 
					  placeholder: {
 | 
				
			||||||
    type: String,
 | 
					    type: String,
 | 
				
			||||||
    default: "请选择动画"
 | 
					    default: "请选择动画"
 | 
				
			||||||
@ -81,7 +81,7 @@ function onMouseleave() {
 | 
				
			|||||||
  <el-select
 | 
					  <el-select
 | 
				
			||||||
    clearable
 | 
					    clearable
 | 
				
			||||||
    filterable
 | 
					    filterable
 | 
				
			||||||
    :placeholder="props.placeholder"
 | 
					    :placeholder="placeholder"
 | 
				
			||||||
    popper-class="pure-animate-popper"
 | 
					    popper-class="pure-animate-popper"
 | 
				
			||||||
    :model-value="inputValue"
 | 
					    :model-value="inputValue"
 | 
				
			||||||
    :filter-method="filterMethod"
 | 
					    :filter-method="filterMethod"
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ defineOptions({
 | 
				
			|||||||
  name: "ReCropperPreview"
 | 
					  name: "ReCropperPreview"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					defineProps({
 | 
				
			||||||
  imgSrc: String
 | 
					  imgSrc: String
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,7 +44,7 @@ defineExpose({ hidePopover });
 | 
				
			|||||||
        <div class="w-[18vw]">
 | 
					        <div class="w-[18vw]">
 | 
				
			||||||
          <ReCropper
 | 
					          <ReCropper
 | 
				
			||||||
            ref="refCropper"
 | 
					            ref="refCropper"
 | 
				
			||||||
            :src="props.imgSrc"
 | 
					            :src="imgSrc"
 | 
				
			||||||
            circled
 | 
					            circled
 | 
				
			||||||
            @cropper="onCropper"
 | 
					            @cropper="onCropper"
 | 
				
			||||||
            @readied="showPopover = true"
 | 
					            @readied="showPopover = true"
 | 
				
			||||||
 | 
				
			|||||||
@ -29,9 +29,11 @@ const addDialog = (options: DialogOptions) => {
 | 
				
			|||||||
const closeDialog = (options: DialogOptions, index: number, args?: any) => {
 | 
					const closeDialog = (options: DialogOptions, index: number, args?: any) => {
 | 
				
			||||||
  dialogStore.value[index].visible = false;
 | 
					  dialogStore.value[index].visible = false;
 | 
				
			||||||
  options.closeCallBack && options.closeCallBack({ options, index, args });
 | 
					  options.closeCallBack && options.closeCallBack({ options, index, args });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const closeDelay = options?.closeDelay ?? 200;
 | 
				
			||||||
  useTimeoutFn(() => {
 | 
					  useTimeoutFn(() => {
 | 
				
			||||||
    dialogStore.value.splice(index, 1);
 | 
					    dialogStore.value.splice(index, 1);
 | 
				
			||||||
  }, 200);
 | 
					  }, closeDelay);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
import VueJsonPretty from "vue-json-pretty";
 | 
					import VueJsonPretty from "vue-json-pretty";
 | 
				
			||||||
import "vue-json-pretty/lib/styles.css";
 | 
					import "vue-json-pretty/lib/styles.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					defineProps({
 | 
				
			||||||
  graphData: Object
 | 
					  graphData: Object
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
@ -12,6 +12,6 @@ const props = defineProps({
 | 
				
			|||||||
    :path="'res'"
 | 
					    :path="'res'"
 | 
				
			||||||
    :deep="3"
 | 
					    :deep="3"
 | 
				
			||||||
    :showLength="true"
 | 
					    :showLength="true"
 | 
				
			||||||
    :data="props.graphData"
 | 
					    :data="graphData"
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,7 @@ const nodeDragNode = item => {
 | 
				
			|||||||
  <!-- 左侧bpmn元素选择器 -->
 | 
					  <!-- 左侧bpmn元素选择器 -->
 | 
				
			||||||
  <div class="node-panel">
 | 
					  <div class="node-panel">
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      v-for="item in props.nodeList"
 | 
					      v-for="item in nodeList"
 | 
				
			||||||
      :key="item.text"
 | 
					      :key="item.text"
 | 
				
			||||||
      class="node-item dark:text-bg_color"
 | 
					      class="node-item dark:text-bg_color"
 | 
				
			||||||
      @mousedown="nodeDragNode(item)"
 | 
					      @mousedown="nodeDragNode(item)"
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
 | 
					 * 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
 | 
				
			||||||
 * @see 点击查看文档图标篇 {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/icon/}
 | 
					 * @see 点击查看文档图标篇 {@link https://pure-admin.github.io/pure-admin-doc/pages/icon/}
 | 
				
			||||||
 * @param icon 必传 图标
 | 
					 * @param icon 必传 图标
 | 
				
			||||||
 * @param attrs 可选 iconType 属性
 | 
					 * @param attrs 可选 iconType 属性
 | 
				
			||||||
 * @returns Component
 | 
					 * @returns Component
 | 
				
			||||||
 | 
				
			|||||||
@ -18,11 +18,11 @@ import {
 | 
				
			|||||||
  getKeyList
 | 
					  getKeyList
 | 
				
			||||||
} from "@pureadmin/utils";
 | 
					} from "@pureadmin/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import DragIcon from "./svg/drag.svg?component";
 | 
					import DragIcon from "@/assets/table-bar/drag.svg?component";
 | 
				
			||||||
import ExpandIcon from "./svg/expand.svg?component";
 | 
					import ExpandIcon from "@/assets/table-bar/expand.svg?component";
 | 
				
			||||||
import RefreshIcon from "./svg/refresh.svg?component";
 | 
					import RefreshIcon from "@/assets/table-bar/refresh.svg?component";
 | 
				
			||||||
import SettingIcon from "./svg/settings.svg?component";
 | 
					import SettingIcon from "@/assets/table-bar/settings.svg?component";
 | 
				
			||||||
import CollapseIcon from "./svg/collapse.svg?component";
 | 
					import CollapseIcon from "@/assets/table-bar/collapse.svg?component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = {
 | 
					const props = {
 | 
				
			||||||
  /** 头部最左边的标题 */
 | 
					  /** 头部最左边的标题 */
 | 
				
			||||||
 | 
				
			|||||||
@ -502,7 +502,7 @@ defineExpose({
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div :ref="'wrap' + props.classOption['key']">
 | 
					  <div :ref="'wrap' + classOption['key']">
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      v-if="navigation"
 | 
					      v-if="navigation"
 | 
				
			||||||
      :style="leftSwitch"
 | 
					      :style="leftSwitch"
 | 
				
			||||||
@ -520,7 +520,7 @@ defineExpose({
 | 
				
			|||||||
      <slot name="right-switch" />
 | 
					      <slot name="right-switch" />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      :ref="'realBox' + props.classOption['key']"
 | 
					      :ref="'realBox' + classOption['key']"
 | 
				
			||||||
      :style="pos"
 | 
					      :style="pos"
 | 
				
			||||||
      @mouseenter="enter"
 | 
					      @mouseenter="enter"
 | 
				
			||||||
      @mouseleave="leave"
 | 
					      @mouseleave="leave"
 | 
				
			||||||
@ -529,7 +529,7 @@ defineExpose({
 | 
				
			|||||||
      @touchend="touchEnd"
 | 
					      @touchend="touchEnd"
 | 
				
			||||||
      @mousewheel.passive="wheel"
 | 
					      @mousewheel.passive="wheel"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div :ref="'slotList' + props.classOption['key']" :style="float">
 | 
					      <div :ref="'slotList' + classOption['key']" :style="float">
 | 
				
			||||||
        <slot />
 | 
					        <slot />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div :style="float" v-html="copyHtml" />
 | 
					      <div :style="float" v-html="copyHtml" />
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ export interface OptionsType {
 | 
				
			|||||||
  label?: string | (() => VNode | Component);
 | 
					  label?: string | (() => VNode | Component);
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @description 图标,采用平台内置的 `useRenderIcon` 函数渲染
 | 
					   * @description 图标,采用平台内置的 `useRenderIcon` 函数渲染
 | 
				
			||||||
   * @see {@link 用法参考 https://yiming_chang.gitee.io/pure-admin-doc/pages/icon/#%E9%80%9A%E7%94%A8%E5%9B%BE%E6%A0%87-userendericon-hooks }
 | 
					   * @see {@link 用法参考 https://pure-admin.github.io/pure-admin-doc/pages/icon/#%E9%80%9A%E7%94%A8%E5%9B%BE%E6%A0%87-userendericon-hooks }
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  icon?: string | Component;
 | 
					  icon?: string | Component;
 | 
				
			||||||
  /** 图标属性、样式配置 */
 | 
					  /** 图标属性、样式配置 */
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								src/components/ReVxeTableBar/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import vxeTableBar from "./src/bar";
 | 
				
			||||||
 | 
					import { withInstall } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 配合 `vxe-table` 实现快速便捷的表格操作 */
 | 
				
			||||||
 | 
					export const VxeTableBar = withInstall(vxeTableBar);
 | 
				
			||||||
							
								
								
									
										362
									
								
								src/components/ReVxeTableBar/src/bar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,362 @@
 | 
				
			|||||||
 | 
					import Sortable from "sortablejs";
 | 
				
			||||||
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
 | 
					import { useEpThemeStoreHook } from "@/store/modules/epTheme";
 | 
				
			||||||
 | 
					import { delay, cloneDeep, getKeyList } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  type PropType,
 | 
				
			||||||
 | 
					  ref,
 | 
				
			||||||
 | 
					  unref,
 | 
				
			||||||
 | 
					  computed,
 | 
				
			||||||
 | 
					  nextTick,
 | 
				
			||||||
 | 
					  defineComponent,
 | 
				
			||||||
 | 
					  getCurrentInstance
 | 
				
			||||||
 | 
					} from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import DragIcon from "@/assets/table-bar/drag.svg?component";
 | 
				
			||||||
 | 
					import ExpandIcon from "@/assets/table-bar/expand.svg?component";
 | 
				
			||||||
 | 
					import RefreshIcon from "@/assets/table-bar/refresh.svg?component";
 | 
				
			||||||
 | 
					import SettingIcon from "@/assets/table-bar/settings.svg?component";
 | 
				
			||||||
 | 
					import CollapseIcon from "@/assets/table-bar/collapse.svg?component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = {
 | 
				
			||||||
 | 
					  /** 头部最左边的标题 */
 | 
				
			||||||
 | 
					  title: {
 | 
				
			||||||
 | 
					    type: String,
 | 
				
			||||||
 | 
					    default: "列表"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  vxeTableRef: {
 | 
				
			||||||
 | 
					    type: Object as PropType<any>
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  /** 需要展示的列 */
 | 
				
			||||||
 | 
					  columns: {
 | 
				
			||||||
 | 
					    type: Array as PropType<any>,
 | 
				
			||||||
 | 
					    default: () => []
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  /** 是否为树列表 */
 | 
				
			||||||
 | 
					  tree: {
 | 
				
			||||||
 | 
					    type: Boolean,
 | 
				
			||||||
 | 
					    default: false
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  isExpandAll: {
 | 
				
			||||||
 | 
					    type: Boolean,
 | 
				
			||||||
 | 
					    default: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  tableKey: {
 | 
				
			||||||
 | 
					    type: [String, Number] as PropType<string | number>,
 | 
				
			||||||
 | 
					    default: "0"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					  name: "VxeTableBar",
 | 
				
			||||||
 | 
					  props,
 | 
				
			||||||
 | 
					  emits: ["refresh"],
 | 
				
			||||||
 | 
					  setup(props, { emit, slots, attrs }) {
 | 
				
			||||||
 | 
					    const size = ref("small");
 | 
				
			||||||
 | 
					    const loading = ref(false);
 | 
				
			||||||
 | 
					    const checkAll = ref(true);
 | 
				
			||||||
 | 
					    const isIndeterminate = ref(false);
 | 
				
			||||||
 | 
					    const instance = getCurrentInstance()!;
 | 
				
			||||||
 | 
					    const isExpandAll = ref(props.isExpandAll);
 | 
				
			||||||
 | 
					    let checkColumnList = getKeyList(cloneDeep(props?.columns), "title");
 | 
				
			||||||
 | 
					    const checkedColumns = ref(getKeyList(cloneDeep(props?.columns), "title"));
 | 
				
			||||||
 | 
					    const dynamicColumns = ref(cloneDeep(props?.columns));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const getDropdownItemStyle = computed(() => {
 | 
				
			||||||
 | 
					      return s => {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          background:
 | 
				
			||||||
 | 
					            s === size.value ? useEpThemeStoreHook().epThemeColor : "",
 | 
				
			||||||
 | 
					          color: s === size.value ? "#fff" : "var(--el-text-color-primary)"
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const iconClass = computed(() => {
 | 
				
			||||||
 | 
					      return [
 | 
				
			||||||
 | 
					        "text-black",
 | 
				
			||||||
 | 
					        "dark:text-white",
 | 
				
			||||||
 | 
					        "duration-100",
 | 
				
			||||||
 | 
					        "hover:!text-primary",
 | 
				
			||||||
 | 
					        "cursor-pointer",
 | 
				
			||||||
 | 
					        "outline-none"
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const topClass = computed(() => {
 | 
				
			||||||
 | 
					      return [
 | 
				
			||||||
 | 
					        "flex",
 | 
				
			||||||
 | 
					        "justify-between",
 | 
				
			||||||
 | 
					        "pt-[3px]",
 | 
				
			||||||
 | 
					        "px-[11px]",
 | 
				
			||||||
 | 
					        "border-b-[1px]",
 | 
				
			||||||
 | 
					        "border-solid",
 | 
				
			||||||
 | 
					        "border-[#dcdfe6]",
 | 
				
			||||||
 | 
					        "dark:border-[#303030]"
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onReFresh() {
 | 
				
			||||||
 | 
					      loading.value = true;
 | 
				
			||||||
 | 
					      emit("refresh");
 | 
				
			||||||
 | 
					      delay(500).then(() => (loading.value = false));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function onExpand() {
 | 
				
			||||||
 | 
					      isExpandAll.value = !isExpandAll.value;
 | 
				
			||||||
 | 
					      isExpandAll.value
 | 
				
			||||||
 | 
					        ? props.vxeTableRef.setAllTreeExpand(true)
 | 
				
			||||||
 | 
					        : props.vxeTableRef.clearTreeExpand();
 | 
				
			||||||
 | 
					      props.vxeTableRef.refreshColumn();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function reloadColumn() {
 | 
				
			||||||
 | 
					      const curCheckedColumns = cloneDeep(dynamicColumns.value).filter(item =>
 | 
				
			||||||
 | 
					        checkedColumns.value.includes(item.title)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      props.vxeTableRef.reloadColumn(curCheckedColumns);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handleCheckAllChange(val: boolean) {
 | 
				
			||||||
 | 
					      checkedColumns.value = val ? checkColumnList : [];
 | 
				
			||||||
 | 
					      isIndeterminate.value = false;
 | 
				
			||||||
 | 
					      reloadColumn();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function handleCheckedColumnsChange(value: string[]) {
 | 
				
			||||||
 | 
					      checkedColumns.value = value;
 | 
				
			||||||
 | 
					      const checkedCount = value.length;
 | 
				
			||||||
 | 
					      checkAll.value = checkedCount === checkColumnList.length;
 | 
				
			||||||
 | 
					      isIndeterminate.value =
 | 
				
			||||||
 | 
					        checkedCount > 0 && checkedCount < checkColumnList.length;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async function onReset() {
 | 
				
			||||||
 | 
					      checkAll.value = true;
 | 
				
			||||||
 | 
					      isIndeterminate.value = false;
 | 
				
			||||||
 | 
					      dynamicColumns.value = cloneDeep(props?.columns);
 | 
				
			||||||
 | 
					      checkColumnList = [];
 | 
				
			||||||
 | 
					      checkColumnList = await getKeyList(cloneDeep(props?.columns), "title");
 | 
				
			||||||
 | 
					      checkedColumns.value = getKeyList(cloneDeep(props?.columns), "title");
 | 
				
			||||||
 | 
					      props.vxeTableRef.refreshColumn();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function changeSize(curSize: string) {
 | 
				
			||||||
 | 
					      size.value = curSize;
 | 
				
			||||||
 | 
					      props.vxeTableRef.refreshColumn();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dropdown = {
 | 
				
			||||||
 | 
					      dropdown: () => (
 | 
				
			||||||
 | 
					        <el-dropdown-menu class="translation">
 | 
				
			||||||
 | 
					          <el-dropdown-item
 | 
				
			||||||
 | 
					            style={getDropdownItemStyle.value("medium")}
 | 
				
			||||||
 | 
					            onClick={() => changeSize("medium")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            宽松
 | 
				
			||||||
 | 
					          </el-dropdown-item>
 | 
				
			||||||
 | 
					          <el-dropdown-item
 | 
				
			||||||
 | 
					            style={getDropdownItemStyle.value("small")}
 | 
				
			||||||
 | 
					            onClick={() => changeSize("small")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            默认
 | 
				
			||||||
 | 
					          </el-dropdown-item>
 | 
				
			||||||
 | 
					          <el-dropdown-item
 | 
				
			||||||
 | 
					            style={getDropdownItemStyle.value("mini")}
 | 
				
			||||||
 | 
					            onClick={() => changeSize("mini")}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            紧凑
 | 
				
			||||||
 | 
					          </el-dropdown-item>
 | 
				
			||||||
 | 
					        </el-dropdown-menu>
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 列展示拖拽排序 */
 | 
				
			||||||
 | 
					    const rowDrop = (event: { preventDefault: () => void }) => {
 | 
				
			||||||
 | 
					      event.preventDefault();
 | 
				
			||||||
 | 
					      nextTick(() => {
 | 
				
			||||||
 | 
					        const wrapper: HTMLElement = (
 | 
				
			||||||
 | 
					          instance?.proxy?.$refs[`VxeGroupRef${unref(props.tableKey)}`] as any
 | 
				
			||||||
 | 
					        ).$el.firstElementChild;
 | 
				
			||||||
 | 
					        Sortable.create(wrapper, {
 | 
				
			||||||
 | 
					          animation: 300,
 | 
				
			||||||
 | 
					          handle: ".drag-btn",
 | 
				
			||||||
 | 
					          onEnd: ({ newIndex, oldIndex, item }) => {
 | 
				
			||||||
 | 
					            const targetThElem = item;
 | 
				
			||||||
 | 
					            const wrapperElem = targetThElem.parentNode as HTMLElement;
 | 
				
			||||||
 | 
					            const oldColumn = dynamicColumns.value[oldIndex];
 | 
				
			||||||
 | 
					            const newColumn = dynamicColumns.value[newIndex];
 | 
				
			||||||
 | 
					            if (oldColumn?.fixed || newColumn?.fixed) {
 | 
				
			||||||
 | 
					              // 当前列存在fixed属性 则不可拖拽
 | 
				
			||||||
 | 
					              const oldThElem = wrapperElem.children[oldIndex] as HTMLElement;
 | 
				
			||||||
 | 
					              if (newIndex > oldIndex) {
 | 
				
			||||||
 | 
					                wrapperElem.insertBefore(targetThElem, oldThElem);
 | 
				
			||||||
 | 
					              } else {
 | 
				
			||||||
 | 
					                wrapperElem.insertBefore(
 | 
				
			||||||
 | 
					                  targetThElem,
 | 
				
			||||||
 | 
					                  oldThElem ? oldThElem.nextElementSibling : oldThElem
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
 | 
				
			||||||
 | 
					            dynamicColumns.value.splice(newIndex, 0, currentRow);
 | 
				
			||||||
 | 
					            reloadColumn();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isFixedColumn = (title: string) => {
 | 
				
			||||||
 | 
					      return dynamicColumns.value.filter(
 | 
				
			||||||
 | 
					        item => transformI18n(item.title) === transformI18n(title)
 | 
				
			||||||
 | 
					      )[0].fixed
 | 
				
			||||||
 | 
					        ? true
 | 
				
			||||||
 | 
					        : false;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const rendTippyProps = (content: string) => {
 | 
				
			||||||
 | 
					      // https://vue-tippy.netlify.app/props
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        content,
 | 
				
			||||||
 | 
					        offset: [0, 18],
 | 
				
			||||||
 | 
					        duration: [300, 0],
 | 
				
			||||||
 | 
					        followCursor: true,
 | 
				
			||||||
 | 
					        hideOnClick: "toggle"
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const reference = {
 | 
				
			||||||
 | 
					      reference: () => (
 | 
				
			||||||
 | 
					        <SettingIcon
 | 
				
			||||||
 | 
					          class={["w-[16px]", iconClass.value]}
 | 
				
			||||||
 | 
					          v-tippy={rendTippyProps("列设置")}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return () => (
 | 
				
			||||||
 | 
					      <>
 | 
				
			||||||
 | 
					        <div {...attrs} class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
 | 
				
			||||||
 | 
					          <div class="flex justify-between w-full h-[60px] p-4">
 | 
				
			||||||
 | 
					            {slots?.title ? (
 | 
				
			||||||
 | 
					              slots.title()
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					              <p class="font-bold truncate">{props.title}</p>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					            <div class="flex items-center justify-around">
 | 
				
			||||||
 | 
					              {slots?.buttons ? (
 | 
				
			||||||
 | 
					                <div class="flex mr-4">{slots.buttons()}</div>
 | 
				
			||||||
 | 
					              ) : null}
 | 
				
			||||||
 | 
					              {props.tree ? (
 | 
				
			||||||
 | 
					                <>
 | 
				
			||||||
 | 
					                  <ExpandIcon
 | 
				
			||||||
 | 
					                    class={["w-[16px]", iconClass.value]}
 | 
				
			||||||
 | 
					                    style={{
 | 
				
			||||||
 | 
					                      transform: isExpandAll.value ? "none" : "rotate(-90deg)"
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					                    v-tippy={rendTippyProps(
 | 
				
			||||||
 | 
					                      isExpandAll.value ? "折叠" : "展开"
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                    onClick={() => onExpand()}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <el-divider direction="vertical" />
 | 
				
			||||||
 | 
					                </>
 | 
				
			||||||
 | 
					              ) : null}
 | 
				
			||||||
 | 
					              <RefreshIcon
 | 
				
			||||||
 | 
					                class={[
 | 
				
			||||||
 | 
					                  "w-[16px]",
 | 
				
			||||||
 | 
					                  iconClass.value,
 | 
				
			||||||
 | 
					                  loading.value ? "animate-spin" : ""
 | 
				
			||||||
 | 
					                ]}
 | 
				
			||||||
 | 
					                v-tippy={rendTippyProps("刷新")}
 | 
				
			||||||
 | 
					                onClick={() => onReFresh()}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					              <el-divider direction="vertical" />
 | 
				
			||||||
 | 
					              <el-dropdown
 | 
				
			||||||
 | 
					                v-slots={dropdown}
 | 
				
			||||||
 | 
					                trigger="click"
 | 
				
			||||||
 | 
					                v-tippy={rendTippyProps("密度")}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <CollapseIcon class={["w-[16px]", iconClass.value]} />
 | 
				
			||||||
 | 
					              </el-dropdown>
 | 
				
			||||||
 | 
					              <el-divider direction="vertical" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <el-popover
 | 
				
			||||||
 | 
					                v-slots={reference}
 | 
				
			||||||
 | 
					                placement="bottom-start"
 | 
				
			||||||
 | 
					                popper-style={{ padding: 0 }}
 | 
				
			||||||
 | 
					                width="200"
 | 
				
			||||||
 | 
					                trigger="click"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <div class={[topClass.value]}>
 | 
				
			||||||
 | 
					                  <el-checkbox
 | 
				
			||||||
 | 
					                    class="!-mr-1"
 | 
				
			||||||
 | 
					                    label="列展示"
 | 
				
			||||||
 | 
					                    v-model={checkAll.value}
 | 
				
			||||||
 | 
					                    indeterminate={isIndeterminate.value}
 | 
				
			||||||
 | 
					                    onChange={value => handleCheckAllChange(value)}
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
 | 
					                  <el-button type="primary" link onClick={() => onReset()}>
 | 
				
			||||||
 | 
					                    重置
 | 
				
			||||||
 | 
					                  </el-button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <div class="pt-[6px] pl-[11px]">
 | 
				
			||||||
 | 
					                  <el-scrollbar max-height="36vh">
 | 
				
			||||||
 | 
					                    <el-checkbox-group
 | 
				
			||||||
 | 
					                      ref={`VxeGroupRef${unref(props.tableKey)}`}
 | 
				
			||||||
 | 
					                      modelValue={checkedColumns.value}
 | 
				
			||||||
 | 
					                      onChange={value => handleCheckedColumnsChange(value)}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <el-space
 | 
				
			||||||
 | 
					                        direction="vertical"
 | 
				
			||||||
 | 
					                        alignment="flex-start"
 | 
				
			||||||
 | 
					                        size={0}
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        {checkColumnList.map((item, index) => {
 | 
				
			||||||
 | 
					                          return (
 | 
				
			||||||
 | 
					                            <div class="flex items-center">
 | 
				
			||||||
 | 
					                              <DragIcon
 | 
				
			||||||
 | 
					                                class={[
 | 
				
			||||||
 | 
					                                  "drag-btn w-[16px] mr-2",
 | 
				
			||||||
 | 
					                                  isFixedColumn(item)
 | 
				
			||||||
 | 
					                                    ? "!cursor-no-drop"
 | 
				
			||||||
 | 
					                                    : "!cursor-grab"
 | 
				
			||||||
 | 
					                                ]}
 | 
				
			||||||
 | 
					                                onMouseenter={(event: {
 | 
				
			||||||
 | 
					                                  preventDefault: () => void;
 | 
				
			||||||
 | 
					                                }) => rowDrop(event)}
 | 
				
			||||||
 | 
					                              />
 | 
				
			||||||
 | 
					                              <el-checkbox
 | 
				
			||||||
 | 
					                                key={index}
 | 
				
			||||||
 | 
					                                label={item}
 | 
				
			||||||
 | 
					                                value={item}
 | 
				
			||||||
 | 
					                                onChange={reloadColumn}
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                <span
 | 
				
			||||||
 | 
					                                  title={transformI18n(item)}
 | 
				
			||||||
 | 
					                                  class="inline-block w-[120px] truncate hover:text-text_color_primary"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                  {transformI18n(item)}
 | 
				
			||||||
 | 
					                                </span>
 | 
				
			||||||
 | 
					                              </el-checkbox>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                          );
 | 
				
			||||||
 | 
					                        })}
 | 
				
			||||||
 | 
					                      </el-space>
 | 
				
			||||||
 | 
					                    </el-checkbox-group>
 | 
				
			||||||
 | 
					                  </el-scrollbar>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </el-popover>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          {slots.default({
 | 
				
			||||||
 | 
					            size: size.value,
 | 
				
			||||||
 | 
					            dynamicColumns: dynamicColumns.value
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					import { useI18n } from "vue-i18n";
 | 
				
			||||||
import Footer from "./footer/index.vue";
 | 
					import LayFrame from "../lay-frame/index.vue";
 | 
				
			||||||
 | 
					import LayFooter from "../lay-footer/index.vue";
 | 
				
			||||||
import { useGlobal, isNumber } from "@pureadmin/utils";
 | 
					import { useGlobal, isNumber } from "@pureadmin/utils";
 | 
				
			||||||
import KeepAliveFrame from "./keepAliveFrame/index.vue";
 | 
					import BackTopIcon from "@/assets/svg/back_top.svg?component";
 | 
				
			||||||
import backTop from "@/assets/svg/back_top.svg?component";
 | 
					 | 
				
			||||||
import { h, computed, Transition, defineComponent } from "vue";
 | 
					import { h, computed, Transition, defineComponent } from "vue";
 | 
				
			||||||
import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -99,15 +99,15 @@ const transitionMain = defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <section
 | 
					  <section
 | 
				
			||||||
    :class="[props.fixedHeader ? 'app-main' : 'app-main-nofixed-header']"
 | 
					    :class="[fixedHeader ? 'app-main' : 'app-main-nofixed-header']"
 | 
				
			||||||
    :style="getSectionStyle"
 | 
					    :style="getSectionStyle"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <router-view>
 | 
					    <router-view>
 | 
				
			||||||
      <template #default="{ Component, route }">
 | 
					      <template #default="{ Component, route }">
 | 
				
			||||||
        <KeepAliveFrame :currComp="Component" :currRoute="route">
 | 
					        <LayFrame :currComp="Component" :currRoute="route">
 | 
				
			||||||
          <template #default="{ Comp, fullPath, frameInfo }">
 | 
					          <template #default="{ Comp, fullPath, frameInfo }">
 | 
				
			||||||
            <el-scrollbar
 | 
					            <el-scrollbar
 | 
				
			||||||
              v-if="props.fixedHeader"
 | 
					              v-if="fixedHeader"
 | 
				
			||||||
              :wrap-style="{
 | 
					              :wrap-style="{
 | 
				
			||||||
                display: 'flex',
 | 
					                display: 'flex',
 | 
				
			||||||
                'flex-wrap': 'wrap',
 | 
					                'flex-wrap': 'wrap',
 | 
				
			||||||
@ -126,7 +126,7 @@ const transitionMain = defineComponent({
 | 
				
			|||||||
                :title="t('buttons.pureBackTop')"
 | 
					                :title="t('buttons.pureBackTop')"
 | 
				
			||||||
                target=".app-main .el-scrollbar__wrap"
 | 
					                target=".app-main .el-scrollbar__wrap"
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <backTop />
 | 
					                <BackTopIcon />
 | 
				
			||||||
              </el-backtop>
 | 
					              </el-backtop>
 | 
				
			||||||
              <div class="grow">
 | 
					              <div class="grow">
 | 
				
			||||||
                <transitionMain :route="route">
 | 
					                <transitionMain :route="route">
 | 
				
			||||||
@ -150,7 +150,7 @@ const transitionMain = defineComponent({
 | 
				
			|||||||
                  />
 | 
					                  />
 | 
				
			||||||
                </transitionMain>
 | 
					                </transitionMain>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              <Footer v-if="!hideFooter" />
 | 
					              <LayFooter v-if="!hideFooter" />
 | 
				
			||||||
            </el-scrollbar>
 | 
					            </el-scrollbar>
 | 
				
			||||||
            <div v-else class="grow">
 | 
					            <div v-else class="grow">
 | 
				
			||||||
              <transitionMain :route="route">
 | 
					              <transitionMain :route="route">
 | 
				
			||||||
@ -175,12 +175,12 @@ const transitionMain = defineComponent({
 | 
				
			|||||||
              </transitionMain>
 | 
					              </transitionMain>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </template>
 | 
					          </template>
 | 
				
			||||||
        </KeepAliveFrame>
 | 
					        </LayFrame>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </router-view>
 | 
					    </router-view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- 页脚 -->
 | 
					    <!-- 页脚 -->
 | 
				
			||||||
    <Footer v-if="!hideFooter && !props.fixedHeader" />
 | 
					    <LayFooter v-if="!hideFooter && !fixedHeader" />
 | 
				
			||||||
  </section>
 | 
					  </section>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { getConfig } from "@/config";
 | 
					import { getConfig } from "@/config";
 | 
				
			||||||
 | 
					import { useMultiFrame } from "@/layout/hooks/useMultiFrame";
 | 
				
			||||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
 | 
					import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
 | 
				
			||||||
import { type Component, shallowRef, watch, computed } from "vue";
 | 
					import { type Component, shallowRef, watch, computed } from "vue";
 | 
				
			||||||
import { type RouteRecordRaw, RouteLocationNormalizedLoaded } from "vue-router";
 | 
					import { type RouteRecordRaw, RouteLocationNormalizedLoaded } from "vue-router";
 | 
				
			||||||
import { useMultiFrame } from "@/layout/components/keepAliveFrame/useMultiFrame";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps<{
 | 
					const props = defineProps<{
 | 
				
			||||||
  currRoute: RouteLocationNormalizedLoaded;
 | 
					  currRoute: RouteLocationNormalizedLoaded;
 | 
				
			||||||
@ -20,7 +20,7 @@ const keep = computed(() => {
 | 
				
			|||||||
    !!props.currRoute.meta?.frameSrc
 | 
					    !!props.currRoute.meta?.frameSrc
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
// 避免重新渲染 frameView
 | 
					// 避免重新渲染 LayFrame
 | 
				
			||||||
const normalComp = computed(() => !keep.value && props.currComp);
 | 
					const normalComp = computed(() => !keep.value && props.currComp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(useMultiTagsStoreHook().multiTags, (tags: any) => {
 | 
					watch(useMultiTagsStoreHook().multiTags, (tags: any) => {
 | 
				
			||||||
@ -65,7 +65,7 @@ watch(
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <template v-for="[fullPath, Comp] in compList" :key="fullPath">
 | 
					  <template v-for="[fullPath, Comp] in compList" :key="fullPath">
 | 
				
			||||||
    <div v-show="fullPath === props.currRoute.fullPath" class="w-full h-full">
 | 
					    <div v-show="fullPath === currRoute.fullPath" class="w-full h-full">
 | 
				
			||||||
      <slot
 | 
					      <slot
 | 
				
			||||||
        :fullPath="fullPath"
 | 
					        :fullPath="fullPath"
 | 
				
			||||||
        :Comp="Comp"
 | 
					        :Comp="Comp"
 | 
				
			||||||
@ -74,6 +74,6 @@ watch(
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </template>
 | 
					  </template>
 | 
				
			||||||
  <div v-show="!keep" class="w-full h-full">
 | 
					  <div v-show="!keep" class="w-full h-full">
 | 
				
			||||||
    <slot :Comp="normalComp" :fullPath="props.currRoute.fullPath" frameInfo />
 | 
					    <slot :Comp="normalComp" :fullPath="currRoute.fullPath" frameInfo />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@ -1,13 +1,14 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import Search from "./search/index.vue";
 | 
					 | 
				
			||||||
import Notice from "./notice/index.vue";
 | 
					 | 
				
			||||||
import mixNav from "./sidebar/mixNav.vue";
 | 
					 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import FullScreen from "./sidebar/fullScreen.vue";
 | 
					import LaySearch from "../lay-search/index.vue";
 | 
				
			||||||
import Breadcrumb from "./sidebar/breadCrumb.vue";
 | 
					import LayNotice from "../lay-notice/index.vue";
 | 
				
			||||||
import topCollapse from "./sidebar/topCollapse.vue";
 | 
					import LayNavMix from "../lay-sidebar/NavMix.vue";
 | 
				
			||||||
import { useTranslationLang } from "../hooks/useTranslationLang";
 | 
					import { useTranslationLang } from "@/layout/hooks/useTranslationLang";
 | 
				
			||||||
import globalization from "@/assets/svg/globalization.svg?component";
 | 
					import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue";
 | 
				
			||||||
 | 
					import LaySidebarBreadCrumb from "../lay-sidebar/components/SidebarBreadCrumb.vue";
 | 
				
			||||||
 | 
					import LaySidebarTopCollapse from "../lay-sidebar/components/SidebarTopCollapse.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import GlobalizationIcon from "@/assets/svg/globalization.svg?component";
 | 
				
			||||||
import AccountSettingsIcon from "@iconify-icons/ri/user-settings-line";
 | 
					import AccountSettingsIcon from "@iconify-icons/ri/user-settings-line";
 | 
				
			||||||
import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
 | 
					import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
 | 
				
			||||||
import Setting from "@iconify-icons/ri/settings-3-line";
 | 
					import Setting from "@iconify-icons/ri/settings-3-line";
 | 
				
			||||||
@ -33,26 +34,26 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="navbar bg-[#fff] shadow-sm shadow-[rgba(0,21,41,0.08)]">
 | 
					  <div class="navbar bg-[#fff] shadow-sm shadow-[rgba(0,21,41,0.08)]">
 | 
				
			||||||
    <topCollapse
 | 
					    <LaySidebarTopCollapse
 | 
				
			||||||
      v-if="device === 'mobile'"
 | 
					      v-if="device === 'mobile'"
 | 
				
			||||||
      class="hamburger-container"
 | 
					      class="hamburger-container"
 | 
				
			||||||
      :is-active="pureApp.sidebar.opened"
 | 
					      :is-active="pureApp.sidebar.opened"
 | 
				
			||||||
      @toggleClick="toggleSideBar"
 | 
					      @toggleClick="toggleSideBar"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <Breadcrumb
 | 
					    <LaySidebarBreadCrumb
 | 
				
			||||||
      v-if="layout !== 'mix' && device !== 'mobile'"
 | 
					      v-if="layout !== 'mix' && device !== 'mobile'"
 | 
				
			||||||
      class="breadcrumb-container"
 | 
					      class="breadcrumb-container"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <mixNav v-if="layout === 'mix'" />
 | 
					    <LayNavMix v-if="layout === 'mix'" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div v-if="layout === 'vertical'" class="vertical-header-right">
 | 
					    <div v-if="layout === 'vertical'" class="vertical-header-right">
 | 
				
			||||||
      <!-- 菜单搜索 -->
 | 
					      <!-- 菜单搜索 -->
 | 
				
			||||||
      <Search id="header-search" />
 | 
					      <LaySearch id="header-search" />
 | 
				
			||||||
      <!-- 国际化 -->
 | 
					      <!-- 国际化 -->
 | 
				
			||||||
      <el-dropdown id="header-translation" trigger="click">
 | 
					      <el-dropdown id="header-translation" trigger="click">
 | 
				
			||||||
        <globalization
 | 
					        <GlobalizationIcon
 | 
				
			||||||
          class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
 | 
					          class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <template #dropdown>
 | 
					        <template #dropdown>
 | 
				
			||||||
@ -83,9 +84,9 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
 | 
				
			|||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </el-dropdown>
 | 
					      </el-dropdown>
 | 
				
			||||||
      <!-- 全屏 -->
 | 
					      <!-- 全屏 -->
 | 
				
			||||||
      <FullScreen id="full-screen" />
 | 
					      <LaySidebarFullScreen id="full-screen" />
 | 
				
			||||||
      <!-- 消息通知 -->
 | 
					      <!-- 消息通知 -->
 | 
				
			||||||
      <Notice id="header-notice" />
 | 
					      <LayNotice id="header-notice" />
 | 
				
			||||||
      <!-- 退出登录 -->
 | 
					      <!-- 退出登录 -->
 | 
				
			||||||
      <el-dropdown trigger="click">
 | 
					      <el-dropdown trigger="click">
 | 
				
			||||||
        <span class="el-dropdown-link navbar-bg-hover select-none">
 | 
					        <span class="el-dropdown-link navbar-bg-hover select-none">
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ListItem } from "./data";
 | 
					import { ListItem } from "../data";
 | 
				
			||||||
import { ref, PropType, nextTick } from "vue";
 | 
					import { ref, PropType, nextTick } from "vue";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import { deviceDetection } from "@pureadmin/utils";
 | 
					import { deviceDetection } from "@pureadmin/utils";
 | 
				
			||||||
@ -52,9 +52,9 @@ function hoverDescription(event, description) {
 | 
				
			|||||||
    class="notice-container border-b-[1px] border-solid border-[#f0f0f0] dark:border-[#303030]"
 | 
					    class="notice-container border-b-[1px] border-solid border-[#f0f0f0] dark:border-[#303030]"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <el-avatar
 | 
					    <el-avatar
 | 
				
			||||||
      v-if="props.noticeItem.avatar"
 | 
					      v-if="noticeItem.avatar"
 | 
				
			||||||
      :size="30"
 | 
					      :size="30"
 | 
				
			||||||
      :src="props.noticeItem.avatar"
 | 
					      :src="noticeItem.avatar"
 | 
				
			||||||
      class="notice-container-avatar"
 | 
					      class="notice-container-avatar"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <div class="notice-container-text">
 | 
					    <div class="notice-container-text">
 | 
				
			||||||
@ -63,7 +63,7 @@ function hoverDescription(event, description) {
 | 
				
			|||||||
          popper-class="notice-title-popper"
 | 
					          popper-class="notice-title-popper"
 | 
				
			||||||
          :effect="tooltipEffect"
 | 
					          :effect="tooltipEffect"
 | 
				
			||||||
          :disabled="!titleTooltip"
 | 
					          :disabled="!titleTooltip"
 | 
				
			||||||
          :content="props.noticeItem.title"
 | 
					          :content="noticeItem.title"
 | 
				
			||||||
          placement="top-start"
 | 
					          placement="top-start"
 | 
				
			||||||
          :enterable="!isMobile"
 | 
					          :enterable="!isMobile"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
@ -72,16 +72,16 @@ function hoverDescription(event, description) {
 | 
				
			|||||||
            class="notice-title-content"
 | 
					            class="notice-title-content"
 | 
				
			||||||
            @mouseover="hoverTitle"
 | 
					            @mouseover="hoverTitle"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            {{ props.noticeItem.title }}
 | 
					            {{ noticeItem.title }}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </el-tooltip>
 | 
					        </el-tooltip>
 | 
				
			||||||
        <el-tag
 | 
					        <el-tag
 | 
				
			||||||
          v-if="props.noticeItem?.extra"
 | 
					          v-if="noticeItem?.extra"
 | 
				
			||||||
          :type="props.noticeItem?.status"
 | 
					          :type="noticeItem?.status"
 | 
				
			||||||
          size="small"
 | 
					          size="small"
 | 
				
			||||||
          class="notice-title-extra"
 | 
					          class="notice-title-extra"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {{ props.noticeItem?.extra }}
 | 
					          {{ noticeItem?.extra }}
 | 
				
			||||||
        </el-tag>
 | 
					        </el-tag>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,19 +89,19 @@ function hoverDescription(event, description) {
 | 
				
			|||||||
        popper-class="notice-title-popper"
 | 
					        popper-class="notice-title-popper"
 | 
				
			||||||
        :effect="tooltipEffect"
 | 
					        :effect="tooltipEffect"
 | 
				
			||||||
        :disabled="!descriptionTooltip"
 | 
					        :disabled="!descriptionTooltip"
 | 
				
			||||||
        :content="props.noticeItem.description"
 | 
					        :content="noticeItem.description"
 | 
				
			||||||
        placement="top-start"
 | 
					        placement="top-start"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
          ref="descriptionRef"
 | 
					          ref="descriptionRef"
 | 
				
			||||||
          class="notice-text-description"
 | 
					          class="notice-text-description"
 | 
				
			||||||
          @mouseover="hoverDescription($event, props.noticeItem.description)"
 | 
					          @mouseover="hoverDescription($event, noticeItem.description)"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {{ props.noticeItem.description }}
 | 
					          {{ noticeItem.description }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </el-tooltip>
 | 
					      </el-tooltip>
 | 
				
			||||||
      <div class="notice-text-datetime text-[#00000073] dark:text-white">
 | 
					      <div class="notice-text-datetime text-[#00000073] dark:text-white">
 | 
				
			||||||
        {{ props.noticeItem.datetime }}
 | 
					        {{ noticeItem.datetime }}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/layout/components/lay-notice/components/NoticeList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { PropType } from "vue";
 | 
				
			||||||
 | 
					import { ListItem } from "../data";
 | 
				
			||||||
 | 
					import NoticeItem from "./NoticeItem.vue";
 | 
				
			||||||
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineProps({
 | 
				
			||||||
 | 
					  list: {
 | 
				
			||||||
 | 
					    type: Array as PropType<Array<ListItem>>,
 | 
				
			||||||
 | 
					    default: () => []
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  emptyText: {
 | 
				
			||||||
 | 
					    type: String,
 | 
				
			||||||
 | 
					    default: ""
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div v-if="list.length">
 | 
				
			||||||
 | 
					    <NoticeItem v-for="(item, index) in list" :key="index" :noticeItem="item" />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  <el-empty v-else :description="transformI18n(emptyText)" />
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
							
								
								
									
										99
									
								
								src/layout/components/lay-notice/data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					import { $t } from "@/plugins/i18n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ListItem {
 | 
				
			||||||
 | 
					  avatar: string;
 | 
				
			||||||
 | 
					  title: string;
 | 
				
			||||||
 | 
					  datetime: string;
 | 
				
			||||||
 | 
					  type: string;
 | 
				
			||||||
 | 
					  description: string;
 | 
				
			||||||
 | 
					  status?: "primary" | "success" | "warning" | "info" | "danger";
 | 
				
			||||||
 | 
					  extra?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface TabItem {
 | 
				
			||||||
 | 
					  key: string;
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  list: ListItem[];
 | 
				
			||||||
 | 
					  emptyText: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const noticesData: TabItem[] = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: "1",
 | 
				
			||||||
 | 
					    name: $t("status.pureNotify"),
 | 
				
			||||||
 | 
					    list: [],
 | 
				
			||||||
 | 
					    emptyText: $t("status.pureNoNotify")
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: "2",
 | 
				
			||||||
 | 
					    name: $t("status.pureMessage"),
 | 
				
			||||||
 | 
					    list: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "https://xiaoxian521.github.io/hyperlink/svg/smile1.svg",
 | 
				
			||||||
 | 
					        title: "小铭 评论了你",
 | 
				
			||||||
 | 
					        description: "诚在于心,信在于行,诚信在于心行合一。",
 | 
				
			||||||
 | 
					        datetime: "今天",
 | 
				
			||||||
 | 
					        type: "2"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "https://xiaoxian521.github.io/hyperlink/svg/smile2.svg",
 | 
				
			||||||
 | 
					        title: "李白 回复了你",
 | 
				
			||||||
 | 
					        description: "长风破浪会有时,直挂云帆济沧海。",
 | 
				
			||||||
 | 
					        datetime: "昨天",
 | 
				
			||||||
 | 
					        type: "2"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "https://xiaoxian521.github.io/hyperlink/svg/smile5.svg",
 | 
				
			||||||
 | 
					        title: "标题",
 | 
				
			||||||
 | 
					        description:
 | 
				
			||||||
 | 
					          "请将鼠标移动到此处,以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2,超过2行的描述内容将被省略并且可以通过tooltip查看完整内容",
 | 
				
			||||||
 | 
					        datetime: "时间",
 | 
				
			||||||
 | 
					        type: "2"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    emptyText: $t("status.pureNoMessage")
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: "3",
 | 
				
			||||||
 | 
					    name: $t("status.pureTodo"),
 | 
				
			||||||
 | 
					    list: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "",
 | 
				
			||||||
 | 
					        title: "第三方紧急代码变更",
 | 
				
			||||||
 | 
					        description:
 | 
				
			||||||
 | 
					          "小林提交于 2024-05-10,需在 2024-05-11 前完成代码变更任务",
 | 
				
			||||||
 | 
					        datetime: "",
 | 
				
			||||||
 | 
					        extra: "马上到期",
 | 
				
			||||||
 | 
					        status: "danger",
 | 
				
			||||||
 | 
					        type: "3"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "",
 | 
				
			||||||
 | 
					        title: "版本发布",
 | 
				
			||||||
 | 
					        description: "指派小铭于 2024-06-18 前完成更新并发布",
 | 
				
			||||||
 | 
					        datetime: "",
 | 
				
			||||||
 | 
					        extra: "已耗时 8 天",
 | 
				
			||||||
 | 
					        status: "warning",
 | 
				
			||||||
 | 
					        type: "3"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "",
 | 
				
			||||||
 | 
					        title: "新功能开发",
 | 
				
			||||||
 | 
					        description: "开发多租户管理",
 | 
				
			||||||
 | 
					        datetime: "",
 | 
				
			||||||
 | 
					        extra: "进行中",
 | 
				
			||||||
 | 
					        type: "3"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        avatar: "",
 | 
				
			||||||
 | 
					        title: "任务名称",
 | 
				
			||||||
 | 
					        description: "任务需要在 2030-10-30 10:00 前启动",
 | 
				
			||||||
 | 
					        datetime: "",
 | 
				
			||||||
 | 
					        extra: "未开始",
 | 
				
			||||||
 | 
					        status: "info",
 | 
				
			||||||
 | 
					        type: "3"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    emptyText: $t("status.pureNoTodo")
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
@ -1,24 +1,36 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { ref } from "vue";
 | 
					 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					import { useI18n } from "vue-i18n";
 | 
				
			||||||
 | 
					import { ref, computed } from "vue";
 | 
				
			||||||
import { noticesData } from "./data";
 | 
					import { noticesData } from "./data";
 | 
				
			||||||
import NoticeList from "./noticeList.vue";
 | 
					import NoticeList from "./components/NoticeList.vue";
 | 
				
			||||||
import Bell from "@iconify-icons/ep/bell";
 | 
					import BellIcon from "@iconify-icons/ep/bell";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { t } = useI18n();
 | 
					const { t } = useI18n();
 | 
				
			||||||
const noticesNum = ref(0);
 | 
					const noticesNum = ref(0);
 | 
				
			||||||
const notices = ref(noticesData);
 | 
					const notices = ref(noticesData);
 | 
				
			||||||
const activeKey = ref(noticesData[0].key);
 | 
					const activeKey = ref(noticesData[0]?.key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
notices.value.map(v => (noticesNum.value += v.list.length));
 | 
					notices.value.map(v => (noticesNum.value += v.list.length));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getLabel = computed(
 | 
				
			||||||
 | 
					  () => item =>
 | 
				
			||||||
 | 
					    t(item.name) + (item.list.length > 0 ? `(${item.list.length})` : "")
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <el-dropdown trigger="click" placement="bottom-end">
 | 
					  <el-dropdown trigger="click" placement="bottom-end">
 | 
				
			||||||
    <span class="dropdown-badge navbar-bg-hover select-none">
 | 
					    <span
 | 
				
			||||||
      <el-badge :value="noticesNum" :max="99">
 | 
					      :class="[
 | 
				
			||||||
 | 
					        'dropdown-badge',
 | 
				
			||||||
 | 
					        'navbar-bg-hover',
 | 
				
			||||||
 | 
					        'select-none',
 | 
				
			||||||
 | 
					        Number(noticesNum) !== 0 && 'mr-[10px]'
 | 
				
			||||||
 | 
					      ]"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <el-badge :value="Number(noticesNum) === 0 ? '' : noticesNum" :max="99">
 | 
				
			||||||
        <span class="header-notice-icon">
 | 
					        <span class="header-notice-icon">
 | 
				
			||||||
          <IconifyIconOffline :icon="Bell" />
 | 
					          <IconifyIconOffline :icon="BellIcon" />
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </el-badge>
 | 
					      </el-badge>
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
@ -37,13 +49,10 @@ notices.value.map(v => (noticesNum.value += v.list.length));
 | 
				
			|||||||
          />
 | 
					          />
 | 
				
			||||||
          <span v-else>
 | 
					          <span v-else>
 | 
				
			||||||
            <template v-for="item in notices" :key="item.key">
 | 
					            <template v-for="item in notices" :key="item.key">
 | 
				
			||||||
              <el-tab-pane
 | 
					              <el-tab-pane :label="getLabel(item)" :name="`${item.key}`">
 | 
				
			||||||
                :label="`${item.name}(${item.list.length})`"
 | 
					 | 
				
			||||||
                :name="`${item.key}`"
 | 
					 | 
				
			||||||
              >
 | 
					 | 
				
			||||||
                <el-scrollbar max-height="330px">
 | 
					                <el-scrollbar max-height="330px">
 | 
				
			||||||
                  <div class="noticeList-container">
 | 
					                  <div class="noticeList-container">
 | 
				
			||||||
                    <NoticeList :list="item.list" />
 | 
					                    <NoticeList :list="item.list" :emptyText="item.emptyText" />
 | 
				
			||||||
                  </div>
 | 
					                  </div>
 | 
				
			||||||
                </el-scrollbar>
 | 
					                </el-scrollbar>
 | 
				
			||||||
              </el-tab-pane>
 | 
					              </el-tab-pane>
 | 
				
			||||||
@ -62,7 +71,6 @@ notices.value.map(v => (noticesNum.value += v.list.length));
 | 
				
			|||||||
  justify-content: center;
 | 
					  justify-content: center;
 | 
				
			||||||
  width: 40px;
 | 
					  width: 40px;
 | 
				
			||||||
  height: 48px;
 | 
					  height: 48px;
 | 
				
			||||||
  margin-right: 10px;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .header-notice-icon {
 | 
					  .header-notice-icon {
 | 
				
			||||||
@ -4,7 +4,7 @@ import { emitter } from "@/utils/mitt";
 | 
				
			|||||||
import { onClickOutside } from "@vueuse/core";
 | 
					import { onClickOutside } from "@vueuse/core";
 | 
				
			||||||
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
 | 
					import { ref, computed, onMounted, onBeforeUnmount } from "vue";
 | 
				
			||||||
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
 | 
					import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
 | 
				
			||||||
import Close from "@iconify-icons/ep/close";
 | 
					import CloseIcon from "@iconify-icons/ep/close";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const target = ref(null);
 | 
					const target = ref(null);
 | 
				
			||||||
const show = ref<Boolean>(false);
 | 
					const show = ref<Boolean>(false);
 | 
				
			||||||
@ -68,7 +68,7 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
            class="dark:text-white"
 | 
					            class="dark:text-white"
 | 
				
			||||||
            width="18px"
 | 
					            width="18px"
 | 
				
			||||||
            height="18px"
 | 
					            height="18px"
 | 
				
			||||||
            :icon="Close"
 | 
					            :icon="CloseIcon"
 | 
				
			||||||
            @click="show = !show"
 | 
					            @click="show = !show"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					import { useI18n } from "vue-i18n";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import mdiKeyboardEsc from "@/assets/svg/keyboard_esc.svg?component";
 | 
					import MdiKeyboardEsc from "@/assets/svg/keyboard_esc.svg?component";
 | 
				
			||||||
import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
 | 
					import EnterOutlined from "@/assets/svg/enter_outlined.svg?component";
 | 
				
			||||||
import ArrowUpLine from "@iconify-icons/ri/arrow-up-line";
 | 
					import ArrowUpLine from "@iconify-icons/ri/arrow-up-line";
 | 
				
			||||||
import ArrowDownLine from "@iconify-icons/ri/arrow-down-line";
 | 
					import ArrowDownLine from "@iconify-icons/ri/arrow-down-line";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,7 +17,7 @@ const { device } = useNav();
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="search-footer text-[#333] dark:text-white">
 | 
					  <div class="search-footer text-[#333] dark:text-white">
 | 
				
			||||||
    <span class="search-footer-item">
 | 
					    <span class="search-footer-item">
 | 
				
			||||||
      <enterOutlined class="icon" />
 | 
					      <EnterOutlined class="icon" />
 | 
				
			||||||
      {{ t("buttons.pureConfirm") }}
 | 
					      {{ t("buttons.pureConfirm") }}
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
    <span class="search-footer-item">
 | 
					    <span class="search-footer-item">
 | 
				
			||||||
@ -26,14 +26,11 @@ const { device } = useNav();
 | 
				
			|||||||
      {{ t("buttons.pureSwitch") }}
 | 
					      {{ t("buttons.pureSwitch") }}
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
    <span class="search-footer-item">
 | 
					    <span class="search-footer-item">
 | 
				
			||||||
      <mdiKeyboardEsc class="icon" />
 | 
					      <MdiKeyboardEsc class="icon" />
 | 
				
			||||||
      {{ t("buttons.pureClose") }}
 | 
					      {{ t("buttons.pureClose") }}
 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
    <p
 | 
					    <p v-if="device !== 'mobile' && total > 0" class="search-footer-total">
 | 
				
			||||||
      v-if="device !== 'mobile' && props.total > 0"
 | 
					      {{ `${t("search.pureTotal")} ${total}` }}
 | 
				
			||||||
      class="search-footer-total"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      {{ `${t("search.pureTotal")} ${props.total}` }}
 | 
					 | 
				
			||||||
    </p>
 | 
					    </p>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@ -2,8 +2,8 @@
 | 
				
			|||||||
import type { optionsItem } from "../types";
 | 
					import type { optionsItem } from "../types";
 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
import Star from "@iconify-icons/ep/star";
 | 
					import StarIcon from "@iconify-icons/ep/star";
 | 
				
			||||||
import Close from "@iconify-icons/ep/close";
 | 
					import CloseIcon from "@iconify-icons/ep/close";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Props {
 | 
					interface Props {
 | 
				
			||||||
  item: optionsItem;
 | 
					  item: optionsItem;
 | 
				
			||||||
@ -33,12 +33,12 @@ function handleDelete(item) {
 | 
				
			|||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
  <IconifyIconOffline
 | 
					  <IconifyIconOffline
 | 
				
			||||||
    v-show="item.type === 'history'"
 | 
					    v-show="item.type === 'history'"
 | 
				
			||||||
    :icon="Star"
 | 
					    :icon="StarIcon"
 | 
				
			||||||
    class="w-[18px] h-[18px] mr-2 hover:text-[#d7d5d4]"
 | 
					    class="w-[18px] h-[18px] mr-2 hover:text-[#d7d5d4]"
 | 
				
			||||||
    @click.stop="handleCollect(item)"
 | 
					    @click.stop="handleCollect(item)"
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
  <IconifyIconOffline
 | 
					  <IconifyIconOffline
 | 
				
			||||||
    :icon="Close"
 | 
					    :icon="CloseIcon"
 | 
				
			||||||
    class="w-[18px] h-[18px] hover:text-[#d7d5d4] cursor-pointer"
 | 
					    class="w-[18px] h-[18px] hover:text-[#d7d5d4] cursor-pointer"
 | 
				
			||||||
    @click.stop="handleDelete(item)"
 | 
					    @click.stop="handleDelete(item)"
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
@ -13,7 +13,7 @@ import { ref, computed, shallowRef, watch } from "vue";
 | 
				
			|||||||
import { useDebounceFn, onKeyStroke } from "@vueuse/core";
 | 
					import { useDebounceFn, onKeyStroke } from "@vueuse/core";
 | 
				
			||||||
import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
				
			||||||
import { cloneDeep, isAllEmpty, storageLocal } from "@pureadmin/utils";
 | 
					import { cloneDeep, isAllEmpty, storageLocal } from "@pureadmin/utils";
 | 
				
			||||||
import Search from "@iconify-icons/ri/search-line";
 | 
					import SearchIcon from "@iconify-icons/ri/search-line";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Props {
 | 
					interface Props {
 | 
				
			||||||
  /** 弹窗显隐 */
 | 
					  /** 弹窗显隐 */
 | 
				
			||||||
@ -298,7 +298,7 @@ onKeyStroke("ArrowDown", handleDown);
 | 
				
			|||||||
    >
 | 
					    >
 | 
				
			||||||
      <template #prefix>
 | 
					      <template #prefix>
 | 
				
			||||||
        <IconifyIconOffline
 | 
					        <IconifyIconOffline
 | 
				
			||||||
          :icon="Search"
 | 
					          :icon="SearchIcon"
 | 
				
			||||||
          class="text-primary w-[24px] h-[24px]"
 | 
					          class="text-primary w-[24px] h-[24px]"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
@ -5,7 +5,7 @@ import { useResizeObserver } from "@pureadmin/utils";
 | 
				
			|||||||
import { useEpThemeStoreHook } from "@/store/modules/epTheme";
 | 
					import { useEpThemeStoreHook } from "@/store/modules/epTheme";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
import { ref, computed, getCurrentInstance, onMounted } from "vue";
 | 
					import { ref, computed, getCurrentInstance, onMounted } from "vue";
 | 
				
			||||||
import enterOutlined from "@/assets/svg/enter_outlined.svg?component";
 | 
					import EnterOutlined from "@/assets/svg/enter_outlined.svg?component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Emits {
 | 
					interface Emits {
 | 
				
			||||||
  (e: "update:value", val: string): void;
 | 
					  (e: "update:value", val: string): void;
 | 
				
			||||||
@ -84,7 +84,7 @@ defineExpose({ handleScroll });
 | 
				
			|||||||
      <span class="result-item-title">
 | 
					      <span class="result-item-title">
 | 
				
			||||||
        {{ transformI18n(item.meta?.title) }}
 | 
					        {{ transformI18n(item.meta?.title) }}
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
      <enterOutlined />
 | 
					      <EnterOutlined />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { SearchModal } from "./components";
 | 
					 | 
				
			||||||
import { useBoolean } from "../../hooks/useBoolean";
 | 
					import { useBoolean } from "../../hooks/useBoolean";
 | 
				
			||||||
 | 
					import SearchModal from "./components/SearchModal.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { bool: show, toggle } = useBoolean();
 | 
					const { bool: show, toggle } = useBoolean();
 | 
				
			||||||
function handleSearch() {
 | 
					function handleSearch() {
 | 
				
			||||||
@ -10,8 +10,8 @@ import {
 | 
				
			|||||||
  onBeforeMount
 | 
					  onBeforeMount
 | 
				
			||||||
} from "vue";
 | 
					} from "vue";
 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					import { useI18n } from "vue-i18n";
 | 
				
			||||||
import panel from "../panel/index.vue";
 | 
					 | 
				
			||||||
import { emitter } from "@/utils/mitt";
 | 
					import { emitter } from "@/utils/mitt";
 | 
				
			||||||
 | 
					import LayPanel from "../lay-panel/index.vue";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import { useAppStoreHook } from "@/store/modules/app";
 | 
					import { useAppStoreHook } from "@/store/modules/app";
 | 
				
			||||||
import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
 | 
					import { toggleTheme } from "@pureadmin/theme/dist/browser-utils";
 | 
				
			||||||
@ -23,9 +23,9 @@ import { useDark, useGlobal, debounce, isNumber } from "@pureadmin/utils";
 | 
				
			|||||||
import Check from "@iconify-icons/ep/check";
 | 
					import Check from "@iconify-icons/ep/check";
 | 
				
			||||||
import LeftArrow from "@iconify-icons/ri/arrow-left-s-line";
 | 
					import LeftArrow from "@iconify-icons/ri/arrow-left-s-line";
 | 
				
			||||||
import RightArrow from "@iconify-icons/ri/arrow-right-s-line";
 | 
					import RightArrow from "@iconify-icons/ri/arrow-right-s-line";
 | 
				
			||||||
import dayIcon from "@/assets/svg/day.svg?component";
 | 
					import DayIcon from "@/assets/svg/day.svg?component";
 | 
				
			||||||
import darkIcon from "@/assets/svg/dark.svg?component";
 | 
					import DarkIcon from "@/assets/svg/dark.svg?component";
 | 
				
			||||||
import systemIcon from "@/assets/svg/system.svg?component";
 | 
					import SystemIcon from "@/assets/svg/system.svg?component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { t } = useI18n();
 | 
					const { t } = useI18n();
 | 
				
			||||||
const { device } = useNav();
 | 
					const { device } = useNav();
 | 
				
			||||||
@ -199,21 +199,21 @@ const themeOptions = computed<Array<OptionsType>>(() => {
 | 
				
			|||||||
  return [
 | 
					  return [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: t("panel.pureOverallStyleLight"),
 | 
					      label: t("panel.pureOverallStyleLight"),
 | 
				
			||||||
      icon: dayIcon,
 | 
					      icon: DayIcon,
 | 
				
			||||||
      theme: "light",
 | 
					      theme: "light",
 | 
				
			||||||
      tip: t("panel.pureOverallStyleLightTip"),
 | 
					      tip: t("panel.pureOverallStyleLightTip"),
 | 
				
			||||||
      iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
 | 
					      iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: t("panel.pureOverallStyleDark"),
 | 
					      label: t("panel.pureOverallStyleDark"),
 | 
				
			||||||
      icon: darkIcon,
 | 
					      icon: DarkIcon,
 | 
				
			||||||
      theme: "dark",
 | 
					      theme: "dark",
 | 
				
			||||||
      tip: t("panel.pureOverallStyleDarkTip"),
 | 
					      tip: t("panel.pureOverallStyleDarkTip"),
 | 
				
			||||||
      iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
 | 
					      iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      label: t("panel.pureOverallStyleSystem"),
 | 
					      label: t("panel.pureOverallStyleSystem"),
 | 
				
			||||||
      icon: systemIcon,
 | 
					      icon: SystemIcon,
 | 
				
			||||||
      theme: "system",
 | 
					      theme: "system",
 | 
				
			||||||
      tip: t("panel.pureOverallStyleSystemTip"),
 | 
					      tip: t("panel.pureOverallStyleSystemTip"),
 | 
				
			||||||
      iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
 | 
					      iconAttrs: { fill: isDark.value ? "#fff" : "#000" }
 | 
				
			||||||
@ -313,7 +313,7 @@ onUnmounted(() => removeMatchMedia);
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <panel>
 | 
					  <LayPanel>
 | 
				
			||||||
    <div class="p-5">
 | 
					    <div class="p-5">
 | 
				
			||||||
      <p :class="pClass">{{ t("panel.pureOverallStyle") }}</p>
 | 
					      <p :class="pClass">{{ t("panel.pureOverallStyle") }}</p>
 | 
				
			||||||
      <Segmented
 | 
					      <Segmented
 | 
				
			||||||
@ -517,7 +517,7 @@ onUnmounted(() => removeMatchMedia);
 | 
				
			|||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
      </ul>
 | 
					      </ul>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </panel>
 | 
					  </LayPanel>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" scoped>
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
@ -1,14 +1,15 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import Search from "../search/index.vue";
 | 
					 | 
				
			||||||
import Notice from "../notice/index.vue";
 | 
					 | 
				
			||||||
import FullScreen from "./fullScreen.vue";
 | 
					 | 
				
			||||||
import SidebarItem from "./sidebarItem.vue";
 | 
					 | 
				
			||||||
import { isAllEmpty } from "@pureadmin/utils";
 | 
					import { isAllEmpty } from "@pureadmin/utils";
 | 
				
			||||||
import { ref, nextTick, computed } from "vue";
 | 
					import { ref, nextTick, computed } from "vue";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
 | 
					import LaySearch from "../lay-search/index.vue";
 | 
				
			||||||
 | 
					import LayNotice from "../lay-notice/index.vue";
 | 
				
			||||||
import { useTranslationLang } from "../../hooks/useTranslationLang";
 | 
					import { useTranslationLang } from "../../hooks/useTranslationLang";
 | 
				
			||||||
import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
				
			||||||
import globalization from "@/assets/svg/globalization.svg?component";
 | 
					import LaySidebarItem from "../lay-sidebar/components/SidebarItem.vue";
 | 
				
			||||||
 | 
					import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import GlobalizationIcon from "@/assets/svg/globalization.svg?component";
 | 
				
			||||||
import AccountSettingsIcon from "@iconify-icons/ri/user-settings-line";
 | 
					import AccountSettingsIcon from "@iconify-icons/ri/user-settings-line";
 | 
				
			||||||
import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
 | 
					import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
 | 
				
			||||||
import Setting from "@iconify-icons/ri/settings-3-line";
 | 
					import Setting from "@iconify-icons/ri/settings-3-line";
 | 
				
			||||||
@ -21,11 +22,11 @@ const { t, route, locale, translationCh, translationEn } =
 | 
				
			|||||||
const {
 | 
					const {
 | 
				
			||||||
  title,
 | 
					  title,
 | 
				
			||||||
  logout,
 | 
					  logout,
 | 
				
			||||||
  backTopMenu,
 | 
					 | 
				
			||||||
  onPanel,
 | 
					  onPanel,
 | 
				
			||||||
  getLogo,
 | 
					  getLogo,
 | 
				
			||||||
  username,
 | 
					  username,
 | 
				
			||||||
  userAvatar,
 | 
					  userAvatar,
 | 
				
			||||||
 | 
					  backTopMenu,
 | 
				
			||||||
  avatarsStyle,
 | 
					  avatarsStyle,
 | 
				
			||||||
  toAccountSettings,
 | 
					  toAccountSettings,
 | 
				
			||||||
  getDropdownItemStyle,
 | 
					  getDropdownItemStyle,
 | 
				
			||||||
@ -58,7 +59,7 @@ nextTick(() => {
 | 
				
			|||||||
      class="horizontal-header-menu"
 | 
					      class="horizontal-header-menu"
 | 
				
			||||||
      :default-active="defaultActive"
 | 
					      :default-active="defaultActive"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <sidebar-item
 | 
					      <LaySidebarItem
 | 
				
			||||||
        v-for="route in usePermissionStoreHook().wholeMenus"
 | 
					        v-for="route in usePermissionStoreHook().wholeMenus"
 | 
				
			||||||
        :key="route.path"
 | 
					        :key="route.path"
 | 
				
			||||||
        :item="route"
 | 
					        :item="route"
 | 
				
			||||||
@ -67,10 +68,10 @@ nextTick(() => {
 | 
				
			|||||||
    </el-menu>
 | 
					    </el-menu>
 | 
				
			||||||
    <div class="horizontal-header-right">
 | 
					    <div class="horizontal-header-right">
 | 
				
			||||||
      <!-- 菜单搜索 -->
 | 
					      <!-- 菜单搜索 -->
 | 
				
			||||||
      <Search id="header-search" />
 | 
					      <LaySearch id="header-search" />
 | 
				
			||||||
      <!-- 国际化 -->
 | 
					      <!-- 国际化 -->
 | 
				
			||||||
      <el-dropdown id="header-translation" trigger="click">
 | 
					      <el-dropdown id="header-translation" trigger="click">
 | 
				
			||||||
        <globalization
 | 
					        <GlobalizationIcon
 | 
				
			||||||
          class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
 | 
					          class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <template #dropdown>
 | 
					        <template #dropdown>
 | 
				
			||||||
@ -99,9 +100,9 @@ nextTick(() => {
 | 
				
			|||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </el-dropdown>
 | 
					      </el-dropdown>
 | 
				
			||||||
      <!-- 全屏 -->
 | 
					      <!-- 全屏 -->
 | 
				
			||||||
      <FullScreen id="full-screen" />
 | 
					      <LaySidebarFullScreen id="full-screen" />
 | 
				
			||||||
      <!-- 消息通知 -->
 | 
					      <!-- 消息通知 -->
 | 
				
			||||||
      <Notice id="header-notice" />
 | 
					      <LayNotice id="header-notice" />
 | 
				
			||||||
      <!-- 退出登录 -->
 | 
					      <!-- 退出登录 -->
 | 
				
			||||||
      <el-dropdown trigger="click">
 | 
					      <el-dropdown trigger="click">
 | 
				
			||||||
        <span class="el-dropdown-link navbar-bg-hover">
 | 
					        <span class="el-dropdown-link navbar-bg-hover">
 | 
				
			||||||
@ -1,17 +1,18 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import extraIcon from "./extraIcon.vue";
 | 
					 | 
				
			||||||
import Search from "../search/index.vue";
 | 
					 | 
				
			||||||
import Notice from "../notice/index.vue";
 | 
					 | 
				
			||||||
import FullScreen from "./fullScreen.vue";
 | 
					 | 
				
			||||||
import { isAllEmpty } from "@pureadmin/utils";
 | 
					import { isAllEmpty } from "@pureadmin/utils";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
 | 
					import LaySearch from "../lay-search/index.vue";
 | 
				
			||||||
 | 
					import LayNotice from "../lay-notice/index.vue";
 | 
				
			||||||
import { ref, toRaw, watch, onMounted, nextTick } from "vue";
 | 
					import { ref, toRaw, watch, onMounted, nextTick } from "vue";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
import { getParentPaths, findRouteByPath } from "@/router/utils";
 | 
					import { getParentPaths, findRouteByPath } from "@/router/utils";
 | 
				
			||||||
import { useTranslationLang } from "../../hooks/useTranslationLang";
 | 
					import { useTranslationLang } from "../../hooks/useTranslationLang";
 | 
				
			||||||
import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
				
			||||||
import globalization from "@/assets/svg/globalization.svg?component";
 | 
					import LaySidebarExtraIcon from "../lay-sidebar/components/SidebarExtraIcon.vue";
 | 
				
			||||||
 | 
					import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import GlobalizationIcon from "@/assets/svg/globalization.svg?component";
 | 
				
			||||||
import AccountSettingsIcon from "@iconify-icons/ri/user-settings-line";
 | 
					import AccountSettingsIcon from "@iconify-icons/ri/user-settings-line";
 | 
				
			||||||
import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
 | 
					import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
 | 
				
			||||||
import Setting from "@iconify-icons/ri/settings-3-line";
 | 
					import Setting from "@iconify-icons/ri/settings-3-line";
 | 
				
			||||||
@ -93,17 +94,17 @@ watch(
 | 
				
			|||||||
            <span class="select-none">
 | 
					            <span class="select-none">
 | 
				
			||||||
              {{ transformI18n(route.meta.title) }}
 | 
					              {{ transformI18n(route.meta.title) }}
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            <extraIcon :extraIcon="route.meta.extraIcon" />
 | 
					            <LaySidebarExtraIcon :extraIcon="route.meta.extraIcon" />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </el-menu-item>
 | 
					      </el-menu-item>
 | 
				
			||||||
    </el-menu>
 | 
					    </el-menu>
 | 
				
			||||||
    <div class="horizontal-header-right">
 | 
					    <div class="horizontal-header-right">
 | 
				
			||||||
      <!-- 菜单搜索 -->
 | 
					      <!-- 菜单搜索 -->
 | 
				
			||||||
      <Search id="header-search" />
 | 
					      <LaySearch id="header-search" />
 | 
				
			||||||
      <!-- 国际化 -->
 | 
					      <!-- 国际化 -->
 | 
				
			||||||
      <el-dropdown id="header-translation" trigger="click">
 | 
					      <el-dropdown id="header-translation" trigger="click">
 | 
				
			||||||
        <globalization
 | 
					        <GlobalizationIcon
 | 
				
			||||||
          class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
 | 
					          class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <template #dropdown>
 | 
					        <template #dropdown>
 | 
				
			||||||
@ -132,9 +133,9 @@ watch(
 | 
				
			|||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </el-dropdown>
 | 
					      </el-dropdown>
 | 
				
			||||||
      <!-- 全屏 -->
 | 
					      <!-- 全屏 -->
 | 
				
			||||||
      <FullScreen id="full-screen" />
 | 
					      <LaySidebarFullScreen id="full-screen" />
 | 
				
			||||||
      <!-- 消息通知 -->
 | 
					      <!-- 消息通知 -->
 | 
				
			||||||
      <Notice id="header-notice" />
 | 
					      <LayNotice id="header-notice" />
 | 
				
			||||||
      <!-- 退出登录 -->
 | 
					      <!-- 退出登录 -->
 | 
				
			||||||
      <el-dropdown trigger="click">
 | 
					      <el-dropdown trigger="click">
 | 
				
			||||||
        <span class="el-dropdown-link navbar-bg-hover select-none">
 | 
					        <span class="el-dropdown-link navbar-bg-hover select-none">
 | 
				
			||||||
@ -1,16 +1,16 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import Logo from "./logo.vue";
 | 
					 | 
				
			||||||
import { useRoute } from "vue-router";
 | 
					import { useRoute } from "vue-router";
 | 
				
			||||||
import { emitter } from "@/utils/mitt";
 | 
					import { emitter } from "@/utils/mitt";
 | 
				
			||||||
import SidebarItem from "./sidebarItem.vue";
 | 
					 | 
				
			||||||
import LeftCollapse from "./leftCollapse.vue";
 | 
					 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import CenterCollapse from "./centerCollapse.vue";
 | 
					 | 
				
			||||||
import { responsiveStorageNameSpace } from "@/config";
 | 
					import { responsiveStorageNameSpace } from "@/config";
 | 
				
			||||||
import { storageLocal, isAllEmpty } from "@pureadmin/utils";
 | 
					import { storageLocal, isAllEmpty } from "@pureadmin/utils";
 | 
				
			||||||
import { findRouteByPath, getParentPaths } from "@/router/utils";
 | 
					import { findRouteByPath, getParentPaths } from "@/router/utils";
 | 
				
			||||||
import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
				
			||||||
import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
 | 
					import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
 | 
				
			||||||
 | 
					import LaySidebarLogo from "../lay-sidebar/components/SidebarLogo.vue";
 | 
				
			||||||
 | 
					import LaySidebarItem from "../lay-sidebar/components/SidebarItem.vue";
 | 
				
			||||||
 | 
					import LaySidebarLeftCollapse from "../lay-sidebar/components/SidebarLeftCollapse.vue";
 | 
				
			||||||
 | 
					import LaySidebarCenterCollapse from "../lay-sidebar/components/SidebarCenterCollapse.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute();
 | 
					const route = useRoute();
 | 
				
			||||||
const isShow = ref(false);
 | 
					const isShow = ref(false);
 | 
				
			||||||
@ -93,7 +93,7 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
    @mouseenter.prevent="isShow = true"
 | 
					    @mouseenter.prevent="isShow = true"
 | 
				
			||||||
    @mouseleave.prevent="isShow = false"
 | 
					    @mouseleave.prevent="isShow = false"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <Logo v-if="showLogo" :collapse="isCollapse" />
 | 
					    <LaySidebarLogo v-if="showLogo" :collapse="isCollapse" />
 | 
				
			||||||
    <el-scrollbar
 | 
					    <el-scrollbar
 | 
				
			||||||
      wrap-class="scrollbar-wrapper"
 | 
					      wrap-class="scrollbar-wrapper"
 | 
				
			||||||
      :class="[device === 'mobile' ? 'mobile' : 'pc']"
 | 
					      :class="[device === 'mobile' ? 'mobile' : 'pc']"
 | 
				
			||||||
@ -109,7 +109,7 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
        :popper-effect="tooltipEffect"
 | 
					        :popper-effect="tooltipEffect"
 | 
				
			||||||
        :default-active="defaultActive"
 | 
					        :default-active="defaultActive"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <sidebar-item
 | 
					        <LaySidebarItem
 | 
				
			||||||
          v-for="routes in menuData"
 | 
					          v-for="routes in menuData"
 | 
				
			||||||
          :key="routes.path"
 | 
					          :key="routes.path"
 | 
				
			||||||
          :item="routes"
 | 
					          :item="routes"
 | 
				
			||||||
@ -118,12 +118,12 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
      </el-menu>
 | 
					      </el-menu>
 | 
				
			||||||
    </el-scrollbar>
 | 
					    </el-scrollbar>
 | 
				
			||||||
    <CenterCollapse
 | 
					    <LaySidebarCenterCollapse
 | 
				
			||||||
      v-if="device !== 'mobile' && (isShow || isCollapse)"
 | 
					      v-if="device !== 'mobile' && (isShow || isCollapse)"
 | 
				
			||||||
      :is-active="pureApp.sidebar.opened"
 | 
					      :is-active="pureApp.sidebar.opened"
 | 
				
			||||||
      @toggleClick="toggleSideBar"
 | 
					      @toggleClick="toggleSideBar"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <LeftCollapse
 | 
					    <LaySidebarLeftCollapse
 | 
				
			||||||
      v-if="device !== 'mobile'"
 | 
					      v-if="device !== 'mobile'"
 | 
				
			||||||
      :is-active="pureApp.sidebar.opened"
 | 
					      :is-active="pureApp.sidebar.opened"
 | 
				
			||||||
      @toggleClick="toggleSideBar"
 | 
					      @toggleClick="toggleSideBar"
 | 
				
			||||||
@ -36,7 +36,7 @@ const toggleClick = () => {
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div
 | 
					  <div
 | 
				
			||||||
    v-tippy="{
 | 
					    v-tippy="{
 | 
				
			||||||
      content: props.isActive
 | 
					      content: isActive
 | 
				
			||||||
        ? t('buttons.pureClickCollapse')
 | 
					        ? t('buttons.pureClickCollapse')
 | 
				
			||||||
        : t('buttons.pureClickExpand'),
 | 
					        : t('buttons.pureClickExpand'),
 | 
				
			||||||
      theme: tooltipEffect,
 | 
					      theme: tooltipEffect,
 | 
				
			||||||
@ -49,7 +49,7 @@ const toggleClick = () => {
 | 
				
			|||||||
    <IconifyIconOffline
 | 
					    <IconifyIconOffline
 | 
				
			||||||
      :icon="ArrowLeft"
 | 
					      :icon="ArrowLeft"
 | 
				
			||||||
      :class="[iconClass, themeColor === 'light' ? '' : 'text-primary']"
 | 
					      :class="[iconClass, themeColor === 'light' ? '' : 'text-primary']"
 | 
				
			||||||
      :style="{ transform: props.isActive ? 'none' : 'rotateY(180deg)' }"
 | 
					      :style="{ transform: isActive ? 'none' : 'rotateY(180deg)' }"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
@ -11,9 +11,9 @@ const props = defineProps({
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div v-if="props.extraIcon" class="flex justify-center items-center">
 | 
					  <div v-if="extraIcon" class="flex justify-center items-center">
 | 
				
			||||||
    <component
 | 
					    <component
 | 
				
			||||||
      :is="useRenderIcon(toRaw(props.extraIcon))"
 | 
					      :is="useRenderIcon(toRaw(extraIcon))"
 | 
				
			||||||
      class="w-[30px] h-[30px]"
 | 
					      class="w-[30px] h-[30px]"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@ -1,12 +1,12 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import path from "path";
 | 
					import path from "path";
 | 
				
			||||||
import { getConfig } from "@/config";
 | 
					import { getConfig } from "@/config";
 | 
				
			||||||
import LinkItem from "./linkItem.vue";
 | 
					import { menuType } from "@/layout/types";
 | 
				
			||||||
import { menuType } from "../../types";
 | 
					 | 
				
			||||||
import extraIcon from "./extraIcon.vue";
 | 
					 | 
				
			||||||
import { ReText } from "@/components/ReText";
 | 
					import { ReText } from "@/components/ReText";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
 | 
					import SidebarLinkItem from "./SidebarLinkItem.vue";
 | 
				
			||||||
 | 
					import SidebarExtraIcon from "./SidebarExtraIcon.vue";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  type PropType,
 | 
					  type PropType,
 | 
				
			||||||
@ -106,9 +106,9 @@ function resolvePath(routePath) {
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <link-item
 | 
					  <SidebarLinkItem
 | 
				
			||||||
    v-if="
 | 
					    v-if="
 | 
				
			||||||
      hasOneShowingChild(props.item.children, props.item) &&
 | 
					      hasOneShowingChild(item.children, item) &&
 | 
				
			||||||
      (!onlyOneChild.children || onlyOneChild.noShowingChildren)
 | 
					      (!onlyOneChild.children || onlyOneChild.noShowingChildren)
 | 
				
			||||||
    "
 | 
					    "
 | 
				
			||||||
    :to="item"
 | 
					    :to="item"
 | 
				
			||||||
@ -120,7 +120,7 @@ function resolvePath(routePath) {
 | 
				
			|||||||
      v-bind="attrs"
 | 
					      v-bind="attrs"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        v-if="toRaw(props.item.meta.icon)"
 | 
					        v-if="toRaw(item.meta.icon)"
 | 
				
			||||||
        class="sub-menu-icon"
 | 
					        class="sub-menu-icon"
 | 
				
			||||||
        :style="getSubMenuIconStyle"
 | 
					        :style="getSubMenuIconStyle"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
@ -128,21 +128,21 @@ function resolvePath(routePath) {
 | 
				
			|||||||
          :is="
 | 
					          :is="
 | 
				
			||||||
            useRenderIcon(
 | 
					            useRenderIcon(
 | 
				
			||||||
              toRaw(onlyOneChild.meta.icon) ||
 | 
					              toRaw(onlyOneChild.meta.icon) ||
 | 
				
			||||||
                (props.item.meta && toRaw(props.item.meta.icon))
 | 
					                (item.meta && toRaw(item.meta.icon))
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          "
 | 
					          "
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <el-text
 | 
					      <el-text
 | 
				
			||||||
        v-if="
 | 
					        v-if="
 | 
				
			||||||
          (!props.item?.meta.icon &&
 | 
					          (!item?.meta.icon &&
 | 
				
			||||||
            isCollapse &&
 | 
					            isCollapse &&
 | 
				
			||||||
            layout === 'vertical' &&
 | 
					            layout === 'vertical' &&
 | 
				
			||||||
            props.item?.pathList?.length === 1) ||
 | 
					            item?.pathList?.length === 1) ||
 | 
				
			||||||
          (!onlyOneChild.meta.icon &&
 | 
					          (!onlyOneChild.meta.icon &&
 | 
				
			||||||
            isCollapse &&
 | 
					            isCollapse &&
 | 
				
			||||||
            layout === 'mix' &&
 | 
					            layout === 'mix' &&
 | 
				
			||||||
            props.item?.pathList?.length === 2)
 | 
					            item?.pathList?.length === 2)
 | 
				
			||||||
        "
 | 
					        "
 | 
				
			||||||
        truncated
 | 
					        truncated
 | 
				
			||||||
        class="!w-full !px-4 !text-inherit"
 | 
					        class="!w-full !px-4 !text-inherit"
 | 
				
			||||||
@ -161,37 +161,35 @@ function resolvePath(routePath) {
 | 
				
			|||||||
          >
 | 
					          >
 | 
				
			||||||
            {{ transformI18n(onlyOneChild.meta.title) }}
 | 
					            {{ transformI18n(onlyOneChild.meta.title) }}
 | 
				
			||||||
          </ReText>
 | 
					          </ReText>
 | 
				
			||||||
          <extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
 | 
					          <SidebarExtraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </el-menu-item>
 | 
					    </el-menu-item>
 | 
				
			||||||
  </link-item>
 | 
					  </SidebarLinkItem>
 | 
				
			||||||
  <el-sub-menu
 | 
					  <el-sub-menu
 | 
				
			||||||
    v-else
 | 
					    v-else
 | 
				
			||||||
    ref="subMenu"
 | 
					    ref="subMenu"
 | 
				
			||||||
    teleported
 | 
					    teleported
 | 
				
			||||||
    :index="resolvePath(props.item.path)"
 | 
					    :index="resolvePath(item.path)"
 | 
				
			||||||
    v-bind="expandCloseIcon"
 | 
					    v-bind="expandCloseIcon"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template #title>
 | 
					    <template #title>
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        v-if="toRaw(props.item.meta.icon)"
 | 
					        v-if="toRaw(item.meta.icon)"
 | 
				
			||||||
        :style="getSubMenuIconStyle"
 | 
					        :style="getSubMenuIconStyle"
 | 
				
			||||||
        class="sub-menu-icon"
 | 
					        class="sub-menu-icon"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <component
 | 
					        <component :is="useRenderIcon(item.meta && toRaw(item.meta.icon))" />
 | 
				
			||||||
          :is="useRenderIcon(props.item.meta && toRaw(props.item.meta.icon))"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <ReText
 | 
					      <ReText
 | 
				
			||||||
        v-if="
 | 
					        v-if="
 | 
				
			||||||
          layout === 'mix' && toRaw(props.item.meta.icon)
 | 
					          layout === 'mix' && toRaw(item.meta.icon)
 | 
				
			||||||
            ? !isCollapse || props.item?.pathList?.length !== 2
 | 
					            ? !isCollapse || item?.pathList?.length !== 2
 | 
				
			||||||
            : !(
 | 
					            : !(
 | 
				
			||||||
                layout === 'vertical' &&
 | 
					                layout === 'vertical' &&
 | 
				
			||||||
                isCollapse &&
 | 
					                isCollapse &&
 | 
				
			||||||
                toRaw(props.item.meta.icon) &&
 | 
					                toRaw(item.meta.icon) &&
 | 
				
			||||||
                props.item.parentId === null
 | 
					                item.parentId === null
 | 
				
			||||||
              )
 | 
					              )
 | 
				
			||||||
        "
 | 
					        "
 | 
				
			||||||
        :tippyProps="{
 | 
					        :tippyProps="{
 | 
				
			||||||
@ -204,17 +202,17 @@ function resolvePath(routePath) {
 | 
				
			|||||||
          '!px-4':
 | 
					          '!px-4':
 | 
				
			||||||
            layout !== 'horizontal' &&
 | 
					            layout !== 'horizontal' &&
 | 
				
			||||||
            isCollapse &&
 | 
					            isCollapse &&
 | 
				
			||||||
            !toRaw(props.item.meta.icon) &&
 | 
					            !toRaw(item.meta.icon) &&
 | 
				
			||||||
            props.item.parentId === null
 | 
					            item.parentId === null
 | 
				
			||||||
        }"
 | 
					        }"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {{ transformI18n(props.item.meta.title) }}
 | 
					        {{ transformI18n(item.meta.title) }}
 | 
				
			||||||
      </ReText>
 | 
					      </ReText>
 | 
				
			||||||
      <extraIcon v-if="!isCollapse" :extraIcon="props.item.meta.extraIcon" />
 | 
					      <SidebarExtraIcon v-if="!isCollapse" :extraIcon="item.meta.extraIcon" />
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <sidebar-item
 | 
					    <sidebar-item
 | 
				
			||||||
      v-for="child in props.item.children"
 | 
					      v-for="child in item.children"
 | 
				
			||||||
      :key="child.path"
 | 
					      :key="child.path"
 | 
				
			||||||
      :is-nest="true"
 | 
					      :is-nest="true"
 | 
				
			||||||
      :item="child"
 | 
					      :item="child"
 | 
				
			||||||
@ -46,7 +46,7 @@ const toggleClick = () => {
 | 
				
			|||||||
  <div class="left-collapse">
 | 
					  <div class="left-collapse">
 | 
				
			||||||
    <IconifyIconOffline
 | 
					    <IconifyIconOffline
 | 
				
			||||||
      v-tippy="{
 | 
					      v-tippy="{
 | 
				
			||||||
        content: props.isActive
 | 
					        content: isActive
 | 
				
			||||||
          ? t('buttons.pureClickCollapse')
 | 
					          ? t('buttons.pureClickCollapse')
 | 
				
			||||||
          : t('buttons.pureClickExpand'),
 | 
					          : t('buttons.pureClickExpand'),
 | 
				
			||||||
        theme: tooltipEffect,
 | 
					        theme: tooltipEffect,
 | 
				
			||||||
@ -55,7 +55,7 @@ const toggleClick = () => {
 | 
				
			|||||||
      }"
 | 
					      }"
 | 
				
			||||||
      :icon="MenuFold"
 | 
					      :icon="MenuFold"
 | 
				
			||||||
      :class="[iconClass, themeColor === 'light' ? '' : 'text-primary']"
 | 
					      :class="[iconClass, themeColor === 'light' ? '' : 'text-primary']"
 | 
				
			||||||
      :style="{ transform: props.isActive ? 'none' : 'rotateY(180deg)' }"
 | 
					      :style="{ transform: isActive ? 'none' : 'rotateY(180deg)' }"
 | 
				
			||||||
      @click="toggleClick"
 | 
					      @click="toggleClick"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@ -3,10 +3,6 @@ import { computed } from "vue";
 | 
				
			|||||||
import { isUrl } from "@pureadmin/utils";
 | 
					import { isUrl } from "@pureadmin/utils";
 | 
				
			||||||
import { menuType } from "@/layout/types";
 | 
					import { menuType } from "@/layout/types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					 | 
				
			||||||
  name: "LinkItem"
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const props = defineProps<{
 | 
					const props = defineProps<{
 | 
				
			||||||
  to: menuType;
 | 
					  to: menuType;
 | 
				
			||||||
}>();
 | 
					}>();
 | 
				
			||||||
@ -10,11 +10,11 @@ const { title, getLogo } = useNav();
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="sidebar-logo-container" :class="{ collapses: props.collapse }">
 | 
					  <div class="sidebar-logo-container" :class="{ collapses: collapse }">
 | 
				
			||||||
    <transition name="sidebarLogoFade">
 | 
					    <transition name="sidebarLogoFade">
 | 
				
			||||||
      <router-link
 | 
					      <router-link
 | 
				
			||||||
        v-if="props.collapse"
 | 
					        v-if="collapse"
 | 
				
			||||||
        key="props.collapse"
 | 
					        key="collapse"
 | 
				
			||||||
        :title="title"
 | 
					        :title="title"
 | 
				
			||||||
        class="sidebar-logo-link"
 | 
					        class="sidebar-logo-link"
 | 
				
			||||||
        :to="getTopMenu()?.path ?? '/'"
 | 
					        :to="getTopMenu()?.path ?? '/'"
 | 
				
			||||||
@ -26,14 +26,12 @@ const toggleClick = () => {
 | 
				
			|||||||
  <div
 | 
					  <div
 | 
				
			||||||
    class="px-3 mr-1 navbar-bg-hover"
 | 
					    class="px-3 mr-1 navbar-bg-hover"
 | 
				
			||||||
    :title="
 | 
					    :title="
 | 
				
			||||||
      props.isActive
 | 
					      isActive ? t('buttons.pureClickCollapse') : t('buttons.pureClickExpand')
 | 
				
			||||||
        ? t('buttons.pureClickCollapse')
 | 
					 | 
				
			||||||
        : t('buttons.pureClickExpand')
 | 
					 | 
				
			||||||
    "
 | 
					    "
 | 
				
			||||||
    @click="toggleClick"
 | 
					    @click="toggleClick"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <IconifyIconOffline
 | 
					    <IconifyIconOffline
 | 
				
			||||||
      :icon="props.isActive ? MenuFold : MenuUnfold"
 | 
					      :icon="isActive ? MenuFold : MenuUnfold"
 | 
				
			||||||
      class="inline-block align-middle hover:text-primary dark:hover:!text-white"
 | 
					      class="inline-block align-middle hover:text-primary dark:hover:!text-white"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@ -1,146 +0,0 @@
 | 
				
			|||||||
export interface ListItem {
 | 
					 | 
				
			||||||
  avatar: string;
 | 
					 | 
				
			||||||
  title: string;
 | 
					 | 
				
			||||||
  datetime: string;
 | 
					 | 
				
			||||||
  type: string;
 | 
					 | 
				
			||||||
  description: string;
 | 
					 | 
				
			||||||
  status?: "primary" | "success" | "warning" | "info" | "danger";
 | 
					 | 
				
			||||||
  extra?: string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface TabItem {
 | 
					 | 
				
			||||||
  key: string;
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  list: ListItem[];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const noticesData: TabItem[] = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: "1",
 | 
					 | 
				
			||||||
    name: "通知",
 | 
					 | 
				
			||||||
    list: [
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png",
 | 
					 | 
				
			||||||
        title: "你收到了 12 份新周报",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
        type: "1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png",
 | 
					 | 
				
			||||||
        title: "你推荐的 前端高手 已通过第三轮面试",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
        type: "1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png",
 | 
					 | 
				
			||||||
        title: "这种模板可以区分多种通知类型",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
        type: "1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png",
 | 
					 | 
				
			||||||
        title:
 | 
					 | 
				
			||||||
          "展示标题内容超过一行后的处理方式,如果内容超过1行将自动截断并支持tooltip显示完整标题。",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
        type: "1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png",
 | 
					 | 
				
			||||||
        title: "左侧图标用于区分不同的类型",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
        type: "1"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png",
 | 
					 | 
				
			||||||
        title: "左侧图标用于区分不同的类型",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        description: "",
 | 
					 | 
				
			||||||
        type: "1"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: "2",
 | 
					 | 
				
			||||||
    name: "消息",
 | 
					 | 
				
			||||||
    list: [
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg",
 | 
					 | 
				
			||||||
        title: "李白 评论了你",
 | 
					 | 
				
			||||||
        description: "长风破浪会有时,直挂云帆济沧海",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        type: "2"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg",
 | 
					 | 
				
			||||||
        title: "李白 回复了你",
 | 
					 | 
				
			||||||
        description: "行路难,行路难,多歧路,今安在。",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        type: "2"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar:
 | 
					 | 
				
			||||||
          "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg",
 | 
					 | 
				
			||||||
        title: "标题",
 | 
					 | 
				
			||||||
        description:
 | 
					 | 
				
			||||||
          "请将鼠标移动到此处,以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2,超过2行的描述内容将被省略并且可以通过tooltip查看完整内容",
 | 
					 | 
				
			||||||
        datetime: "一年前",
 | 
					 | 
				
			||||||
        type: "2"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    key: "3",
 | 
					 | 
				
			||||||
    name: "待办",
 | 
					 | 
				
			||||||
    list: [
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar: "",
 | 
					 | 
				
			||||||
        title: "任务名称",
 | 
					 | 
				
			||||||
        description: "任务需要在 2022-11-16 20:00 前启动",
 | 
					 | 
				
			||||||
        datetime: "",
 | 
					 | 
				
			||||||
        extra: "未开始",
 | 
					 | 
				
			||||||
        status: "info",
 | 
					 | 
				
			||||||
        type: "3"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar: "",
 | 
					 | 
				
			||||||
        title: "第三方紧急代码变更",
 | 
					 | 
				
			||||||
        description:
 | 
					 | 
				
			||||||
          "一拳提交于 2022-11-16,需在 2022-11-18 前完成代码变更任务",
 | 
					 | 
				
			||||||
        datetime: "",
 | 
					 | 
				
			||||||
        extra: "马上到期",
 | 
					 | 
				
			||||||
        status: "danger",
 | 
					 | 
				
			||||||
        type: "3"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar: "",
 | 
					 | 
				
			||||||
        title: "信息安全考试",
 | 
					 | 
				
			||||||
        description: "指派小仙于 2022-12-12 前完成更新并发布",
 | 
					 | 
				
			||||||
        datetime: "",
 | 
					 | 
				
			||||||
        extra: "已耗时 8 天",
 | 
					 | 
				
			||||||
        status: "warning",
 | 
					 | 
				
			||||||
        type: "3"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        avatar: "",
 | 
					 | 
				
			||||||
        title: "vue-pure-admin 版本发布",
 | 
					 | 
				
			||||||
        description: "vue-pure-admin 版本发布",
 | 
					 | 
				
			||||||
        datetime: "",
 | 
					 | 
				
			||||||
        extra: "进行中",
 | 
					 | 
				
			||||||
        type: "3"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					 | 
				
			||||||
import { PropType } from "vue";
 | 
					 | 
				
			||||||
import { ListItem } from "./data";
 | 
					 | 
				
			||||||
import { useI18n } from "vue-i18n";
 | 
					 | 
				
			||||||
import NoticeItem from "./noticeItem.vue";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const props = defineProps({
 | 
					 | 
				
			||||||
  list: {
 | 
					 | 
				
			||||||
    type: Array as PropType<Array<ListItem>>,
 | 
					 | 
				
			||||||
    default: () => []
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { t } = useI18n();
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<template>
 | 
					 | 
				
			||||||
  <div v-if="props.list.length">
 | 
					 | 
				
			||||||
    <NoticeItem
 | 
					 | 
				
			||||||
      v-for="(item, index) in props.list"
 | 
					 | 
				
			||||||
      :key="index"
 | 
					 | 
				
			||||||
      :noticeItem="item"
 | 
					 | 
				
			||||||
    />
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
  <el-empty v-else :description="t('status.pureNoMessage')" />
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
@ -1,3 +0,0 @@
 | 
				
			|||||||
import SearchModal from "./SearchModal.vue";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export { SearchModal };
 | 
					 | 
				
			||||||
@ -4,7 +4,7 @@ import { useRoute } from "vue-router";
 | 
				
			|||||||
import { ref, unref, watch, onMounted, nextTick } from "vue";
 | 
					import { ref, unref, watch, onMounted, nextTick } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: "FrameView"
 | 
					  name: "LayFrame"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps<{
 | 
					const props = defineProps<{
 | 
				
			||||||
@ -24,13 +24,13 @@ import {
 | 
				
			|||||||
  useResizeObserver
 | 
					  useResizeObserver
 | 
				
			||||||
} from "@pureadmin/utils";
 | 
					} from "@pureadmin/utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import navbar from "./components/navbar.vue";
 | 
					import LayTag from "./components/lay-tag/index.vue";
 | 
				
			||||||
import tag from "./components/tag/index.vue";
 | 
					import LayNavbar from "./components/lay-navbar/index.vue";
 | 
				
			||||||
import appMain from "./components/appMain.vue";
 | 
					import LayContent from "./components/lay-content/index.vue";
 | 
				
			||||||
import setting from "./components/setting/index.vue";
 | 
					import LaySetting from "./components/lay-setting/index.vue";
 | 
				
			||||||
import Vertical from "./components/sidebar/vertical.vue";
 | 
					import NavVertical from "./components/lay-sidebar/NavVertical.vue";
 | 
				
			||||||
import Horizontal from "./components/sidebar/horizontal.vue";
 | 
					import NavHorizontal from "./components/lay-sidebar/NavHorizontal.vue";
 | 
				
			||||||
import backTop from "@/assets/svg/back_top.svg?component";
 | 
					import BackTopIcon from "@/assets/svg/back_top.svg?component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { t } = useI18n();
 | 
					const { t } = useI18n();
 | 
				
			||||||
const appWrapperRef = ref();
 | 
					const appWrapperRef = ref();
 | 
				
			||||||
@ -126,7 +126,8 @@ onBeforeMount(() => {
 | 
				
			|||||||
  useDataThemeChange().dataThemeChange($storage.layout?.overallStyle);
 | 
					  useDataThemeChange().dataThemeChange($storage.layout?.overallStyle);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const layoutHeader = defineComponent({
 | 
					const LayHeader = defineComponent({
 | 
				
			||||||
 | 
					  name: "LayHeader",
 | 
				
			||||||
  render() {
 | 
					  render() {
 | 
				
			||||||
    return h(
 | 
					    return h(
 | 
				
			||||||
      "div",
 | 
					      "div",
 | 
				
			||||||
@ -144,12 +145,12 @@ const layoutHeader = defineComponent({
 | 
				
			|||||||
        default: () => [
 | 
					        default: () => [
 | 
				
			||||||
          !pureSetting.hiddenSideBar &&
 | 
					          !pureSetting.hiddenSideBar &&
 | 
				
			||||||
          (layout.value.includes("vertical") || layout.value.includes("mix"))
 | 
					          (layout.value.includes("vertical") || layout.value.includes("mix"))
 | 
				
			||||||
            ? h(navbar)
 | 
					            ? h(LayNavbar)
 | 
				
			||||||
            : null,
 | 
					            : null,
 | 
				
			||||||
          !pureSetting.hiddenSideBar && layout.value.includes("horizontal")
 | 
					          !pureSetting.hiddenSideBar && layout.value.includes("horizontal")
 | 
				
			||||||
            ? h(Horizontal)
 | 
					            ? h(NavHorizontal)
 | 
				
			||||||
            : null,
 | 
					            : null,
 | 
				
			||||||
          h(tag)
 | 
					          h(LayTag)
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@ -168,7 +169,7 @@ const layoutHeader = defineComponent({
 | 
				
			|||||||
      class="app-mask"
 | 
					      class="app-mask"
 | 
				
			||||||
      @click="useAppStoreHook().toggleSideBar()"
 | 
					      @click="useAppStoreHook().toggleSideBar()"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <Vertical
 | 
					    <NavVertical
 | 
				
			||||||
      v-show="
 | 
					      v-show="
 | 
				
			||||||
        !pureSetting.hiddenSideBar &&
 | 
					        !pureSetting.hiddenSideBar &&
 | 
				
			||||||
        (layout.includes('vertical') || layout.includes('mix'))
 | 
					        (layout.includes('vertical') || layout.includes('mix'))
 | 
				
			||||||
@ -181,24 +182,24 @@ const layoutHeader = defineComponent({
 | 
				
			|||||||
      ]"
 | 
					      ]"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div v-if="set.fixedHeader">
 | 
					      <div v-if="set.fixedHeader">
 | 
				
			||||||
        <layout-header />
 | 
					        <LayHeader />
 | 
				
			||||||
        <!-- 主体内容 -->
 | 
					        <!-- 主体内容 -->
 | 
				
			||||||
        <app-main :fixed-header="set.fixedHeader" />
 | 
					        <LayContent :fixed-header="set.fixedHeader" />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <el-scrollbar v-else>
 | 
					      <el-scrollbar v-else>
 | 
				
			||||||
        <el-backtop
 | 
					        <el-backtop
 | 
				
			||||||
          :title="t('buttons.pureBackTop')"
 | 
					          :title="t('buttons.pureBackTop')"
 | 
				
			||||||
          target=".main-container .el-scrollbar__wrap"
 | 
					          target=".main-container .el-scrollbar__wrap"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <backTop />
 | 
					          <BackTopIcon />
 | 
				
			||||||
        </el-backtop>
 | 
					        </el-backtop>
 | 
				
			||||||
        <layout-header />
 | 
					        <LayHeader />
 | 
				
			||||||
        <!-- 主体内容 -->
 | 
					        <!-- 主体内容 -->
 | 
				
			||||||
        <app-main :fixed-header="set.fixedHeader" />
 | 
					        <LayContent :fixed-header="set.fixedHeader" />
 | 
				
			||||||
      </el-scrollbar>
 | 
					      </el-scrollbar>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <!-- 系统设置 -->
 | 
					    <!-- 系统设置 -->
 | 
				
			||||||
    <setting />
 | 
					    <LaySetting />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,11 +20,12 @@ import {
 | 
				
			|||||||
  // 可选组件
 | 
					  // 可选组件
 | 
				
			||||||
  Icon,
 | 
					  Icon,
 | 
				
			||||||
  Column,
 | 
					  Column,
 | 
				
			||||||
 | 
					  Grid,
 | 
				
			||||||
 | 
					  Pager,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
  // Colgroup,
 | 
					  // Colgroup,
 | 
				
			||||||
  // Grid,
 | 
					 | 
				
			||||||
  // Tooltip,
 | 
					  // Tooltip,
 | 
				
			||||||
  // Toolbar,
 | 
					  // Toolbar,
 | 
				
			||||||
  // Pager,
 | 
					 | 
				
			||||||
  // Form,
 | 
					  // Form,
 | 
				
			||||||
  // FormItem,
 | 
					  // FormItem,
 | 
				
			||||||
  // FormGather,
 | 
					  // FormGather,
 | 
				
			||||||
@ -35,7 +36,6 @@ import {
 | 
				
			|||||||
  // RadioButton,
 | 
					  // RadioButton,
 | 
				
			||||||
  // Switch,
 | 
					  // Switch,
 | 
				
			||||||
  // Input,
 | 
					  // Input,
 | 
				
			||||||
  // Select,
 | 
					 | 
				
			||||||
  // Optgroup,
 | 
					  // Optgroup,
 | 
				
			||||||
  // Option,
 | 
					  // Option,
 | 
				
			||||||
  // Textarea,
 | 
					  // Textarea,
 | 
				
			||||||
@ -76,11 +76,12 @@ export function useVxeTable(app: App) {
 | 
				
			|||||||
    // 可选组件
 | 
					    // 可选组件
 | 
				
			||||||
    .use(Icon)
 | 
					    .use(Icon)
 | 
				
			||||||
    .use(Column)
 | 
					    .use(Column)
 | 
				
			||||||
 | 
					    .use(Grid)
 | 
				
			||||||
 | 
					    .use(Pager)
 | 
				
			||||||
 | 
					    .use(Select)
 | 
				
			||||||
    // .use(Colgroup)
 | 
					    // .use(Colgroup)
 | 
				
			||||||
    // .use(Grid)
 | 
					 | 
				
			||||||
    // .use(Tooltip)
 | 
					    // .use(Tooltip)
 | 
				
			||||||
    // .use(Toolbar)
 | 
					    // .use(Toolbar)
 | 
				
			||||||
    // .use(Pager)
 | 
					 | 
				
			||||||
    // .use(Form)
 | 
					    // .use(Form)
 | 
				
			||||||
    // .use(FormItem)
 | 
					    // .use(FormItem)
 | 
				
			||||||
    // .use(FormGather)
 | 
					    // .use(FormGather)
 | 
				
			||||||
@ -91,7 +92,6 @@ export function useVxeTable(app: App) {
 | 
				
			|||||||
    // .use(RadioButton)
 | 
					    // .use(RadioButton)
 | 
				
			||||||
    // .use(Switch)
 | 
					    // .use(Switch)
 | 
				
			||||||
    // .use(Input)
 | 
					    // .use(Input)
 | 
				
			||||||
    // .use(Select)
 | 
					 | 
				
			||||||
    // .use(Optgroup)
 | 
					    // .use(Optgroup)
 | 
				
			||||||
    // .use(Option)
 | 
					    // .use(Option)
 | 
				
			||||||
    // .use(Textarea)
 | 
					    // .use(Textarea)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { $t } from "@/plugins/i18n";
 | 
					import { $t } from "@/plugins/i18n";
 | 
				
			||||||
import { board } from "@/router/enums";
 | 
					import { board } from "@/router/enums";
 | 
				
			||||||
const IFrame = () => import("@/layout/frameView.vue");
 | 
					const IFrame = () => import("@/layout/frame.vue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  path: "/board",
 | 
					  path: "/board",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { $t } from "@/plugins/i18n";
 | 
					import { $t } from "@/plugins/i18n";
 | 
				
			||||||
import { formdesign } from "@/router/enums";
 | 
					import { formdesign } from "@/router/enums";
 | 
				
			||||||
const IFrame = () => import("@/layout/frameView.vue");
 | 
					const IFrame = () => import("@/layout/frame.vue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  path: "/form-design",
 | 
					  path: "/form-design",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { $t } from "@/plugins/i18n";
 | 
					import { $t } from "@/plugins/i18n";
 | 
				
			||||||
import { mind } from "@/router/enums";
 | 
					import { mind } from "@/router/enums";
 | 
				
			||||||
const IFrame = () => import("@/layout/frameView.vue");
 | 
					const IFrame = () => import("@/layout/frame.vue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  path: "/mind-map",
 | 
					  path: "/mind-map",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { ppt } from "@/router/enums";
 | 
					import { ppt } from "@/router/enums";
 | 
				
			||||||
const IFrame = () => import("@/layout/frameView.vue");
 | 
					const IFrame = () => import("@/layout/frame.vue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  path: "/ppt",
 | 
					  path: "/ppt",
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ import { userKey, type DataInfo } from "@/utils/auth";
 | 
				
			|||||||
import { type menuType, routerArrays } from "@/layout/types";
 | 
					import { type menuType, routerArrays } from "@/layout/types";
 | 
				
			||||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
 | 
					import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
 | 
				
			||||||
import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
					import { usePermissionStoreHook } from "@/store/modules/permission";
 | 
				
			||||||
const IFrame = () => import("@/layout/frameView.vue");
 | 
					const IFrame = () => import("@/layout/frame.vue");
 | 
				
			||||||
// https://cn.vitejs.dev/guide/features.html#glob-import
 | 
					// https://cn.vitejs.dev/guide/features.html#glob-import
 | 
				
			||||||
const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
 | 
					const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -82,10 +82,7 @@ export function useColumns() {
 | 
				
			|||||||
      className: "pure-version",
 | 
					      className: "pure-version",
 | 
				
			||||||
      cellRenderer: () => {
 | 
					      cellRenderer: () => {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
          <a
 | 
					          <a href="https://pure-admin.github.io/pure-admin-doc" target="_blank">
 | 
				
			||||||
            href="https://yiming_chang.gitee.io/pure-admin-doc"
 | 
					 | 
				
			||||||
            target="_blank"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <span style="color: var(--el-color-primary)">文档链接</span>
 | 
					            <span style="color: var(--el-color-primary)">文档链接</span>
 | 
				
			||||||
          </a>
 | 
					          </a>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
@ -97,10 +94,7 @@ export function useColumns() {
 | 
				
			|||||||
      className: "pure-version",
 | 
					      className: "pure-version",
 | 
				
			||||||
      cellRenderer: () => {
 | 
					      cellRenderer: () => {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
          <a
 | 
					          <a href="https://pure-admin.github.io/vue-pure-admin" target="_blank">
 | 
				
			||||||
            href="https://yiming_chang.gitee.io/vue-pure-admin"
 | 
					 | 
				
			||||||
            target="_blank"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            <span style="color: var(--el-color-primary)">预览链接</span>
 | 
					            <span style="color: var(--el-color-primary)">预览链接</span>
 | 
				
			||||||
          </a>
 | 
					          </a>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -8,8 +8,8 @@ import Preferences from "./components/Preferences.vue";
 | 
				
			|||||||
import SecurityLog from "./components/SecurityLog.vue";
 | 
					import SecurityLog from "./components/SecurityLog.vue";
 | 
				
			||||||
import { useGlobal, deviceDetection } from "@pureadmin/utils";
 | 
					import { useGlobal, deviceDetection } from "@pureadmin/utils";
 | 
				
			||||||
import AccountManagement from "./components/AccountManagement.vue";
 | 
					import AccountManagement from "./components/AccountManagement.vue";
 | 
				
			||||||
import TopCollapse from "@/layout/components/sidebar/topCollapse.vue";
 | 
					 | 
				
			||||||
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
 | 
					import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
 | 
				
			||||||
 | 
					import LaySidebarTopCollapse from "@/layout/components/lay-sidebar/components/SidebarTopCollapse.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import leftLine from "@iconify-icons/ri/arrow-left-s-line";
 | 
					import leftLine from "@iconify-icons/ri/arrow-left-s-line";
 | 
				
			||||||
import ProfileIcon from "@iconify-icons/ri/user-3-line";
 | 
					import ProfileIcon from "@iconify-icons/ri/user-3-line";
 | 
				
			||||||
@ -115,7 +115,7 @@ getMine().then(res => {
 | 
				
			|||||||
      </el-menu>
 | 
					      </el-menu>
 | 
				
			||||||
    </el-aside>
 | 
					    </el-aside>
 | 
				
			||||||
    <el-main>
 | 
					    <el-main>
 | 
				
			||||||
      <TopCollapse
 | 
					      <LaySidebarTopCollapse
 | 
				
			||||||
        v-if="deviceDetection()"
 | 
					        v-if="deviceDetection()"
 | 
				
			||||||
        class="px-0"
 | 
					        class="px-0"
 | 
				
			||||||
        :is-active="isOpen"
 | 
					        :is-active="isOpen"
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ const { isDisabled, text } = useVerifyCode();
 | 
				
			|||||||
const onLogin = async (formEl: FormInstance | undefined) => {
 | 
					const onLogin = async (formEl: FormInstance | undefined) => {
 | 
				
			||||||
  loading.value = true;
 | 
					  loading.value = true;
 | 
				
			||||||
  if (!formEl) return;
 | 
					  if (!formEl) return;
 | 
				
			||||||
  await formEl.validate((valid, fields) => {
 | 
					  await formEl.validate(valid => {
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) {
 | 
				
			||||||
      // 模拟登录请求,需根据实际开发进行修改
 | 
					      // 模拟登录请求,需根据实际开发进行修改
 | 
				
			||||||
      setTimeout(() => {
 | 
					      setTimeout(() => {
 | 
				
			||||||
@ -34,7 +34,6 @@ const onLogin = async (formEl: FormInstance | undefined) => {
 | 
				
			|||||||
      }, 2000);
 | 
					      }, 2000);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      loading.value = false;
 | 
					      loading.value = false;
 | 
				
			||||||
      return fields;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ const repeatPasswordRule = [
 | 
				
			|||||||
const onUpdate = async (formEl: FormInstance | undefined) => {
 | 
					const onUpdate = async (formEl: FormInstance | undefined) => {
 | 
				
			||||||
  loading.value = true;
 | 
					  loading.value = true;
 | 
				
			||||||
  if (!formEl) return;
 | 
					  if (!formEl) return;
 | 
				
			||||||
  await formEl.validate((valid, fields) => {
 | 
					  await formEl.validate(valid => {
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) {
 | 
				
			||||||
      if (checked.value) {
 | 
					      if (checked.value) {
 | 
				
			||||||
        // 模拟请求,需根据实际开发进行修改
 | 
					        // 模拟请求,需根据实际开发进行修改
 | 
				
			||||||
@ -63,7 +63,6 @@ const onUpdate = async (formEl: FormInstance | undefined) => {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      loading.value = false;
 | 
					      loading.value = false;
 | 
				
			||||||
      return fields;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -42,7 +42,7 @@ const repeatPasswordRule = [
 | 
				
			|||||||
const onUpdate = async (formEl: FormInstance | undefined) => {
 | 
					const onUpdate = async (formEl: FormInstance | undefined) => {
 | 
				
			||||||
  loading.value = true;
 | 
					  loading.value = true;
 | 
				
			||||||
  if (!formEl) return;
 | 
					  if (!formEl) return;
 | 
				
			||||||
  await formEl.validate((valid, fields) => {
 | 
					  await formEl.validate(valid => {
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) {
 | 
				
			||||||
      // 模拟请求,需根据实际开发进行修改
 | 
					      // 模拟请求,需根据实际开发进行修改
 | 
				
			||||||
      setTimeout(() => {
 | 
					      setTimeout(() => {
 | 
				
			||||||
@ -53,7 +53,6 @@ const onUpdate = async (formEl: FormInstance | undefined) => {
 | 
				
			|||||||
      }, 2000);
 | 
					      }, 2000);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      loading.value = false;
 | 
					      loading.value = false;
 | 
				
			||||||
      return fields;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -64,7 +64,7 @@ const ruleForm = reactive({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const onLogin = async (formEl: FormInstance | undefined) => {
 | 
					const onLogin = async (formEl: FormInstance | undefined) => {
 | 
				
			||||||
  if (!formEl) return;
 | 
					  if (!formEl) return;
 | 
				
			||||||
  await formEl.validate((valid, fields) => {
 | 
					  await formEl.validate(valid => {
 | 
				
			||||||
    if (valid) {
 | 
					    if (valid) {
 | 
				
			||||||
      loading.value = true;
 | 
					      loading.value = true;
 | 
				
			||||||
      useUserStoreHook()
 | 
					      useUserStoreHook()
 | 
				
			||||||
@ -86,8 +86,6 @@ const onLogin = async (formEl: FormInstance | undefined) => {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .finally(() => (loading.value = false));
 | 
					        .finally(() => (loading.value = false));
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      return fields;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -82,12 +82,7 @@ const dataList = ref([
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div>
 | 
					  <div>
 | 
				
			||||||
    <el-scrollbar>
 | 
					    <el-scrollbar>
 | 
				
			||||||
      <PureDescriptions
 | 
					      <PureDescriptions border :data="data" :columns="columns" :column="5" />
 | 
				
			||||||
        border
 | 
					 | 
				
			||||||
        :data="props.data"
 | 
					 | 
				
			||||||
        :columns="columns"
 | 
					 | 
				
			||||||
        :column="5"
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </el-scrollbar>
 | 
					    </el-scrollbar>
 | 
				
			||||||
    <el-tabs :modelValue="'responseBody'" type="border-card" class="mt-4">
 | 
					    <el-tabs :modelValue="'responseBody'" type="border-card" class="mt-4">
 | 
				
			||||||
      <el-tab-pane
 | 
					      <el-tab-pane
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
| `name`            | 路由名称(必须唯一并且和当前路由`component`字段对应的页面里用`defineOptions`包起来的`name`保持一致) |
 | 
					| `name`            | 路由名称(必须唯一并且和当前路由`component`字段对应的页面里用`defineOptions`包起来的`name`保持一致) |
 | 
				
			||||||
| `path`            | 路由路径                                                     |
 | 
					| `path`            | 路由路径                                                     |
 | 
				
			||||||
| `component`       | 组件路径(传`component`组件路径,那么`path`可以随便写,如果不传,`component`组件路径会跟`path`保持一致) |
 | 
					| `component`       | 组件路径(传`component`组件路径,那么`path`可以随便写,如果不传,`component`组件路径会跟`path`保持一致) |
 | 
				
			||||||
| `rank`            | 菜单排序(平台规定只有`home`路由的`rank`才能为`0`,所以后端在返回`rank`的时候需要从非`0`开始 [点击查看更多](https://yiming_chang.gitee.io/pure-admin-doc/pages/routerMenu/#%E8%8F%9C%E5%8D%95%E6%8E%92%E5%BA%8F-rank)) |
 | 
					| `rank`            | 菜单排序(平台规定只有`home`路由的`rank`才能为`0`,所以后端在返回`rank`的时候需要从非`0`开始 [点击查看更多](https://pure-admin.github.io/pure-admin-doc/pages/routerMenu/#%E8%8F%9C%E5%8D%95%E6%8E%92%E5%BA%8F-rank)) |
 | 
				
			||||||
| `redirect`        | 路由重定向                                                   |
 | 
					| `redirect`        | 路由重定向                                                   |
 | 
				
			||||||
| `icon`            | 菜单图标                                                     |
 | 
					| `icon`            | 菜单图标                                                     |
 | 
				
			||||||
| `extraIcon`       | 右侧图标                                                     |
 | 
					| `extraIcon`       | 右侧图标                                                     |
 | 
				
			||||||
@ -22,5 +22,5 @@
 | 
				
			|||||||
| `hiddenTag`       | 标签页(当前菜单名称或自定义信息禁止添加到标签页)           |
 | 
					| `hiddenTag`       | 标签页(当前菜单名称或自定义信息禁止添加到标签页)           |
 | 
				
			||||||
| `fixedTag`        | 固定标签页(当前菜单名称是否固定显示在标签页且不可关闭)           |
 | 
					| `fixedTag`        | 固定标签页(当前菜单名称是否固定显示在标签页且不可关闭)           |
 | 
				
			||||||
| `showLink`        | 菜单(是否显示该菜单)                                       |
 | 
					| `showLink`        | 菜单(是否显示该菜单)                                       |
 | 
				
			||||||
| `showParent`      | 父级菜单(是否显示父级菜单 [点击查看更多](https://yiming_chang.gitee.io/pure-admin-doc/pages/routerMenu/#%E7%AC%AC%E4%B8%80%E7%A7%8D-%E8%AF%A5%E6%A8%A1%E5%BC%8F%E9%92%88%E5%AF%B9%E7%88%B6%E7%BA%A7%E8%8F%9C%E5%8D%95%E4%B8%8B%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AD%90%E8%8F%9C%E5%8D%95%E7%9A%84%E6%83%85%E5%86%B5-%E5%9C%A8%E5%AD%90%E8%8F%9C%E5%8D%95%E7%9A%84-meta-%E5%B1%9E%E6%80%A7%E4%B8%AD%E5%8A%A0%E4%B8%8A-showparent-true-%E5%8D%B3%E5%8F%AF)) |
 | 
					| `showParent`      | 父级菜单(是否显示父级菜单 [点击查看更多](https://pure-admin.github.io/pure-admin-doc/pages/routerMenu/#%E7%AC%AC%E4%B8%80%E7%A7%8D-%E8%AF%A5%E6%A8%A1%E5%BC%8F%E9%92%88%E5%AF%B9%E7%88%B6%E7%BA%A7%E8%8F%9C%E5%8D%95%E4%B8%8B%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AD%90%E8%8F%9C%E5%8D%95%E7%9A%84%E6%83%85%E5%86%B5-%E5%9C%A8%E5%AD%90%E8%8F%9C%E5%8D%95%E7%9A%84-meta-%E5%B1%9E%E6%80%A7%E4%B8%AD%E5%8A%A0%E4%B8%8A-showparent-true-%E5%8D%B3%E5%8F%AF)) |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ interface Tree {
 | 
				
			|||||||
  children?: Tree[];
 | 
					  children?: Tree[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					defineProps({
 | 
				
			||||||
  treeLoading: Boolean,
 | 
					  treeLoading: Boolean,
 | 
				
			||||||
  treeData: Array
 | 
					  treeData: Array
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@ -95,7 +95,7 @@ defineExpose({ onTreeReset });
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div
 | 
					  <div
 | 
				
			||||||
    v-loading="props.treeLoading"
 | 
					    v-loading="treeLoading"
 | 
				
			||||||
    class="h-full bg-bg_color overflow-auto"
 | 
					    class="h-full bg-bg_color overflow-auto"
 | 
				
			||||||
    :style="{ minHeight: `calc(100vh - 141px)` }"
 | 
					    :style="{ minHeight: `calc(100vh - 141px)` }"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
@ -153,7 +153,7 @@ defineExpose({ onTreeReset });
 | 
				
			|||||||
    <el-divider />
 | 
					    <el-divider />
 | 
				
			||||||
    <el-tree
 | 
					    <el-tree
 | 
				
			||||||
      ref="treeRef"
 | 
					      ref="treeRef"
 | 
				
			||||||
      :data="props.treeData"
 | 
					      :data="treeData"
 | 
				
			||||||
      node-key="id"
 | 
					      node-key="id"
 | 
				
			||||||
      size="small"
 | 
					      size="small"
 | 
				
			||||||
      :props="defaultProps"
 | 
					      :props="defaultProps"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { tableDataMore } from "./data";
 | 
					import { tableDataMore } from "./data";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = withDefaults(
 | 
					withDefaults(
 | 
				
			||||||
  defineProps<{
 | 
					  defineProps<{
 | 
				
			||||||
    height?: string;
 | 
					    height?: string;
 | 
				
			||||||
  }>(),
 | 
					  }>(),
 | 
				
			||||||
@ -62,12 +62,12 @@ function handleClick(row) {
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <pure-table
 | 
					  <pure-table
 | 
				
			||||||
    :data="
 | 
					    :data="
 | 
				
			||||||
      props.height
 | 
					      height
 | 
				
			||||||
        ? tableDataMore.concat(tableDataMore).concat(tableDataMore)
 | 
					        ? tableDataMore.concat(tableDataMore).concat(tableDataMore)
 | 
				
			||||||
        : tableDataMore
 | 
					        : tableDataMore
 | 
				
			||||||
    "
 | 
					    "
 | 
				
			||||||
    :columns="columns"
 | 
					    :columns="columns"
 | 
				
			||||||
    :height="props.height"
 | 
					    :height="height"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template #operation="{ row }">
 | 
					    <template #operation="{ row }">
 | 
				
			||||||
      <el-button link type="primary" size="small" @click="handleClick(row)">
 | 
					      <el-button link type="primary" size="small" @click="handleClick(row)">
 | 
				
			||||||
 | 
				
			|||||||
@ -30,7 +30,7 @@ const columns: TableColumnList = [
 | 
				
			|||||||
    <template #video>
 | 
					    <template #video>
 | 
				
			||||||
      <video width="180" height="180" controls>
 | 
					      <video width="180" height="180" controls>
 | 
				
			||||||
        <source
 | 
					        <source
 | 
				
			||||||
          src="https://yiming_chang.gitee.io/pure-admin-doc/video/url.mov"
 | 
					          src="https://pure-admin.github.io/pure-admin-doc/video/url.mov"
 | 
				
			||||||
          type="video/mp4"
 | 
					          type="video/mp4"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </video>
 | 
					      </video>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import List from "./list.vue";
 | 
					import List from "./list.vue";
 | 
				
			||||||
import TreeList from "./treeList.vue";
 | 
					import TreeList from "./treeList.vue";
 | 
				
			||||||
 | 
					import PageList from "./pageList.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const rendContent = (val: string) =>
 | 
					const rendContent = (val: string) =>
 | 
				
			||||||
  `代码位置:src/views/table/virtual/${val}.vue`;
 | 
					  `代码位置:src/views/table/virtual/${val}.vue`;
 | 
				
			||||||
@ -8,13 +9,19 @@ export const list = [
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    key: "list",
 | 
					    key: "list",
 | 
				
			||||||
    content: rendContent("list"),
 | 
					    content: rendContent("list"),
 | 
				
			||||||
    title: "虚拟列表",
 | 
					    title: "虚拟表格",
 | 
				
			||||||
    component: List
 | 
					    component: List
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    key: "treeList",
 | 
					    key: "treeList",
 | 
				
			||||||
    content: rendContent("treeList"),
 | 
					    content: rendContent("treeList"),
 | 
				
			||||||
    title: "虚拟树",
 | 
					    title: "虚拟树形表格",
 | 
				
			||||||
    component: TreeList
 | 
					    component: TreeList
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: "pageList",
 | 
				
			||||||
 | 
					    content: rendContent("pageList"),
 | 
				
			||||||
 | 
					    title: "分页表格",
 | 
				
			||||||
 | 
					    component: PageList
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,20 @@
 | 
				
			|||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { ref } from "vue";
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					import { VxeTableBar } from "@/components/ReVxeTableBar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const vxeTableRef = ref();
 | 
				
			||||||
 | 
					const loading = ref(true);
 | 
				
			||||||
const tableData = ref([]);
 | 
					const tableData = ref([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setTimeout(() => {
 | 
					const columns = [
 | 
				
			||||||
 | 
					  { type: "seq", field: "seq", title: "序号", width: 100 },
 | 
				
			||||||
 | 
					  { field: "name", title: "名称", sortable: true },
 | 
				
			||||||
 | 
					  { field: "role", title: "角色" },
 | 
				
			||||||
 | 
					  { field: "sex", title: "性别" }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function onSearch() {
 | 
				
			||||||
 | 
					  loading.value = true;
 | 
				
			||||||
  // 模拟数据
 | 
					  // 模拟数据
 | 
				
			||||||
  const mockList = [];
 | 
					  const mockList = [];
 | 
				
			||||||
  for (let index = 0; index < 500; index++) {
 | 
					  for (let index = 0; index < 500; index++) {
 | 
				
			||||||
@ -15,21 +26,33 @@ setTimeout(() => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  tableData.value = mockList;
 | 
					  tableData.value = mockList;
 | 
				
			||||||
}, 100);
 | 
					  setTimeout(() => {
 | 
				
			||||||
 | 
					    loading.value = false;
 | 
				
			||||||
 | 
					  }, 500);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onSearch();
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <vxe-table
 | 
					  <VxeTableBar
 | 
				
			||||||
    border
 | 
					    :vxeTableRef="vxeTableRef"
 | 
				
			||||||
 | 
					    :columns="columns"
 | 
				
			||||||
 | 
					    title="虚拟表格"
 | 
				
			||||||
 | 
					    @refresh="onSearch"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
 | 
					      <vxe-grid
 | 
				
			||||||
 | 
					        ref="vxeTableRef"
 | 
				
			||||||
 | 
					        v-loading="loading"
 | 
				
			||||||
        show-overflow
 | 
					        show-overflow
 | 
				
			||||||
        height="500"
 | 
					        height="500"
 | 
				
			||||||
 | 
					        :size="size"
 | 
				
			||||||
        :row-config="{ isHover: true }"
 | 
					        :row-config="{ isHover: true }"
 | 
				
			||||||
    :data="tableData"
 | 
					 | 
				
			||||||
        :scroll-y="{ enabled: true }"
 | 
					        :scroll-y="{ enabled: true }"
 | 
				
			||||||
  >
 | 
					        :columns="dynamicColumns"
 | 
				
			||||||
    <vxe-column type="seq" title="序号" width="100" />
 | 
					        :data="tableData"
 | 
				
			||||||
    <vxe-column field="name" title="名称" sortable />
 | 
					      />
 | 
				
			||||||
    <vxe-column field="role" title="角色" />
 | 
					    </template>
 | 
				
			||||||
    <vxe-column field="sex" title="性别" />
 | 
					  </VxeTableBar>
 | 
				
			||||||
  </vxe-table>
 | 
					 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										86
									
								
								src/views/table/virtual/pageList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					<script lang="ts" setup>
 | 
				
			||||||
 | 
					import { ref, reactive, computed } from "vue";
 | 
				
			||||||
 | 
					import { VxeTableBar } from "@/components/ReVxeTableBar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const vxeTableRef = ref();
 | 
				
			||||||
 | 
					const loading = ref(true);
 | 
				
			||||||
 | 
					const tableData = ref([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getTableHeight = computed(() => {
 | 
				
			||||||
 | 
					  return (size: string) => {
 | 
				
			||||||
 | 
					    switch (size) {
 | 
				
			||||||
 | 
					      case "medium":
 | 
				
			||||||
 | 
					        return 531;
 | 
				
			||||||
 | 
					      case "small":
 | 
				
			||||||
 | 
					        return 482;
 | 
				
			||||||
 | 
					      case "mini":
 | 
				
			||||||
 | 
					        return 433;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const pagerConfig = reactive({
 | 
				
			||||||
 | 
					  total: 0,
 | 
				
			||||||
 | 
					  currentPage: 1,
 | 
				
			||||||
 | 
					  pageSize: 10,
 | 
				
			||||||
 | 
					  pageSizes: [5, 10, 15, 20]
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const columns = [
 | 
				
			||||||
 | 
					  { type: "seq", field: "seq", title: "序号", width: 100 },
 | 
				
			||||||
 | 
					  { field: "name", title: "名称", sortable: true },
 | 
				
			||||||
 | 
					  { field: "role", title: "角色" },
 | 
				
			||||||
 | 
					  { field: "sex", title: "性别" }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function onSearch() {
 | 
				
			||||||
 | 
					  loading.value = true;
 | 
				
			||||||
 | 
					  // 模拟数据
 | 
				
			||||||
 | 
					  const mockList = [];
 | 
				
			||||||
 | 
					  for (let index = 0; index < 10; index++) {
 | 
				
			||||||
 | 
					    mockList.push({
 | 
				
			||||||
 | 
					      id: index,
 | 
				
			||||||
 | 
					      name: "Test" + index,
 | 
				
			||||||
 | 
					      role: "Developer",
 | 
				
			||||||
 | 
					      sex: "男"
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  pagerConfig.total = 20;
 | 
				
			||||||
 | 
					  tableData.value = mockList;
 | 
				
			||||||
 | 
					  setTimeout(() => {
 | 
				
			||||||
 | 
					    loading.value = false;
 | 
				
			||||||
 | 
					  }, 500);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handlePageChange = ({ currentPage, pageSize }) => {
 | 
				
			||||||
 | 
					  pagerConfig.currentPage = currentPage;
 | 
				
			||||||
 | 
					  pagerConfig.pageSize = pageSize;
 | 
				
			||||||
 | 
					  onSearch();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onSearch();
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <VxeTableBar
 | 
				
			||||||
 | 
					    :vxeTableRef="vxeTableRef"
 | 
				
			||||||
 | 
					    :columns="columns"
 | 
				
			||||||
 | 
					    title="分页表格"
 | 
				
			||||||
 | 
					    @refresh="onSearch"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
 | 
					      <vxe-grid
 | 
				
			||||||
 | 
					        ref="vxeTableRef"
 | 
				
			||||||
 | 
					        v-loading="loading"
 | 
				
			||||||
 | 
					        show-overflow
 | 
				
			||||||
 | 
					        :height="getTableHeight(size)"
 | 
				
			||||||
 | 
					        :size="size"
 | 
				
			||||||
 | 
					        :column-config="{ resizable: true }"
 | 
				
			||||||
 | 
					        :columns="dynamicColumns"
 | 
				
			||||||
 | 
					        :pagerConfig="pagerConfig"
 | 
				
			||||||
 | 
					        :data="tableData"
 | 
				
			||||||
 | 
					        @page-change="handlePageChange"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					  </VxeTableBar>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
@ -1,56 +1,51 @@
 | 
				
			|||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { ref } from "vue";
 | 
					import { ref } from "vue";
 | 
				
			||||||
import treeList from "./tree.json";
 | 
					import treeList from "./tree.json";
 | 
				
			||||||
 | 
					import { VxeTableBar } from "@/components/ReVxeTableBar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const tableRef = ref();
 | 
					const vxeTableRef = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const loading = ref(false);
 | 
					const loading = ref(true);
 | 
				
			||||||
const tableData = ref([]);
 | 
					const tableData = ref([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const loadList = () => {
 | 
					const columns = [
 | 
				
			||||||
 | 
					  { type: "seq", field: "seq", title: "序号", width: 200, treeNode: true },
 | 
				
			||||||
 | 
					  { field: "id", title: "Id" },
 | 
				
			||||||
 | 
					  { field: "name", title: "地点" }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function onSearch() {
 | 
				
			||||||
  loading.value = true;
 | 
					  loading.value = true;
 | 
				
			||||||
  setTimeout(() => {
 | 
					 | 
				
			||||||
  tableData.value = treeList;
 | 
					  tableData.value = treeList;
 | 
				
			||||||
 | 
					  setTimeout(() => {
 | 
				
			||||||
    loading.value = false;
 | 
					    loading.value = false;
 | 
				
			||||||
  }, 200);
 | 
					  }, 500);
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const expandAllEvent = () => {
 | 
					onSearch();
 | 
				
			||||||
  const $table = tableRef.value;
 | 
					 | 
				
			||||||
  if ($table) {
 | 
					 | 
				
			||||||
    $table.setAllTreeExpand(true);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const claseExpandEvent = () => {
 | 
					 | 
				
			||||||
  const $table = tableRef.value;
 | 
					 | 
				
			||||||
  if ($table) {
 | 
					 | 
				
			||||||
    $table.clearTreeExpand();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
loadList();
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div>
 | 
					  <VxeTableBar
 | 
				
			||||||
    <div class="mb-4">
 | 
					    tree
 | 
				
			||||||
      <el-button @click="expandAllEvent">展开所有</el-button>
 | 
					    title="虚拟树形表格"
 | 
				
			||||||
      <el-button @click="claseExpandEvent">收起所有</el-button>
 | 
					    :isExpandAll="false"
 | 
				
			||||||
    </div>
 | 
					    :vxeTableRef="vxeTableRef"
 | 
				
			||||||
 | 
					    :columns="columns"
 | 
				
			||||||
    <vxe-table
 | 
					    @refresh="onSearch"
 | 
				
			||||||
      ref="tableRef"
 | 
					  >
 | 
				
			||||||
 | 
					    <template v-slot="{ size, dynamicColumns }">
 | 
				
			||||||
 | 
					      <vxe-grid
 | 
				
			||||||
 | 
					        ref="vxeTableRef"
 | 
				
			||||||
 | 
					        v-loading="loading"
 | 
				
			||||||
        show-overflow
 | 
					        show-overflow
 | 
				
			||||||
        height="500"
 | 
					        height="500"
 | 
				
			||||||
      :loading="loading"
 | 
					        :size="size"
 | 
				
			||||||
        :tree-config="{ transform: true }"
 | 
					        :tree-config="{ transform: true }"
 | 
				
			||||||
        :scroll-y="{ enabled: true, gt: 20 }"
 | 
					        :scroll-y="{ enabled: true, gt: 20 }"
 | 
				
			||||||
 | 
					        :columns="dynamicColumns"
 | 
				
			||||||
        :data="tableData"
 | 
					        :data="tableData"
 | 
				
			||||||
    >
 | 
					      />
 | 
				
			||||||
      <vxe-column type="seq" title="序号" width="200" tree-node />
 | 
					    </template>
 | 
				
			||||||
      <vxe-column field="id" title="Id" />
 | 
					  </VxeTableBar>
 | 
				
			||||||
      <vxe-column field="name" title="地点" />
 | 
					 | 
				
			||||||
    </vxe-table>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -61,7 +61,7 @@ declare global {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * 全局自定义环境变量的类型声明
 | 
					   * 全局自定义环境变量的类型声明
 | 
				
			||||||
   * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/config/#%E5%85%B7%E4%BD%93%E9%85%8D%E7%BD%AE}
 | 
					   * @see {@link https://pure-admin.github.io/pure-admin-doc/pages/config/#%E5%85%B7%E4%BD%93%E9%85%8D%E7%BD%AE}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  interface ViteEnv {
 | 
					  interface ViteEnv {
 | 
				
			||||||
    VITE_PORT: number;
 | 
					    VITE_PORT: number;
 | 
				
			||||||
@ -79,7 +79,7 @@ declare global {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * 对应 `public/platform-config.json` 文件的类型声明
 | 
					   * 对应 `public/platform-config.json` 文件的类型声明
 | 
				
			||||||
   * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/config/#platform-config-json}
 | 
					   * @see {@link https://pure-admin.github.io/pure-admin-doc/pages/config/#platform-config-json}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  interface PlatformConfigs {
 | 
					  interface PlatformConfigs {
 | 
				
			||||||
    Version?: string;
 | 
					    Version?: string;
 | 
				
			||||||
@ -120,7 +120,7 @@ declare global {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * 与 `PlatformConfigs` 类型不同,这里是缓存到浏览器本地存储的类型声明
 | 
					   * 与 `PlatformConfigs` 类型不同,这里是缓存到浏览器本地存储的类型声明
 | 
				
			||||||
   * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/config/#platform-config-json}
 | 
					   * @see {@link https://pure-admin.github.io/pure-admin-doc/pages/config/#platform-config-json}
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  interface StorageConfigs {
 | 
					  interface StorageConfigs {
 | 
				
			||||||
    version?: string;
 | 
					    version?: string;
 | 
				
			||||||
 | 
				
			|||||||