feat: 优化路由权限逻辑
自动部署 / build (push) Failing after 12s
Details
自动部署 / build (push) Failing after 12s
Details
parent
21de506907
commit
9436f5feee
File diff suppressed because one or more lines are too long
|
|
@ -2,9 +2,10 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="./favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>%VITE_TITLE% | %VITE_SUBTITLE%</title>
|
<meta name="description" content="%VITE_SUBTITLE%" />
|
||||||
|
<link rel="icon" href="./favicon.ico" />
|
||||||
|
<title>%VITE_TITLE%</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app" class="dark:bg-slate-900 dark:text-slate-200">
|
<div id="app" class="dark:bg-slate-900 dark:text-slate-200">
|
||||||
|
|
@ -13,6 +14,8 @@
|
||||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHN0eWxlPSJtYXJnaW46IGF1dG87IGJhY2tncm91bmQ6IHJnYigyNTUsIDI1NSwgMjU1KTsgZGlzcGxheTogYmxvY2s7IHNoYXBlLXJlbmRlcmluZzogYXV0bzsiIHdpZHRoPSIyMDBweCIgaGVpZ2h0PSIyMDBweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1MCA1MCkiPjxnPjxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiB2YWx1ZXM9IjA7NDUiIGtleVRpbWVzPSIwOzEiIGR1cj0iMC4ycyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiPjwvYW5pbWF0ZVRyYW5zZm9ybT48cGF0aCBkPSJNMjkuNDkxNTI0MjA2MTE3MjU1IC01LjUgTDM3LjQ5MTUyNDIwNjExNzI1NSAtNS41IEwzNy40OTE1MjQyMDYxMTcyNTUgNS41IEwyOS40OTE1MjQyMDYxMTcyNTUgNS41IEEzMCAzMCAwIDAgMSAyNC43NDI3NDQwNTAxOTg3MzggMTYuOTY0NTY5NDU3MTQ2NzEyIEwyNC43NDI3NDQwNTAxOTg3MzggMTYuOTY0NTY5NDU3MTQ2NzEyIEwzMC4zOTk1OTgyOTk2OTExMTcgMjIuNjIxNDIzNzA2NjM5MDkyIEwyMi42MjE0MjM3MDY2MzkwOTYgMzAuMzk5NTk4Mjk5NjkxMTE0IEwxNi45NjQ1Njk0NTcxNDY3MTYgMjQuNzQyNzQ0MDUwMTk4NzM0IEEzMCAzMCAwIDAgMSA1LjUgMjkuNDkxNTI0MjA2MTE3MjU1IEw1LjUgMjkuNDkxNTI0MjA2MTE3MjU1IEw1LjUgMzcuNDkxNTI0MjA2MTE3MjU1IEwtNS40OTk5OTk5OTk5OTk5OTcgMzcuNDkxNTI0MjA2MTE3MjU1IEwtNS40OTk5OTk5OTk5OTk5OTcgMjkuNDkxNTI0MjA2MTE3MjU1IEEzMCAzMCAwIDAgMSAtMTYuOTY0NTY5NDU3MTQ2NzA1IDI0Ljc0Mjc0NDA1MDE5ODczOCBMLTE2Ljk2NDU2OTQ1NzE0NjcwNSAyNC43NDI3NDQwNTAxOTg3MzggTC0yMi42MjE0MjM3MDY2MzkwODUgMzAuMzk5NTk4Mjk5NjkxMTE3IEwtMzAuMzk5NTk4Mjk5NjkxMTE3IDIyLjYyMTQyMzcwNjYzOTA5MiBMLTI0Ljc0Mjc0NDA1MDE5ODczOCAxNi45NjQ1Njk0NTcxNDY3MTIgQTMwIDMwIDAgMCAxIC0yOS40OTE1MjQyMDYxMTcyNTUgNS41MDAwMDAwMDAwMDAwMDkgTC0yOS40OTE1MjQyMDYxMTcyNTUgNS41MDAwMDAwMDAwMDAwMDkgTC0zNy40OTE1MjQyMDYxMTcyNTUgNS41MDAwMDAwMDAwMDAwMSBMLTM3LjQ5MTUyNDIwNjExNzI1NSAtNS41MDAwMDAwMDAwMDAwMDEgTC0yOS40OTE1MjQyMDYxMTcyNTUgLTUuNTAwMDAwMDAwMDAwMDAyIEEzMCAzMCAwIDAgMSAtMjQuNzQyNzQ0MDUwMTk4NzM4IC0xNi45NjQ1Njk0NTcxNDY3MDUgTC0yNC43NDI3NDQwNTAxOTg3MzggLTE2Ljk2NDU2OTQ1NzE0NjcwNSBMLTMwLjM5OTU5ODI5OTY5MTExNyAtMjIuNjIxNDIzNzA2NjM5MDg1IEwtMjIuNjIxNDIzNzA2NjM5MDkyIC0zMC4zOTk1OTgyOTk2OTExMTcgTC0xNi45NjQ1Njk0NTcxNDY3MTIgLTI0Ljc0Mjc0NDA1MDE5ODczOCBBMzAgMzAgMCAwIDEgLTUuNTAwMDAwMDAwMDAwMDExIC0yOS40OTE1MjQyMDYxMTcyNTUgTC01LjUwMDAwMDAwMDAwMDAxMSAtMjkuNDkxNTI0MjA2MTE3MjU1IEwtNS41MDAwMDAwMDAwMDAwMTIgLTM3LjQ5MTUyNDIwNjExNzI1NSBMNS40OTk5OTk5OTk5OTk5OTggLTM3LjQ5MTUyNDIwNjExNzI1NSBMNS41IC0yOS40OTE1MjQyMDYxMTcyNTUgQTMwIDMwIDAgMCAxIDE2Ljk2NDU2OTQ1NzE0NjcwMiAtMjQuNzQyNzQ0MDUwMTk4NzQgTDE2Ljk2NDU2OTQ1NzE0NjcwMiAtMjQuNzQyNzQ0MDUwMTk4NzQgTDIyLjYyMTQyMzcwNjYzOTA4IC0zMC4zOTk1OTgyOTk2OTExMiBMMzAuMzk5NTk4Mjk5NjkxMTE3IC0yMi42MjE0MjM3MDY2MzkxIEwyNC43NDI3NDQwNTAxOTg3MzggLTE2Ljk2NDU2OTQ1NzE0NjcxNiBBMzAgMzAgMCAwIDEgMjkuNDkxNTI0MjA2MTE3MjU1IC01LjUwMDAwMDAwMDAwMDAxMyBNMCAtMjBBMjAgMjAgMCAxIDAgMCAyMCBBMjAgMjAgMCAxIDAgMCAtMjAiIGZpbGw9IiMwOWYiPjwvcGF0aD48L2c+PC9nPjwvc3ZnPgo="
|
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHN0eWxlPSJtYXJnaW46IGF1dG87IGJhY2tncm91bmQ6IHJnYigyNTUsIDI1NSwgMjU1KTsgZGlzcGxheTogYmxvY2s7IHNoYXBlLXJlbmRlcmluZzogYXV0bzsiIHdpZHRoPSIyMDBweCIgaGVpZ2h0PSIyMDBweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1MCA1MCkiPjxnPjxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiB2YWx1ZXM9IjA7NDUiIGtleVRpbWVzPSIwOzEiIGR1cj0iMC4ycyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiPjwvYW5pbWF0ZVRyYW5zZm9ybT48cGF0aCBkPSJNMjkuNDkxNTI0MjA2MTE3MjU1IC01LjUgTDM3LjQ5MTUyNDIwNjExNzI1NSAtNS41IEwzNy40OTE1MjQyMDYxMTcyNTUgNS41IEwyOS40OTE1MjQyMDYxMTcyNTUgNS41IEEzMCAzMCAwIDAgMSAyNC43NDI3NDQwNTAxOTg3MzggMTYuOTY0NTY5NDU3MTQ2NzEyIEwyNC43NDI3NDQwNTAxOTg3MzggMTYuOTY0NTY5NDU3MTQ2NzEyIEwzMC4zOTk1OTgyOTk2OTExMTcgMjIuNjIxNDIzNzA2NjM5MDkyIEwyMi42MjE0MjM3MDY2MzkwOTYgMzAuMzk5NTk4Mjk5NjkxMTE0IEwxNi45NjQ1Njk0NTcxNDY3MTYgMjQuNzQyNzQ0MDUwMTk4NzM0IEEzMCAzMCAwIDAgMSA1LjUgMjkuNDkxNTI0MjA2MTE3MjU1IEw1LjUgMjkuNDkxNTI0MjA2MTE3MjU1IEw1LjUgMzcuNDkxNTI0MjA2MTE3MjU1IEwtNS40OTk5OTk5OTk5OTk5OTcgMzcuNDkxNTI0MjA2MTE3MjU1IEwtNS40OTk5OTk5OTk5OTk5OTcgMjkuNDkxNTI0MjA2MTE3MjU1IEEzMCAzMCAwIDAgMSAtMTYuOTY0NTY5NDU3MTQ2NzA1IDI0Ljc0Mjc0NDA1MDE5ODczOCBMLTE2Ljk2NDU2OTQ1NzE0NjcwNSAyNC43NDI3NDQwNTAxOTg3MzggTC0yMi42MjE0MjM3MDY2MzkwODUgMzAuMzk5NTk4Mjk5NjkxMTE3IEwtMzAuMzk5NTk4Mjk5NjkxMTE3IDIyLjYyMTQyMzcwNjYzOTA5MiBMLTI0Ljc0Mjc0NDA1MDE5ODczOCAxNi45NjQ1Njk0NTcxNDY3MTIgQTMwIDMwIDAgMCAxIC0yOS40OTE1MjQyMDYxMTcyNTUgNS41MDAwMDAwMDAwMDAwMDkgTC0yOS40OTE1MjQyMDYxMTcyNTUgNS41MDAwMDAwMDAwMDAwMDkgTC0zNy40OTE1MjQyMDYxMTcyNTUgNS41MDAwMDAwMDAwMDAwMSBMLTM3LjQ5MTUyNDIwNjExNzI1NSAtNS41MDAwMDAwMDAwMDAwMDEgTC0yOS40OTE1MjQyMDYxMTcyNTUgLTUuNTAwMDAwMDAwMDAwMDAyIEEzMCAzMCAwIDAgMSAtMjQuNzQyNzQ0MDUwMTk4NzM4IC0xNi45NjQ1Njk0NTcxNDY3MDUgTC0yNC43NDI3NDQwNTAxOTg3MzggLTE2Ljk2NDU2OTQ1NzE0NjcwNSBMLTMwLjM5OTU5ODI5OTY5MTExNyAtMjIuNjIxNDIzNzA2NjM5MDg1IEwtMjIuNjIxNDIzNzA2NjM5MDkyIC0zMC4zOTk1OTgyOTk2OTExMTcgTC0xNi45NjQ1Njk0NTcxNDY3MTIgLTI0Ljc0Mjc0NDA1MDE5ODczOCBBMzAgMzAgMCAwIDEgLTUuNTAwMDAwMDAwMDAwMDExIC0yOS40OTE1MjQyMDYxMTcyNTUgTC01LjUwMDAwMDAwMDAwMDAxMSAtMjkuNDkxNTI0MjA2MTE3MjU1IEwtNS41MDAwMDAwMDAwMDAwMTIgLTM3LjQ5MTUyNDIwNjExNzI1NSBMNS40OTk5OTk5OTk5OTk5OTggLTM3LjQ5MTUyNDIwNjExNzI1NSBMNS41IC0yOS40OTE1MjQyMDYxMTcyNTUgQTMwIDMwIDAgMCAxIDE2Ljk2NDU2OTQ1NzE0NjcwMiAtMjQuNzQyNzQ0MDUwMTk4NzQgTDE2Ljk2NDU2OTQ1NzE0NjcwMiAtMjQuNzQyNzQ0MDUwMTk4NzQgTDIyLjYyMTQyMzcwNjYzOTA4IC0zMC4zOTk1OTgyOTk2OTExMiBMMzAuMzk5NTk4Mjk5NjkxMTE3IC0yMi42MjE0MjM3MDY2MzkxIEwyNC43NDI3NDQwNTAxOTg3MzggLTE2Ljk2NDU2OTQ1NzE0NjcxNiBBMzAgMzAgMCAwIDEgMjkuNDkxNTI0MjA2MTE3MjU1IC01LjUwMDAwMDAwMDAwMDAxMyBNMCAtMjBBMjAgMjAgMCAxIDAgMCAyMCBBMjAgMjAgMCAxIDAgMCAtMjAiIGZpbGw9IiMwOWYiPjwvcGF0aD48L2c+PC9nPjwvc3ZnPgo="
|
||||||
alt="loading"
|
alt="loading"
|
||||||
class="loading-image"
|
class="loading-image"
|
||||||
|
width="64"
|
||||||
|
height="64"
|
||||||
/>
|
/>
|
||||||
<h1 class="loading-title">欢迎访问%VITE_TITLE%</h1>
|
<h1 class="loading-title">欢迎访问%VITE_TITLE%</h1>
|
||||||
<div class="loading-tip">资源加载中, 请稍等...</div>
|
<div class="loading-tip">资源加载中, 请稍等...</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import { Plugin, ResolvedConfig } from 'vite';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条件加载
|
||||||
|
* @description
|
||||||
|
* 先尝试 index.xx.vue 文件,
|
||||||
|
* 回退至 index.vue 文件。
|
||||||
|
*/
|
||||||
|
export default function plugin(): Plugin {
|
||||||
|
let config: ResolvedConfig;
|
||||||
|
let extension: string;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'vite:extension',
|
||||||
|
enforce: 'pre',
|
||||||
|
|
||||||
|
configResolved(resolvedConfig) {
|
||||||
|
config = resolvedConfig;
|
||||||
|
extension = config.env.VITE_EXTENTION ?? config.isProduction ? 'prod' : 'dev';
|
||||||
|
},
|
||||||
|
|
||||||
|
load(id) {
|
||||||
|
if (!extension || !id.includes('src')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (id.includes('?vue')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const targetPath = id.replace(/\.([^.]*?)$/, `.${extension}.$1`);
|
||||||
|
if (targetPath && fs.existsSync(targetPath)) {
|
||||||
|
return fs.readFileSync(targetPath, 'utf-8');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { spawn } from "child_process";
|
import { spawn } from 'child_process';
|
||||||
import fs from "fs";
|
import { Plugin, ResolvedConfig } from 'vite';
|
||||||
import { Plugin, ResolvedConfig } from "vite";
|
import pkg from '../../package.json';
|
||||||
import pkg from "../../package.json";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目 logo
|
* 项目 logo
|
||||||
|
|
@ -21,15 +20,15 @@ const LOGO = ` _ _______ _______ ____ _____ _____ ________ ____
|
||||||
* @returns Promise<string | void>
|
* @returns Promise<string | void>
|
||||||
*/
|
*/
|
||||||
const exec = (cmd: string) => {
|
const exec = (cmd: string) => {
|
||||||
return new Promise<string | void>((resolve) => {
|
return new Promise<string | void>(resolve => {
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
const child = spawn(cmd, [], { shell: true });
|
const child = spawn(cmd, [], { shell: true });
|
||||||
child.stdout.once("data", (data) => {
|
child.stdout.once('data', data => {
|
||||||
resolve(data.toString().replace(/"|\n/g, ""));
|
resolve(data.toString().replace(/"|\n/g, ''));
|
||||||
});
|
});
|
||||||
child.stderr.once("data", () => {
|
child.stderr.once('data', () => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -40,9 +39,9 @@ const exec = (cmd: string) => {
|
||||||
* @returns Promise<string>
|
* @returns Promise<string>
|
||||||
*/
|
*/
|
||||||
const getBuildInfo = async () => {
|
const getBuildInfo = async () => {
|
||||||
const hash = await exec("git log --format=%h -n 1");
|
const hash = await exec('git log --format=%h -n 1');
|
||||||
const time = new Date().toLocaleString("zh-Hans-CN");
|
const time = new Date().toLocaleString('zh-Hans-CN');
|
||||||
const latestTag = await exec("git describe --tags --abbrev=0");
|
const latestTag = await exec('git describe --tags --abbrev=0');
|
||||||
const commits = await exec(`git rev-list --count ${latestTag}..HEAD`);
|
const commits = await exec(`git rev-list --count ${latestTag}..HEAD`);
|
||||||
const version = commits ? `${latestTag}.${commits}` : `v${pkg.version}`;
|
const version = commits ? `${latestTag}.${commits}` : `v${pkg.version}`;
|
||||||
const content = `欢迎访问!版本: ${version} 标识: ${hash} 构建: ${time}`;
|
const content = `欢迎访问!版本: ${version} 标识: ${hash} 构建: ${time}`;
|
||||||
|
|
@ -57,39 +56,24 @@ const getBuildInfo = async () => {
|
||||||
*/
|
*/
|
||||||
export default function plugin(): Plugin {
|
export default function plugin(): Plugin {
|
||||||
let config: ResolvedConfig;
|
let config: ResolvedConfig;
|
||||||
let extension: string;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "vite:customizer",
|
name: 'vite:info',
|
||||||
enforce: "pre",
|
enforce: 'pre',
|
||||||
|
|
||||||
configResolved(resolvedConfig) {
|
configResolved(resolvedConfig) {
|
||||||
config = resolvedConfig;
|
config = resolvedConfig;
|
||||||
extension = config.env.VITE_EXTENTION ?? config.isProduction ? "prod" : "dev";
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async transformIndexHtml() {
|
async transformIndexHtml() {
|
||||||
const script = await getBuildInfo();
|
const script = await getBuildInfo();
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
tag: "script",
|
tag: 'script',
|
||||||
injectTo: "body",
|
injectTo: 'body',
|
||||||
children: script,
|
children: script,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
load(id) {
|
|
||||||
if (!extension || !id.includes("src")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id.includes("?vue")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const targetPath = id.replace(/\.([^.]*?)$/, `.${extension}.$1`);
|
|
||||||
if (targetPath && fs.existsSync(targetPath)) {
|
|
||||||
return fs.readFileSync(targetPath, "utf-8");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
27
src/App.vue
27
src/App.vue
|
|
@ -2,7 +2,7 @@
|
||||||
<a-config-provider>
|
<a-config-provider>
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<keep-alive :include="menuStore.caches">
|
<keep-alive :include="menuStore.caches">
|
||||||
<component v-if="hasAuth(route)" :is="Component"></component>
|
<component v-if="hasAuth" :is="Component"></component>
|
||||||
<AnForbidden v-else></AnForbidden>
|
<AnForbidden v-else></AnForbidden>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|
@ -10,27 +10,36 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
import { useMenuStore } from '@/store/menu';
|
import { useMenuStore } from '@/store/menu';
|
||||||
|
import { useUserStore } from '@/store/user';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore();
|
||||||
|
|
||||||
const hasAuth = (route: RouteLocationNormalizedLoaded) => {
|
const hasAuth = computed(() => {
|
||||||
const neddAuth = route.meta.auth;
|
return route.matched.every(item => {
|
||||||
|
console.log('i', item);
|
||||||
|
const needAuth = item.meta.auth;
|
||||||
const userAuth = userStore.auth;
|
const userAuth = userStore.auth;
|
||||||
if (!neddAuth?.length) {
|
if (needAuth?.includes('*')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (neddAuth.some(i => i === '*')) {
|
if (!userStore.accessToken && needAuth?.includes('unlogin')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (userAuth.some(i => neddAuth.some(j => j === i))) {
|
if (!userStore.accessToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!needAuth) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (userAuth.some(i => needAuth.some(j => j === i))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full overflow-hidden grid grid-rows-[auto_1fr]">
|
<div class="h-full overflow-hidden grid grid-rows-[auto_1fr]">
|
||||||
<div class="bg-white px-4 py-2">
|
<div class="bg-white px-4 py-2 border-b border-gray-200">
|
||||||
<div class="flex justify-between gap-4">
|
<div class="flex justify-between gap-4">
|
||||||
<BreadCrumb></BreadCrumb>
|
<BreadCrumb></BreadCrumb>
|
||||||
<div>
|
<div>
|
||||||
<a-link>需要帮助?</a-link>
|
<a-link>需要帮助?</a-link>
|
||||||
<a-link @click="router.push({ path: route.path, query: { s: Math.random() }, force: true })">
|
<a-button size="mini" @click="router.push({ path: route.path, query: { s: Math.random() }, force: true })">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="icon-park-outline-refresh"></i>
|
<i class="icon-park-outline-refresh"></i>
|
||||||
</template>
|
</template>
|
||||||
</a-link>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div :style="style"></div>
|
<div :style="style" class="w-full h-full bg-orange-500 flex items-center justify-center text-white text-lg">
|
||||||
|
图片组件
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType } from 'vue';
|
import { CSSProperties, PropType } from 'vue';
|
||||||
import { Image } from './interface';
|
import { Image } from './interface';
|
||||||
import { CSSProperties } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div :style="style" class="w-full h-full bg-brand-500 flex items-center justify-center text-white text-lg">
|
<div :style="style" class="w-full h-full bg-blue-500 flex items-center justify-center text-white text-lg">
|
||||||
视频组件
|
视频组件
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType } from 'vue';
|
import { CSSProperties, PropType } from 'vue';
|
||||||
import { Video } from './interface';
|
import { Video } from './interface';
|
||||||
import { CSSProperties } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<!-- 修改自: https://github.com/zuley/vue-color-picker -->
|
<!-- 修改自: https://github.com/zuley/vue-color-picker -->
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
// @ts-nocheck
|
||||||
import { onClickOutside } from "@vueuse/core";
|
import { onClickOutside } from "@vueuse/core";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
|
|
@ -1,12 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal v-model:visible="show" :fullscreen="true" :footer="false" class="an-editor">
|
||||||
v-model:visible="show"
|
|
||||||
mask-animation-name=""
|
|
||||||
modal-animation-name=""
|
|
||||||
:fullscreen="true"
|
|
||||||
:footer="false"
|
|
||||||
class="ani-modal"
|
|
||||||
>
|
|
||||||
<div class="w-full h-full bg-slate-100 grid grid-rows-[auto_1fr] select-none">
|
<div class="w-full h-full bg-slate-100 grid grid-rows-[auto_1fr] select-none">
|
||||||
<div class="h-13 bg-white border-b border-slate-200 z-10">
|
<div class="h-13 bg-white border-b border-slate-200 z-10">
|
||||||
<EditorHeader
|
<EditorHeader
|
||||||
|
|
@ -144,7 +137,7 @@ onMounted(loadData);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.ani-modal {
|
.an-editor {
|
||||||
.muti-form-item .arco-form-item .arco-form-item-label {
|
.muti-form-item .arco-form-item .arco-form-item-label {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Ref } from "vue";
|
import { Ref } from "vue";
|
||||||
import { Block } from "./block";
|
|
||||||
import { getClosestValInSortedArr } from "../utils/closest";
|
import { getClosestValInSortedArr } from "../utils/closest";
|
||||||
|
import { Block } from "./block";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件参考线
|
* 组件参考线
|
||||||
|
|
@ -100,8 +100,8 @@ export const useReferenceLine = (blocks: Ref<Block[]>, current: Ref<Block | null
|
||||||
* 6. 绘制参考线段
|
* 6. 绘制参考线段
|
||||||
*/
|
*/
|
||||||
function updateRefLine(rect: DragRect) {
|
function updateRefLine(rect: DragRect) {
|
||||||
const allXLines = [];
|
const allXLines: any[] = [];
|
||||||
const allYLines = [];
|
const allYLines: any[] = [];
|
||||||
const box = getRectBox(rect);
|
const box = getRectBox(rect);
|
||||||
let offsetX: number | undefined;
|
let offsetX: number | undefined;
|
||||||
let offsetY: number | undefined;
|
let offsetY: number | undefined;
|
||||||
|
|
@ -138,7 +138,7 @@ export const useReferenceLine = (blocks: Ref<Block[]>, current: Ref<Block | null
|
||||||
} else if (isEqualNum(closetDistX, distMaxX)) {
|
} else if (isEqualNum(closetDistX, distMaxX)) {
|
||||||
offsetX = closetMaxX - box.maxX;
|
offsetX = closetMaxX - box.maxX;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("un");
|
throw new Error('un');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ export const useReferenceLine = (blocks: Ref<Block[]>, current: Ref<Block | null
|
||||||
} else if (isEqualNum(closetDistY, distMaxY)) {
|
} else if (isEqualNum(closetDistY, distMaxY)) {
|
||||||
offsetY = closetMaxY - box.maxY;
|
offsetY = closetMaxY - box.maxY;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("un");
|
throw new Error('un');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
export function getModel(model: Recordable) {
|
export function getModel(model: Recordable) {
|
||||||
const data: Recordable = {};
|
const data: Recordable = {};
|
||||||
|
|
||||||
|
|
@ -42,7 +41,7 @@ function rmString(str: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setModelArray(data: Recordable, key: string) {
|
function setModelArray(data: Recordable, key: string) {
|
||||||
const result = [];
|
const result: any[] = [];
|
||||||
const field = rmString(key);
|
const field = rmString(key);
|
||||||
for (const key of field.split(',')) {
|
for (const key of field.split(',')) {
|
||||||
result.push(data[key]);
|
result.push(data[key]);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
{{ currentFormated }}
|
{{ currentFormated }}
|
||||||
</div>
|
</div>
|
||||||
<div class="w-96">
|
<div class="w-96">
|
||||||
<audio ref="audioRef" src="" class="hidden" @timeupdate="onTimeUpdate"></audio>
|
<audio ref="audioRef" src="" class="hidden"></audio>
|
||||||
<a-slider class="block!"></a-slider>
|
<a-slider class="block!"></a-slider>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -19,10 +19,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="dd">
|
<div class="dd">
|
||||||
<a-popover>
|
<a-popover>
|
||||||
<div
|
<div class="text-xl hover:bg-[rgba(255,255,255,.1)] h-8 px-1.5 flex items-center justify-center rounded">
|
||||||
@click="onMuteToggle"
|
|
||||||
class="text-xl hover:bg-[rgba(255,255,255,.1)] h-8 px-1.5 flex items-center justify-center rounded"
|
|
||||||
>
|
|
||||||
<i :class="volumeIcon"></i>
|
<i :class="volumeIcon"></i>
|
||||||
</div>
|
</div>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
|
@ -39,6 +36,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import numeral from 'numeral';
|
||||||
|
|
||||||
const playing = ref(true);
|
const playing = ref(true);
|
||||||
const volume = ref(50);
|
const volume = ref(50);
|
||||||
const volumeLast = ref(50);
|
const volumeLast = ref(50);
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { getIcon } from '@/pages/content/material/components/util';
|
import { getIcon } from '@/pages/content/material/util';
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
import DPlayer from 'dplayer';
|
import DPlayer from 'dplayer';
|
||||||
import numeral from 'numeral';
|
import numeral from 'numeral';
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ const router = useRouter();
|
||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"title": "404",
|
"title": "404",
|
||||||
|
"auth": ["*"],
|
||||||
"icon": "icon-park-outline-home"
|
"icon": "icon-park-outline-home"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
本页面可直接访问!
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
|
||||||
|
<route lang="json">
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"name": "DemoPage",
|
||||||
|
"sort": 101,
|
||||||
|
"title": "测试页面",
|
||||||
|
"auth": ["*"],
|
||||||
|
"icon": "icon-park-outline-home"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</route>
|
||||||
|
|
@ -30,7 +30,7 @@ export default defineComponent({
|
||||||
function renderItem(routes: MenuItem[], level = 1) {
|
function renderItem(routes: MenuItem[], level = 1) {
|
||||||
return routes.map((route): any => {
|
return routes.map((route): any => {
|
||||||
const icon = route.icon ? () => <i class={route.icon} /> : null;
|
const icon = route.icon ? () => <i class={route.icon} /> : null;
|
||||||
if (level < 3 && route.children?.some(i => !i.hide)) {
|
if (level < 3 && route.children?.some(i => i.hide !== true)) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<a-divider margin={6} class="!border-slate-100 px-2"></a-divider>
|
<a-divider margin={6} class="!border-slate-100 px-2"></a-divider>
|
||||||
|
|
@ -45,7 +45,7 @@ export default defineComponent({
|
||||||
<div>{route.title}</div>
|
<div>{route.title}</div>
|
||||||
<div class="text-xs text-gray-400">
|
<div class="text-xs text-gray-400">
|
||||||
{/* <a-badge count={8}>8</a-badge> */}
|
{/* <a-badge count={8}>8</a-badge> */}
|
||||||
{route.hide === 'prod' ? <a-tag color="blue">{'开发'}</a-tag> : null}
|
{route.hide === 'prod' ? <a-tag color="red">{'开发'}</a-tag> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ import userDropdown from './UserDropdown.vue';
|
||||||
|
|
||||||
defineOptions({ name: 'LayoutPage' });
|
defineOptions({ name: 'LayoutPage' });
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore();
|
||||||
const isCollapsed = ref(false);
|
const isCollapsed = ref(false);
|
||||||
|
|
@ -131,13 +131,6 @@ const buttons = [
|
||||||
window.open('https://github.com/appnify/starter-vue', '_blank');
|
window.open('https://github.com/appnify/starter-vue', '_blank');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: 'icon-park-outline-info',
|
|
||||||
tooltip: '关于',
|
|
||||||
onClick: () => {
|
|
||||||
window.open('https://github.com/appnify/starter-vue', '_blank');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,7 @@ const onSubmitForm = async () => {
|
||||||
"name": "LoginPage",
|
"name": "LoginPage",
|
||||||
"sort": 101,
|
"sort": 101,
|
||||||
"title": "登录",
|
"title": "登录",
|
||||||
|
"auth": ["unlogin"],
|
||||||
"icon": "icon-park-outline-home"
|
"icon": "icon-park-outline-home"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<script></script>
|
<template></template>
|
||||||
<route lang="json">
|
<route lang="json">
|
||||||
{
|
{
|
||||||
"component": null,
|
"component": null,
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<bread-page>
|
<bread-page>
|
||||||
<div class="h-full grid grid-cols-[auto_auto_1fr]">
|
<div class="h-full grid grid-cols-[1fr_auto_1fr]">
|
||||||
<div class="w-[300px]">
|
<div>
|
||||||
<a-tabs type="capsule" @change="onChange">
|
<a-tabs @change="onChange">
|
||||||
<a-tab-pane v-for="tag in tags" :key="tag.name" :title="tag.description">
|
<a-tab-pane v-for="tag in tags" :key="tag.name" :title="tag.description">
|
||||||
<a-form :model="{}" layout="vertical">
|
<a-form :model="{}" layout="vertical">
|
||||||
<a-form-item label="新增接口">
|
<a-form-item label="新增接口">
|
||||||
<a-radio-group type="button" v-model="type.create">
|
<a-radio-group type="button" v-model="type.create">
|
||||||
<a-radio
|
<a-radio
|
||||||
v-for="route in routes.filter((i) => i.tag === tag.name)"
|
v-for="route in routes.filter(i => i.tag === tag.name)"
|
||||||
:value="route.operationId"
|
:value="route.operationId"
|
||||||
:key="route.path"
|
:key="route.path"
|
||||||
>
|
>
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<a-form-item label="修改接口">
|
<a-form-item label="修改接口">
|
||||||
<a-radio-group type="button" v-model="type.modify">
|
<a-radio-group type="button" v-model="type.modify">
|
||||||
<a-radio
|
<a-radio
|
||||||
v-for="route in routes.filter((i) => i.tag === tag.name)"
|
v-for="route in routes.filter(i => i.tag === tag.name)"
|
||||||
:value="route.operationId"
|
:value="route.operationId"
|
||||||
:key="route.path"
|
:key="route.path"
|
||||||
>
|
>
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
<a-form-item label="查询接口">
|
<a-form-item label="查询接口">
|
||||||
<a-radio-group type="button" v-model="type.select">
|
<a-radio-group type="button" v-model="type.select">
|
||||||
<a-radio
|
<a-radio
|
||||||
v-for="route in routes.filter((i) => i.tag === tag.name)"
|
v-for="route in routes.filter(i => i.tag === tag.name)"
|
||||||
:value="route.operationId"
|
:value="route.operationId"
|
||||||
:key="route.path"
|
:key="route.path"
|
||||||
>
|
>
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
<a-form-item label="删除接口">
|
<a-form-item label="删除接口">
|
||||||
<a-radio-group type="button" v-model="type.delete">
|
<a-radio-group type="button" v-model="type.delete">
|
||||||
<a-radio
|
<a-radio
|
||||||
v-for="route in routes.filter((i) => i.tag === tag.name)"
|
v-for="route in routes.filter(i => i.tag === tag.name)"
|
||||||
:value="route.operationId"
|
:value="route.operationId"
|
||||||
:key="route.path"
|
:key="route.path"
|
||||||
>
|
>
|
||||||
|
|
@ -65,12 +65,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ejs from "ejs";
|
import ejs from 'ejs';
|
||||||
import doc from "./components/data.json";
|
import doc from './data.json';
|
||||||
import editorModal from "./components/editor.vue";
|
import editorModal from './editor.vue';
|
||||||
import template from "./components/page.ejs?raw";
|
import template from './page.ejs?raw';
|
||||||
|
|
||||||
const content = ref("");
|
const content = ref('');
|
||||||
const { tags, routes } = doc;
|
const { tags, routes } = doc;
|
||||||
const type = ref({
|
const type = ref({
|
||||||
create: undefined,
|
create: undefined,
|
||||||
|
|
@ -85,8 +85,8 @@ const onChange = (value: string | number) => {
|
||||||
|
|
||||||
const onOpen = () => {
|
const onOpen = () => {
|
||||||
const data = {
|
const data = {
|
||||||
tag: "",
|
tag: '',
|
||||||
operationId: "",
|
operationId: '',
|
||||||
create: {},
|
create: {},
|
||||||
select: {},
|
select: {},
|
||||||
modify: {},
|
modify: {},
|
||||||
|
|
@ -114,9 +114,9 @@ const onOpen = () => {
|
||||||
|
|
||||||
<route lang="json">
|
<route lang="json">
|
||||||
{
|
{
|
||||||
"only": "dev",
|
|
||||||
"meta": {
|
"meta": {
|
||||||
"sort": 20010,
|
"sort": 20010,
|
||||||
|
"hide": "prod",
|
||||||
"title": "接口生成",
|
"title": "接口生成",
|
||||||
"icon": "icon-park-outline-code"
|
"icon": "icon-park-outline-code"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
<template></template>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -9,6 +7,7 @@
|
||||||
"component": null,
|
"component": null,
|
||||||
"meta": {
|
"meta": {
|
||||||
"sort": 120012,
|
"sort": 120012,
|
||||||
|
"hide": "prod",
|
||||||
"title": "前端导航",
|
"title": "前端导航",
|
||||||
"link": "https://nav.juetan.cn",
|
"link": "https://nav.juetan.cn",
|
||||||
"icon": "icon-park-outline-mail"
|
"icon": "icon-park-outline-mail"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
<template>
|
<template></template>
|
||||||
<div></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<route lang="json">
|
<route lang="json">
|
||||||
{
|
{
|
||||||
"component": null,
|
"component": null,
|
||||||
"meta": {
|
"meta": {
|
||||||
|
"sort": 30000,
|
||||||
"title": "日志管理",
|
"title": "日志管理",
|
||||||
"icon": "icon-park-outline-log",
|
"icon": "icon-park-outline-log"
|
||||||
"sort": 30000
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</route>
|
</route>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
</template>
|
</template>
|
||||||
添加
|
添加
|
||||||
</a-button>
|
</a-button>
|
||||||
<ani-editor v-model:visible="visible"></ani-editor>
|
<Editor v-model:visible="visible"></Editor>
|
||||||
</template>
|
</template>
|
||||||
</LoginLogTable>
|
</LoginLogTable>
|
||||||
</BreadPage>
|
</BreadPage>
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { api } from '@/api';
|
import { api } from '@/api';
|
||||||
|
import { Editor } from '@/components/AnEditor';
|
||||||
import { useTable } from '@/components/AnTable';
|
import { useTable } from '@/components/AnTable';
|
||||||
import { Editor as aniEditor } from '@/components/editor';
|
|
||||||
import { TableColumnData } from '@arco-design/web-vue';
|
import { TableColumnData } from '@arco-design/web-vue';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ const { component: LoginLogTable } = useTable({
|
||||||
{
|
{
|
||||||
field: 'nickname',
|
field: 'nickname',
|
||||||
label: '登陆账号',
|
label: '登陆账号',
|
||||||
setter: 'input',
|
setter: 'search',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<bread-page>
|
<bread-page>
|
||||||
<a-form :model="{}" :label-col-props="{ span: 3 }" label-align="left" layout="vertical">
|
<a-form :model="{}" :label-col-props="{ span: 3 }" label-align="left" layout="vertical" class="space-y-6">
|
||||||
<a-form-item label="站点LOGO">
|
<a-form-item label="站点LOGO">
|
||||||
<a-avatar :size="64">
|
<a-avatar :size="64">
|
||||||
<img :src="appStore.logo" alt="" />
|
<img :src="appStore.logo" alt="" />
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
:disabled="!mail.enable"
|
:disabled="!mail.enable"
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
label-align="left"
|
label-align="left"
|
||||||
class="w-[580px]! divide-y divide-gray-100"
|
class="w-[580px]! space-y-6"
|
||||||
>
|
>
|
||||||
<a-form-item label="是否启用" :disabled="false">
|
<a-form-item label="是否启用" :disabled="false">
|
||||||
<a-radio-group v-model="mail.enable">
|
<a-radio-group v-model="mail.enable">
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ const { component: UserTable } = useTable({
|
||||||
{
|
{
|
||||||
field: 'nickname',
|
field: 'nickname',
|
||||||
label: '用户昵称',
|
label: '用户昵称',
|
||||||
setter: 'input',
|
setter: 'search',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
create: {
|
create: {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
<template>
|
<template></template>
|
||||||
<div></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<route lang="json">
|
<route lang="json">
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ const { component: RoleTable } = useTable({
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
label: '角色名称',
|
label: '角色名称',
|
||||||
setter: 'input',
|
setter: 'search',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
create: {
|
create: {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ const { component: PasswordModal, open } = useFormModal({
|
||||||
|
|
||||||
const usernameRender: TableColumnRender = ({ record }) => (
|
const usernameRender: TableColumnRender = ({ record }) => (
|
||||||
<div class="flex items-center gap-4 w-full overflow-hidden">
|
<div class="flex items-center gap-4 w-full overflow-hidden">
|
||||||
<a-avatar size={32} class="!bg-brand-500">
|
<a-avatar size={32}>
|
||||||
{record.avatar?.startsWith('/') ? <img src={record.avatar} alt="" /> : record.nickname?.[0]}
|
{record.avatar?.startsWith('/') ? <img src={record.avatar} alt="" /> : record.nickname?.[0]}
|
||||||
</a-avatar>
|
</a-avatar>
|
||||||
<div class="w-full flex-1 overflow-hidden">
|
<div class="w-full flex-1 overflow-hidden">
|
||||||
|
|
@ -98,7 +98,7 @@ const { component: UserTable } = useTable({
|
||||||
{
|
{
|
||||||
field: 'nickname',
|
field: 'nickname',
|
||||||
label: '用户昵称',
|
label: '用户昵称',
|
||||||
setter: 'input',
|
setter: 'search',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
create: {
|
create: {
|
||||||
|
|
@ -176,6 +176,7 @@ const { component: UserTable } = useTable({
|
||||||
"cache": true,
|
"cache": true,
|
||||||
"sort": 10301,
|
"sort": 10301,
|
||||||
"title": "用户管理",
|
"title": "用户管理",
|
||||||
|
"auth": ["*"],
|
||||||
"icon": "icon-park-outline-user"
|
"icon": "icon-park-outline-user"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,6 @@ import { menus } from '../menus';
|
||||||
import { APP_HOME_NAME } from '../routes/base';
|
import { APP_HOME_NAME } from '../routes/base';
|
||||||
import { APP_ROUTE_NAME, routes } from '../routes/page';
|
import { APP_ROUTE_NAME, routes } from '../routes/page';
|
||||||
|
|
||||||
const WHITE_LIST = ['/:all(.*)*'];
|
|
||||||
const UNSIGNIN_LIST = ['/login'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限守卫
|
* 权限守卫
|
||||||
* @param to 路由
|
* @param to 路由
|
||||||
|
|
@ -31,17 +28,12 @@ export function useAuthGuard(router: Router) {
|
||||||
const menuStore = useMenuStore(store);
|
const menuStore = useMenuStore(store);
|
||||||
|
|
||||||
// 手动指定直接通过
|
// 手动指定直接通过
|
||||||
if (to.meta.auth?.some(i => i === '*')) {
|
if (to.meta.auth?.includes('*')) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在白名单内直接通过
|
|
||||||
if (WHITE_LIST.includes(to.path)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未登陆才能访问的页面
|
// 未登陆才能访问的页面
|
||||||
if (UNSIGNIN_LIST.includes(to.path)) {
|
if (to.meta.auth?.includes('unlogin')) {
|
||||||
// 未登陆则允许通过
|
// 未登陆则允许通过
|
||||||
if (!userStore.accessToken) {
|
if (!userStore.accessToken) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
import generatedRoutes from 'virtual:generated-pages';
|
import generatedRoutes from 'virtual:generated-pages';
|
||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import { routes as vroutes } from 'vue-router/auto/routes';
|
|
||||||
|
|
||||||
console.log({ vroutes, generatedRoutes });
|
|
||||||
|
|
||||||
export const TOP_ROUTE_PREF = '_';
|
export const TOP_ROUTE_PREF = '_';
|
||||||
export const APP_ROUTE_NAME = '_layout';
|
export const APP_ROUTE_NAME = '_layout';
|
||||||
|
|
|
||||||
|
|
@ -59,30 +59,30 @@ declare module 'vue' {
|
||||||
ATextarea: typeof import('@arco-design/web-vue')['Textarea']
|
ATextarea: typeof import('@arco-design/web-vue')['Textarea']
|
||||||
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
|
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
|
||||||
AUpload: typeof import('@arco-design/web-vue')['Upload']
|
AUpload: typeof import('@arco-design/web-vue')['Upload']
|
||||||
BaseOption: typeof import('./../components/editor/components/BaseOption.vue')['default']
|
BaseOption: typeof import('./../components/AnEditor/components/BaseOption.vue')['default']
|
||||||
BreadCrumb: typeof import('./../components/breadcrumb/bread-crumb.vue')['default']
|
BreadCrumb: typeof import('./../components/AnBreadcrumb/bread-crumb.vue')['default']
|
||||||
BreadPage: typeof import('./../components/breadcrumb/bread-page.vue')['default']
|
BreadPage: typeof import('./../components/AnBreadcrumb/bread-page.vue')['default']
|
||||||
ColorPicker: typeof import('./../components/editor/components/ColorPicker.vue')['default']
|
ColorPicker: typeof import('./../components/AnEditor/components/ColorPicker.vue')['default']
|
||||||
ContextMenu: typeof import('./../components/editor/components/ContextMenu.vue')['default']
|
ContextMenu: typeof import('./../components/AnEditor/components/ContextMenu.vue')['default']
|
||||||
ContextMenuList: typeof import('./../components/editor/components/ContextMenuList.vue')['default']
|
ContextMenuList: typeof import('./../components/AnEditor/components/ContextMenuList.vue')['default']
|
||||||
DragResizer: typeof import('./../components/editor/components/DragResizer.vue')['default']
|
DragResizer: typeof import('./../components/AnEditor/components/DragResizer.vue')['default']
|
||||||
Editor: typeof import('./../components/editor/components/Editor.vue')['default']
|
Editor: typeof import('./../components/AnEditor/components/Editor.vue')['default']
|
||||||
EditorConfig: typeof import('./../components/editor/components/EditorConfig.vue')['default']
|
EditorConfig: typeof import('./../components/AnEditor/components/EditorConfig.vue')['default']
|
||||||
EditorHeader: typeof import('./../components/editor/components/EditorHeader.vue')['default']
|
EditorHeader: typeof import('./../components/AnEditor/components/EditorHeader.vue')['default']
|
||||||
EditorLeft: typeof import('./../components/editor/components/EditorLeft.vue')['default']
|
EditorLeft: typeof import('./../components/AnEditor/components/EditorLeft.vue')['default']
|
||||||
EditorMain: typeof import('./../components/editor/components/EditorMain.vue')['default']
|
EditorMain: typeof import('./../components/AnEditor/components/EditorMain.vue')['default']
|
||||||
EditorMainBlock: typeof import('./../components/editor/components/EditorMainBlock.vue')['default']
|
EditorMainBlock: typeof import('./../components/AnEditor/components/EditorMainBlock.vue')['default']
|
||||||
EditorMainHeader: typeof import('./../components/editor/components/EditorMainHeader.vue')['default']
|
EditorMainHeader: typeof import('./../components/AnEditor/components/EditorMainHeader.vue')['default']
|
||||||
EditorPreview: typeof import('./../components/editor/components/EditorPreview.vue')['default']
|
EditorPreview: typeof import('./../components/AnEditor/components/EditorPreview.vue')['default']
|
||||||
EditorRight: typeof import('./../components/editor/components/EditorRight.vue')['default']
|
EditorRight: typeof import('./../components/AnEditor/components/EditorRight.vue')['default']
|
||||||
EditorSetting: typeof import('./../components/editor/components/EditorSetting.vue')['default']
|
EditorSetting: typeof import('./../components/AnEditor/components/EditorSetting.vue')['default']
|
||||||
ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default']
|
ImagePicker: typeof import('./../components/AnEditor/components/ImagePicker.vue')['default']
|
||||||
InputColor: typeof import('./../components/editor/components/InputColor.vue')['default']
|
InputColor: typeof import('./../components/AnEditor/components/InputColor.vue')['default']
|
||||||
InputImage: typeof import('./../components/editor/components/InputImage.vue')['default']
|
InputImage: typeof import('./../components/AnEditor/components/InputImage.vue')['default']
|
||||||
InputTexter: typeof import('./../components/editor/components/InputTexter.vue')['default']
|
InputTexter: typeof import('./../components/AnEditor/components/InputTexter.vue')['default']
|
||||||
Marquee: typeof import('./../components/editor/blocks/text/marquee.vue')['default']
|
Marquee: typeof import('./../components/AnEditor/blocks/text/marquee.vue')['default']
|
||||||
Option: typeof import('./../components/editor/blocks/date/option.vue')['default']
|
Option: typeof import('./../components/AnEditor/blocks/date/option.vue')['default']
|
||||||
Render: typeof import('./../components/editor/blocks/date/render.vue')['default']
|
Render: typeof import('./../components/AnEditor/blocks/date/render.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import type {
|
||||||
|
|
||||||
declare module 'vue-router/auto/routes' {
|
declare module 'vue-router/auto/routes' {
|
||||||
export interface RouteNamedMap {
|
export interface RouteNamedMap {
|
||||||
|
'/_demo/': RouteRecordInfo<'/_demo/', '/_demo', Record<never, never>, Record<never, never>>,
|
||||||
'/_layout/': RouteRecordInfo<'/_layout/', '/_layout', Record<never, never>, Record<never, never>>,
|
'/_layout/': RouteRecordInfo<'/_layout/', '/_layout', Record<never, never>, Record<never, never>>,
|
||||||
'/_login/': RouteRecordInfo<'/_login/', '/_login', Record<never, never>, Record<never, never>>,
|
'/_login/': RouteRecordInfo<'/_login/', '/_login', Record<never, never>, Record<never, never>>,
|
||||||
'/[..._all]/': RouteRecordInfo<'/[..._all]/', '/:_all(.*)', { _all: ParamValue<true> }, { _all: ParamValue<false> }>,
|
'/[..._all]/': RouteRecordInfo<'/[..._all]/', '/:_all(.*)', { _all: ParamValue<true> }, { _all: ParamValue<false> }>,
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
import Vue from '@vitejs/plugin-vue';
|
import Vue from '@vitejs/plugin-vue';
|
||||||
import VueJsx from '@vitejs/plugin-vue-jsx';
|
import VueJsx from '@vitejs/plugin-vue-jsx';
|
||||||
import Unocss from 'unocss/vite';
|
|
||||||
import AutoImport from 'unplugin-auto-import/vite';
|
|
||||||
import AutoComponent from 'unplugin-vue-components/vite';
|
|
||||||
import router from 'unplugin-vue-router/vite';
|
|
||||||
import Page from 'vite-plugin-pages';
|
|
||||||
import iconFile from './scripts/vite/file.json';
|
|
||||||
import iconFmt from './scripts/vite/fmt.json';
|
|
||||||
import plugin from './scripts/vite/plugin';
|
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
import { presetIcons, presetUno } from 'unocss';
|
import { presetIcons, presetUno } from 'unocss';
|
||||||
|
import Unocss from 'unocss/vite';
|
||||||
|
import AutoImport from 'unplugin-auto-import/vite';
|
||||||
import { ArcoResolver } from 'unplugin-vue-components/resolvers';
|
import { ArcoResolver } from 'unplugin-vue-components/resolvers';
|
||||||
|
import AutoComponent from 'unplugin-vue-components/vite';
|
||||||
|
import router from 'unplugin-vue-router/vite';
|
||||||
import { defineConfig, loadEnv } from 'vite';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
|
import Page from 'vite-plugin-pages';
|
||||||
import { arcoToUnoColor } from './scripts/vite/color';
|
import { arcoToUnoColor } from './scripts/vite/color';
|
||||||
|
import iconFile from './scripts/vite/file.json';
|
||||||
|
import iconFmt from './scripts/vite/fmt.json';
|
||||||
|
import extension from './scripts/vite/plugin-extension';
|
||||||
|
import info from './scripts/vite/plugin-info';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vite 配置
|
* vite 配置
|
||||||
|
|
@ -78,7 +79,7 @@ export default defineConfig(({ mode }) => {
|
||||||
*/
|
*/
|
||||||
Page({
|
Page({
|
||||||
exclude: ['**/components/*', '**/*.*.*', '**/!(index).*'],
|
exclude: ['**/components/*', '**/*.*.*', '**/!(index).*'],
|
||||||
importMode: 'async',
|
importMode: 'sync',
|
||||||
extensions: ['vue'],
|
extensions: ['vue'],
|
||||||
onRoutesGenerated(routes) {
|
onRoutesGenerated(routes) {
|
||||||
const isProd = mode !== 'development';
|
const isProd = mode !== 'development';
|
||||||
|
|
@ -133,10 +134,16 @@ export default defineConfig(({ mode }) => {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目插件,打包时注入版本信息、基于文件后缀打包等
|
* 项目插件,打包时注入版本信息
|
||||||
* @see ./scripts/vite/plugin.ts
|
* @see ./scripts/vite/plugin-info.ts
|
||||||
*/
|
*/
|
||||||
plugin(),
|
info(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目插件,添加文件后缀加载内容
|
||||||
|
* @see ./scripts/vite/plugin-extension.ts
|
||||||
|
*/
|
||||||
|
extension(),
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: [
|
alias: [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue