feat:重构模块
5
Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
FROM nginx:1.27.0
|
||||||
|
COPY dist/ /usr/share/nginx/html/
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||||
|
RUN echo 'Asia/Shanghai' > /etc/timezone
|
||||||
22
nginx.conf
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
location /blog-admin/ {
|
||||||
|
alias /usr/share/nginx/html/;
|
||||||
|
try_files $uri $uri/ /blog-admin/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /blog-api/ {
|
||||||
|
proxy_pass http://blog-service:8082/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
6112
pnpm-lock.yaml
generated
@@ -4,7 +4,7 @@ import { IBlog, IBlogCategory, IBlogComment, IBlogStats, IBlogVisit, INewBlog, I
|
|||||||
import qs from 'qs'
|
import qs from 'qs'
|
||||||
import { IPageRecord } from '@/types'
|
import { IPageRecord } from '@/types'
|
||||||
|
|
||||||
export const queryBlogApi = (currentPage: number, pageSize: number): Promise<any> =>
|
export const queryBlogApi = (currentPage: number, pageSize: number): Promise<IPageRecord<IBlog>> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/blog-api/blog/page',
|
url: '/blog-api/blog/page',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -58,50 +58,30 @@ export const addBlogCommentApi = (blogComment: IBlogComment): Promise<boolean> =
|
|||||||
data: blogComment
|
data: blogComment
|
||||||
})
|
})
|
||||||
|
|
||||||
export const queryAdminBlogApi = (currentPage: number,
|
|
||||||
pageSize: number): Promise<IPageRecord<IBlog>> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/admin-service/blog-manage/page',
|
|
||||||
method: 'get',
|
|
||||||
params: { currentPage, pageSize }
|
|
||||||
})
|
|
||||||
|
|
||||||
export const queryAdminBlogByIdApi = (id: number): Promise<IBlog> =>
|
|
||||||
cloudService({
|
|
||||||
url: `/admin-service/blog-manage/content/${id}`,
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const queryAdminBlogCategoryApi = (): Promise<IBlogCategory[]> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/admin-service/blog-manage/category',
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const addBlogApi = (blog: INewBlog): Promise<boolean> =>
|
export const addBlogApi = (blog: INewBlog): Promise<boolean> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/admin-service/blog-manage',
|
url: '/blog-api/blog',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: blog
|
data: blog
|
||||||
})
|
})
|
||||||
|
|
||||||
export const updateBlogApi = (id: number, blog: INewBlog): Promise<boolean> =>
|
export const updateBlogApi = (id: number, blog: INewBlog): Promise<boolean> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: `/admin-service/blog-manage/${id}`,
|
url: `/blog-api/blog/${id}`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: blog
|
data: blog
|
||||||
})
|
})
|
||||||
|
|
||||||
export const deleteBlogApi = (id: number): Promise<boolean> =>
|
export const deleteBlogApi = (id: number): Promise<boolean> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: `/admin-service/blog-manage/${id}`,
|
url: `/blog-api/blog/${id}`,
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
})
|
})
|
||||||
|
|
||||||
export const queryBlogVisitApi = (currentPage: number,
|
export const queryBlogVisitApi = (currentPage: number,
|
||||||
pageSize: number): Promise<IPageRecord<IBlogVisit>> =>
|
pageSize: number): Promise<IPageRecord<IBlogVisit>> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/admin-service/blog-manage/visit',
|
url: '/blog-api/blog/visit',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { currentPage, pageSize }
|
params: { currentPage, pageSize }
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -43,35 +43,8 @@
|
|||||||
<el-button type="primary" style="width: 100%;"
|
<el-button type="primary" style="width: 100%;"
|
||||||
:disabled="!authStore.isVerified"
|
:disabled="!authStore.isVerified"
|
||||||
:loading="authStore.loginLoading"
|
:loading="authStore.loginLoading"
|
||||||
@click.prevent="handleLogin('common')">登录
|
@click.prevent="handleLogin()">登录
|
||||||
</el-button>
|
</el-button>
|
||||||
<div />
|
|
||||||
<el-button type="primary" style="width: 100%;"
|
|
||||||
:disabled="!authStore.isVerified"
|
|
||||||
:loading="authStore.loginAdminLoading"
|
|
||||||
@click.prevent="handleLogin('admin')">登录管理系统
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<div class="login-type">
|
|
||||||
<el-button @click="authStore.changeLoginType('phone')">手机号登录</el-button>
|
|
||||||
<el-button>扫码登录</el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="login-others-type">
|
|
||||||
<el-divider content-position="center">其他登录方式</el-divider>
|
|
||||||
|
|
||||||
<div class="type-list">
|
|
||||||
<i class="fa-brands fa-weixin" style="color: #3CB034"></i>
|
|
||||||
<i class="fa-brands fa-qq" style="color: #29A4D9"></i>
|
|
||||||
<i class="fa-solid fa-envelope" style="color: #4971B8"
|
|
||||||
@click="authStore.changeLoginType('email')"></i>
|
|
||||||
<i class="fa-brands fa-github" style="color: #555555"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="login-register">
|
|
||||||
<span>还没有账户?</span><el-link type="primary">创建账户</el-link>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -84,7 +57,6 @@ import { ElMessage, FormRules } from 'element-plus'
|
|||||||
import { onMounted, reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
import { loginRules } from '@/utils/element/elRules'
|
import { loginRules } from '@/utils/element/elRules'
|
||||||
import { getLocalStorage, setLocalStorage } from 'vue3-common/utils/storageUtil'
|
import { getLocalStorage, setLocalStorage } from 'vue3-common/utils/storageUtil'
|
||||||
import { ILoginType } from '@/types/auth'
|
|
||||||
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
import { isMobile } from 'vue3-common/utils/layoutUtil'
|
||||||
|
|
||||||
const rules = reactive<FormRules>(loginRules)
|
const rules = reactive<FormRules>(loginRules)
|
||||||
@@ -101,42 +73,31 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleLogin = async (type: ILoginType) => {
|
const handleLogin = async () => {
|
||||||
loginFormRef.value.validate(async (valid: any) => {
|
loginFormRef.value.validate(async (valid: any) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (type === 'common' && !isMobile()) {
|
if (isMobile()) {
|
||||||
ElMessage.error('目前只支持移动端')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === 'admin' && isMobile()) {
|
|
||||||
ElMessage.error('目前只支持PC端')
|
ElMessage.error('目前只支持PC端')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'common') {
|
authStore.loginLoading = true
|
||||||
authStore.loginLoading = true
|
|
||||||
} else {
|
|
||||||
authStore.loginAdminLoading = true
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await authStore.handleLogin(type)
|
if (authStore.loginForm.username === 'admin' && authStore.loginForm.password === '19940822Cxx') {
|
||||||
userStore.handleSession(authStore.homeSession)
|
await router.push('/dashboard')
|
||||||
|
} else {
|
||||||
|
ElMessage.error('账号或密码错误')
|
||||||
|
}
|
||||||
|
// await authStore.handleLogin(type)
|
||||||
|
// userStore.handleSession(authStore.homeSession)
|
||||||
|
|
||||||
// 2. 存储账户密码到localStorage中
|
// 2. 存储账户密码到localStorage中
|
||||||
if (authStore.loginForm.isRemember) {
|
// if (authStore.loginForm.isRemember) {
|
||||||
setLocalStorage('loginForm', JSON.stringify(authStore.loginForm))
|
// setLocalStorage('loginForm', JSON.stringify(authStore.loginForm))
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (type === 'common') {
|
|
||||||
await router.push('/mobile-home')
|
|
||||||
} else {
|
|
||||||
await router.push('/admin')
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
authStore.loginLoading = false
|
authStore.loginLoading = false
|
||||||
authStore.loginAdminLoading = false
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error('请输入正确的信息')
|
ElMessage.error('请输入正确的信息')
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="email-login">
|
|
||||||
<el-form ref="loginFormRef" :model="authStore.emailLoginForm"
|
|
||||||
:rules="rules" class="login-form"
|
|
||||||
autocomplete="on" label-position="left"
|
|
||||||
@submit.native.prevent>
|
|
||||||
<el-form-item prop="email" class="form-item">
|
|
||||||
<el-input
|
|
||||||
v-model="authStore.emailLoginForm.email"
|
|
||||||
placeholder="请输入邮箱地址" clearable
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<i class="fa-solid fa-envelope"></i>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item prop="code" class="code-item">
|
|
||||||
<el-input
|
|
||||||
v-model="authStore.emailLoginForm.code"
|
|
||||||
placeholder="请输入验证码" type="password"
|
|
||||||
show-password clearable
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<i class="fa-solid fa-shield-halved"></i>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
|
|
||||||
<el-button type="primary"
|
|
||||||
:disabled="authStore.isGettingCode"
|
|
||||||
@click="authStore.getAuthCode('email')">
|
|
||||||
{{ authStore.isGettingCode ? authStore.getCodeCountdown + 's' : '获取验证码' }}
|
|
||||||
</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<el-button type="primary" style="width: 100%;"
|
|
||||||
:loading="authStore.loginLoading"
|
|
||||||
@click.prevent="handleLogin()">登录
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<el-button style="width: 100%;margin-left: 0;"
|
|
||||||
@click="authStore.changeLoginType('common')">取消
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useAuthStore } from '@/store/auth'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { ElMessage, FormRules } from 'element-plus'
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import { loginRules } from '@/utils/element/elRules'
|
|
||||||
|
|
||||||
const rules = reactive<FormRules>(loginRules)
|
|
||||||
const authStore = useAuthStore()
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const loginFormRef = ref()
|
|
||||||
|
|
||||||
const handleLogin = async () => {
|
|
||||||
loginFormRef.value.validate(async (valid: any) => {
|
|
||||||
if (valid) {
|
|
||||||
authStore.loginLoading = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
await authStore.handleLogin('email')
|
|
||||||
await router.push('/home')
|
|
||||||
} finally {
|
|
||||||
authStore.loginLoading = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ElMessage.error('请输入正确的信息')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="phone-login">
|
|
||||||
<el-form ref="loginFormRef" :model="authStore.phoneLoginForm"
|
|
||||||
:rules="rules" class="login-form"
|
|
||||||
autocomplete="on" label-position="left"
|
|
||||||
@submit.native.prevent>
|
|
||||||
<el-form-item prop="phoneNumber" class="form-item">
|
|
||||||
<el-input
|
|
||||||
v-model="authStore.phoneLoginForm.phoneNumber"
|
|
||||||
placeholder="请输入手机号" clearable
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<i class="fa-solid fa-mobile-screen"></i>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item prop="code" class="code-item">
|
|
||||||
<el-input
|
|
||||||
v-model="authStore.phoneLoginForm.code"
|
|
||||||
placeholder="请输入验证码" type="password"
|
|
||||||
show-password clearable
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<i class="fa-solid fa-shield-halved"></i>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
|
|
||||||
<el-button type="primary"
|
|
||||||
:disabled="authStore.isGettingCode"
|
|
||||||
@click="authStore.getAuthCode('phone')">
|
|
||||||
{{ authStore.isGettingCode ? authStore.getCodeCountdown + 's' : '获取验证码' }}
|
|
||||||
</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<el-button type="primary" style="width: 100%;"
|
|
||||||
:loading="authStore.loginLoading"
|
|
||||||
@click.prevent="handleLogin()">登录
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<el-button style="width: 100%;margin-left: 0;"
|
|
||||||
@click="authStore.changeLoginType('common')">取消
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useAuthStore } from '@/store/auth'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { ElMessage, FormRules } from 'element-plus'
|
|
||||||
import { reactive, ref } from 'vue'
|
|
||||||
import { loginRules } from '@/utils/element/elRules'
|
|
||||||
|
|
||||||
const rules = reactive<FormRules>(loginRules)
|
|
||||||
const authStore = useAuthStore()
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const loginFormRef = ref()
|
|
||||||
|
|
||||||
const handleLogin = async () => {
|
|
||||||
loginFormRef.value.validate(async (valid: any) => {
|
|
||||||
if (valid) {
|
|
||||||
authStore.loginLoading = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
await authStore.handleLogin('phone')
|
|
||||||
await router.push('/home')
|
|
||||||
} finally {
|
|
||||||
authStore.loginLoading = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ElMessage.error('请输入正确的信息')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
1
src/icons/svg/admin/account.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1740234710091" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5922" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M843.887 795.499H721.549c-26.891-104.975-116.46-186.516-227.404-204.47 26.375-19.235 48.58-43.592 65.038-71.555a223.756 223.756 0 0 1 21.676-1.06h153.435c120.558 0 219.195 95.915 219.195 213.138 0 35.17-73.433 63.947-109.602 63.947zM657.575 465.012c-25.475 0-49.679-5.289-71.527-14.793a229.522 229.522 0 0 0 4.892-47.229c0-74.293-35.478-140.508-90.843-183.551 28.547-56.531 88.333-95.448 157.478-95.448 96.851 0 175.356 76.339 175.356 170.51 0 94.171-78.505 170.511-175.356 170.511zM367.4 569.5c-96.843 0-175.357-76.346-175.357-170.508 0-94.177 78.514-170.511 175.357-170.511 96.842 0 175.352 76.334 175.352 170.511 0 94.162-78.51 170.508-175.352 170.508z m76.715 53.405c120.554 0 219.19 95.912 219.19 213.138 0 35.17-73.428 63.946-109.593 63.946H181.083c-36.165 0-109.598-28.776-109.598-63.946 0-117.226 98.637-213.138 219.195-213.138h153.435z" fill="" p-id="5923"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
1
src/icons/svg/admin/blog.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728286707582" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M146.285714 292.571429l585.142857 0 0 73.142857-585.142857 0 0-73.142857Z" p-id="5405"></path><path d="M146.285714 475.428571l219.428571 0 0 256-219.428571 0 0-256Z" p-id="5406"></path><path d="M438.857143 475.428571l292.571429 0 0 36.571429-292.571429 0 0-36.571429Z" p-id="5407"></path><path d="M438.857143 585.142857l292.571429 0 0 36.571429-292.571429 0 0-36.571429Z" p-id="5408"></path><path d="M438.857143 694.857143l292.571429 0 0 36.571429-292.571429 0 0-36.571429Z" p-id="5409"></path><path d="M987.428571 292.571429l-109.714286 0L877.714286 109.714286c0-20.196571-16.356571-36.571429-36.571429-36.571429L36.571429 73.142857C16.3584 73.142857 0 89.517714 0 109.714286l0 804.571429c0 20.214857 16.356571 36.571429 36.571429 36.571429l950.857143 0c20.214857 0 36.571429-16.356571 36.571429-36.571429L1024 329.142857C1024 308.946286 1007.643429 292.571429 987.428571 292.571429zM804.571429 877.714286 73.142857 877.714286 73.142857 146.285714l731.428571 0L804.571429 877.714286zM950.857143 877.714286l-73.142857 0L877.714286 365.714286l73.142857 0L950.857143 877.714286z" p-id="5410"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
1
src/icons/svg/admin/blogArticle.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728286765424" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6478" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M788.551 292.895c-74.801 0-135.633-60.832-135.633-135.605v-156.171h-487.636c-45.595 0-82.548 36.982-82.548 82.549v856.719c0 45.567 36.955 82.493 82.548 82.493h693.46c45.571 0 82.523-36.926 82.523-82.493v-647.493h-152.714zM805.084 839.116h-586.199v-55.301h586.199v55.301zM805.084 662.15h-586.199v-55.301h586.199v55.301zM805.084 485.184h-586.199v-55.301h586.199v55.301z" fill="" p-id="6479"></path><path d="M706.002 1.119v156.171c0 45.567 36.955 82.493 82.549 82.493h152.714l-235.263-238.662z" fill="" p-id="6480"></path></svg>
|
||||||
|
After Width: | Height: | Size: 859 B |
1
src/icons/svg/admin/blogCategory.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728286806955" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7518" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M366.553536 16.452169 92.462812 16.452169c-50.531062 0-91.873497 41.343614-91.873497 91.873497l0 274.090527c0 50.531062 41.343614 91.873497 91.873497 91.873497l274.090527 0c50.531062 0 91.873497-41.343614 91.873497-91.873497L458.426836 108.326846C458.427033 57.795783 417.083418 16.452169 366.553536 16.452169zM366.553536 566.164563 92.462812 566.164563c-50.531062 0-91.873497 39.812275-91.873497 90.342354l0 275.621867c0 50.531062 41.343614 91.873693 91.873497 91.873693l274.090527 0c50.531062 0 91.873497-41.343614 91.873497-91.873693L458.426836 658.03806C458.427033 607.508178 417.083418 566.164563 366.553536 566.164563zM916.26593 16.452169 642.175206 16.452169c-50.531062 0-91.873497 41.343614-91.873497 91.873497l0 274.090527c0 50.531062 41.343614 91.873497 91.873497 91.873497l274.090527 0c50.531062 0 91.873497-41.343614 91.873497-91.873497L1008.139231 108.326846C1008.140607 57.795783 966.796993 16.452169 916.26593 16.452169zM916.26593 566.164563 642.175206 566.164563c-50.531062 0-91.873497 39.812275-91.873497 90.342354l0 275.621867c0 50.531062 41.343614 91.873693 91.873497 91.873693l274.090527 0c50.531062 0 91.873497-41.343614 91.873497-91.873693l0-274.089544C1008.140607 607.508178 966.796993 566.164563 916.26593 566.164563z" fill="" p-id="7519"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
1
src/icons/svg/admin/blogLog.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728286912539" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9408" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M960 512c0-59.5-40.9-109.7-96.1-124v68.6c-9.4-5.5-20.4-8.6-32-8.6-35.3 0-64.1 28.7-64.1 64s28.7 64 64.1 64c11.7 0 22.6-3.1 32-8.6V636c-10.2 2.6-21 4.1-32 4.1-70.7 0-128.1-57.4-128.1-128s57.5-128 128.1-128c11.1 0 21.8 1.4 32 4V192c0-52.9-41.8-96-93.1-96H221.2c-51.3 0-93.1 43.1-93.1 96v159.5h128.1v64H128.1V352H64v64h64.1v191.5h128.1v64H127.1V608H64v64h64.1v160c0 52.9 41.8 96 93.1 96h549.6c51.3 0 93.1-43.1 93.1-96V635.9C919.1 621.7 960 571.5 960 512zM320.3 288h384.4v64H320.3v-64z m0 192h318.4v64H320.3v-64z m384.4 256H320.3v-64h384.4v64z m164.4-276z m4.9 3.9l-0.1-0.1s0.1 0 0.1 0.1zM869.1 564z m4.9-3.9l-0.1 0.1s0.1 0 0.1-0.1z m21.9-45.2c0-1 0.1-1.9 0.1-2.9s0-2-0.1-2.9c0 1 0.1 1.9 0.1 2.9s-0.1 2-0.1 2.9z m-17.7 41.2l0.3-0.3-0.3 0.3z m1.6-1.7l0.1-0.1-0.1 0.1z m2.3-2.8c0.2-0.2 0.3-0.4 0.5-0.6-0.2 0.2-0.3 0.4-0.5 0.6z m1.5-1.9c0.2-0.2 0.4-0.5 0.5-0.7-0.2 0.2-0.3 0.4-0.5 0.7z m2-2.9c0.2-0.3 0.4-0.6 0.6-1-0.2 0.4-0.4 0.7-0.6 1z m1.3-2.2c0.3-0.4 0.5-0.9 0.8-1.4-0.2 0.5-0.5 1-0.8 1.4z m1.7-2.9c0.2-0.5 0.5-0.9 0.7-1.4-0.2 0.5-0.5 0.9-0.7 1.4z m1.2-2.5c0.3-0.6 0.6-1.3 0.9-1.9-0.3 0.7-0.6 1.3-0.9 1.9z m1.3-2.9c0.2-0.6 0.5-1.2 0.7-1.8-0.2 0.6-0.4 1.2-0.7 1.8z m1.1-2.8c0.3-0.8 0.5-1.6 0.8-2.4-0.3 0.9-0.5 1.7-0.8 2.4z m1-2.9c0.2-0.7 0.4-1.5 0.6-2.2-0.2 0.8-0.4 1.5-0.6 2.2z m0.8-3c0.2-0.9 0.4-1.8 0.6-2.6-0.2 0.8-0.4 1.7-0.6 2.6z m0.7-2.9c0.2-0.8 0.3-1.7 0.5-2.5-0.2 0.8-0.4 1.6-0.5 2.5z m0.5-3.3c0.1-0.9 0.3-1.9 0.4-2.8-0.1 0.9-0.2 1.8-0.4 2.8z m0.4-3c0.1-0.9 0.2-1.9 0.2-2.8 0 1-0.1 1.9-0.2 2.8z m-17.4-50.5l0.3 0.3-0.3-0.3z m1.6 1.7l0.1 0.1-0.1-0.1z m2.3 2.8c0.2 0.2 0.3 0.4 0.5 0.6-0.2-0.2-0.3-0.4-0.5-0.6z m1.5 1.9c0.2 0.2 0.4 0.5 0.5 0.7-0.2-0.2-0.3-0.4-0.5-0.7z m2 2.9c0.2 0.3 0.4 0.7 0.6 1-0.2-0.4-0.4-0.7-0.6-1z m1.3 2.2c0.3 0.4 0.5 0.9 0.8 1.4-0.2-0.5-0.5-1-0.8-1.4z m1.7 2.9c0.2 0.5 0.5 0.9 0.7 1.4-0.2-0.5-0.5-0.9-0.7-1.4z m1.2 2.5c0.3 0.6 0.6 1.3 0.9 1.9-0.3-0.7-0.6-1.3-0.9-1.9z m1.3 2.9c0.2 0.6 0.5 1.2 0.7 1.8-0.2-0.6-0.4-1.2-0.7-1.8z m1.1 2.8c0.3 0.8 0.5 1.6 0.8 2.4-0.3-0.9-0.5-1.7-0.8-2.4z m1 2.9c0.2 0.7 0.4 1.5 0.6 2.2-0.2-0.8-0.4-1.5-0.6-2.2z m0.8 3c0.2 0.9 0.4 1.8 0.6 2.6-0.2-0.8-0.4-1.7-0.6-2.6z m0.7 2.9c0.2 0.8 0.3 1.7 0.5 2.5-0.2-0.8-0.4-1.6-0.5-2.5z m0.5 3.3c0.1 0.9 0.3 1.9 0.4 2.8-0.1-0.9-0.2-1.8-0.4-2.8z m0.4 3c0.1 0.9 0.2 1.9 0.2 2.8 0-1-0.1-1.9-0.2-2.8z" fill="#47444F" p-id="9409"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
1
src/icons/svg/admin/blogVisit.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728286946997" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12215" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M801 516c46.4 0 90.1 11.9 128.2 32.7V163.1c0-35.3-28.7-64-64-64H164.9c-35.3 0-64 28.7-64 64v700.2c0 35.3 28.7 64 64 64h410.9c-26.7-41.6-42.1-91-42.1-144.1C533.7 635.6 653.4 516 801 516zM218.9 271.2c0-22.1 17.9-40 40-40h504.8c22.1 0 40 17.9 40 40s-17.9 40-40 40H258.9c-22.1 0-40-17.9-40-40z m0 216.6c0-22.1 14.2-40 31.8-40h293.6c17.6 0 31.8 17.9 31.8 40s-14.2 40-31.8 40H250.7c-17.5 0-31.8-17.9-31.8-40zM453 704.4c0 22.1-13.5 40-30.2 40H249.1c-16.7 0-30.2-17.9-30.2-40s13.5-40 30.2-40h173.7c16.7 0 30.2 17.9 30.2 40z" p-id="12216"></path><path d="M1001.7 747.5l2.3 1.2s0-5.3-49.7-50.9c-47.8-46.3-114.3-67.9-180.2-58.5-30.4 4.1-59.4 15.1-84.8 32.2-24.5 16.7-46.9 36.4-66.7 58.5-8.4 7-15.7 15.3-21.6 24.6-5.6 11.7-5.6 25.2 0 36.9l31.6 31c43.4 45.3 102.4 72.5 165 76.1 56-0.2 110-21 151.6-58.5 19.7-17.4 37.4-37.1 52.7-58.5 4.5-11 4.5-23.3-0.2-34.1zM802.8 859.3c-36.9 0-70.2-22.2-84.3-56.4-14.1-34.1-6.3-73.4 19.8-99.5 26.1-26.1 65.4-33.9 99.5-19.8 34.1 14.1 56.4 47.4 56.4 84.3-0.1 50.5-41 91.4-91.4 91.4z" p-id="12217"></path><path d="M784 725.8c-10.9 4.7-19.6 13.5-24 24.6-2.4 5.4-4 11.1-4.7 17 0.5 6 1.9 11.9 4.1 17.6 2.2 5.4 5.4 10.4 9.4 14.6 4.1 4.3 9.1 7.7 14.6 9.9 11 4.6 23.5 4.6 34.5 0 5.6-2.1 10.6-5.5 14.6-9.9 8.8-8.2 13.9-19.6 14-31.6-0.1-6.1-1.5-12.1-4.1-17.6-9.6-22.7-35.4-33.6-58.4-24.6z" p-id="12218"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
1
src/icons/svg/admin/dashboard.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728286413135" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4365" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512.546 86.050c0 0-12.561-0.546-24.030 7.1-12.015 8.192-462.029 380.109-462.029 380.109s-32.768 25.668 2.731 70.997 74.82 3.823 74.82 3.823l407.962-359.356 414.515 364.817c0 0 36.591 30.583 70.451-11.469 33.86-42.598-3.277-72.090-3.277-72.090l-121.242-99.942v-175.309h-164.932v39.868l-168.209-139.81c0 0-10.923-9.83-26.761-8.738z" p-id="4366"></path><path d="M512.546 241.152l-410.146 357.171v300.919l333.141 0.546v-246.306l152.917 1.638v244.122l333.141 0.546v-300.919z" p-id="4367"></path></svg>
|
||||||
|
After Width: | Height: | Size: 830 B |
1
src/icons/svg/admin/quartz.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1738923698040" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5255" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M738.6 955.6c-111.3-0.9-200.9-91.7-200.3-203 0.6-111.3 91.2-201.1 202.4-200.8 111.3 0.3 201.4 90.6 201.4 201.9-1.2 111.6-91.9 201.6-203.5 201.9z m94.9-215.2h-81.3v-80.9c0-15-12.1-27.1-27.1-27.1-15 0-27.1 12.1-27.1 27.1v107.7c-0.4 7.3 2.3 14.4 7.5 19.5s12.3 7.8 19.6 7.3h108.4c14.8 0 26.9-12 26.9-26.9-0.1-14.7-12.1-26.7-26.9-26.7z m-352.7 26.9c0.6 58.2 19.6 114.7 54.2 161.5H155c-29.8 0-54-24-54.2-53.7V121.4c0.3-29.8 24.5-53.7 54.2-53.7h651.3c29.8 0 54.1 24 54.4 53.7v398.4c-34.5-14.2-71.4-21.6-108.7-21.7-148.9-0.2-270.1 120.1-271.2 269.2z m-244.4-26.9h163.4c14.8 0 26.9-12 26.9-26.9v-0.2c0-14.8-12-26.9-26.9-26.9H236.4c-14.8 0-26.9 12-26.9 26.9v0.2c0 14.9 12.1 26.9 26.9 26.9z m0-161.5h244.7c14.8 0 26.9-12 26.9-26.9 0-14.8-12-26.9-26.9-26.9H236.4c-14.8 0-26.9 12-26.9 26.9 0 14.9 12.1 26.9 26.9 26.9z m486-376.7h-483c-16.5 0-29.8 13.3-29.8 29.8v47.9c0 16.5 13.3 29.8 29.8 29.8h483c16.5 0 29.8-13.3 29.8-29.8V232c-0.1-16.4-13.4-29.8-29.8-29.8z m2.9 188.4H236.4c-14.8 0-26.9 12-26.9 26.9 0 14.8 12 26.9 26.9 26.9h488.9c14.8 0 26.9-12 26.9-26.9-0.1-14.9-12.1-26.9-26.9-26.9z" p-id="5256"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
1
src/icons/svg/admin/user.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1713405591273" class="icon" viewBox="0 0 1028 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9454" width="128.5" height="128" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M815.814506 299.350645c0 165.306834-134.011812 299.350645-299.350645 299.350645s-299.350645-134.011812-299.350645-299.350645c0-165.306834 134.011812-299.350645 299.350645-299.350645s299.350645 134.011812 299.350645 299.350645z" p-id="9455"></path><path d="M763.52814 612.780851c-69.75782 55.070279-156.219118 85.661323-247.064279 85.661323-91.901128 0-179.1944-31.295022-249.27221-87.421268-184.698228 67.805881-267.19165 304.758476-267.19165 412.979094l1027.711884 0c0-107.260648-83.133402-342.549295-264.183744-411.18715z" p-id="9456"></path></svg>
|
||||||
|
After Width: | Height: | Size: 885 B |
@@ -9,7 +9,7 @@
|
|||||||
@toggleClick="toggleSideBar" />
|
@toggleClick="toggleSideBar" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="title">Sweet Hut</h3>
|
<h3 class="title">{{ appStore.appName }}</h3>
|
||||||
|
|
||||||
<!-- 右上角菜单栏 -->
|
<!-- 右上角菜单栏 -->
|
||||||
<div class="right-container">
|
<div class="right-container">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<!-- <img :src="logoInfo.logo" alt="logo">-->
|
<!-- <img :src="logoInfo.logo" alt="logo">-->
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link v-else key="expand" class="logo" to="/dashboard">
|
<router-link v-else key="expand" class="logo" to="/dashboard">
|
||||||
<img :src="getAssetsImageFile('logo/logo.png')"
|
<img :src="getAssetsImageFile('vue.svg')"
|
||||||
alt="logo">
|
alt="logo">
|
||||||
</router-link>
|
</router-link>
|
||||||
</transition>
|
</transition>
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ import '@fortawesome/fontawesome-free/css/all.css'
|
|||||||
|
|
||||||
import 'animate.css'
|
import 'animate.css'
|
||||||
|
|
||||||
|
// 注册svg-icon
|
||||||
|
import 'virtual:svg-icons-register'
|
||||||
|
|
||||||
// 创建Vue3实例
|
// 创建Vue3实例
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
// 使用路由
|
// 使用路由
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import AdminLayout from '@/layout/index.vue'
|
import Layout from '@/layout/index.vue'
|
||||||
import { adminMeta } from '@/views/meta'
|
import { metaList } from '@/views/meta'
|
||||||
import { getRoutersByModules, sortRoutesByOrder } from 'vue3-common/utils/routerUtil'
|
import { getRoutersByModules, sortRoutesByOrder } from 'vue3-common/utils/routerUtil'
|
||||||
|
|
||||||
const adminRoutes = getRoutersByModules(import.meta.glob('@/views/**/*.vue'), AdminLayout, adminMeta)
|
const modules = {
|
||||||
|
...import.meta.glob('@/views/blog/**/*.vue'),
|
||||||
|
...import.meta.glob('@/views/dashboard/**/*.vue'),
|
||||||
|
...import.meta.glob('@/views/monitor/**/*.vue')
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminRoutes = getRoutersByModules(modules, Layout, metaList)
|
||||||
|
|
||||||
export default sortRoutesByOrder(adminRoutes)
|
export default sortRoutesByOrder(adminRoutes)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const constantRoutes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
component: () => import('@/pages/login/index.vue'),
|
component: () => import('@/views/login/index.vue'),
|
||||||
meta: { hidden: true }
|
meta: { hidden: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ const router = createRouter({
|
|||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(routes)
|
// setupRouteGuard(router)
|
||||||
|
|
||||||
setupRouteGuard(router)
|
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useDark, useToggle } from '@vueuse/core'
|
|||||||
|
|
||||||
export const useAppStore = defineStore('ipp', {
|
export const useAppStore = defineStore('ipp', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
appName: 'Sweet Hut',
|
appName: '博客管理系统',
|
||||||
sidebar: {
|
sidebar: {
|
||||||
// !!:转为布尔值
|
// !!:转为布尔值
|
||||||
// 保存当前菜单栏显示和隐藏的状态
|
// 保存当前菜单栏显示和隐藏的状态
|
||||||
@@ -15,12 +15,9 @@ export const useAppStore = defineStore('ipp', {
|
|||||||
homeTitle: '',
|
homeTitle: '',
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
isLogin: false,
|
isLogin: false,
|
||||||
isShowMobileBack: false,
|
|
||||||
isShowSetting: false,
|
isShowSetting: false,
|
||||||
themeColor: '',
|
themeColor: '',
|
||||||
isDark: false,
|
isDark: false,
|
||||||
isWebSocket: false,
|
|
||||||
serverIp: '14.103.235.151',
|
|
||||||
version: 'v1.0.0.2025042901'
|
version: 'v1.0.0.2025042901'
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ILoginType, ISession } from '@/types/auth'
|
import { ISession } from '@/types/auth'
|
||||||
import { loginAdminApi, loginHomeApi } from '@/apis/session'
|
import { loginAdminApi } from '@/apis/session'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { emailPattern, phonePattern } from '@/utils/element/elRules'
|
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', {
|
export const useAuthStore = defineStore('auth', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -11,117 +10,21 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
password: '',
|
password: '',
|
||||||
isRemember: false
|
isRemember: false
|
||||||
},
|
},
|
||||||
phoneLoginForm: {
|
|
||||||
phoneNumber: '',
|
|
||||||
code: ''
|
|
||||||
},
|
|
||||||
emailLoginForm: {
|
|
||||||
email: '',
|
|
||||||
code: ''
|
|
||||||
},
|
|
||||||
loginType: 'common' as ILoginType,
|
|
||||||
loginLoading: false,
|
loginLoading: false,
|
||||||
loginAdminLoading: false,
|
|
||||||
isVerified: false,
|
isVerified: false,
|
||||||
isGettingCode: false,
|
|
||||||
getCodeCountdown: 60,
|
|
||||||
getCodeTimer: null as NodeJS.Timeout | null,
|
|
||||||
homeSession: {} as ISession
|
homeSession: {} as ISession
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
changeLoginType(type: ILoginType) {
|
async handleLogin() {
|
||||||
this.loginType = type
|
|
||||||
|
|
||||||
if (type === 'common') {
|
|
||||||
this.stopCountdown()
|
|
||||||
}
|
|
||||||
this.resetLoginForm()
|
|
||||||
},
|
|
||||||
getAuthCode(type: ILoginType) {
|
|
||||||
switch (type) {
|
|
||||||
case 'phone':
|
|
||||||
if (phonePattern.test(this.phoneLoginForm.phoneNumber)) {
|
|
||||||
this.isGettingCode = true
|
|
||||||
ElMessage.success('验证码已发送至手机')
|
|
||||||
this.startCountdown()
|
|
||||||
} else {
|
|
||||||
ElMessage.error('请先输入正确的手机号')
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'email':
|
|
||||||
if (emailPattern.test(this.emailLoginForm.email)) {
|
|
||||||
this.isGettingCode = true
|
|
||||||
ElMessage.success('验证码已发送至邮箱')
|
|
||||||
this.startCountdown()
|
|
||||||
} else {
|
|
||||||
ElMessage.error('请先输入正确的邮箱地址')
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
startCountdown() {
|
|
||||||
this.getCodeTimer = setInterval(() => {
|
|
||||||
if (this.getCodeCountdown > 0) {
|
|
||||||
this.getCodeCountdown--
|
|
||||||
} else {
|
|
||||||
clearInterval(this.getCodeTimer as NodeJS.Timeout)
|
|
||||||
this.isGettingCode = false
|
|
||||||
this.getCodeCountdown = 60
|
|
||||||
}
|
|
||||||
}, 1000)
|
|
||||||
},
|
|
||||||
stopCountdown() {
|
|
||||||
if (this.getCodeTimer) {
|
|
||||||
clearInterval(this.getCodeTimer)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async handleLogin(type: ILoginType) {
|
|
||||||
const { username, password } = this.loginForm
|
const { username, password } = this.loginForm
|
||||||
const { phoneNumber, code: phoneCode } = this.phoneLoginForm
|
this.homeSession = await loginAdminApi(username, password)
|
||||||
const { email, code: emailCode } = this.emailLoginForm
|
|
||||||
switch (type) {
|
|
||||||
case 'common':
|
|
||||||
this.homeSession = await loginHomeApi(username, password)
|
|
||||||
break
|
|
||||||
case 'phone':
|
|
||||||
this.homeSession = await loginHomeApi(phoneNumber, phoneCode)
|
|
||||||
break
|
|
||||||
case 'email':
|
|
||||||
this.homeSession = await loginHomeApi(email, emailCode)
|
|
||||||
break
|
|
||||||
case 'admin':
|
|
||||||
this.homeSession = await loginAdminApi(username, password)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ElMessage.success('登录成功')
|
ElMessage.success('登录成功')
|
||||||
},
|
},
|
||||||
resetLoginForm() {
|
resetLoginForm() {
|
||||||
switch (this.loginType) {
|
this.loginForm = {
|
||||||
case 'common':
|
username: '',
|
||||||
this.loginForm = {
|
password: '',
|
||||||
username: '',
|
isRemember: false
|
||||||
password: '',
|
|
||||||
isRemember: false
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'phone':
|
|
||||||
this.phoneLoginForm = {
|
|
||||||
phoneNumber: '',
|
|
||||||
code: ''
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'email':
|
|
||||||
this.emailLoginForm = {
|
|
||||||
email: '',
|
|
||||||
code: ''
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
IBlogLatest, IBlogNestedComment, IBlogStats, INewBlog, IQueryBlog
|
IBlogLatest, IBlogNestedComment, IBlogStats, INewBlog, IQueryBlog
|
||||||
} from '@/types/blog'
|
} from '@/types/blog'
|
||||||
import {
|
import {
|
||||||
addBlogApi, addBlogCommentApi, deleteBlogApi, queryAdminBlogApi, queryAdminBlogByIdApi, queryAdminBlogCategoryApi,
|
addBlogApi, addBlogCommentApi, deleteBlogApi,
|
||||||
queryBlogApi, queryBlogByConditionApi, queryBlogByIdApi,
|
queryBlogApi, queryBlogByConditionApi, queryBlogByIdApi,
|
||||||
queryBlogCategoryApi, queryBlogCommentApi, queryBlogStatsApi, queryLatestBlogApi, updateBlogApi
|
queryBlogCategoryApi, queryBlogCommentApi, queryBlogStatsApi, queryLatestBlogApi, updateBlogApi
|
||||||
} from '@/apis/blog.ts'
|
} from '@/apis/blog.ts'
|
||||||
@@ -59,32 +59,15 @@ export const useBlogStore = defineStore('blog', {
|
|||||||
totalSize: 1
|
totalSize: 1
|
||||||
},
|
},
|
||||||
isScrollEnd: false,
|
isScrollEnd: false,
|
||||||
adminPageInfo: {
|
|
||||||
currentPage: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
totalSize: 1
|
|
||||||
},
|
|
||||||
progressValue: '0%'
|
progressValue: '0%'
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async queryBlog() {
|
async queryBlogList() {
|
||||||
const { currentPage, pageSize } = this.pageInfo
|
const { currentPage, pageSize } = this.pageInfo
|
||||||
const result = await queryBlogApi(currentPage, pageSize)
|
const result = await queryBlogApi(currentPage, pageSize)
|
||||||
this.blogList = result.records
|
this.blogList = result.records
|
||||||
this.pageInfo.totalSize = result.total
|
this.pageInfo.totalSize = result.total
|
||||||
},
|
},
|
||||||
async queryMobileBlog() {
|
|
||||||
const { currentPage, pageSize } = this.pageInfo
|
|
||||||
const result = await queryBlogApi(currentPage, pageSize)
|
|
||||||
this.blogList.push(...result.records)
|
|
||||||
this.pageInfo.totalSize = result.total
|
|
||||||
},
|
|
||||||
async queryAdminBlog() {
|
|
||||||
const { currentPage, pageSize } = this.adminPageInfo
|
|
||||||
const result = await queryAdminBlogApi(currentPage, pageSize)
|
|
||||||
this.blogList = result.records
|
|
||||||
this.pageInfo.totalSize = result.total
|
|
||||||
},
|
|
||||||
async queryBlogByCondition(query: IQueryBlog) {
|
async queryBlogByCondition(query: IQueryBlog) {
|
||||||
this.blogList = await queryBlogByConditionApi(query)
|
this.blogList = await queryBlogByConditionApi(query)
|
||||||
},
|
},
|
||||||
@@ -93,8 +76,8 @@ export const useBlogStore = defineStore('blog', {
|
|||||||
await this.queryBlogComment(this.currentBlogId)
|
await this.queryBlogComment(this.currentBlogId)
|
||||||
this.blogNestedCommentList = flattenToTwoLevel(this.blogCommentList)
|
this.blogNestedCommentList = flattenToTwoLevel(this.blogCommentList)
|
||||||
},
|
},
|
||||||
async queryAdminBlogById(id: number) {
|
async queryBlogByIdApi(id: number) {
|
||||||
this.currentBlog = await queryAdminBlogByIdApi(id)
|
this.currentBlog = await queryBlogByIdApi(id)
|
||||||
},
|
},
|
||||||
async queryBlogComment(blogId: number) {
|
async queryBlogComment(blogId: number) {
|
||||||
this.blogCommentList = await queryBlogCommentApi(blogId)
|
this.blogCommentList = await queryBlogCommentApi(blogId)
|
||||||
@@ -106,9 +89,6 @@ export const useBlogStore = defineStore('blog', {
|
|||||||
async queryBlogCategory() {
|
async queryBlogCategory() {
|
||||||
this.blogCategoryList = await queryBlogCategoryApi()
|
this.blogCategoryList = await queryBlogCategoryApi()
|
||||||
},
|
},
|
||||||
async queryAdminBlogCategory() {
|
|
||||||
this.blogCategoryList = await queryAdminBlogCategoryApi()
|
|
||||||
},
|
|
||||||
async queryBlogStats() {
|
async queryBlogStats() {
|
||||||
this.blogStats = await queryBlogStatsApi()
|
this.blogStats = await queryBlogStatsApi()
|
||||||
},
|
},
|
||||||
@@ -136,7 +116,7 @@ export const useBlogStore = defineStore('blog', {
|
|||||||
},
|
},
|
||||||
async refreshInfo() {
|
async refreshInfo() {
|
||||||
this.pageInfo.currentPage = 1
|
this.pageInfo.currentPage = 1
|
||||||
await this.queryBlog()
|
await this.queryBlogList()
|
||||||
await this.queryBlogStats()
|
await this.queryBlogStats()
|
||||||
await this.queryLatestBlog()
|
await this.queryLatestBlog()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,9 +38,9 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-model:current-page="blogStore.adminPageInfo.currentPage"
|
v-model:current-page="blogStore.pageInfo.currentPage"
|
||||||
:page-size="blogStore.adminPageInfo.pageSize"
|
:page-size="blogStore.pageInfo.pageSize"
|
||||||
:total="blogStore.adminPageInfo.totalSize"
|
:total="blogStore.pageInfo.totalSize"
|
||||||
layout="total, prev, pager, next"
|
layout="total, prev, pager, next"
|
||||||
@change="changePageClick"
|
@change="changePageClick"
|
||||||
/>
|
/>
|
||||||
@@ -58,7 +58,7 @@ const router = useRouter()
|
|||||||
const blogStore = useBlogStore()
|
const blogStore = useBlogStore()
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await blogStore.queryAdminBlog()
|
await blogStore.queryBlogList()
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,16 +67,16 @@ onMounted(async () => {
|
|||||||
* @param pageSize 每页大小
|
* @param pageSize 每页大小
|
||||||
*/
|
*/
|
||||||
const changePageClick = async (page: number, pageSize: number) => {
|
const changePageClick = async (page: number, pageSize: number) => {
|
||||||
blogStore.adminPageInfo.currentPage = page
|
blogStore.pageInfo.currentPage = page
|
||||||
blogStore.adminPageInfo.pageSize = pageSize
|
blogStore.pageInfo.pageSize = pageSize
|
||||||
await blogStore.queryAdminBlog()
|
await blogStore.queryBlogList()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 点击新增博客按钮
|
* 点击新增博客按钮
|
||||||
*/
|
*/
|
||||||
const addNewBlogClick = () => {
|
const addNewBlogClick = () => {
|
||||||
router.push({ name: 'AdminBlogDetailId', params: { id: 0 } })
|
router.push({ name: 'BlogDetailId', params: { id: 0 } })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +84,7 @@ const addNewBlogClick = () => {
|
|||||||
* @param blog 博客
|
* @param blog 博客
|
||||||
*/
|
*/
|
||||||
const previewBlogClick = async (blog: IBlog) => {
|
const previewBlogClick = async (blog: IBlog) => {
|
||||||
await router.push({ name: 'AdminBlogPreviewId', params: { id: blog.id } })
|
await router.push({ name: 'BlogPreviewId', params: { id: blog.id } })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +92,7 @@ const previewBlogClick = async (blog: IBlog) => {
|
|||||||
* @param blog 博客
|
* @param blog 博客
|
||||||
*/
|
*/
|
||||||
const editBlogClick = async (blog: IBlog) => {
|
const editBlogClick = async (blog: IBlog) => {
|
||||||
await router.push({ name: 'AdminBlogDetailId', params: { id: blog.id } })
|
await router.push({ name: 'BlogDetailId', params: { id: blog.id } })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,7 +59,7 @@ const router = useRouter()
|
|||||||
const blogStore = useBlogStore()
|
const blogStore = useBlogStore()
|
||||||
|
|
||||||
const focusCategoryEvent = async () => {
|
const focusCategoryEvent = async () => {
|
||||||
await blogStore.queryAdminBlogCategory()
|
await blogStore.queryBlogCategory()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
@@ -70,7 +70,7 @@ onMounted(async () => {
|
|||||||
const blogId = route.params.id as number
|
const blogId = route.params.id as number
|
||||||
if (blogId > 0) {
|
if (blogId > 0) {
|
||||||
blogStore.blogApiType = 'UPDATE'
|
blogStore.blogApiType = 'UPDATE'
|
||||||
await blogStore.queryAdminBlogById(route.params.id as number)
|
await blogStore.queryBlogById(route.params.id as number)
|
||||||
blogStore.newBlog = blogStore.currentBlog
|
blogStore.newBlog = blogStore.currentBlog
|
||||||
} else {
|
} else {
|
||||||
blogStore.blogApiType = 'ADD'
|
blogStore.blogApiType = 'ADD'
|
||||||
@@ -98,7 +98,7 @@ const submitFormEvent = () => {
|
|||||||
formRef.value?.validate().then(async () => {
|
formRef.value?.validate().then(async () => {
|
||||||
if (validateBlog()) {
|
if (validateBlog()) {
|
||||||
await blogStore.handleBlogApi()
|
await blogStore.handleBlogApi()
|
||||||
await router.push('/admin/blog/article')
|
await router.push('/blog')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ const onUploadImg = async (files: File[], callback) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const backClick = () => {
|
const backClick = () => {
|
||||||
router.push('/admin/blog/article')
|
router.push('/blog')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -24,11 +24,11 @@ const blogStore = useBlogStore()
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const blogId = route.params.id as number
|
const blogId = route.params.id as number
|
||||||
await blogStore.queryAdminBlogById(blogId)
|
await blogStore.queryBlogById(blogId)
|
||||||
blogStore.newBlog = blogStore.currentBlog
|
blogStore.newBlog = blogStore.currentBlog
|
||||||
})
|
})
|
||||||
|
|
||||||
const backClick = () => {
|
const backClick = () => {
|
||||||
router.push('/admin/blog/article')
|
router.push('/blog')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="admin-module">
|
||||||
Dashboard
|
Dashboard
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,36 +7,24 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<common-login v-if="authStore.loginType === 'common'"
|
<common-login class="animate__animated animate__bounceIn"/>
|
||||||
class="animate__animated animate__bounceIn"/>
|
|
||||||
<phone-login v-if="authStore.loginType === 'phone'"
|
|
||||||
class="animate__animated animate__bounceIn"/>
|
|
||||||
<email-login v-if="authStore.loginType === 'email'"
|
|
||||||
class="animate__animated animate__bounceIn"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CommonLogin from '@/components/Login/CommonLogin.vue'
|
import CommonLogin from '@/components/Login/CommonLogin.vue'
|
||||||
import PhoneLogin from '@/components/Login/PhoneLogin.vue'
|
|
||||||
import EmailLogin from '@/components/Login/EmailLogin.vue'
|
|
||||||
import { useAuthStore } from '@/store/auth'
|
import { useAuthStore } from '@/store/auth'
|
||||||
import { onMounted, onUnmounted, reactive } from 'vue'
|
import { onMounted, reactive } from 'vue'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
const loginInfo = reactive({
|
const loginInfo = reactive({
|
||||||
title: 'Sweet Hut'
|
title: '博客管理系统'
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
authStore.isVerified = false
|
authStore.isVerified = false
|
||||||
// authStore.resetLoginForm()
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
authStore.stopCountdown()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -1,44 +1,48 @@
|
|||||||
import { IRouteMetaConfig } from 'vue3-common/types'
|
import { IRouteMetaConfig } from 'vue3-common/types'
|
||||||
|
|
||||||
export const adminMeta: IRouteMetaConfig = {
|
export const metaList: IRouteMetaConfig = {
|
||||||
'/dashboard': {
|
'/dashboard': {
|
||||||
title: '总览',
|
title: '总览',
|
||||||
icon: '',
|
icon: 'admin-dashboard',
|
||||||
order: 1,
|
order: 1,
|
||||||
redirect: '/dashboard/index'
|
redirect: '/dashboard/index'
|
||||||
},
|
},
|
||||||
'/dashboard/index': {
|
'/dashboard/index': {
|
||||||
title: '',
|
title: '首页',
|
||||||
icon: ''
|
icon: 'admin-dashboard'
|
||||||
},
|
},
|
||||||
'/article': {
|
'/blog': {
|
||||||
|
title: '博客管理',
|
||||||
|
icon: 'admin-blog',
|
||||||
|
order: 2,
|
||||||
|
redirect: '/blog/article'
|
||||||
|
},
|
||||||
|
'/blog/article': {
|
||||||
title: '文章管理',
|
title: '文章管理',
|
||||||
|
icon: 'admin-blogArticle'
|
||||||
|
},
|
||||||
|
'/blog/category': {
|
||||||
|
title: '类别管理',
|
||||||
|
icon: 'admin-blogCategory'
|
||||||
|
},
|
||||||
|
'/blog/detail/:id': {
|
||||||
|
title: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
redirect: '/article/article'
|
hidden: true
|
||||||
},
|
},
|
||||||
'/article/article': {
|
'/blog/preview/:id': {
|
||||||
title: '',
|
title: '',
|
||||||
icon: ''
|
icon: '',
|
||||||
},
|
hidden: true
|
||||||
'/article/category': {
|
|
||||||
title: '',
|
|
||||||
icon: ''
|
|
||||||
},
|
|
||||||
'/article/detail/:id': {
|
|
||||||
title: '',
|
|
||||||
icon: ''
|
|
||||||
},
|
|
||||||
'/article/preview/:id': {
|
|
||||||
title: '',
|
|
||||||
icon: ''
|
|
||||||
},
|
},
|
||||||
'/monitor': {
|
'/monitor': {
|
||||||
title: '监控管理',
|
title: '监控管理',
|
||||||
icon: '',
|
icon: 'admin-blogVisit',
|
||||||
|
order: 3,
|
||||||
redirect: '/monitor/visit'
|
redirect: '/monitor/visit'
|
||||||
},
|
},
|
||||||
'/monitor/visit': {
|
'/monitor/visit': {
|
||||||
title: '',
|
title: '监控管理',
|
||||||
icon: ''
|
icon: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||