1
This commit is contained in:
parent
876358ea28
commit
086b4761db
@ -96,83 +96,300 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<!-- 单个开票确认模态框 -->
|
<!-- 单个开票模态框 -->
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="singleInvoiceModalVisible"
|
v-model:visible="singleInvoiceModalVisible"
|
||||||
title="开票确认"
|
:title="isBatch ? '批量开票' : '开票申请'"
|
||||||
@ok="handleSingleInvoiceConfirm"
|
@ok="handleSingleInvoiceConfirm"
|
||||||
@cancel="singleInvoiceModalVisible = false"
|
@cancel="handleInvoiceModalCancel"
|
||||||
:confirm-loading="singleInvoiceLoading"
|
:confirm-loading="singleInvoiceLoading"
|
||||||
centered
|
centered
|
||||||
|
width="800px"
|
||||||
|
:okText="isBatch ? '确认批量开票' : '确认开票'"
|
||||||
>
|
>
|
||||||
<div class="invoice-confirm-content">
|
<div class="invoice-modal-content">
|
||||||
<div class="confirm-item">
|
<!-- 订单信息区域 -->
|
||||||
<span class="confirm-label">流水号:</span>
|
<div class="order-info-section">
|
||||||
<span class="confirm-value">{{ currentInvoiceRecord?.serial_number || '-' }}</span>
|
<div class="section-title">
|
||||||
|
<a-icon type="shopping" />
|
||||||
|
<span style="margin-left: 8px;">订单信息</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="confirm-item">
|
<div class="order-info-grid">
|
||||||
<span class="confirm-label">交易时间:</span>
|
<template v-if="isBatch">
|
||||||
<span class="confirm-value">{{ currentInvoiceRecord?.created_at ? dayjs(currentInvoiceRecord.created_at).format('YYYY-MM-DD HH:mm') : '-' }}</span>
|
<!-- 批量开票显示多个订单 -->
|
||||||
|
<div class="order-info-item">
|
||||||
|
<span class="info-label">订单数量:</span>
|
||||||
|
<span class="info-value">{{ selectedRows.length }} 个订单</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="confirm-item">
|
<div class="order-info-item">
|
||||||
<span class="confirm-label">交易金额:</span>
|
<span class="info-label">总金额:</span>
|
||||||
<span class="confirm-value">¥{{ currentInvoiceRecord?.real_amount || '0.00' }}</span>
|
<span class="info-value total-amount">¥{{ selectedTotalAmount.toFixed(2) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="confirm-tips">
|
<div class="order-list-preview" style="grid-column: span 2;">
|
||||||
确认要为该订单申请发票吗?
|
<div class="preview-title">订单列表:</div>
|
||||||
|
<div class="order-list">
|
||||||
|
<div v-for="(order, index) in selectedRows.slice(0, 3)" :key="order.id" class="order-item">
|
||||||
|
<span>{{ order.serial_number }}</span>
|
||||||
|
<span>-¥{{ order.real_amount || '0.00' }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedRows.length > 3" class="order-more">
|
||||||
|
等 {{ selectedRows.length }} 个订单
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<!-- 单个开票显示单个订单 -->
|
||||||
|
<div class="order-info-item">
|
||||||
|
<span class="info-label">订单编号:</span>
|
||||||
|
<span class="info-value">{{ currentInvoiceRecord?.serial_number || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="order-info-item">
|
||||||
|
<span class="info-label">开票金额:</span>
|
||||||
|
<span class="info-value">¥{{ currentInvoiceRecord?.real_amount || '0.00' }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 发票信息区域 -->
|
||||||
|
<div class="invoice-info-section">
|
||||||
|
<div class="section-title">
|
||||||
|
<a-icon type="file-text" />
|
||||||
|
<span style="margin-left: 8px;">发票信息</span>
|
||||||
|
</div>
|
||||||
|
<a-form
|
||||||
|
ref="invoiceFormRef"
|
||||||
|
:model="invoiceFormData"
|
||||||
|
:rules="invoiceFormRules"
|
||||||
|
layout="vertical"
|
||||||
|
class="invoice-form"
|
||||||
|
>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="发票类型" name="invoiceType" required>
|
||||||
|
<a-select
|
||||||
|
v-model:value="invoiceFormData.invoiceType"
|
||||||
|
placeholder="请选择发票类型"
|
||||||
|
>
|
||||||
|
<a-select-option value="normal">普通发票</a-select-option>
|
||||||
|
<a-select-option value="special">专用发票</a-select-option>
|
||||||
|
<a-select-option value="electronic">电子发票</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="开票类型" name="billingType" required>
|
||||||
|
<a-select
|
||||||
|
v-model:value="invoiceFormData.billingType"
|
||||||
|
placeholder="请选择开票类型"
|
||||||
|
>
|
||||||
|
<a-select-option value="personal">个人</a-select-option>
|
||||||
|
<a-select-option value="company">企业</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-form-item label="抬头类型" name="titleType" required>
|
||||||
|
<a-radio-group v-model:value="invoiceFormData.titleType">
|
||||||
|
<a-radio value="personal">个人抬头</a-radio>
|
||||||
|
<a-radio value="company">公司抬头</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="发票抬头"
|
||||||
|
name="invoiceTitle"
|
||||||
|
required
|
||||||
|
v-if="invoiceFormData.titleType === 'company'"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:value="invoiceFormData.invoiceTitle"
|
||||||
|
placeholder="请选择发票抬头"
|
||||||
|
:options="invoiceTitleOptions"
|
||||||
|
@search="handleSearchInvoiceTitle"
|
||||||
|
show-search
|
||||||
|
allow-clear
|
||||||
|
>
|
||||||
|
<template #dropdownRender="{ menuNode: menu }">
|
||||||
|
<v-nodes :vnodes="menu" />
|
||||||
|
<a-divider style="margin: 4px 0" />
|
||||||
|
<div
|
||||||
|
style="padding: 8px; cursor: pointer;"
|
||||||
|
@click="handleAddInvoiceTitle"
|
||||||
|
>
|
||||||
|
<a-icon type="plus" /> 新增发票抬头
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="发票抬头"
|
||||||
|
name="personalTitle"
|
||||||
|
required
|
||||||
|
v-else
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="invoiceFormData.personalTitle"
|
||||||
|
placeholder="请输入个人姓名"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="纳税人识别号"
|
||||||
|
name="taxNumber"
|
||||||
|
v-if="invoiceFormData.titleType === 'company' && invoiceFormData.invoiceTitle"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model:value="invoiceFormData.taxNumber"
|
||||||
|
placeholder="请输入纳税人识别号"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="备注" name="remark">
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="invoiceFormData.remark"
|
||||||
|
placeholder="请输入开票备注(可选)"
|
||||||
|
:rows="2"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<!-- 批量开票确认模态框 -->
|
<!-- 新增发票抬头模态框 -->
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="batchInvoiceModalVisible"
|
v-model:visible="addTitleModalVisible"
|
||||||
title="批量开票确认"
|
title="新增发票抬头"
|
||||||
@ok="handleBatchInvoiceConfirm"
|
@ok="handleAddTitleConfirm"
|
||||||
@cancel="batchInvoiceModalVisible = false"
|
@cancel="addTitleModalVisible = false"
|
||||||
:confirm-loading="batchInvoiceLoading"
|
width="500px"
|
||||||
centered
|
centered
|
||||||
width="600px"
|
|
||||||
>
|
>
|
||||||
<div class="batch-invoice-content">
|
<a-form :model="newTitleForm" layout="vertical">
|
||||||
<div class="selected-count">
|
<a-form-item label="公司名称" required>
|
||||||
已选择 {{ selectedRowKeys.length }} 条记录进行批量开票
|
<a-input
|
||||||
</div>
|
v-model:value="newTitleForm.companyName"
|
||||||
<div class="total-amount">
|
placeholder="请输入公司全称"
|
||||||
<span class="total-label">合计金额:</span>
|
/>
|
||||||
<span class="total-value">¥{{ selectedTotalAmount.toFixed(2) }}</span>
|
</a-form-item>
|
||||||
</div>
|
<a-form-item label="纳税人识别号" required>
|
||||||
<div class="invoice-list" style="max-height: 300px; overflow-y: auto; margin-top: 16px;">
|
<a-input
|
||||||
<a-table
|
v-model:value="newTitleForm.taxNumber"
|
||||||
:dataSource="selectedInvoiceRecords"
|
placeholder="请输入纳税人识别号"
|
||||||
:columns="selectedColumns"
|
/>
|
||||||
size="small"
|
</a-form-item>
|
||||||
:pagination="false"
|
<a-form-item label="公司地址">
|
||||||
bordered
|
<a-input
|
||||||
>
|
v-model:value="newTitleForm.address"
|
||||||
<template #bodyCell="{ column, record }">
|
placeholder="请输入公司地址"
|
||||||
<template v-if="column.key === 'created_at'">
|
/>
|
||||||
{{ record.created_at ? dayjs(record.created_at).format('YYYY-MM-DD HH:mm') : '-' }}
|
</a-form-item>
|
||||||
</template>
|
<a-form-item label="开户银行">
|
||||||
<template v-if="column.key === 'real_amount'">
|
<a-input
|
||||||
-¥{{ record.real_amount || '0.00' }}
|
v-model:value="newTitleForm.bank"
|
||||||
</template>
|
placeholder="请输入开户银行"
|
||||||
</template>
|
/>
|
||||||
</a-table>
|
</a-form-item>
|
||||||
</div>
|
<a-form-item label="银行账号">
|
||||||
<div class="batch-tips" style="margin-top: 16px; color: #ff4d4f;">
|
<a-input
|
||||||
注意:批量开票将为所有选中的订单统一生成一张发票。
|
v-model:value="newTitleForm.bankAccount"
|
||||||
</div>
|
placeholder="请输入银行账号"
|
||||||
</div>
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onBeforeMount, computed } from 'vue'
|
import { ref, onBeforeMount, computed, reactive, nextTick } from 'vue'
|
||||||
import { usePagination } from '@/hooks'
|
import { usePagination } from '@/hooks'
|
||||||
import { useList } from '@/apis/admin'
|
import { useList } from '@/apis/admin'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { message } from 'ant-design-vue'
|
import { message, FormInstance } from 'ant-design-vue'
|
||||||
|
import type { Rule } from 'ant-design-vue/es/form'
|
||||||
|
|
||||||
|
// 模拟表格数据
|
||||||
|
const mockData = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
serial_number: 'SN202312270001',
|
||||||
|
created_at: '2023-12-27 10:30:00',
|
||||||
|
host_id: 'HOST-001',
|
||||||
|
host_case_id: 'CASE-001',
|
||||||
|
computing_power_model: 'RTX 4090',
|
||||||
|
gpu_count: 2,
|
||||||
|
billing_start: '2023-12-27 10:00:00',
|
||||||
|
billing_end: '2023-12-27 11:00:00',
|
||||||
|
bill_time: '1小时',
|
||||||
|
price: '50.00',
|
||||||
|
real_amount: '100.00',
|
||||||
|
status: '待开票'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
serial_number: 'SN202312270002',
|
||||||
|
created_at: '2023-12-27 11:45:00',
|
||||||
|
host_id: 'HOST-002',
|
||||||
|
host_case_id: 'CASE-002',
|
||||||
|
computing_power_model: 'RTX 4080',
|
||||||
|
gpu_count: 1,
|
||||||
|
billing_start: '2023-12-27 11:30:00',
|
||||||
|
billing_end: '2023-12-27 12:30:00',
|
||||||
|
bill_time: '1小时',
|
||||||
|
price: '40.00',
|
||||||
|
real_amount: '40.00',
|
||||||
|
status: '待开票'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
serial_number: 'SN202312270003',
|
||||||
|
created_at: '2023-12-27 14:20:00',
|
||||||
|
host_id: 'HOST-003',
|
||||||
|
host_case_id: 'CASE-003',
|
||||||
|
computing_power_model: 'RTX 3090',
|
||||||
|
gpu_count: 4,
|
||||||
|
billing_start: '2023-12-27 14:00:00',
|
||||||
|
billing_end: '2023-12-27 15:00:00',
|
||||||
|
bill_time: '1小时',
|
||||||
|
price: '30.00',
|
||||||
|
real_amount: '120.00',
|
||||||
|
status: '已开票'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
serial_number: 'SN202312270004',
|
||||||
|
created_at: '2023-12-27 16:15:00',
|
||||||
|
host_id: 'HOST-004',
|
||||||
|
host_case_id: 'CASE-004',
|
||||||
|
computing_power_model: 'A100',
|
||||||
|
gpu_count: 2,
|
||||||
|
billing_start: '2023-12-27 16:00:00',
|
||||||
|
billing_end: '2023-12-27 17:00:00',
|
||||||
|
bill_time: '1小时',
|
||||||
|
price: '80.00',
|
||||||
|
real_amount: '160.00',
|
||||||
|
status: '待开票'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
serial_number: 'SN202312270005',
|
||||||
|
created_at: '2023-12-27 18:30:00',
|
||||||
|
host_id: 'HOST-005',
|
||||||
|
host_case_id: 'CASE-005',
|
||||||
|
computing_power_model: 'H100',
|
||||||
|
gpu_count: 1,
|
||||||
|
billing_start: '2023-12-27 18:00:00',
|
||||||
|
billing_end: '2023-12-27 19:00:00',
|
||||||
|
bill_time: '1小时',
|
||||||
|
price: '100.00',
|
||||||
|
real_amount: '100.00',
|
||||||
|
status: '待开票'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
// 表格数据
|
// 表格数据
|
||||||
const { listData, paginationState, resetPagination, searchFormData } = usePagination()
|
const { listData, paginationState, resetPagination, searchFormData } = usePagination()
|
||||||
@ -183,13 +400,67 @@ const selectedRows = ref<any[]>([])
|
|||||||
|
|
||||||
// 模态框状态
|
// 模态框状态
|
||||||
const singleInvoiceModalVisible = ref(false)
|
const singleInvoiceModalVisible = ref(false)
|
||||||
const batchInvoiceModalVisible = ref(false)
|
const addTitleModalVisible = ref(false)
|
||||||
const singleInvoiceLoading = ref(false)
|
const singleInvoiceLoading = ref(false)
|
||||||
const batchInvoiceLoading = ref(false)
|
const isBatch = ref(false) // 是否为批量开票
|
||||||
|
|
||||||
// 当前操作的开票记录
|
// 当前操作的开票记录
|
||||||
const currentInvoiceRecord = ref<any>(null)
|
const currentInvoiceRecord = ref<any>(null)
|
||||||
|
|
||||||
|
// 表单引用
|
||||||
|
const invoiceFormRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
// 发票抬头选项
|
||||||
|
const invoiceTitleOptions = ref([
|
||||||
|
{ value: 'company1', label: '北京科技有限公司' },
|
||||||
|
{ value: 'company2', label: '上海信息技术有限公司' },
|
||||||
|
{ value: 'company3', label: '广州人工智能有限公司' },
|
||||||
|
{ value: 'company4', label: '深圳云计算有限公司' }
|
||||||
|
])
|
||||||
|
|
||||||
|
// 新增发票抬头表单
|
||||||
|
const newTitleForm = reactive({
|
||||||
|
companyName: '',
|
||||||
|
taxNumber: '',
|
||||||
|
address: '',
|
||||||
|
bank: '',
|
||||||
|
bankAccount: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 发票表单数据
|
||||||
|
const invoiceFormData = reactive({
|
||||||
|
invoiceType: undefined,
|
||||||
|
billingType: undefined,
|
||||||
|
titleType: 'company',
|
||||||
|
invoiceTitle: undefined,
|
||||||
|
personalTitle: '',
|
||||||
|
taxNumber: '',
|
||||||
|
remark: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const invoiceFormRules = reactive<Record<string, Rule[]>>({
|
||||||
|
invoiceType: [
|
||||||
|
{ required: true, message: '请选择发票类型', trigger: 'change' }
|
||||||
|
],
|
||||||
|
billingType: [
|
||||||
|
{ required: true, message: '请选择开票类型', trigger: 'change' }
|
||||||
|
],
|
||||||
|
titleType: [
|
||||||
|
{ required: true, message: '请选择抬头类型', trigger: 'change' }
|
||||||
|
],
|
||||||
|
invoiceTitle: [
|
||||||
|
{ required: true, message: '请选择发票抬头', trigger: 'change' }
|
||||||
|
],
|
||||||
|
personalTitle: [
|
||||||
|
{ required: true, message: '请输入个人姓名', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
taxNumber: [
|
||||||
|
{ required: true, message: '请输入纳税人识别号', trigger: 'blur' },
|
||||||
|
{ pattern: /^[A-Z0-9]{15}$|^[A-Z0-9]{18}$|^[A-Z0-9]{20}$/, message: '请输入正确的纳税人识别号' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
// 表格列定义
|
// 表格列定义
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
{ title: '流水号', dataIndex: 'serial_number', key: 'serial_number' },
|
{ title: '流水号', dataIndex: 'serial_number', key: 'serial_number' },
|
||||||
@ -202,6 +473,7 @@ const columns = ref([
|
|||||||
{ title: '计费时长', dataIndex: 'bill_time', key: 'bill_time' },
|
{ title: '计费时长', dataIndex: 'bill_time', key: 'bill_time' },
|
||||||
{ title: '单价', dataIndex: 'price', key: 'price' },
|
{ title: '单价', dataIndex: 'price', key: 'price' },
|
||||||
{ title: '交易金额', dataIndex: 'real_amount', key: 'real_amount' },
|
{ title: '交易金额', dataIndex: 'real_amount', key: 'real_amount' },
|
||||||
|
{ title: '状态', dataIndex: 'status', key: 'status' },
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
@ -210,13 +482,6 @@ const columns = ref([
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
// 批量开票模态框表格列
|
|
||||||
const selectedColumns = ref([
|
|
||||||
{ title: '流水号', dataIndex: 'serial_number', key: 'serial_number', width: 120 },
|
|
||||||
{ title: '交易时间', dataIndex: 'created_at', key: 'created_at', width: 150 },
|
|
||||||
{ title: '交易金额', dataIndex: 'real_amount', key: 'real_amount', width: 100, align: 'right' }
|
|
||||||
])
|
|
||||||
|
|
||||||
// 行选择配置
|
// 行选择配置
|
||||||
const rowSelection = computed(() => ({
|
const rowSelection = computed(() => ({
|
||||||
selectedRowKeys: selectedRowKeys.value,
|
selectedRowKeys: selectedRowKeys.value,
|
||||||
@ -225,7 +490,7 @@ const rowSelection = computed(() => ({
|
|||||||
selectedRows.value = selectedRows
|
selectedRows.value = selectedRows
|
||||||
},
|
},
|
||||||
getCheckboxProps: (record: any) => ({
|
getCheckboxProps: (record: any) => ({
|
||||||
disabled: record.status === '已开票' // 可以根据状态禁用已开票的记录
|
disabled: record.status === '已开票'
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -237,13 +502,16 @@ const selectedTotalAmount = computed(() => {
|
|||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取选中记录的数据
|
// 初始化模拟数据
|
||||||
const selectedInvoiceRecords = computed(() => {
|
const initMockData = () => {
|
||||||
return selectedRows.value
|
listData.value = mockData
|
||||||
})
|
paginationState.total = mockData.length
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
getPageList()
|
// 初始化模拟数据
|
||||||
|
initMockData()
|
||||||
|
// 如果需要真实数据,可以调用 getPageList()
|
||||||
})
|
})
|
||||||
|
|
||||||
const getPageList = async () => {
|
const getPageList = async () => {
|
||||||
@ -255,6 +523,8 @@ const getPageList = async () => {
|
|||||||
console.log('订单列表:', res)
|
console.log('订单列表:', res)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('产品优势请求失败:', error)
|
console.error('产品优势请求失败:', error)
|
||||||
|
// 如果API请求失败,使用模拟数据
|
||||||
|
initMockData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,33 +563,11 @@ function handleResetSearch() {
|
|||||||
*/
|
*/
|
||||||
function handleSingleInvoice(record: any) {
|
function handleSingleInvoice(record: any) {
|
||||||
currentInvoiceRecord.value = record
|
currentInvoiceRecord.value = record
|
||||||
|
isBatch.value = false
|
||||||
|
resetInvoiceForm()
|
||||||
singleInvoiceModalVisible.value = true
|
singleInvoiceModalVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 确认单个开票
|
|
||||||
*/
|
|
||||||
async function handleSingleInvoiceConfirm() {
|
|
||||||
singleInvoiceLoading.value = true
|
|
||||||
try {
|
|
||||||
// 这里调用开票API
|
|
||||||
// await invoiceApi.createSingleInvoice(currentInvoiceRecord.value.id)
|
|
||||||
|
|
||||||
// 模拟API调用延迟
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
||||||
|
|
||||||
message.success('开票申请已提交成功!')
|
|
||||||
singleInvoiceModalVisible.value = false
|
|
||||||
|
|
||||||
// 刷新列表
|
|
||||||
getPageList()
|
|
||||||
} catch (error) {
|
|
||||||
message.error('开票申请提交失败,请稍后重试')
|
|
||||||
} finally {
|
|
||||||
singleInvoiceLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量去开票
|
* 批量去开票
|
||||||
*/
|
*/
|
||||||
@ -328,23 +576,89 @@ function handleBatchInvoice() {
|
|||||||
message.warning('请先选择要开票的记录')
|
message.warning('请先选择要开票的记录')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
batchInvoiceModalVisible.value = true
|
isBatch.value = true
|
||||||
|
resetInvoiceForm()
|
||||||
|
singleInvoiceModalVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确认批量开票
|
* 重置发票表单
|
||||||
*/
|
*/
|
||||||
async function handleBatchInvoiceConfirm() {
|
function resetInvoiceForm() {
|
||||||
batchInvoiceLoading.value = true
|
invoiceFormData.invoiceType = undefined
|
||||||
|
invoiceFormData.billingType = undefined
|
||||||
|
invoiceFormData.titleType = 'company'
|
||||||
|
invoiceFormData.invoiceTitle = undefined
|
||||||
|
invoiceFormData.personalTitle = ''
|
||||||
|
invoiceFormData.taxNumber = ''
|
||||||
|
invoiceFormData.remark = ''
|
||||||
|
|
||||||
|
// 清除表单验证状态
|
||||||
|
nextTick(() => {
|
||||||
|
invoiceFormRef.value?.clearValidate()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭开票模态框
|
||||||
|
*/
|
||||||
|
function handleInvoiceModalCancel() {
|
||||||
|
singleInvoiceModalVisible.value = false
|
||||||
|
resetInvoiceForm()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认开票
|
||||||
|
*/
|
||||||
|
async function handleSingleInvoiceConfirm() {
|
||||||
try {
|
try {
|
||||||
// 这里调用批量开票API
|
// 验证表单
|
||||||
// await invoiceApi.createBatchInvoice(selectedRowKeys.value)
|
await invoiceFormRef.value?.validate()
|
||||||
|
|
||||||
|
singleInvoiceLoading.value = true
|
||||||
|
|
||||||
|
// 根据抬头类型获取抬头信息
|
||||||
|
const titleInfo = invoiceFormData.titleType === 'company'
|
||||||
|
? {
|
||||||
|
titleType: 'company',
|
||||||
|
companyName: invoiceFormData.invoiceTitle,
|
||||||
|
taxNumber: invoiceFormData.taxNumber
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
titleType: 'personal',
|
||||||
|
personalName: invoiceFormData.personalTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备开票数据
|
||||||
|
const invoiceData = {
|
||||||
|
...titleInfo,
|
||||||
|
invoiceType: invoiceFormData.invoiceType,
|
||||||
|
billingType: invoiceFormData.billingType,
|
||||||
|
remark: invoiceFormData.remark,
|
||||||
|
orders: isBatch.value
|
||||||
|
? selectedRows.value.map(row => ({
|
||||||
|
id: row.id,
|
||||||
|
serialNumber: row.serial_number,
|
||||||
|
amount: row.real_amount
|
||||||
|
}))
|
||||||
|
: [{
|
||||||
|
id: currentInvoiceRecord.value.id,
|
||||||
|
serialNumber: currentInvoiceRecord.value.serial_number,
|
||||||
|
amount: currentInvoiceRecord.value.real_amount
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('提交开票数据:', invoiceData)
|
||||||
|
|
||||||
// 模拟API调用延迟
|
// 模拟API调用延迟
|
||||||
await new Promise(resolve => setTimeout(resolve, 1500))
|
await new Promise(resolve => setTimeout(resolve, 1500))
|
||||||
|
|
||||||
message.success(`批量开票申请已提交成功,共 ${selectedRowKeys.value.length} 条记录`)
|
const successMessage = isBatch.value
|
||||||
batchInvoiceModalVisible.value = false
|
? `批量开票申请已提交成功,共 ${selectedRows.value.length} 条记录`
|
||||||
|
: '开票申请已提交成功!'
|
||||||
|
|
||||||
|
message.success(successMessage)
|
||||||
|
singleInvoiceModalVisible.value = false
|
||||||
|
|
||||||
// 清空选择
|
// 清空选择
|
||||||
selectedRowKeys.value = []
|
selectedRowKeys.value = []
|
||||||
@ -352,11 +666,65 @@ async function handleBatchInvoiceConfirm() {
|
|||||||
|
|
||||||
// 刷新列表
|
// 刷新列表
|
||||||
getPageList()
|
getPageList()
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('批量开票申请提交失败,请稍后重试')
|
console.error('表单验证失败:', error)
|
||||||
} finally {
|
if (error && typeof error === 'object' && 'errorFields' in error) {
|
||||||
batchInvoiceLoading.value = false
|
message.error('请完善开票信息')
|
||||||
|
} else {
|
||||||
|
const errorMessage = isBatch.value
|
||||||
|
? '批量开票申请提交失败,请稍后重试'
|
||||||
|
: '开票申请提交失败,请稍后重试'
|
||||||
|
message.error(errorMessage)
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
singleInvoiceLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索发票抬头
|
||||||
|
*/
|
||||||
|
function handleSearchInvoiceTitle(value: string) {
|
||||||
|
console.log('搜索发票抬头:', value)
|
||||||
|
// 这里可以实现搜索逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加发票抬头
|
||||||
|
*/
|
||||||
|
function handleAddInvoiceTitle() {
|
||||||
|
addTitleModalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认新增发票抬头
|
||||||
|
*/
|
||||||
|
function handleAddTitleConfirm() {
|
||||||
|
if (!newTitleForm.companyName || !newTitleForm.taxNumber) {
|
||||||
|
message.error('请填写公司名称和纳税人识别号')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到选项列表
|
||||||
|
const newOption = {
|
||||||
|
value: newTitleForm.companyName,
|
||||||
|
label: newTitleForm.companyName
|
||||||
|
}
|
||||||
|
|
||||||
|
invoiceTitleOptions.value.push(newOption)
|
||||||
|
|
||||||
|
// 设置当前选择的发票抬头
|
||||||
|
invoiceFormData.invoiceTitle = newTitleForm.companyName
|
||||||
|
invoiceFormData.taxNumber = newTitleForm.taxNumber
|
||||||
|
|
||||||
|
// 重置表单并关闭模态框
|
||||||
|
Object.keys(newTitleForm).forEach(key => {
|
||||||
|
newTitleForm[key] = ''
|
||||||
|
})
|
||||||
|
addTitleModalVisible.value = false
|
||||||
|
|
||||||
|
message.success('发票抬头添加成功')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -367,75 +735,118 @@ async function handleBatchInvoiceConfirm() {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invoice-confirm-content {
|
.invoice-modal-content {
|
||||||
padding: 8px 0;
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm-item {
|
.order-info-section,
|
||||||
display: flex;
|
.invoice-info-section {
|
||||||
justify-content: space-between;
|
margin-bottom: 24px;
|
||||||
margin-bottom: 12px;
|
border: 1px solid #e8e8e8;
|
||||||
padding-bottom: 12px;
|
border-radius: 8px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
padding: 20px;
|
||||||
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm-item:last-child {
|
.section-title {
|
||||||
border-bottom: none;
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-label {
|
|
||||||
color: #666;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-value {
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm-tips {
|
|
||||||
margin-top: 16px;
|
|
||||||
padding: 12px;
|
|
||||||
background-color: #f6ffed;
|
|
||||||
border-radius: 6px;
|
|
||||||
color: #52c41a;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.batch-invoice-content .selected-count {
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 16px;
|
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-amount {
|
.order-info-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-info-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background-color: #fafafa;
|
background: #fafafa;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-label {
|
.info-label {
|
||||||
font-size: 16px;
|
color: #666;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-value {
|
.total-amount {
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.batch-tips {
|
.order-list-preview {
|
||||||
font-size: 14px;
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-title {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-list {
|
||||||
|
max-height: 120px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-more {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
color: #999;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-form {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义滚动条 */
|
||||||
|
.invoice-modal-content::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-modal-content::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-modal-content::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invoice-modal-content::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 适配响应式 */
|
/* 适配响应式 */
|
||||||
@ -446,10 +857,26 @@ async function handleBatchInvoiceConfirm() {
|
|||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-amount {
|
.order-info-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-info-item {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 8px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 必填字段标记 */
|
||||||
|
:deep(.ant-form-item-required::before) {
|
||||||
|
content: '*';
|
||||||
|
color: #ff4d4f;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单间距优化 */
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user