Files
xk-client-wx/subPackages/my/my-drug/invoice-apply.vue
2026-07-28 12:45:56 +08:00

327 lines
8.0 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>
<view class="page safe-area-inset-bottom">
<!-- 订单摘要 -->
<view class="card">
<view class="card_title">订单信息</view>
<view class="card_row">
<text class="label">订单号</text>
<text class="value">{{ orderNo }}</text>
</view>
<view class="card_row last">
<text class="label">开票金额</text>
<text class="value price">{{ amount }}</text>
</view>
</view>
<!-- 抬头信息 -->
<view class="card">
<view class="card_title">抬头信息</view>
<view class="card_row">
<text class="label">抬头类型</text>
<view class="seg">
<view
class="seg_item"
:class="{ active: titleType == 1 }"
@tap="titleType = 1"
>个人</view>
<view
class="seg_item"
:class="{ active: titleType == 2 }"
@tap="titleType = 2"
>企业</view>
</view>
</view>
<view class="card_row">
<text class="label"><text class="req">*</text>抬头名称</text>
<input
class="input"
v-model="titleName"
:placeholder="titleType == 2 ? '请输入企业名称' : '请输入个人姓名'"
placeholder-class="ph"
/>
</view>
<view class="card_row last" v-if="titleType == 2">
<text class="label"><text class="req">*</text>企业税号</text>
<input
class="input"
v-model="taxNo"
placeholder="请输入纳税人识别号"
placeholder-class="ph"
/>
</view>
</view>
<!-- 接收方式暂时隐藏保留代码默认小程序可查 + 邮箱选填 -->
<view class="card" v-if="false">
<view class="card_title">接收方式</view>
<view class="seg full">
<view
class="seg_item"
:class="{ active: receiveType == 1 }"
@tap="receiveType = 1"
>小程序下载</view>
<view
class="seg_item"
:class="{ active: receiveType == 2 }"
@tap="receiveType = 2"
>邮箱接收</view>
</view>
</view>
<!-- 邮箱选填 + 说明 -->
<view class="card">
<view class="card_title">接收邮箱</view>
<view class="card_row last">
<text class="label">邮箱</text>
<input
class="input"
v-model="email"
placeholder="选填,便于邮件查收"
placeholder-class="ph"
/>
</view>
<view class="tip">开具发票后可到小程序或邮箱中查收</view>
</view>
<view class="footer">
<button class="submit" :loading="submitting" @tap="onSubmit">提交申请</button>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import { applyInvoiceApi, INVOICE_NOTICE_TMPL_ID } from '@/request/api/invoice.js'
/**
* 申请开票页:抬头必填、邮箱选填;接收方式隐藏,固定小程序通道
* 提交前申请一次订阅授权(留给开票完成推送)
*/
export default {
data() {
return {
orderId: 0,
orderNo: '',
amount: '',
titleType: 1,
titleName: '',
taxNo: '',
// 固定小程序可查;接收方式选择 UI 已隐藏
receiveType: 1,
email: '',
submitting: false
}
},
onLoad(query) {
this.orderId = Number(query.order_id || 0)
this.orderNo = decodeURIComponent(query.order_no || '')
this.amount = query.amount || ''
},
/**
* 下拉刷新:重置表单字段,保留路由带来的订单信息
*/
onPullDownRefresh() {
this.resetForm()
uni.stopPullDownRefresh()
},
methods: {
/** 重置抬头与邮箱,订单号/金额不动 */
resetForm() {
this.titleType = 1
this.titleName = ''
this.taxNo = ''
this.receiveType = 1
this.email = ''
},
/**
* 校验表单后请求订阅授权,再提交申请
*/
onSubmit() {
if (!this.orderId) {
this.$refs.uToast.show({ title: '订单无效', type: 'error' })
return
}
const titleName = (this.titleName || '').trim()
if (!titleName) {
this.$refs.uToast.show({ title: '请填写抬头名称', type: 'warning' })
return
}
if (this.titleType == 2 && !(this.taxNo || '').trim()) {
this.$refs.uToast.show({ title: '请填写企业税号', type: 'warning' })
return
}
let email = (this.email || '').trim()
// 邮箱选填:有值才校验格式
if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
this.$refs.uToast.show({ title: '请填写正确邮箱', type: 'warning' })
return
}
if (!email) {
email = ''
}
// 订阅消息同模板一次手势只给 1 次额度,留给「开票完成」推送
uni.requestSubscribeMessage({
tmplIds: [INVOICE_NOTICE_TMPL_ID],
complete: () => {
this.doApply(titleName, email)
}
})
},
/**
* 调用后端提交开票申请(固定 receive_type=1邮箱可带
*/
doApply(titleName, email) {
if (this.submitting) return
this.submitting = true
applyInvoiceApi({
order_id: this.orderId,
title_type: this.titleType,
title_name: titleName,
tax_no: this.titleType == 2 ? (this.taxNo || '').trim() : '',
receive_type: 1,
email: email
}).then((res) => {
if (res.data && res.data.errcode == 0) {
const id = res.data.data && res.data.data.id
uni.showToast({ title: '提交成功', icon: 'success' })
setTimeout(() => {
if (id) {
uni.redirectTo({
url: '/subPackages/my/my-drug/invoice-detail?id=' + id
})
} else {
uni.navigateBack()
}
}, 500)
} else {
uni.showToast({
title: (res.data && (res.data.errmsg || res.data.message)) || '提交失败',
icon: 'none'
})
}
}).catch(() => {
uni.showToast({ title: '提交失败', icon: 'none' })
}).finally(() => {
this.submitting = false
})
}
}
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #f8fafc;
padding: 20rpx 0 180rpx;
box-sizing: border-box;
}
.card {
width: 720rpx;
margin: 0 auto 20rpx;
background: #fff;
border-radius: 16rpx;
padding: 0 28rpx 8rpx;
box-sizing: border-box;
}
.card_title {
height: 96rpx;
line-height: 96rpx;
font-size: 32rpx;
font-weight: 500;
color: #232323;
border-bottom: 1rpx solid #e2e8f0;
}
.card_row {
min-height: 100rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1rpx solid #e2e8f0;
padding: 12rpx 0;
}
.card_row.last {
border-bottom: none;
}
.label {
color: #1e293b;
font-size: 28rpx;
flex-shrink: 0;
margin-right: 24rpx;
}
.req {
color: #ff5050;
margin-right: 4rpx;
}
.value {
color: #334155;
font-size: 28rpx;
text-align: right;
flex: 1;
word-break: break-all;
}
.price {
color: #ff5050;
font-weight: 600;
}
.input {
flex: 1;
font-size: 28rpx;
color: #1e293b;
text-align: right;
}
.ph {
color: #94a3b8;
}
.seg {
display: flex;
gap: 16rpx;
}
.seg.full {
width: 100%;
margin: 24rpx 0;
}
.seg_item {
min-width: 140rpx;
padding: 12rpx 28rpx;
text-align: center;
border-radius: 32rpx;
border: 2rpx solid #e5e5e5;
color: #64748b;
font-size: 26rpx;
background: #fff;
}
.seg_item.active {
border-color: #5f71fe;
color: #5f71fe;
background: #f4f5ff;
font-weight: 500;
}
.tip {
font-size: 24rpx;
color: #94a3b8;
line-height: 1.5;
padding: 8rpx 0 24rpx;
}
.footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 32rpx calc(20rpx + env(safe-area-inset-bottom));
background: #fff;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.04);
}
.submit {
background: #5f71fe;
color: #fff;
border-radius: 44rpx;
font-size: 30rpx;
height: 88rpx;
line-height: 88rpx;
}
.submit::after {
border: none;
}
</style>