feat:财税管理-银行日记账&财税管理-进项发票联调

feature-JimuReport-1106-yjl
yujinlong 1 month ago
parent a9a3221153
commit 4fe3c2cf00

@ -0,0 +1,24 @@
// @ts-ignore
import { request } from '/@/utils/request'
import { DataResult, PageRequest } from '/@/api/model/baseModel'
enum Api {
bankList = '/feeApi/BankStatement/GetBankAccountList',
bankFlow = '/feeApi/BankStatement/GetBankStatementList',
}
// 获取银行卡列表 (Auth)
export function ApiBankList() {
return request<DataResult>({
url: Api.bankList,
method: 'post',
})
}
// 获取银行流水列表 (Auth)
export function ApiBankFlowList(data: PageRequest) {
return request<DataResult>({
url: Api.bankFlow,
method: 'post',
data,
})
}

@ -0,0 +1,316 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
export type BankItem = {
accountId: string
bankName: string
}
export const searchFormSchema: FormSchema[] = [
{
field: 'transactionType',
label: '交易类型',
component: 'Select',
dynamicDisabled: false,
defaultValue: '',
colProps: { span: 4 },
componentProps: () => {
return {
allowClear: false,
options: [
{ label: '全部', value: '' },
{ label: '来账', value: '来账' },
{ label: '往账', value: '往账' },
],
}
},
},
{
field: 'payerAccountNumber',
label: '银行账号',
component: 'Input',
colProps: { span: 4 },
},
{
field: 'payerName',
label: '付款人名称',
component: 'Input',
colProps: { span: 4 },
},
{
field: 'payDateTime',
label: '交易日期',
component: 'RangePicker',
colProps: { span: 4 },
componentProps: {
allowClear: true,
},
},
]
export const columns: BasicColumn[] = [
{
title: '交易日期',
align: 'center',
width: 100,
dataIndex: 'transactionDate',
sorter: true,
},
{
title: '交易时间',
align: 'center',
width: 100,
dataIndex: 'transactionTime',
sorter: true,
},
{
title: '交易类型',
width: 100,
dataIndex: 'transactionType',
sorter: true,
},
{
title: '业务类型',
align: 'center',
width: 100,
dataIndex: 'businessType',
sorter: true,
},
{
title: '交易金额',
width: 100,
dataIndex: 'tradeAmount',
sorter: true,
},
{
title: '交易后余额',
align: 'center',
width: 150,
dataIndex: 'afterTransactionBalance',
sorter: true,
},
{
title: '交易货币',
width: 80,
dataIndex: 'tradeCurrency',
sorter: true,
},
{
title: '客户名',
width: 200,
dataIndex: 'custom',
sorter: true,
},
{
title: '银行名',
width: 100,
dataIndex: 'bankName',
sorter: true,
},
{
title: '账户名',
width: 200,
dataIndex: 'accountName',
sorter: true,
},
{
title: '账户ID',
align: 'center',
width: 180,
dataIndex: 'accountId',
sorter: true,
},
{
title: '付款人名称',
width: 200,
dataIndex: 'payerName',
sorter: true,
},
{
title: '付款人账号',
width: 180,
dataIndex: 'payerAccountNumber',
sorter: true,
},
{
title: '付款人开户行号',
width: 180,
dataIndex: 'accountHoldingBankNumberOfPayer',
sorter: true,
},
{
title: '付款人开户行名',
width: 180,
dataIndex: 'payerAccountBank',
sorter: true,
},
{
title: '收款人开户行行号',
width: 180,
dataIndex: 'accountHoldingBankNumberOfPayee',
sorter: true,
},
{
title: '收款人开户行名',
width: 180,
dataIndex: 'payeeAccountBank',
sorter: true,
},
{
title: '收款人账号',
width: 150,
dataIndex: 'payeeAccountNumber',
sorter: true,
},
{
title: '收款人名称',
width: 180,
dataIndex: 'payeeName',
sorter: true,
},
{
title: '起息日期',
width: 100,
dataIndex: 'valueDate',
sorter: true,
},
{
title: '汇率',
width: 100,
dataIndex: 'exchangeRate',
sorter: true,
},
{
title: '交易流水号',
width: 120,
dataIndex: 'transactionReferenceNumber',
sorter: true,
},
{
title: '客户申请号',
width: 120,
dataIndex: 'onlineBankingTransactionRef',
sorter: true,
},
{
title: '客户业务编号',
width: 120,
dataIndex: 'customerTransactionRef',
sorter: true,
},
{
title: '凭证类型',
width: 150,
dataIndex: 'voucherType',
sorter: true,
},
{
title: '凭证号码',
width: 180,
dataIndex: 'voucherNumber',
sorter: true,
},
{
title: '记录标识号',
width: 180,
dataIndex: 'recordID',
sorter: true,
},
{
title: '摘要',
width: 200,
dataIndex: 'reference',
ellipsis: true,
sorter: true,
},
{
title: '用途',
width: 200,
dataIndex: 'purpose',
ellipsis: true,
sorter: true,
},
{
title: '交易附言',
width: 200,
dataIndex: 'remark',
ellipsis: true,
sorter: true,
},
{
title: '备注',
width: 200,
dataIndex: 'remarks',
ellipsis: true,
sorter: true,
},
{
title: '名义付款人开户行行号',
width: 180,
dataIndex: 'openingBankNumberOfNominalPayer',
sorter: true,
},
{
title: '名义付款人开户行名',
width: 180,
dataIndex: 'openingBankNameOfNominalPayer',
sorter: true,
},
{
title: '名义付款人账号',
width: 180,
dataIndex: 'accountNumberOfNominalPayer',
sorter: true,
},
{
title: '名义付款人名称',
width: 180,
dataIndex: 'nameOfNominalPayer',
sorter: true,
},
{
title: '名义收款人开户行号',
width: 180,
dataIndex: 'openingBankNumberOfNominalPayee',
sorter: true,
},
{
title: '名义收款人开户行名',
width: 180,
dataIndex: 'openingBankNameOfNominalPayee',
sorter: true,
},
{
title: '名义收款人账号',
width: 180,
dataIndex: 'accountNumberOfNominalPayee',
sorter: true,
},
{
title: '名义收款人名称',
width: 180,
dataIndex: 'nameOfNominalPayee',
sorter: true,
},
{
title: '预留项1',
width: 150,
dataIndex: 'reserve1',
sorter: true,
},
{
title: '预留项2',
width: 150,
dataIndex: 'reserve2',
sorter: true,
},
{
title: '预留项3',
width: 150,
dataIndex: 'reserve3',
sorter: true,
},
]
export const bankNoFormat = (bankNo) => {
return bankNo.replace(/\s/g, '').replace(/(.{4})/g, '$1 ')
}

