25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

131 satır
4.4 KiB

  1. <template>
  2. <view class="agreement-page">
  3. <!-- 加载中:协议正文有 3 万多字,等待期间给骨架反馈 -->
  4. <view v-if="loading" class="skeleton">
  5. <view v-for="i in 8" :key="i" class="skeleton-line" :class="{ short: i % 4 === 0 }"></view>
  6. </view>
  7. <!-- 富文本正文:统一用 uview-plus 的 up-parse 渲染,各端表现一致 -->
  8. <up-parse v-else-if="content" :content="content" :tag-style="tagStyle" selectable />
  9. <!-- 空态 / 失败态:内容缺失时不能是白屏 -->
  10. <view v-else class="empty">
  11. <text class="empty-title">{{ errorMsg ? '内容加载失败' : '内容暂未发布' }}</text>
  12. <text class="empty-desc">{{ errorMsg || '该内容正在整理中,可稍后再来查看。' }}</text>
  13. <view class="empty-btn" @click="loadHtml">重新加载</view>
  14. </view>
  15. </view>
  16. </template>
  17. <script setup>
  18. import { computed, ref } from 'vue'
  19. import { onLoad } from '@dcloudio/uni-app'
  20. import { commonApi } from '@/api/index.js'
  21. import { cleanRichText } from '@/utils/richtext.js'
  22. /**
  23. * 富文本标签样式重置。
  24. * 后台正文是 Word 导出的,标签用得很随意(p 套 span、ul 无 li 缩进、字号写死 14px),
  25. * 这里统一接管排版:正文 28rpx / 行高 1.8,段间距用 margin 而不是空段落。
  26. */
  27. const tagStyle = {
  28. p: 'margin: 0 0 20rpx; padding: 0; line-height: 1.8; font-size: 28rpx; color: #172033; word-break: break-word;',
  29. div: 'line-height: 1.8; font-size: 28rpx; color: #172033; word-break: break-word;',
  30. span: 'font-size: 28rpx; line-height: 1.8; color: #172033;',
  31. h1: 'margin: 34rpx 0 16rpx; padding: 0; font-size: 34rpx; font-weight: 700; line-height: 1.45; color: #172033;',
  32. h2: 'margin: 30rpx 0 14rpx; padding: 0; font-size: 32rpx; font-weight: 700; line-height: 1.45; color: #172033;',
  33. h3: 'margin: 28rpx 0 12rpx; padding: 0; font-size: 30rpx; font-weight: 700; line-height: 1.45; color: #172033;',
  34. h4: 'margin: 26rpx 0 12rpx; padding: 0; font-size: 29rpx; font-weight: 700; line-height: 1.45; color: #172033;',
  35. ul: 'margin: 16rpx 0; padding-left: 44rpx; list-style: disc;',
  36. ol: 'margin: 16rpx 0; padding-left: 44rpx; list-style: decimal;',
  37. li: 'margin: 0 0 10rpx; line-height: 1.8; font-size: 28rpx; color: #172033;',
  38. strong: 'font-weight: 700; color: #172033;',
  39. b: 'font-weight: 700; color: #172033;',
  40. a: 'color: #1f8cff; word-break: break-all;',
  41. br: 'line-height: 1.8;',
  42. hr: 'margin: 28rpx 0; border: none; border-top: 1rpx solid #eef2f7;',
  43. img: 'max-width: 100%; height: auto; border-radius: 12rpx;',
  44. table: 'width: 100%; margin: 20rpx 0; border-collapse: collapse; font-size: 26rpx;',
  45. td: 'padding: 12rpx; border: 1rpx solid #e6ebf2; line-height: 1.6;',
  46. th: 'padding: 12rpx; border: 1rpx solid #e6ebf2; background: #f7f9fd; font-weight: 700; line-height: 1.6;'
  47. }
  48. const detail = ref({})
  49. const loading = ref(true)
  50. const errorMsg = ref('')
  51. let configKey = ''
  52. // 清洗后的正文:去空段落、剥内联字体与颜色,排版交给上面的 tagStyle
  53. const content = computed(() => cleanRichText(detail.value.content))
  54. onLoad((options) => {
  55. configKey = (options && options.key) || ''
  56. loadHtml()
  57. })
  58. async function loadHtml() {
  59. if (!configKey) {
  60. loading.value = false
  61. errorMsg.value = '缺少内容标识'
  62. return
  63. }
  64. loading.value = true
  65. errorMsg.value = ''
  66. try {
  67. const res = await commonApi.getHtml({ key: configKey })
  68. detail.value = res.data || {}
  69. if (detail.value.title) {
  70. uni.setNavigationBarTitle({ title: detail.value.title })
  71. }
  72. } catch (e) {
  73. errorMsg.value = (e && e.msg) || '网络异常,请稍后重试'
  74. } finally {
  75. loading.value = false
  76. }
  77. }
  78. </script>
  79. <style lang="scss" scoped>
  80. .agreement-page {
  81. min-height: 100vh;
  82. padding: 30rpx 30rpx 60rpx;
  83. background: #ffffff;
  84. box-sizing: border-box;
  85. }
  86. .skeleton-line {
  87. height: 30rpx;
  88. margin-bottom: 22rpx;
  89. border-radius: 8rpx;
  90. background: #f1f5fa;
  91. &.short { width: 60%; }
  92. }
  93. .empty {
  94. padding: 160rpx 40rpx;
  95. display: flex;
  96. flex-direction: column;
  97. align-items: center;
  98. text-align: center;
  99. }
  100. .empty-title { color: $ai-text; font-size: 32rpx; font-weight: 700; }
  101. .empty-desc {
  102. margin-top: 14rpx;
  103. color: $ai-muted;
  104. font-size: 26rpx;
  105. line-height: 1.6;
  106. }
  107. .empty-btn {
  108. margin-top: 30rpx;
  109. width: 240rpx;
  110. height: 76rpx;
  111. border-radius: 999rpx;
  112. color: #1f8cff;
  113. background: #eef7ff;
  114. font-size: 27rpx;
  115. font-weight: 700;
  116. line-height: 76rpx;
  117. }
  118. </style>