Files
yuxingu-Miniprogram-dev/pages/yxg/report.vue
T
jackyu66gitandCursor b09d82df8d feat: 小程序统一走 Go 后台,咨询与登录切到 /api/v1
去掉协会 WebView 和魔方账密页,微信登录与咨询接口共用同一 token 和拦截器。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 00:26:28 +08:00

84 lines
3.2 KiB
Vue

<template>
<yxg-page :title="typeLabel(report?.type) || '报告详情'">
<text v-if="loading" class="hint">加载中</text>
<text v-else-if="error" class="err">{{ error }}</text>
<view v-else-if="report" class="card">
<yxg-tool-icon :name="toolIconFor(report.type)" :size="40" />
<text class="h1">{{ headlineOf(report) }}</text>
<text class="meta">{{ formatDate(report.created_at) }}</text>
<text v-if="oneLiner" class="lead">{{ oneLiner }}</text>
<view v-if="keywords.length" class="tags">
<text v-for="k in keywords" :key="k" class="tag">{{ k }}</text>
</view>
<text v-if="bodyText" class="body">{{ bodyText }}</text>
<rich-text v-else-if="html" class="html" :nodes="html" />
<view class="btn" @click="yxgGo('/share', { id: report.id })"><text>分享</text></view>
</view>
</yxg-page>
</template>
<script setup>
import YxgPage from '@/components/yxg/yxg-page.vue'
import YxgToolIcon from '@/components/yxg/yxg-tool-icon.vue'
import { yxgApi } from '@/util/yxgApi.js'
import { ensureAccount } from '@/util/yxgAuth.js'
import { formatDate, headlineOf, toolIconFor, typeLabel } from '@/util/yxgCatalog.js'
import { yxgGo } from '@/util/yxgNav.js'
const id = ref('')
const report = ref(null)
const loading = ref(true)
const error = ref('')
const summary = computed(() => report.value?.summary || {})
const detail = computed(() => report.value?.detail || {})
const oneLiner = computed(() => String(summary.value.one_liner || summary.value.overview || ''))
const keywords = computed(() => (Array.isArray(summary.value.keywords) ? summary.value.keywords : []))
const bodyText = computed(() => {
const d = detail.value || {}
return String(d.body_text || d.narrative || d.content || summary.value.body || '')
})
const html = computed(() => String(detail.value?.html || detail.value?.rich_html || ''))
async function load() {
loading.value = true
error.value = ''
if (!(await ensureAccount(`/reports/${id.value}`))) {
loading.value = false
return
}
try {
report.value = await yxgApi.getReport(id.value)
} catch (e) {
error.value = e instanceof Error ? e.message : '加载失败'
} finally {
loading.value = false
}
}
onLoad((q) => {
id.value = q.id || ''
load()
})
</script>
<style>
page { background-color: #ffd1c7; }
</style>
<style scoped>
.hint, .err { display: block; padding: 16px; font-size: 13px; color: #999; }
.err { color: #e54d42; }
.card { margin: 12px 16px; padding: 18px 16px; background: #fff; border-radius: 18px; }
.h1 { display: block; margin-top: 10px; font-size: 20px; font-weight: 700; color: #333; }
.meta { display: block; margin-top: 4px; font-size: 12px; color: #bbb; }
.lead { display: block; margin-top: 12px; font-size: 14px; color: #555; line-height: 1.6; }
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.tag { padding: 3px 8px; border-radius: 8px; background: #ffe4e4; color: #e54d42; font-size: 11px; }
.body { display: block; margin-top: 14px; font-size: 14px; color: #444; line-height: 1.7; white-space: pre-wrap; }
.html { margin-top: 14px; }
.btn {
margin-top: 16px; height: 42px; border-radius: 999px; background: #e54d42; color: #fff;
display: flex; align-items: center; justify-content: center; font-weight: 700;
}
</style>