文章详情组件

master
fuxiaochun 2023-08-17 12:47:52 +08:00
parent a747231358
commit 40c4bb38ce
4 changed files with 1185 additions and 857 deletions

View File

@ -0,0 +1,257 @@
<template>
<div class="pageContainer">
<div class="breadNav" v-if="props.breadNav.length > 0">
<template :key="item.path" v-for="item in props.breadNav">
<router-link :to="item.path">{{item.name}}</router-link><span>&gt;</span>
</template>
<span>详情</span>
</div>
<div class="article">
<template v-if="detail">
<h1 class="title">{{ detail.title }}</h1>
<div class="props">
<span>作者{{ detail.author }}</span>
<span>责编{{ detail.editor }}</span>
<span>{{ DateFormat(new Date(detail.published_at * 1000), 'yyyy.MM.dd') }}</span>
</div>
<div class="info">
<div v-html="detail.content"></div>
</div>
</template>
<div class="loadingBox" v-else>{{ placeholder }}</div>
<div class="recommend" v-if="recommend.length > 0">
<div class="blockTitle">推荐文章</div>
<ul>
<li :key="item.id" v-for="item in recommend" @click="goDetail(item.id)">
<div class="img"><img :src="item.cover" :alt="item.title"></div>
<div class="info">
<h3>{{ item.title }}</h3>
<p>{{ item.description }}1</p>
<span>{{ DateFormat(new Date(item.published_at * 1000), 'yyyy.MM.dd') }}</span>
</div>
</li>
</ul>
</div>
</div>
<!-- <AiAssistant></AiAssistant> -->
</div>
</template>
<script setup>
import { ref, onBeforeMount, onMounted } from 'vue';
import http from '@/io/http';
import { showToast } from 'vant';
import { useRouter, useRoute } from 'vue-router';
import { DateFormat } from '@/utils/format.js';
// import AiAssistant from '@/views/chat/components/ai-assistant.vue';
const props = defineProps({
id: {type: [Number, String], required: true },
breadNav: {type: Array, default: []},
type: String,
isRecommend: {type: Boolean, default: false }
});
const router = useRouter();
const route = useRoute();
const id = ref(props.id || route.params.id);
const detail = ref();
const recommend = ref([]);
const placeholder = ref('数据加载中...');
onMounted(() => {
getDetail();
props.isRecommend && getRecommendList();
});
const getDetail = () => {
http(`/api/article/${id.value}`, {}, 'get').then(res => {
detail.value = res.data;
}).catch(err => {
showToast(err.message);
if(err.status == 1001){
placeholder.value = '无权限阅读,或会员已过期,请先订阅会员';
}else{
placeholder.value = '内容获取失败';
}
});
};
const getRecommendList = () => {
let params = {
recommend: 1,
type: props.type, // policy
per_page: 4,
page: 1
};
http('/api/article', params, 'get').then(res => {
recommend.value = res.data.data || [];
}).catch(err => {
message.error(err.message);
});
};
const goDetail = (id) => {
const urlOptions = {
policy: `/business/legal/policy/detail/${id}`,
insight: '',
};
if(urlOptions[props.type]){
router.push(urlOptions[props.type]);
}
};
</script>
<style lang="scss" scoped>
.pageContainer {
color: #FFF;
padding: 25px;
background-color: #242527;
.breadNav {
height: 30px;
line-height: 30px;
color: #999;
font-size: 22px;
span {
padding: 0 5px;
}
a {
color: #999;
&:hover {
color: #FFF;
}
}
}
.loadingBox {
width: 100%;
height: 400px;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
}
.article {
padding: 20px 0;
.title {
font-size: 26px;
line-height: 30px;
font-weight: bold;
color: #FFF;
text-align: center;
padding: 10px 0;
}
.props {
width: 100%;
text-align: center;
line-height: 30px;
color: #999;
font-size: 23px;
span {
display: inline-block;
margin: 10px;
}
}
.info {
line-height: 1.5;
font-size: 23px;
:deep(p) {
padding: 10px 0;
}
:deep(strong) {
font-weight: bold;
}
:deep(b) {
font-weight: bold;
}
:deep(h1) {
font-weight: bold;
}
:deep(img) {
max-width: 100%;
display: block;
margin: 10px auto;
}
}
.recommend {
padding: 30px 0;
.blockTitle {
height: 80px;
line-height: 80px;
border-bottom: 1px solid #666;
font-size: 39px;
font-weight: bold;
}
ul {
display: flex;
flex-wrap: wrap;
li {
width: 100%;
padding-right: 30px;
display: flex;
margin-top: 30px;
.img {
width: 260px;
height: 360px;
overflow: hidden;
img {
width: 260px;
height: 360px;
}
}
.info {
flex: 1;
margin-left: 15px;
height: 360px;
display: flex;
flex-direction: column;
justify-content: space-between;
h3 {
font-size: 32px;
font-weight: bold;
padding-bottom: 10px;
}
p {
padding: 10px 0;
font-size: 26px;
line-height: 30px;
flex: 1;
}
span {
color: #999;
font-size: 22px;
}
}
}
}
}
}
}
</style>

