327 lines
8.0 KiB
Vue
327 lines
8.0 KiB
Vue
<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>
|