<!-- 顶部状态栏 -->
This commit is contained in:
491
src/pagesInsurance/claim-review/detail.vue
Normal file
491
src/pagesInsurance/claim-review/detail.vue
Normal file
@@ -0,0 +1,491 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ClaimApplication } from '@/api/types/insurance'
|
||||
import { getClaimApplicationDetail, reviewClaimApplication } from '@/api/insurance'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '理赔审核详情',
|
||||
},
|
||||
})
|
||||
|
||||
const claimId = ref('')
|
||||
const claim = ref<ClaimApplication | null>(null)
|
||||
const loading = ref(false)
|
||||
const reviewing = ref(false)
|
||||
const rejectionReason = ref('')
|
||||
const payoutAmount = ref('')
|
||||
|
||||
// 状态映射
|
||||
const statusMap: Record<string, { text: string, color: string }> = {
|
||||
pending: { text: '待审核', color: '#F59E0B' },
|
||||
approved: { text: '已通过', color: '#00c05a' },
|
||||
rejected: { text: '已拒绝', color: '#fa4350' },
|
||||
}
|
||||
|
||||
const statusInfo = computed(() => {
|
||||
if (!claim.value)
|
||||
return null
|
||||
return statusMap[claim.value.status] || { text: claim.value.status, color: '#666' }
|
||||
})
|
||||
|
||||
async function loadDetail() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getClaimApplicationDetail(claimId.value)
|
||||
claim.value = res
|
||||
if (res.payoutAmount) {
|
||||
payoutAmount.value = res.payoutAmount.toString()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 预览图片
|
||||
function handlePreviewImage(url: string) {
|
||||
uni.previewImage({
|
||||
urls: [url],
|
||||
})
|
||||
}
|
||||
|
||||
// 理赔审核通过
|
||||
async function handleApprove() {
|
||||
if (!payoutAmount.value || Number(payoutAmount.value) <= 0) {
|
||||
uni.showToast({ title: '请输入赔付金额', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
reviewing.value = true
|
||||
try {
|
||||
await reviewClaimApplication(claimId.value, {
|
||||
approved: true,
|
||||
payoutAmount: Number(payoutAmount.value),
|
||||
})
|
||||
uni.showToast({ title: '审核通过', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
finally {
|
||||
reviewing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 理赔审核拒绝
|
||||
async function handleReject() {
|
||||
if (!rejectionReason.value) {
|
||||
uni.showToast({ title: '请填写拒绝原因', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
reviewing.value = true
|
||||
try {
|
||||
await reviewClaimApplication(claimId.value, {
|
||||
approved: false,
|
||||
rejectionReason: rejectionReason.value,
|
||||
})
|
||||
uni.showToast({ title: '已拒绝', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
finally {
|
||||
reviewing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
if (options?.id) {
|
||||
claimId.value = options.id
|
||||
loadDetail()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="claim-review-detail-page">
|
||||
<view v-if="loading" class="loading-state">
|
||||
加载中...
|
||||
</view>
|
||||
|
||||
<template v-else-if="claim">
|
||||
<!-- 状态卡片 -->
|
||||
<view class="status-card" :style="{ background: statusInfo?.color }">
|
||||
<text class="status-text">{{ statusInfo?.text }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 银行信息 -->
|
||||
<view class="section-card">
|
||||
<view class="card-header">
|
||||
银行信息
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="label">银行名称</text>
|
||||
<text class="value">{{ claim.bankName }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">保险单号</text>
|
||||
<text class="value">{{ claim.policyNumber }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 保险公司信息 -->
|
||||
<view class="section-card">
|
||||
<view class="card-header">
|
||||
保险公司信息
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="label">保险公司</text>
|
||||
<text class="value">{{ claim.companyName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 理赔信息 -->
|
||||
<view class="section-card">
|
||||
<view class="card-header">
|
||||
理赔信息
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="label">理赔金额</text>
|
||||
<text class="value amount">{{ claim.claimAmount }}元</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">理赔原因</text>
|
||||
<text class="value reason">{{ claim.claimReason }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">提交时间</text>
|
||||
<text class="value">{{ claim.submittedAt }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 理赔材料 -->
|
||||
<view class="section-card">
|
||||
<view class="card-header">
|
||||
理赔材料
|
||||
</view>
|
||||
<view class="materials-list">
|
||||
<view
|
||||
v-for="material in claim.materials"
|
||||
:key="material.id"
|
||||
class="material-item"
|
||||
@click="handlePreviewImage(material.url)"
|
||||
>
|
||||
<image :src="material.url" mode="aspectFill" />
|
||||
<view class="material-info">
|
||||
<text class="material-name">{{ material.name }}</text>
|
||||
<text class="upload-time">{{ material.uploadTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 审核操作 -->
|
||||
<view v-if="claim.status === 'pending'" class="action-card">
|
||||
<view class="card-header">
|
||||
理赔审核
|
||||
</view>
|
||||
<view class="action-buttons">
|
||||
<button
|
||||
class="btn approve"
|
||||
:disabled="reviewing"
|
||||
@click="handleApprove"
|
||||
>
|
||||
<text v-if="reviewing">处理中...</text>
|
||||
<text v-else>通过</text>
|
||||
</button>
|
||||
<button
|
||||
class="btn reject"
|
||||
:disabled="reviewing"
|
||||
@click="handleReject"
|
||||
>
|
||||
<text v-if="reviewing">处理中...</text>
|
||||
<text v-else>拒绝</text>
|
||||
</button>
|
||||
</view>
|
||||
<view class="payout-input">
|
||||
<text class="label">赔付金额(元)</text>
|
||||
<input
|
||||
v-model="payoutAmount"
|
||||
type="digit"
|
||||
class="input"
|
||||
placeholder="请输入赔付金额"
|
||||
>
|
||||
</view>
|
||||
<view v-if="!reviewing" class="reject-reason">
|
||||
<textarea
|
||||
v-model="rejectionReason"
|
||||
class="textarea"
|
||||
placeholder="请输入拒绝原因..."
|
||||
:maxlength="500"
|
||||
/>
|
||||
<text class="char-count">{{ rejectionReason.length }}/500</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已审核信息 -->
|
||||
<view v-if="claim.status !== 'pending'" class="section-card">
|
||||
<view class="card-header">
|
||||
审核信息
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="label">审核时间</text>
|
||||
<text class="value">{{ claim.reviewedAt }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="label">审核人员</text>
|
||||
<text class="value">{{ claim.reviewedBy }}</text>
|
||||
</view>
|
||||
<view v-if="claim.payoutAmount" class="info-item">
|
||||
<text class="label">赔付金额</text>
|
||||
<text class="value payout">{{ claim.payoutAmount }}元</text>
|
||||
</view>
|
||||
<view v-if="claim.payoutDate" class="info-item">
|
||||
<text class="label">赔付日期</text>
|
||||
<text class="value">{{ claim.payoutDate }}</text>
|
||||
</view>
|
||||
<view v-if="claim.rejectionReason" class="info-item full">
|
||||
<text class="label">拒绝原因</text>
|
||||
<text class="value reason">{{ claim.rejectionReason }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.claim-review-detail-page {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fa;
|
||||
padding: 20rpx;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.loading-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 0;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.status-card {
|
||||
background: linear-gradient(135deg, #00c05a 0%, #34d19d 100%);
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
text-align: center;
|
||||
|
||||
.status-text {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.section-card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.card-header {
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.info-list {
|
||||
padding: 20rpx 0;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 0;
|
||||
font-size: 26rpx;
|
||||
border-bottom: 1rpx solid #f9f9f9;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
text-align: right;
|
||||
|
||||
&.amount {
|
||||
color: #ff8f0d;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.reason {
|
||||
text-align: left;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
&.payout {
|
||||
color: #00c05a;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&.full {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.value {
|
||||
margin-top: 8rpx;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.materials-list {
|
||||
padding: 20rpx 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16rpx;
|
||||
|
||||
.material-item {
|
||||
position: relative;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
background: #f8f9fa;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 200rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.material-info {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
padding: 12rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rpx;
|
||||
|
||||
.material-name {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.upload-time {
|
||||
font-size: 20rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.card-header {
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.btn {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
|
||||
&.approve {
|
||||
background: #00c05a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.reject {
|
||||
background: #fa4350;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.payout-input {
|
||||
padding: 0 0 20rpx 0;
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
padding: 16rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.reject-reason {
|
||||
padding: 0 0 20rpx 0;
|
||||
|
||||
.textarea {
|
||||
width: 100%;
|
||||
min-height: 150rpx;
|
||||
padding: 16rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
text-align: right;
|
||||
margin-top: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user