View File

@ -1,71 +1,44 @@
<template>
<div class="pageContainer">
<div class="breadNav">
<router-link to="/">首页</router-link><span>&gt;</span>
<router-link to="/business">AI商情</router-link><span>&gt;</span>
<router-link to="/business/insight">行业洞察</router-link><span>&gt;</span>
<router-link :to="`/business/insight/category/${category.id}`" v-if="category.id">{{category.name}}</router-link><span v-if="category.id">&gt;</span>
<span>详情</span>
</div>
<div class="article" v-if="detail">
<h1 class="title">{{detail.title}}</h1>
<div class="props">
<span>作者{{detail.author }}</span>
<span>责编{{detail.editor }}</span>
<span>{{DateFormat(new Date(detail.published_at * 1000), 'yyyy.MM.dd')}}</span>
</div>
<div class="info">
<div v-html="detail.content"></div>
</div>
</div>
<div class="loadingBox" v-else>...</div>
<!-- <AiAssistant></AiAssistant> -->
</div>
<ArticleDetail :id="id" :breadNav="breadNav" type="insight" :isRecommend="false" />
</template>
<script setup>
import { ref, onBeforeMount, onMounted } from 'vue';
import http from '@/io/http';
import { showToast } from 'vant';
import { useRouter, useRoute } from 'vue-router';
import { DateFormat } from '@/utils/format.js';
// import AiAssistant from '@/views/chat/components/ai-assistant.vue';
import { useRoute } from 'vue-router';
import ArticleDetail from '@/components/ArticleDetail/index.vue';
const breadNav = [
{ path: '/', name: '首页' },
{ path: '/business', name: 'AI商情' },
{ path: '/business/insight', name: '行业洞察' },
];
const router = useRouter();
const route = useRoute();
const cid = ref(route.params.cid);
const id = ref(route.params.id);
const category = ref({});
const detail = ref();
onBeforeMount(()=>{
getCategories();
});
onMounted(()=>{
getDetail();
});
const getCategories = () => {
let params = { type_key: 'business' };
http('/api/keywords', params, 'get').then(res => {
category.value = res.data.filter(v => v.id == cid.value)[0];
}).catch(err => {
showToast(err.message);
});
};
// const getCategories = () => {
// let params = { type_key: 'business' };
// http('/api/keywords', params, 'get').then(res => {
// category.value = res.data.filter(v => v.id == cid.value)[0];
// }).catch(err => {
// showToast(err.message);
// });
// };
const getDetail = ()=>{
const getDetail = () => {
http(`/api/article/${id.value}`, {}, 'get').then(res => {
detail.value = res.data;
console.log(res.data);
}).catch(err => {
showToast(err.message);
// showToast(err.message);
});
};
const goBack = () => {
router.back();
};
</script>

View File

@ -1,216 +1,19 @@
<template>
<div class="pageContainer">
<div class="breadNav">
<router-link to="/">首页</router-link><span>&gt;</span>
<router-link to="/business">AI商情</router-link><span>&gt;</span>
<router-link to="/business/legal">法律法规</router-link><span>&gt;</span>
<router-link to="/business/legal/policy">政策解读</router-link><span>&gt;</span>
<span>详情</span>
</div>
<div class="article">
<template v-if="detail">
<h1 class="title">{{detail.title}}</h1>
<div class="props">
<span>作者{{detail.author }}</span>
<span>责编{{detail.editor }}</span>
<span>{{DateFormat(new Date(detail.published_at * 1000), 'yyyy.MM.dd')}}</span>
</div>
<div class="info">
<div v-html="detail.content"></div>
</div>
</template>
<div class="loadingBox" v-else>...</div>
<div class="recommend" v-if="recommend.length > 0">
<div class="blockTitle">推荐文章</div>
<ul>
<li :key="item.id" v-for="item in recommend" @click="goDetail(item.id)">
<div class="img"><img :src="item.cover" :alt="item.title"></div>
<div class="info">
<h3>{{ item.title }}</h3>
<p>{{ item.description }}1</p>
<span>{{ DateFormat(new Date(item.published_at * 1000), 'yyyy.MM.dd') }}</span>
</div>
</li>
</ul>
</div>
</div>
<!-- <AiAssistant></AiAssistant> -->
</div>
<ArticleDetail :id="id" :breadNav="breadNav" type="policy" :isRecommend="true" />
</template>
<script setup>
import { ref, onBeforeMount, onMounted } from 'vue';
import http from '@/io/http';
import { showToast } from 'vant';
import { useRouter, useRoute } from 'vue-router';
import { DateFormat } from '@/utils/format.js';
// import AiAssistant from '@/views/chat/components/ai-assistant.vue';
import { useRoute } from 'vue-router';
import ArticleDetail from '@/components/ArticleDetail/index.vue';
const breadNav = [
{path: '/', name: '首页'},
{path: '/business', name: 'AI商情'},
{path: '/business/legal', name: '法律法规'},
{path: '/business/legal/policy', name: '政策解读'},
];
const router = useRouter();
const route = useRoute();
const id = ref(route.params.id);
const category = ref({});
const detail = ref();
const recommend = ref([]);
onMounted(()=>{
getDetail();
getRecommendList();
});
const getDetail = ()=>{
http(`/api/article/${id.value}`, {}, 'get').then(res => {
detail.value = res.data;
category.value = res.data.category;
}).catch(err => {
showToast(err.message);
});
};
const getRecommendList = () => {
let params = {
recommend: 1,
type: 'policy',
per_page: 4,
page: 1
};
http('/api/article', params, 'get').then(res => {
recommend.value = res.data.data || [];
}).catch(err => {
message.error(err.message);
});
};
const goDetail = (id) => {
router.push(`/business/legal/policy/detail/${id}`);
};
</script>
<style lang="scss" scoped>
.pageContainer{
color: #FFF;
padding: 25px;
background-color: #242527;
.breadNav{
height: 30px;
line-height: 30px;
color: #999;
font-size: 22px;
span{
padding: 0 5px;
}
a{
color: #999;
&:hover{
color: #FFF;
}
}
}
.loadingBox{
width: 100%;
height: 400px;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
}
.article{
padding: 20px 0;
.title{
font-size: 26px;
line-height: 30px;
font-weight: bold;
color: #FFF;
text-align: center;
padding: 10px 0;
}
.props{
width: 100%;
text-align: center;
line-height: 30px;
color: #999;
font-size: 23px;
span{
display: inline-block;
margin: 10px;
}
}
.info{
line-height: 1.5;
font-size: 23px;
:deep(p){
padding: 10px 0;
}
:deep(strong){
font-weight: bold;
}
:deep(b){
font-weight: bold;
}
:deep(h1){
font-weight: bold;
}
:deep(img){
max-width: 100%;
display: block;
margin: 10px auto;
}
}
.recommend{
padding: 30px 0;
.blockTitle{
height: 80px;
line-height: 80px;
border-bottom: 1px solid #666;
font-size: 39px;
font-weight: bold;
}
ul{
display: flex;
flex-wrap: wrap;
li{
width: 100%;
padding-right: 30px;
display: flex;
margin-top: 30px;
.img{
width: 260px;
height: 360px;
overflow: hidden;
img{
width: 260px;
height: 360px;
}
}
.info{
flex: 1;
margin-left: 15px;
height: 360px;
display: flex;
flex-direction: column;
justify-content: space-between;
h3{
font-size: 32px;
font-weight: bold;
padding-bottom: 10px;
}
p{
padding: 10px 0;
font-size: 26px;
line-height: 30px;
flex: 1;
}
span{
color: #999;
font-size: 22px;
}
}
}
}
}
}
}
</style>

1501
yarn.lock

File diff suppressed because it is too large Load Diff