去掉协会 WebView 和魔方账密页,微信登录与咨询接口共用同一 token 和拦截器。 Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
3.2 KiB
Vue
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>
|