完成帖子详情前端部分

This commit is contained in:
柏码の讲师 2023-10-23 19:18:47 +08:00
parent cc4eb03592
commit 506dadb784
8 changed files with 177 additions and 33 deletions

View File

@ -19,7 +19,7 @@ public class TopicDetailVO {
String username;
String avatar;
String desc;
boolean gender;
Integer gender;
String qq;
String wx;
String phone;

View File

@ -14,6 +14,7 @@
"axios": "^1.4.0",
"element-plus": "^2.3.9",
"pinia": "^2.1.6",
"quill-delta-to-html": "^0.12.1",
"quill-image-resize-vue": "^1.0.4",
"quill-image-super-solution-module": "^2.0.1",
"vue": "^3.3.4",
@ -1827,6 +1828,14 @@
"lodash.isequal": "^4.5.0"
}
},
"node_modules/quill-delta-to-html": {
"version": "0.12.1",
"resolved": "https://registry.npmmirror.com/quill-delta-to-html/-/quill-delta-to-html-0.12.1.tgz",
"integrity": "sha512-QhpeMk9+5ge3HYbL5A0Ewz3pXCsbemqGvIF/kw5D6D4V68AtcUp7yt9xNUkzOk/0IQz43hKy3IkzBzRhLIE+oA==",
"dependencies": {
"lodash.isequal": "^4.5.0"
}
},
"node_modules/quill-image-resize-vue": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/quill-image-resize-vue/-/quill-image-resize-vue-1.0.4.tgz",

View File

@ -14,6 +14,7 @@
"axios": "^1.4.0",
"element-plus": "^2.3.9",
"pinia": "^2.1.6",
"quill-delta-to-html": "^0.12.1",
"quill-image-resize-vue": "^1.0.4",
"quill-image-super-solution-module": "^2.0.1",
"vue": "^3.3.4",

View File

@ -0,0 +1,31 @@
<script setup>
import {useStore} from "@/store";
const store = useStore()
defineProps({
type: Number
})
</script>
<template>
<div class="topic-type"
:style="{
color: store.findTypeById(type)?.color + 'EE',
'border-color': store.findTypeById(type)?.color + '77',
'background': store.findTypeById(type)?.color + '33'
}">
{{store.findTypeById(type)?.name}}
</div>
</template>
<style scoped>
.topic-type {
display: inline-block;
border: solid 0.5px grey;
border-radius: 3px;
font-size: 12px;
padding: 0 5px;
height: 18px;
}
</style>

View File

