Просмотр исходного кода

feat(frontend): 文章详情mp-html富文本渲染 + 列表摘要去HTML标签

- article-detail 改用 mp-html 渲染富文本内容(图片相对路径走 API_BASE_URL)
- mind-detail/mind-extra 列表摘要 stripHtml 清理,避免富文本标签直接展示

Ultraworked with [Sisyphus](https://github.com/OhMyOpenCode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
E2E Test Bot 1 месяц назад
Родитель
Сommit
2b982d4ed3

+ 3 - 2
cfc-frontend/pages/article-center/article-detail.vue

@@ -32,7 +32,7 @@
           </view>
           </view>
         </view>
         </view>
         <view class="divider"></view>
         <view class="divider"></view>
-        <view class="detail-body"><rich-text :nodes="article.content"></rich-text></view>
+        <view class="detail-body"><mp-html :content="article.content" :domain="config.API_BASE_URL" /></view>
 
 
         <!-- 评论区(已屏蔽) -->
         <!-- 评论区(已屏蔽) -->
         <view style="height: 200rpx;"></view>
         <view style="height: 200rpx;"></view>
@@ -82,11 +82,12 @@
 import { getArticleDetail, reportReadingTime, getShareQrCode, completeArticleRead, generateQuiz, submitQuiz, getMyMembership } from '@/utils/api.js'
 import { getArticleDetail, reportReadingTime, getShareQrCode, completeArticleRead, generateQuiz, submitQuiz, getMyMembership } from '@/utils/api.js'
 import shareMixin from '../../components/share-mixin.js'
 import shareMixin from '../../components/share-mixin.js'
 import ContentSharePoster from '@/components/ContentSharePoster.vue'
 import ContentSharePoster from '@/components/ContentSharePoster.vue'
+import MpHtml from '@/components/mp-html/mp-html.vue'
 import config from '@/config.js'
 import config from '@/config.js'
 
 
 export default {
 export default {
   mixins: [shareMixin],
   mixins: [shareMixin],
-  components: { ContentSharePoster },
+  components: { ContentSharePoster, MpHtml },
   data() {
   data() {
     return {
     return {
       articleId: '', article: null, loading: true, error: false, errorMsg: '',
       articleId: '', article: null, loading: true, error: false, errorMsg: '',

+ 17 - 3
cfc-frontend/pages/mind-detail/articles.vue

@@ -68,7 +68,7 @@
               </view>
               </view>
             </view>
             </view>
             <text class="article-title">{{ item.title }}</text>
             <text class="article-title">{{ item.title }}</text>
-            <text class="article-summary">{{ item.summary || item.content }}</text>
+            <text class="article-summary" v-if="item.summary">{{ item.summary }}</text>
             <view class="article-footer">
             <view class="article-footer">
               <text class="article-author">{{ item.author || '浠艾福' }}</text>
               <text class="article-author">{{ item.author || '浠艾福' }}</text>
               <text class="article-read-count">阅读 {{ item.readCount || 0 }}</text>
               <text class="article-read-count">阅读 {{ item.readCount || 0 }}</text>
@@ -190,6 +190,7 @@ export default {
     async loadArticles() {
     async loadArticles() {
       if (this.loading) return
       if (this.loading) return
       this.loading = true
       this.loading = true
+      var self = this
       try {
       try {
         var params = { page: this.page, size: this.size }
         var params = { page: this.page, size: this.size }
         if (this.currentCategory) {
         if (this.currentCategory) {
@@ -206,8 +207,7 @@ export default {
             return {
             return {
               id: item.id,
               id: item.id,
               title: item.title || '',
               title: item.title || '',
-              summary: item.summary || '',
-              content: item.content || '',
+              summary: self.stripHtml(item.summary || item.content),
               coverImage: item.coverImage || '',
               coverImage: item.coverImage || '',
               author: item.author || '浠艾福',
               author: item.author || '浠艾福',
               categoryName: item.categoryName || item.category || '',
               categoryName: item.categoryName || item.category || '',
@@ -243,6 +243,20 @@ export default {
     goDetail(id) {
     goDetail(id) {
       uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
       uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
     },
     },
+    stripHtml: function(html) {
+      if (!html) return ''
+      return html
+        .replace(/<style[\s\S]*?<\/style>/gi, ' ')
+        .replace(/<script[\s\S]*?<\/script>/gi, ' ')
+        .replace(/<[^>]+>/g, ' ')
+        .replace(/&nbsp;/gi, ' ')
+        .replace(/&lt;/gi, '<')
+        .replace(/&gt;/gi, '>')
+        .replace(/&amp;/gi, '&')
+        .replace(/&quot;/gi, '"')
+        .replace(/\s+/g, ' ')
+        .trim()
+    },
     getImageUrl: function(path) {
     getImageUrl: function(path) {
       return config.API_BASE_URL + path
       return config.API_BASE_URL + path
     }
     }

+ 17 - 3
cfc-frontend/pages/mind-extra/articles.vue

@@ -96,7 +96,7 @@
                 </view>
                 </view>
               </view>
               </view>
               <text class="article-title">{{ item.title }}</text>
               <text class="article-title">{{ item.title }}</text>
-              <text class="article-summary">{{ item.summary || item.content }}</text>
+              <text class="article-summary" v-if="item.summary">{{ item.summary }}</text>
               <view class="article-footer">
               <view class="article-footer">
                 <text class="article-author">{{ item.author || '浠艾福' }}</text>
                 <text class="article-author">{{ item.author || '浠艾福' }}</text>
                 <text class="article-read-count">阅读 {{ item.readCount || 0 }}</text>
                 <text class="article-read-count">阅读 {{ item.readCount || 0 }}</text>
@@ -255,6 +255,7 @@ export default {
     async loadArticles() {
     async loadArticles() {
       if (this.loading) return
       if (this.loading) return
       this.loading = true
       this.loading = true
+      var self = this
       try {
       try {
         var params = { page: this.page, size: this.size }
         var params = { page: this.page, size: this.size }
         if (this.currentCategory) {
         if (this.currentCategory) {
@@ -274,8 +275,7 @@ export default {
             return {
             return {
               id: item.id,
               id: item.id,
               title: item.title || '',
               title: item.title || '',
-              summary: item.summary || '',
-              content: item.content || '',
+              summary: self.stripHtml(item.summary || item.content),
               coverImage: item.coverImage || '',
               coverImage: item.coverImage || '',
               author: item.author || '浠艾福',
               author: item.author || '浠艾福',
               categoryName: item.categoryName || item.category || '',
               categoryName: item.categoryName || item.category || '',
@@ -311,6 +311,20 @@ export default {
     goDetail(id) {
     goDetail(id) {
       uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
       uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
     },
     },
+    stripHtml: function(html) {
+      if (!html) return ''
+      return html
+        .replace(/<style[\s\S]*?<\/style>/gi, ' ')
+        .replace(/<script[\s\S]*?<\/script>/gi, ' ')
+        .replace(/<[^>]+>/g, ' ')
+        .replace(/&nbsp;/gi, ' ')
+        .replace(/&lt;/gi, '<')
+        .replace(/&gt;/gi, '>')
+        .replace(/&amp;/gi, '&')
+        .replace(/&quot;/gi, '"')
+        .replace(/\s+/g, ' ')
+        .trim()
+    },
     goCreate() {
     goCreate() {
       if (this.isLoggedIn) {
       if (this.isLoggedIn) {
         uni.navigateTo({ url: '/pages/article-center/article-edit' })
         uni.navigateTo({ url: '/pages/article-center/article-edit' })