Files
msh-system/msh_single_uniapp/pages/tool/knowledge-detail.vue
scottpan 4be53dcd1b feat: 集成 KieAI 服务,移除 models-integration 子项目
- 添加 Gemini 2.5 Flash 对话接口(流式+非流式)
- 添加 NanoBanana 图像生成/编辑接口
- 添加 Sora2 视频生成接口(文生视频、图生视频、去水印)
- 移除 models-integration 子项目(功能已迁移至主后端)
- 新增测试文档和 Playwright E2E 配置
- 更新前端页面和 API 接口
- 更新后端配置和日志处理
2026-03-03 15:33:50 +08:00

157 lines
3.3 KiB
Vue

<template>
<view class="knowledge-detail-page">
<scroll-view class="content-scroll" scroll-y v-if="detail.title">
<view class="detail-header">
<view class="detail-title">{{ detail.title }}</view>
<view class="detail-meta">
<text class="meta-item">{{ detail.time }}</text>
<text class="meta-dot">·</text>
<text class="meta-item">{{ detail.views }} 阅读</text>
</view>
<image
v-if="detail.coverImage || detail.cover_image"
class="detail-cover"
:src="detail.coverImage || detail.cover_image"
mode="widthFix"
/>
</view>
<view class="detail-body">
<jyf-parser :html="detail.content || ''" :tag-style="tagStyle" />
</view>
</scroll-view>
<view v-else-if="loading" class="loading-wrap">
<text>加载中...</text>
</view>
<view v-else-if="error" class="error-wrap">
<text>{{ error }}</text>
</view>
</view>
</template>
<script>
import { getKnowledgeDetail } from '@/api/tool.js';
import parser from '@/components/jyf-parser/jyf-parser';
export default {
components: {
'jyf-parser': parser
},
data() {
return {
id: '',
detail: {},
loading: true,
error: '',
tagStyle: {
img: 'width:100%;display:block;',
table: 'width:100%',
video: 'width:100%'
}
};
},
onLoad(options) {
if (options.id) {
this.id = options.id;
} else {
this.loading = false;
this.error = '缺少文章 ID';
}
},
onShow() {
if (this.id) {
this.loadDetail();
}
},
methods: {
formatTime(val) {
if (!val) return '';
const d = new Date(val);
if (isNaN(d.getTime())) return String(val);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
},
async loadDetail() {
this.loading = true;
this.error = '';
try {
const res = await getKnowledgeDetail(this.id);
if (res && res.data) {
const d = res.data;
this.detail = {
...d,
time: this.formatTime(d.publishedAt || d.updatedAt || d.createdAt),
views: d.viewCount != null ? d.viewCount : (d.views != null ? d.views : 0),
coverImage: d.coverImage || d.cover_image || ''
};
uni.setNavigationBarTitle({
title: (d.title || '知识详情').substring(0, 12) + (d.title && d.title.length > 12 ? '...' : '')
});
} else {
this.error = '加载失败';
}
} catch (e) {
console.error('知识详情加载失败:', e);
this.error = (e && (e.message || e.msg)) || '加载失败,请重试';
} finally {
this.loading = false;
}
}
}
};
</script>
<style lang="scss" scoped>
.knowledge-detail-page {
min-height: 100vh;
background: #f4f5f7;
}
.content-scroll {
height: 100vh;
}
.detail-header {
padding: 24rpx 30rpx;
background: #fff;
margin-bottom: 16rpx;
}
.detail-title {
font-size: 36rpx;
font-weight: bold;
color: #282828;
line-height: 1.4;
margin-bottom: 16rpx;
}
.detail-meta {
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
}
.meta-dot {
margin: 0 8rpx;
}
.detail-cover {
width: 100%;
border-radius: 16rpx;
display: block;
}
.detail-body {
padding: 24rpx 30rpx;
background: #fff;
min-height: 200rpx;
font-size: 30rpx;
line-height: 1.6;
color: #333;
}
.loading-wrap,
.error-wrap {
padding: 80rpx 30rpx;
text-align: center;
color: #999;
font-size: 28rpx;
}
.error-wrap {
color: #f56c6c;
}
</style>