mirror of https://github.com/certd/certd
chore: 集成vben
parent
8fcabc5e9f
commit
9557fc799e
|
@ -58,7 +58,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||||
},
|
},
|
||||||
required: false,
|
required: false,
|
||||||
order: 100,
|
order: 100,
|
||||||
helper: "PFX、jks格式证书是否加密\njks必须设置密码,不传则默认123456",
|
helper: "PFX、jks格式证书是否加密\njks必须设置密码,不传则默认123456\npfx不传则为空密码",
|
||||||
})
|
})
|
||||||
pfxPassword!: string;
|
pfxPassword!: string;
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,8 @@ function createService() {
|
||||||
error.message += `: ${error.response?.config?.url}`;
|
error.message += `: ${error.response?.config?.url}`;
|
||||||
errorLog(error, error?.response?.config?.showErrorNotify);
|
errorLog(error, error?.response?.config?.showErrorNotify);
|
||||||
if (status === 401) {
|
if (status === 401) {
|
||||||
const userStore = useUserStore();
|
// const userStore = useUserStore();
|
||||||
userStore.logout();
|
// userStore.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error?.config?.onError) {
|
if (error?.config?.onError) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<td style="width: 100px; text-align: center">记录类型</td>
|
<td style="width: 100px; text-align: center">记录类型</td>
|
||||||
<td style="width: 250px">请设置CNAME记录(验证成功以后不要删除)</td>
|
<td style="width: 250px">请设置CNAME记录(验证成功以后不要删除)</td>
|
||||||
<td style="width: 120px" class="center">状态</td>
|
<td style="width: 120px" class="center">状态</td>
|
||||||
<td style="width: 80px" class="center">操作</td>
|
<td style="width: 90px" class="center">操作</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<template v-for="key in domains" :key="key">
|
<template v-for="key in domains" :key="key">
|
||||||
|
|
|
@ -13,7 +13,7 @@ const slots = defineSlots();
|
||||||
<div class="tutorial-button pointer" @click="open">
|
<div class="tutorial-button pointer" @click="open">
|
||||||
<template v-if="!slots.default">
|
<template v-if="!slots.default">
|
||||||
<fs-icon icon="ant-design:question-circle-outlined"></fs-icon>
|
<fs-icon icon="ant-design:question-circle-outlined"></fs-icon>
|
||||||
<div class="ml-5">使用教程</div>
|
<div class="hidden md:block ml-0.5">使用教程</div>
|
||||||
</template>
|
</template>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<a-modal v-model:open="openedRef" class="tutorial-modal" width="90%">
|
<a-modal v-model:open="openedRef" class="tutorial-modal" width="90%">
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
<contextHolder />
|
<contextHolder />
|
||||||
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
||||||
|
|
||||||
<div v-if="mode !== 'icon'" class="text">
|
<div v-if="mode !== 'icon'" class="text hidden md:block ml-0.5">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template #title> {{ text.title }}</template>
|
<template #title> {{ text.title }}</template>
|
||||||
<span>{{ text.name }}</span>
|
<span class="">{{ text.name }}</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -390,7 +390,6 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
margin-left: 5px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import { createI18n } from "vue-i18n";
|
|
||||||
import en from "./locale/en";
|
import en from "./locale/en";
|
||||||
import zh from "./locale/zh_CN";
|
import zh from "./locale/zh_CN";
|
||||||
const messages = {
|
import { SupportedLanguagesType } from "/@/vben/locales";
|
||||||
en: {
|
export const messages = {
|
||||||
|
"en-US": {
|
||||||
label: "English",
|
label: "English",
|
||||||
...en
|
...en
|
||||||
},
|
},
|
||||||
"zh-cn": {
|
"zh-CN": {
|
||||||
label: "简体中文",
|
label: "简体中文",
|
||||||
...zh
|
...zh
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createI18n({
|
// export default createI18n({
|
||||||
legacy: false,
|
// legacy: false,
|
||||||
locale: "zh-cn",
|
// locale: "zh-cn",
|
||||||
fallbackLocale: "zh-cn",
|
// fallbackLocale: "zh-cn",
|
||||||
messages
|
// messages
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
export async function loadMessages(lang: SupportedLanguagesType) {
|
||||||
|
return messages[lang];
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-between full-w">
|
<div class="flex flex-between w-full text-sm p-5 bg-neutral-100 dark:bg-neutral-900">
|
||||||
<div class="flex">
|
<div class="flex items-center">
|
||||||
<span v-if="!settingStore.isComm">
|
<span v-if="!settingStore.isComm">
|
||||||
<span>Powered by</span>
|
<span>Powered by</span>
|
||||||
<a> handsfree.work </a>
|
<a> handsfree.work </a>
|
||||||
|
@ -26,7 +26,7 @@ import { computed, onMounted, ref } from "vue";
|
||||||
import { useSettingStore } from "/@/store/modules/settings";
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "Footer"
|
name: "PageFooter"
|
||||||
});
|
});
|
||||||
const version = ref(import.meta.env.VITE_APP_VERSION);
|
const version = ref(import.meta.env.VITE_APP_VERSION);
|
||||||
|
|
||||||
|
|
|
@ -8,28 +8,29 @@ import { useUserStore } from "/@/store/modules/user";
|
||||||
import VipButton from "/@/components/vip-button/index.vue";
|
import VipButton from "/@/components/vip-button/index.vue";
|
||||||
import TutorialButton from "/@/components/tutorial/index.vue";
|
import TutorialButton from "/@/components/tutorial/index.vue";
|
||||||
import { useSettingStore } from "/@/store/modules/settings";
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
import Footer from "./components/footer/index.vue";
|
import PageFooter from "./components/footer/index.vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const accessStore = useAccessStore();
|
const accessStore = useAccessStore();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
const menus = computed(() => [
|
const menus = computed(() => [
|
||||||
// {
|
{
|
||||||
// handler: () => {
|
handler: () => {
|
||||||
// openWindow(VBEN_DOC_URL, {
|
router.push("/certd/mine/user-profile");
|
||||||
// target: "_blank"
|
},
|
||||||
// });
|
icon: "fa-solid:book",
|
||||||
// },
|
text: "账号信息"
|
||||||
// icon: BookOpenText,
|
}
|
||||||
// text: $t("ui.widgets.document")
|
|
||||||
// }
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const avatar = computed(() => {
|
const avatar = computed(() => {
|
||||||
return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
|
const avt = userStore.getUserInfo?.avatar;
|
||||||
|
return avt ? `/api/basic/file/download?key=${avt}` : "";
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleLogout() {
|
async function handleLogout() {
|
||||||
await userStore.logout(true);
|
userStore.logout(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
@ -56,21 +57,21 @@ onMounted(async () => {
|
||||||
<template>
|
<template>
|
||||||
<BasicLayout @clear-preferences-and-logout="handleLogout">
|
<BasicLayout @clear-preferences-and-logout="handleLogout">
|
||||||
<template #user-dropdown>
|
<template #user-dropdown>
|
||||||
<UserDropdown :avatar :menus :text="userStore.userInfo?.nickName" description="development@handsfree.work" tag-text="Pro" @logout="handleLogout" />
|
<UserDropdown :avatar="avatar" :menus="menus" :text="userStore.userInfo?.nickName || userStore.userInfo?.username" description="" tag-text="" @logout="handleLogout" />
|
||||||
</template>
|
</template>
|
||||||
<template #lock-screen>
|
<template #lock-screen>
|
||||||
<LockScreen :avatar @to-login="handleLogout" />
|
<LockScreen :avatar @to-login="handleLogout" />
|
||||||
</template>
|
</template>
|
||||||
<template #header-right-0>
|
<template #header-right-0>
|
||||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5 pl-3 pr-3">
|
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
|
||||||
<tutorial-button v-if="!settingStore.isComm" class="flex-center header-btn" />
|
<tutorial-button v-if="!settingStore.isComm" class="flex-center header-btn" />
|
||||||
</div>
|
</div>
|
||||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5 pl-3 pr-3">
|
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full">
|
||||||
<vip-button class="flex-center header-btn" mode="nav" />
|
<vip-button class="flex-center header-btn" mode="nav" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<Footer></Footer>
|
<PageFooter></PageFooter>
|
||||||
</template>
|
</template>
|
||||||
</BasicLayout>
|
</BasicLayout>
|
||||||
</template>
|
</template>
|
||||||
|
@ -78,5 +79,6 @@ onMounted(async () => {
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.header-btn {
|
.header-btn {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
padding: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,7 +3,8 @@ import App from "./App.vue";
|
||||||
// import Antd from "ant-design-vue";
|
// import Antd from "ant-design-vue";
|
||||||
import Antd from "./plugin/antdv-async/index";
|
import Antd from "./plugin/antdv-async/index";
|
||||||
import "./style/common.less";
|
import "./style/common.less";
|
||||||
import i18n from "./i18n";
|
import { loadMessages } from "./i18n";
|
||||||
|
import { i18n } from "/@/vben/locales";
|
||||||
import components from "./components";
|
import components from "./components";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import plugin from "./plugin/";
|
import plugin from "./plugin/";
|
||||||
|
@ -17,9 +18,9 @@ async function bootstrap() {
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
// app.use(Antd);
|
// app.use(Antd);
|
||||||
app.use(Antd);
|
app.use(Antd);
|
||||||
await setupVben(app);
|
await setupVben(app, { loadMessages });
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(i18n);
|
// app.use(i18n);
|
||||||
// app.use(store);
|
// app.use(store);
|
||||||
app.use(components);
|
app.use(components);
|
||||||
app.use(plugin, { i18n });
|
app.use(plugin, { i18n });
|
||||||
|
|
|
@ -7,15 +7,17 @@ import Empty from "ant-design-vue/es/empty";
|
||||||
import Avatar from "ant-design-vue/es/avatar";
|
import Avatar from "ant-design-vue/es/avatar";
|
||||||
import Steps from "ant-design-vue/es/steps";
|
import Steps from "ant-design-vue/es/steps";
|
||||||
import Select from "ant-design-vue/es/select";
|
import Select from "ant-design-vue/es/select";
|
||||||
|
import PageHeader from "ant-design-vue/es/page-header";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(app: any) {
|
install(app: any) {
|
||||||
app.use(Input);
|
app.use(Input);
|
||||||
app.use(Button);
|
app.use(Button);
|
||||||
app.component("ADivider", Divider);
|
app.use(Divider);
|
||||||
app.component("ABadge", Badge);
|
app.use(Badge);
|
||||||
app.component("AEmpty", Empty);
|
app.use(Empty);
|
||||||
app.component("AAvatar", Avatar);
|
app.use(Avatar);
|
||||||
|
app.use(PageHeader);
|
||||||
app.use(Steps);
|
app.use(Steps);
|
||||||
app.use(Select);
|
app.use(Select);
|
||||||
|
|
||||||
|
@ -165,8 +167,8 @@ export default {
|
||||||
defineAsyncComponent(() => import("ant-design-vue/es/tree-select"))
|
defineAsyncComponent(() => import("ant-design-vue/es/tree-select"))
|
||||||
);
|
);
|
||||||
app.component(
|
app.component(
|
||||||
"AToar",
|
"ATour",
|
||||||
defineAsyncComponent(() => import("ant-design-vue/es/tree-select"))
|
defineAsyncComponent(() => import("ant-design-vue/es/tour"))
|
||||||
);
|
);
|
||||||
|
|
||||||
app.component(
|
app.component(
|
||||||
|
@ -186,5 +188,40 @@ export default {
|
||||||
"AProgress",
|
"AProgress",
|
||||||
defineAsyncComponent(() => import("ant-design-vue/es/progress"))
|
defineAsyncComponent(() => import("ant-design-vue/es/progress"))
|
||||||
);
|
);
|
||||||
|
app.component(
|
||||||
|
"ATimelineItem",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/timeline/TimelineItem"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"ATimeline",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/timeline/Timeline"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"APageHeader",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/page-header/index"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"APopover",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/popover"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"APopconfirm",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/popconfirm"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"ACollapse",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/collapse"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"ADescriptions",
|
||||||
|
defineAsyncComponent(() => import("ant-design-vue/es/descriptions"))
|
||||||
|
);
|
||||||
|
app.component(
|
||||||
|
"ADescriptionsItem",
|
||||||
|
defineAsyncComponent(async () => {
|
||||||
|
const m = await import("ant-design-vue/es/descriptions/");
|
||||||
|
return m.DescriptionsItem;
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,7 +28,6 @@ export function registerRouterHook() {
|
||||||
if (!token || token === "undefined") {
|
if (!token || token === "undefined") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化权限列表
|
// 初始化权限列表
|
||||||
try {
|
try {
|
||||||
console.log("permission is enabled");
|
console.log("permission is enabled");
|
||||||
|
|
|
@ -4,17 +4,25 @@ import { getPermissions } from "./api";
|
||||||
import { mitter } from "/@/utils/util.mitt";
|
import { mitter } from "/@/utils/util.mitt";
|
||||||
import { env } from "/@/utils/util.env";
|
import { env } from "/@/utils/util.env";
|
||||||
import { useAccessStore } from "/@/vben/stores";
|
import { useAccessStore } from "/@/vben/stores";
|
||||||
|
import { eachTree } from "/@/utils/util.tree";
|
||||||
|
import util from "/@/plugin/permission/util.permission";
|
||||||
|
|
||||||
//监听注销事件
|
//监听注销事件
|
||||||
mitter.on("app.logout", () => {
|
mitter.on("app.logout", () => {
|
||||||
const permissionStore = usePermissionStore();
|
const permissionStore = usePermissionStore();
|
||||||
permissionStore.clear();
|
permissionStore.clear();
|
||||||
|
const accessStore = useAccessStore();
|
||||||
|
accessStore.setIsAccessChecked(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
mitter.on("app.login", () => {
|
mitter.on("app.login", () => {
|
||||||
const permissionStore = useResourceStore();
|
const accessStore = useAccessStore();
|
||||||
|
accessStore.setIsAccessChecked(false);
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
permissionStore.clear();
|
permissionStore.clear();
|
||||||
permissionStore.init();
|
// const accessStore = useAccessStore();
|
||||||
|
// accessStore.setAccessCode([]);
|
||||||
|
// permissionStore.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
interface PermissionState {
|
interface PermissionState {
|
||||||
|
@ -28,7 +36,7 @@ interface PermissionState {
|
||||||
* @param permissionList
|
* @param permissionList
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
function formatPermissions(menuTree: Array<any>, permissionList: any[] = []) {
|
export function formatPermissions(menuTree: Array<any>, permissionList: any[] = []) {
|
||||||
if (menuTree == null) {
|
if (menuTree == null) {
|
||||||
menuTree = [];
|
menuTree = [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,32 @@ import { useAccessStore } from "/@/vben/stores";
|
||||||
import { generateMenus, startProgress, stopProgress } from "/@/vben/utils";
|
import { generateMenus, startProgress, stopProgress } from "/@/vben/utils";
|
||||||
import { frameworkRoutes } from "/@/router/resolve";
|
import { frameworkRoutes } from "/@/router/resolve";
|
||||||
import { useSettingStore } from "/@/store/modules/settings";
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
import { usePermissionStore } from "/@/plugin/permission/store.permission";
|
||||||
|
import util from "/@/plugin/permission/util.permission";
|
||||||
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
|
|
||||||
|
function buildAccessedMenus(menus: any) {
|
||||||
|
if (menus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const list: any = [];
|
||||||
|
for (const sub of menus) {
|
||||||
|
if (sub.meta?.permission != null) {
|
||||||
|
if (!util.hasPermissions(sub.meta.permission)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const item: any = {
|
||||||
|
...sub
|
||||||
|
};
|
||||||
|
|
||||||
|
list.push(item);
|
||||||
|
if (sub.children && sub.children.length > 0) {
|
||||||
|
item.children = buildAccessedMenus(sub.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 通用守卫配置
|
* 通用守卫配置
|
||||||
* @param router
|
* @param router
|
||||||
|
@ -70,7 +95,15 @@ function setupAccessGuard(router: Router) {
|
||||||
|
|
||||||
// 是否已经生成过动态路由
|
// 是否已经生成过动态路由
|
||||||
if (!accessStore.isAccessChecked) {
|
if (!accessStore.isAccessChecked) {
|
||||||
const accessibleMenus = await generateMenus(frameworkRoutes[0].children, router);
|
if (accessStore.accessToken) {
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
|
await permissionStore.loadFromRemote();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
await userStore.getUserInfoAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const allMenus = await generateMenus(frameworkRoutes[0].children, router);
|
||||||
|
const accessibleMenus = buildAccessedMenus(allMenus);
|
||||||
accessStore.setAccessRoutes(frameworkRoutes);
|
accessStore.setAccessRoutes(frameworkRoutes);
|
||||||
accessStore.setAccessMenus(accessibleMenus);
|
accessStore.setAccessMenus(accessibleMenus);
|
||||||
accessStore.setIsAccessChecked(true);
|
accessStore.setIsAccessChecked(true);
|
||||||
|
|
|
@ -66,7 +66,8 @@ export const certdResources = [
|
||||||
{
|
{
|
||||||
title: "设置",
|
title: "设置",
|
||||||
name: "MineSetting",
|
name: "MineSetting",
|
||||||
path: "/certd/mine",
|
path: "/certd/setting",
|
||||||
|
redirect: "/certd/cname/record",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:settings-outline",
|
icon: "ion:settings-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { HeaderMenus, PlusInfo, SiteEnv, SiteInfo, SuiteSetting, SysInstallInfo,
|
||||||
import { useUserStore } from "/@/store/modules/user";
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
import { mitter } from "/@/utils/util.mitt";
|
import { mitter } from "/@/utils/util.mitt";
|
||||||
import { env } from "/@/utils/util.env";
|
import { env } from "/@/utils/util.env";
|
||||||
import { preferences } from "/@/vben/preferences";
|
import { updatePreferences } from "/@/vben/preferences";
|
||||||
|
|
||||||
export interface SettingState {
|
export interface SettingState {
|
||||||
sysPublic?: SysPublicSetting;
|
sysPublic?: SysPublicSetting;
|
||||||
|
@ -140,7 +140,11 @@ export const useSettingStore = defineStore({
|
||||||
this.siteInfo = _.merge({}, defaultSiteInfo, siteInfo);
|
this.siteInfo = _.merge({}, defaultSiteInfo, siteInfo);
|
||||||
|
|
||||||
if (this.siteInfo.logo) {
|
if (this.siteInfo.logo) {
|
||||||
preferences.logo.source = this.siteInfo.logo;
|
updatePreferences({
|
||||||
|
logo: {
|
||||||
|
source: this.siteInfo.logo
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async checkUrlBound() {
|
async checkUrlBound() {
|
||||||
|
|
|
@ -13,6 +13,8 @@ import { useI18n } from "vue-i18n";
|
||||||
import { mitter } from "/src/utils/util.mitt";
|
import { mitter } from "/src/utils/util.mitt";
|
||||||
import { resetAllStores, useAccessStore } from "/@/vben/stores";
|
import { resetAllStores, useAccessStore } from "/@/vben/stores";
|
||||||
|
|
||||||
|
import { useUserStore as vbenUserStore } from "/@/vben/stores/modules/user";
|
||||||
|
|
||||||
interface UserState {
|
interface UserState {
|
||||||
userInfo: Nullable<UserInfoRes>;
|
userInfo: Nullable<UserInfoRes>;
|
||||||
token?: string;
|
token?: string;
|
||||||
|
@ -48,6 +50,8 @@ export const useUserStore = defineStore({
|
||||||
},
|
},
|
||||||
setUserInfo(info: UserInfoRes) {
|
setUserInfo(info: UserInfoRes) {
|
||||||
this.userInfo = info;
|
this.userInfo = info;
|
||||||
|
const userStore = vbenUserStore();
|
||||||
|
userStore.setUserInfo(info);
|
||||||
LocalStorage.set(USER_INFO_KEY, info);
|
LocalStorage.set(USER_INFO_KEY, info);
|
||||||
},
|
},
|
||||||
resetState() {
|
resetState() {
|
||||||
|
@ -81,6 +85,7 @@ export const useUserStore = defineStore({
|
||||||
// get user info
|
// get user info
|
||||||
return await this.onLoginSuccess(loginRes);
|
return await this.onLoginSuccess(loginRes);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,8 +11,8 @@ import "./styles/antd/index.css";
|
||||||
import { useTitle } from "@vueuse/core";
|
import { useTitle } from "@vueuse/core";
|
||||||
import { setupI18n } from "/@/vben/locales";
|
import { setupI18n } from "/@/vben/locales";
|
||||||
|
|
||||||
export async function setupVben(app: any) {
|
export async function setupVben(app: any, { loadMessages }: any) {
|
||||||
await setupI18n(app);
|
await setupI18n(app, { loadMessages });
|
||||||
const store = await initStores(app, { namespace: "fs" });
|
const store = await initStores(app, { namespace: "fs" });
|
||||||
|
|
||||||
return { store };
|
return { store };
|
||||||
|
|
|
@ -78,7 +78,7 @@ function transformComponent(component: VNode, route: RouteLocationNormalizedLoad
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative h-full">
|
<div class="relative h-full bg-white dark:bg-black">
|
||||||
<IFrameRouterView />
|
<IFrameRouterView />
|
||||||
<RouterView v-slot="{ Component, route }">
|
<RouterView v-slot="{ Component, route }">
|
||||||
<Transition :name="getTransitionName(route)" appear mode="out-in">
|
<Transition :name="getTransitionName(route)" appear mode="out-in">
|
||||||
|
|
|
@ -73,7 +73,7 @@ function useMixedMenu() {
|
||||||
if (!needSplit.value) {
|
if (!needSplit.value) {
|
||||||
return menus.value;
|
return menus.value;
|
||||||
}
|
}
|
||||||
return menus.value.map((item) => {
|
return menus.value.map((item: any) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
children: []
|
children: []
|
||||||
|
@ -85,6 +85,10 @@ function useMixedMenu() {
|
||||||
* 侧边菜单
|
* 侧边菜单
|
||||||
*/
|
*/
|
||||||
const sidebarMenus = computed(() => {
|
const sidebarMenus = computed(() => {
|
||||||
|
if (preferences.app.isMobile) {
|
||||||
|
return [...holdMenus.value, ...menus.value];
|
||||||
|
}
|
||||||
|
|
||||||
const sideMenus = needSplit.value ? splitSideMenus.value : menus.value;
|
const sideMenus = needSplit.value ? splitSideMenus.value : menus.value;
|
||||||
return [...holdMenus.value, ...sideMenus];
|
return [...holdMenus.value, ...sideMenus];
|
||||||
});
|
});
|
||||||
|
@ -116,7 +120,7 @@ function useMixedMenu() {
|
||||||
}
|
}
|
||||||
if (!splitSideMenus.value || splitSideMenus.value.length === 0) {
|
if (!splitSideMenus.value || splitSideMenus.value.length === 0) {
|
||||||
//仍然为空,从所有菜单中查找
|
//仍然为空,从所有菜单中查找
|
||||||
const hasChildren = allMenus.value.find((item) => {
|
const hasChildren = allMenus.value.find((item: any) => {
|
||||||
return item.children && item.children.length > 0;
|
return item.children && item.children.length > 0;
|
||||||
});
|
});
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
|
@ -136,7 +140,7 @@ function useMixedMenu() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootMenu = menus.value.find((item) => item.path === key);
|
const rootMenu = menus.value.find((item: any) => item.path === key);
|
||||||
rootMenuPath.value = rootMenu?.path ?? "";
|
rootMenuPath.value = rootMenu?.path ?? "";
|
||||||
splitSideMenus.value = rootMenu?.children ?? [];
|
splitSideMenus.value = rootMenu?.children ?? [];
|
||||||
saveLastSplitSideMenus();
|
saveLastSplitSideMenus();
|
||||||
|
@ -165,7 +169,7 @@ function useMixedMenu() {
|
||||||
function calcSideMenus(path: string = route.path) {
|
function calcSideMenus(path: string = route.path) {
|
||||||
let { rootMenu } = findRootMenuByPath(menus.value, path);
|
let { rootMenu } = findRootMenuByPath(menus.value, path);
|
||||||
if (!rootMenu) {
|
if (!rootMenu) {
|
||||||
rootMenu = menus.value.find((item) => item.path === path);
|
rootMenu = menus.value.find((item: any) => item.path === path);
|
||||||
}
|
}
|
||||||
const result = findRootMenuByPath(rootMenu?.children || [], path, 1);
|
const result = findRootMenuByPath(rootMenu?.children || [], path, 1);
|
||||||
mixedRootMenuPath.value = result.rootMenuPath ?? "";
|
mixedRootMenuPath.value = result.rootMenuPath ?? "";
|
||||||
|
|
|
@ -9,9 +9,9 @@ const defaultPreferences: Preferences = {
|
||||||
colorWeakMode: false,
|
colorWeakMode: false,
|
||||||
compact: false,
|
compact: false,
|
||||||
contentCompact: "wide",
|
contentCompact: "wide",
|
||||||
defaultAvatar: "https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp",
|
defaultAvatar: "./static/images/logo/logo.svg",
|
||||||
dynamicTitle: true,
|
dynamicTitle: true,
|
||||||
enableCheckUpdates: true,
|
enableCheckUpdates: false,
|
||||||
enablePreferences: true,
|
enablePreferences: true,
|
||||||
enableRefreshToken: false,
|
enableRefreshToken: false,
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
|
@ -65,7 +65,7 @@ const defaultPreferences: Preferences = {
|
||||||
globalSearch: true
|
globalSearch: true
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
autoActivateChild: false,
|
autoActivateChild: true,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapsedShowTitle: false,
|
collapsedShowTitle: false,
|
||||||
enable: true,
|
enable: true,
|
||||||
|
@ -108,9 +108,9 @@ const defaultPreferences: Preferences = {
|
||||||
widget: {
|
widget: {
|
||||||
fullscreen: true,
|
fullscreen: true,
|
||||||
globalSearch: true,
|
globalSearch: true,
|
||||||
languageToggle: true,
|
languageToggle: false,
|
||||||
lockScreen: true,
|
lockScreen: true,
|
||||||
notification: true,
|
notification: false,
|
||||||
refresh: true,
|
refresh: true,
|
||||||
sidebarToggle: true,
|
sidebarToggle: true,
|
||||||
themeToggle: true
|
themeToggle: true
|
||||||
|
|
|
@ -1,40 +1,32 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TabsEmits, TabsProps } from './types';
|
import type { TabsEmits, TabsProps } from "./types";
|
||||||
|
|
||||||
import { useForwardPropsEmits } from '/@/vben/composables';
|
import { useForwardPropsEmits } from "/@/vben/composables";
|
||||||
import { ChevronLeft, ChevronRight } from '/@/vben/icons';
|
import { ChevronLeft, ChevronRight } from "/@/vben/icons";
|
||||||
import { VbenScrollbar } from '/@/vben/shadcn-ui';
|
import { VbenScrollbar } from "/@/vben/shadcn-ui";
|
||||||
|
|
||||||
import { Tabs, TabsChrome } from './components';
|
import { Tabs, TabsChrome } from "./components";
|
||||||
import { useTabsDrag } from './use-tabs-drag';
|
import { useTabsDrag } from "./use-tabs-drag";
|
||||||
import { useTabsViewScroll } from './use-tabs-view-scroll';
|
import { useTabsViewScroll } from "./use-tabs-view-scroll";
|
||||||
|
|
||||||
interface Props extends TabsProps {}
|
interface Props extends TabsProps {}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'TabsView',
|
name: "TabsView"
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
contentClass: 'vben-tabs-content',
|
contentClass: "vben-tabs-content",
|
||||||
draggable: true,
|
draggable: true,
|
||||||
styleType: 'chrome',
|
styleType: "chrome",
|
||||||
wheelable: true,
|
wheelable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<TabsEmits>();
|
const emit = defineEmits<TabsEmits>();
|
||||||
|
|
||||||
const forward = useForwardPropsEmits(props, emit);
|
const forward = useForwardPropsEmits(props, emit);
|
||||||
|
|
||||||
const {
|
const { handleScrollAt, handleWheel, scrollbarRef, scrollDirection, scrollIsAtLeft, scrollIsAtRight, showScrollButton } = useTabsViewScroll(props);
|
||||||
handleScrollAt,
|
|
||||||
handleWheel,
|
|
||||||
scrollbarRef,
|
|
||||||
scrollDirection,
|
|
||||||
scrollIsAtLeft,
|
|
||||||
scrollIsAtRight,
|
|
||||||
showScrollButton,
|
|
||||||
} = useTabsViewScroll(props);
|
|
||||||
|
|
||||||
function onWheel(e: WheelEvent) {
|
function onWheel(e: WheelEvent) {
|
||||||
if (props.wheelable) {
|
if (props.wheelable) {
|
||||||
|
@ -48,13 +40,13 @@ useTabsDrag(props, emit);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex h-full flex-1 overflow-hidden">
|
<div class="flex h-full flex-1 overflow-hidden bg-gray-100 dark:bg-black">
|
||||||
<!-- 左侧滚动按钮 -->
|
<!-- 左侧滚动按钮 -->
|
||||||
<span
|
<span
|
||||||
v-show="showScrollButton"
|
v-show="showScrollButton"
|
||||||
:class="{
|
:class="{
|
||||||
'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtLeft,
|
'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtLeft,
|
||||||
'pointer-events-none opacity-30': scrollIsAtLeft,
|
'pointer-events-none opacity-30': scrollIsAtLeft
|
||||||
}"
|
}"
|
||||||
class="border-r px-2"
|
class="border-r px-2"
|
||||||
@click="scrollDirection('left')"
|
@click="scrollDirection('left')"
|
||||||
|
@ -64,27 +56,12 @@ useTabsDrag(props, emit);
|
||||||
|
|
||||||
<div
|
<div
|
||||||
:class="{
|
:class="{
|
||||||
'pt-[3px]': styleType === 'chrome',
|
'pt-[3px]': styleType === 'chrome'
|
||||||
}"
|
}"
|
||||||
class="size-full flex-1 overflow-hidden"
|
class="size-full flex-1 overflow-hidden"
|
||||||
>
|
>
|
||||||
<VbenScrollbar
|
<VbenScrollbar ref="scrollbarRef" :shadow-bottom="false" :shadow-top="false" class="h-full" horizontal scroll-bar-class="z-10 hidden " shadow shadow-left shadow-right @scroll-at="handleScrollAt" @wheel="onWheel">
|
||||||
ref="scrollbarRef"
|
<TabsChrome v-if="styleType === 'chrome'" v-bind="{ ...forward, ...$attrs, ...$props }" />
|
||||||
:shadow-bottom="false"
|
|
||||||
:shadow-top="false"
|
|
||||||
class="h-full"
|
|
||||||
horizontal
|
|
||||||
scroll-bar-class="z-10 hidden "
|
|
||||||
shadow
|
|
||||||
shadow-left
|
|
||||||
shadow-right
|
|
||||||
@scroll-at="handleScrollAt"
|
|
||||||
@wheel="onWheel"
|
|
||||||
>
|
|
||||||
<TabsChrome
|
|
||||||
v-if="styleType === 'chrome'"
|
|
||||||
v-bind="{ ...forward, ...$attrs, ...$props }"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Tabs v-else v-bind="{ ...forward, ...$attrs, ...$props }" />
|
<Tabs v-else v-bind="{ ...forward, ...$attrs, ...$props }" />
|
||||||
</VbenScrollbar>
|
</VbenScrollbar>
|
||||||
|
@ -95,7 +72,7 @@ useTabsDrag(props, emit);
|
||||||
v-show="showScrollButton"
|
v-show="showScrollButton"
|
||||||
:class="{
|
:class="{
|
||||||
'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtRight,
|
'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtRight,
|
||||||
'pointer-events-none opacity-30': scrollIsAtRight,
|
'pointer-events-none opacity-30': scrollIsAtRight
|
||||||
}"
|
}"
|
||||||
class="hover:bg-muted text-muted-foreground cursor-pointer border-l px-2"
|
class="hover:bg-muted text-muted-foreground cursor-pointer border-l px-2"
|
||||||
@click="scrollDirection('right')"
|
@click="scrollDirection('right')"
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<div class="layout-left">
|
<div class="layout-left">
|
||||||
<div class="pipeline-container">
|
<div class="pipeline-container bg-neutral-100 dark:bg-black">
|
||||||
<div class="pipeline">
|
<div class="pipeline">
|
||||||
<v-draggable v-model="pipeline.stages" class="stages" item-key="id" handle=".stage-move-handle" :disabled="!settingStore.isPlus">
|
<v-draggable v-model="pipeline.stages" class="stages" item-key="id" handle=".stage-move-handle" :disabled="!settingStore.isPlus">
|
||||||
<template #header>
|
<template #header>
|
||||||
|
@ -95,19 +95,10 @@
|
||||||
<!-- :open="true"-->
|
<!-- :open="true"-->
|
||||||
<template #content>
|
<template #content>
|
||||||
<div v-for="(item, index) of task.steps" :key="item.id" class="flex-o w-100">
|
<div v-for="(item, index) of task.steps" :key="item.id" class="flex-o w-100">
|
||||||
<span class="ellipsis flex-1 step-title" :class="{ disabled: item.disabled, deleted: item.disabled }">
|
<span class="ellipsis flex-1 step-title" :class="{ disabled: item.disabled, deleted: item.disabled }"> {{ index + 1 }}. {{ item.title }} </span>
|
||||||
{{ index + 1 }}. {{ item.title }}
|
|
||||||
</span>
|
|
||||||
<pi-status-show v-if="!editMode" :status="item.status?.result"></pi-status-show>
|
<pi-status-show v-if="!editMode" :status="item.status?.result"></pi-status-show>
|
||||||
<a-tooltip title="强制重新执行此步骤">
|
<a-tooltip title="强制重新执行此步骤">
|
||||||
<fs-icon
|
<fs-icon v-if="!editMode" class="pointer color-blue ml-2" style="font-size: 16px" title="强制重新执行此步骤" icon="icon-park-outline:replay-music" @click="run(item.id)"></fs-icon>
|
||||||
v-if="!editMode"
|
|
||||||
class="pointer color-blue ml-2"
|
|
||||||
style="font-size: 16px"
|
|
||||||
title="强制重新执行此步骤"
|
|
||||||
icon="icon-park-outline:replay-music"
|
|
||||||
@click="run(item.id)"
|
|
||||||
></fs-icon>
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -231,7 +222,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layout-right">
|
<div class="layout-right">
|
||||||
<a-page-header title="运行历史" sub-title="点任务可查看日志" class="logs-block">
|
<a-page-header title="运行历史" sub-title="点任务可查看日志" class="logs-block" :ghost="false">
|
||||||
<a-timeline class="mt-10">
|
<a-timeline class="mt-10">
|
||||||
<template v-for="item of histories" :key="item.id">
|
<template v-for="item of histories" :key="item.id">
|
||||||
<pi-history-timeline-item
|
<pi-history-timeline-item
|
||||||
|
@ -813,7 +804,6 @@ export default defineComponent({
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #f0f0f0;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
.pipeline {
|
.pipeline {
|
||||||
|
@ -821,7 +811,6 @@ export default defineComponent({
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #f0f0f0;
|
|
||||||
.stages {
|
.stages {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
|
@ -1,36 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dashboard-user">
|
<div class="dashboard-user">
|
||||||
<div class="header-profile">
|
<div class="header-profile flex-wrap bg-white dark:bg-black">
|
||||||
<div class="avatar">
|
<div class="flex flex-1">
|
||||||
<a-avatar v-if="userInfo.avatar" size="large" :src="'/api/basic/file/download?&key=' + userInfo.avatar" style="background-color: #eee"> </a-avatar>
|
<div class="avatar">
|
||||||
<a-avatar v-else size="large" style="background-color: #00b4f5">
|
<a-avatar v-if="userInfo.avatar" size="large" :src="'/api/basic/file/download?&key=' + userInfo.avatar" style="background-color: #eee"> </a-avatar>
|
||||||
{{ userInfo.username }}
|
<a-avatar v-else size="large" style="background-color: #00b4f5">
|
||||||
</a-avatar>
|
{{ userInfo.username }}
|
||||||
</div>
|
</a-avatar>
|
||||||
<div class="text">
|
</div>
|
||||||
<div class="left">
|
<div class="text">
|
||||||
<div>
|
<div class="left">
|
||||||
<span>您好,{{ userInfo.nickName || userInfo.username }}, 欢迎使用 【{{ siteInfo.title }}】</span>
|
<div>
|
||||||
</div>
|
<span>您好,{{ userInfo.nickName || userInfo.username }}, 欢迎使用 【{{ siteInfo.title }}】</span>
|
||||||
<div class="flex-o">
|
</div>
|
||||||
<a-tag color="green" class="flex-inline pointer m-0"> <fs-icon icon="ion:time-outline"></fs-icon> {{ now }}</a-tag>
|
<div class="flex-o">
|
||||||
<template v-if="userStore.isAdmin">
|
<a-tag color="green" class="flex-inline pointer m-0"> <fs-icon icon="ion:time-outline"></fs-icon> {{ now }}</a-tag>
|
||||||
<a-divider type="vertical" />
|
<template v-if="userStore.isAdmin">
|
||||||
<a-badge :dot="hasNewVersion">
|
<a-divider type="vertical" />
|
||||||
<a-tag color="blue" class="flex-inline pointer m-0" :title="'最新版本:' + latestVersion" @click="openUpgradeUrl()">
|
<a-badge :dot="hasNewVersion">
|
||||||
<fs-icon icon="ion:rocket-outline" class="mr-5"></fs-icon>
|
<a-tag color="blue" class="flex-inline pointer m-0" :title="'最新版本:' + latestVersion" @click="openUpgradeUrl()">
|
||||||
v{{ version }}
|
<fs-icon icon="ion:rocket-outline" class="mr-5"></fs-icon>
|
||||||
</a-tag>
|
v{{ version }}
|
||||||
</a-badge>
|
</a-tag>
|
||||||
</template>
|
</a-badge>
|
||||||
<template v-if="settingsStore.isComm">
|
</template>
|
||||||
<a-divider type="vertical" />
|
<template v-if="settingsStore.isComm">
|
||||||
<suite-card class="m-0"></suite-card>
|
<a-divider type="vertical" />
|
||||||
</template>
|
<suite-card class="m-0"></suite-card>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="suggest">
|
|
||||||
|
<div class="suggest hidden md:block">
|
||||||
<tutorial-button class="flex-center mt-2">
|
<tutorial-button class="flex-center mt-2">
|
||||||
<a-tooltip title="点击查看详细教程">
|
<a-tooltip title="点击查看详细教程">
|
||||||
<a-tag color="blue" class="flex-center">
|
<a-tag color="blue" class="flex-center">
|
||||||
|
@ -53,8 +56,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="statistic-data m-20">
|
<div class="statistic-data m-20">
|
||||||
<a-row :gutter="20">
|
<a-row :gutter="20" class="flex-wrap">
|
||||||
<a-col :span="6">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="证书流水线数量" :count="count.pipelineCount">
|
<statistic-card title="证书流水线数量" :count="count.pipelineCount">
|
||||||
<template v-if="count.pipelineCount === 0" #default>
|
<template v-if="count.pipelineCount === 0" #default>
|
||||||
<div class="flex-center flex-1 flex-col">
|
<div class="flex-center flex-1 flex-col">
|
||||||
|
@ -67,17 +70,17 @@
|
||||||
</template>
|
</template>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="流水线状态" :footer="false">
|
<statistic-card title="流水线状态" :footer="false">
|
||||||
<pie-count v-if="count.pipelineStatusCount" :data="count.pipelineStatusCount"></pie-count>
|
<pie-count v-if="count.pipelineStatusCount" :data="count.pipelineStatusCount"></pie-count>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="最近运行统计" :footer="false">
|
<statistic-card title="最近运行统计" :footer="false">
|
||||||
<day-count v-if="count.historyCountPerDay" :data="count.historyCountPerDay" title="运行次数"></day-count>
|
<day-count v-if="count.historyCountPerDay" :data="count.historyCountPerDay" title="运行次数"></day-count>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="最快到期证书">
|
<statistic-card title="最快到期证书">
|
||||||
<expiring-list v-if="count.expiringList" :data="count.expiringList"></expiring-list>
|
<expiring-list v-if="count.expiringList" :data="count.expiringList"></expiring-list>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
|
@ -91,9 +94,9 @@
|
||||||
已支持的部署任务总览 <a-tag color="green">{{ pluginGroups.groups.all.plugins.length }}</a-tag>
|
已支持的部署任务总览 <a-tag color="green">{{ pluginGroups.groups.all.plugins.length }}</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<a-row :gutter="10">
|
<a-row :gutter="10">
|
||||||
<a-col v-for="item of pluginGroups.groups.all.plugins" :key="item.name" class="plugin-item-col" :span="4">
|
<a-col v-for="item of pluginGroups.groups.all.plugins" :key="item.name" class="plugin-item-col" :xl="4" :md="6" :xs="24">
|
||||||
<a-card>
|
<a-card>
|
||||||
<a-tooltip :title="item.desc" class="flex-between">
|
<a-tooltip :title="item.desc" class="flex-between overflow-hidden">
|
||||||
<div class="plugin-item pointer">
|
<div class="plugin-item pointer">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<fs-icon :icon="item.icon" class="font-size-16 color-blue" />
|
<fs-icon :icon="item.icon" class="font-size-16 color-blue" />
|
||||||
|
@ -239,7 +242,6 @@ function openUpgradeUrl() {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<fs-page class="home—index">
|
<fs-page class="home—index bg-neutral-100 dark:bg-black">
|
||||||
<!-- <page-content />-->
|
<!-- <page-content />-->
|
||||||
<dashboard-user />
|
<dashboard-user />
|
||||||
<change-password-button ref="changePasswordButtonRef" :show-button="false"></change-password-button>
|
<change-password-button ref="changePasswordButtonRef" :show-button="false"></change-password-button>
|
||||||
|
@ -32,6 +32,5 @@ onMounted(() => {
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.home—index {
|
.home—index {
|
||||||
background-color: #eee;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="sys-settings-form sys-settings-register">
|
<div class="sys-settings-form sys-settings-register">
|
||||||
<a-form :model="formState" name="register" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish">
|
<a-form :model="formState" name="register" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish">
|
||||||
|
<a-form-item label="管理其他用户流水线" :name="['public', 'managerOtherUserPipeline']">
|
||||||
|
<a-switch v-model:checked="formState.public.managerOtherUserPipeline" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="限制用户流水线数量" :name="['public', 'limitUserPipelineCount']">
|
||||||
|
<a-input-number v-model:value="formState.public.limitUserPipelineCount" />
|
||||||
|
<div class="helper">0为不限制</div>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label="开启自助注册" :name="['public', 'registerEnabled']">
|
<a-form-item label="开启自助注册" :name="['public', 'registerEnabled']">
|
||||||
<a-switch v-model:checked="formState.public.registerEnabled" />
|
<a-switch v-model:checked="formState.public.registerEnabled" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<template v-if="formState.public.registerEnabled">
|
<template v-if="formState.public.registerEnabled">
|
||||||
<a-form-item label="限制用户流水线数量" :name="['public', 'limitUserPipelineCount']">
|
|
||||||
<a-input-number v-model:value="formState.public.limitUserPipelineCount" />
|
|
||||||
<div class="helper">0为不限制</div>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="管理其他用户流水线" :name="['public', 'managerOtherUserPipeline']">
|
|
||||||
<a-switch v-model:checked="formState.public.managerOtherUserPipeline" />
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item label="开启用户名注册" :name="['public', 'usernameRegisterEnabled']">
|
<a-form-item label="开启用户名注册" :name="['public', 'usernameRegisterEnabled']">
|
||||||
<a-switch v-model:checked="formState.public.usernameRegisterEnabled" />
|
<a-switch v-model:checked="formState.public.usernameRegisterEnabled" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
|
@ -97,7 +97,7 @@ export default ({ command, mode }) => {
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: 3002,
|
port: 3008,
|
||||||
fs: devServerFs,
|
fs: devServerFs,
|
||||||
proxy: {
|
proxy: {
|
||||||
// with options
|
// with options
|
||||||
|
|
Loading…
Reference in New Issue