temp-save
This commit is contained in:
parent
f4ed5f5db5
commit
c1296a21b4
316
app/components/news/new.vue
Normal file
316
app/components/news/new.vue
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
<script lang="ts" setup>
|
||||
import {computed} from "vue";
|
||||
import {useImageStyles} from '~/composables/useImageStyles';
|
||||
|
||||
// 组件属性
|
||||
interface Props {
|
||||
articleData: {
|
||||
title: string
|
||||
publishDate: string
|
||||
category: string
|
||||
content: string
|
||||
prevArticle: {
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
nextArticle: {
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
}
|
||||
loading: boolean
|
||||
error: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
articleData: () => ({
|
||||
title: '',
|
||||
publishDate: '',
|
||||
category: '',
|
||||
content: '',
|
||||
prevArticle: {
|
||||
title: '',
|
||||
url: '#'
|
||||
},
|
||||
nextArticle: {
|
||||
title: '',
|
||||
url: '#'
|
||||
}
|
||||
}),
|
||||
loading: true,
|
||||
error: ''
|
||||
})
|
||||
|
||||
// 使用传入的数据
|
||||
const articleData = computed(() => props.articleData)
|
||||
const loading = computed(() => props.loading)
|
||||
const error = computed(() => props.error)
|
||||
|
||||
// 热门标签
|
||||
const hotTags = ref([
|
||||
'景区单车', '政务平台', '共享经济', '共享汽车APP开发', '共享类',
|
||||
'共享汽车软件开发', '共享雨伞APP开发', '共享雨伞软件开发', '共享货车开发'
|
||||
])
|
||||
|
||||
// 重新加载页面方法
|
||||
const reloadPage = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
// 使用图片样式处理 composable
|
||||
const {initImageStyles} = useImageStyles(
|
||||
() => props.articleData?.content || '',
|
||||
'.article-content',
|
||||
{
|
||||
maxWidth: '100%',
|
||||
margin: '15px 0',
|
||||
display: 'block',
|
||||
boxSizing: 'border-box'
|
||||
}
|
||||
)
|
||||
|
||||
// 使用 Nuxt 的 useHead 来管理页面资源
|
||||
useHead({
|
||||
title: computed(() => articleData.value?.title ? `${articleData.value.title} - 创特科技` : '文章详情 - 创特科技'),
|
||||
meta: [
|
||||
{
|
||||
name: 'description',
|
||||
content: computed(() => articleData.value?.content ? articleData.value.content.substring(0, 160) + '...' : '创特科技专业文章')
|
||||
},
|
||||
{name: 'keywords', content: '创特科技,技术文章,共享单车,软件开发,解决方案'}
|
||||
],
|
||||
link: [
|
||||
{rel: 'stylesheet', href: '/news/bootstrap.min.css'},
|
||||
|
||||
{rel: 'stylesheet', href: '/news/main22.css'},
|
||||
|
||||
{rel: 'stylesheet', href: '/news/new_index.css'},
|
||||
{rel: 'stylesheet', href: '/news/float.css'},
|
||||
{rel: 'stylesheet', href: '/news/animate.min.css'},
|
||||
{rel: 'stylesheet', href: '/css/main2.css'},
|
||||
],
|
||||
script: [
|
||||
|
||||
{src: '/news/float.js', defer: true}
|
||||
]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化图片样式处理
|
||||
initImageStyles()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<!-- 顶部 -->
|
||||
|
||||
<!-- 文章正文 -->
|
||||
<section class="container" style="margin-top: 88px;">
|
||||
<div class="row">
|
||||
<!-- 左边部分 -->
|
||||
<div class="col-md-8 wow fadeInLeft animated" style="visibility: visible; animation-name: fadeInLeft;">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-container" style="text-align: center; padding: 50px;">
|
||||
<div
|
||||
class="loading-spinner"
|
||||
style="border: 4px solid #f3f3f3; border-top: 4px solid #ff8200; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto;"/>
|
||||
<p style="margin-top: 20px; color: #666;">正在加载文章...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<div v-else-if="error" class="error-container" style="text-align: center; padding: 50px; color: #ff6b6b;">
|
||||
<p>{{ error }}</p>
|
||||
<button
|
||||
style="margin-top: 20px; padding: 10px 20px; background: #ff8200; color: white; border: none; border-radius: 4px; cursor: pointer;"
|
||||
@click="reloadPage">
|
||||
重新加载
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 文章内容 -->
|
||||
<div v-else class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2>{{ articleData?.title || '暂无标题' }}</h2>
|
||||
<p id="label" style="border-bottom: 1px solid #ddd; margin-top: 20px;">
|
||||
<span>{{ articleData?.publishDate || '暂无日期' }}</span>
|
||||
<span class="pull-right">分类:{{ articleData?.category || '暂无分类' }}</span>
|
||||
</p>
|
||||
<div class="article-content" v-html="articleData?.content || '暂无内容'"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 上一篇/下一篇 -->
|
||||
<div class="nextorpre" style="margin-top: 38px; border-top: 1px solid #ddd; padding-top: 8px;">
|
||||
<li class="pull-left">上一篇:
|
||||
<a :href="articleData?.prevArticle?.url || '#'">{{ articleData?.prevArticle?.title || '暂无上一篇' }}</a>
|
||||
</li>
|
||||
<li class="pull-right">下一篇:
|
||||
<a :href="articleData?.nextArticle?.url || '#'">{{ articleData?.nextArticle?.title || '暂无下一篇' }}</a>
|
||||
</li>
|
||||
</div>
|
||||
<br><br><br><br>
|
||||
</div><!--左边部分-->
|
||||
|
||||
<!-- 右边部分 -->
|
||||
<aside class="col-md-4" style="border-left: 1px solid #eee; background: #fefefe;">
|
||||
<!-- 热门标签 -->
|
||||
<div
|
||||
class="widget tags wow fadeInRight animated"
|
||||
style="margin-bottom: 30px !important; visibility: visible; animation-name: fadeInRight;">
|
||||
<h4>热门标签</h4>
|
||||
<ul class="tag-cloud">
|
||||
<li v-for="tag in hotTags" :key="tag">
|
||||
<a class="btn btn-xs" href="#" @click.prevent>{{ tag }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!-- 热门标签 -->
|
||||
|
||||
<!-- 推荐文章 -->
|
||||
<div
|
||||
class="sy_news animated" data-wow-delay="200ms"
|
||||
style="visibility: visible; animation-delay: 200ms; animation-name: fadeInDown;">
|
||||
<RecommendedArticles
|
||||
:articles-per-type="3"
|
||||
:show-title="false"
|
||||
:show-types="['solution', 'developKnowledge', 'industryTrend']"
|
||||
/>
|
||||
</div>
|
||||
</aside><!-- 右边部分 -->
|
||||
|
||||
</div><!--/.row-->
|
||||
</section><!--/#blog-->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 文章内容样式 */
|
||||
.article-content {
|
||||
margin-top: 20px;
|
||||
line-height: 1.8;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
word-wrap: break-word; /* 长单词换行 */
|
||||
}
|
||||
|
||||
.article-content p {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 1024px) {
|
||||
.col-md-8, .col-md-4 {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* 标签云样式 */
|
||||
.tag-cloud li {
|
||||
display: inline-block;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.tag-cloud a {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tag-cloud a:hover {
|
||||
background-color: #ff8200;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 推荐文章样式 */
|
||||
.sy_news ul li {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.sy_news ul li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.sy_news ul li a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
display: block;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.sy_news ul li a:hover {
|
||||
color: #ff8200;
|
||||
}
|
||||
|
||||
.sy_news ul li a span {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 上一篇下一篇样式 */
|
||||
.nextorpre {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nextorpre li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nextorpre a {
|
||||
color: #ff8200;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nextorpre a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 加载状态样式 */
|
||||
.loading-container {
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 错误状态样式 */
|
||||
.error-container {
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
160
app/composables/useArticleApi.ts
Normal file
160
app/composables/useArticleApi.ts
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// 文章API服务
|
||||
// 导入API配置
|
||||
import {getApiUrl, API_CONFIG} from '~/config/api'
|
||||
|
||||
export interface Article {
|
||||
id: string
|
||||
title: string
|
||||
brief: string | null
|
||||
content: string | null
|
||||
createTime: string
|
||||
code: string | null
|
||||
status: string | null
|
||||
}
|
||||
|
||||
export interface ArticleListResponse {
|
||||
msg: string
|
||||
code: number
|
||||
data: Article[]
|
||||
}
|
||||
|
||||
export interface ArticleListParams {
|
||||
code?: string // 文章类型:solution、developKnowledge、industryTrend
|
||||
orderByColumn?: string
|
||||
isAsc?: string
|
||||
pageNum?: number
|
||||
pageSize?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
* @param params 查询参数
|
||||
* @returns Promise<ArticleListResponse>
|
||||
*/
|
||||
export const fetchArticleList = async (params: ArticleListParams = {}): Promise<ArticleListResponse> => {
|
||||
try {
|
||||
// 构建查询参数
|
||||
const queryParams = new URLSearchParams()
|
||||
|
||||
if (params.code) queryParams.append('code', params.code)
|
||||
if (params.orderByColumn) queryParams.append('orderByColumn', params.orderByColumn)
|
||||
if (params.isAsc) queryParams.append('isAsc', params.isAsc)
|
||||
if (params.pageNum) queryParams.append('pageNum', params.pageNum.toString())
|
||||
if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString())
|
||||
|
||||
const url = `${getApiUrl(API_CONFIG.ENDPOINTS.ARTICLE.LIST)}?${queryParams.toString()}`
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: API_CONFIG.REQUEST.HEADERS,
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
const result: ArticleListResponse = await response.json()
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('获取文章列表失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐文章(按类型分组)
|
||||
* @param types 文章类型数组
|
||||
* @param pageSize 每页数量
|
||||
* @returns Promise<Record<string, Article[]>>
|
||||
*/
|
||||
export const fetchRecommendedArticles = async (
|
||||
types: string[] = ['solution', 'developKnowledge', 'industryTrend'],
|
||||
pageSize: number = 5
|
||||
): Promise<Record<string, Article[]>> => {
|
||||
try {
|
||||
const result: Record<string, Article[]> = {}
|
||||
|
||||
// 并发获取各类型文章
|
||||
const promises = types.map(async (type) => {
|
||||
const response = await fetchArticleList({
|
||||
code: type,
|
||||
orderByColumn: 'createTime',
|
||||
isAsc: 'descending',
|
||||
pageNum: 1,
|
||||
pageSize: pageSize
|
||||
})
|
||||
return {type, articles: response.data}
|
||||
})
|
||||
|
||||
const responses = await Promise.all(promises)
|
||||
|
||||
// 整理结果
|
||||
responses.forEach(({type, articles}) => {
|
||||
result[type] = articles
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('获取推荐文章失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章类型映射
|
||||
*/
|
||||
export const ARTICLE_TYPE_MAP: Record<string, string> = {
|
||||
'solution': '解决方案',
|
||||
'developKnowledge': '开发知识',
|
||||
'industryTrend': '行业动态',
|
||||
'aboutUs': '关于我们'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章类型的中文名称
|
||||
* @param code 文章类型代码
|
||||
* @returns 中文名称
|
||||
*/
|
||||
export const getArticleTypeName = (code: string): string => {
|
||||
return ARTICLE_TYPE_MAP[code] || '未知类型'
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章API Composable
|
||||
* @returns 文章API相关方法
|
||||
*/
|
||||
export const useArticleApi = () => {
|
||||
/**
|
||||
* 获取文章列表
|
||||
* @param params 查询参数
|
||||
* @returns Promise<Article[]>
|
||||
*/
|
||||
const getArticles = async (params: ArticleListParams = {}): Promise<Article[]> => {
|
||||
try {
|
||||
const response = await fetchArticleList(params)
|
||||
return response.data || []
|
||||
} catch (error) {
|
||||
console.error('获取文章列表失败:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推荐文章(按类型分组)
|
||||
* @param types 文章类型数组
|
||||
* @param pageSize 每页数量
|
||||
* @returns Promise<Record<string, Article[]>>
|
||||
*/
|
||||
const getRecommendedArticles = async (
|
||||
types: string[] = ['solution', 'developKnowledge', 'industryTrend'],
|
||||
pageSize: number = 5
|
||||
): Promise<Record<string, Article[]>> => {
|
||||
return await fetchRecommendedArticles(types, pageSize)
|
||||
}
|
||||
|
||||
return {
|
||||
getArticles,
|
||||
getRecommendedArticles,
|
||||
getArticleTypeName
|
||||
}
|
||||
}
|
||||
82
app/composables/useImageStyles.ts
Normal file
82
app/composables/useImageStyles.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import {nextTick, watch, watchEffect, onMounted, type Ref} from 'vue'
|
||||
|
||||
/**
|
||||
* 图片样式处理 Composable
|
||||
* 用于强制处理 v-html 内容中的图片样式
|
||||
*/
|
||||
export const useImageStyles = (
|
||||
contentRef: Ref<string> | (() => string),
|
||||
containerSelector: string = '.article-content',
|
||||
options: {
|
||||
maxWidth?: string
|
||||
margin?: string
|
||||
display?: string
|
||||
boxSizing?: string
|
||||
} = {}
|
||||
) => {
|
||||
// 默认配置
|
||||
const defaultOptions = {
|
||||
maxWidth: 'calc(100% - 0px)',
|
||||
margin: '15px 0',
|
||||
display: 'block',
|
||||
boxSizing: 'border-box',
|
||||
...options
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制处理图片样式
|
||||
*/
|
||||
const forceImageStyles = () => {
|
||||
if (typeof document === 'undefined') return
|
||||
|
||||
const images = document.querySelectorAll(`${containerSelector} img`)
|
||||
images.forEach((img: any) => {
|
||||
// 强制设置样式
|
||||
img.style.maxWidth = defaultOptions.maxWidth
|
||||
img.style.height = 'auto'
|
||||
img.style.width = 'auto'
|
||||
img.style.display = defaultOptions.display
|
||||
img.style.margin = defaultOptions.margin
|
||||
img.style.boxSizing = defaultOptions.boxSizing
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理图片样式的核心方法
|
||||
*/
|
||||
const processImageStyles = () => {
|
||||
nextTick(() => {
|
||||
forceImageStyles()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化图片样式处理
|
||||
*/
|
||||
const initImageStyles = () => {
|
||||
// 组件挂载时处理
|
||||
onMounted(() => {
|
||||
processImageStyles()
|
||||
})
|
||||
|
||||
// 监听内容变化
|
||||
if (typeof contentRef === 'function') {
|
||||
// 如果是函数,使用 watchEffect 监听
|
||||
watchEffect(() => {
|
||||
contentRef() // 触发函数执行
|
||||
processImageStyles()
|
||||
})
|
||||
} else {
|
||||
// 如果是 Ref,监听其值
|
||||
watch(contentRef, () => {
|
||||
processImageStyles()
|
||||
}, {deep: true})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
forceImageStyles,
|
||||
processImageStyles,
|
||||
initImageStyles
|
||||
}
|
||||
}
|
||||
61
app/config/api.ts
Normal file
61
app/config/api.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* API配置文件
|
||||
* 统一管理所有API相关配置
|
||||
*/
|
||||
|
||||
// API基础地址配置
|
||||
export const API_CONFIG = {
|
||||
// 开发环境API地址
|
||||
BASE_URL: 'http://192.168.1.4:4101',
|
||||
|
||||
// API端点配置
|
||||
ENDPOINTS: {
|
||||
// 文章相关API
|
||||
ARTICLE: {
|
||||
LIST: '/app/owArticle/list',
|
||||
GET: '/app/owArticle/get',
|
||||
CREATE: '/app/owArticle/create',
|
||||
UPDATE: '/app/owArticle/update',
|
||||
DELETE: '/app/owArticle/delete'
|
||||
}
|
||||
},
|
||||
|
||||
// 请求配置
|
||||
REQUEST: {
|
||||
TIMEOUT: 10000, // 请求超时时间(毫秒)
|
||||
RETRY_COUNT: 3, // 重试次数
|
||||
HEADERS: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
}
|
||||
} as const
|
||||
|
||||
/**
|
||||
* 获取完整的API URL
|
||||
* @param endpoint API端点
|
||||
* @returns 完整的API URL
|
||||
*/
|
||||
export const getApiUrl = (endpoint: string): string => {
|
||||
return `${API_CONFIG.BASE_URL}${endpoint}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章API URL
|
||||
* @param action 操作类型
|
||||
* @param id 文章ID(可选)
|
||||
* @returns 文章API URL
|
||||
*/
|
||||
export const getArticleApiUrl = (action: keyof typeof API_CONFIG.ENDPOINTS.ARTICLE, id?: string | number): string => {
|
||||
const endpoint = API_CONFIG.ENDPOINTS.ARTICLE[action]
|
||||
const baseUrl = getApiUrl(endpoint)
|
||||
|
||||
if (id && (action === 'GET' || action === 'UPDATE' || action === 'DELETE')) {
|
||||
return `${baseUrl}/${id}`
|
||||
}
|
||||
|
||||
return baseUrl
|
||||
}
|
||||
|
||||
// 导出默认配置
|
||||
export default API_CONFIG
|
||||
103
app/pages/news/[id].vue
Normal file
103
app/pages/news/[id].vue
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<script lang="ts" setup>
|
||||
// 设置页面布局
|
||||
// 导入API配置
|
||||
import {getArticleApiUrl} from '~/config/api'
|
||||
|
||||
|
||||
// 获取路由参数
|
||||
const route = useRoute()
|
||||
const articleId = route.params.id as string
|
||||
|
||||
// 文章数据
|
||||
const articleData = ref({
|
||||
title: '',
|
||||
publishDate: '',
|
||||
category: '',
|
||||
content: '',
|
||||
prevArticle: {
|
||||
title: '',
|
||||
url: '#'
|
||||
},
|
||||
nextArticle: {
|
||||
title: '',
|
||||
url: '#'
|
||||
}
|
||||
})
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(true)
|
||||
const error = ref('')
|
||||
|
||||
// 获取文章详情
|
||||
const fetchArticle = async (id: string) => {
|
||||
try {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
const response = await fetch(getArticleApiUrl('GET', id))
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
|
||||
const res = await response.json()
|
||||
const data = res.data
|
||||
|
||||
console.log('api请求数据', data)
|
||||
|
||||
// 分类映射配置
|
||||
const categoryMapping: Record<string, string> = {
|
||||
'solution': '解决方案',
|
||||
'developKnowledge': '开发知识',
|
||||
'industryTrend': '行业动态',
|
||||
'aboutUs': '关于我们'
|
||||
}
|
||||
|
||||
data.code = categoryMapping[data.code] || '暂无分类'
|
||||
|
||||
// 更新文章数据
|
||||
articleData.value = {
|
||||
title: data.title || '暂无标题',
|
||||
publishDate: data.createTime || '暂无日期',
|
||||
category: data.code || '暂无分类',
|
||||
content: data.content || '暂无内容',
|
||||
prevArticle: data.prevArticle || {
|
||||
title: '暂无上一篇',
|
||||
url: '#'
|
||||
},
|
||||
nextArticle: data.nextArticle || {
|
||||
title: '暂无下一篇',
|
||||
url: '#'
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取文章失败:', err)
|
||||
error.value = '获取文章失败,请稍后重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载时获取文章详情
|
||||
onMounted(() => {
|
||||
if (articleId) {
|
||||
fetchArticle(articleId)
|
||||
}
|
||||
})
|
||||
|
||||
// 监听路由变化
|
||||
watch(() => route.params.id, (newId) => {
|
||||
if (newId) {
|
||||
fetchArticle(newId as string)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<NewsNew :article-data="articleData" :error="error" :loading="loading"/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
BIN
public/img/news/banner2.png
Normal file
BIN
public/img/news/banner2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Loading…
Reference in New Issue
Block a user