443 lines
15 KiB
TypeScript
443 lines
15 KiB
TypeScript
import React, { useRef, useState } from 'react';
|
||
import ProTable, { ActionType, ProColumns } from '@ant-design/pro-table';
|
||
import { Button, message, Tag, FormInstance, Popconfirm } from 'antd';
|
||
import { handleGetInvoicePageTable } from '../Invoicing/service';
|
||
import { handleGetAppToken, handleGetInvoiceSearch, handleGetKaiPiao, handleGetSDToken } from '../DigitalElectronics/service';
|
||
|
||
// 定义查询接口的返回类型
|
||
export interface ApifoxModel {
|
||
businessSystemCode: string;
|
||
data: Data;
|
||
interfaceCode: InterfaceCode;
|
||
requestId: string;
|
||
[property: string]: any;
|
||
}
|
||
|
||
export interface Data {
|
||
sellerTaxpayerId: string;
|
||
serialNo: string;
|
||
[property: string]: any;
|
||
}
|
||
|
||
export enum InterfaceCode {
|
||
BillInvoiceQuery = "BILL.INVOICE.QUERY",
|
||
}
|
||
|
||
// 发票查询页面组件
|
||
const InvoiceSearch: React.FC = () => {
|
||
const actionRef = useRef<ActionType>();
|
||
const formRef = useRef<FormInstance>();
|
||
// 第一个接口的token
|
||
const [appToken, setAppToken] = useState<any>()
|
||
// 第二个接口的token
|
||
const [accessToken, setAccessToken] = useState<any>()
|
||
// 查看详情
|
||
const handleViewDetail = (record: any) => {
|
||
message.info('查看详情功能待开发');
|
||
console.log('详情数据:', record);
|
||
};
|
||
|
||
// 表格列定义
|
||
const columns: ProColumns<any>[] = [
|
||
{
|
||
title: '序号',
|
||
dataIndex: 'index',
|
||
valueType: "index",
|
||
width: 48,
|
||
align: 'center',
|
||
ellipsis: true,
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: '单据编号',
|
||
dataIndex: 'billNo',
|
||
width: 150,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
hideInSearch: false,
|
||
},
|
||
{
|
||
title: '发票代码',
|
||
dataIndex: 'invoiceCode',
|
||
width: 120,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: '发票号码',
|
||
dataIndex: 'invoiceNumber',
|
||
width: 120,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: '发票种类',
|
||
dataIndex: 'invoiceType',
|
||
width: 120,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
valueType: 'select',
|
||
valueEnum: {
|
||
'004': { text: '增值税纸质专用发票' },
|
||
'007': { text: '增值税纸质普通发票' },
|
||
'025': { text: '增值税电子普通发票(卷票)' },
|
||
'026': { text: '增值税电子普通发票' },
|
||
'028': { text: '增值税电子专用发票' },
|
||
'08xdp': { text: '数电专票' },
|
||
'10xdp': { text: '数电普票' },
|
||
},
|
||
},
|
||
{
|
||
title: '购方名称',
|
||
dataIndex: 'buyerName',
|
||
width: 200,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: '购方税号',
|
||
dataIndex: 'buyerTaxpayerId',
|
||
width: 180,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
hideInSearch: false,
|
||
},
|
||
{
|
||
title: '销方名称',
|
||
dataIndex: 'sellerName',
|
||
width: 180,
|
||
align: 'center',
|
||
ellipsis: true,
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: '销方税号',
|
||
dataIndex: 'sellerTaxpayerId',
|
||
width: 180,
|
||
align: 'center',
|
||
ellipsis: true,
|
||
hideInSearch: false,
|
||
},
|
||
{
|
||
title: '开票日期',
|
||
dataIndex: 'invoiceDate',
|
||
valueType: 'date',
|
||
width: 120,
|
||
ellipsis: true,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
render: (text, record) => {
|
||
if (record.invoiceDate) {
|
||
return new Date(record.invoiceDate).toLocaleDateString();
|
||
}
|
||
return '-';
|
||
},
|
||
},
|
||
{
|
||
title: '合计金额',
|
||
dataIndex: 'totalAmount',
|
||
width: 120,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
render: (text) => {
|
||
if (text !== undefined && text !== null) {
|
||
return `¥${Number(text).toFixed(2)}`;
|
||
}
|
||
return '-';
|
||
},
|
||
},
|
||
{
|
||
title: '合计税额',
|
||
dataIndex: 'totalTaxAmount',
|
||
width: 120,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
render: (text) => {
|
||
if (text !== undefined && text !== null) {
|
||
return `¥${Number(text).toFixed(2)}`;
|
||
}
|
||
return '-';
|
||
},
|
||
},
|
||
{
|
||
title: '发票状态',
|
||
dataIndex: 'invoiceStatus',
|
||
width: 100,
|
||
align: 'center',
|
||
ellipsis: true,
|
||
hideInSearch: false,
|
||
valueType: 'select',
|
||
valueEnum: {
|
||
0: { text: '正常', status: 'Success' },
|
||
1: { text: '作废', status: 'Error' },
|
||
2: { text: '红冲', status: 'Warning' },
|
||
},
|
||
},
|
||
{
|
||
title: '操作',
|
||
valueType: 'option',
|
||
width: 200,
|
||
align: 'center',
|
||
fixed: 'right',
|
||
hideInSearch: true,
|
||
render: (text, record) => [
|
||
<Popconfirm
|
||
title="确认撤回?"
|
||
onConfirm={async () => {
|
||
await handleRevoke(record)
|
||
}}
|
||
onCancel={() => { }}
|
||
okText="确认"
|
||
cancelText="取消"
|
||
>
|
||
< Button type="primary" size="small" >撤回</Button >
|
||
</Popconfirm>,
|
||
<Popconfirm
|
||
title="确认红冲?"
|
||
onConfirm={async () => {
|
||
await handleRedReversal(record)
|
||
}}
|
||
onCancel={() => { }}
|
||
okText="确认"
|
||
cancelText="取消"
|
||
>
|
||
< Button type="primary" size="small" >红冲</Button >
|
||
</Popconfirm>
|
||
],
|
||
},
|
||
];
|
||
|
||
// 撤回
|
||
const handleRevoke = async (params: any) => {
|
||
console.log('paramsparamsparams', params);
|
||
const queryData = {
|
||
sellerTaxpayerId: "91530112MA7MQ2JR9U",
|
||
serialNos: params.billNo || "",
|
||
};
|
||
// 将data字段进行base64加密
|
||
const dataString = JSON.stringify(queryData);
|
||
const encryptedData = btoa(unescape(encodeURIComponent(dataString)));
|
||
const req: any = {
|
||
requestId: Date.now().toString(),
|
||
businessSystemCode: "BUSINESS_YCIC",
|
||
interfaceCode: "BILL.WITHDRAW",
|
||
data: encryptedData
|
||
}
|
||
// 他这个接口 就一个地址 改不一样的参数就能调不一样的接口
|
||
const data = await handleGetInvoiceSearch(req, accessToken)
|
||
if (data && data.success) {
|
||
let res = JSON.parse(decodeURIComponent(escape(atob(data.data))))
|
||
if (res && res.length > 0) {
|
||
let result = res[0]
|
||
message.success(result.message)
|
||
actionRef.current?.reload()
|
||
}
|
||
} else {
|
||
message.error(data?.message || '查询失败');
|
||
}
|
||
}
|
||
|
||
// 红冲
|
||
const handleRedReversal = async (params: any) => {
|
||
// 整单红冲 不需要调用红冲接口 申请里面放蓝票信息 就是红冲
|
||
console.log('paramsparams', params);
|
||
|
||
let obj: any = {
|
||
billNo: "SRM_202509011366",
|
||
billDate: "2025-09-01",
|
||
autoInvoice: "1",
|
||
includeTaxFlag: "1",
|
||
invoiceProperty: "1",
|
||
totalAmount: -10,
|
||
invoiceType: "10xdp",
|
||
buyerTaxpayerId: "91440300MA5G9GK78Y",
|
||
buyerName: "深圳市顺丰快运有限公司test01",
|
||
sellerTaxpayerId: "91530112MA7MQ2JR9U",
|
||
sellerName: "云南交投集团经营开发有限公司彩云驿商业管理分公司",
|
||
sellerBankAndAccount: "13710884704",
|
||
sellerAddressAndTel: "高新技术产业园南区科技南十二路58996989",
|
||
drawer: "王协芬",
|
||
buyerRecipientPhone: "18158132615",
|
||
buyerRecipientMail: "",
|
||
autoMerge: "0",
|
||
blueinvoiceCode: "",
|
||
blueinvoiceNo: "22944630796032563200",
|
||
redReason: "2",
|
||
billDetail: [
|
||
{
|
||
amount: -5,
|
||
detailId: "11112222333344445555",
|
||
goodsName: "通天口服液",
|
||
lineProperty: 2,
|
||
price: 5,
|
||
quantity: -1,
|
||
revenueCode: "1070304990000000000",
|
||
taxRate: "0.13",
|
||
units: "盒"
|
||
},
|
||
{
|
||
amount: -5,
|
||
detailId: "55554444333322221111",
|
||
goodsName: "通天口服液2",
|
||
lineProperty: 2,
|
||
price: 5,
|
||
quantity: -1,
|
||
revenueCode: "1070304990000000000",
|
||
taxRate: "0.13",
|
||
units: "盒"
|
||
}
|
||
]
|
||
}
|
||
console.log('objobjobj', obj);
|
||
|
||
// 构造原始数据
|
||
const originalData = [obj]; // 将record作为data数组的一项
|
||
// 将data字段进行base64加密
|
||
const dataString = JSON.stringify(originalData);
|
||
const encryptedData = btoa(unescape(encodeURIComponent(dataString))); // base64编码,支持中文
|
||
// 构造开票请求数据
|
||
const invoiceData = {
|
||
businessSystemCode: "BUSINESS_YCIC", // 来源系统编码
|
||
interfaceCode: "BILL.PUSH", // 接口业务编码
|
||
requestId: Date.now().toString(), // 时间戳作为请求ID
|
||
data: encryptedData // 加密后的data字符串
|
||
};
|
||
const response = await handleGetKaiPiao(invoiceData, accessToken);
|
||
|
||
console.log('responseresponseresponse', response);
|
||
|
||
// const queryData = {
|
||
// billNo: params?.billNo || "",
|
||
// drawer: params?.drawer || "",
|
||
// orgCode: params?.orgCode || "",
|
||
// sellerTaxpayerId: "91530112MA7MQ2JR9U",
|
||
// redReason: "111",
|
||
// };
|
||
// console.log('queryDataqueryDataqueryData', queryData);
|
||
|
||
// // 将data字段进行base64加密
|
||
// const dataString = JSON.stringify(queryData);
|
||
// const encryptedData = btoa(unescape(encodeURIComponent(dataString)));
|
||
// const req: any = {
|
||
// requestId: Date.now().toString(),
|
||
// businessSystemCode: "BUSINESS_YCIC",
|
||
// interfaceCode: "BILL.QUICK.RED",
|
||
// data: encryptedData
|
||
// }
|
||
// // 他这个接口 就一个地址 改不一样的参数就能调不一样的接口
|
||
// const data = await handleGetInvoiceSearch(req, accessToken)
|
||
// console.log('datadatadatadata', data);
|
||
|
||
// if (data && data.success) {
|
||
// let res = JSON.parse(decodeURIComponent(escape(atob(data.data))))
|
||
// console.log('resresresresres', res);
|
||
// if (res && res.length > 0) {
|
||
// let result = res[0]
|
||
// message.success(result.message)
|
||
// actionRef.current?.reload()
|
||
// }
|
||
// } else {
|
||
// message.error(data?.message || '查询失败');
|
||
// }
|
||
}
|
||
|
||
// 请求表格数据
|
||
const request = async (params: any) => {
|
||
try {
|
||
console.log('查询参数:', params);
|
||
let req: any = {
|
||
appId: "FPY001",
|
||
appSecret: "FPY001fpy@2023***",
|
||
accountId: "2280459335882518528",
|
||
tenantid: "xhcamzchwbgonerr",
|
||
language: ""
|
||
}
|
||
const token = await handleGetAppToken(req)
|
||
console.log('tokentokentoken', token);
|
||
|
||
let appToken: any = token.data.app_token
|
||
|
||
let tokenReq: any = {
|
||
user: "18620126214",
|
||
apptoken: appToken,
|
||
tenantid: "xhcamzchwbgonerr",
|
||
accountId: "2280459335882518528",
|
||
usertype: ""
|
||
}
|
||
|
||
const accessToken: any = await handleGetSDToken(tokenReq)
|
||
console.log('accessTokenaccessTokenaccessToken', accessToken);
|
||
setAppToken(appToken)
|
||
setAccessToken(accessToken.data.access_token)
|
||
|
||
// 构造查询数据
|
||
const queryData = {
|
||
sellerTaxpayerId: "91530112MA7MQ2JR9U",
|
||
serialNo: params.serialNo || "SRM_202509011363",
|
||
};
|
||
|
||
// 将data字段进行base64加密
|
||
const dataString = JSON.stringify(queryData);
|
||
const encryptedData = btoa(unescape(encodeURIComponent(dataString)));
|
||
|
||
// 构造最终请求参数
|
||
const requestParams = {
|
||
businessSystemCode: "BUSINESS_YCIC",
|
||
interfaceCode: "BILL.INVOICE.QUERY",
|
||
requestId: Date.now().toString(),
|
||
data: encryptedData
|
||
};
|
||
|
||
console.log('最终请求参数:', requestParams);
|
||
|
||
// 调用查询接口 (这里需要传入正确的code参数)
|
||
const response = await handleGetInvoiceSearch(requestParams, accessToken.data.access_token);
|
||
console.log('responseresponseresponseresponse', response);
|
||
|
||
|
||
if (response && response.success) {
|
||
|
||
let res = JSON.parse(decodeURIComponent(escape(atob(response.data))))
|
||
console.log('最终请求结果:', res);
|
||
let result = res[0].invoiceList
|
||
|
||
return { data: result || [], success: true };
|
||
} else {
|
||
message.error(response?.message || '查询失败');
|
||
return { data: [], success: true };
|
||
}
|
||
} catch (error) {
|
||
console.error('查询异常:', error);
|
||
message.error('查询异常,请重试');
|
||
return {
|
||
data: [],
|
||
success: false,
|
||
total: 0,
|
||
};
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div>
|
||
<ProTable
|
||
actionRef={actionRef}
|
||
formRef={formRef}
|
||
columns={columns}
|
||
request={request}
|
||
bordered
|
||
rowKey="id"
|
||
scroll={{ x: "100%", y: 'calc(100vh - 450px)' }}
|
||
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}>发票查询列表</span>}
|
||
search={{ span: 6 }}
|
||
toolBarRender={() => [
|
||
]}
|
||
/>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default InvoiceSearch;
|