Files
danyang-match/h5-demo/src/pages/content/AntiFraudPage.vue
T
WorkBuddy 69ebf33e18
CI/CD Pipeline / Backend Build & Test (push) Canceled after 0s
CI/CD Pipeline / Admin Web Build (push) Canceled after 0s
CI/CD Pipeline / Mini Program Compile Check (push) Canceled after 0s
CI/CD Pipeline / Migration Validation (push) Canceled after 0s
CI/CD Pipeline / Test Shell Guard (Phase 23 Gate) (push) Canceled after 0s
CI/CD Pipeline / UI Contracts (source-structure gates) (push) Canceled after 0s
CI/CD Pipeline / E2E (live stack) (push) Canceled after 0s
release: freeze demo v1.1.0 2026-10-19
2026-10-19 20:36:22 +08:00

296 lines
8.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<PageLayout title="婚恋反诈">
<div class="fraud">
<div class="fraud__hero">
<div class="fraud__eyebrow">提高警惕 · 守护真心</div>
<div class="fraud__title">婚恋反诈</div>
<div class="fraud__desc">识别风险信号,守护你的真心与财产安全</div>
</div>
<div class="fraud__body">
<UiErrorState v-if="error" message="暂时无法加载反诈内容" @retry="load" />
<UiLoading v-else-if="loading" />
<template v-else>
<UiSectionHeader title="常见风险信号" />
<div class="fraud__grid">
<div v-for="r in RISKS" :key="r.title" class="fraud__risk">
<div class="fraud__risk-icon">!</div>
<div class="fraud__risk-title">{{ r.title }}</div>
<div class="fraud__risk-desc">{{ r.description }}</div>
</div>
</div>
<UiSectionHeader title="遇到可疑情况怎么办" />
<div class="fraud__card">
<div v-for="(s, i) in STEPS" :key="s.title" class="fraud__step">
<div class="fraud__step-index">{{ i + 1 }}</div>
<div class="fraud__step-copy">
<div class="fraud__step-title">{{ s.title }}</div>
<div class="fraud__step-desc">{{ s.description }}</div>
</div>
</div>
</div>
<template v-if="articles.length">
<UiSectionHeader title="反诈科普内容" />
<div
v-for="a in articles"
:key="a.id"
class="fraud__article"
@click="router.push({ path: '/content/detail', query: { id: a.id } })"
>
<div class="fraud__article-cover">{{ (a.title || '反').slice(0, 1) }}</div>
<div class="fraud__article-info">
<div class="fraud__article-title">{{ a.title }}</div>
<div v-if="a.summary" class="fraud__article-summary">{{ a.summary }}</div>
</div>
<van-icon name="arrow" color="#9aa0b5" />
</div>
</template>
</template>
</div>
<div class="fraud__action">
<van-button class="fraud__action-btn" plain @click="requestHelp">安全求助</van-button>
<van-button class="fraud__action-btn" type="primary" @click="report">举报可疑行为</van-button>
</div>
</div>
</PageLayout>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { showConfirmDialog } from 'vant'
import { contentService } from '@/api/services'
import { useAppStore } from '@/stores/app'
import PageLayout from '@/layouts/PageLayout.vue'
import UiLoading from '@/components/UiLoading.vue'
import UiErrorState from '@/components/UiErrorState.vue'
import UiSectionHeader from '@/components/UiSectionHeader.vue'
const router = useRouter()
const appStore = useAppStore()
const RISKS = [
{ title: '投资博彩诱导', description: '刚认识便引导投资、博彩或下载陌生应用' },
{ title: '借款资金周转', description: '以生病、工程或临时周转为由反复借款' },
{ title: '索取隐私资料', description: '催促脱离平台并索要验证码、银行卡或证件信息' },
{ title: '冒充平台人员', description: '以认证、保证金或解冻账户为由要求转账' },
]
const STEPS = [
{ title: '立即停止资金操作', description: '不要继续转账、充值或提供验证码' },
{ title: '保存相关证据', description: '保留聊天、付款和对方账号信息' },
{ title: '及时举报或报警', description: '平台举报不会通知被举报人,紧急情况请拨打 110' },
]
const loading = ref(true)
const error = ref(false)
const articles = ref<any[]>([])
async function load() {
loading.value = true
error.value = false
try {
// 反诈栏目的内容按分类 code(anti_fraud)取,避免客户端硬编码分类 id
const catResult: any = await contentService.getCategories()
const categories: any[] = catResult?.items || catResult?.records || (Array.isArray(catResult) ? catResult : [])
const antiFraud = categories.find((c) => c.code === 'anti_fraud')
if (!antiFraud?.id) {
articles.value = []
return
}
const result: any = await contentService.getArticles({ categoryId: antiFraud.id })
articles.value = result?.items || result?.records || (Array.isArray(result) ? result : [])
} catch {
error.value = true
} finally {
loading.value = false
}
}
function report() {
router.push({ path: '/report', query: { type: 'fraud' } })
}
async function requestHelp() {
try {
await showConfirmDialog({
title: '安全求助',
message: '如有财产损失或人身危险,请立即拨打 110;非紧急问题可前往平台帮助中心。',
confirmButtonText: '拨打 110',
cancelButtonText: '帮助中心',
})
window.location.href = 'tel:110'
} catch {
router.push('/help')
}
}
onMounted(load)
</script>
<style scoped>
.fraud {
min-height: 100vh;
background: var(--mini-bg);
padding-bottom: 76px;
}
.fraud__hero {
background: var(--mini-brand-gradient);
color: #fff;
padding: 18px 16px 20px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.fraud__eyebrow {
font-size: 11px;
opacity: 0.8;
}
.fraud__title {
font-size: 19px;
font-weight: 600;
margin-top: 4px;
}
.fraud__desc {
font-size: 12px;
opacity: 0.85;
margin-top: 6px;
}
.fraud__body {
padding: 0 16px;
}
.fraud__grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.fraud__risk {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
padding: 14px;
}
.fraud__risk-icon {
width: 26px;
height: 26px;
border-radius: 8px;
background: var(--mini-danger);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 15px;
font-weight: 700;
}
.fraud__risk-title {
font-size: 14px;
font-weight: 600;
color: var(--mini-text-strong);
margin-top: 8px;
}
.fraud__risk-desc {
font-size: 12px;
color: var(--mini-text-secondary);
line-height: 1.5;
margin-top: 4px;
}
.fraud__card {
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
padding: 4px 14px;
}
.fraud__step {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 14px 0;
border-bottom: 1px solid var(--mini-border);
}
.fraud__step:last-child {
border-bottom: none;
}
.fraud__step-index {
width: 24px;
height: 24px;
border-radius: 50%;
background: rgba(47, 179, 109, 0.14);
color: var(--mini-success);
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 600;
flex: none;
}
.fraud__step-title {
font-size: 14px;
font-weight: 600;
color: var(--mini-text-strong);
}
.fraud__step-desc {
font-size: 12px;
color: var(--mini-text-secondary);
line-height: 1.5;
margin-top: 2px;
}
.fraud__article {
display: flex;
align-items: center;
gap: 12px;
background: var(--mini-surface);
border-radius: var(--mini-radius);
box-shadow: var(--mini-shadow);
padding: 12px;
margin-bottom: 10px;
}
.fraud__article-cover {
width: 46px;
height: 46px;
border-radius: 11px;
background: linear-gradient(135deg, #3fc98a 0%, #199e64 100%);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 600;
flex: none;
}
.fraud__article-info {
flex: 1;
min-width: 0;
}
.fraud__article-title {
font-size: 14px;
font-weight: 600;
color: var(--mini-text-strong);
}
.fraud__article-summary {
font-size: 12px;
color: var(--mini-text-secondary);
margin-top: 4px;
line-height: 1.5;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.fraud__action {
position: fixed;
left: 0;
right: 0;
bottom: 0;
display: flex;
gap: 10px;
padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
background: var(--mini-surface);
box-shadow: 0 -4px 16px rgba(23, 42, 114, 0.08);
}
.fraud__action-btn {
flex: 1;
border-radius: var(--mini-radius);
}
</style>