feat: 继续完成后台前端实现
This commit is contained in:
1 parent
83f5788dee
commit
caadd5a484
15 files changed
+781
-17
No files matched your search
@@ -26,8 +26,9 @@ const title = ref('')
|
||||
|
||||
const renderedData = ref('')
|
||||
|
||||
const id = route.params.id as string
|
||||
|
||||
onMounted(async () => {
|
||||
const id = route.params.id as string
|
||||
|
||||
const _p = new Promise<postContent>(async (resolve, reject) => {
|
||||
try {
|
||||
|
||||
+171
-11
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button @click="handleLogout">
|
||||
logout
|
||||
</el-button>
|
||||
<nuxt-link to="user/test"> test</nuxt-link>
|
||||
<div class="loading-wrapper">
|
||||
<div class="loading">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -13,16 +15,174 @@ import useUserStore from '~/hooks/pinia/useUserStore';
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const handleLogout = () => {
|
||||
userStore.logout()
|
||||
router.push('user/login')
|
||||
}
|
||||
// definePageMeta({
|
||||
// middleware: [
|
||||
// function (to, from) {
|
||||
// // if (userStore.isLogin === false) {
|
||||
// // return navigateTo('user/login')
|
||||
// // }
|
||||
// console.log(to, from)
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (userStore.isLogin === false) {
|
||||
return router.push('user/login')
|
||||
return router.replace('/user/login')
|
||||
} else {
|
||||
return router.replace('/user/main')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.loading-wrapper {
|
||||
height: calc(100vh - 60px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.loading>div {
|
||||
/* scale: 1.5; */
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: block;
|
||||
font-size: 0;
|
||||
color: #15aa87;
|
||||
}
|
||||
|
||||
.loading>div {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
background-color: currentColor;
|
||||
border: 0 solid currentColor;
|
||||
}
|
||||
|
||||
.loading {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.loading>div {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: ball-fussion-ball1 1s 0s ease infinite;
|
||||
}
|
||||
|
||||
.loading>div:nth-child(1) {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.loading>div:nth-child(2) {
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
z-index: 2;
|
||||
animation-name: ball-fussion-ball2;
|
||||
}
|
||||
|
||||
.loading>div:nth-child(3) {
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
animation-name: ball-fussion-ball3;
|
||||
}
|
||||
|
||||
.loading>div:nth-child(4) {
|
||||
top: 50%;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
animation-name: ball-fussion-ball4;
|
||||
}
|
||||
|
||||
@keyframes ball-fussion-ball2 {
|
||||
0% {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
50% {
|
||||
top: 200%;
|
||||
left: 200%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
opacity: 0.35;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ball-fussion-ball1 {
|
||||
0% {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
50% {
|
||||
top: -100%;
|
||||
left: 200%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
z-index: 2;
|
||||
opacity: 0.35;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ball-fussion-ball3 {
|
||||
0% {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
50% {
|
||||
top: 200%;
|
||||
left: -100%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 50%;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
opacity: 0.35;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ball-fussion-ball4 {
|
||||
0% {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
50% {
|
||||
top: -100%;
|
||||
left: -100%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
opacity: 0.35;
|
||||
}
|
||||
}
|
||||
|
||||
/* 作者:德育处主任
|
||||
链接:https://juejin.cn/post/7037036742985121800
|
||||
来源:稀土掘金
|
||||
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 */
|
||||
</style>
|
||||
@@ -33,6 +33,9 @@ const userStore = useUserStore()
|
||||
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
username.value = '539943419'
|
||||
password.value = 'zjh030628'
|
||||
onMounted(() => handleLogin())
|
||||
|
||||
let isLogining = false
|
||||
|
||||
|
||||
+321
-2
@@ -1,13 +1,332 @@
|
||||
<template>
|
||||
<div>
|
||||
用户主界面
|
||||
<div :class="['user-main', showSidebar ? '' : 'hide-sidebar']">
|
||||
<div class="user-sidebar">
|
||||
<!-- <el-button @click="handleHideSidebar">hide</el-button> -->
|
||||
<div class="sidebar-item" @click="handleHideSidebar">
|
||||
<div class="sidebar-item-icon">
|
||||
<component class="sidebar-item-icon-noFill" :is="chevronDown"
|
||||
:style="{ transform: showSidebar ? '' : 'rotate(-90deg)' }"></component>
|
||||
</div>
|
||||
<div class="sidebar-item-title">
|
||||
<!-- {{ '隐藏' }} -->
|
||||
</div>
|
||||
</div>
|
||||
<NuxtLink v-for="item in menuItem" class="sidebar-item" :to="item.to">
|
||||
<div class="sidebar-item-icon">
|
||||
<component :class="item.iconFill ? 'sidebar-item-icon-noFill' : ''" :is="item.icon"></component>
|
||||
</div>
|
||||
<div class="sidebar-item-title">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="user-content">
|
||||
<el-scrollbar>
|
||||
<router-view></router-view>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<div class="user-bottom-bar">
|
||||
<NuxtLink v-for="item in menuItem" class="bottom-item" :to="item.to">
|
||||
<div class="bottom-item-icon">
|
||||
<component :class="item.iconFill ? 'bottom-item-icon-noFill' : ''" :is="item.icon"></component>
|
||||
</div>
|
||||
<div class="bottom-item-title">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import useUserStore from '~/hooks/pinia/useUserStore';
|
||||
import Cat from '~/components/icons/cat.vue'
|
||||
import chevronDown from '~/components/icons/chevronDown.vue';
|
||||
import Documents from '~/components/icons/documents.vue';
|
||||
import Home from '~/components/icons/home.vue';
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const menuItem = shallowReactive([
|
||||
{
|
||||
title: '主页',
|
||||
icon: Home,
|
||||
iconFill: true,
|
||||
to: '/user/main'
|
||||
}, {
|
||||
title: '文章',
|
||||
icon: Documents,
|
||||
iconFill: true,
|
||||
to: '/user/main/post'
|
||||
}, {
|
||||
title: '账户',
|
||||
icon: Cat,
|
||||
to: '/user/main/account'
|
||||
}, {
|
||||
title: '测试',
|
||||
icon: Cat,
|
||||
to: '/user/main/test'
|
||||
}
|
||||
])
|
||||
|
||||
const showSidebar = ref(true)
|
||||
|
||||
const handleHideSidebar = () => {
|
||||
showSidebar.value = !showSidebar.value
|
||||
}
|
||||
|
||||
const handleLogout = () => {
|
||||
userStore.logout()
|
||||
router.push('user/login')
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (userStore.isLogin === false) {
|
||||
return router.replace('/user/login')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-main {
|
||||
width: 100%;
|
||||
height: calc(100vh - 60px);
|
||||
max-height: calc(100vh - 60px);
|
||||
display: grid;
|
||||
grid-template: 1fr 40px / 100px 1fr;
|
||||
transition: grid-template .2s ease;
|
||||
|
||||
.user-content {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 1 / -1;
|
||||
max-height: calc(100vh - 60px);
|
||||
}
|
||||
|
||||
.user-sidebar {
|
||||
grid-column: 1;
|
||||
grid-row: 1 / -1;
|
||||
border-right: 1px solid #ccc;
|
||||
padding: 10px 0px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// gap: 10px;
|
||||
// align-items: start;
|
||||
|
||||
.sidebar-item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
// justify-content: center;
|
||||
text-decoration: none;
|
||||
padding: 5px 0px;
|
||||
transition: all .2s ease;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
background-color: #e0e0e054;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
min-width: 40px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: black;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
aspect-ratio: 1;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
margin-left: 6px;
|
||||
text-wrap: nowrap;
|
||||
letter-spacing: 2px;
|
||||
color: black;
|
||||
font-family: PT Serif, Serif;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-bottom-bar {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 2;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
|
||||
.bottom-item {
|
||||
height: 30px;
|
||||
aspect-ratio: 1;
|
||||
color: #000;
|
||||
transition: all .2s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
|
||||
&-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #000;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
aspect-ratio: 1;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
text-wrap: nowrap;
|
||||
letter-spacing: 2px;
|
||||
color: #000;
|
||||
font-family: PT Serif, Serif;
|
||||
transition: all .2s ease;
|
||||
font-size: 7px;
|
||||
margin-top: 3px;
|
||||
transform: translateX(1px);
|
||||
}
|
||||
|
||||
// &:hover {
|
||||
// scale: 1.05;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.hide-sidebar {
|
||||
grid-template: 1fr 40px / 40px 1fr;
|
||||
|
||||
// .sidebar-item-title {
|
||||
// // display: none;
|
||||
// }
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.user-main {
|
||||
.user-sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user-content {
|
||||
grid-row: 1;
|
||||
max-height: calc(100vh - 100px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.user-main {
|
||||
.user-bottom-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.user-content {
|
||||
grid-column: 2;
|
||||
grid-row: 1 / -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.user-main {
|
||||
.user-sidebar {
|
||||
.sidebar-item {
|
||||
.sidebar-item-icon {
|
||||
svg {
|
||||
path {
|
||||
fill: black;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-item-icon-noFill {
|
||||
path {
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.router-link-exact-active {
|
||||
.sidebar-item-icon {
|
||||
svg {
|
||||
path {
|
||||
fill: #15aa87;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-item-icon-noFill {
|
||||
path {
|
||||
fill: none;
|
||||
stroke: #15aa87;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-item-title {
|
||||
color: #15aa87 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-bottom-bar {
|
||||
.bottom-item {
|
||||
.bottom-item-icon {
|
||||
svg {
|
||||
path {
|
||||
fill: black;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-item-icon-noFill {
|
||||
path {
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.router-link-exact-active {
|
||||
.bottom-item-icon {
|
||||
svg {
|
||||
path {
|
||||
fill: #15aa87;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-item-icon-noFill {
|
||||
path {
|
||||
fill: none;
|
||||
stroke: #15aa87;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-item-title {
|
||||
color: #15aa87 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button @click="handleLogout">登出</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useUserStore from '~/hooks/pinia/useUserStore';
|
||||
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
|
||||
const handleLogout = () => {
|
||||
userStore.logout()
|
||||
router.push('/user/login')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
index
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<nuxt-page></nuxt-page>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
edit: id-{{ route.params.id }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="post-index">
|
||||
<div class="post-index-title">
|
||||
文章列表
|
||||
</div>
|
||||
<div class="post-index-list">
|
||||
<div class="post-index-list-item">
|
||||
上传文章
|
||||
</div>
|
||||
<div v-for="post in postList" :key="post.id" class="post-item post-index-list-item">
|
||||
<div class="post-item-header">
|
||||
<div class="post-item-header-title">
|
||||
{{ post.title }}
|
||||
</div>
|
||||
<!-- <div class="post-item-header-date">
|
||||
{{ formatDate(post.date, 'yy-MM-dd HH:mm:ss') }}
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="post-item-content">
|
||||
<span>
|
||||
{{ post.summary }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="post-item-footer">
|
||||
<div class="post-item-footer-info">
|
||||
<div class="post-item-footer-info-date">
|
||||
{{ formatDate(post.date, 'yy-MM-dd HH:mm:ss') }}
|
||||
</div>
|
||||
<div class="post-item-footer-info-tags">
|
||||
<span v-for="tag in post.tags" :key="tag">{{ tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-button class="post-item-footer-btn" @click="handleClickEditBtn(post.id)">
|
||||
编辑
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { postItem } from '~/types/post';
|
||||
import getPostList from '~/utils/getPost';
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const postList = ref<postItem[]>([]);
|
||||
|
||||
const handleClickEditBtn = (id: number) => {
|
||||
router.push(`/user/main/post/edit-${id}`)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
postList.value = await getPostList();
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.post-index {
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&-title {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 0 0 10px 0;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1rem;
|
||||
letter-spacing: 4px;
|
||||
text-decoration: none;
|
||||
font-family: PT Serif, Serif;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 10px 0 20px;
|
||||
}
|
||||
|
||||
&-list {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
|
||||
&-item {
|
||||
// height: 100px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.post-item {
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
padding-bottom: 5px;
|
||||
|
||||
// padding: 10px;
|
||||
&-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
&-title {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
letter-spacing: 4px;
|
||||
text-decoration: none;
|
||||
font-size: large;
|
||||
background-color: #15aa87;
|
||||
color: #fff;
|
||||
padding: 3px 0 5px;
|
||||
// font-family: PT Serif, Serif;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
max-height: 45px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-indent: 2em;
|
||||
color: #363636;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 5px;
|
||||
|
||||
&-info {
|
||||
padding: 0 5px;
|
||||
|
||||
&>div {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&-btn {
|
||||
height: 25px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
Reference in new issue
Block a user