mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-09 13:53:38 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3701161022 | ||
|
|
e3898df731 | ||
|
|
32172220f7 | ||
|
|
fcdfe6d0c0 | ||
|
|
67bc933d5c | ||
|
|
feb1532549 | ||
|
|
1722ee7a9b | ||
|
|
710e119397 | ||
|
|
f21d9f38e5 | ||
|
|
727c0fe3c0 | ||
|
|
e3fda52801 | ||
|
|
37762e45fd | ||
|
|
d43316f7c9 | ||
|
|
6971ba6c53 | ||
|
|
a175cf9fe0 | ||
|
|
9927e6f217 | ||
|
|
bc300eab18 | ||
|
|
3ca4729421 | ||
|
|
dfaa76cc29 | ||
|
|
7103b04283 | ||
|
|
d2ddb49314 | ||
|
|
a4a042bfd7 | ||
|
|
a9a8115d46 | ||
|
|
3676014eb6 | ||
|
|
52910602ff | ||
|
|
a2d1cf0e5f | ||
|
|
8e886e83e7 |
34
.github/workflows/preview.yml
vendored
Normal file
34
.github/workflows/preview.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: preview
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [12.x]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: "16"
|
||||||
|
registry-url: https://registry.npmjs.com/
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: run deploy.sh
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: pnpm install && pnpm deploy
|
||||||
@@ -1,3 +1,17 @@
|
|||||||
|
# 3.1.0 (2022-3-3)
|
||||||
|
|
||||||
|
### 🎫 Feat
|
||||||
|
|
||||||
|
- iframe supports dynamic loading
|
||||||
|
- Watermark example
|
||||||
|
- Print examples (pictures, tables, echarts)
|
||||||
|
- Add running and packaging information, use `lodash-unified` to replace `lodash-es`, `lodash-unified` supports `ESM` and is compatible with `CJS`
|
||||||
|
|
||||||
|
### 🐞 Bug fixes
|
||||||
|
|
||||||
|
- Fixed jumping to another menu page alone in one menu page, the routing page jumped but the tab page was not displayed
|
||||||
|
- Fixed the route that returns dynamic level 3 and above in the background, and the menu does not correspond to the page
|
||||||
|
|
||||||
# 3.0 (2022-2-14)
|
# 3.0 (2022-2-14)
|
||||||
|
|
||||||
### 🎫 Feat
|
### 🎫 Feat
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,3 +1,17 @@
|
|||||||
|
# 3.1.0 (2022-3-3)
|
||||||
|
|
||||||
|
### 🎫 Feat
|
||||||
|
|
||||||
|
- iframe supports dynamic loading
|
||||||
|
- Watermark example
|
||||||
|
- Print examples (pictures, tables, echarts)
|
||||||
|
- Add running and packaging information, use `lodash-unified` to replace `lodash-es`, `lodash-unified` supports `ESM` and is compatible with `CJS`
|
||||||
|
|
||||||
|
### 🐞 Bug fixes
|
||||||
|
|
||||||
|
- Fixed jumping to another menu page alone in one menu page, the routing page jumped but the tab page was not displayed
|
||||||
|
- Fixed the route that returns dynamic level 3 and above in the background, and the menu does not correspond to the page
|
||||||
|
|
||||||
# 3.0 (2022-2-14)
|
# 3.0 (2022-2-14)
|
||||||
|
|
||||||
### 🎫 Feat
|
### 🎫 Feat
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
# 3.1.0 (2022-3-3)
|
||||||
|
|
||||||
|
### 🎫 Feat
|
||||||
|
|
||||||
|
- iframe 支持动态加载
|
||||||
|
- 水印示例
|
||||||
|
- 打印示例(图片、表格、echarts)
|
||||||
|
- 添加运行、打包信息, 使用`lodash-unified`替换`lodash-es`,`lodash-unified`支持`ESM`同时兼容`CJS`
|
||||||
|
|
||||||
|
### 🐞 Bug fixes
|
||||||
|
|
||||||
|
- 修复在一个菜单页面内单独跳转到另一个菜单页面,路由页面跳转了但是标签页不显示的情况
|
||||||
|
- 修复后台返回动态三级及以上的路由,出现菜单与页面不对应的情况
|
||||||
|
|
||||||
# 3.0 (2022-2-14)
|
# 3.0 (2022-2-14)
|
||||||
|
|
||||||
### 🎫 Feat
|
### 🎫 Feat
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ vue-pure-admin is a free and open source middle and back-end template. Using the
|
|||||||
|
|
||||||
## Preview
|
## Preview
|
||||||
|
|
||||||
- [vue-pure-admin](http://yiming_chang.gitee.io/manages)
|
- [vue-pure-admin](https://vue-pure-admin.vercel.app)
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b4857fc7eb7d4c0f8deeefc644c1f7dd~tplv-k3u1fbpfcp-watermark.awebp?">
|
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b4857fc7eb7d4c0f8deeefc644c1f7dd~tplv-k3u1fbpfcp-watermark.awebp?">
|
||||||
@@ -46,7 +46,7 @@ Open the project in Gitpod (free online dev environment for GitHub) and start co
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/xiaoxian521/vue-pure-admin.git
|
git clone https://github.com/xiaoxian521/vue-pure-admin.git
|
||||||
or
|
or
|
||||||
git clone https://github.com.cnpmjs.org/xiaoxian521/vue-pure-admin.git
|
git clone https://gitee.com/yiming_chang/vue-pure-admin.git
|
||||||
```
|
```
|
||||||
|
|
||||||
- Installation dependencies
|
- Installation dependencies
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3
|
|||||||
|
|
||||||
## 预览
|
## 预览
|
||||||
|
|
||||||
- [vue-pure-admin](http://yiming_chang.gitee.io/manages)
|
- [vue-pure-admin](https://vue-pure-admin.vercel.app)
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b4857fc7eb7d4c0f8deeefc644c1f7dd~tplv-k3u1fbpfcp-watermark.awebp?">
|
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b4857fc7eb7d4c0f8deeefc644c1f7dd~tplv-k3u1fbpfcp-watermark.awebp?">
|
||||||
@@ -46,7 +46,7 @@ vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/xiaoxian521/vue-pure-admin.git
|
git clone https://github.com/xiaoxian521/vue-pure-admin.git
|
||||||
or
|
or
|
||||||
git clone https://github.com.cnpmjs.org/xiaoxian521/vue-pure-admin.git
|
git clone https://gitee.com/yiming_chang/vue-pure-admin.git
|
||||||
```
|
```
|
||||||
|
|
||||||
- 安装依赖
|
- 安装依赖
|
||||||
|
|||||||
85
build/info.ts
Normal file
85
build/info.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { readdir, stat } from "fs";
|
||||||
|
import type { Plugin } from "vite";
|
||||||
|
import dayjs, { Dayjs } from "dayjs";
|
||||||
|
import { sum } from "lodash-unified";
|
||||||
|
import duration from "dayjs/plugin/duration";
|
||||||
|
import { green, blue, bold } from "picocolors";
|
||||||
|
dayjs.extend(duration);
|
||||||
|
|
||||||
|
const staticPath = "dist";
|
||||||
|
const fileListTotal: number[] = [];
|
||||||
|
|
||||||
|
const recursiveDirectory = (folder: string, callback: Function): void => {
|
||||||
|
readdir(folder, (err, files: string[]) => {
|
||||||
|
if (err) throw err;
|
||||||
|
let count = 0;
|
||||||
|
const checkEnd = () => {
|
||||||
|
++count == files.length && callback();
|
||||||
|
};
|
||||||
|
files.forEach((item: string) => {
|
||||||
|
stat(folder + "/" + item, async (err, stats) => {
|
||||||
|
if (err) throw err;
|
||||||
|
if (stats.isFile()) {
|
||||||
|
fileListTotal.push(stats.size);
|
||||||
|
checkEnd();
|
||||||
|
} else if (stats.isDirectory()) {
|
||||||
|
recursiveDirectory(`${staticPath}/${item}/`, checkEnd);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
files.length === 0 && callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatBytes = (a: number, b?: number): string => {
|
||||||
|
if (0 == a) return "0 Bytes";
|
||||||
|
const c = 1024,
|
||||||
|
d = b || 2,
|
||||||
|
e = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
|
||||||
|
f = Math.floor(Math.log(a) / Math.log(c));
|
||||||
|
return parseFloat((a / Math.pow(c, f)).toFixed(d)) + " " + e[f];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function viteBuildInfo(): Plugin {
|
||||||
|
let config: { command: string };
|
||||||
|
let startTime: Dayjs;
|
||||||
|
let endTime: Dayjs;
|
||||||
|
return {
|
||||||
|
name: "vite:buildInfo",
|
||||||
|
configResolved(resolvedConfig: { command: string }) {
|
||||||
|
config = resolvedConfig;
|
||||||
|
},
|
||||||
|
buildStart() {
|
||||||
|
console.log(
|
||||||
|
bold(
|
||||||
|
green(
|
||||||
|
`👏欢迎使用${blue(
|
||||||
|
"[vue-pure-admin]"
|
||||||
|
)},如果您感觉不错,记得点击后面链接给个star哦💖 https://github.com/xiaoxian521/vue-pure-admin`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (config.command === "build") {
|
||||||
|
startTime = dayjs(new Date());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeBundle() {
|
||||||
|
if (config.command === "build") {
|
||||||
|
endTime = dayjs(new Date());
|
||||||
|
recursiveDirectory(staticPath, () => {
|
||||||
|
console.log(
|
||||||
|
bold(
|
||||||
|
green(
|
||||||
|
`恭喜打包完成🎉(总用时${dayjs
|
||||||
|
.duration(endTime.diff(startTime))
|
||||||
|
.format("mm分ss秒")},打包后的大小为${formatBytes(
|
||||||
|
sum(fileListTotal)
|
||||||
|
)})`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import vue from "@vitejs/plugin-vue";
|
import vue from "@vitejs/plugin-vue";
|
||||||
|
import { viteBuildInfo } from "./info";
|
||||||
import svgLoader from "vite-svg-loader";
|
import svgLoader from "vite-svg-loader";
|
||||||
import legacy from "@vitejs/plugin-legacy";
|
import legacy from "@vitejs/plugin-legacy";
|
||||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||||
@@ -21,6 +22,7 @@ export function getPluginsList(command, VITE_LEGACY) {
|
|||||||
WindiCSS(),
|
WindiCSS(),
|
||||||
// 线上环境删除console
|
// 线上环境删除console
|
||||||
removeConsole(),
|
removeConsole(),
|
||||||
|
viteBuildInfo(),
|
||||||
// 修改layout文件夹下的文件时自动重载浏览器 解决 https://github.com/xiaoxian521/vue-pure-admin/issues/170
|
// 修改layout文件夹下的文件时自动重载浏览器 解决 https://github.com/xiaoxian521/vue-pure-admin/issues/170
|
||||||
liveReload(["src/layout/**/*", "src/router/**/*"]),
|
liveReload(["src/layout/**/*", "src/router/**/*"]),
|
||||||
// 自定义主题
|
// 自定义主题
|
||||||
|
|||||||
30
deploy.sh
Normal file
30
deploy.sh
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# Replace packaging path
|
||||||
|
sed -i "s#VITE_PUBLIC_PATH = /#VITE_PUBLIC_PATH = /vue-pure-admin/#g" $(pwd)/.env.production
|
||||||
|
|
||||||
|
# Make sure the script throws the error encountered
|
||||||
|
set -e
|
||||||
|
|
||||||
|
pnpm build
|
||||||
|
cd dist
|
||||||
|
touch README.md .nojekyll
|
||||||
|
|
||||||
|
# deploy to github
|
||||||
|
if [ -z "$GITHUB_TOKEN" ]; then
|
||||||
|
msg='deploy'
|
||||||
|
githubUrl=git@github.com:xiaoxian521/vue-pure-admin.git
|
||||||
|
else
|
||||||
|
msg='ci: Automatic deployment from github actions'
|
||||||
|
githubUrl=https://xiaoxian521:${GITHUB_TOKEN}@github.com/xiaoxian521/vue-pure-admin.git
|
||||||
|
git config --global user.name "xiaoxian521"
|
||||||
|
git config --global user.email "1923740402@qq.com"
|
||||||
|
fi
|
||||||
|
git init
|
||||||
|
git add -A
|
||||||
|
git commit -m "${msg}"
|
||||||
|
# Push to github gh-pages branch
|
||||||
|
git push -f $githubUrl master:gh-pages
|
||||||
|
|
||||||
|
cd -
|
||||||
|
rm -rf dist
|
||||||
14
index.html
14
index.html
@@ -14,20 +14,16 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<style>
|
<style>
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body,
|
||||||
|
#app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: "Reggae One", cursive;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader,
|
.loader,
|
||||||
@@ -53,6 +49,8 @@
|
|||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
-webkit-animation-delay: -0.16s;
|
-webkit-animation-delay: -0.16s;
|
||||||
animation-delay: -0.16s;
|
animation-delay: -0.16s;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.loader:before,
|
.loader:before,
|
||||||
@@ -96,7 +94,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="loader">Loading...</div>
|
<div class="loader"></div>
|
||||||
</div>
|
</div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const permissionRouter = {
|
|||||||
title: "menus.permission",
|
title: "menus.permission",
|
||||||
icon: "lollipop",
|
icon: "lollipop",
|
||||||
i18n: true,
|
i18n: true,
|
||||||
rank: 3
|
rank: 7
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@@ -64,6 +64,46 @@ const permissionRouter = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const frameRouter = {
|
||||||
|
path: "/iframe",
|
||||||
|
name: "reFrame",
|
||||||
|
redirect: "/iframe/pure",
|
||||||
|
meta: {
|
||||||
|
icon: "monitor",
|
||||||
|
title: "menus.hsExternalPage",
|
||||||
|
i18n: true,
|
||||||
|
rank: 10
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/iframe/pure",
|
||||||
|
name: "reFramePure",
|
||||||
|
meta: {
|
||||||
|
i18n: true,
|
||||||
|
title: "menus.hsPureDocument",
|
||||||
|
frameSrc: "https://pure-admin-doc.vercel.app"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/external",
|
||||||
|
name: "https://pure-admin-doc.vercel.app",
|
||||||
|
meta: {
|
||||||
|
title: "menus.externalLink",
|
||||||
|
i18n: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/iframe/ep",
|
||||||
|
name: "reFrameEp",
|
||||||
|
meta: {
|
||||||
|
i18n: true,
|
||||||
|
title: "menus.hsEpDocument",
|
||||||
|
frameSrc: "https://element-plus.gitee.io/zh-CN/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
const tabsRouter = {
|
const tabsRouter = {
|
||||||
path: "/tabs",
|
path: "/tabs",
|
||||||
name: "reTabs",
|
name: "reTabs",
|
||||||
@@ -72,7 +112,7 @@ const tabsRouter = {
|
|||||||
icon: "IF-team-icontabs",
|
icon: "IF-team-icontabs",
|
||||||
title: "menus.hstabs",
|
title: "menus.hstabs",
|
||||||
i18n: true,
|
i18n: true,
|
||||||
rank: 8
|
rank: 11
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@@ -113,6 +153,7 @@ export default [
|
|||||||
code: 0,
|
code: 0,
|
||||||
info: [
|
info: [
|
||||||
tabsRouter,
|
tabsRouter,
|
||||||
|
frameRouter,
|
||||||
systemRouter,
|
systemRouter,
|
||||||
setDifAuthority("v-admin", permissionRouter)
|
setDifAuthority("v-admin", permissionRouter)
|
||||||
]
|
]
|
||||||
|
|||||||
31
package.json
31
package.json
@@ -1,16 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-pure-admin",
|
"name": "vue-pure-admin",
|
||||||
"version": "3.0",
|
"version": "3.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
|
||||||
"node": ">= 16",
|
|
||||||
"pnpm": ">= 6"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env --max_old_space_size=4096 vite",
|
"dev": "cross-env --max_old_space_size=4096 vite",
|
||||||
"serve": "pnpm dev",
|
"serve": "pnpm dev",
|
||||||
"build": "rimraf dist && cross-env vite build",
|
"build": "rimraf dist && cross-env vite build",
|
||||||
"report": "rimraf dist && cross-env vite build",
|
"report": "rimraf dist && cross-env vite build",
|
||||||
|
"deploy": "bash deploy.sh",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"preview:build": "pnpm build && vite preview",
|
"preview:build": "pnpm build && vite preview",
|
||||||
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install",
|
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install",
|
||||||
@@ -43,10 +40,11 @@
|
|||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"driver.js": "^0.9.8",
|
"driver.js": "^0.9.8",
|
||||||
"echarts": "^5.3.0",
|
"echarts": "^5.3.0",
|
||||||
"element-plus": "^2.0.2",
|
"element-plus": "^2.0.3",
|
||||||
"element-resize-detector": "^1.2.3",
|
"element-resize-detector": "^1.2.3",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lodash-unified": "^1.0.2",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
@@ -60,10 +58,10 @@
|
|||||||
"vue": "^3.2.31",
|
"vue": "^3.2.31",
|
||||||
"vue-i18n": "^9.2.0-beta.30",
|
"vue-i18n": "^9.2.0-beta.30",
|
||||||
"vue-json-pretty": "^2.0.2",
|
"vue-json-pretty": "^2.0.2",
|
||||||
"vue-router": "^4.0.12",
|
"vue-router": "^4.0.13",
|
||||||
"vue-types": "^4.1.1",
|
"vue-types": "^4.1.1",
|
||||||
"vuedraggable": "4.1.0",
|
"vuedraggable": "4.1.0",
|
||||||
"vxe-table": "^4.1.18",
|
"vxe-table": "^4.1.21",
|
||||||
"wangeditor": "^4.7.9",
|
"wangeditor": "^4.7.9",
|
||||||
"xe-utils": "^3.5.2",
|
"xe-utils": "^3.5.2",
|
||||||
"xgplayer": "2.28.0"
|
"xgplayer": "2.28.0"
|
||||||
@@ -78,15 +76,16 @@
|
|||||||
"@iconify/vue": "^3.1.3",
|
"@iconify/vue": "^3.1.3",
|
||||||
"@types/element-resize-detector": "1.1.3",
|
"@types/element-resize-detector": "1.1.3",
|
||||||
"@types/js-cookie": "^3.0.1",
|
"@types/js-cookie": "^3.0.1",
|
||||||
|
"@types/lodash-es": "^4.17.6",
|
||||||
"@types/mockjs": "1.0.3",
|
"@types/mockjs": "1.0.3",
|
||||||
"@types/node": "14.14.14",
|
"@types/node": "14.14.14",
|
||||||
"@types/nprogress": "0.2.0",
|
"@types/nprogress": "0.2.0",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/qs": "^6.9.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
||||||
"@typescript-eslint/parser": "^5.10.2",
|
"@typescript-eslint/parser": "^5.10.2",
|
||||||
"@vitejs/plugin-legacy": "^1.7.0",
|
"@vitejs/plugin-legacy": "^1.7.1",
|
||||||
"@vitejs/plugin-vue": "^2.2.0",
|
"@vitejs/plugin-vue": "^2.2.4",
|
||||||
"@vitejs/plugin-vue-jsx": "^1.3.4",
|
"@vitejs/plugin-vue-jsx": "^1.3.8",
|
||||||
"@vue/eslint-config-prettier": "^7.0.0",
|
"@vue/eslint-config-prettier": "^7.0.0",
|
||||||
"@vue/eslint-config-typescript": "^10.0.0",
|
"@vue/eslint-config-typescript": "^10.0.0",
|
||||||
"@zougt/vite-plugin-theme-preprocessor": "^1.4.4",
|
"@zougt/vite-plugin-theme-preprocessor": "^1.4.4",
|
||||||
@@ -95,8 +94,10 @@
|
|||||||
"eslint": "^8.8.0",
|
"eslint": "^8.8.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-vue": "^8.4.1",
|
"eslint-plugin-vue": "^8.4.1",
|
||||||
|
"font-awesome": "^4.7.0",
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"lint-staged": "11.1.2",
|
"lint-staged": "11.1.2",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
"postcss": "^8.4.6",
|
"postcss": "^8.4.6",
|
||||||
"postcss-html": "^1.3.0",
|
"postcss-html": "^1.3.0",
|
||||||
"postcss-import": "14.0.0",
|
"postcss-import": "14.0.0",
|
||||||
@@ -104,7 +105,7 @@
|
|||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"pretty-quick": "3.1.1",
|
"pretty-quick": "3.1.1",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"rollup-plugin-visualizer": "^5.5.4",
|
"rollup-plugin-visualizer": "^5.6.0",
|
||||||
"sass": "^1.49.7",
|
"sass": "^1.49.7",
|
||||||
"sass-loader": "^12.4.0",
|
"sass-loader": "^12.4.0",
|
||||||
"stylelint": "^14.3.0",
|
"stylelint": "^14.3.0",
|
||||||
@@ -115,15 +116,15 @@
|
|||||||
"stylelint-order": "^5.0.0",
|
"stylelint-order": "^5.0.0",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.5.5",
|
||||||
"unplugin-element-plus": "^0.2.0",
|
"unplugin-element-plus": "^0.2.0",
|
||||||
"vite": "2.7.13",
|
"vite": "^2.8.6",
|
||||||
"vite-plugin-live-reload": "^2.1.0",
|
"vite-plugin-live-reload": "^2.1.0",
|
||||||
"vite-plugin-mock": "^2.9.6",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
"vite-plugin-remove-console": "^0.0.6",
|
"vite-plugin-remove-console": "^0.0.6",
|
||||||
"vite-plugin-style-import": "1.4.1",
|
"vite-plugin-style-import": "1.4.1",
|
||||||
"vite-plugin-windicss": "^1.7.0",
|
"vite-plugin-windicss": "^1.8.2",
|
||||||
"vite-svg-loader": "2.2.0",
|
"vite-svg-loader": "2.2.0",
|
||||||
"vue-eslint-parser": "^8.2.0",
|
"vue-eslint-parser": "^8.2.0",
|
||||||
"windicss": "^3.4.3"
|
"windicss": "^3.5.1"
|
||||||
},
|
},
|
||||||
"repository": "git@github.com:xiaoxian521/vue-pure-admin.git",
|
"repository": "git@github.com:xiaoxian521/vue-pure-admin.git",
|
||||||
"author": "xiaoxian521",
|
"author": "xiaoxian521",
|
||||||
|
|||||||
458
pnpm-lock.yaml
generated
458
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"Version": "3.0",
|
"Version": "3.1.0",
|
||||||
"Title": "PureAdmin",
|
"Title": "PureAdmin",
|
||||||
"FixedHeader": true,
|
"FixedHeader": true,
|
||||||
"HiddenSideBar": false,
|
"HiddenSideBar": false,
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
font-size: 25px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-container p {
|
.control-container p {
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
import { iconType } from "./types";
|
||||||
import { h, defineComponent, Component } from "vue";
|
import { h, defineComponent, Component } from "vue";
|
||||||
import { IconifyIconOffline, FontIcon } from "../index";
|
import { IconifyIconOffline, FontIcon } from "../index";
|
||||||
|
|
||||||
// 支持fontawesome4、5+、iconfont、remixicon、element-plus的icons、自定义svg
|
/**
|
||||||
export function useRenderIcon(icon: string): Component {
|
* 支持fontawesome4、5+、iconfont、remixicon、element-plus的icons、自定义svg
|
||||||
|
* @param icon 必传 string 图标
|
||||||
|
* @param attrs 可选 iconType 属性
|
||||||
|
* @returns Component
|
||||||
|
*/
|
||||||
|
export function useRenderIcon(icon: string, attrs?: iconType): Component {
|
||||||
// iconfont
|
// iconfont
|
||||||
const ifReg = /^IF-/;
|
const ifReg = /^IF-/;
|
||||||
// typeof icon === "function" 属于SVG
|
// typeof icon === "function" 属于SVG
|
||||||
@@ -19,7 +25,8 @@ export function useRenderIcon(icon: string): Component {
|
|||||||
render() {
|
render() {
|
||||||
return h(FontIcon, {
|
return h(FontIcon, {
|
||||||
icon: iconName,
|
icon: iconName,
|
||||||
iconType
|
iconType,
|
||||||
|
...attrs
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -31,7 +38,8 @@ export function useRenderIcon(icon: string): Component {
|
|||||||
name: "Icon",
|
name: "Icon",
|
||||||
render() {
|
render() {
|
||||||
return h(IconifyIconOffline, {
|
return h(IconifyIconOffline, {
|
||||||
icon: icon
|
icon: icon,
|
||||||
|
...attrs
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ import Location from "@iconify-icons/ep/location";
|
|||||||
import Tickets from "@iconify-icons/ep/tickets";
|
import Tickets from "@iconify-icons/ep/tickets";
|
||||||
import OfficeBuilding from "@iconify-icons/ep/office-building";
|
import OfficeBuilding from "@iconify-icons/ep/office-building";
|
||||||
import Notebook from "@iconify-icons/ep/notebook";
|
import Notebook from "@iconify-icons/ep/notebook";
|
||||||
|
import Rank from "@iconify-icons/ep/rank";
|
||||||
|
import videoPlay from "@iconify-icons/ep/video-play";
|
||||||
|
import Monitor from "@iconify-icons/ep/monitor";
|
||||||
addIcon("check", Check);
|
addIcon("check", Check);
|
||||||
addIcon("menu", Menu);
|
addIcon("menu", Menu);
|
||||||
addIcon("home-filled", HomeFilled);
|
addIcon("home-filled", HomeFilled);
|
||||||
@@ -46,16 +49,23 @@ addIcon("location", Location);
|
|||||||
addIcon("tickets", Tickets);
|
addIcon("tickets", Tickets);
|
||||||
addIcon("office-building", OfficeBuilding);
|
addIcon("office-building", OfficeBuilding);
|
||||||
addIcon("notebook", Notebook);
|
addIcon("notebook", Notebook);
|
||||||
|
addIcon("video-play", videoPlay);
|
||||||
|
addIcon("rank", Rank);
|
||||||
|
addIcon("monitor", Monitor);
|
||||||
|
|
||||||
// remixicon
|
// remixicon
|
||||||
import arrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
|
import arrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
|
||||||
import arrowLeftSLine from "@iconify-icons/ri/arrow-left-s-line";
|
import arrowLeftSLine from "@iconify-icons/ri/arrow-left-s-line";
|
||||||
import logoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
|
import logoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
|
||||||
import nodeTree from "@iconify-icons/ri/node-tree";
|
import nodeTree from "@iconify-icons/ri/node-tree";
|
||||||
|
import ubuntuFill from "@iconify-icons/ri/ubuntu-fill";
|
||||||
|
import questionLine from "@iconify-icons/ri/question-line";
|
||||||
addIcon("arrow-right-s-line", arrowRightSLine);
|
addIcon("arrow-right-s-line", arrowRightSLine);
|
||||||
addIcon("arrow-left-s-line", arrowLeftSLine);
|
addIcon("arrow-left-s-line", arrowLeftSLine);
|
||||||
addIcon("logout-circle-r-line", logoutCircleRLine);
|
addIcon("logout-circle-r-line", logoutCircleRLine);
|
||||||
addIcon("node-tree", nodeTree);
|
addIcon("node-tree", nodeTree);
|
||||||
|
addIcon("ubuntu-fill", ubuntuFill);
|
||||||
|
addIcon("question-line", questionLine);
|
||||||
|
|
||||||
// Font Awesome 4
|
// Font Awesome 4
|
||||||
import faUser from "@iconify-icons/fa/user";
|
import faUser from "@iconify-icons/fa/user";
|
||||||
|
|||||||
18
src/components/ReIcon/src/types.ts
Normal file
18
src/components/ReIcon/src/types.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export interface iconType {
|
||||||
|
// iconify (https://docs.iconify.design/icon-components/vue/#properties)
|
||||||
|
inline?: boolean;
|
||||||
|
width?: string | number;
|
||||||
|
height?: string | number;
|
||||||
|
horizontalFlip?: boolean;
|
||||||
|
verticalFlip?: boolean;
|
||||||
|
flip?: string;
|
||||||
|
rotate?: number | string;
|
||||||
|
color?: string;
|
||||||
|
horizontalAlign?: boolean;
|
||||||
|
verticalAlign?: boolean;
|
||||||
|
align?: string;
|
||||||
|
onLoad?: Function;
|
||||||
|
|
||||||
|
// all icon
|
||||||
|
style?: object;
|
||||||
|
}
|
||||||
@@ -19,10 +19,6 @@ type resultType = {
|
|||||||
info: Array<undefined>;
|
info: Array<undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface mapInter {
|
|
||||||
loading: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
let MarkerCluster;
|
let MarkerCluster;
|
||||||
let map: MapConfigureInter;
|
let map: MapConfigureInter;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
defineComponent,
|
defineComponent,
|
||||||
getCurrentInstance
|
getCurrentInstance
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import { RouterView } from "vue-router";
|
|
||||||
import backTop from "/@/assets/svg/back_top.svg?component";
|
import backTop from "/@/assets/svg/back_top.svg?component";
|
||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
getCurrentInstance
|
getCurrentInstance
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import rgbHex from "rgb-hex";
|
import rgbHex from "rgb-hex";
|
||||||
import { find } from "lodash-es";
|
import { find } from "lodash-unified";
|
||||||
import { getConfig } from "/@/config";
|
import { getConfig } from "/@/config";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import panel from "../panel/index.vue";
|
import panel from "../panel/index.vue";
|
||||||
@@ -111,7 +111,7 @@ function storageConfigureChange<T>(key: string, val: T): void {
|
|||||||
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
|
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
|
||||||
const targetEl = target || document.body;
|
const targetEl = target || document.body;
|
||||||
let { className } = targetEl;
|
let { className } = targetEl;
|
||||||
className = className.replace(clsName, "");
|
className = className.replace(clsName, "").trim();
|
||||||
targetEl.className = flag ? `${className} ${clsName} ` : className;
|
targetEl.className = flag ? `${className} ${clsName} ` : className;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { isEqual } from "lodash-es";
|
import { isEqual } from "lodash-unified";
|
||||||
import { transformI18n } from "/@/plugins/i18n";
|
import { transformI18n } from "/@/plugins/i18n";
|
||||||
import { getParentPaths, findRouteByPath } from "/@/router/utils";
|
import { getParentPaths, findRouteByPath } from "/@/router/utils";
|
||||||
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
|
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
menuSelect(route.path, routers);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function translationCh() {
|
function translationCh() {
|
||||||
instance.locale = { locale: "zh" };
|
instance.locale = { locale: "zh" };
|
||||||
locale.value = "zh";
|
locale.value = "zh";
|
||||||
|
|||||||
@@ -111,6 +111,10 @@ function hasOneShowingChild(
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (showingChildren[0]?.meta?.showParent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (showingChildren.length === 1) {
|
if (showingChildren.length === 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ onBeforeMount(() => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
() => getSubMenuData(route.path)
|
() => {
|
||||||
|
getSubMenuData(route.path);
|
||||||
|
menuSelect(route.path, routers);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ import closeRight from "/@/assets/svg/close_right.svg?component";
|
|||||||
|
|
||||||
import { emitter } from "/@/utils/mitt";
|
import { emitter } from "/@/utils/mitt";
|
||||||
import { $t as t } from "/@/plugins/i18n";
|
import { $t as t } from "/@/plugins/i18n";
|
||||||
import { isEqual, isEmpty } from "lodash-es";
|
|
||||||
import { transformI18n } from "/@/plugins/i18n";
|
import { transformI18n } from "/@/plugins/i18n";
|
||||||
import { storageLocal } from "/@/utils/storage";
|
import { storageLocal } from "/@/utils/storage";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { isEqual, isEmpty } from "lodash-unified";
|
||||||
import { RouteConfigs, tagsViewsType } from "../../types";
|
import { RouteConfigs, tagsViewsType } from "../../types";
|
||||||
import { useSettingStoreHook } from "/@/store/modules/settings";
|
import { useSettingStoreHook } from "/@/store/modules/settings";
|
||||||
import { handleAliveRoute, delAliveRoutes } from "/@/router/utils";
|
import { handleAliveRoute, delAliveRoutes } from "/@/router/utils";
|
||||||
|
|||||||
63
src/layout/frameView.vue
Normal file
63
src/layout/frameView.vue
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div class="frame" v-loading="loading">
|
||||||
|
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef"></iframe>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { ref, unref, onMounted, nextTick } from "vue";
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const currentRoute = useRoute();
|
||||||
|
const frameSrc = ref<string>("");
|
||||||
|
const frameRef = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
if (unref(currentRoute.meta)?.frameSrc) {
|
||||||
|
frameSrc.value = unref(currentRoute.meta)?.frameSrc as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideLoading() {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
nextTick(() => {
|
||||||
|
const iframe = unref(frameRef);
|
||||||
|
if (!iframe) return;
|
||||||
|
const _frame = iframe as any;
|
||||||
|
if (_frame.attachEvent) {
|
||||||
|
_frame.attachEvent("onload", () => {
|
||||||
|
hideLoading();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
iframe.onload = () => {
|
||||||
|
hideLoading();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loading.value = true;
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.frame {
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 998;
|
||||||
|
|
||||||
|
.frame-iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,6 +5,7 @@ import { routeMetaType } from "../types";
|
|||||||
import { transformI18n } from "/@/plugins/i18n";
|
import { transformI18n } from "/@/plugins/i18n";
|
||||||
import { storageSession } from "/@/utils/storage";
|
import { storageSession } from "/@/utils/storage";
|
||||||
import { useAppStoreHook } from "/@/store/modules/app";
|
import { useAppStoreHook } from "/@/store/modules/app";
|
||||||
|
import { remainingPaths } from "/@/router/modules/index";
|
||||||
import { Title } from "../../../public/serverConfig.json";
|
import { Title } from "../../../public/serverConfig.json";
|
||||||
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
|
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ export function useNav() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function menuSelect(indexPath: string, routers): void {
|
function menuSelect(indexPath: string, routers): void {
|
||||||
|
if (isRemaining(indexPath)) return;
|
||||||
let parentPath = "";
|
let parentPath = "";
|
||||||
const parentPathIndex = indexPath.lastIndexOf("/");
|
const parentPathIndex = indexPath.lastIndexOf("/");
|
||||||
if (parentPathIndex > 0) {
|
if (parentPathIndex > 0) {
|
||||||
@@ -93,6 +95,11 @@ export function useNav() {
|
|||||||
findCurrentRoute(indexPath, routers);
|
findCurrentRoute(indexPath, routers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断路径是否参与菜单
|
||||||
|
function isRemaining(path: string): boolean {
|
||||||
|
return remainingPaths.includes(path);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
logout,
|
logout,
|
||||||
backHome,
|
backHome,
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
<template>
|
|
||||||
<router-view>
|
|
||||||
<template #default="{ Component, route }">
|
|
||||||
<transition appear name="fade-transform" mode="out-in">
|
|
||||||
<component :is="Component" :key="route.fullPath" />
|
|
||||||
</transition>
|
|
||||||
</template>
|
|
||||||
</router-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: "layoutParentView"
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -67,6 +67,7 @@ export type childrenType = {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
i18n?: boolean;
|
i18n?: boolean;
|
||||||
|
showParent?: boolean;
|
||||||
extraIcon?: {
|
extraIcon?: {
|
||||||
svg?: boolean;
|
svg?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
|||||||
10
src/main.ts
10
src/main.ts
@@ -37,14 +37,10 @@ app.component("IconifyIconOnline", IconifyIconOnline);
|
|||||||
app.component("FontIcon", FontIcon);
|
app.component("FontIcon", FontIcon);
|
||||||
|
|
||||||
getServerConfig(app).then(async config => {
|
getServerConfig(app).then(async config => {
|
||||||
|
app.use(router);
|
||||||
|
await router.isReady();
|
||||||
injectResponsiveStorage(app, config);
|
injectResponsiveStorage(app, config);
|
||||||
setupStore(app);
|
setupStore(app);
|
||||||
app
|
app.use(MotionPlugin).use(useElementPlus).use(useTable).use(usI18n);
|
||||||
.use(router)
|
|
||||||
.use(MotionPlugin)
|
|
||||||
.use(useElementPlus)
|
|
||||||
.use(useTable)
|
|
||||||
.use(usI18n);
|
|
||||||
await router.isReady();
|
|
||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ import {
|
|||||||
ElCollapse,
|
ElCollapse,
|
||||||
ElCollapseItem,
|
ElCollapseItem,
|
||||||
ElTreeV2,
|
ElTreeV2,
|
||||||
|
ElTable,
|
||||||
|
ElTableColumn,
|
||||||
|
ElLink,
|
||||||
|
ElColorPicker,
|
||||||
|
ElSelect,
|
||||||
|
ElOption,
|
||||||
// 指令
|
// 指令
|
||||||
ElLoading,
|
ElLoading,
|
||||||
ElInfiniteScroll
|
ElInfiniteScroll
|
||||||
@@ -96,7 +102,13 @@ const components = [
|
|||||||
ElEmpty,
|
ElEmpty,
|
||||||
ElCollapse,
|
ElCollapse,
|
||||||
ElCollapseItem,
|
ElCollapseItem,
|
||||||
ElTreeV2
|
ElTreeV2,
|
||||||
|
ElTable,
|
||||||
|
ElTableColumn,
|
||||||
|
ElLink,
|
||||||
|
ElColorPicker,
|
||||||
|
ElSelect,
|
||||||
|
ElOption
|
||||||
];
|
];
|
||||||
|
|
||||||
export function useElementPlus(app: App) {
|
export function useElementPlus(app: App) {
|
||||||
|
|||||||
@@ -32,7 +32,14 @@ export default {
|
|||||||
permissionPage: "Page Permission",
|
permissionPage: "Page Permission",
|
||||||
permissionButton: "Button Permission",
|
permissionButton: "Button Permission",
|
||||||
hstabs: "Tabs Operate",
|
hstabs: "Tabs Operate",
|
||||||
hsMenuTree: "Menu Tree",
|
|
||||||
hsguide: "Guide",
|
hsguide: "Guide",
|
||||||
externalLink: "External Link"
|
hsAble: "Able",
|
||||||
|
hsMenuTree: "Menu Tree",
|
||||||
|
hsWatermark: "Water Mark",
|
||||||
|
hsPrint: "Print",
|
||||||
|
hsExternalPage: "External Page",
|
||||||
|
hsPureDocument: "Pure Doc(Embedded)",
|
||||||
|
externalLink: "Pure Doc(External)",
|
||||||
|
hsEpDocument: "Element Plus Doc(Embedded)",
|
||||||
|
hsAbout: "About"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// 多组件库的国际化和本地项目国际化兼容
|
// 多组件库的国际化和本地项目国际化兼容
|
||||||
import { App } from "vue";
|
import { App } from "vue";
|
||||||
import { set } from "lodash-es";
|
import { set } from "lodash-unified";
|
||||||
import { createI18n } from "vue-i18n";
|
import { createI18n } from "vue-i18n";
|
||||||
import { localesConfigs } from "./config";
|
import { localesConfigs } from "./config";
|
||||||
import { storageLocal } from "/@/utils/storage";
|
import { storageLocal } from "/@/utils/storage";
|
||||||
|
|||||||
@@ -32,7 +32,14 @@ export default {
|
|||||||
permissionPage: "页面权限",
|
permissionPage: "页面权限",
|
||||||
permissionButton: "按钮权限",
|
permissionButton: "按钮权限",
|
||||||
hstabs: "标签页操作",
|
hstabs: "标签页操作",
|
||||||
hsMenuTree: "菜单树结构",
|
|
||||||
hsguide: "引导页",
|
hsguide: "引导页",
|
||||||
externalLink: "外链"
|
hsAble: "功能",
|
||||||
|
hsMenuTree: "菜单树结构",
|
||||||
|
hsWatermark: "水印",
|
||||||
|
hsPrint: "打印",
|
||||||
|
hsExternalPage: "外部页面",
|
||||||
|
hsPureDocument: "平台文档(内嵌)",
|
||||||
|
externalLink: "平台文档(外链)",
|
||||||
|
hsEpDocument: "Element Plus文档(内嵌)",
|
||||||
|
hsAbout: "关于"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import "xe-utils";
|
import "xe-utils";
|
||||||
import { App } from "vue";
|
import { App } from "vue";
|
||||||
import { i18n } from "../i18n/index";
|
import { i18n } from "../i18n/index";
|
||||||
|
import "font-awesome/css/font-awesome.min.css";
|
||||||
import {
|
import {
|
||||||
// 核心
|
// 核心
|
||||||
VXETable,
|
VXETable,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { isUrl } from "/@/utils/is";
|
||||||
import { toRouteType } from "./types";
|
import { toRouteType } from "./types";
|
||||||
import { openLink } from "/@/utils/link";
|
import { openLink } from "/@/utils/link";
|
||||||
import NProgress from "/@/utils/progress";
|
import NProgress from "/@/utils/progress";
|
||||||
import { constantRoutes } from "./modules";
|
import { constantRoutes } from "./modules";
|
||||||
import { split, findIndex } from "lodash-es";
|
import { findIndex } from "lodash-unified";
|
||||||
import { transformI18n } from "/@/plugins/i18n";
|
import { transformI18n } from "/@/plugins/i18n";
|
||||||
import remainingRouter from "./modules/remaining";
|
import remainingRouter from "./modules/remaining";
|
||||||
import { storageSession } from "/@/utils/storage";
|
import { storageSession } from "/@/utils/storage";
|
||||||
@@ -52,7 +53,7 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
|||||||
}
|
}
|
||||||
const name = storageSession.getItem("info");
|
const name = storageSession.getItem("info");
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
const externalLink = to?.redirectedFrom?.fullPath;
|
const externalLink = isUrl(to?.name);
|
||||||
if (!externalLink)
|
if (!externalLink)
|
||||||
to.matched.some(item => {
|
to.matched.some(item => {
|
||||||
if (!item.meta.title) return "";
|
if (!item.meta.title) return "";
|
||||||
@@ -65,9 +66,9 @@ router.beforeEach((to: toRouteType, _from, next) => {
|
|||||||
});
|
});
|
||||||
if (name) {
|
if (name) {
|
||||||
if (_from?.name) {
|
if (_from?.name) {
|
||||||
// 如果路由包含http 则是超链接 反之是普通路由
|
// name为超链接
|
||||||
if (externalLink && externalLink.includes("http")) {
|
if (externalLink) {
|
||||||
openLink(`http${split(externalLink, "http")[1]}`);
|
openLink(to?.name);
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
|||||||
46
src/router/modules/able.ts
Normal file
46
src/router/modules/able.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { $t } from "/@/plugins/i18n";
|
||||||
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
|
const ableRouter = {
|
||||||
|
path: "/able",
|
||||||
|
name: "components",
|
||||||
|
component: Layout,
|
||||||
|
redirect: "/able/menuTree",
|
||||||
|
meta: {
|
||||||
|
icon: "ubuntu-fill",
|
||||||
|
title: $t("menus.hsAble"),
|
||||||
|
i18n: true,
|
||||||
|
rank: 3
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/able/menuTree",
|
||||||
|
name: "reMenuTree",
|
||||||
|
component: () => import("/@/views/able/menu-tree.vue"),
|
||||||
|
meta: {
|
||||||
|
title: $t("menus.hsMenuTree"),
|
||||||
|
i18n: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/able/watermark",
|
||||||
|
name: "reWatermark",
|
||||||
|
component: () => import("/@/views/able/watermark.vue"),
|
||||||
|
meta: {
|
||||||
|
title: $t("menus.hsWatermark"),
|
||||||
|
i18n: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/able/print",
|
||||||
|
name: "rePrint",
|
||||||
|
component: () => import("/@/views/able/print.vue"),
|
||||||
|
meta: {
|
||||||
|
title: $t("menus.hsPrint"),
|
||||||
|
i18n: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ableRouter;
|
||||||
28
src/router/modules/about.ts
Normal file
28
src/router/modules/about.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { $t } from "/@/plugins/i18n";
|
||||||
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
|
const aboutRouter = {
|
||||||
|
path: "/about",
|
||||||
|
name: "reAbout",
|
||||||
|
component: Layout,
|
||||||
|
redirect: "/about",
|
||||||
|
meta: {
|
||||||
|
icon: "question-line",
|
||||||
|
title: $t("menus.hsAbout"),
|
||||||
|
i18n: true,
|
||||||
|
rank: 12
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/about",
|
||||||
|
name: "reAbout",
|
||||||
|
component: () => import("/@/views/about.vue"),
|
||||||
|
meta: {
|
||||||
|
title: $t("menus.hsAbout"),
|
||||||
|
i18n: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default aboutRouter;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const componentsRouter = {
|
const componentsRouter = {
|
||||||
path: "/components",
|
path: "/components",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const editorRouter = {
|
const editorRouter = {
|
||||||
path: "/editor",
|
path: "/editor",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const errorRouter = {
|
const errorRouter = {
|
||||||
path: "/error",
|
path: "/error",
|
||||||
@@ -10,7 +10,7 @@ const errorRouter = {
|
|||||||
icon: "position",
|
icon: "position",
|
||||||
title: $t("menus.hserror"),
|
title: $t("menus.hserror"),
|
||||||
i18n: true,
|
i18n: true,
|
||||||
rank: 7
|
rank: 9
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
|
||||||
import Layout from "/@/layout/index.vue";
|
|
||||||
|
|
||||||
const externalLink = {
|
|
||||||
path: "/external",
|
|
||||||
name: "external",
|
|
||||||
component: Layout,
|
|
||||||
meta: {
|
|
||||||
icon: "link",
|
|
||||||
title: $t("menus.externalLink"),
|
|
||||||
i18n: true,
|
|
||||||
rank: 190
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "https://github.com/xiaoxian521/vue-pure-admin",
|
|
||||||
meta: {
|
|
||||||
title: $t("menus.externalLink"),
|
|
||||||
i18n: true,
|
|
||||||
rank: 191
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default externalLink;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const flowChartRouter = {
|
const flowChartRouter = {
|
||||||
path: "/flowChart",
|
path: "/flowChart",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const guideRouter = {
|
const guideRouter = {
|
||||||
path: "/guide",
|
path: "/guide",
|
||||||
@@ -10,7 +10,7 @@ const guideRouter = {
|
|||||||
icon: "guide",
|
icon: "guide",
|
||||||
title: $t("menus.hsguide"),
|
title: $t("menus.hsguide"),
|
||||||
i18n: true,
|
i18n: true,
|
||||||
rank: 10
|
rank: 11
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const homeRouter = {
|
const homeRouter = {
|
||||||
path: "/",
|
path: "/",
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// 静态路由
|
// 静态路由
|
||||||
|
import about from "./about";
|
||||||
import homeRouter from "./home";
|
import homeRouter from "./home";
|
||||||
|
import ableRouter from "./able";
|
||||||
import errorRouter from "./error";
|
import errorRouter from "./error";
|
||||||
import guideRouter from "./guide";
|
import guideRouter from "./guide";
|
||||||
import editorRouter from "./editor";
|
import editorRouter from "./editor";
|
||||||
import nestedRouter from "./nested";
|
import nestedRouter from "./nested";
|
||||||
import menuTreeRouter from "./menuTree";
|
|
||||||
import externalLink from "./externalLink";
|
|
||||||
import flowChartRouter from "./flowchart";
|
import flowChartRouter from "./flowchart";
|
||||||
import remainingRouter from "./remaining";
|
import remainingRouter from "./remaining";
|
||||||
import componentsRouter from "./components";
|
import componentsRouter from "./components";
|
||||||
@@ -20,13 +20,13 @@ import { buildHierarchyTree } from "/@/utils/tree";
|
|||||||
|
|
||||||
// 原始静态路由(未做任何处理)
|
// 原始静态路由(未做任何处理)
|
||||||
const routes = [
|
const routes = [
|
||||||
|
about,
|
||||||
homeRouter,
|
homeRouter,
|
||||||
|
ableRouter,
|
||||||
errorRouter,
|
errorRouter,
|
||||||
guideRouter,
|
guideRouter,
|
||||||
nestedRouter,
|
nestedRouter,
|
||||||
externalLink,
|
|
||||||
editorRouter,
|
editorRouter,
|
||||||
menuTreeRouter,
|
|
||||||
flowChartRouter,
|
flowChartRouter,
|
||||||
componentsRouter
|
componentsRouter
|
||||||
];
|
];
|
||||||
@@ -40,3 +40,8 @@ export const constantRoutes: Array<RouteRecordRaw> = formatTwoStageRoutes(
|
|||||||
export const constantMenus: Array<RouteComponent> = ascending(routes).concat(
|
export const constantMenus: Array<RouteComponent> = ascending(routes).concat(
|
||||||
...remainingRouter
|
...remainingRouter
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 不参与菜单的路由
|
||||||
|
export const remainingPaths = Object.keys(remainingRouter).map(v => {
|
||||||
|
return remainingRouter[v].path;
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
|
||||||
import Layout from "/@/layout/index.vue";
|
|
||||||
|
|
||||||
const menuTreeRouter = {
|
|
||||||
path: "/menuTree",
|
|
||||||
name: "reMenuTree",
|
|
||||||
component: Layout,
|
|
||||||
redirect: "/menuTree/index",
|
|
||||||
meta: {
|
|
||||||
icon: "node-tree",
|
|
||||||
title: $t("menus.hsMenuTree"),
|
|
||||||
i18n: true,
|
|
||||||
rank: 9
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "/menuTree/index",
|
|
||||||
name: "reMenuTree",
|
|
||||||
component: () => import("/@/views/menu-tree/index.vue"),
|
|
||||||
meta: {
|
|
||||||
title: $t("menus.hsMenuTree"),
|
|
||||||
i18n: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
export default menuTreeRouter;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const nestedRouter = {
|
const nestedRouter = {
|
||||||
path: "/nested",
|
path: "/nested",
|
||||||
@@ -10,12 +10,11 @@ const nestedRouter = {
|
|||||||
title: $t("menus.hsmenus"),
|
title: $t("menus.hsmenus"),
|
||||||
icon: "histogram",
|
icon: "histogram",
|
||||||
i18n: true,
|
i18n: true,
|
||||||
rank: 5
|
rank: 8
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/nested/menu1",
|
path: "/nested/menu1",
|
||||||
component: () => import("/@/layout/routerView/parent.vue"),
|
|
||||||
name: "Menu1",
|
name: "Menu1",
|
||||||
meta: {
|
meta: {
|
||||||
title: $t("menus.hsmenu1"),
|
title: $t("menus.hsmenu1"),
|
||||||
@@ -36,7 +35,6 @@ const nestedRouter = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/nested/menu1/menu1-2",
|
path: "/nested/menu1/menu1-2",
|
||||||
component: () => import("/@/layout/routerView/parent.vue"),
|
|
||||||
name: "Menu1-2",
|
name: "Menu1-2",
|
||||||
redirect: "/nested/menu1/menu1-2/menu1-2-1",
|
redirect: "/nested/menu1/menu1-2/menu1-2-1",
|
||||||
meta: {
|
meta: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { $t } from "/@/plugins/i18n";
|
import { $t } from "/@/plugins/i18n";
|
||||||
import Layout from "/@/layout/index.vue";
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
|
||||||
const remainingRouter = [
|
const remainingRouter = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ import {
|
|||||||
} from "vue-router";
|
} from "vue-router";
|
||||||
import { router } from "./index";
|
import { router } from "./index";
|
||||||
import { loadEnv } from "../../build";
|
import { loadEnv } from "../../build";
|
||||||
import Layout from "/@/layout/index.vue";
|
|
||||||
import { useTimeoutFn } from "@vueuse/core";
|
import { useTimeoutFn } from "@vueuse/core";
|
||||||
import { RouteConfigs } from "/@/layout/types";
|
import { RouteConfigs } from "/@/layout/types";
|
||||||
|
import { buildHierarchyTree } from "/@/utils/tree";
|
||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
||||||
|
const Layout = () => import("/@/layout/index.vue");
|
||||||
|
const IFrame = () => import("/@/layout/frameView.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}");
|
||||||
|
|
||||||
@@ -125,6 +127,10 @@ function initRouter(name: string) {
|
|||||||
// 最终路由进行升序
|
// 最终路由进行升序
|
||||||
ascending(router.options.routes[0].children);
|
ascending(router.options.routes[0].children);
|
||||||
if (!router.hasRoute(v?.name)) router.addRoute(v);
|
if (!router.hasRoute(v?.name)) router.addRoute(v);
|
||||||
|
const flattenRouters = router
|
||||||
|
.getRoutes()
|
||||||
|
.find(n => n.path === "/");
|
||||||
|
router.addRoute(flattenRouters);
|
||||||
}
|
}
|
||||||
resolve(router);
|
resolve(router);
|
||||||
}
|
}
|
||||||
@@ -146,14 +152,15 @@ function initRouter(name: string) {
|
|||||||
*/
|
*/
|
||||||
function formatFlatteningRoutes(routesList: RouteRecordRaw[]) {
|
function formatFlatteningRoutes(routesList: RouteRecordRaw[]) {
|
||||||
if (routesList.length === 0) return routesList;
|
if (routesList.length === 0) return routesList;
|
||||||
for (let i = 0; i < routesList.length; i++) {
|
let hierarchyList = buildHierarchyTree(routesList);
|
||||||
if (routesList[i].children) {
|
for (let i = 0; i < hierarchyList.length; i++) {
|
||||||
routesList = routesList
|
if (hierarchyList[i].children) {
|
||||||
|
hierarchyList = hierarchyList
|
||||||
.slice(0, i + 1)
|
.slice(0, i + 1)
|
||||||
.concat(routesList[i].children, routesList.slice(i + 1));
|
.concat(hierarchyList[i].children, hierarchyList.slice(i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return routesList;
|
return hierarchyList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,6 +223,8 @@ function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>) {
|
|||||||
arrRoutes.forEach((v: RouteRecordRaw) => {
|
arrRoutes.forEach((v: RouteRecordRaw) => {
|
||||||
if (v.redirect) {
|
if (v.redirect) {
|
||||||
v.component = Layout;
|
v.component = Layout;
|
||||||
|
} else if (v.meta?.frameSrc) {
|
||||||
|
v.component = IFrame;
|
||||||
} else {
|
} else {
|
||||||
const index = modulesRoutesKeys.findIndex(ev => ev.includes(v.path));
|
const index = modulesRoutesKeys.findIndex(ev => ev.includes(v.path));
|
||||||
v.component = modulesRoutes[modulesRoutesKeys[index]];
|
v.component = modulesRoutes[modulesRoutesKeys[index]];
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { store } from "/@/store";
|
import { store } from "/@/store";
|
||||||
import { isEqual } from "lodash-es";
|
import { isUrl } from "/@/utils/is";
|
||||||
|
import { isEqual } from "lodash-unified";
|
||||||
import { storageLocal } from "/@/utils/storage";
|
import { storageLocal } from "/@/utils/storage";
|
||||||
import { multiType, positionType } from "./types";
|
import { multiType, positionType } from "./types";
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ export const useMultiTagsStore = defineStore({
|
|||||||
case "push":
|
case "push":
|
||||||
{
|
{
|
||||||
const tagVal = value as multiType;
|
const tagVal = value as multiType;
|
||||||
|
if (isUrl(tagVal?.name)) return;
|
||||||
const tagPath = tagVal?.path;
|
const tagPath = tagVal?.path;
|
||||||
// 判断tag是否已存在
|
// 判断tag是否已存在
|
||||||
const tagHasExits = this.multiTags.some(tag => {
|
const tagHasExits = this.multiTags.some(tag => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { store } from "/@/store";
|
import { store } from "/@/store";
|
||||||
import { cacheType } from "./types";
|
import { cacheType } from "./types";
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from "lodash-unified";
|
||||||
import { RouteConfigs } from "/@/layout/types";
|
import { RouteConfigs } from "/@/layout/types";
|
||||||
import { constantMenus } from "/@/router/modules";
|
import { constantMenus } from "/@/router/modules";
|
||||||
import { ascending, filterTree } from "/@/router/utils";
|
import { ascending, filterTree } from "/@/router/utils";
|
||||||
|
|||||||
@@ -38,14 +38,16 @@
|
|||||||
|
|
||||||
/* 动态改变cssvar 用于主题切换 https://github.com/element-plus/element-plus/issues/4856#issuecomment-1000174357 */
|
/* 动态改变cssvar 用于主题切换 https://github.com/element-plus/element-plus/issues/4856#issuecomment-1000174357 */
|
||||||
.el-button--primary {
|
.el-button--primary {
|
||||||
--el-button-bg-color: var(--el-color-primary) !important;
|
|
||||||
--el-button-border-color: var(--el-color-primary) !important;
|
|
||||||
--el-button-hover-bg-color: var(--el-color-primary-light-2) !important;
|
|
||||||
--el-button-hover-border-color: var(--el-color-primary-light-2) !important;
|
|
||||||
--el-button-active-bg-color: var(--el-color-primary-active) !important;
|
--el-button-active-bg-color: var(--el-color-primary-active) !important;
|
||||||
--el-button-active-border-color: var(--el-color-primary-active) !important;
|
--el-button-active-border-color: var(--el-color-primary-active) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* button--primary plain */
|
||||||
|
.el-button--primary.is-plain {
|
||||||
|
--el-button-active-bg-color: var(--el-color-primary) !important;
|
||||||
|
--el-button-active-border-color: var(--el-color-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* nprogress适配ep的primary */
|
/* nprogress适配ep的primary */
|
||||||
#nprogress {
|
#nprogress {
|
||||||
& .bar {
|
& .bar {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
text-rendering: optimizelegibility;
|
text-rendering: optimizelegibility;
|
||||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
|
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
|
||||||
Microsoft YaHei, Arial, sans-serif;
|
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@@ -22,6 +22,11 @@ html {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,16 +23,6 @@
|
|||||||
margin-left: $sideBarWidth;
|
margin-left: $sideBarWidth;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #f0f2f5;
|
background: #f0f2f5;
|
||||||
@media screen and (min-width: 150px) and (max-width: 420px) {
|
|
||||||
.app-main .el-scrollbar__view:first-child {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 420px) {
|
|
||||||
.app-main .el-scrollbar__view:first-child {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-header {
|
.fixed-header {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
resultType,
|
resultType,
|
||||||
PureHttpError,
|
PureHttpError,
|
||||||
RequestMethods,
|
RequestMethods,
|
||||||
PureHttpResoponse,
|
PureHttpResponse,
|
||||||
PureHttpRequestConfig
|
PureHttpRequestConfig
|
||||||
} from "./types.d";
|
} from "./types.d";
|
||||||
import qs from "qs";
|
import qs from "qs";
|
||||||
@@ -91,7 +91,7 @@ class PureHttp {
|
|||||||
private httpInterceptorsResponse(): void {
|
private httpInterceptorsResponse(): void {
|
||||||
const instance = PureHttp.axiosInstance;
|
const instance = PureHttp.axiosInstance;
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
(response: PureHttpResoponse) => {
|
(response: PureHttpResponse) => {
|
||||||
const $config = response.config;
|
const $config = response.config;
|
||||||
// 关闭进度条动画
|
// 关闭进度条动画
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
@@ -145,21 +145,21 @@ class PureHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 单独抽离的post工具函数
|
// 单独抽离的post工具函数
|
||||||
public post<T>(
|
public post<T, P>(
|
||||||
url: string,
|
url: string,
|
||||||
params?: T,
|
params?: T,
|
||||||
config?: PureHttpRequestConfig
|
config?: PureHttpRequestConfig
|
||||||
): Promise<T> {
|
): Promise<P> {
|
||||||
return this.request<T>("post", url, params, config);
|
return this.request<P>("post", url, params, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单独抽离的get工具函数
|
// 单独抽离的get工具函数
|
||||||
public get<T>(
|
public get<T, P>(
|
||||||
url: string,
|
url: string,
|
||||||
params?: T,
|
params?: T,
|
||||||
config?: PureHttpRequestConfig
|
config?: PureHttpRequestConfig
|
||||||
): Promise<T> {
|
): Promise<P> {
|
||||||
return this.request<T>("get", url, params, config);
|
return this.request<P>("get", url, params, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/utils/http/types.d.ts
vendored
16
src/utils/http/types.d.ts
vendored
@@ -18,13 +18,13 @@ export interface PureHttpError extends AxiosError {
|
|||||||
isCancelRequest?: boolean;
|
isCancelRequest?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PureHttpResoponse extends AxiosResponse {
|
export interface PureHttpResponse extends AxiosResponse {
|
||||||
config: PureHttpRequestConfig;
|
config: PureHttpRequestConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PureHttpRequestConfig extends AxiosRequestConfig {
|
export interface PureHttpRequestConfig extends AxiosRequestConfig {
|
||||||
beforeRequestCallback?: (request: PureHttpRequestConfig) => void;
|
beforeRequestCallback?: (request: PureHttpRequestConfig) => void;
|
||||||
beforeResponseCallback?: (response: PureHttpResoponse) => void;
|
beforeResponseCallback?: (response: PureHttpResponse) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PureHttp {
|
export default class PureHttp {
|
||||||
@@ -34,6 +34,14 @@ export default class PureHttp {
|
|||||||
param?: AxiosRequestConfig,
|
param?: AxiosRequestConfig,
|
||||||
axiosConfig?: PureHttpRequestConfig
|
axiosConfig?: PureHttpRequestConfig
|
||||||
): Promise<T>;
|
): Promise<T>;
|
||||||
post<T>(url: string, params?: T, config?: PureHttpRequestConfig): Promise<T>;
|
post<T, P>(
|
||||||
get<T>(url: string, params?: T, config?: PureHttpRequestConfig): Promise<T>;
|
url: string,
|
||||||
|
params?: T,
|
||||||
|
config?: PureHttpRequestConfig
|
||||||
|
): Promise<P>;
|
||||||
|
get<T, P>(
|
||||||
|
url: string,
|
||||||
|
params?: T,
|
||||||
|
config?: PureHttpRequestConfig
|
||||||
|
): Promise<P>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,8 +94,9 @@ export const isServer = typeof window === "undefined";
|
|||||||
|
|
||||||
export const isClient = !isServer;
|
export const isClient = !isServer;
|
||||||
|
|
||||||
export function isUrl(path: string): boolean {
|
export function isUrl<T>(path: T): boolean {
|
||||||
const reg =
|
const reg =
|
||||||
/(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
/(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
||||||
|
// @ts-expect-error
|
||||||
return reg.test(path);
|
return reg.test(path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export const openLink = (link: string) => {
|
export const openLink = <T>(link: T): void => {
|
||||||
const $a: HTMLElement = document.createElement("a");
|
const $a: HTMLElement = document.createElement("a");
|
||||||
|
// @ts-expect-error
|
||||||
$a.setAttribute("href", link);
|
$a.setAttribute("href", link);
|
||||||
$a.setAttribute("target", "_blank");
|
$a.setAttribute("target", "_blank");
|
||||||
$a.setAttribute("rel", "noreferrer noopener");
|
$a.setAttribute("rel", "noreferrer noopener");
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { FunctionArgs } from "@vueuse/core";
|
||||||
|
|
||||||
export const hasClass = (ele: RefType<any>, cls: string): any => {
|
export const hasClass = (ele: RefType<any>, cls: string): any => {
|
||||||
return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
|
return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
|
||||||
};
|
};
|
||||||
@@ -40,3 +42,16 @@ export const toggleClass = (
|
|||||||
className = className.replace(clsName, "");
|
className = className.replace(clsName, "");
|
||||||
targetEl.className = flag ? `${className} ${clsName} ` : className;
|
targetEl.className = flag ? `${className} ${clsName} ` : className;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function useRafThrottle<T extends FunctionArgs>(fn: T): T {
|
||||||
|
let locked = false;
|
||||||
|
// @ts-ignore
|
||||||
|
return function (...args) {
|
||||||
|
if (locked) return;
|
||||||
|
locked = true;
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
fn.apply(this, args);
|
||||||
|
locked = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
226
src/utils/print.ts
Normal file
226
src/utils/print.ts
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
interface PrintFunction {
|
||||||
|
extendOptions: Function;
|
||||||
|
getStyle: Function;
|
||||||
|
setDomHeight: Function;
|
||||||
|
toPrint: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Print = function (dom, options?: object): PrintFunction {
|
||||||
|
options = options || {};
|
||||||
|
// @ts-expect-error
|
||||||
|
if (!(this instanceof Print)) return new Print(dom, options);
|
||||||
|
this.conf = {
|
||||||
|
styleStr: "",
|
||||||
|
// Elements that need to dynamically get and set the height
|
||||||
|
setDomHeightArr: [],
|
||||||
|
// Echart dom List
|
||||||
|
echartDomArr: [],
|
||||||
|
// Callback before printing
|
||||||
|
printBeforeFn: null,
|
||||||
|
// Callback after printing
|
||||||
|
printDoneCallBack: null
|
||||||
|
};
|
||||||
|
for (const key in this.conf) {
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
if (key && options.hasOwnProperty(key)) {
|
||||||
|
this.conf[key] = options[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof dom === "string") {
|
||||||
|
this.dom = document.querySelector(dom);
|
||||||
|
} else {
|
||||||
|
this.dom = this.isDOM(dom) ? dom : dom.$el;
|
||||||
|
}
|
||||||
|
if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) {
|
||||||
|
this.setDomHeight(this.conf.setDomHeightArr);
|
||||||
|
}
|
||||||
|
this.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
Print.prototype = {
|
||||||
|
/**
|
||||||
|
* init
|
||||||
|
*/
|
||||||
|
init: function (): void {
|
||||||
|
const content = this.getStyle() + this.getHtml();
|
||||||
|
this.writeIframe(content);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Configuration property extension
|
||||||
|
* @param {Object} obj
|
||||||
|
* @param {Object} obj2
|
||||||
|
*/
|
||||||
|
extendOptions: function <T>(obj, obj2: T): T {
|
||||||
|
for (const k in obj2) {
|
||||||
|
obj[k] = obj2[k];
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
Copy all styles of the original page
|
||||||
|
*/
|
||||||
|
getStyle: function (): string {
|
||||||
|
let str = "";
|
||||||
|
const styles: NodeListOf<Element> = document.querySelectorAll("style,link");
|
||||||
|
for (let i = 0; i < styles.length; i++) {
|
||||||
|
str += styles[i].outerHTML;
|
||||||
|
}
|
||||||
|
str += `<style>.no-print{display:none;}${this.conf.styleStr}</style>`;
|
||||||
|
return str;
|
||||||
|
},
|
||||||
|
// form assignment
|
||||||
|
getHtml: function (): Element {
|
||||||
|
const inputs = document.querySelectorAll("input");
|
||||||
|
const selects = document.querySelectorAll("select");
|
||||||
|
const textareas = document.querySelectorAll("textarea");
|
||||||
|
for (let k = 0; k < inputs.length; k++) {
|
||||||
|
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
|
||||||
|
if (inputs[k].checked == true) {
|
||||||
|
inputs[k].setAttribute("checked", "checked");
|
||||||
|
} else {
|
||||||
|
inputs[k].removeAttribute("checked");
|
||||||
|
}
|
||||||
|
} else if (inputs[k].type == "text") {
|
||||||
|
inputs[k].setAttribute("value", inputs[k].value);
|
||||||
|
} else {
|
||||||
|
inputs[k].setAttribute("value", inputs[k].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let k2 = 0; k2 < textareas.length; k2++) {
|
||||||
|
if (textareas[k2].type == "textarea") {
|
||||||
|
textareas[k2].innerHTML = textareas[k2].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let k3 = 0; k3 < selects.length; k3++) {
|
||||||
|
if (selects[k3].type == "select-one") {
|
||||||
|
const child = selects[k3].children;
|
||||||
|
for (const i in child) {
|
||||||
|
if (child[i].tagName == "OPTION") {
|
||||||
|
// @ts-ignore
|
||||||
|
if (child[i].selected == true) {
|
||||||
|
child[i].setAttribute("selected", "selected");
|
||||||
|
} else {
|
||||||
|
child[i].removeAttribute("selected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dom.outerHTML;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
create iframe
|
||||||
|
*/
|
||||||
|
writeIframe: function (content) {
|
||||||
|
let w: Document | Window;
|
||||||
|
let doc: Document;
|
||||||
|
const iframe: HTMLIFrameElement = document.createElement("iframe");
|
||||||
|
const f: HTMLIFrameElement = document.body.appendChild(iframe);
|
||||||
|
iframe.id = "myIframe";
|
||||||
|
iframe.setAttribute(
|
||||||
|
"style",
|
||||||
|
"position:absolute;width:0;height:0;top:-10px;left:-10px;"
|
||||||
|
);
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
w = f.contentWindow || f.contentDocument;
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
doc = f.contentDocument || f.contentWindow.document;
|
||||||
|
doc.open();
|
||||||
|
doc.write(content);
|
||||||
|
doc.close();
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
|
const _this = this;
|
||||||
|
iframe.onload = function (): void {
|
||||||
|
// Before popping, callback
|
||||||
|
if (_this.conf.printBeforeFn) {
|
||||||
|
_this.conf.printBeforeFn({ doc });
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.drawEchartImg(doc).then(() => {
|
||||||
|
_this.toPrint(w);
|
||||||
|
setTimeout(function () {
|
||||||
|
document.body.removeChild(iframe);
|
||||||
|
// After popup, callback
|
||||||
|
if (_this.conf.printDoneCallBack) {
|
||||||
|
_this.conf.printDoneCallBack();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* echarts printing
|
||||||
|
* @param {Object} doc iframe window
|
||||||
|
*/
|
||||||
|
drawEchartImg(doc): Promise<void> {
|
||||||
|
return new Promise<void>(resolve => {
|
||||||
|
if (this.conf.echartDomArr && this.conf.echartDomArr.length > 0) {
|
||||||
|
this.conf.echartDomArr.forEach(e => {
|
||||||
|
const dom = doc.querySelector("#" + e.$el.id);
|
||||||
|
const img = new Image();
|
||||||
|
const w = dom.offsetWidth + "px";
|
||||||
|
const H = dom.offsetHeight + "px";
|
||||||
|
|
||||||
|
img.style.width = w;
|
||||||
|
img.style.height = H;
|
||||||
|
img.src = e.imgSrc;
|
||||||
|
dom.innerHTML = "";
|
||||||
|
dom.appendChild(img);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
Print
|
||||||
|
*/
|
||||||
|
toPrint: function (frameWindow): void {
|
||||||
|
try {
|
||||||
|
setTimeout(function () {
|
||||||
|
frameWindow.focus();
|
||||||
|
try {
|
||||||
|
if (!frameWindow.document.execCommand("print", false, null)) {
|
||||||
|
frameWindow.print();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
frameWindow.print();
|
||||||
|
}
|
||||||
|
frameWindow.close();
|
||||||
|
}, 10);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isDOM:
|
||||||
|
typeof HTMLElement === "object"
|
||||||
|
? function (obj) {
|
||||||
|
return obj instanceof HTMLElement;
|
||||||
|
}
|
||||||
|
: function (obj) {
|
||||||
|
return (
|
||||||
|
obj &&
|
||||||
|
typeof obj === "object" &&
|
||||||
|
obj.nodeType === 1 &&
|
||||||
|
typeof obj.nodeName === "string"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Set the height of the specified dom element by getting the existing height of the dom element and setting
|
||||||
|
* @param {Array} arr
|
||||||
|
*/
|
||||||
|
setDomHeight(arr) {
|
||||||
|
if (arr && arr.length) {
|
||||||
|
arr.forEach(name => {
|
||||||
|
const domArr = document.querySelectorAll(name);
|
||||||
|
domArr.forEach(dom => {
|
||||||
|
dom.style.height = dom.offsetHeight + "px";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Print;
|
||||||
116
src/utils/watermark.ts
Normal file
116
src/utils/watermark.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import {
|
||||||
|
ref,
|
||||||
|
Ref,
|
||||||
|
unref,
|
||||||
|
shallowRef,
|
||||||
|
onBeforeUnmount,
|
||||||
|
getCurrentInstance
|
||||||
|
} from "vue";
|
||||||
|
import { isDef } from "/@/utils/is";
|
||||||
|
import { useRafThrottle } from "/@/utils/operate";
|
||||||
|
import { addResizeListener, removeResizeListener } from "/@/utils/resize";
|
||||||
|
|
||||||
|
const domSymbol = Symbol("watermark-dom");
|
||||||
|
|
||||||
|
type attr = {
|
||||||
|
font?: string;
|
||||||
|
fillStyle?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useWatermark(
|
||||||
|
appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>
|
||||||
|
) {
|
||||||
|
const func = useRafThrottle(function () {
|
||||||
|
const el = unref(appendEl);
|
||||||
|
if (!el) return;
|
||||||
|
const { clientHeight: height, clientWidth: width } = el;
|
||||||
|
updateWatermark({ height, width });
|
||||||
|
});
|
||||||
|
const id = domSymbol.toString();
|
||||||
|
const watermarkEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
const domId = unref(watermarkEl);
|
||||||
|
watermarkEl.value = undefined;
|
||||||
|
const el = unref(appendEl);
|
||||||
|
if (!el) return;
|
||||||
|
domId && el.removeChild(domId);
|
||||||
|
removeResizeListener(el, func);
|
||||||
|
};
|
||||||
|
|
||||||
|
function createBase64(str: string, attr?: attr) {
|
||||||
|
const can = document.createElement("canvas");
|
||||||
|
const width = 300;
|
||||||
|
const height = 240;
|
||||||
|
Object.assign(can, { width, height });
|
||||||
|
|
||||||
|
const cans = can.getContext("2d");
|
||||||
|
if (cans) {
|
||||||
|
cans.rotate((-20 * Math.PI) / 120);
|
||||||
|
cans.font = attr?.font ?? "15px Reggae One";
|
||||||
|
cans.fillStyle = attr?.fillStyle ?? "rgba(0, 0, 0, 0.15)";
|
||||||
|
cans.textAlign = "left";
|
||||||
|
cans.textBaseline = "middle";
|
||||||
|
cans.fillText(str, width / 20, height);
|
||||||
|
}
|
||||||
|
return can.toDataURL("image/png");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWatermark(
|
||||||
|
options: {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
str?: string;
|
||||||
|
attr?: attr;
|
||||||
|
} = {}
|
||||||
|
) {
|
||||||
|
const el = unref(watermarkEl);
|
||||||
|
if (!el) return;
|
||||||
|
if (isDef(options.width)) {
|
||||||
|
el.style.width = `${options.width}px`;
|
||||||
|
}
|
||||||
|
if (isDef(options.height)) {
|
||||||
|
el.style.height = `${options.height}px`;
|
||||||
|
}
|
||||||
|
if (isDef(options.str)) {
|
||||||
|
el.style.background = `url(${createBase64(
|
||||||
|
options.str,
|
||||||
|
options.attr
|
||||||
|
)}) left top repeat`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createWatermark = (str: string, attr?: attr) => {
|
||||||
|
if (unref(watermarkEl)) {
|
||||||
|
updateWatermark({ str, attr });
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
const div = document.createElement("div");
|
||||||
|
watermarkEl.value = div;
|
||||||
|
div.id = id;
|
||||||
|
div.style.pointerEvents = "none";
|
||||||
|
div.style.top = "0px";
|
||||||
|
div.style.left = "0px";
|
||||||
|
div.style.position = "absolute";
|
||||||
|
div.style.zIndex = "100000";
|
||||||
|
const el = unref(appendEl);
|
||||||
|
if (!el) return id;
|
||||||
|
const { clientHeight: height, clientWidth: width } = el;
|
||||||
|
updateWatermark({ str, width, height, attr });
|
||||||
|
el.appendChild(div);
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
function setWatermark(str: string, attr?: attr) {
|
||||||
|
createWatermark(str, attr);
|
||||||
|
addResizeListener(document.documentElement, func);
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
if (instance) {
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { setWatermark, clear };
|
||||||
|
}
|
||||||
83
src/views/able/menu-tree.vue
Normal file
83
src/views/able/menu-tree.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: "reMenuTree"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
import type { ElTreeV2 } from "element-plus";
|
||||||
|
import { transformI18n } from "/@/plugins/i18n";
|
||||||
|
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
|
||||||
|
import { extractPathList, deleteChildren } from "/@/utils/tree";
|
||||||
|
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
||||||
|
import type { TreeNode } from "element-plus/es/components/tree-v2/src/types";
|
||||||
|
|
||||||
|
interface treeNode extends TreeNode {
|
||||||
|
meta: {
|
||||||
|
title: string;
|
||||||
|
i18n: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = ref("");
|
||||||
|
let dataProps = ref({
|
||||||
|
value: "uniqueId",
|
||||||
|
children: "children"
|
||||||
|
});
|
||||||
|
const treeRef = ref<InstanceType<typeof ElTreeV2>>();
|
||||||
|
|
||||||
|
let menusData = computed(() => {
|
||||||
|
return deleteChildren(usePermissionStoreHook().menusTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
let expandedKeys = extractPathList(menusData.value);
|
||||||
|
|
||||||
|
const onQueryChanged = (query: string) => {
|
||||||
|
// @ts-expect-error
|
||||||
|
treeRef.value!.filter(query);
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterMethod = (query: string, node: treeNode) => {
|
||||||
|
return transformI18n(node.meta.title, node.meta.i18n)!.indexOf(query) !== -1;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium"
|
||||||
|
>菜单树结构(采用element-plus的
|
||||||
|
<el-link
|
||||||
|
href="https://element-plus.gitee.io/zh-CN/component/tree-v2.html"
|
||||||
|
target="_blank"
|
||||||
|
:icon="useRenderIcon('node-tree')"
|
||||||
|
style="font-size: 16px; margin: 0 5px 4px 0"
|
||||||
|
>Tree V2</el-link
|
||||||
|
>组件并支持国际化)</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-input
|
||||||
|
class="mb-4"
|
||||||
|
v-model="query"
|
||||||
|
placeholder="请输入关键字查找"
|
||||||
|
clearable
|
||||||
|
@input="onQueryChanged"
|
||||||
|
></el-input>
|
||||||
|
<el-tree-v2
|
||||||
|
ref="treeRef"
|
||||||
|
:data="menusData"
|
||||||
|
:props="dataProps"
|
||||||
|
show-checkbox
|
||||||
|
:height="500"
|
||||||
|
:filter-method="filterMethod"
|
||||||
|
:default-expanded-keys="expandedKeys"
|
||||||
|
>
|
||||||
|
<template #default="{ data }">
|
||||||
|
<span>{{ $t(data.meta.title) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-tree-v2>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
329
src/views/able/print.vue
Normal file
329
src/views/able/print.vue
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Print from "/@/utils/print";
|
||||||
|
import { reactive, ref } from "vue";
|
||||||
|
import { VxeTablePropTypes } from "vxe-table";
|
||||||
|
import { ReLine } from "/@/components/ReCharts/index";
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
date: string;
|
||||||
|
name: string;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const demo1 = reactive({
|
||||||
|
tableData: [
|
||||||
|
{
|
||||||
|
id: 10001,
|
||||||
|
name: "Test1",
|
||||||
|
role: "Develop",
|
||||||
|
sex: "Man",
|
||||||
|
age: 28,
|
||||||
|
address: "test abc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10002,
|
||||||
|
name: "Test2",
|
||||||
|
role: "Test",
|
||||||
|
sex: "Women",
|
||||||
|
age: 22,
|
||||||
|
address: "Guangzhou"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10003,
|
||||||
|
name: "Test3",
|
||||||
|
role: "PM",
|
||||||
|
sex: "Man",
|
||||||
|
age: 32,
|
||||||
|
address: "Shanghai"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10004,
|
||||||
|
name: "Test4",
|
||||||
|
role: "Designer",
|
||||||
|
sex: "Women",
|
||||||
|
age: 24,
|
||||||
|
address: "Shanghai"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const value = ref("1");
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: "1",
|
||||||
|
el: ".el-table",
|
||||||
|
label: "Element-Plus Table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "2",
|
||||||
|
el: ".vxe-table",
|
||||||
|
label: "Vxe Table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "3",
|
||||||
|
el: ".echart",
|
||||||
|
label: "Echart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "4",
|
||||||
|
el: ".img",
|
||||||
|
label: "Image"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function onPrint() {
|
||||||
|
let el = options.filter(v => v.value === value.value)[0]?.el;
|
||||||
|
Print(el).toPrint;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerCellStyle: VxeTablePropTypes.HeaderCellStyle = ({ column }) => {
|
||||||
|
if (column.property === "name") {
|
||||||
|
return {
|
||||||
|
backgroundColor: "#f60",
|
||||||
|
color: "#ffffff"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rowStyle: VxeTablePropTypes.RowStyle = ({ rowIndex }) => {
|
||||||
|
if ([2, 3, 5].includes(rowIndex)) {
|
||||||
|
return {
|
||||||
|
backgroundColor: "red",
|
||||||
|
color: "#ffffff"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cellStyle: VxeTablePropTypes.CellStyle = ({ row, column }) => {
|
||||||
|
if (column.property === "sex") {
|
||||||
|
if (row.sex >= "1") {
|
||||||
|
return {
|
||||||
|
backgroundColor: "#187"
|
||||||
|
};
|
||||||
|
} else if (row.age === 26) {
|
||||||
|
return {
|
||||||
|
backgroundColor: "#2db7f5"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableRowClassName = ({ rowIndex }: { row: User; rowIndex: number }) => {
|
||||||
|
if (rowIndex === 1) {
|
||||||
|
return "warning-row";
|
||||||
|
} else if (rowIndex === 3) {
|
||||||
|
return "success-row";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
const tableData: User[] = [
|
||||||
|
{
|
||||||
|
date: "2016-05-03",
|
||||||
|
name: "Tom",
|
||||||
|
address: "No. 189, Grove St, Los Angeles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "2016-05-02",
|
||||||
|
name: "Tom",
|
||||||
|
address: "No. 189, Grove St, Los Angeles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "2016-05-04",
|
||||||
|
name: "Tom",
|
||||||
|
address: "No. 189, Grove St, Los Angeles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "2016-05-01",
|
||||||
|
name: "Tom",
|
||||||
|
address: "No. 189, Grove St, Los Angeles"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">打印功能(报表、图表、图片)</span>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
v-model="value"
|
||||||
|
class="m-2"
|
||||||
|
placeholder="Select"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-button size="small" type="primary" @click="onPrint"
|
||||||
|
>打印</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col
|
||||||
|
:xs="22"
|
||||||
|
:sm="22"
|
||||||
|
:md="11"
|
||||||
|
:lg="11"
|
||||||
|
:xl="11"
|
||||||
|
style="margin: 10px; border: 0.01rem solid var(--el-color-primary)"
|
||||||
|
v-motion
|
||||||
|
:initial="{
|
||||||
|
opacity: 0,
|
||||||
|
y: 100
|
||||||
|
}"
|
||||||
|
:enter="{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
delay: 200
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<p class="font-medium pt-1">Element-Plus Table</p>
|
||||||
|
<el-table
|
||||||
|
class="el-table"
|
||||||
|
:data="tableData"
|
||||||
|
border
|
||||||
|
style="margin: 40px auto; width: 100%"
|
||||||
|
:row-class-name="tableRowClassName"
|
||||||
|
>
|
||||||
|
<el-table-column prop="date" label="Date" width="180" />
|
||||||
|
<el-table-column prop="name" label="Name" width="180" />
|
||||||
|
<el-table-column prop="address" label="Address" />
|
||||||
|
</el-table>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col
|
||||||
|
:xs="22"
|
||||||
|
:sm="22"
|
||||||
|
:md="11"
|
||||||
|
:lg="11"
|
||||||
|
:xl="11"
|
||||||
|
style="margin: 10px; border: 0.01rem solid var(--el-color-primary)"
|
||||||
|
v-motion
|
||||||
|
:initial="{
|
||||||
|
opacity: 0,
|
||||||
|
y: 100
|
||||||
|
}"
|
||||||
|
:enter="{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
delay: 200
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<p class="font-medium pt-1">Vxe Table</p>
|
||||||
|
<vxe-table
|
||||||
|
class="vxe-table"
|
||||||
|
border
|
||||||
|
style="margin: 40px auto"
|
||||||
|
:header-cell-style="headerCellStyle"
|
||||||
|
:row-style="rowStyle"
|
||||||
|
:cell-style="cellStyle"
|
||||||
|
:data="demo1.tableData"
|
||||||
|
>
|
||||||
|
<vxe-column type="seq" width="60"></vxe-column>
|
||||||
|
<vxe-column field="name" title="Name"></vxe-column>
|
||||||
|
<vxe-column field="sex" title="Sex"></vxe-column>
|
||||||
|
<vxe-column field="age" title="Age"></vxe-column>
|
||||||
|
<vxe-column field="attr1" title="Attr1"></vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="address"
|
||||||
|
title="Address"
|
||||||
|
show-overflow
|
||||||
|
></vxe-column>
|
||||||
|
</vxe-table>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col
|
||||||
|
:xs="22"
|
||||||
|
:sm="22"
|
||||||
|
:md="11"
|
||||||
|
:lg="11"
|
||||||
|
:xl="11"
|
||||||
|
style="
|
||||||
|
width: 200px;
|
||||||
|
height: 300px;
|
||||||
|
margin: 10px;
|
||||||
|
border: 0.01rem solid var(--el-color-primary);
|
||||||
|
"
|
||||||
|
v-motion
|
||||||
|
:initial="{
|
||||||
|
opacity: 0,
|
||||||
|
y: 100
|
||||||
|
}"
|
||||||
|
:enter="{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
delay: 200
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<p class="font-medium pt-1">Echart</p>
|
||||||
|
<ReLine class="echart" style="margin: 0 auto" />
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col
|
||||||
|
:xs="22"
|
||||||
|
:sm="22"
|
||||||
|
:md="11"
|
||||||
|
:lg="11"
|
||||||
|
:xl="11"
|
||||||
|
style="
|
||||||
|
width: 200px;
|
||||||
|
height: 300px;
|
||||||
|
margin: 10px;
|
||||||
|
border: 0.01rem solid var(--el-color-primary);
|
||||||
|
"
|
||||||
|
v-motion
|
||||||
|
:initial="{
|
||||||
|
opacity: 0,
|
||||||
|
y: 100
|
||||||
|
}"
|
||||||
|
:enter="{
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: {
|
||||||
|
delay: 200
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<p class="font-medium pt-1">Image</p>
|
||||||
|
<img
|
||||||
|
src="../../assets/avatars.jpg"
|
||||||
|
alt="avatars"
|
||||||
|
class="img"
|
||||||
|
style="width: 200px; height: 200px; margin: 50px auto"
|
||||||
|
/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-table__row.warning-row) {
|
||||||
|
--el-table-tr-bg-color: var(--el-color-warning-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__row.success-row) {
|
||||||
|
--el-table-tr-bg-color: var(--el-color-success-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
34
src/views/able/watermark.vue
Normal file
34
src/views/able/watermark.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useWatermark } from "/@/utils/watermark";
|
||||||
|
|
||||||
|
let color = ref("#409EFF");
|
||||||
|
let value = ref("vue-pure-admin");
|
||||||
|
const { setWatermark, clear } = useWatermark();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">页面水印功能</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span>请输入要创建水印的值:</span
|
||||||
|
><el-input
|
||||||
|
class="mb-4 mr-4"
|
||||||
|
style="width: 200px"
|
||||||
|
v-model="value"
|
||||||
|
clearable
|
||||||
|
></el-input>
|
||||||
|
<span>请选择要创建水印的颜色:</span
|
||||||
|
><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-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
136
src/views/about.vue
Normal file
136
src/views/about.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
export interface schemaItem {
|
||||||
|
field: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const { pkg, lastBuildTime } = __APP_INFO__;
|
||||||
|
const { dependencies, devDependencies, version } = pkg;
|
||||||
|
|
||||||
|
const schema: schemaItem[] = [];
|
||||||
|
const devSchema: schemaItem[] = [];
|
||||||
|
|
||||||
|
Object.keys(dependencies).forEach(key => {
|
||||||
|
schema.push({ field: dependencies[key], label: key });
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(devDependencies).forEach(key => {
|
||||||
|
devSchema.push({ field: devDependencies[key], label: key });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-card class="box-card mb-4" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">关于</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span style="font-size: 15px">
|
||||||
|
Pure-Admin 是一个基于Vue3、Vite2、TypeScript、Element-Plus
|
||||||
|
的中后台解决方案,它可以帮助您快速搭建企业级中后台,提供现成的开箱解决方案及丰富的示例。原则上不收取任何费用及版权,可以放心使用,不过如需二次开源(比如用此平台二次开发并开源)请联系作者获取许可!
|
||||||
|
</span>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="box-card m-4" shadow="hover">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">项目信息</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions :column="2" border>
|
||||||
|
<el-descriptions-item label="版本" label-align="left" align="left">
|
||||||
|
<el-tag>{{ version }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item
|
||||||
|
label="最后编译时间"
|
||||||
|
label-align="left"
|
||||||
|
align="left"
|
||||||
|
>
|
||||||
|
<el-tag>{{ lastBuildTime }}</el-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="文档地址" label-align="left" align="left">
|
||||||
|
<a href="https://pure-admin-doc.vercel.app" target="_blank">
|
||||||
|
<span style="color: var(--el-color-primary)">文档地址</span>
|
||||||
|
</a>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="预览地址" label-align="left" align="left">
|
||||||
|
<a href="https://vue-pure-admin.vercel.app" target="_blank">
|
||||||
|
<span style="color: var(--el-color-primary)">预览地址</span>
|
||||||
|
</a>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="Github" label-align="left" align="left">
|
||||||
|
<a
|
||||||
|
href="https://github.com/xiaoxian521/vue-pure-admin"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span style="color: var(--el-color-primary)">Github</span>
|
||||||
|
</a>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="QQ交流群" label-align="left" align="left">
|
||||||
|
<a href="https://jq.qq.com/?_wv=1027&k=HntMx0dt" target="_blank"
|
||||||
|
><span style="color: var(--el-color-primary)"
|
||||||
|
>点击链接加入群聊【Pure Admin】</span
|
||||||
|
></a
|
||||||
|
>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="box-card m-4" shadow="hover">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">生产环境依赖</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions border>
|
||||||
|
<el-descriptions-item
|
||||||
|
:label="item.label"
|
||||||
|
label-align="left"
|
||||||
|
align="left"
|
||||||
|
v-for="(item, index) in schema"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
:href="'https://www.npmjs.com/package/' + item.label"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span style="color: var(--el-color-primary)">{{ item.field }}</span>
|
||||||
|
</a>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="box-card m-4" shadow="hover">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">开发环境依赖</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-descriptions border>
|
||||||
|
<el-descriptions-item
|
||||||
|
:label="item.label"
|
||||||
|
label-align="left"
|
||||||
|
align="left"
|
||||||
|
v-for="(item, index) in devSchema"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
:href="'https://www.npmjs.com/package/' + item.label"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span style="color: var(--el-color-primary)">{{ item.field }}</span>
|
||||||
|
</a>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.main-content {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,13 +7,19 @@ const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<iframe :src="url" frameborder="0" class="iframe"></iframe>
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">通过iframe引入按钮页面</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<iframe :src="url" frameborder="0" class="iframe"></iframe>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.iframe {
|
.iframe {
|
||||||
width: 98%;
|
width: 100%;
|
||||||
height: 90vh;
|
height: 60vh;
|
||||||
border-radius: 6px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ import menuDynamic from "./menuDynamic.vue";
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">右键菜单组件</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="10">
|
<el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="10">
|
||||||
<!-- 基本使用 -->
|
<!-- 基本使用 -->
|
||||||
@@ -20,5 +25,5 @@ import menuDynamic from "./menuDynamic.vue";
|
|||||||
<menuDynamic />
|
<menuDynamic />
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,35 +3,32 @@ import { ReNormalCountTo, ReboundCountTo } from "/@/components/ReCountTo";
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
<el-row :gutter="24">
|
<template #header>
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
|
<div class="card-header">
|
||||||
<el-card shadow="always">
|
<span class="font-medium">数字动画组件</span>
|
||||||
<ReNormalCountTo
|
</div>
|
||||||
prefix="$"
|
</template>
|
||||||
:duration="1000"
|
<div class="flex items-center">
|
||||||
:color="'#409EFF'"
|
<ReNormalCountTo
|
||||||
:fontSize="'2.3em'"
|
prefix="$"
|
||||||
:startVal="1"
|
:duration="1000"
|
||||||
:endVal="1000"
|
:color="'#409EFF'"
|
||||||
/>
|
:fontSize="'2em'"
|
||||||
</el-card>
|
:startVal="1"
|
||||||
</el-col>
|
:endVal="1000"
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
|
/>
|
||||||
<el-card shadow="always">
|
<ul class="flex ml-8">
|
||||||
<ul class="flex">
|
<ReboundCountTo
|
||||||
<ReboundCountTo
|
v-for="(num, inx) of [1, 6, 6, 6]"
|
||||||
v-for="(num, inx) of [1, 6, 6, 6]"
|
:key="inx"
|
||||||
:key="inx"
|
:i="num"
|
||||||
:i="num"
|
:blur="inx"
|
||||||
:blur="inx"
|
:delay="inx + 1"
|
||||||
:delay="inx + 1"
|
/>
|
||||||
/>
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { ref, nextTick, getCurrentInstance } from "vue";
|
|||||||
import Cropper from "/@/components/ReCropper";
|
import Cropper from "/@/components/ReCropper";
|
||||||
import img from "./picture.jpeg";
|
import img from "./picture.jpeg";
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
|
||||||
let info = ref<object>(null);
|
let info = ref<object>(null);
|
||||||
let cropperImg = ref<string>("");
|
let cropperImg = ref<string>("");
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
|
||||||
const onCropper = (): void => {
|
const onCropper = (): void => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -25,14 +25,19 @@ const onCropper = (): void => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium">图片裁剪组件</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<div class="cropper-container">
|
<div class="cropper-container">
|
||||||
<Cropper ref="refCropper" :width="'40vw'" :src="img" />
|
<Cropper ref="refCropper" :width="'40vw'" :src="img" />
|
||||||
<img :src="cropperImg" class="croppered" v-if="cropperImg" />
|
<img :src="cropperImg" class="croppered" v-if="cropperImg" />
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" @click="onCropper">裁剪</el-button>
|
<el-button type="primary" @click="onCropper">裁剪</el-button>
|
||||||
<p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
|
<p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import draggable from "vuedraggable/src/vuedraggable";
|
import draggable from "vuedraggable/src/vuedraggable";
|
||||||
|
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
|
||||||
|
|
||||||
let gridLists = ref<Array<Object>>([
|
let gridLists = ref<Array<Object>>([
|
||||||
{ grid: "cn", num: 1 },
|
{ grid: "cn", num: 1 },
|
||||||
@@ -47,77 +48,92 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="drag-container">
|
<el-card>
|
||||||
<!-- grid列表拖拽 -->
|
<template #header>
|
||||||
<el-row :gutter="25">
|
<div class="card-header">
|
||||||
<el-col :xs="25" :sm="8" :md="8" :lg="8">
|
<span
|
||||||
<el-card>
|
>拖拽组件,采用开源的<el-link
|
||||||
<template #header>
|
href="https://sortablejs.github.io/vue.draggable.next/#/simple"
|
||||||
<div class="card-header">
|
target="_blank"
|
||||||
<span>grid列表拖拽</span>
|
:icon="useRenderIcon('rank')"
|
||||||
</div>
|
style="font-size: 16px; margin: 0 4px 5px"
|
||||||
</template>
|
>vuedraggable</el-link
|
||||||
<draggable
|
></span
|
||||||
v-model="gridLists"
|
>
|
||||||
class="grid-container"
|
</div>
|
||||||
item-key="grid"
|
</template>
|
||||||
animation="300"
|
<div class="drag-container">
|
||||||
chosenClass="chosen"
|
<!-- grid列表拖拽 -->
|
||||||
forceFallback="true"
|
<el-row :gutter="25">
|
||||||
>
|
<el-col :xs="25" :sm="8" :md="8" :lg="8">
|
||||||
<template #item="{ element }">
|
<el-card>
|
||||||
<div :class="'item' + ' ' + 'item-' + element.num">
|
<template #header>
|
||||||
{{ element.num }}
|
<div class="card-header">
|
||||||
|
<span>grid列表拖拽</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
<draggable
|
||||||
</el-card>
|
v-model="gridLists"
|
||||||
</el-col>
|
class="grid-container"
|
||||||
|
item-key="grid"
|
||||||
<el-col :xs="25" :sm="8" :md="8" :lg="8">
|
animation="300"
|
||||||
<el-card>
|
chosenClass="chosen"
|
||||||
<template #header>
|
forceFallback="true"
|
||||||
<div class="card-header">
|
|
||||||
<span>单列拖拽</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!-- 单列拖拽 -->
|
|
||||||
<draggable
|
|
||||||
v-model="lists"
|
|
||||||
item-key="name"
|
|
||||||
@change="change"
|
|
||||||
chosen-class="chosen"
|
|
||||||
force-fallback="true"
|
|
||||||
animation="300"
|
|
||||||
>
|
|
||||||
<template #item="{ element, index }">
|
|
||||||
<div class="item-single">{{ element.name }} {{ index }}</div>
|
|
||||||
</template>
|
|
||||||
</draggable>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :xs="25" :sm="8" :md="8" :lg="8">
|
|
||||||
<el-card>
|
|
||||||
<template #header>
|
|
||||||
<div class="card-header">
|
|
||||||
<span>拖拽实现元素位置切换</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!-- 拖拽实现元素位置切换 -->
|
|
||||||
<div class="cut-container">
|
|
||||||
<div
|
|
||||||
class="item-cut"
|
|
||||||
v-for="(item, index) in cutLists"
|
|
||||||
:key="index"
|
|
||||||
>
|
>
|
||||||
<p>{{ item.name }}</p>
|
<template #item="{ element }">
|
||||||
|
<div :class="'item' + ' ' + 'item-' + element.num">
|
||||||
|
{{ element.num }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :xs="25" :sm="8" :md="8" :lg="8">
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>单列拖拽</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 单列拖拽 -->
|
||||||
|
<draggable
|
||||||
|
v-model="lists"
|
||||||
|
item-key="name"
|
||||||
|
@change="change"
|
||||||
|
chosen-class="chosen"
|
||||||
|
force-fallback="true"
|
||||||
|
animation="300"
|
||||||
|
>
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<div class="item-single">{{ element.name }} {{ index }}</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :xs="25" :sm="8" :md="8" :lg="8">
|
||||||
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>拖拽实现元素位置切换</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 拖拽实现元素位置切换 -->
|
||||||
|
<div class="cut-container">
|
||||||
|
<div
|
||||||
|
class="item-cut"
|
||||||
|
v-for="(item, index) in cutLists"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<p>{{ item.name }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-card>
|
||||||
</el-card>
|
</el-col>
|
||||||
</el-col>
|
</el-row>
|
||||||
</el-row>
|
</div>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ import { Amap } from "/@/components/ReMap";
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.main-content {
|
.main-content {
|
||||||
margin: 0;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -16,27 +16,34 @@ const settingTB: ContextProps = reactive({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="split-pane">
|
<el-card>
|
||||||
<splitpane :splitSet="settingLR">
|
<template #header>
|
||||||
<!-- #paneL 表示指定该组件为左侧面板 -->
|
<div class="card-header">
|
||||||
<template #paneL>
|
<span class="font-medium">切割面板组件</span>
|
||||||
<!-- 自定义左侧面板的内容 -->
|
</div>
|
||||||
<div class="dv-a">A</div>
|
</template>
|
||||||
</template>
|
<div class="split-pane">
|
||||||
<!-- #paneR 表示指定该组件为右侧面板 -->
|
<splitpane :splitSet="settingLR">
|
||||||
<template #paneR>
|
<!-- #paneL 表示指定该组件为左侧面板 -->
|
||||||
<!-- 再次将右侧面板进行拆分 -->
|
<template #paneL>
|
||||||
<splitpane :splitSet="settingTB">
|
<!-- 自定义左侧面板的内容 -->
|
||||||
<template #paneL>
|
<div class="dv-a">A</div>
|
||||||
<div class="dv-b">B</div>
|
</template>
|
||||||
</template>
|
<!-- #paneR 表示指定该组件为右侧面板 -->
|
||||||
<template #paneR>
|
<template #paneR>
|
||||||
<div class="dv-c">C</div>
|
<!-- 再次将右侧面板进行拆分 -->
|
||||||
</template>
|
<splitpane :splitSet="settingTB">
|
||||||
</splitpane>
|
<template #paneL>
|
||||||
</template>
|
<div class="dv-b">B</div>
|
||||||
</splitpane>
|
</template>
|
||||||
</div>
|
<template #paneR>
|
||||||
|
<div class="dv-c">C</div>
|
||||||
|
</template>
|
||||||
|
</splitpane>
|
||||||
|
</template>
|
||||||
|
</splitpane>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -2,13 +2,16 @@
|
|||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
import Player from "xgplayer/dist/simple_player";
|
import Player from "xgplayer/dist/simple_player";
|
||||||
import volume from "xgplayer/es/controls/volume";
|
import volume from "xgplayer/es/controls/volume";
|
||||||
import playbackRate from "xgplayer/es/controls/playbackRate";
|
|
||||||
import screenShot from "xgplayer/es/controls/screenShot";
|
import screenShot from "xgplayer/es/controls/screenShot";
|
||||||
import { deviceDetection } from "/@/utils/deviceDetection";
|
import { deviceDetection } from "/@/utils/deviceDetection";
|
||||||
|
import playbackRate from "xgplayer/es/controls/playbackRate";
|
||||||
|
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
new Player({
|
new Player({
|
||||||
id: "mse",
|
id: "mse",
|
||||||
|
// 默认静音
|
||||||
|
volume: 0,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
screenShot: true,
|
screenShot: true,
|
||||||
url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
|
url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
|
||||||
@@ -23,7 +26,22 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="mse"></div>
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium"
|
||||||
|
>视频组件,采用开源的<el-link
|
||||||
|
href="https://v2.h5player.bytedance.com"
|
||||||
|
target="_blank"
|
||||||
|
:icon="useRenderIcon('video-play')"
|
||||||
|
style="font-size: 16px; margin: 0 4px 5px"
|
||||||
|
>西瓜播放器</el-link
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div id="mse"></div>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onBeforeUnmount, ref, unref } from "vue";
|
|
||||||
import WangEditor from "wangeditor";
|
import WangEditor from "wangeditor";
|
||||||
|
import { onMounted, onBeforeUnmount, ref, unref } from "vue";
|
||||||
|
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const editor = ref(null);
|
|
||||||
const html = ref(null);
|
const html = ref(null);
|
||||||
|
const editor = ref(null);
|
||||||
let instance: WangEditor;
|
let instance: WangEditor;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -29,17 +29,26 @@ onBeforeUnmount(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium"
|
||||||
|
>编辑器组件,采用开源的<el-link
|
||||||
|
href="https://www.wangeditor.com"
|
||||||
|
target="_blank"
|
||||||
|
:icon="useRenderIcon('edit')"
|
||||||
|
style="font-size: 16px; margin: 0 4px 5px"
|
||||||
|
>wangeditor</el-link
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<div ref="editor"></div>
|
<div ref="editor"></div>
|
||||||
<div :innerHTML="html"></div>
|
<div :innerHTML="html"></div>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main-content {
|
|
||||||
margin: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.w-e-text-container) {
|
:deep(.w-e-text-container) {
|
||||||
z-index: 99 !important;
|
z-index: 99 !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, unref, onMounted } from "vue";
|
import demoData from "./dataTurbo.json";
|
||||||
import LogicFlow from "@logicflow/core";
|
|
||||||
import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
|
|
||||||
import "@logicflow/core/dist/style/index.css";
|
import "@logicflow/core/dist/style/index.css";
|
||||||
import "@logicflow/extension/lib/style/index.css";
|
import "@logicflow/extension/lib/style/index.css";
|
||||||
|
|
||||||
|
import LogicFlow from "@logicflow/core";
|
||||||
|
import { ref, unref, onMounted } from "vue";
|
||||||
|
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
|
||||||
|
import { BpmnNode } from "/@/components/ReFlowChart/src/config";
|
||||||
|
import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
|
||||||
import { Control, NodePanel, DataDialog } from "/@/components/ReFlowChart";
|
import { Control, NodePanel, DataDialog } from "/@/components/ReFlowChart";
|
||||||
import { toLogicflowData } from "/@/components/ReFlowChart/src/adpterForTurbo";
|
import { toLogicflowData } from "/@/components/ReFlowChart/src/adpterForTurbo";
|
||||||
import { BpmnNode } from "/@/components/ReFlowChart/src/config";
|
|
||||||
import demoData from "./dataTurbo.json";
|
|
||||||
|
|
||||||
let lf = ref(null);
|
let lf = ref(null);
|
||||||
let graphData = ref(null);
|
let graphData = ref(null);
|
||||||
@@ -57,37 +59,52 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="logic-flow-view">
|
<el-card>
|
||||||
<!-- 辅助工具栏 -->
|
<template #header>
|
||||||
<Control
|
<div class="card-header">
|
||||||
class="demo-control"
|
<span class="font-medium"
|
||||||
v-if="lf"
|
>流程图组件,采用开源的<el-link
|
||||||
:lf="lf"
|
href="http://logic-flow.org/"
|
||||||
:catTurboData="false"
|
target="_blank"
|
||||||
@catData="catData"
|
:icon="useRenderIcon('set-up')"
|
||||||
></Control>
|
style="font-size: 16px; margin: 0 4px 5px"
|
||||||
<!-- 节点面板 -->
|
>LogicFlow</el-link
|
||||||
<NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
|
></span
|
||||||
<!-- 画布 -->
|
>
|
||||||
<div id="LF-Turbo"></div>
|
</div>
|
||||||
<!-- 数据查看面板 -->
|
</template>
|
||||||
<el-dialog
|
<div class="logic-flow-view">
|
||||||
customClass="flow-dialog"
|
<!-- 辅助工具栏 -->
|
||||||
title="数据"
|
<Control
|
||||||
v-model="dataVisible"
|
class="demo-control"
|
||||||
width="50%"
|
v-if="lf"
|
||||||
>
|
:lf="lf"
|
||||||
<el-scrollbar>
|
:catTurboData="false"
|
||||||
<DataDialog :graphData="graphData"></DataDialog>
|
@catData="catData"
|
||||||
</el-scrollbar>
|
></Control>
|
||||||
</el-dialog>
|
<!-- 节点面板 -->
|
||||||
</div>
|
<NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
|
||||||
|
<!-- 画布 -->
|
||||||
|
<div id="LF-Turbo"></div>
|
||||||
|
<!-- 数据查看面板 -->
|
||||||
|
<el-dialog
|
||||||
|
customClass="flow-dialog"
|
||||||
|
title="数据"
|
||||||
|
v-model="dataVisible"
|
||||||
|
width="50%"
|
||||||
|
>
|
||||||
|
<el-scrollbar>
|
||||||
|
<DataDialog :graphData="graphData"></DataDialog>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
#LF-Turbo {
|
#LF-Turbo {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - 90px);
|
height: 70vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logic-flow-view {
|
.logic-flow-view {
|
||||||
@@ -137,8 +154,4 @@ onMounted(() => {
|
|||||||
height: 85vh;
|
height: 85vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: "reGuide"
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Driver from "driver.js";
|
import Driver from "driver.js";
|
||||||
import "driver.js/dist/driver.min.css";
|
import "driver.js/dist/driver.min.css";
|
||||||
|
|
||||||
// 步骤
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{
|
{
|
||||||
element: "#header-notice",
|
element: "#header-notice",
|
||||||
@@ -72,8 +65,14 @@ const guide = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
<p>引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能</p>
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="font-medium"
|
||||||
|
>引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
style="margin-top: 10px"
|
style="margin-top: 10px"
|
||||||
@@ -81,7 +80,7 @@ const guide = () => {
|
|||||||
>
|
>
|
||||||
打开引导页
|
打开引导页
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: "reMenuTree"
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed } from "vue";
|
|
||||||
import { extractPathList, deleteChildren } from "/@/utils/tree";
|
|
||||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
|
|
||||||
|
|
||||||
let dataProps = ref({
|
|
||||||
value: "uniqueId",
|
|
||||||
children: "children"
|
|
||||||
});
|
|
||||||
|
|
||||||
let menusData = computed(() => {
|
|
||||||
return deleteChildren(usePermissionStoreHook().menusTree);
|
|
||||||
});
|
|
||||||
|
|
||||||
let expandedKeys = extractPathList(menusData.value);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<el-tree-v2
|
|
||||||
:data="menusData"
|
|
||||||
:props="dataProps"
|
|
||||||
show-checkbox
|
|
||||||
:height="500"
|
|
||||||
:default-expanded-keys="expandedKeys"
|
|
||||||
>
|
|
||||||
<template #default="{ data }">
|
|
||||||
<span>{{ $t(data.meta.title) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-tree-v2>
|
|
||||||
</template>
|
|
||||||
@@ -20,12 +20,16 @@ function changRole(value) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
<el-radio-group v-model="auth" @change="changRole">
|
<template #header>
|
||||||
<el-radio-button label="admin"></el-radio-button>
|
<div class="card-header">
|
||||||
<el-radio-button label="test"></el-radio-button>
|
<el-radio-group v-model="auth" @change="changRole">
|
||||||
</el-radio-group>
|
<el-radio-button label="admin"></el-radio-button>
|
||||||
|
<el-radio-button label="test"></el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<p v-auth="'v-admin'">只有admin可看</p>
|
<p v-auth="'v-admin'">只有admin可看</p>
|
||||||
<p v-auth="'v-test'">只有test可看</p>
|
<p v-auth="'v-test'">只有test可看</p>
|
||||||
</div>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export default {
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, unref } from "vue";
|
import { ref, unref } from "vue";
|
||||||
import { storageSession } from "/@/utils/storage";
|
import { storageSession } from "/@/utils/storage";
|
||||||
|
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
|
||||||
|
|
||||||
let purview = ref<string>(storageSession.getItem("info").username);
|
let purview = ref<string>(storageSession.getItem("info").username);
|
||||||
|
|
||||||
@@ -28,14 +29,23 @@ function changRole() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<el-card>
|
||||||
<h4>
|
<template #header>
|
||||||
当前角色:
|
<div class="card-header">
|
||||||
<span style="font-size: 26px">{{ purview }}</span>
|
<span>
|
||||||
<p style="color: #ffa500">
|
当前角色:
|
||||||
查看左侧菜单变化(系统管理),模拟后台根据不同角色返回对应路由
|
<span style="font-size: 26px">{{ purview }}</span>
|
||||||
</p>
|
<p style="color: #ffa500">
|
||||||
</h4>
|
查看左侧菜单变化(系统管理),模拟后台根据不同角色返回对应路由
|
||||||
<el-button type="primary" @click="changRole">切换角色</el-button>
|
</p></span
|
||||||
</div>
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="changRole"
|
||||||
|
:icon="useRenderIcon('user', { color: '#fff' })"
|
||||||
|
>切换角色</el-button
|
||||||
|
>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Config from "./config.vue";
|
|
||||||
import { reactive, ref, unref, nextTick } from "vue";
|
|
||||||
import XEUtils from "xe-utils";
|
import XEUtils from "xe-utils";
|
||||||
import { cloneDeep } from "lodash-es";
|
import Config from "./config.vue";
|
||||||
|
import { cloneDeep } from "lodash-unified";
|
||||||
import { templateRef } from "@vueuse/core";
|
import { templateRef } from "@vueuse/core";
|
||||||
|
import { reactive, ref, unref, nextTick } from "vue";
|
||||||
import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
|
import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
|
||||||
import {
|
import {
|
||||||
VXETable,
|
VXETable,
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
|
||||||
import { useRouter, useRoute } from "vue-router";
|
import { useRouter, useRoute } from "vue-router";
|
||||||
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
|
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const activeName = ref("tag");
|
|
||||||
|
|
||||||
function toDetail(index: number) {
|
function toDetail(index: number) {
|
||||||
useMultiTagsStoreHook().handleTags("push", {
|
useMultiTagsStoreHook().handleTags("push", {
|
||||||
@@ -25,33 +23,16 @@ function toDetail(index: number) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-collapse v-model="activeName" class="tabs-container">
|
<el-card>
|
||||||
<el-collapse-item
|
<template #header>
|
||||||
title="标签页复用超出限制自动关闭(使用场景: 动态路由)"
|
<div class="card-header">
|
||||||
name="tag"
|
<span class="font-medium"
|
||||||
>
|
>标签页复用,超出限制自动关闭(使用场景: 动态路由)</span
|
||||||
<el-button v-for="index in 6" :key="index" @click="toDetail(index)">
|
>
|
||||||
打开{{ index }}详情页
|
</div>
|
||||||
</el-button>
|
</template>
|
||||||
</el-collapse-item>
|
<el-button v-for="index in 6" :key="index" @click="toDetail(index)">
|
||||||
</el-collapse>
|
打开{{ index }}详情页
|
||||||
|
</el-button>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.tabs-container {
|
|
||||||
padding: 10px;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
::v-deep(.el-collapse-item__header) {
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep(.el-collapse-item__wrap) {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const openDepot = (): void => {
|
|||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<el-card>
|
<el-card style="height: 360px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<span style="font-size: 16px; font-weight: 500">GitHub信息</span>
|
<span style="font-size: 16px; font-weight: 500">GitHub信息</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -93,7 +93,7 @@ const openDepot = (): void => {
|
|||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<el-card>
|
<el-card style="height: 360px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<span style="font-size: 16px; font-weight: 500"
|
<span style="font-size: 16px; font-weight: 500"
|
||||||
>GitHub滚动信息</span
|
>GitHub滚动信息</span
|
||||||
@@ -220,7 +220,7 @@ const openDepot = (): void => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main-content {
|
.main-content {
|
||||||
margin: 0;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.welcome {
|
.welcome {
|
||||||
|
|||||||
9
types/global.d.ts
vendored
9
types/global.d.ts
vendored
@@ -16,6 +16,15 @@ declare module "vue" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
const __APP_INFO__: {
|
||||||
|
pkg: {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
dependencies: Recordable<string>;
|
||||||
|
devDependencies: Recordable<string>;
|
||||||
|
};
|
||||||
|
lastBuildTime: string;
|
||||||
|
};
|
||||||
interface Window {
|
interface Window {
|
||||||
// Global vue app instance
|
// Global vue app instance
|
||||||
__APP__: App<Element>;
|
__APP__: App<Element>;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
|
import pkg from "./package.json";
|
||||||
import { warpperEnv, regExps } from "./build";
|
import { warpperEnv, regExps } from "./build";
|
||||||
import { getPluginsList } from "./build/plugins";
|
import { getPluginsList } from "./build/plugins";
|
||||||
import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
|
import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
|
||||||
@@ -19,6 +21,12 @@ const alias: Record<string, string> = {
|
|||||||
"vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js"
|
"vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { dependencies, devDependencies, name, version } = pkg;
|
||||||
|
const __APP_INFO__ = {
|
||||||
|
pkg: { dependencies, devDependencies, name, version },
|
||||||
|
lastBuildTime: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss")
|
||||||
|
};
|
||||||
|
|
||||||
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
|
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
|
||||||
const {
|
const {
|
||||||
VITE_PORT,
|
VITE_PORT,
|
||||||
@@ -92,7 +100,8 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
|
|||||||
chunkSizeWarningLimit: 2000
|
chunkSizeWarningLimit: 2000
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
__INTLIFY_PROD_DEVTOOLS__: false
|
__INTLIFY_PROD_DEVTOOLS__: false,
|
||||||
|
__APP_INFO__: JSON.stringify(__APP_INFO__)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user