615 lines
17 KiB
Vue
615 lines
17 KiB
Vue
<template>
|
||
<view class="invoice-detail-page">
|
||
<!-- 头部状态卡片 -->
|
||
<view class="header-section">
|
||
<view class="status-card" :class="statusClass">
|
||
<view class="status-icon">{{ statusIcon }}</view>
|
||
<view class="status-info">
|
||
<view class="status-text">{{ statusText }}</view>
|
||
<view class="status-desc">{{ statusDesc }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 主要内容区域 -->
|
||
<view class="main-content">
|
||
<!-- 发票基本信息卡片 -->
|
||
<view class="detail-card">
|
||
<view class="card-header">
|
||
<view class="card-title">发票基本信息</view>
|
||
<view class="card-icon">📋</view>
|
||
</view>
|
||
|
||
<view class="card-content">
|
||
<view class="info-row">
|
||
<text class="info-label">发票抬头</text>
|
||
<text class="info-value">{{ invoice.title }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">发票号码</text>
|
||
<text class="info-value">{{ invoice.invoiceNumber }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">发票类型</text>
|
||
<text class="info-value">{{ invoice.type }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">开票金额</text>
|
||
<text class="info-value amount">¥{{ invoice.amount }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">申请时间</text>
|
||
<text class="info-value">{{ invoice.createTime }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="invoice.status === 'issued' && invoice.issueTime">
|
||
<text class="info-label">开票时间</text>
|
||
<text class="info-value">{{ invoice.issueTime }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 联系信息卡片 -->
|
||
<view class="detail-card">
|
||
<view class="card-header">
|
||
<view class="card-title">联系信息</view>
|
||
<view class="card-icon">📞</view>
|
||
</view>
|
||
|
||
<view class="card-content">
|
||
<view class="info-row">
|
||
<text class="info-label">电子邮箱</text>
|
||
<text class="info-value">{{ invoice.email || '未填写' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="info-label">手机号码</text>
|
||
<text class="info-value">{{ invoice.phone || '未填写' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 企业信息卡片(仅企业发票显示) -->
|
||
<view class="detail-card" v-if="invoice.taxNumber">
|
||
<view class="card-header">
|
||
<view class="card-title">企业信息</view>
|
||
<view class="card-icon">🏢</view>
|
||
</view>
|
||
|
||
<view class="card-content">
|
||
<view class="info-row">
|
||
<text class="info-label">税号</text>
|
||
<text class="info-value">{{ invoice.taxNumber }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="invoice.bankName">
|
||
<text class="info-label">开户银行</text>
|
||
<text class="info-value">{{ invoice.bankName }}</text>
|
||
</view>
|
||
<view class="info-row" v-if="invoice.bankAccount">
|
||
<text class="info-label">银行账号</text>
|
||
<text class="info-value">{{ invoice.bankAccount }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 驳回原因卡片(仅驳回状态显示) -->
|
||
<view class="detail-card reject-card" v-if="invoice.status === 'rejected' && invoice.rejectReason">
|
||
<view class="card-header">
|
||
<view class="card-title">驳回原因</view>
|
||
<view class="card-icon">⚠️</view>
|
||
</view>
|
||
|
||
<view class="card-content">
|
||
<view class="reject-reason">
|
||
{{ invoice.rejectReason }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 票据图片卡片 -->
|
||
<view class="detail-card" v-if="invoice.status === 'issued' && invoiceImages && invoiceImages.length > 0">
|
||
<view class="card-header">
|
||
<view class="card-title">票据图片</view>
|
||
<view class="card-icon">🖼️</view>
|
||
</view>
|
||
|
||
<view class="card-content">
|
||
<view class="invoice-images">
|
||
<view class="image-item" v-for="(image, index) in invoiceImages" :key="index"
|
||
@click="previewImage(index)">
|
||
<image class="invoice-image" :src="image.url" mode="aspectFill" />
|
||
<view class="image-overlay">
|
||
<view class="preview-icon">👁️</view>
|
||
<text class="preview-text">点击预览</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
menu: {}, // 手机配置信息
|
||
invoice: {}, // 发票详情数据
|
||
invoiceId: null, // 发票ID
|
||
invoiceImages: [] // 票据图片数组
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
// 状态样式类
|
||
statusClass() {
|
||
var classMap = {
|
||
'issued': 'status-issued',
|
||
'applying': 'status-applying',
|
||
'rejected': 'status-rejected'
|
||
};
|
||
return classMap[this.invoice.status] || '';
|
||
},
|
||
|
||
// 状态图标
|
||
statusIcon() {
|
||
var iconMap = {
|
||
'issued': '✅',
|
||
'applying': '⏳',
|
||
'rejected': '❌'
|
||
};
|
||
return iconMap[this.invoice.status] || '';
|
||
},
|
||
|
||
// 状态文本
|
||
statusText() {
|
||
var textMap = {
|
||
'issued': '已开票',
|
||
'applying': '申请中',
|
||
'rejected': '已驳回'
|
||
};
|
||
return textMap[this.invoice.status] || '未知';
|
||
},
|
||
|
||
// 状态描述
|
||
statusDesc() {
|
||
var descMap = {
|
||
'issued': '您的发票已开具完成',
|
||
'applying': '正在为您开具发票,请耐心等待',
|
||
'rejected': '申请被驳回,请根据驳回原因修改后重新申请'
|
||
};
|
||
return descMap[this.invoice.status] || '';
|
||
}
|
||
},
|
||
|
||
onLoad(options) {
|
||
this.menu = uni.getMenuButtonBoundingClientRect();
|
||
|
||
if (options.id) {
|
||
this.invoiceId = options.id;
|
||
}
|
||
|
||
if (options.invoice) {
|
||
try {
|
||
this.invoice = JSON.parse(decodeURIComponent(options.invoice));
|
||
} catch (error) {
|
||
console.error('解析发票数据失败:', error);
|
||
}
|
||
}
|
||
|
||
// 如果没有从列表页传数据,则根据ID获取详情
|
||
if (!this.invoice.id && this.invoiceId) {
|
||
this.loadInvoiceDetail();
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 加载发票详情
|
||
loadInvoiceDetail() {
|
||
var _this = this;
|
||
try {
|
||
uni.showLoading({
|
||
title: '加载中...',
|
||
mask: true
|
||
});
|
||
|
||
// 模拟API调用
|
||
setTimeout(function () {
|
||
// 模拟数据
|
||
var mockData = {
|
||
id: _this.invoiceId,
|
||
title: '云南高速公路服务区有限公司',
|
||
invoiceNumber: 'FP202401001',
|
||
amount: '1000.00',
|
||
status: 'issued',
|
||
type: '增值税普通发票',
|
||
createTime: '2024-01-15 14:30:00',
|
||
issueTime: '2024-01-16 10:00:00',
|
||
email: 'zhangsan@example.com',
|
||
phone: '13800138000',
|
||
taxNumber: '91530100MA6KXXXXXX',
|
||
bankName: '中国银行昆明分行',
|
||
bankAccount: '6217 9027 0000 1234 567',
|
||
downloadUrl: 'https://example.com/invoice/FP202401001.pdf'
|
||
};
|
||
|
||
_this.invoice = mockData;
|
||
|
||
// 模拟票据图片数据
|
||
if (mockData.status === 'issued') {
|
||
_this.invoiceImages = [
|
||
{
|
||
url: 'https://picsum.photos/seed/invoice1/800/600.jpg',
|
||
name: '票据正面'
|
||
},
|
||
{
|
||
url: 'https://picsum.photos/seed/invoice2/800/600.jpg',
|
||
name: '票据背面'
|
||
}
|
||
];
|
||
}
|
||
|
||
uni.hideLoading();
|
||
}, 1000);
|
||
|
||
} catch (error) {
|
||
console.error('加载发票详情失败:', error);
|
||
uni.showToast({
|
||
title: '加载失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
uni.hideLoading();
|
||
}
|
||
},
|
||
|
||
// 返回列表
|
||
goBack() {
|
||
uni.navigateBack({
|
||
delta: 1
|
||
});
|
||
},
|
||
// 预览图片
|
||
previewImage(index) {
|
||
var urls = this.invoiceImages.map(function (image) {
|
||
return image.url;
|
||
});
|
||
|
||
uni.previewImage({
|
||
current: index,
|
||
urls: urls
|
||
});
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.invoice-detail-page {
|
||
min-height: 100vh;
|
||
background: linear-gradient(135deg, #E8F5E8 0%, #F8F9FA 50%, #FFFFFF 100%);
|
||
padding-bottom: 120rpx;
|
||
}
|
||
|
||
.mainTop {
|
||
width: 100%;
|
||
background-color: #f8f8f8;
|
||
box-sizing: border-box;
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
z-index: 999;
|
||
|
||
.pageTitle {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
/* 头部状态卡片 */
|
||
.header-section {
|
||
padding: 40rpx 24rpx 24rpx;
|
||
}
|
||
|
||
.status-card {
|
||
border-radius: 24rpx;
|
||
padding: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
|
||
|
||
&.status-issued {
|
||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||
color: white;
|
||
}
|
||
|
||
&.status-applying {
|
||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||
color: white;
|
||
}
|
||
|
||
&.status-rejected {
|
||
background: linear-gradient(135deg, #ef4444, #dc2626);
|
||
color: white;
|
||
}
|
||
|
||
.status-icon {
|
||
font-size: 40rpx;
|
||
margin-right: 24rpx;
|
||
}
|
||
|
||
.status-info {
|
||
flex: 1;
|
||
|
||
.status-text {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.status-desc {
|
||
font-size: 24rpx;
|
||
opacity: 0.9;
|
||
line-height: 1.4;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 主要内容区域 */
|
||
.main-content {
|
||
padding: 0 24rpx;
|
||
}
|
||
|
||
.detail-card {
|
||
background: white;
|
||
border-radius: 24rpx;
|
||
margin-bottom: 24rpx;
|
||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||
border: 1rpx solid #f0f0f0;
|
||
overflow: hidden;
|
||
|
||
&.reject-card {
|
||
border-left: 8rpx solid #ef4444;
|
||
}
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 24rpx;
|
||
border-bottom: 2rpx solid #f0fdf4;
|
||
background: linear-gradient(135deg, rgba(34, 197, 94, 0.03) 0%, rgba(22, 163, 74, 0.03) 100%);
|
||
|
||
.card-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #15803d;
|
||
}
|
||
|
||
.card-icon {
|
||
font-size: 30rpx;
|
||
opacity: 0.7;
|
||
color: #22c55e;
|
||
}
|
||
}
|
||
|
||
.card-content {
|
||
padding: 24rpx;
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-bottom: 12rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
width: 140rpx;
|
||
flex-shrink: 0;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.info-value {
|
||
flex: 1;
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
line-height: 1.5;
|
||
word-break: break-all;
|
||
|
||
&.amount {
|
||
color: #22c55e;
|
||
font-weight: 600;
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 驳回原因样式 */
|
||
.reject-reason {
|
||
background: #fef2f2;
|
||
border: 1rpx solid #fecaca;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
font-size: 28rpx;
|
||
color: #dc2626;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 文件下载样式 */
|
||
.file-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 24rpx;
|
||
background: #f8fafc;
|
||
border-radius: 16rpx;
|
||
border: 1rpx solid #e2e8f0;
|
||
transition: all 0.3s ease;
|
||
|
||
&:active {
|
||
background: #f1f5f9;
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
.file-icon {
|
||
font-size: 48rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.file-info {
|
||
flex: 1;
|
||
|
||
.file-name {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.file-size {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
}
|
||
|
||
.download-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 12rpx 20rpx;
|
||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||
border-radius: 24rpx;
|
||
color: white;
|
||
|
||
.download-text {
|
||
font-size: 26rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.download-icon {
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 底部操作区域 */
|
||
.bottom-actions {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: white;
|
||
padding: 24rpx;
|
||
border-top: 1rpx solid #f0f0f0;
|
||
display: flex;
|
||
gap: 16rpx;
|
||
box-shadow: 0 -8rpx 32rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.action-btn {
|
||
flex: 1;
|
||
padding: 24rpx;
|
||
border-radius: 40rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
transition: all 0.3s ease;
|
||
|
||
&.back-btn {
|
||
background: #f5f5f5;
|
||
color: #666;
|
||
|
||
&:active {
|
||
background: #e5e5e5;
|
||
}
|
||
}
|
||
|
||
&.primary-btn {
|
||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||
color: white;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 4rpx 16rpx rgba(34, 197, 94, 0.4);
|
||
}
|
||
}
|
||
|
||
&.secondary-btn {
|
||
background: linear-gradient(135deg, #3b82f6, #2563eb);
|
||
color: white;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 4rpx 16rpx rgba(59, 130, 246, 0.4);
|
||
}
|
||
}
|
||
|
||
.btn-text {
|
||
font-size: 28rpx;
|
||
}
|
||
}
|
||
|
||
/* 票据图片样式 */
|
||
.invoice-images {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.image-item {
|
||
position: relative;
|
||
width: calc(50% - 8rpx);
|
||
height: 200rpx;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
||
transition: all 0.3s ease;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
|
||
}
|
||
}
|
||
|
||
.invoice-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 16rpx;
|
||
}
|
||
|
||
.image-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.6));
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
border-radius: 16rpx;
|
||
|
||
.preview-icon {
|
||
font-size: 48rpx;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.preview-text {
|
||
font-size: 24rpx;
|
||
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
|
||
}
|
||
}
|
||
|
||
.image-item:hover .image-overlay,
|
||
.image-item:active .image-overlay {
|
||
opacity: 1;
|
||
}
|
||
</style> |