diff --git a/package.json b/package.json
index 6848b2c..0a0dd25 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,8 @@
"react-i18next": "^14.1.2",
"react-router-dom": "^6.10.0",
"react-to-pdf": "^1.0.1",
- "zustand": "^4.5.2"
+ "zustand": "^4.5.2",
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.18.11/xlsx-0.18.11.tgz"
},
"devDependencies": {
"@types/react": "^18.0.28",
diff --git a/src/components/Data.jsx b/src/components/Data.jsx
new file mode 100644
index 0000000..d067a63
--- /dev/null
+++ b/src/components/Data.jsx
@@ -0,0 +1,94 @@
+import React, { useState, useEffect } from "react";
+import { Tag, Button, message } from 'antd';
+import { CaretUpOutlined, CaretDownOutlined, DownloadOutlined } from '@ant-design/icons';
+import { utils, writeFile } from "xlsx";
+import { isEmpty, getNestedValue } from "../utils/commons";
+
+/**
+ * @property diffPercent
+ * @property diffData
+ * @property data1
+ * @property data2
+ */
+export const VSTag = (props) => {
+ const { diffPercent, diffData, data1, data2 } = props;
+ const CaretIcon = parseInt(diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined;
+ const tagColor = parseInt(diffPercent) < 0 ? 'gold' : 'lime';
+ return parseInt(diffPercent) === 0 ? (
+ '-'
+ ) : (
+
+ {/*
+ {data1} vs {data2}
+
*/}
+ } color={tagColor}>
+ {diffPercent}%{' '}{diffData}
+
+
+ );
+};
+
+/**
+ * 导出表格数据存为xlsx
+ */
+export const TableExportBtn = (props) => {
+ const output_name = `${props.label}`;
+ const [columnsMap, setColumnsMap] = useState([]);
+ const [summaryRow, setSummaryRow] = useState({});
+ useEffect(() => {
+ const r1 = props.columns.reduce((r, v) => ({
+ ...r,
+ ...(v.children ? v.children.reduce((rc, vc, ci) => ({
+ ...rc,
+ ...(vc?.titleX ? {[`${v?.titleX || v.title},${vc.titleX}`]: vc.titleX } : {[(v?.titleX || v.title) + (ci || '')]: `${vc?.titleX || vc?.title || ''}`}),
+ }), {}) : {})
+ }), {});
+ const flatCols = props.columns.flatMap((v, k) =>
+ v.children ? v.children.map((vc, ci) => ({ ...vc, title: `${v?.titleX || v.title}` + (vc?.titleX ? `,${vc.titleX}` : (ci || '')) })) : {...v, title: `${v?.titleX || v.title}`}
+ );
+ // .filter((c) => c.dataIndex)
+ // !['string', 'number'].includes(typeof vc.title) ? `${v?.titleX || v.title}` : `${v?.titleX || v.title}-${vc.title || ''}`
+ ;
+ setColumnsMap(flatCols);
+ // console.log('flatCols', flatCols);
+
+ setSummaryRow(r1);
+ // console.log('summaryRow', r1);
+
+ return () => {};
+ }, [props.columns]);
+
+ const onExport = () => {
+ if (isEmpty(props.dataSource)) {
+ message.warning('无结果.');
+ return false;
+ }
+ const data = props.dataSource.map((item) => {
+ const itemMapped = columnsMap.reduce((sv, kset) => {
+ const render_val = typeof kset?.render === 'function' ? kset.render('', item) : null;
+ const data_val = kset?.dataIndex ? (Array.isArray(kset.dataIndex) ? getNestedValue(item, kset.dataIndex) : item[kset.dataIndex]) : undefined;
+ const x_val = item[`${kset.dataIndex}_X`];
+ // const _title = kset.title.replace('-[object Object]', '');
+ const v = { [kset.title]: x_val || data_val || render_val };
+ return { ...sv, ...v };
+ }, {});
+ return itemMapped;
+ });
+ const ws = utils.json_to_sheet([].concat(isEmpty(summaryRow) ? [] : [summaryRow], data), { header: columnsMap.filter((r) => r.dataIndex).map((r) => r.title) });
+ const wb = utils.book_new();
+ utils.book_append_sheet(wb, ws, 'sheet');
+ writeFile(wb, `${output_name}.xlsx`);
+ };
+
+ return (
+ }
+ size="small"
+ disabled={false}
+ onClick={onExport}
+ >
+ {props.btnTxt || '导出excel'}
+
+ );
+};
diff --git a/src/views/airticket/Index.jsx b/src/views/airticket/Index.jsx
index 16c4287..334207e 100644
--- a/src/views/airticket/Index.jsx
+++ b/src/views/airticket/Index.jsx
@@ -1,11 +1,12 @@
import { useState, useEffect } from "react";
import { Grid, Divider, Layout, Spin, Input, Col, Row, Space, List, Table, Button } from "antd";
-import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined,AuditOutlined } from "@ant-design/icons";
+import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined, AuditOutlined } from "@ant-design/icons";
import { useParams, useHref, useNavigate, NavLink } from "react-router-dom";
import { isEmpty, formatColonTime } from "@/utils/commons";
import dayjs from "dayjs";
import SearchForm from "@/components/SearchForm";
-
+import { DATE_FORMAT } from "@/config";
+import { TableExportBtn } from "@/components/Data";
import airTicketStore from "@/stores/Airticket";
import { usingStorage } from "@/hooks/usingStorage";
@@ -89,7 +90,9 @@ const Airticket = props => {
const [getPlanList, planList, loading] = airTicketStore(state => [state.getPlanList, state.planList, state.loading]);
const showTotal = total => `合计 ${total} `;
- useEffect(() => {}, []);
+ useEffect(() => {
+ getPlanList(travelAgencyId, "", dayjs().startOf("M").format(DATE_FORMAT), dayjs().endOf("M").format(DATE_FORMAT));
+ }, []);
return (
@@ -103,7 +106,7 @@ const Airticket = props => {
shows: ["referenceNo", "dates"],
fieldProps: {
referenceNo: { label: "搜索计划" },
- dates: { label: "出发日期" ,col:8},
+ dates: { label: "出发日期", col: 8 },
},
}}
onSubmit={(err, formVal, filedsVal) => {
@@ -112,7 +115,7 @@ const Airticket = props => {
/>
- } onClick={() => navigate(`/airticket/invoice`)}>
+ } onClick={() => navigate(`/airticket/invoice`)}>
报账
@@ -121,6 +124,7 @@ const Airticket = props => {
+
diff --git a/src/views/airticket/Invoice.jsx b/src/views/airticket/Invoice.jsx
index 254a752..8fa5f30 100644
--- a/src/views/airticket/Invoice.jsx
+++ b/src/views/airticket/Invoice.jsx
@@ -6,6 +6,7 @@ import { isEmpty, formatColonTime } from "@/utils/commons";
import dayjs from "dayjs";
import SearchForm from "@/components/SearchForm";
import BackBtn from "@/components/BackBtn";
+import { TableExportBtn } from "@/components/Data";
import airTicketStore from "@/stores/Airticket";
import { usingStorage } from "@/hooks/usingStorage";
@@ -82,7 +83,7 @@ const Invoice = props => {
key: "Cost",
},
{
- title: "手续费",
+ title: "服务费",
children: [
{
title: vEIFlightBill && vEIFlightBill.reduce((acc, curr) => acc + curr.ServiceFee, 0),
@@ -199,7 +200,9 @@ const Invoice = props => {
+
+
diff --git a/src/views/airticket/Plan.jsx b/src/views/airticket/Plan.jsx
index 254f519..4635de9 100644
--- a/src/views/airticket/Plan.jsx
+++ b/src/views/airticket/Plan.jsx
@@ -80,7 +80,7 @@ const AirticketPlan = props => {
render: (text, record) => (record.CostType == "出票" ? text : "-"),
},
{
- title: "手续费",
+ title: "服务费",
key: "ServiceFee",
dataIndex: "ServiceFee",
},
@@ -131,7 +131,7 @@ const AirticketPlan = props => {
wrapperCol={{
span: 16,
}}
- initialValues={{...airInfo,StartDate:dayjs(airInfo.StartDate)}}
+ initialValues={{ ...airInfo, StartDate: dayjs(airInfo.StartDate) }}
onFinish={values => {
postFlightDetail(airInfo.CLF_SN, airInfo.GRI_SN, airInfo.VEI_SN, airInfo, values)
.then(() => {
@@ -308,17 +308,21 @@ const AirticketPlan = props => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [isModalOpen_confirmInfo, setisModalOpen_confirmInfo] = useState(false);
const [isTicketType, setisTicketType] = useState(true);
+ const [isAddNew, setisAddNew] = useState(true); //是否是在新增费用信息
const [ticket_form] = Form.useForm();
const [confirmInfo_form] = Form.useForm();
const showModal = ticket => {
setIsModalOpen(true);
+ ticket_form.resetFields();
if (isEmpty(ticket.CostType)) ticket.CostType = "出票";
ticket.CostType == "出票" ? setisTicketType(true) : setisTicketType(false); //如果是出票类型,显示票号、折扣等选项
+ isEmpty(ticket.CLC_SN) ? setisAddNew(true) : setisAddNew(false); //如果是新增窗口
ticket_form.setFieldsValue(ticket);
+ if (isEmpty(ticket.Memo)) ticket_form.setFieldsValue({ Memo: "" });
};
- const handleOk = () => {
+ const handleOk = (close_modal = true) => {
ticket_form
.validateFields()
.then(values => {
@@ -344,8 +348,7 @@ const AirticketPlan = props => {
icon: ,
});
});
- ticket_form.resetFields();
- setIsModalOpen(false);
+ if (close_modal) setIsModalOpen(false);
})
.catch(info => {
console.log("Validate Failed:", info);
@@ -391,7 +394,30 @@ const AirticketPlan = props => {
const TicketModal = () => {
return (
<>
-
+ (
+ <>
+
+ {isAddNew ? (
+ <>
+ {" "}
+
+ >
+ ) : (
+
+ )}
+ >
+ )}>
-
-
+
{isTicketType && (
<>
-
+
-
-
+
+
-
+
-
+
{
}}
/>
-
+ >
+ )}
+
+
+
+ {isTicketType && (
+ <>
+
{
/>
-
>
)}
+
- {" "}
+