补充前台页面
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":"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":"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":"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) => {
|
router.beforeEach((to, from) => {
|
||||||
const whiteList = ['login']
|
const whiteList = ['login', 'frontend']
|
||||||
if (!whiteList.includes(to.name)) {
|
if (!whiteList.includes(to.name)) {
|
||||||
// 需要做权限判断
|
// 需要做权限判断
|
||||||
if (isLogin()) {
|
if (isLogin()) {
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
<div style="font-size: 16px;font-weight: 500;">
|
<div style="font-size: 16px;font-weight: 500;">
|
||||||
博客管理系统
|
博客管理系统
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<a-space>
|
||||||
<a-button @click="logout">
|
<a-button @click="$router.push({ name: 'frontend' })">
|
||||||
<span style="margin-right: 12px;">
|
<span>
|
||||||
退出登录
|
前台
|
||||||
</span>
|
</span>
|
||||||
<icon-export />
|
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
<LogoutButton></LogoutButton>
|
||||||
|
</a-space>
|
||||||
</a-layout-header>
|
</a-layout-header>
|
||||||
<a-layout class="body">
|
<a-layout class="body">
|
||||||
<!-- 侧边栏 -->
|
<!-- 侧边栏 -->
|
||||||
@ -51,7 +51,7 @@
|
|||||||
import { token } from '@/stores/token';
|
import { token } from '@/stores/token';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { systemConfig } from '@/stores/system';
|
import { systemConfig } from '@/stores/system';
|
||||||
|
import LogoutButton from '@/components/LogoutButton.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
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