mirror of
https://github.com/certd/certd.git
synced 2026-04-24 12:27:25 +08:00
chore: license说明
This commit is contained in:
@@ -60,7 +60,14 @@ export async function mine(): Promise<UserInfoRes> {
|
||||
});
|
||||
}
|
||||
return await request({
|
||||
url: "/sys/authority/user/mine",
|
||||
url: "/mine/info",
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
|
||||
export async function getPlusInfo() {
|
||||
return await request({
|
||||
url: "/mine/plusInfo",
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { request } from "/@/api/service";
|
||||
|
||||
export async function doActive(form: any) {
|
||||
return await request({
|
||||
url: "/sys/plus/active",
|
||||
method: "post",
|
||||
data: form
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="layout-vip" :class="{ 'layout-plus': userStore.plusInfo?.isPlus }">
|
||||
<contextHolder />
|
||||
<fs-icon icon="mingcute:vip-1-line"></fs-icon>
|
||||
<div class="text">
|
||||
<span v-if="userStore.plusInfo?.isPlus">
|
||||
<span>专业版</span>
|
||||
<span>{{ expireTime }}</span>
|
||||
</span>
|
||||
<span v-else @click="openUpgrade"> 当前免费版 </span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import dayjs from "dayjs";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const expireTime = ref("");
|
||||
if (userStore.plusInfo?.isPlus) {
|
||||
expireTime.value = dayjs(userStore.plusInfo.expireTime).format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
const formState = reactive({
|
||||
code: ""
|
||||
});
|
||||
|
||||
async function doActive() {
|
||||
if (!formState.code) {
|
||||
message.error("请输入激活码");
|
||||
throw new Error("请输入激活码");
|
||||
}
|
||||
const res = await api.doActive(formState);
|
||||
if (res) {
|
||||
await userStore.reInit();
|
||||
Modal.success({
|
||||
title: "激活成功",
|
||||
content: `您已成功激活专业版,有效期至:${dayjs(userStore.plusInfo.expireTime).format("YYYY-MM-DD")}`
|
||||
});
|
||||
}
|
||||
}
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
function openUpgrade() {
|
||||
const placeholder = "请输入激活码";
|
||||
modal.confirm({
|
||||
title: "升级专业版",
|
||||
async onOk() {
|
||||
await doActive();
|
||||
},
|
||||
content: () => {
|
||||
return (
|
||||
<div class="mt-10 mb-10">
|
||||
<a-input v-model:value={formState.code} placeholder={placeholder} />
|
||||
<div class="mt-10">
|
||||
<a href="https://afdian.com/a/greper" target="_blank">
|
||||
爱发电赞助获取激活码
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.layout-vip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
&.isPlus {
|
||||
color: #c5913f;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -12,14 +12,14 @@
|
||||
|
||||
<a-layout class="layout-body">
|
||||
<a-layout-header class="header">
|
||||
<div class="header-buttons">
|
||||
<div class="header-left header-buttons">
|
||||
<div class="menu-fold" @click="asideCollapsedToggle">
|
||||
<MenuUnfoldOutlined v-if="asideCollapsed" />
|
||||
<MenuFoldOutlined v-else />
|
||||
</div>
|
||||
<fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />
|
||||
<vip-info class="flex-center header-btn"></vip-info>
|
||||
</div>
|
||||
|
||||
<fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />
|
||||
<div class="header-right header-buttons">
|
||||
<!-- <button-->
|
||||
<!-- w:bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"-->
|
||||
@@ -83,10 +83,11 @@ import { MenuFoldOutlined, MenuUnfoldOutlined } from "@ant-design/icons-vue";
|
||||
import FsThemeSet from "/@/layout/components/theme/index.vue";
|
||||
import { env } from "../utils/util.env";
|
||||
import FsThemeModeSet from "./components/theme/mode-set.vue";
|
||||
import VipInfo from "./components/vip-info/index.vue";
|
||||
export default {
|
||||
name: "LayoutFramework",
|
||||
// eslint-disable-next-line vue/no-unused-components
|
||||
components: { FsThemeSet, MenuFoldOutlined, MenuUnfoldOutlined, FsMenu, FsLocale, FsSourceLink, FsUserInfo, FsTabs, FsThemeModeSet },
|
||||
components: { FsThemeSet, MenuFoldOutlined, MenuUnfoldOutlined, FsMenu, FsLocale, FsSourceLink, FsUserInfo, FsTabs, FsThemeModeSet, VipInfo },
|
||||
setup() {
|
||||
const resourceStore = useResourceStore();
|
||||
const frameworkMenus = computed(() => {
|
||||
@@ -133,6 +134,7 @@ export default {
|
||||
.fs-framework {
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
min-width: 1200px;
|
||||
.menu-fold {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -174,34 +176,41 @@ export default {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
.header-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > * {
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
}
|
||||
height: 100%;
|
||||
|
||||
& > .header-btn {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
.ant-layout-header.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.header-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > * {
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
}
|
||||
height: 100%;
|
||||
//border-bottom: 1px solid rgba(255, 255, 255, 0);
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
|
||||
& > .header-btn {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
//border-bottom: 1px solid rgba(255, 255, 255, 0);
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.header-right {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
.header-menu {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.header-right {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
.header-menu {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.aside-menu {
|
||||
flex: 1;
|
||||
ui {
|
||||
|
||||
@@ -146,7 +146,6 @@ export default {
|
||||
// position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
// 请根据自身业务需要修改
|
||||
const token = userStore.getToken;
|
||||
if (token) {
|
||||
await userStore.init();
|
||||
next();
|
||||
} else {
|
||||
// 没有登录的时候跳转到登录界面
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "../index";
|
||||
import router from "../../router";
|
||||
// @ts-ignore
|
||||
import { LocalStorage } from "/src/utils/util.storage";
|
||||
// @ts-ignore
|
||||
import * as UserApi from "/src/api/modules/api.user";
|
||||
import { RegisterReq } from "/src/api/modules/api.user";
|
||||
// @ts-ignore
|
||||
import { LoginReq, UserInfoRes } from "/@/api/modules/api.user";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
import { mitter } from "/src/utils/util.mitt";
|
||||
import { RegisterReq } from "/src/api/modules/api.user";
|
||||
|
||||
interface UserState {
|
||||
userInfo: Nullable<UserInfoRes>;
|
||||
token?: string;
|
||||
plusInfo?: PlusInfo;
|
||||
inited: boolean;
|
||||
}
|
||||
|
||||
interface PlusInfo {
|
||||
level: number;
|
||||
expireTime: number;
|
||||
isPlus: boolean;
|
||||
}
|
||||
|
||||
const USER_INFO_KEY = "USER_INFO";
|
||||
@@ -26,7 +33,10 @@ export const useUserStore = defineStore({
|
||||
// user info
|
||||
userInfo: null,
|
||||
// token
|
||||
token: undefined
|
||||
token: undefined,
|
||||
// plus
|
||||
plusInfo: null,
|
||||
inited: false
|
||||
}),
|
||||
getters: {
|
||||
getUserInfo(): UserInfoRes {
|
||||
@@ -73,10 +83,7 @@ export const useUserStore = defineStore({
|
||||
// save token
|
||||
this.setToken(token, expire);
|
||||
// get user info
|
||||
const userInfo = await this.getUserInfoAction();
|
||||
await router.replace("/");
|
||||
mitter.emit("app.login", { userInfo, token: data });
|
||||
return userInfo;
|
||||
return await this.onLoginSuccess(data);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
@@ -86,6 +93,19 @@ export const useUserStore = defineStore({
|
||||
this.setUserInfo(userInfo);
|
||||
return userInfo;
|
||||
},
|
||||
|
||||
async onLoginSuccess(loginData: any) {
|
||||
await this.getUserInfoAction();
|
||||
await this.loadPlusInfo();
|
||||
const userInfo = await this.getUserInfoAction();
|
||||
mitter.emit("app.login", { userInfo, token: loginData, plusInfo: this.plusInfo });
|
||||
await router.replace("/");
|
||||
return userInfo;
|
||||
},
|
||||
|
||||
async loadPlusInfo() {
|
||||
this.plusInfo = await UserApi.getPlusInfo();
|
||||
},
|
||||
/**
|
||||
* @description: logout
|
||||
*/
|
||||
@@ -108,6 +128,19 @@ export const useUserStore = defineStore({
|
||||
await this.logout(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
async init() {
|
||||
if (this.inited) {
|
||||
return;
|
||||
}
|
||||
if (this.getToken) {
|
||||
await this.loadPlusInfo();
|
||||
}
|
||||
this.inited = true;
|
||||
},
|
||||
async reInit() {
|
||||
this.inited = false;
|
||||
await this.init();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,9 +14,6 @@ html, body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body{
|
||||
min-width: 1000px;
|
||||
}
|
||||
div#app {
|
||||
height: 100%
|
||||
}
|
||||
@@ -48,6 +45,11 @@ h1, h2, h3, h4, h5, h6 {
|
||||
vertical-align: 0 !important;
|
||||
}
|
||||
|
||||
.flex-center{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.flex-o{
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user