@ -0,0 +1,203 @@
<template>
<div class="main">
<div style="width: 100%">
<BasicTable class="ds-table-detail" @register="registerTable">
<template #left>
<div class="nav-box">
<div class="module-title">银行账户</div>
<a-spin :spinning="bankLoading" tip="加载中...">
<div class="nav-content-box">
<div
class="bank-item"
v-for="item in bankList"
:key="item.accountId"
:style="{
background: activeBank == item.accountId ? '#F5F9FC' : '',
color: activeBank == item.accountId ? '#257AFA' : '',
}"
@click="changeActiveBank(item.accountId)"
>
<i
class="iconfont icon-yinhangzhanghu"
:style="{ color: activeBank == item.accountId ? '#257AFA' : '#7A8798' }"
></i>
<span class="bank-name">{{ item.bankName }}</span>
<span>{{ bankNoFormat(item.accountId) }}</span>
</div>
</div>
</a-spin>
</div>
</template>
<template #tableTitle>
<div class="module-title">流水详情</div>
</template>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.key === 'tradeAmount'">
<span v-if="record.transactionType == '来账'" class="success">
{{ record.tradeAmount }}
</span>
<span v-if="record.transactionType == '往账'" class="error">
{{ record.tradeAmount }}
</span>
</template>
<template v-if="column.key === 'action'">
<TableAction :actions="getActionOptList(record)" />
</template>
</template>
</BasicTable>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import type { BankItem } from './columns'
import { columns, searchFormSchema, bankNoFormat } from './columns'
import { BasicTable, useTable, TableAction, ActionItem } from '/@/components/Table'
import { useMessage } from '/@/hooks/web/useMessage'
const { createMessage } = useMessage()
import { ApiBankList, ApiBankFlowList } from './api'
import { formatParams } from '/@/hooks/web/common'
const [registerTable, { reload, getForm }] = useTable({
api: async (p) => {
const res: API.DataResult = await ApiBankFlowList(p)
return new Promise((resolve) => {
resolve({
data: res.data,
total: res.count,
})
})
},
beforeFetch: (p) => {
return formatParams({ ...p, accountId: activeBank.value })
},
immediate: false,
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
submitFunc: handleNext,
resetFunc: handleReset,
},
isTreeTable: false,
pagination: true,
striped: true,
useSearchForm: true,
bordered: true,
showIndexColumn: true,
showTableSetting: true,
indexColumnProps: {
width: 60,
},
canResize: true,
resizeHeightOffset: 35,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
})
const bankLoading = ref(false)
const bankList = ref<BankItem[]>([])
const activeBank = ref('')
const getBankList = async () => {
bankLoading.value = true
const res: API.DataResult = await ApiBankList()
console.log(res)
activeBank.value = res.data?.[0]?.accountId || ''
reload()
bankList.value = res.data
bankLoading.value = false
}
const changeActiveBank = (no) => {
activeBank.value = no
reload()
}
function handleNext() {
reload()
}
function handleReset() {
getBankList()
}
const getActionOptList = (record): ActionItem[] => {
return [
{
icon: h('i', {
class: 'iconfont icon-xiazai',
style: { color: '#257afa', fontSize: '14px' },
}),
isCustomIcon: true,
tooltip: '下载',
onClick: handleDownload.bind(null, record),
},
]
}
//
function handleDownload(row) {
const filePath = row.filePaths ? JSON.parse(row.filePaths) : null
if (!filePath || (filePath && !filePath?.pdf)) {
return createMessage.warning('暂未获取到相关文件')
}
if (filePath && filePath?.pdf) {
window.open(filePath.pdf, '_blank')
}
}
onMounted(() => {
getBankList()
})
</script>
<style lang="less" scoped>
:deep(.ant-table.ant-table-bordered > .ant-table-container) {
border-left: none !important;
}
.main {
display: flex;
.module-title {
font-size: 12px;
font-weight: 700;
letter-spacing: 1px;
color: #33383d;
}
.nav-box {
padding: 8px 8px;
background: #fff;
border-radius: 2px;
width: 20%;
flex-shrink: 0;
margin-top: 4px;
.nav-content-box {
margin-top: 16px;
padding: 18px 12px;
border: 1px solid #e8ebed;
.bank-item {
display: flex;
justify-content: flex-start;
align-items: center;
color: #33383d;
font-size: 12px;
font-weight: 400;
padding: 4px;
box-sizing: border-box;
border-radius: 2px;
background: #ffffff;
cursor: pointer;
.bank-name {
margin: 0 6px;
}
}
}
}
.success {
color: #17a6a3;
}
.error {
color: #ba3849;
}
}
</style>

