Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

125 linhas
4.6 KiB

  1. <template>
  2. <div class="min-h-screen bg-[var(--c-f3f7fb)]">
  3. <AppHero :kicker="kicker" :title="title" :desc="updatedText" />
  4. <main class="mx-auto max-w-4xl px-4 py-7 sm:px-6 lg:py-10">
  5. <article class="rounded-3xl border border-[var(--c-e7eef7)] bg-[var(--c-ffffff)] p-6 shadow-[0_16px_40px_var(--sh-34-68-112-60)] lg:p-10">
  6. <!-- 正文由后台维护,服务端渲染,内容缺失时给明确空态而不是白屏 -->
  7. <div v-if="content" class="legal-body" v-html="content" />
  8. <div v-else class="py-16 text-center">
  9. <UIcon name="i-lucide-file-text" class="mx-auto mb-4 size-10 text-[var(--c-a0aabb)]" />
  10. <div class="text-base font-extrabold text-[var(--c-172033)]">内容暂未发布</div>
  11. <p class="mx-auto mt-2 max-w-md text-sm leading-6 text-[var(--c-8a97a8)]">
  12. 该内容正在整理中,如需了解详情可通过页脚的联系方式与我们沟通。
  13. </p>
  14. <NuxtLink
  15. to="/"
  16. class="mt-6 inline-flex h-10 cursor-pointer items-center rounded-full bg-[var(--c-eef7ff)] px-6 text-sm font-bold text-[var(--c-0b8cff)] transition-colors hover:bg-[var(--c-e0f0ff)]"
  17. >
  18. 返回首页
  19. </NuxtLink>
  20. </div>
  21. </article>
  22. </main>
  23. </div>
  24. </template>
  25. <script setup>
  26. import dayjs from 'dayjs'
  27. import { cleanRichText } from '~/utils/richtext'
  28. const props = defineProps({
  29. /** html 表里的 key:service / privacy */
  30. docKey: { type: String, required: true },
  31. fallbackTitle: { type: String, default: '' },
  32. kicker: { type: String, default: 'LEGAL' },
  33. })
  34. const { post } = useApi()
  35. /*
  36. SSR 取正文:协议页要能被搜索引擎抓到。
  37. 清洗放在 transform 里,这样 Nuxt payload 里只带清洗后的正文——
  38. 否则原始 Word 正文(3 万多字、带满内联样式)会被序列化进页面,白白多传一份。
  39. */
  40. const { data } = await useAsyncData(
  41. () => `legal-${props.docKey}`,
  42. () => post('/common/gethtml', { key: props.docKey }).catch(() => ({ data: {} })),
  43. {
  44. transform: (res) => {
  45. const doc = res?.data || {}
  46. return {
  47. title: doc.title || '',
  48. content: cleanRichText(doc.content || ''),
  49. update_time: doc.update_time || '',
  50. }
  51. },
  52. },
  53. )
  54. const title = computed(() => data.value?.title || props.fallbackTitle)
  55. const content = computed(() => data.value?.content || '')
  56. const updatedText = computed(() => {
  57. const time = data.value?.update_time
  58. if (!time) return ''
  59. return `最近更新:${dayjs(time).format('YYYY-MM-DD')}`
  60. })
  61. </script>
  62. <style scoped>
  63. /*
  64. 正文来自后台富文本,用 :deep 统一排版;
  65. 颜色走主题变量,暗色模式下同样可读。
  66. */
  67. .legal-body {
  68. color: var(--c-4b5b70);
  69. font-size: 15px;
  70. line-height: 1.85;
  71. word-break: break-word;
  72. }
  73. .legal-body :deep(h1),
  74. .legal-body :deep(h2),
  75. .legal-body :deep(h3),
  76. .legal-body :deep(h4) {
  77. margin: 1.6em 0 0.7em;
  78. color: var(--c-172033);
  79. font-weight: 800;
  80. line-height: 1.4;
  81. }
  82. .legal-body :deep(h1) { font-size: 22px; }
  83. .legal-body :deep(h2) { font-size: 19px; }
  84. .legal-body :deep(h3) { font-size: 17px; }
  85. .legal-body :deep(h4) { font-size: 15px; }
  86. /* Word 导出的正文里 p / div / span 用得很随意,这里统一接管排版 */
  87. .legal-body :deep(p) { margin: 0 0 0.9em; padding: 0; }
  88. .legal-body :deep(p:last-child) { margin-bottom: 0; }
  89. .legal-body :deep(div) { line-height: 1.85; }
  90. .legal-body :deep(span) { font-size: inherit; line-height: inherit; color: inherit; }
  91. .legal-body :deep(strong),
  92. .legal-body :deep(b) { color: var(--c-172033); font-weight: 700; }
  93. /* Tailwind preflight 会清掉列表符号与缩进,这里补回来 */
  94. .legal-body :deep(ul),
  95. .legal-body :deep(ol) { margin: 0.9em 0; padding-left: 1.6em; }
  96. .legal-body :deep(ul) { list-style: disc outside; }
  97. .legal-body :deep(ol) { list-style: decimal outside; }
  98. .legal-body :deep(ul ul) { list-style: circle outside; }
  99. .legal-body :deep(li) { margin: 0.35em 0; padding: 0; line-height: 1.8; }
  100. .legal-body :deep(li > p) { margin: 0; }
  101. .legal-body :deep(a) { color: var(--c-0b8cff); text-decoration: underline; }
  102. .legal-body :deep(img) { max-width: 100%; height: auto; border-radius: 12px; }
  103. .legal-body :deep(table) {
  104. width: 100%;
  105. margin: 1.2em 0;
  106. border-collapse: collapse;
  107. font-size: 14px;
  108. }
  109. .legal-body :deep(th),
  110. .legal-body :deep(td) {
  111. padding: 8px 10px;
  112. border: 1px solid var(--c-e7eef7);
  113. text-align: left;
  114. }
  115. .legal-body :deep(th) { background: var(--c-f7f9fd); color: var(--c-172033); font-weight: 700; }
  116. .legal-body :deep(hr) { margin: 1.6em 0; border: 0; border-top: 1px solid var(--c-eef2f7); }
  117. </style>