<template>
|
<view class="invoice-page">
|
<view class="search-bar">
|
<view class="search-box">
|
<image src="/static/icon/ic_search2@2x.png" mode="widthFix"></image>
|
<input
|
v-model="keyword"
|
class="search-input"
|
type="text"
|
:placeholder="currentTab === 'apply' ? '搜索订单编号' : '搜索'"
|
/>
|
</view>
|
</view>
|
|
<scroll-view scroll-y class="page-scroll">
|
<view v-if="currentTab === 'apply'" class="card-list">
|
<view v-for="item in applyList" :key="item.id" class="invoice-card apply-card">
|
<view class="order-no">订单编号:{{ item.orderNo }}</view>
|
<view class="address-group">
|
<view class="address-row">
|
<view class="address-tag send-tag">寄</view>
|
<view class="address-copy">
|
<view class="address-title-row">
|
<text class="address-title">{{ item.fromAddress }}</text>
|
<u-icon name="arrow-right" size="14" color="#40454d"></u-icon>
|
</view>
|
<text class="address-user">{{ item.fromUser }}</text>
|
</view>
|
</view>
|
<view class="address-dash"></view>
|
<view class="address-row">
|
<view class="address-tag receive-tag">收</view>
|
<view class="address-copy">
|
<view class="address-title-row">
|
<text class="address-title">{{ item.toAddress }}</text>
|
<u-icon name="arrow-right" size="14" color="#40454d"></u-icon>
|
</view>
|
<text class="address-user">{{ item.toUser }}</text>
|
</view>
|
</view>
|
</view>
|
|
<view class="goods-line">
|
<text class="goods-text">{{ item.goodsText }}</text>
|
<u-icon name="arrow-down" size="14" color="#a2a7b1"></u-icon>
|
</view>
|
|
<view class="price-row">
|
<view class="price-copy">
|
<text class="price-label">实付款:</text>
|
<text class="price-value">¥{{ item.amount }}</text>
|
</view>
|
<view class="action-btn primary-btn" @tap="goInvoiceRequest(item)">申请开票</view>
|
</view>
|
</view>
|
</view>
|
|
<view v-else class="card-list">
|
<view v-for="item in historyList" :key="item.id" class="invoice-card history-card">
|
<view class="history-head">
|
<text class="company-name">{{ item.company }}</text>
|
<text class="history-status" :class="item.status">{{ item.statusText }}</text>
|
</view>
|
<view class="history-subline">
|
<text>{{ item.ticketType }}</text>
|
<text class="sub-sep">|</text>
|
<text>发票金额:</text>
|
<text class="history-amount">¥{{ item.amount }}</text>
|
</view>
|
<view class="history-divider"></view>
|
<view class="history-detail">
|
<view class="detail-item">开票编号:{{ item.applyNo }}</view>
|
<view class="detail-item">发票号码:{{ item.invoiceNo }}</view>
|
<view class="detail-item">申请时间:{{ item.applyTime }}</view>
|
<view v-if="item.failReason" class="detail-item fail-row">失败理由:<text class="fail-text">{{ item.failReason }}</text></view>
|
</view>
|
|
<view v-if="item.actions && item.actions.length" class="history-actions">
|
<view
|
v-for="action in item.actions"
|
:key="action.text"
|
class="action-btn"
|
:class="action.primary ? 'primary-btn' : 'ghost-btn'"
|
@tap="handleAction(action, item)"
|
>
|
{{ action.text }}
|
</view>
|
</view>
|
</view>
|
</view>
|
</scroll-view>
|
|
<u-popup :show="showEmailPopup" mode="center" bgColor="transparent" @close="closeEmailPopup">
|
<view class="email-popup">
|
<view class="email-title">发送至邮箱</view>
|
<view class="email-input-wrap">
|
<input v-model="email" class="email-input" type="text" placeholder="请输入邮箱" />
|
<u-icon v-if="email" name="close-circle-fill" size="20" color="#a7a7a7" @tap="email = ''"></u-icon>
|
</view>
|
<view class="email-footer">
|
<view class="popup-btn popup-btn-cancel" @tap="closeEmailPopup">取消</view>
|
<view class="popup-btn popup-btn-confirm" @tap="confirmSendEmail">确认发送</view>
|
</view>
|
</view>
|
</u-popup>
|
|
<view class="bottom-tabs">
|
<view
|
v-for="tab in tabs"
|
:key="tab.value"
|
class="bottom-tab"
|
:class="{ active: currentTab === tab.value }"
|
@tap="currentTab = tab.value"
|
>
|
<image
|
v-if="getTabIcon(tab)"
|
class="tab-icon"
|
:src="getTabIcon(tab)"
|
mode="aspectFit"
|
></image>
|
<view v-else class="tab-icon placeholder-icon"></view>
|
<text class="tab-label">{{ tab.label }}</text>
|
</view>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
data() {
|
return {
|
currentTab: 'apply',
|
keyword: '',
|
showEmailPopup: false,
|
email: '38742937@qq.com',
|
currentYear: '近一年',
|
tabs: [
|
{
|
label: '开票',
|
value: 'apply',
|
icon: '/shop/static/icon/nav_kaipiao@2x.png',
|
activeIcon: '/shop/static/icon/nav_kaipiao_sel@2x.png'
|
},
|
{
|
label: '开票历史',
|
value: 'history',
|
icon: '/shop/static/icon/nav_lishi@2x.png',
|
activeIcon: '/shop/static/icon/nav_lishi_sel@2x.png'
|
}
|
],
|
applyList: [
|
{
|
id: 1,
|
orderNo: '202607131742520001',
|
fromAddress: '安徽省合肥市蜀山区莲花科技产业园F401',
|
fromUser: '张海涛 18733987653',
|
toAddress: '安徽省合肥市蜀山区尚泽大都会2栋302',
|
toUser: '张海涛 18733987653',
|
goodsText: '大件行李*1、中件行李*2、小件行李*3、背...',
|
amount: '125.00'
|
},
|
{
|
id: 2,
|
orderNo: '202607131742520001',
|
fromAddress: '安徽省合肥市蜀山区莲花科技产业园F401',
|
fromUser: '张海涛 18733987653',
|
toAddress: '安徽省合肥市蜀山区尚泽大都会2栋302',
|
toUser: '张海涛 18733987653',
|
goodsText: '大件行李*1、中件行李*2、小件行李*3、背...',
|
amount: '125.00'
|
}
|
],
|
historyList: [
|
{
|
id: 1,
|
company: '安徽豆米科技有限公司',
|
status: 'processing',
|
statusText: '开票中',
|
ticketType: '电子专用发票',
|
amount: '100.00',
|
applyNo: '202607131742520001',
|
invoiceNo: '20260713174252000324',
|
applyTime: '2026-05-12 11:34:11',
|
failReason: '',
|
actions: []
|
},
|
{
|
id: 2,
|
company: '安徽豆米科技有限公司',
|
status: 'done',
|
statusText: '已开票',
|
ticketType: '电子专用发票',
|
amount: '100.00',
|
applyNo: '202607131742520001',
|
invoiceNo: '20260713174252000324',
|
applyTime: '2026-05-12 11:34:11',
|
failReason: '',
|
actions: [
|
{ text: '查看电子发票', primary: false },
|
{ text: '发送至邮箱', primary: true }
|
]
|
},
|
{
|
id: 3,
|
company: '安徽豆米科技有限公司',
|
status: 'failed',
|
statusText: '开票失败',
|
ticketType: '电子专用发票',
|
amount: '100.00',
|
applyNo: '202607131742520001',
|
invoiceNo: '20260713174252000324',
|
applyTime: '2026-05-12 11:34:11',
|
failReason: '发票抬头错误',
|
actions: [
|
{ text: '申请开票', primary: true }
|
]
|
}
|
]
|
};
|
},
|
methods: {
|
getTabIcon(tab) {
|
return this.currentTab === tab.value ? tab.activeIcon : tab.icon;
|
},
|
goInvoiceRequest(item) {
|
const id = item && item.id ? `?id=${item.id}` : '';
|
uni.navigateTo({
|
url: `/shop/pages/Invoice-request/Invoice-request${id}`
|
});
|
},
|
handleAction(action) {
|
if (action.text === '发送至邮箱') {
|
this.showEmailPopup = true;
|
return;
|
}
|
|
if (action.text === '申请开票') {
|
this.goInvoiceRequest();
|
}
|
},
|
closeEmailPopup() {
|
this.showEmailPopup = false;
|
},
|
confirmSendEmail() {
|
this.showEmailPopup = false;
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.invoice-page {
|
min-height: 100vh;
|
background: linear-gradient(180deg, #f8f9fc 0%, #f4f6fb 100%);
|
}
|
|
.search-bar {
|
display: flex;
|
align-items: center;
|
gap: 18rpx;
|
padding: 18rpx 24rpx 16rpx;
|
background: #ffffff;
|
}
|
|
.search-box {
|
width: 100%;
|
height: 100%;
|
padding: 0 30rpx;
|
box-sizing: border-box;
|
display: flex;
|
align-items: center;
|
background: #EEEEEE;
|
border-radius: 158rpx;
|
border: 1rpx solid #EEEEEE;
|
}
|
|
.search-bar image {
|
width: 32rpx;
|
height: 32rpx;
|
margin-right: 16rpx;
|
}
|
|
.search-input {
|
flex: 1;
|
height: 72rpx;
|
padding: 0 24rpx 0 0;
|
font-size: 28rpx;
|
color: #2f3137;
|
}
|
|
.search-bar {
|
position: relative;
|
}
|
|
.search-bar > * {
|
position: relative;
|
z-index: 1;
|
}
|
|
.page-scroll {
|
height: calc(100vh - 124rpx - 124rpx);
|
}
|
|
.card-list {
|
padding: 20rpx 30rpx;
|
box-sizing: border-box;
|
}
|
|
.invoice-card {
|
padding: 30rpx;
|
box-sizing: border-box;
|
margin-bottom: 20rpx;
|
background: #ffffff;
|
border-radius: 20rpx;
|
box-shadow: 0 12rpx 30rpx rgba(45, 82, 134, 0.04);
|
}
|
|
.order-no {
|
font-size: 28rpx;
|
line-height: 40rpx;
|
color: #9ca3af;
|
}
|
|
.address-group {
|
position: relative;
|
margin-top: 24rpx;
|
}
|
|
.address-row {
|
display: flex;
|
align-items: flex-start;
|
gap: 18rpx;
|
}
|
|
.address-tag {
|
flex-shrink: 0;
|
width: 40rpx;
|
height: 40rpx;
|
line-height: 40rpx;
|
border-radius: 50%;
|
text-align: center;
|
font-size: 24rpx;
|
font-weight: 600;
|
color: #ffffff;
|
}
|
|
.send-tag {
|
background: linear-gradient(180deg, #4bc7ff 0%, #1ea4ff 100%);
|
}
|
|
.receive-tag {
|
background: linear-gradient(180deg, #ffb248 0%, #ff8600 100%);
|
}
|
|
.address-copy {
|
flex: 1;
|
min-width: 0;
|
}
|
|
.address-title-row {
|
display: flex;
|
align-items: center;
|
gap: 8rpx;
|
}
|
|
.address-title {
|
flex: 1;
|
font-size: 38rpx;
|
font-weight: 700;
|
line-height: 52rpx;
|
color: #252a33;
|
}
|
|
.address-user {
|
display: block;
|
margin-top: 8rpx;
|
font-size: 30rpx;
|
line-height: 42rpx;
|
color: #9aa0aa;
|
}
|
|
.address-dash {
|
width: 0;
|
height: 26rpx;
|
margin: 8rpx 0 8rpx 20rpx;
|
border-left: 2rpx dashed #e1e5ec;
|
}
|
|
.goods-line {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
gap: 16rpx;
|
padding: 20rpx;
|
box-sizing: border-box;
|
margin-top: 22rpx;
|
border-radius: 14rpx;
|
background: #f6f7fa;
|
}
|
|
.goods-text {
|
flex: 1;
|
font-size: 30rpx;
|
line-height: 42rpx;
|
color: #686f7c;
|
}
|
|
.price-row {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
gap: 20rpx;
|
margin-top: 26rpx;
|
}
|
|
.price-copy {
|
display: flex;
|
align-items: baseline;
|
}
|
|
.price-label {
|
font-size: 32rpx;
|
line-height: 44rpx;
|
color: #353b44;
|
}
|
|
.price-value {
|
font-size: 44rpx;
|
font-weight: 700;
|
line-height: 56rpx;
|
color: #252a33;
|
}
|
|
.action-btn {
|
display: inline-flex;
|
align-items: center;
|
justify-content: center;
|
min-width: 168rpx;
|
height: 68rpx;
|
padding: 0 26rpx;
|
border-radius: 999rpx;
|
font-size: 30rpx;
|
font-weight: 500;
|
}
|
|
.primary-btn {
|
background: linear-gradient(135deg, #3bc6ff 0%, #1ea5ff 100%);
|
color: #ffffff;
|
box-shadow: 0 10rpx 22rpx rgba(30, 165, 255, 0.22);
|
}
|
|
.ghost-btn {
|
border: 2rpx solid #d9dce4;
|
background: #ffffff;
|
color: #6e7581;
|
}
|
|
.history-head {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
gap: 20rpx;
|
}
|
|
.company-name {
|
flex: 1;
|
font-size: 38rpx;
|
font-weight: 700;
|
line-height: 52rpx;
|
color: #252a33;
|
}
|
|
.history-status {
|
flex-shrink: 0;
|
font-size: 32rpx;
|
font-weight: 600;
|
}
|
|
.history-status.processing {
|
color: #ff4b4b;
|
}
|
|
.history-status.done,
|
.history-amount {
|
color: #1eb6ff;
|
}
|
|
.history-status.failed {
|
color: #a8adb8;
|
}
|
|
.history-subline {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 8rpx;
|
margin-top: 14rpx;
|
font-size: 28rpx;
|
line-height: 40rpx;
|
color: #7b818c;
|
}
|
|
.sub-sep {
|
color: #d3d7df;
|
}
|
|
.history-divider {
|
height: 2rpx;
|
margin: 22rpx 0;
|
background: #f1f3f6;
|
}
|
|
.history-detail {
|
font-size: 28rpx;
|
line-height: 44rpx;
|
color: #a1a7b2;
|
}
|
|
.detail-item + .detail-item {
|
margin-top: 6rpx;
|
}
|
|
.fail-row {
|
margin-top: 10rpx;
|
}
|
|
.fail-text {
|
color: #ff4b4b;
|
}
|
|
.history-actions {
|
display: flex;
|
justify-content: flex-end;
|
gap: 18rpx;
|
margin-top: 24rpx;
|
}
|
|
.email-popup {
|
width: 680rpx;
|
overflow: hidden;
|
background: #ffffff;
|
border-radius: 22rpx;
|
}
|
|
.email-title {
|
padding: 50rpx 32rpx 38rpx;
|
text-align: center;
|
font-size: 40rpx;
|
font-weight: 700;
|
line-height: 56rpx;
|
color: #222222;
|
}
|
|
.email-input-wrap {
|
display: flex;
|
align-items: center;
|
margin: 0 54rpx 44rpx;
|
padding: 0 24rpx 0 34rpx;
|
height: 84rpx;
|
border-radius: 999rpx;
|
background: #f6f6f6;
|
}
|
|
.email-input {
|
flex: 1;
|
height: 84rpx;
|
font-size: 34rpx;
|
text-align: center;
|
color: #4a4a4a;
|
}
|
|
.email-footer {
|
display: flex;
|
align-items: center;
|
height: 100rpx;
|
border-top: 1rpx solid #f1f1f1;
|
}
|
|
.popup-btn {
|
flex: 1;
|
height: 100rpx;
|
line-height: 100rpx;
|
text-align: center;
|
font-size: 36rpx;
|
font-weight: 500;
|
}
|
|
.popup-btn-cancel {
|
color: #999999;
|
}
|
|
.popup-btn-confirm {
|
color: #1eb6ff;
|
border-left: 1rpx solid #f1f1f1;
|
}
|
|
.bottom-tabs {
|
display: flex;
|
align-items: center;
|
justify-content: space-around;
|
height: 124rpx;
|
background: rgba(255, 255, 255, 0.98);
|
box-shadow: 0 -8rpx 30rpx rgba(35, 60, 96, 0.05);
|
}
|
|
.bottom-tab {
|
display: flex;
|
flex: 1;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
gap: 8rpx;
|
color: #a4a9b2;
|
}
|
|
.bottom-tab.active {
|
color: #1ea5ff;
|
}
|
|
.tab-icon {
|
width: 52rpx;
|
height: 52rpx;
|
}
|
|
.placeholder-icon {
|
border-radius: 10rpx;
|
background: #dfe4ec;
|
}
|
|
.tab-label {
|
font-size: 26rpx;
|
line-height: 36rpx;
|
font-weight: 500;
|
}
|
</style>
|