@ -0,0 +1,23 @@
import { request } from '/@/utils/request'
import { DataResult, PageRequest } from '/@/api/model/baseModel'
enum Api {
list = '/feeApi/InInvoicet/GetInInvoicet',
info = '/feeApi/InInvoicet/GetInInvoicetDetail',
}
// 列表 (Auth)
export function GetList(data: PageRequest) {
return request<DataResult>({
url: Api.list,
method: 'post',
data
})
}
// 详情 (Auth)
export function GetInfo(data) {
return request<DataResult>({
url: Api.info,
method: 'post',
data
})
}

@ -0,0 +1,361 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
export const invoiceCodeList: LabelValueOptions = [
{ label: '全电发票(铁路电子客票)', value: '51' },
{ label: '全电发票(航空运输电子客票行程单)', value: '61' },
{ label: '全电发票(增值税专用发票)', value: '81' },
{ label: '全电发票(普通发票)', value: '82' },
{ label: '全电纸质发票(增值税专用发票)', value: '85' },
{ label: '全电纸质发票(普通发票)', value: '86' },
{ label: '增值税电子普票发票', value: '026' },
{ label: '增值税电子专用发票', value: '028' },
{ label: '增值税普通发票', value: '007' },
{ label: '增值税专用发票', value: '004' },
{ label: '税控卷票', value: '025' },
]
export const invoiceStatusList: LabelValueOptions = [
{ label: '蓝票', value: '00' },
{ label: '红票', value: '01' },
]
export const columns: BasicColumn[] = [
{
title: '发票号码',
dataIndex: 'invoiceNumber',
width: 200,
sorter: true,
},
{
title: '发票类型代码',
dataIndex: 'invoiceTypeCode',
width: 180,
sorter: true,
customRender({ text }) {
return invoiceCodeList.find((el) => el.value === text)?.label || ''
},
},
{
title: '开票时间',
dataIndex: 'invoicingDate',
sorter: true,
width: 150,
},
{
title: '合计金额',
dataIndex: 'totalAmount',
sorter: true,
width: 100,
},
{
title: '合计税额',
dataIndex: 'totalTax',
width: 100,
sorter: true,
},
{
title: '价税合计',
dataIndex: 'totalWithTax',
width: 100,
sorter: true,
},
{
title: '发票状态',
dataIndex: 'invoiceStatus',
width: 100,
sorter: true,
customRender: ({ text }) => {
return invoiceStatusList.find((el) => el.value === text)?.label || '未知'
},
},
{
title: '开票人',
dataIndex: 'invoicer',
width: 80,
sorter: true,
},
{
title: '原发票号码',
dataIndex: 'originalInvoiceNumber',
width: 200,
sorter: true,
},
{
title: '购方开票名称',
dataIndex: 'buyerInvoiceName',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '购方开票税号',
dataIndex: 'buyerInvoiceTaxNumber',
width: 200,
sorter: true,
},
{
title: '销方开票名称',
dataIndex: 'sellerInvoiceName',
width: 130,
sorter: true,
},
{
title: '销方开票税号',
dataIndex: 'sellerInvoiceTaxNumber',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '是否已获取详情',
dataIndex: 'isDetailObtained',
width: 120,
align: 'center',
sorter: true,
},
{
title: '销方识别号',
dataIndex: 'sellerIdentificationNumber',
width: 200,
sorter: true,
},
{
title: '最终校验码',
dataIndex: 'finalCheckCode',
width: 130,
sorter: true,
},
{
title: '购方名称',
dataIndex: 'buyerName',
width: 200,
sorter: true,
},
{
title: '当前时间',
dataIndex: 'currentTime',
sorter: true,
width: 150,
},
{
title: '扣除额',
dataIndex: 'deductionAmount',
width: 100,
sorter: true,
},
{
title: '机动车发票类型代码',
dataIndex: 'vehicleInvoiceTypeCode',
width: 200,
sorter: true,
},
{
title: '税控码',
dataIndex: 'taxControlCode',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '购方税号',
dataIndex: 'buyerTaxNumber',
width: 200,
sorter: true,
},
{
title: '纸质发票号码',
dataIndex: 'paperInvoiceNumber',
width: 200,
sorter: true,
},
{
title: '收款人',
dataIndex: 'payee',
width: 100,
sorter: true,
},
{
title: '清单标志',
dataIndex: 'itemFlag',
width: 120,
sorter: true,
},
{
title: '开票单位代码',
dataIndex: 'invoiceUnitCode',
width: 200,
sorter: true,
},
{
title: '购方银行账户',
dataIndex: 'buyerBankAccount',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '购方银行账号',
dataIndex: 'buyerBankAccountNumber',
width: 200,
sorter: true,
},
{
title: '金额',
dataIndex: 'amount',
width: 100,
sorter: true,
},
{
title: '销方名称',
dataIndex: 'sellerName',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '特定要素',
dataIndex: 'specialElements',
width: 100,
sorter: true,
},
{
title: '特定要素类型代码',
dataIndex: 'specialElementTypeCode',
width: 200,
sorter: true,
},
{
title: '报销状态',
dataIndex: 'reimbursementStatus',
width: 100,
sorter: true,
},
{
title: '操作员代码',
dataIndex: 'operatorCode',
width: 200,
sorter: true,
},
{
title: '购方地址电话',
dataIndex: 'buyerAddressPhone',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '是否为纸质发票',
dataIndex: 'isPaperInvoice',
width: 120,
align: 'center',
sorter: true,
},
{
title: '发票请求流水号',
dataIndex: 'invoiceRequestNumber',
width: 200,
sorter: true,
},
{
title: '税额',
dataIndex: 'taxAmount',
width: 100,
sorter: true,
},
{
title: '备注',
dataIndex: 'remarks',
width: 200,
ellipsis: true,
sorter: true,
},
{
title: '购方识别号',
dataIndex: 'buyerIdentificationNumber',
width: 200,
sorter: true,
},
{
title: '购方名称',
dataIndex: 'buyerFullName',
width: 200,
sorter: true,
},
{
title: '销方税号',
dataIndex: 'sellerTaxNumber',
width: 200,
sorter: true,
},
{
title: '发票代码',
dataIndex: 'invoiceCode',
width: 160,
sorter: true,
},
{
title: '销方地址电话',
dataIndex: 'sellerAddressPhone',
width: 200,
sorter: true,
},
{
title: '销方银行账号',
dataIndex: 'sellerBankAccountNumber',
width: 200,
sorter: true,
},
{
title: '复核人',
dataIndex: 'reviewer',
width: 100,
sorter: true,
},
{
title: '机器编号',
dataIndex: 'machineCode',
width: 100,
sorter: true,
},
{
title: '商品或服务名称',
dataIndex: 'itemOrServiceName',
width: 200,
sorter: true,
},
{
title: '销方银行账户',
dataIndex: 'sellerBankAccount',
width: 200,
sorter: true,
},
]
export const searchFormSchema: FormSchema[] = [
{
field: 'invoiceNumber',
label: '发票号码',
colProps: { span: 4 },
component: 'Input',
},
{
field: 'buyerInvoiceTaxNumber',
label: '购方开票税号',
colProps: { span: 4 },
component: 'Input',
},
{
field: 'buyerInvoiceName',
label: '购方开票名称',
colProps: { span: 4 },
component: 'Input',
},
{
field: 'invoicingDate',
label: '开票时间',
component: 'RangePicker',
colProps: { span: 4 },
componentProps: {
allowClear: true,
},
},
]

