|
|
@@ -0,0 +1,297 @@
|
|
|
+<template>
|
|
|
+ <div class="page-container">
|
|
|
+ <div class="page-header">
|
|
|
+ <el-button type="primary" link @click="handleBack">
|
|
|
+ <el-icon><ArrowLeft /></el-icon>返回
|
|
|
+ </el-button>
|
|
|
+ <span class="page-title">销售发票详情</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-loading="loading" class="drawer-content">
|
|
|
+ <el-form ref="formRef" :model="form" label-width="120px">
|
|
|
+ <!-- 基本信息 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">基本信息</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="开票单号:" prop="statementInvoiceNo">
|
|
|
+ <el-input v-model="form.statementInvoiceNo" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="开票状态:" prop="invoiceStatus">
|
|
|
+ {{ getDictLabel(invoice_status, form.invoiceStatus) }}
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="客户名称:" prop="customerName">
|
|
|
+ <el-input v-model="form.customerName" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="开票金额:" prop="invoiceAmount">
|
|
|
+ <el-input v-model="form.invoiceAmount" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="开票日期:" prop="invoiceTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="form.invoiceTime"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择开票日期"
|
|
|
+ style="width: 100%"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ disabled
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 账单列表 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">账单列表</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <el-table :data="form.detailList" border style="width: 100%; margin-bottom: 20px">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
+ <el-table-column prop="statementOrderNo" label="对账单编号" min-width="150" align="center" />
|
|
|
+ <el-table-column prop="statementAmount" label="对账金额" min-width="120" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.statementAmount != null ? Number(row.statementAmount).toFixed(2) : '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="orderNo" label="订单编号" min-width="150" align="center" />
|
|
|
+ <el-table-column prop="orderAmount" label="金额" min-width="120" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.orderAmount != null ? Number(row.orderAmount).toFixed(2) : '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="orderTime" label="下单日期" min-width="120" align="center" />
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 商品清单 -->
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">商品清单</span>
|
|
|
+ </el-divider>
|
|
|
+
|
|
|
+ <el-table :data="pagedProductList" border style="width: 100%; margin-bottom: 20px">
|
|
|
+ <el-table-column
|
|
|
+ type="index"
|
|
|
+ label="序号"
|
|
|
+ width="60"
|
|
|
+ align="center"
|
|
|
+ :index="(index) => (productPage.pageNum - 1) * productPage.pageSize + index + 1"
|
|
|
+ />
|
|
|
+ <el-table-column prop="orderNo" label="订单编号" min-width="120" align="center" />
|
|
|
+ <el-table-column prop="productNo" label="商品编号" min-width="120" align="center" />
|
|
|
+ <el-table-column prop="itemName" label="商品名称" min-width="180" align="center" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="unitName" label="单位" align="center" />
|
|
|
+ <el-table-column prop="quantity" label="数量" align="center" />
|
|
|
+ <el-table-column prop="unitPrice" label="单价" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.row.unitPrice ? Number(scope.row.unitPrice).toFixed(2) : '0.00' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="小计" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ (Number(scope.row.quantity || 0) * Number(scope.row.unitPrice || 0)).toFixed(2) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 商品清单分页 -->
|
|
|
+ <div class="pagination-wrapper">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="productPage.pageNum"
|
|
|
+ v-model:page-size="productPage.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50]"
|
|
|
+ :total="form.productList?.length || 0"
|
|
|
+ layout="prev, pager, next, sizes, jumper"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 发票附件 -->
|
|
|
+ <div v-if="form.invoiceList && form.invoiceList.length > 0">
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">发票信息</span>
|
|
|
+ </el-divider>
|
|
|
+ <el-table :data="form.invoiceList" border style="width: 100%; margin-bottom: 20px">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
+ <el-table-column prop="invoiceAmount" label="发票金额" min-width="120" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.invoiceAmount != null ? Number(row.invoiceAmount).toFixed(2) : '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="invoiceDate" label="发票日期" min-width="150" align="center" />
|
|
|
+ <el-table-column prop="invoiceType" label="发票类型" min-width="120" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ getDictLabel(invoice_type, row.invoiceType) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="150" align="center" fixed="right">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button type="primary" link @click="handlePreviewInvoice(row)" v-if="row.invoiceAnnex">预览</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 发票附件 -->
|
|
|
+ <div v-if="form.annexAddress">
|
|
|
+ <el-divider content-position="left">
|
|
|
+ <span style="color: #409eff; font-weight: 600">发票附件</span>
|
|
|
+ </el-divider>
|
|
|
+ <el-table :data="attachmentList" border style="width: 100%">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
+ <el-table-column prop="name" label="文件名称" min-width="200" align="center" />
|
|
|
+ <el-table-column label="操作" width="150" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button type="primary" link @click="handlePreview(row.url)">预览</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, computed, getCurrentInstance, toRefs, onMounted } from 'vue';
|
|
|
+import { useRoute, useRouter } from 'vue-router';
|
|
|
+import { ArrowLeft } from '@element-plus/icons-vue';
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+import { getStatementInvoice } from '@/api/pc/enterprise/statement';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance() as any;
|
|
|
+const { invoice_status, invoice_type } = toRefs<any>(proxy?.useDict('invoice_status', 'invoice_type'));
|
|
|
+
|
|
|
+const route = useRoute();
|
|
|
+const router = useRouter();
|
|
|
+const loading = ref(false);
|
|
|
+const form = ref<Record<string, any>>({
|
|
|
+ detailList: [],
|
|
|
+ productList: []
|
|
|
+});
|
|
|
+
|
|
|
+// 商品清单分页
|
|
|
+const productPage = ref({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10
|
|
|
+});
|
|
|
+
|
|
|
+// 分页后的商品列表
|
|
|
+const pagedProductList = computed(() => {
|
|
|
+ const list = form.value.productList || [];
|
|
|
+ const start = (productPage.value.pageNum - 1) * productPage.value.pageSize;
|
|
|
+ const end = start + productPage.value.pageSize;
|
|
|
+ return list.slice(start, end);
|
|
|
+});
|
|
|
+
|
|
|
+// 附件列表
|
|
|
+const attachmentList = computed(() => {
|
|
|
+ if (!form.value.annexAddress) return [];
|
|
|
+ const urls = form.value.annexAddress.split(',').filter(Boolean);
|
|
|
+ return urls.map((url: string, index: number) => {
|
|
|
+ const fileName = url.split('/').pop() || `附件${index + 1}`;
|
|
|
+ return {
|
|
|
+ name: decodeURIComponent(fileName),
|
|
|
+ url: url.trim()
|
|
|
+ };
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+const getDictLabel = (dictOptions: any[], value: string) => {
|
|
|
+ if (!dictOptions || !value) return value;
|
|
|
+ const dict = dictOptions.find((item) => item.value === value);
|
|
|
+ return dict ? dict.label : value;
|
|
|
+};
|
|
|
+
|
|
|
+// 预览附件
|
|
|
+const handlePreview = (url: string) => {
|
|
|
+ if (!url) {
|
|
|
+ ElMessage.warning('文件地址不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ window.open(url, '_blank');
|
|
|
+};
|
|
|
+
|
|
|
+// 预览发票附件
|
|
|
+const handlePreviewInvoice = (row: any) => {
|
|
|
+ if (!row.invoiceAnnex) {
|
|
|
+ ElMessage.warning('发票附件不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ window.open(row.invoiceAnnex, '_blank');
|
|
|
+};
|
|
|
+
|
|
|
+const handleBack = () => {
|
|
|
+ router.back();
|
|
|
+};
|
|
|
+
|
|
|
+const loadDetail = async (id: number | string) => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await getStatementInvoice(id);
|
|
|
+ if (res.code === 200) {
|
|
|
+ form.value = res.data || {};
|
|
|
+ // 确保数组存在
|
|
|
+ if (!form.value.detailList) form.value.detailList = [];
|
|
|
+ if (!form.value.productList) form.value.productList = [];
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg || '获取详情失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取销售发票详情失败:', error);
|
|
|
+ ElMessage.error('获取销售发票详情失败');
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const id = route.query.id;
|
|
|
+ if (id) {
|
|
|
+ loadDetail(id as string);
|
|
|
+ } else {
|
|
|
+ ElMessage.error('缺少发票ID');
|
|
|
+ handleBack();
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.page-container {
|
|
|
+ padding: 20px;
|
|
|
+ background: #fff;
|
|
|
+ min-height: 100%;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.page-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 25px;
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-content {
|
|
|
+ padding: 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination-wrapper {
|
|
|
+ margin-top: 16px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+}
|
|
|
+</style>
|