Compare commits

...

25 Commits

Author SHA1 Message Date
xiaoxian521
a8c59c5c36 release: update 3.7.0 2022-11-21 17:14:22 +08:00
xiaoxian521
0d4d3a301b fix: 优化单点登录 2022-11-21 16:44:31 +08:00
xiaoxian521
b10c3eb1bb feat: 添加前端单点登录 2022-11-21 16:22:17 +08:00
RealityBoy
9b62d6ef1e feat: add ample demos to @pureadmin/table (#379)
* feat: add ample demos to @pureadmin/table
2022-11-21 11:42:33 +08:00
xiaoxian521
8ff242ea45 docs: update README.md 2022-11-18 22:40:32 +08:00
xiaoxian521
867ef87a34 chore: use intro.js replace driver.js 2022-11-18 19:54:08 +08:00
xiaoxian521
2235d9d7a8 chore: 删除 @vitejs/plugin-legacyvue3 无法通过任何工具使其支持ie 2022-11-17 22:11:13 +08:00
clovelll
5c82fdcd0f fix: 卡片列表页编辑菜单高度问题 (#376)
Co-authored-by: chenanrong <chenanrong@kezaihui.com>
2022-11-17 19:21:02 +08:00
xiaoxian521
641355083c feat: 兼容引入某个库导致 global is not defined 报错 2022-11-17 18:54:09 +08:00
xiaoxian521
cadd611559 perf: 补充注释 2022-11-17 18:12:03 +08:00
xiaoxian521
fb734f3394 chore: 删除 httpREADME.md,看文档 http请求 即可 2022-11-17 15:48:03 +08:00
xiaoxian521
e4a87e2138 perf: 优化环境变量注释 2022-11-17 15:44:11 +08:00
xiaoxian521
12db42892d chore: 规范menuArrowIconNoTransition 写法 2022-11-17 15:29:12 +08:00
xiaoxian521
13a0db0180 perf: 删除已废弃的 $baseUrl 2022-11-17 14:59:36 +08:00
xiaoxian521
facb09d779 fix: 页内菜单带参互相跳转,标签没有选中高亮 2022-11-16 17:30:24 +08:00
xiaoxian521
617f8e936c chore: update 2022-11-16 12:03:34 +08:00
xiaoxian521
6e48ad79a7 feat: 优化菜单,添加 menuArrowIconNoTransition 全局配置 2022-11-16 11:59:59 +08:00
xiaoxian521
3984ab19c9 docs: update 2022-11-16 01:34:19 +08:00
xiaoxian521
49a9259f2e perf: 规范script setup写法 2022-11-16 00:40:13 +08:00
xiaoxian521
867bbad1be docs: update README 2022-11-14 12:09:10 +08:00
xiaoxian521
ead4318163 feat: 丰富水印功能页面 2022-11-13 13:15:01 +08:00
xiaoxian521
bfa9203883 chore: update dependencies 2022-11-12 17:48:05 +08:00
xiaoxian521
4f5f18f61c perf: update 2022-11-12 09:55:20 +08:00
xiaoxian521
df71c7f75c chore: update dependencies 2022-11-11 03:36:18 +08:00
xiaoxian521
c4839aa5f4 chore: 更换表单设计器组件 2022-11-10 13:00:48 +08:00
128 changed files with 3793 additions and 1691 deletions

2
.env
View File

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

View File

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

View File

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

View File

@@ -4,12 +4,9 @@ NODE_ENV=production
VITE_PUBLIC_PATH = /
# 线上环境路由历史模式
# 预发布环境路由历史模式Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数"
VITE_ROUTER_HISTORY = "hash"
# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false
# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
VITE_CDN = true

View File

@@ -1,6 +1,7 @@
public
dist
*.d.ts
/src/assets
package.json
.eslintrc.js
.prettierrc.js
@@ -8,3 +9,5 @@ commitlint.config.js
postcss.config.js
tailwind.config.js
stylelint.config.js
src/components/ReSplitPane/iconfont
src/components/ReFlowChart/src/assets/iconfont

View File

@@ -1,3 +1,27 @@
# 3.7.0 (2022-11-21)
### ✔️ refactor
- Replace `driver.js` with `intro.js`
### 🎫 Feat
- Add front-end single sign-on, test address https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
- Add more examples for [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/serverConfig.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
- Replacement form designer component demo
### 🐞 Bug fixes
- Repair the in-page menu with parameters to jump to each other, the label is not selected and highlighted
### 🍏 Perf
- Removed deprecated `$baseUrl`
- Compatible importing a certain library leads to `global is not defined` error, importing `src/utils/globalPolyfills.ts` file into `src/main.ts` can solve the problem
- Remove `@vitejs/plugin-legacy`, `vue3` cannot make it support `ie` through any tool
# 3.6.4 (2022-11-10)
### 🎫 Feat
@@ -121,7 +145,7 @@
- Secondary encapsulation of `Table` of `element-plus` into [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table), providing flexible configuration items and integrating into the platform
- Secondary encapsulation of `Descriptions` of `element-plus` into [@pureadmin/descriptions](https://github.com/xiaoxian521/pure-admin-descriptions), providing flexible configuration items and integrating into the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils-docs.vercel.app/), and delete the code concentrated in this library to reduce the size of the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils.netlify.app), and delete the code concentrated in this library to reduce the size of the platform
- Add [unplugin-vue-define-options](https://www.npmjs.com/package/unplugin-vue-define-options) plugin, the page can directly write `defineOptions({name: custom name})`
- Add project files, language analysis tool [cloc](https://www.npmjs.com/package/cloc)
- Added landing page internationalization
@@ -282,7 +306,6 @@
- Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter
- Packaged files provide traditional browser compatibility support, configure VITE_LEGACY to true
# 2.6.0(2021-11-10)

View File

@@ -1,3 +1,27 @@
# 3.7.0 (2022-11-21)
### ✔️ refactor
- Replace `driver.js` with `intro.js`
### 🎫 Feat
- Add front-end single sign-on, test address https://yiming_chang.gitee.io/vue-pure-admin/#/pure-table/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
- Add more examples for [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table) and `element-plus` [table](https://element-plus.org /zh-CN/component/table.html) example remains the same
- Rich watermark function page (supports customizing various colors, shadows, text, additional attributes, setting undeletable watermarks and setting watermarks for specified elements)
- Optimize the menu, add `MenuArrowIconNoTransition` global configuration, configure it in `public/serverConfig.json`, for the left menu mode, the menu expansion can be set `MenuArrowIconNoTransition: true` to solve
- Replacement form designer component demo
### 🐞 Bug fixes
- Repair the in-page menu with parameters to jump to each other, the label is not selected and highlighted
### 🍏 Perf
- Removed deprecated `$baseUrl`
- Compatible importing a certain library leads to `global is not defined` error, importing `src/utils/globalPolyfills.ts` file into `src/main.ts` can solve the problem
- Remove `@vitejs/plugin-legacy`, `vue3` cannot make it support `ie` through any tool
# 3.6.4 (2022-11-10)
### 🎫 Feat
@@ -121,7 +145,7 @@
- Secondary encapsulation of `Table` of `element-plus` into [@pureadmin/table](https://github.com/xiaoxian521/pure-admin-table), providing flexible configuration items and integrating into the platform
- Secondary encapsulation of `Descriptions` of `element-plus` into [@pureadmin/descriptions](https://github.com/xiaoxian521/pure-admin-descriptions), providing flexible configuration items and integrating into the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils-docs.vercel.app/), and delete the code concentrated in this library to reduce the size of the platform
- Centralize most of the tools and hooks of the platform to [@pureadmin/utils](https://pure-admin-utils.netlify.app), and delete the code concentrated in this library to reduce the size of the platform
- Add [unplugin-vue-define-options](https://www.npmjs.com/package/unplugin-vue-define-options) plugin, the page can directly write `defineOptions({name: custom name})`
- Add project files, language analysis tool [cloc](https://www.npmjs.com/package/cloc)
- Added landing page internationalization
@@ -282,7 +306,6 @@
- Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter
- Packaged files provide traditional browser compatibility support, configure VITE_LEGACY to true
# 2.6.0(2021-11-10)

View File

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

View File

@@ -12,7 +12,7 @@
## Supporting Video
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1534y1S7HV)
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1kg411v7QT)
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
## Docs (support `PWA` fast, offline access)
@@ -29,6 +29,10 @@
- [Click Watch Tauri](https://github.com/xiaoxian521/tauri-pure-admin)
## Electron
- [Click Watch Electron](https://github.com/xiaoxian521/electron-pure-admin)
## Preview
- [Click me to view the domestic preview station](https://yiming_chang.gitee.io/vue-pure-admin)

View File

@@ -12,7 +12,7 @@
## 配套视频
- [点我查看教程](https://www.bilibili.com/video/BV1534y1S7HV)
- [点我查看快速开发教程](https://www.bilibili.com/video/BV1kg411v7QT)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
## 配套文档(支持 `PWA` 快速、离线访问)
@@ -29,6 +29,10 @@
- [点我查看 Tauri 版](https://github.com/xiaoxian521/tauri-pure-admin)
## Electron 版
- [点我查看 Electron 版](https://github.com/xiaoxian521/electron-pure-admin)
## 预览
- [点我查看国内预览站](https://yiming_chang.gitee.io/vue-pure-admin)
@@ -144,7 +148,7 @@ pnpm build
一群已满,下面是二群,群里严禁`黄``赌``毒``vpn`等违法行为!
<img src="http://yiming_chang.gitee.io/pure-admin-doc/img/support/qq.png" width="150px" height="225px" />
<img src="https://yiming_chang.gitee.io/pure-admin-doc/img/support/qq.png" width="150px" height="225px" />
## 许可证

View File

@@ -1,11 +1,10 @@
/** 处理环境变量 */
const warpperEnv = (envConf: Recordable): ViteEnv => {
/** 此处为默认值,无需修改 */
/** 此处为默认值 */
const ret: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_ROUTER_HISTORY: "",
VITE_LEGACY: false,
VITE_CDN: false,
VITE_COMPRESSION: "none"
};
@@ -28,7 +27,7 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
return ret;
};
/** 环境变量 */
/** 获取环境变量 */
const loadEnv = (): ViteEnv => {
return import.meta.env;
};

View File

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

View File

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

View File

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

2442
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,6 +29,10 @@ import Refresh from "@iconify-icons/ep/refresh";
import EditPen from "@iconify-icons/ep/edit-pen";
import Delete from "@iconify-icons/ep/delete";
import More from "@iconify-icons/ep/more-filled";
import EpArrowDown from "@iconify-icons/ep/arrow-down";
import ArrowUp from "@iconify-icons/ep/arrow-up";
import ArrowRight from "@iconify-icons/ep/arrow-right";
import ArrowLeft from "@iconify-icons/ep/arrow-left";
addIcon("check", Check);
addIcon("menu", Menu);
addIcon("home-filled", HomeFilled);
@@ -56,6 +60,10 @@ addIcon("refresh", Refresh);
addIcon("edits", EditPen);
addIcon("delete", Delete);
addIcon("more", More);
addIcon("ep-arrow-down", EpArrowDown);
addIcon("ep-arrow-up", ArrowUp);
addIcon("ep-arrow-right", ArrowRight);
addIcon("ep-arrow-left", ArrowLeft);
// remixicon
import ArrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
import "@/utils/sso";
import { getConfig } from "@/config";
import { toRouteType } from "./types";
import NProgress from "@/utils/progress";
@@ -33,6 +34,7 @@ import pptRouter from "./modules/ppt";
import homeRouter from "./modules/home";
import ableRouter from "./modules/able";
import listRouter from "./modules/list";
import tableRouter from "./modules/table";
import aboutRouter from "./modules/about";
import errorRouter from "./modules/error";
import guideRouter from "./modules/guide";
@@ -50,6 +52,7 @@ const routes = [
homeRouter,
ableRouter,
listRouter,
tableRouter,
aboutRouter,
errorRouter,
guideRouter,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -170,6 +170,12 @@ html.dark {
}
}
/* intro.js */
.introjs-tooltip-title,
.introjs-tooltiptext {
color: var(--el-color-primary);
}
/* element-plus */
.el-table__cell {
background: var(--el-bg-color);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,15 @@
<script setup lang="ts">
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
defineOptions({
name: "Menu1-2-2"
});
let input = ref("");
const input = ref("");
const { t } = useI18n();
const { query } = useRoute();
</script>
<template>
@@ -16,5 +18,9 @@ const { t } = useI18n();
<p style="text-indent: 2em">{{ t("menus.hsmenu1-2") }}</p>
<p style="text-indent: 4em">{{ t("menus.hsmenu1-2-2") }}</p>
<el-input v-model="input" />
<div class="mt-4" v-if="query.text">
此页面携带的参数值为{{ query.text }}
</div>
</div>
</template>

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ defineOptions({
name: "PermissionButton"
});
let elStyle = computed((): CSSProperties => {
const elStyle = computed((): CSSProperties => {
return {
width: "85vw",
justifyContent: "start"

View File

@@ -8,14 +8,14 @@ defineOptions({
name: "PermissionPage"
});
let elStyle = computed((): CSSProperties => {
const elStyle = computed((): CSSProperties => {
return {
width: "85vw",
justifyContent: "start"
};
});
let username = ref(useUserStoreHook()?.username);
const username = ref(useUserStoreHook()?.username);
const options = [
{

View File

@@ -0,0 +1,22 @@
<script setup lang="ts">
import { tableData } from "./data";
const columns: TableColumnList = [
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
</script>
<template>
<pure-table :data="tableData" :columns="columns" />
</template>

View File

@@ -0,0 +1,22 @@
<script setup lang="ts">
import { tableData } from "./data";
const columns: TableColumnList = [
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
</script>
<template>
<pure-table :data="tableData" :columns="columns" border />
</template>

View File

@@ -0,0 +1,70 @@
import { message } from "@pureadmin/components";
import { tableData } from "../data";
// 如果您不习惯tsx写法可以传slot然后在template里写
// 需是hooks写法函数中有return避免失去响应性
export function useColumns() {
const columns: TableColumnList = [
{
label: "日期",
prop: "date",
cellRenderer: ({ row }) => (
<div style="display: flex; align-items: center">
<iconify-icon-online icon="ep:timer" />
<span style="margin-left: 10px">{row.date}</span>
</div>
)
},
{
label: "姓名",
prop: "name",
cellRenderer: ({ row }) => (
<el-popover effect="light" trigger="hover" placement="top" width="auto">
{{
default: () => (
<>
<div>name: {row.name}</div>
<div>address: {row.address}</div>
</>
),
reference: () => <el-tag>{row.name}</el-tag>
}}
</el-popover>
)
},
{
label: "地址",
prop: "address"
},
{
label: "操作",
cellRenderer: ({ index, row }) => (
<>
<el-button size="small" onClick={() => handleEdit(index + 1, row)}>
Edit
</el-button>
<el-button
size="small"
type="danger"
onClick={() => handleDelete(index + 1, row)}
>
Delete
</el-button>
</>
)
}
];
const handleEdit = (index: number, row) => {
message.success(`您编辑了第 ${index} 行,数据为:${JSON.stringify(row)}`);
};
const handleDelete = (index: number, row) => {
message.error(`您删除了第 ${index} 行,数据为:${JSON.stringify(row)}`);
};
return {
columns,
tableData
};
}

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, tableData } = useColumns();
</script>
<template>
<pure-table :data="tableData" :columns="columns" />
</template>

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
import { tableData } from "./data";
const indexMethod = (index: number) => {
return index * 2;
};
const columns: TableColumnList = [
{
type: "index",
index: indexMethod
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
</script>
<template>
<pure-table :data="tableData" :columns="columns" />
</template>

View File

@@ -0,0 +1,285 @@
import dayjs from "dayjs";
import { clone } from "@pureadmin/utils";
const date = dayjs(new Date()).format("YYYY-MM-DD");
const tableData = [
{
date,
name: "Tom",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Jack",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Dick",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Harry",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Sam",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Lucy",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Mary",
address: "No. 189, Grove St, Los Angeles"
},
{
date,
name: "Mike",
address: "No. 189, Grove St, Los Angeles"
}
];
const cloneData = clone(tableData, true);
const tableDataMore = cloneData.map(item =>
Object.assign(item, {
state: "California",
city: "Los Angeles",
"post-code": "CA 90036"
})
);
const tableDataSortable = cloneData.map((item, index) =>
Object.assign(item, {
date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
})
);
const tableDataExpand = [
{
date: "2016-05-03",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
},
{
date: "2016-05-02",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
},
{
date: "2016-05-04",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
},
{
date: "2016-05-01",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
},
{
date: "2016-05-08",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
},
{
date: "2016-05-06",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
},
{
date: "2016-05-07",
name: "Tom",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114",
family: [
{
name: "Jerry",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Spike",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
},
{
name: "Tyke",
state: "California",
city: "San Francisco",
address: "3650 21st St, San Francisco",
zip: "CA 94114"
}
]
}
];
export { tableData, tableDataMore, tableDataSortable, tableDataExpand };

View File

@@ -0,0 +1,72 @@
<script setup lang="ts">
import { ref } from "vue";
import { tableDataExpand } from "./data";
const parentBorder = ref(false);
const childBorder = ref(false);
const columns: TableColumnList = [
{
type: "expand",
slot: "expand"
},
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
}
];
const childColumns: TableColumnList = [
{
label: "Name",
prop: "name"
},
{
label: "State",
prop: "state"
},
{
label: "City",
prop: "city"
},
{
label: "Address",
prop: "address"
},
{
label: "Zip",
prop: "zip"
}
];
</script>
<template>
<div>
switch parent border: <el-switch v-model="parentBorder" /> switch child
border: <el-switch v-model="childBorder" />
<pure-table
:data="tableDataExpand"
:columns="columns"
:border="parentBorder"
>
<template #expand="{ row }">
<div class="m-4">
<p class="mb-2">State: {{ row.state }}</p>
<p class="mb-2">City: {{ row.city }}</p>
<p class="mb-2">Address: {{ row.address }}</p>
<p class="mb-4">Zip: {{ row.zip }}</p>
<h3>Family</h3>
<pure-table
:data="row.family"
:columns="childColumns"
:border="childBorder"
/>
</div>
</template>
</pure-table>
</div>
</template>

View File

@@ -0,0 +1,104 @@
<script setup lang="ts">
import { ref } from "vue";
const tableRef = ref();
const clearFilter = val => {
const { clearFilter } = tableRef.value.getTableRef();
clearFilter(val);
};
const resetDateFilter = () => {
clearFilter(["date"]);
};
const filterTag = (value, row) => {
return row.tag === value;
};
const filterHandler = (value, row, column) => {
const property = column["property"];
return row[property] === value;
};
const columns: TableColumnList = [
{
label: "日期",
prop: "date",
sortable: true,
columnKey: "date",
filters: [
{ text: "2016-05-01", value: "2016-05-01" },
{ text: "2016-05-02", value: "2016-05-02" },
{ text: "2016-05-03", value: "2016-05-03" },
{ text: "2016-05-04", value: "2016-05-04" }
],
filterMethod: filterHandler
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
},
{
label: "标签",
prop: "tag",
filters: [
{ text: "Home", value: "Home" },
{ text: "Office", value: "Office" }
],
filterMethod: filterTag,
filterPlacement: "bottom-end",
slot: "tag"
}
];
const tableData = [
{
date: "2016-05-03",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
tag: "Home"
},
{
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
tag: "Office"
},
{
date: "2016-05-04",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
tag: "Home"
},
{
date: "2016-05-01",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
tag: "Office"
}
];
</script>
<template>
<div>
<el-button @click="resetDateFilter">reset date filter</el-button>
<el-button @click="clearFilter">reset all filters</el-button>
<pure-table
ref="tableRef"
row-key="date"
:data="tableData"
:columns="columns"
>
<template #tag="{ row }">
<el-tag :type="row.tag === 'Home' ? '' : 'success'" disable-transitions>
{{ row.tag }}
</el-tag>
</template>
</pure-table>
</div>
</template>

View File

@@ -0,0 +1,79 @@
<script setup lang="ts">
import { tableDataMore } from "./data";
const props = withDefaults(
defineProps<{
height?: string;
}>(),
{
height: null
}
);
const columns: TableColumnList = [
{
label: "日期",
prop: "date",
width: "260",
fixed: true
},
{
label: "姓名",
prop: "name",
width: "260"
},
{
label: "地区",
prop: "state",
width: "260"
},
{
label: "城市",
prop: "city",
width: "260"
},
{
label: "地址",
prop: "address",
width: "260"
},
{
label: "邮编",
prop: "post-code",
width: "260"
},
{
label: "操作",
width: "120",
fixed: "right",
slot: "operation"
}
];
function handleClick(row) {
console.log(
"%crow===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
row
);
}
</script>
<template>
<pure-table
:data="
props.height
? tableDataMore.concat(tableDataMore).concat(tableDataMore)
: tableDataMore
"
:columns="columns"
:height="props.height"
>
<template #operation="{ row }">
<el-button link type="primary" size="small" @click="handleClick(row)">
Detail
</el-button>
<el-button link type="primary" size="small">Edit</el-button>
</template>
</pure-table>
</template>

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
import { tableData } from "./data";
const columns: TableColumnList = [
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
}
];
</script>
<template>
<pure-table
:data="tableData.concat(tableData).concat(tableData)"
:columns="columns"
height="360"
/>
</template>

View File

@@ -0,0 +1,84 @@
<script setup lang="ts">
import { ref } from "vue";
import dayjs from "dayjs";
import { tableDataMore } from "./data";
const columns: TableColumnList = [
{
label: "日期",
prop: "date",
width: "260",
fixed: true
},
{
label: "姓名",
prop: "name",
width: "260"
},
{
label: "地区",
prop: "state",
width: "260"
},
{
label: "城市",
prop: "city",
width: "260"
},
{
label: "地址",
prop: "address",
width: "260"
},
{
label: "邮编",
prop: "post-code",
width: "260"
},
{
label: "操作",
width: "120",
fixed: "right",
slot: "operation"
}
];
const now = new Date();
const tableData = ref(tableDataMore);
const deleteRow = (index: number) => {
tableData.value.splice(index, 1);
};
const onAddItem = () => {
now.setDate(now.getDate() + 1);
tableData.value.push({
date: dayjs(now).format("YYYY-MM-DD"),
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
state: "California",
city: "Los Angeles",
"post-code": "CA 90036"
});
};
</script>
<template>
<div>
<pure-table :data="tableData" :columns="columns" maxHeight="500">
<template #operation="{ $index }">
<el-button
link
type="primary"
size="small"
@click.prevent="deleteRow($index)"
>
Remove
</el-button>
</template>
</pure-table>
<el-button class="mt-4" style="width: 100%" @click="onAddItem">
Add Item
</el-button>
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { tableDataMore } from "./data";
const columns: TableColumnList = [
{
label: "日期",
prop: "date",
fixed: true
},
{
label: "姓名",
prop: "name",
children: [
{
label: "地区",
children: [
{
label: "城市",
prop: "city"
},
{
label: "地址",
prop: "address"
}
]
}
]
},
{
label: "邮编",
prop: "post-code"
}
];
</script>
<template>
<pure-table :data="tableDataMore" :columns="columns" alignWhole="center" />
</template>

View File

@@ -0,0 +1,70 @@
import { message } from "@pureadmin/components";
import { tableData } from "../data";
import { ref, computed } from "vue";
// 如果您不习惯tsx写法可以传slot然后在template里写
// 需是hooks写法函数中有return避免失去响应性
export function useColumns() {
const search = ref("");
const filterTableData = computed(() =>
tableData.filter(
data =>
!search.value ||
data.name.toLowerCase().includes(search.value.toLowerCase())
)
);
const handleEdit = (index: number, row) => {
message.success(`您编辑了第 ${index} 行,数据为:${JSON.stringify(row)}`);
};
const handleDelete = (index: number, row) => {
message.error(`您删除了第 ${index} 行,数据为:${JSON.stringify(row)}`);
};
const columns: TableColumnList = [
{
label: "日期",
prop: "date"
},
{
label: "姓名",
prop: "name"
},
{
label: "地址",
prop: "address"
},
{
align: "right",
// 自定义表头
headerRenderer: () => (
<el-input
v-model={search.value}
size="small"
clearable
placeholder="Type to search"
/>
),
cellRenderer: ({ index, row }) => (
<>
<el-button size="small" onClick={() => handleEdit(index + 1, row)}>
Edit
</el-button>
<el-button
size="small"
type="danger"
onClick={() => handleDelete(index + 1, row)}
>
Delete
</el-button>
</>
)
}
];
return {
columns,
filterTableData
};
}

View File

@@ -0,0 +1,9 @@
<script setup lang="ts">
import { useColumns } from "./columns";
const { columns, filterTableData } = useColumns();
</script>
<template>
<pure-table :data="filterTableData" :columns="columns" />
</template>

View File

@@ -0,0 +1,43 @@
import Base from "./base.vue";
import Stripe from "./stripe.vue";
import Border from "./border.vue";
import Status from "./status.vue";
import FixHeader from "./fixHeader.vue";
import FixColumn from "./fixColumn.vue";
import FluidHeight from "./fluidHeight.vue";
import GroupHeader from "./groupHeader.vue";
import Radio from "./radio.vue";
import MultipleChoice from "./multipleChoice.vue";
import Sortable from "./sortable.vue";
import Filters from "./filters.vue";
import ColumnTemplate from "./column-template/index.vue";
import HeaderRenderer from "./header-renderer/index.vue";
import Expand from "./expand.vue";
import TreeTable from "./tree.vue";
import TotalRow from "./totalRow.vue";
import Merge from "./merge.vue";
import CustomIndex from "./customIndex.vue";
import Layout from "./layout.vue";
export {
Base,
Stripe,
Border,
Status,
FixHeader,
FixColumn,
FluidHeight,
GroupHeader,
Radio,
MultipleChoice,
Sortable,
Filters,
ColumnTemplate,
HeaderRenderer,
Expand,
TreeTable,
TotalRow,
Merge,
CustomIndex,
Layout
};

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