@ -0,0 +1,204 @@
import { invoiceCodeList, invoiceStatusList } from '../columns'
import { BasicColumn } from '/@/components/Table'
import moment from 'moment'
type DisplayCardList = Array<
Array<{
label: string
key: string
isSearch?: boolean
isDate?: boolean
isCustomRender?: boolean
list?: LabelValueOptions
}>
>
export const displayCardList: DisplayCardList = [
[
{ label: '发票号码:', key: 'invoiceNumber' },
{ label: '发票代码:', key: 'invoiceCode' },
{ label: '发票类型代码:', key: 'invoiceTypeCode', isSearch: true, list: invoiceCodeList },
{ label: '发票状态:', key: 'invoiceStatus', isSearch: true, list: invoiceStatusList },
{ label: '发票请求流水号:', key: 'invoiceRequestNumber' },
{ label: '商品或服务名称:', key: 'itemOrServiceName' },
{ label: '开票日期:', key: 'invoicingDate', isDate: true },
{ label: '当前时间:', key: 'currentTime' },
{ label: '税控码:', key: 'taxControlCode' },
{ label: '开票单位代码:', key: 'invoiceUnitCode' },
{ label: '是否为纸质发票:', key: 'isPaperInvoice', isCustomRender: true },
{ label: '纸质发票号码:', key: 'paperInvoiceNumber' },
{ label: '特定要素:', key: 'specialElements' },
{ label: '特定要素类型代码:', key: 'specialElementTypeCode' },
{ label: '报销状态:', key: 'reimbursementStatus' },
{ label: '最终校验码:', key: 'finalCheckCode' },
{ label: '清单标志:', key: 'itemFlag' },
{ label: '机器编号:', key: 'machineCode' },
{ label: '机动车发票类型代码:', key: 'vehicleInvoiceTypeCode' },
{ label: '原发票号码:', key: 'originalInvoiceNumber' },
{ label: '是否已获取详情:', key: 'isDetailObtained', isCustomRender: true },
{ label: '备注:', key: 'remarks' },
],
[
{ label: '购方名称:', key: 'buyerName' },
{ label: '购方开票名称:', key: 'buyerInvoiceName' },
{ label: '购方税号:', key: 'buyerTaxNumber' },
{ label: '购方开票税号:', key: 'buyerInvoiceTaxNumber' },
{ label: '购方识别号:', key: 'buyerIdentificationNumber' },
{ label: '购方银行账户:', key: 'buyerBankAccount' },
{ label: '购方银行账号:', key: 'buyerBankAccountNumber' },
{ label: '购方地址电话:', key: 'buyerAddressPhone' },
],
[
{ label: '销方名称:', key: 'sellerName' },
{ label: '销方开票名称:', key: 'sellerInvoiceName' },
{ label: '销方税号:', key: 'sellerTaxNumber' },
{ label: '销方开票税号:', key: 'sellerInvoiceTaxNumber' },
{ label: '销方识别号:', key: 'sellerIdentificationNumber' },
{ label: '销方银行账户:', key: 'sellerBankAccount' },
{ label: '销方银行账号:', key: 'sellerBankAccountNumber' },
{ label: '销方地址电话:', key: 'sellerAddressPhone' },
],
[
{ label: '开票人:', key: 'invoicer' },
{ label: '收款人:', key: 'payee' },
{ label: '复核人:', key: 'reviewer' },
{ label: '操作员代码:', key: 'operatorCode' },
],
[
{ label: '合计金额:', key: 'totalAmount' },
{ label: '合计税额:', key: 'totalTax' },
{ label: '扣除额:', key: 'deductionAmount' },
{ label: '价税合计:', key: 'totalWithTax' },
],
]
export const columns: BasicColumn[] = [
{
title: '序号',
dataIndex: 'serialNumber',
width: 80,
},
{
title: '名称',
dataIndex: 'name',
width: 200,
},
{
title: '发票代码',
dataIndex: 'invoiceCode',
width: 200,
},
{
title: '发票号码',
dataIndex: 'invoiceNumber',
width: 200,
},
{
title: '发票类型代码',
dataIndex: 'invoiceTypeCode',
width: 200,
customRender({ text }) {
return invoiceCodeList.find((el) => el.value === text)?.label || ''
},
},
{
title: '发票明细行序号',
dataIndex: 'invoiceDetailLineNumber',
width: 200,
customRender({ text }) {
return text || '-'
},
},
{
title: '发票行性质',
dataIndex: 'invoiceLineNature',
width: 200,
customRender({ text }) {
return text || '-'
},
},
{
title: '金额',
dataIndex: 'amount',
width: 100,
},
{
title: '税率',
dataIndex: 'taxRate',
width: 100,
},
{
title: '税额',
dataIndex: 'taxAmount',
width: 100,
},
{
title: '商品名称',
dataIndex: 'productName',
width: 200,
},
{
title: '规格型号',
dataIndex: 'specification',
width: 200,
customRender({ text }) {
return text || '-'
},
},
{
title: '单位',
dataIndex: 'unit',
width: 100,
},
{
title: '商品数量',
dataIndex: 'quantity',
width: 100,
},
{
title: '商品单价',
dataIndex: 'unitPrice',
width: 100,
},
{
title: '商品编码',
dataIndex: 'productCode',
width: 200,
},
{
title: '版本',
dataIndex: 'version',
width: 200,
},
{
title: '优惠政策标识',
dataIndex: 'preferentialPolicyFlag',
width: 150,
customRender({ text }) {
return text || '-'
},
},
{
title: '开票日期',
dataIndex: 'invoicingDate',
width: 120,
},
{
title: '开票单位代码',
dataIndex: 'invoicingUnitCode',
width: 150,
},
]
export const getDisplayValLabel = (displayItem, detailInfo): string => {
if (displayItem['isSearch']) {
return (
displayItem?.['list'].find((el) => el.value === detailInfo?.[displayItem?.['key']])?.label ||
'未知'
)
} else if (displayItem['isDate']) {
return moment(detailInfo?.[displayItem?.['key']]).format('YYYY-MM-DD HH:mm:ss')
} else {
return detailInfo?.[displayItem?.['key']] || ''
}
}

