补充前台页面
This commit is contained in:
parent
0952098885
commit
c319804716
@ -489,3 +489,13 @@
|
||||
{"level":"info","component":"http","time":"2025-01-19T14:50:39+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
|
||||
{"level":"error","component":"http","time":"2025-01-19T14:50:39+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
|
||||
{"level":"info","component":"server","time":"2025-01-19T14:50:39+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
|
||||
{"level":"info","component":"gin_webframework","time":"2025-01-19T14:52:20+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
|
||||
{"level":"debug","time":"2025-01-19T14:52:20+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
|
||||
{"level":"info","component":"server","time":"2025-01-19T14:52:20+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
|
||||
{"level":"info","component":"server","time":"2025-01-19T14:52:20+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
|
||||
{"level":"info","component":"server","time":"2025-01-19T14:52:20+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
|
||||
{"level":"info","component":"server","time":"2025-01-19T14:52:20+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
|
||||
{"level":"info","component":"http","time":"2025-01-19T14:52:20+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
|
||||
{"level":"debug","time":"2025-01-19T15:29:38+08:00","caller":"token/api/api.go:57","message":"cookie domain: localhost"}
|
||||
{"level":"debug","time":"2025-01-19T15:32:21+08:00","caller":"token/api/api.go:57","message":"cookie domain: localhost"}
|
||||
{"level":"debug","time":"2025-01-19T15:57:25+08:00","caller":"token/api/api.go:57","message":"cookie domain: localhost"}
|
||||
|
39
vblog/web/src/components/LogoutButton.vue
Normal file
39
vblog/web/src/components/LogoutButton.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button v-if="isLogin()" @click="logout">
|
||||
<span style="margin-right: 12px;">
|
||||
退出
|
||||
</span>
|
||||
<icon-export />
|
||||
</a-button>
|
||||
<a-button v-else @click="$router.push({ name: 'login' })">
|
||||
<span>
|
||||
登录
|
||||
</span>
|
||||
</a-button>
|
||||
</a-space>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { isLogin, token } from '@/stores/token'
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const props = defineProps({
|
||||
redirectToLogin: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
}
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const logout = () => {
|
||||
token.value = undefined
|
||||
if (props.redirectToLogin) {
|
||||
router.push({ name: 'login' })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped></style>
|
@ -73,11 +73,29 @@ const router = createRouter({
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/frontend',
|
||||
name: 'frontend',
|
||||
redirect: '/frontend/blog_list',
|
||||
component: () => import('../views/frontend/FrontendLayout.vue'),
|
||||
children: [
|
||||
{
|
||||
path: 'blog_list',
|
||||
name: 'frontend_blog_list',
|
||||
component: () => import('../views/frontend/blog/ListPage.vue'),
|
||||
},
|
||||
{
|
||||
path: 'blog_detail',
|
||||
name: 'frontend_blog_detail',
|
||||
component: () => import('../views/frontend/blog/DetailPage.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
router.beforeEach((to, from) => {
|
||||
const whiteList = ['login']
|
||||
const whiteList = ['login', 'frontend']
|
||||
if (!whiteList.includes(to.name)) {
|
||||
// 需要做权限判断
|
||||
if (isLogin()) {
|
||||
|
@ -5,14 +5,14 @@
|
||||
<div style="font-size: 16px;font-weight: 500;">
|
||||
博客管理系统
|
||||
</div>
|
||||
<div>
|
||||
<a-button @click="logout">
|
||||
<span style="margin-right: 12px;">
|
||||
退出登录
|
||||
<a-space>
|
||||
<a-button @click="$router.push({ name: 'frontend' })">
|
||||
<span>
|
||||
前台
|
||||
</span>
|
||||
<icon-export />
|
||||
</a-button>
|
||||
</div>
|
||||
<LogoutButton></LogoutButton>
|
||||
</a-space>
|
||||
</a-layout-header>
|
||||
<a-layout class="body">
|
||||
<!-- 侧边栏 -->
|
||||
@ -51,7 +51,7 @@
|
||||
import { token } from '@/stores/token';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { systemConfig } from '@/stores/system';
|
||||
|
||||
import LogoutButton from '@/components/LogoutButton.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
|
85
vblog/web/src/views/frontend/FrontendLayout.vue
Normal file
85
vblog/web/src/views/frontend/FrontendLayout.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<a-layout class="layout">
|
||||
<!-- 顶部导航 -->
|
||||
<a-layout-header class="header">
|
||||
<div style="font-size: 16px;font-weight: 500;">
|
||||
博客管理系统
|
||||
</div>
|
||||
<div>
|
||||
<LogoutButton :redirectToLogin="false"></LogoutButton>
|
||||
</div>
|
||||
</a-layout-header>
|
||||
<a-layout-content class="content">
|
||||
<div class="left">
|
||||
|
||||
</div>
|
||||
<div class="center">
|
||||
<RouterView></RouterView>
|
||||
</div>
|
||||
<div class="right">
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import LogoutButton from '@/components/LogoutButton.vue'
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.layout {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 60px;
|
||||
box-sizing: border-box;
|
||||
min-height: 60px;
|
||||
max-height: 60px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background-color: var(--color-bg-2);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 300px;
|
||||
border-right: 1px solid var(--color-border);
|
||||
height: calc(100vh - 60xp);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 300px;
|
||||
border-left: 1px solid var(--color-border);
|
||||
height: calc(100vh - 60xp);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 60px;
|
||||
height: calc(100vh - 60xp);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 100%;
|
||||
height: calc(100vh - 60xp);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.center::-webkit-scrollbar {
|
||||
display: none;
|
||||
/* Chrome, Safari 和 Opera */
|
||||
}
|
||||
</style>
|
11
vblog/web/src/views/frontend/blog/DetailPage.vue
Normal file
11
vblog/web/src/views/frontend/blog/DetailPage.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
文章详情
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped></style>
|
59
vblog/web/src/views/frontend/blog/ListPage.vue
Normal file
59
vblog/web/src/views/frontend/blog/ListPage.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<a-list :loading="queryBlogLoadding" class="list-demo-action-layout" :bordered="false" :data="data.items"
|
||||
:pagination-props="{ pageSize: blogQueryRequest.page_size, total: data.total }">
|
||||
<template #item="{ item }">
|
||||
<a-list-item class="list-demo-item" action-layout="vertical">
|
||||
<template #actions>
|
||||
<span><icon-heart />83</span>
|
||||
<span><icon-star />{{ item.id }}</span>
|
||||
<span><icon-message />Reply</span>
|
||||
</template>
|
||||
<template #extra>
|
||||
<div className="image-area">
|
||||
<img @click="$router.push({ name: 'frontend_blog_detail', query: { id: item.id } })" alt="arco-design"
|
||||
width="200" height="120"
|
||||
src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/1f61854a849a076318ed527c8fca1bbf.png~tplv-uwbnlip3yd-webp.webp" />
|
||||
</div>
|
||||
</template>
|
||||
<a-list-item-meta :title="item.title" :description="item.summary">
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { QUERY_BLOG } from '@/api/blog'
|
||||
|
||||
onMounted(() => {
|
||||
queryData()
|
||||
})
|
||||
|
||||
// API 请求数据
|
||||
const blogQueryRequest = reactive({
|
||||
keywords: '',
|
||||
category: '',
|
||||
page_size: 10,
|
||||
page_number: 1,
|
||||
})
|
||||
// 数据, reactive, 一个一个修改每个属性的值 ({data...})
|
||||
// ref data.value = {}
|
||||
const data = ref({
|
||||
items: [],
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 查询函数
|
||||
const queryBlogLoadding = ref(false)
|
||||
const queryData = async () => {
|
||||
try {
|
||||
queryBlogLoadding.value = true
|
||||
data.value = await QUERY_BLOG(blogQueryRequest)
|
||||
} finally {
|
||||
queryBlogLoadding.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped></style>
|
Loading…
x
Reference in New Issue
Block a user