Add admin-frontend and user-frontend standalone projects, certification/invoice/discovery features, fix auth header and theme consistency
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header-card">
|
||||
<text class="title">实名认证</text>
|
||||
<text class="subtitle">认证后可申请发票</text>
|
||||
</view>
|
||||
|
||||
<view v-if="loading.status" class="loading-wrap">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view v-else-if="cert" class="section">
|
||||
<view class="status-bar" :class="cert.status">
|
||||
<text class="status-icon">{{ statusIcon }}</text>
|
||||
<text class="status-text">{{ statusText }}</text>
|
||||
<text v-if="cert.reject_reason" class="reject-reason">原因:{{ cert.reject_reason }}</text>
|
||||
</view>
|
||||
<view class="info-card">
|
||||
<view class="info-row">
|
||||
<text class="info-label">认证类型</text>
|
||||
<text class="info-value">{{ cert.cert_type === 'individual' ? '个人认证' : '企业认证' }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="cert.personal_name">
|
||||
<text class="info-label">姓名</text>
|
||||
<text class="info-value">{{ cert.personal_name }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="cert.company_name">
|
||||
<text class="info-label">企业名称</text>
|
||||
<text class="info-value">{{ cert.company_name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="cert.status === 'rejected'" class="action-bar">
|
||||
<button class="primary-btn" @click="resetForm">重新提交</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="section">
|
||||
<view class="input-group">
|
||||
<text class="input-label">认证类型</text>
|
||||
<view class="type-selector">
|
||||
<text class="type-option" :class="{ active: form.cert_type === 'individual' }" @click="form.cert_type = 'individual'">个人认证</text>
|
||||
<text class="type-option" :class="{ active: form.cert_type === 'enterprise' }" @click="form.cert_type = 'enterprise'">企业认证</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<text class="input-label">姓名</text>
|
||||
<input class="input-field" v-model="form.personal_name" placeholder="输入真实姓名" />
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<text class="input-label">身份证号</text>
|
||||
<input class="input-field" v-model="form.personal_id" placeholder="输入身份证号码" />
|
||||
</view>
|
||||
|
||||
<view v-if="form.cert_type === 'enterprise'" class="enterprise-fields">
|
||||
<view class="input-group">
|
||||
<text class="input-label">企业名称</text>
|
||||
<input class="input-field" v-model="form.company_name" placeholder="输入营业执照上的企业名称" />
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<text class="input-label">统一社会信用代码</text>
|
||||
<input class="input-field" v-model="form.tax_id" placeholder="输入税号" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="notice">
|
||||
<text class="notice-text">提交后预计 1-3 个工作日审核完成</text>
|
||||
</view>
|
||||
|
||||
<button class="primary-btn" :disabled="loading.submit" @click="doSubmit">
|
||||
<text v-if="loading.submit">提交中...</text>
|
||||
<text v-else>提交认证</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { certificationApi } from '@/utils/api.js'
|
||||
|
||||
const loading = reactive({ status: false, submit: false })
|
||||
const cert = ref(null)
|
||||
const form = reactive({
|
||||
cert_type: 'individual',
|
||||
personal_name: '',
|
||||
personal_id: '',
|
||||
company_name: '',
|
||||
tax_id: '',
|
||||
})
|
||||
|
||||
const statusIcon = computed(() => ({ pending: '⏳', approved: '✅', rejected: '❌' })[cert.value?.status] || '')
|
||||
const statusText = computed(() => ({ pending: '审核中', approved: '已认证', rejected: '认证未通过' })[cert.value?.status] || '')
|
||||
|
||||
async function loadStatus() {
|
||||
loading.status = true
|
||||
try {
|
||||
const res = await certificationApi.status()
|
||||
if (res.success && res.data) {
|
||||
cert.value = res.data
|
||||
form.personal_name = res.data.personal_name || ''
|
||||
form.company_name = res.data.company_name || ''
|
||||
}
|
||||
} catch (e) {
|
||||
// not certified yet
|
||||
}
|
||||
loading.status = false
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
cert.value = null
|
||||
form.cert_type = 'individual'
|
||||
form.personal_name = ''
|
||||
form.personal_id = ''
|
||||
form.company_name = ''
|
||||
form.tax_id = ''
|
||||
}
|
||||
|
||||
async function doSubmit() {
|
||||
if (!form.personal_name) { uni.showToast({ title: '请填写姓名', icon: 'none' }); return }
|
||||
if (!form.personal_id) { uni.showToast({ title: '请填写身份证号', icon: 'none' }); return }
|
||||
if (form.cert_type === 'enterprise' && !form.company_name) {
|
||||
uni.showToast({ title: '请填写企业名称', icon: 'none' }); return
|
||||
}
|
||||
loading.submit = true
|
||||
try {
|
||||
const res = await certificationApi.submit(form)
|
||||
if (res.success) {
|
||||
uni.showToast({ title: '提交成功', icon: 'success' })
|
||||
loadStatus()
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: e.message || '提交失败', icon: 'none' })
|
||||
}
|
||||
loading.submit = false
|
||||
}
|
||||
|
||||
onMounted(loadStatus)
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page { background: #f5f5f5; }
|
||||
.page { padding: 16px; }
|
||||
.header-card { background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 12px; padding: 20px; margin-bottom: 16px; }
|
||||
.header-card .title { font-size: 20px; font-weight: 600; color: #fff; display: block; }
|
||||
.header-card .subtitle { font-size: 13px; color: rgba(255,255,255,.8); display: block; margin-top: 4px; }
|
||||
.section { background: #fff; border-radius: 12px; padding: 16px; margin-bottom: 16px; }
|
||||
.loading-wrap { text-align: center; padding: 40px; }
|
||||
.loading-text { color: #999; }
|
||||
.status-bar { text-align: center; padding: 16px; border-radius: 8px; margin-bottom: 16px; }
|
||||
.status-bar.pending { background: #fff7e6; }
|
||||
.status-bar.approved { background: #f6ffed; }
|
||||
.status-bar.rejected { background: #fff2f0; }
|
||||
.status-icon { font-size: 32px; display: block; }
|
||||
.status-text { font-size: 16px; font-weight: 500; display: block; margin-top: 4px; }
|
||||
.reject-reason { font-size: 13px; color: #ff4d4f; display: block; margin-top: 8px; }
|
||||
.info-card { }
|
||||
.info-row { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid #f0f0f0; }
|
||||
.info-label { color: #666; font-size: 14px; }
|
||||
.info-value { color: #333; font-size: 14px; font-weight: 500; }
|
||||
.action-bar { margin-top: 16px; }
|
||||
.input-group { margin-bottom: 16px; }
|
||||
.input-label { font-size: 14px; color: #333; display: block; margin-bottom: 6px; font-weight: 500; }
|
||||
.input-field { width: 100%; height: 44px; border: 1px solid #d9d9d9; border-radius: 8px; padding: 0 12px; font-size: 14px; box-sizing: border-box; }
|
||||
.type-selector { display: flex; gap: 12px; }
|
||||
.type-option { flex: 1; text-align: center; padding: 10px; border: 2px solid #d9d9d9; border-radius: 8px; font-size: 14px; }
|
||||
.type-option.active { border-color: #667eea; color: #667eea; font-weight: 500; }
|
||||
.notice { background: #fffbe6; border: 1px solid #ffe58f; border-radius: 6px; padding: 10px; margin-bottom: 16px; }
|
||||
.notice-text { font-size: 13px; color: #ad8b00; }
|
||||
.primary-btn { width: 100%; height: 44px; background: #667eea; color: #fff; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 16px; border: none; }
|
||||
.primary-btn:disabled { opacity: .6; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user