@ -0,0 +1,244 @@
<template>
<div class="ds-income-invoice-wrapper">
<a-spin :spinning="loadingFlag" tip="加载中...">
<div class="top-opt-wrapper">
<a-tooltip placement="top" :mouseEnterDelay="0.5">
<template #title>
<span>上一票</span>
</template>
<span class="ds-action-svg-btn" @click="toPage('next')">
<SvgIcon class="next" size="18" name="next" />
</span>
</a-tooltip>
<a-tooltip placement="top" :mouseEnterDelay="0.5">
<template #title>
<span>下一票</span>
</template>
<span class="ds-action-svg-btn" @click="toPage('last')">
<SvgIcon size="18" name="next" />
</span>
</a-tooltip>
</div>
<div class="ds-income-invoice-content-wrapper">
<div class="basic-wrapper">
<div class="module-title">发票信息</div>
<div class="info-wrapper" v-for="(cardItem, index) in displayCardList" :key="index">
<div class="info-item" v-for="item in cardItem" :key="item.key">
<div class="info-item-label">{{ item.label }}</div>
<div class="info-item-value">
<template v-if="item.isCustomRender && incomeInvoiceDetail">
<CheckCircleFilled
style="color: #257afa; font-size: 14px"
v-if="incomeInvoiceDetail[item['key']]"
/>
<CloseCircleFilled v-else style="color: #adadad; font-size: 14px" />
</template>
<span v-else>
{{ getDisplayValLabel(item, incomeInvoiceDetail) }}
</span>
</div>
</div>
<div class="info-item-line"></div>
</div>
</div>
<BasicTable class="ds-table" @register="registerTable">
<template #tableTitle>
<div class="module-title">发票详情</div>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'invoiceNumber'">
<i
class="iconfont icon-fuzhi3"
style="color: #257afa; font-size: 14px; margin-right: 4px; cursor: pointer"
v-if="record.invoiceNumber"
@click="copyHandle(record)"
></i>
<span>{{ record.invoiceNumber || '' }}</span>
</template>
</template>
</BasicTable>
</div>
</a-spin>
</div>
</template>
<script lang="ts" setup>
import { SvgIcon } from '/@/components/Icon'
import { BasicTable, useTable } from '/@/components/Table'
import { GetInfo } from '../api'
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'
import { columns, displayCardList, getDisplayValLabel } from './columns'
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue'
import { useMessage } from '/@/hooks/web/useMessage'
import { useGo } from '/@/hooks/web/usePage'
import { useRoute } from 'vue-router'
import { useAppStore } from '/@/store/modules/app'
import { closePage } from '/@/hooks/web/common'
const appStore = useAppStore()
const go = useGo()
const route = useRoute()
const { createMessage } = useMessage()
const loadingFlag = ref(true)
const incomeInvoiceDetail = ref(null)
const incomeInvoiceDetailTableData = ref([])
const [registerTable, { setTableData }] = useTable({
title: '',
dataSource: incomeInvoiceDetailTableData.value,
columns,
isTreeTable: false,
pagination: false,
striped: true,
useSearchForm: false,
showTableSetting: false,
bordered: true,
showIndexColumn: false,
indexColumnProps: {
width: 60,
},
canResize: true,
resizeHeightOffset: 15,
immediate: true,
})
const copyHandle = (row) => {
const { clipboardRef, isSuccessRef } = useCopyToClipboard(row.invoiceNumber)
clipboardRef.value = row.invoiceNumber
if (unref(isSuccessRef)) {
createMessage.success('复制成功!')
}
}
const getDetails = async () => {
try {
loadingFlag.value = true
const res = await GetInfo({
id: route.query.id,
})
console.log('res', res)
incomeInvoiceDetail.value = res.data
incomeInvoiceDetailTableData.value = res.data?.data || []
setTableData(incomeInvoiceDetailTableData.value)
} catch (error) {
} finally {
loadingFlag.value = false
}
}
//
const toPage = (v) => {
const obj = appStore.getIds
if (obj && obj['incomeInvoice']) {
const ids = obj['incomeInvoice']
const index = ids.indexOf(route.query.id as string)
let id = ''
if (v == 'next') {
//
if (index == 0) {
return createMessage.warning('该票为当前页码第一票!')
}
id = ids[index - 1]
} else {
//
if (index == 19) {
return createMessage.warning('该票为当前页码最后一票!')
}
id = ids[index + 1]
}
go({
path: route.path,
query: {
id,
},
})
closePage(route.path + '?id=' + id)
} else {
createMessage.warning('列表页面数据丢失,请回退列表页面后重试!')
}
}
getDetails()
</script>
<style lang="less" scoped>
.ds-income-invoice-wrapper {
background: #ffffff;
:deep(.ant-table-title) {
padding: 0;
margin-bottom: 10px;
}
:deep(.ant-table-container) {
padding: 0;
}
.top-opt-wrapper {
display: flex;
justify-content: flex-start;
align-items: center;
padding: 8px 16px;
background: #f5f9fc;
.ds-action-svg-btn {
display: inline-block;
width: 32px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 2px;
margin-right: 8px;
cursor: pointer;
.next {
transform: rotate(180deg);
}
}
.ds-action-svg-btn:hover {
box-shadow: 0px 2px 4px #cad1db;
}
}
.ds-income-invoice-content-wrapper {
padding: 0 20px;
.module-title {
font-size: 12px;
font-weight: 700;
letter-spacing: 1px;
color: #33383d;
padding: 14px 0 4px 0;
}
.info-wrapper {
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: wrap;
.info-item {
display: flex;
width: calc(100% / 6);
padding-top: 16px;
font-size: 12px;
font-weight: 400;
letter-spacing: 0px;
line-height: 15.84px;
&-label {
color: #7a8798;
}
&-value {
flex: 1;
color: #33383d;
word-break: break-all;
word-wrap: break-word;
white-space: break-spaces;
hyphens: auto;
}
}
.info-item-line {
margin-top: 16px;
width: 100%;
height: 1px;
background: #e8ebed;
}
}
}
}
</style>