@ -30,12 +30,19 @@ const router = createRouter({
children: [
{
path: '',
name: 'topic-list',
component: () => import('@/views/forum/TopicList.vue')
},{
path: 'topic-detail/:tid',
name: 'topic-detail',
component: () => import('@/views/forum/TopicDetail.vue')
name: 'topics',
component: () => import('@/views/forum/Forum.vue'),
children: [
{
path: '',
name: 'topic-list',
component: () => import('@/views/forum/TopicList.vue')
},{
path: 'topic-detail/:tid',
name: 'topic-detail',
component: () => import('@/views/forum/TopicDetail.vue')
}
]
}, {
path: 'user-setting',
name: 'user-setting',

View File

@ -0,0 +1,23 @@
<script setup>
import {get} from "@/net";
import {useStore} from "@/store";
const store = useStore()
get('/api/forum/types', data => {
const array = []
array.push({name: '全部', id: 0, color: 'linear-gradient(45deg, white, red, orange, gold, green, blue)'})
data.forEach(d => array.push(d))
store.forum.types = array
})
</script>
<template>
<router-view v-slot="{ Component }">
<transition name="el-fade-in-linear" mode="out-in">
<keep-alive include="TopicList">
<component :is="Component"/>
</keep-alive>
</transition>
</router-view>
</template>

View File

@ -1,20 +1,114 @@
<script setup>
import {useRoute} from "vue-router";
import {get} from "@/net";
import axios from "axios";
import {computed, reactive} from "vue";
import {ArrowLeft, Female, Male} from "@element-plus/icons-vue";
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html';
import Card from "@/components/Card.vue";
import router from "@/router";
import TopicTag from "@/components/TopicTag.vue";
const route = useRoute()
const tid = route.params.tid
get(`api/forum/topic?tid=${tid}`, data => {
console.info(data)
const topic = reactive({
data: null,
comments: []
})
get(`api/forum/topic?tid=${tid}`, data => topic.data = data)
const content = computed(() => {
const ops = JSON.parse(topic.data.content).ops
const converter = new QuillDeltaToHtmlConverter(ops, { inlineStyles: true });
return converter.convert();
})
</script>
<template>
<div class="topic-page" v-if="topic.data">
<div class="topic-main" style="position: sticky;top: 0;z-index: 10">
<card style="display: flex;width: 100%;">
<el-button :icon="ArrowLeft" type="info" size="small"
plain round @click="router.push('/index')">返回列表</el-button>
<div style="text-align: center;flex: 1">
<topic-tag :type="topic.data.type"/>
<span style="font-weight: bold;margin-left: 5px">{{topic.data.title}}</span>
</div>
</card>
</div>
<div class="topic-main">
<div class="topic-main-left">
<el-avatar :src="axios.defaults.baseURL + '/images' + topic.data.user.avatar" :size="60"/>
<div>
<div style="font-size: 18px;font-weight: bold">
{{topic.data.user.username}}
<span style="color: hotpink" v-if="topic.data.user.gender === 1">
<el-icon><Female/></el-icon>
</span>
<span style="color: dodgerblue" v-if="topic.data.user.gender === 0">
<el-icon><Male/></el-icon>
</span>
</div>
<div class="desc">{{topic.data.user.email}}</div>
</div>
<el-divider style="margin: 10px 0"/>
<div style="text-align: left;margin: 0 5px">
<div class="desc">微信号: {{topic.data.user.wx || '已隐藏或未填写'}}</div>
<div class="desc">QQ号: {{topic.data.user.qq || '已隐藏或未填写'}}</div>
<div class="desc">手机号: {{topic.data.user.phone || '已隐藏或未填写'}}</div>
</div>
<el-divider style="margin: 10px 0"/>
<div class="desc" style="margin: 0 5px">{{topic.data.user.desc}}</div>
</div>
<div class="topic-main-right">
<div class="topic-content" v-html="content"></div>
</div>
</div>
<div>
</div>
</div>
</template>
<style scoped>
.topic-page {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px 0;
}
.topic-main {
display: flex;
border-radius: 7px;
margin: 0 auto;
background-color: var(--el-bg-color);
width: 800px;
.topic-main-left {
width: 200px;
padding: 10px;
text-align: center;
border-right: solid 1px var(--el-border-color);
.desc {
font-size: 12px;
color: grey;
}
}
.topic-main-right {
width: 600px;
padding: 10px 20px;
.topic-content {
font-size: 14px;
line-height: 22px;
opacity: 0.8;
}
}
}
</style>

View File

@ -21,6 +21,7 @@ import {useStore} from "@/store";
import axios from "axios";
import ColorDot from "@/components/ColorDot.vue";
import router from "@/router";
import TopicTag from "@/components/TopicTag.vue";
const store = useStore()
@ -45,12 +46,6 @@ const today = computed(() => {
const date = new Date()
return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}`
})
get('/api/forum/types', data => {
const array = []
array.push({name: '全部', id: 0, color: 'linear-gradient(45deg, white, red, orange, gold, green, blue)'})
data.forEach(d => array.push(d))
store.forum.types = array
})
get('/api/forum/top-topic', data => topics.top = data)
function updateList(){
if(topics.end) return
@ -112,7 +107,7 @@ navigator.geolocation.getCurrentPosition(position => {
</div>
</light-card>
<light-card style="margin-top: 10px;display: flex;flex-direction: column;gap: 10px">
<div v-for="item in topics.top" class="top-topic">
<div v-for="item in topics.top" class="top-topic" @click="router.push(`/index/topic-detail/${item.id}`)">
<el-tag type="info" size="small">置顶</el-tag>
<div>{{item.title}}</div>
<div>{{new Date(item.time).toLocaleDateString()}}</div>
@ -147,14 +142,7 @@ navigator.geolocation.getCurrentPosition(position => {
</div>
</div>
<div style="margin-top: 5px">
<div class="topic-type"
:style="{
color: store.findTypeById(item.type)?.color + 'EE',
'border-color': store.findTypeById(item.type)?.color + '77',
'background': store.findTypeById(item.type)?.color + '33'
}">
{{store.findTypeById(item.type)?.name}}
</div>
<topic-tag :type="item.type"/>
<span style="font-weight: bold;margin-left: 7px">{{item.title}}</span>
</div>
<div class="topic-content">{{item.text}}</div>
@ -285,15 +273,6 @@ navigator.geolocation.getCurrentPosition(position => {
text-overflow: ellipsis;
}
.topic-type {
display: inline-block;
border: solid 0.5px grey;
border-radius: 3px;
font-size: 12px;
padding: 0 5px;
height: 18px;
}
.topic-image {
width: 100%;
height: 100%;