ykt-wxapp/pages/message/article-detail.vue

202 lines
4.4 KiB
Vue
Raw Normal View History

2026-01-27 13:42:59 +08:00
<template>
<view class="article-detail-page">
<view v-if="loading" class="loading-container">
<uni-icons type="spinner-cycle" size="40" color="#999" />
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="error" class="error-container">
<text class="error-text">{{ error }}</text>
<button class="retry-btn" @click="loadArticle">重试</button>
</view>
<scroll-view v-else scroll-y class="article-content">
<view class="article-header">
<text class="article-title">{{ articleData.title }}</text>
<text class="article-date">{{ articleData.date }}</text>
</view>
<view class="article-body">
<view class="rich-text-wrapper">
<rich-text :nodes="articleData.content"></rich-text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
2026-01-27 15:07:39 +08:00
import { onLoad } from "@dcloudio/uni-app";
2026-01-28 16:35:14 +08:00
import api from "@/utils/api.js";
2026-01-27 15:07:39 +08:00
import { ref } from "vue";
const env = __VITE_ENV__;
const corpId = env.MP_CORP_ID;
2026-01-27 13:42:59 +08:00
const loading = ref(true);
2026-01-27 15:07:39 +08:00
const error = ref("");
2026-01-27 13:42:59 +08:00
const articleData = ref({
2026-01-27 15:07:39 +08:00
title: "",
content: "",
date: "",
2026-01-27 13:42:59 +08:00
});
2026-01-27 15:07:39 +08:00
let articleId = "";
2026-01-27 13:42:59 +08:00
// 处理富文本内容,使图片自适应
const processRichTextContent = (html) => {
2026-01-27 15:07:39 +08:00
if (!html) return "";
2026-01-27 13:42:59 +08:00
// 给所有 img 标签添加样式
let processedHtml = html.replace(
/<img/gi,
'<img style="max-width:100%;height:auto;display:block;margin:10px 0;"'
);
2026-01-27 15:07:39 +08:00
2026-01-27 13:42:59 +08:00
// 移除可能存在的固定宽度样式
processedHtml = processedHtml.replace(
/style="[^"]*width:\s*\d+px[^"]*"/gi,
(match) => {
2026-01-27 15:07:39 +08:00
return match.replace(/width:\s*\d+px;?/gi, "max-width:100%;");
2026-01-27 13:42:59 +08:00
}
);
2026-01-27 15:07:39 +08:00
2026-01-27 13:42:59 +08:00
// 处理表格,添加自适应样式
processedHtml = processedHtml.replace(
/<table/gi,
'<table style="max-width:100%;overflow-x:auto;display:block;"'
);
2026-01-27 15:07:39 +08:00
2026-01-27 13:42:59 +08:00
// 给整体内容添加容器样式
processedHtml = `<div style="width:100%;overflow-x:hidden;word-wrap:break-word;word-break:break-all;">${processedHtml}</div>`;
2026-01-27 15:07:39 +08:00
2026-01-27 13:42:59 +08:00
return processedHtml;
};
// 加载文章
const loadArticle = async () => {
loading.value = true;
2026-01-27 15:07:39 +08:00
error.value = "";
2026-01-27 13:42:59 +08:00
try {
2026-01-28 16:35:14 +08:00
const res = await api("getArticle", { id: articleId, corpId });
2026-01-27 13:42:59 +08:00
if (res.success && res.data) {
// 格式化日期
2026-01-27 15:07:39 +08:00
let date = "";
2026-01-27 13:42:59 +08:00
if (res.data.createTime) {
const d = new Date(res.data.createTime);
const year = d.getFullYear();
2026-01-27 15:07:39 +08:00
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
2026-01-27 13:42:59 +08:00
date = `${year}-${month}-${day}`;
}
articleData.value = {
2026-01-27 15:07:39 +08:00
title: res.data.title || "宣教文章",
content: processRichTextContent(res.data.content || ""),
date: date,
2026-01-27 13:42:59 +08:00
};
} else {
2026-01-27 15:07:39 +08:00
error.value = res.message || "加载文章失败";
2026-01-27 13:42:59 +08:00
}
} catch (err) {
2026-01-27 15:07:39 +08:00
console.error("加载文章失败:", err);
error.value = "加载失败,请重试";
2026-01-27 13:42:59 +08:00
} finally {
loading.value = false;
}
};
onLoad((options) => {
2026-01-27 15:07:39 +08:00
if (options.id) {
2026-01-27 13:42:59 +08:00
articleId = options.id;
loadArticle();
} else {
2026-01-27 15:07:39 +08:00
error.value = "文章信息不完整";
2026-01-27 13:42:59 +08:00
loading.value = false;
}
});
</script>
<style scoped lang="scss">
.article-detail-page {
width: 100%;
height: 100vh;
background-color: #fff;
}
.loading-container,
.error-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
padding: 40rpx;
}
.loading-text {
margin-top: 20rpx;
font-size: 28rpx;
color: #999;
}
.error-text {
font-size: 28rpx;
color: #999;
margin-bottom: 30rpx;
text-align: center;
}
.retry-btn {
padding: 16rpx 60rpx;
2026-01-27 15:07:39 +08:00
background-color: #0877f1;
2026-01-27 13:42:59 +08:00
color: #fff;
border: none;
border-radius: 8rpx;
font-size: 28rpx;
}
.article-content {
height: 100vh;
}
.article-header {
padding: 40rpx 30rpx 20rpx;
border-bottom: 1px solid #eee;
}
.article-title {
display: block;
font-size: 36rpx;
font-weight: bold;
color: #333;
line-height: 1.6;
margin-bottom: 20rpx;
}
.article-date {
display: block;
font-size: 24rpx;
color: #999;
}
.article-body {
padding: 0;
}
.rich-text-wrapper {
padding: 30rpx;
width: 100%;
box-sizing: border-box;
overflow: hidden;
}
.rich-text-wrapper ::v-deep rich-text {
width: 100%;
}
.rich-text-wrapper ::v-deep rich-text img {
max-width: 100% !important;
height: auto !important;
display: block;
}
</style>