@ -0,0 +1,143 @@
<template>
<div class="ds-fee-settle-main-table">
<BasicTable class="ds-table" @register="registerTable" @row-dbClick="handleDetails">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex == 'invoiceNumber'">
<span>{{ record.invoiceNumber || '' }}</span>
<i
class="iconfont icon-fuzhi3"
style="color: #257afa; font-size: 14px; margin-left: 4px; cursor: pointer"
v-if="record.invoiceNumber"
@click="copyHandle(record)"
></i>
</template>
<template v-if="column.dataIndex == 'isDetailObtained'">
<CheckCircleFilled
style="color: #257afa; font-size: 14px"
v-if="record.isDetailObtained"
/>
</template>
<template v-if="column.dataIndex == 'isPaperInvoice'">
<CheckCircleFilled style="color: #257afa; font-size: 14px" v-if="record.isPaperInvoice" />
<CloseCircleFilled v-else style="color: #adadad; font-size: 14px"
/></template>
<template v-if="column.key === 'action'">
<TableAction :actions="getActionOptList(record)" />
</template>
</template>
</BasicTable>
</div>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue'
import { BasicTable, useTable, TableAction, ActionItem } from '/@/components/Table'
import { GetList } from './api'
import { formatParams } from '/@/hooks/web/common'
import { useGo } from '/@/hooks/web/usePage'
import { columns, searchFormSchema } from './columns'
import { useMessage } from '/@/hooks/web/useMessage'
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue'
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'
import { useAppStore } from '/@/store/modules/app'
const appStore = useAppStore()
const { createMessage } = useMessage()
const go = useGo()
const [registerTable, { reload, getForm }] = useTable({
title: '',
api: async (p) => {
const res: API.DataResult = await GetList(p)
return new Promise((resolve) => {
const ids = res.data.map((item) => {
return item.id
})
appStore.setIds(ids, 'incomeInvoice')
resolve({ data: [...res.data], total: res.count })
})
},
beforeFetch: (p) => {
return formatParams(p)
},
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
// ()
useAdvancedSearch: true,
},
isTreeTable: false,
pagination: true,
striped: true,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: true,
indexColumnProps: {
width: 60,
},
canResize: true,
resizeHeightOffset: 15,
immediate: true,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
})
const getActionOptList = (record): ActionItem[] => {
return [
{
icon: h('i', {
class: 'iconfont icon-chakan',
style: { color: '#257afa', fontSize: '16px' },
}),
isCustomIcon: true,
tooltip: '明细',
onClick: handleDetails.bind(null, record),
},
{
icon: h('i', {
class: 'iconfont icon-xiazai',
style: { color: '#257afa', fontSize: '14px' },
}),
isCustomIcon: true,
tooltip: '下载',
onClick: handleDownload.bind(null, record),
},
]
}
//
function handleDownload(row) {
const filePath = row?.pdfFilePath
if (!filePath) {
return createMessage.warning('暂未获取到相关文件')
}
window.open(filePath, '_blank')
}
//
const handleDetails = (row) => {
go(`/incomeInvoice-details?id=${row.id}`)
}
const copyHandle = (row) => {
const { clipboardRef, isSuccessRef } = useCopyToClipboard(row.invoiceNumber)
clipboardRef.value = row.invoiceNumber
if (unref(isSuccessRef)) {
createMessage.success('复制成功!')
}
}
function handleSuccess() {
reload()
}
onMounted(() => {
//
})
</script>
<style lang="less" scoped>
.ds-fee-settle-main-table {
}
</style>
Loading…
Cancel
Save