You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
GHHub/src/views/trainticket/plan.jsx

722 lines
21 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useState, useEffect } from "react";
import { Checkbox, Divider, DatePicker, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, App, Popconfirm, Switch, Radio, List } from "antd";
import { PhoneOutlined, FrownTwoTone, LikeTwoTone, ArrowUpOutlined, ArrowDownOutlined, PlusOutlined } from "@ant-design/icons";
import { useParams, useHref, useNavigate, NavLink } from "react-router-dom";
import { isEmpty, formatColonTime } from "@/utils/commons";
import { OFFICEWEBVIEWERURL } from "@/config";
import dayjs from "dayjs";
import trainTicketStore from "@/stores/Trainticket";
import { usingStorage } from "@/hooks/usingStorage";
import BackBtn from "@/components/BackBtn";
import { station_names } from "@/views/trainticket/station_name";
import { Upload } from "antd";
import ImageUploader from "@/components/ImageUploader";
const TrainticketPlan = props => {
const { coli_sn, gri_sn } = useParams();
const { travelAgencyId, loginToken, userId } = usingStorage();
const [
getPlanDetail,
planDetail,
getGuestList,
guestList,
loading,
postFlightDetail,
postFlightCost,
deleteFlightCost,
getVeiPlanChange,
veiPlanChangeTxt,
postVeiFlightPlanConfirm,
ticketIssuedNotifications,
delete_flight_info,
seatTable,
] = trainTicketStore(state => [
state.getPlanDetail,
state.planDetail,
state.getGuestList,
state.guestList,
state.loading,
state.postFlightDetail,
state.postFlightCost,
state.deleteFlightCost,
state.getVeiPlanChange,
state.veiPlanChangeTxt,
state.postVeiFlightPlanConfirm,
state.ticketIssuedNotifications,
state.delete_flight_info,
state.seatTable,
]);
const reservationUrl = `https://p9axztuwd7x8a7.mycht.cn/Service_BaseInfoWeb/FlightPlanDocx?GRI_SN=${gri_sn}&VEI_SN=${travelAgencyId}&token=${loginToken}`;
const reservationPreviewUrl = OFFICEWEBVIEWERURL + encodeURIComponent(reservationUrl);
// const [form] = Form.useForm();
const { notification } = App.useApp();
//乘客下拉列表
const guestList_select = () => {
return (
guestList &&
guestList.map(item => {
return { label: `${item.MEI_Name} , ${item.MEI_PassportNo}`, value: `${item.MEI_Name} , ${item.MEI_PassportNo} , ${item.MEI_Country} , ${item.MEI_Gender} , ${item.MEI_age} , ${item.MEI_Birthday}` };
})
);
};
const station_name_select = rawStr => {
const records = rawStr.split("@").filter(item => item); // 1. 按@分割记录(过滤空的首元素)
return records.map(record => {
// 按|分割字段最多取前8个有效字段忽略末尾空字段
const [
abbreviation, // 缩写如bjb
name, // 站名(如北京北)
code, // 代码如VAP
pinyin, // 拼音如beijingbei
shortPinyin, // 简拼如bjb
sequence, // 序号如0
areaCode, // 区域代码如0357
city, // 城市(如北京)
] = record.split("|");
return {
value: name + "(" + pinyin + ")",
label: name,
};
});
};
const guestList_OnChange = e => {
ticket_form.setFieldsValue({ Memo: `${e.target.value}` });
};
//座位类型下拉列表
const seatTableList_select = () => {
return (
seatTable &&
seatTable.map(item => {
return { label: `${item.name}`, value: `${item.name}` };
})
);
};
//费用列表
const costListColumns = [
{
title: "客人信息/备注",
key: "Memo",
dataIndex: "Memo",
},
{
title: "费用类型",
key: "CostType",
dataIndex: "CostType",
},
{
title: "车厢",
key: "Cabin",
dataIndex: "Cabin",
render: (text, record) => (record.CostType == "出票" ? text : "-"),
},
{
title: "座位号",
key: "SeatNo",
dataIndex: "SeatNo",
render: (text, record) => (record.CostType == "出票" ? text : "-"),
},
{
title: "座位类型",
key: "SeatClass",
dataIndex: "SeatClass",
render: (text, record) => (record.CostType == "出票" ? text : "-"),
},
{
title: "车票价格",
key: "Cost",
dataIndex: "Cost",
render: (text, record) => (record.CostType == "出票" ? text : "-"),
},
{
title: "服务费",
key: "ServiceFee",
dataIndex: "ServiceFee",
},
{
title: "编辑",
key: "CLC_SN",
dataIndex: "CLC_SN",
render: (text, record) =>
record.CheckStatus <= 2 ? (
<Space>
<a onClick={() => showModal(record)}>编辑</a>
<Popconfirm title="删除" description="请确认是否删除?" onConfirm={() => handleDelete(record.CLC_SN)} okText="是" cancelText="否">
<Button danger type="link">
删除
</Button>
</Popconfirm>
</Space>
) : (
record.CheckStatusName
),
},
];
const Trainticket_form = trainInfo => {
return (
<>
<Form
name={"ticket_form_" + trainInfo.id}
labelCol={{
span: 6,
}}
wrapperCol={{
span: 16,
}}
initialValues={{ ...trainInfo, StartDate: dayjs(trainInfo.StartDate) }}
onFinish={values => {
postFlightDetail(trainInfo.CLF_SN, trainInfo.GRI_SN, trainInfo.VEI_SN, trainInfo, values)
.then(() => {
notification.success({
message: `成功`,
description: "车票信息保存成功!",
placement: "top",
duration: 4,
icon: <LikeTwoTone />,
});
})
.catch(() => {
notification.error({
message: `错误`,
description: "保存失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
}}
autoComplete="off">
<Divider orientation="left">火车信息</Divider>
<Row gutter={16}>
<Col md={24} lg={20} xxl={20}>
<Form.Item label="出发日期、车次、取票号" required>
<Space>
<Form.Item name="StartDate" noStyle rules={[{ required: true, message: "请输入出发日期!" }]}>
<DatePicker
placeholder="出发日期"
style={{
minWidth: 160,
}}
/>
</Form.Item>
<Form.Item name="FlightNo" noStyle rules={[{ required: true, message: "请输入车次!" }]}>
<Input placeholder="车次" />
</Form.Item>
<Form.Item name="TicketNo" noStyle rules={[{ required: true, message: "请输入取票号!" }]}>
<Input placeholder="取票号" maxLength={9} />
</Form.Item>
</Space>
</Form.Item>
<Form.Item label="出发站、抵达站" required>
<Space>
<Form.Item name="FromAirport" noStyle rules={[{ required: true, message: "请输入出发站!" }]}>
{/* <Input placeholder="出发" /> */}
<Select
placeholder="出发"
showSearch
style={{
minWidth: 160,
}}
options={station_name_select(station_names)}
/>
</Form.Item>
<Form.Item name="FlightStart" noStyle rules={[{ required: true, message: "请输入出发时间!" }]}>
<Input placeholder="出发时间" />
</Form.Item>
-
<Form.Item name="ToAirport" noStyle rules={[{ required: true, message: "请输入抵达站!" }]}>
{/* <Input placeholder="抵达" /> */}
<Select
placeholder="抵达"
showSearch
style={{
minWidth: 160,
}}
options={station_name_select(station_names)}
/>
</Form.Item>
<Form.Item name="FlightEnd" noStyle rules={[{ required: true, message: "请输入抵达时间!" }]}>
<Input placeholder="抵达时间" />
</Form.Item>
</Space>
</Form.Item>
<Form.Item name="ServiceType" hidden initialValue="2">
<input type="hidden" />
</Form.Item>
</Col>
<Col md={24} lg={4} xxl={4}>
<Space direction="vertical">
<Form.Item name="TicketIssued">
<Switch checkedChildren="已处理" unCheckedChildren="未处理" />
</Form.Item>
<Button type="primary" htmlType="submit">
1. 保存车票信息
</Button>
</Space>
</Col>
</Row>
<Divider orientation="left">出票信息</Divider>
<Row gutter={16}>
<Col md={24} lg={20} xxl={20}>
<Table bordered={true} rowKey="CLC_SN" columns={costListColumns} dataSource={trainInfo.Flightcost_AsJOSN} loading={loading} pagination={false} />
</Col>
<Col md={24} lg={4} xxl={4}>
<Space direction="vertical">
<Button type="primary" onClick={() => showModal(trainInfo)}>
2. 添加出票信息
</Button>
</Space>
</Col>
</Row>
</Form>
<Form
labelCol={{
span: 6,
}}
wrapperCol={{
span: 16,
}}
initialValues={{ ...trainInfo }}
onFinish={values => {
ticketIssuedNotifications(userId, trainInfo.CLF_SN, trainInfo.OPI_SN, values.FlightMemo_messages,values.ticketImages)
.then(() => {
notification.success({
message: `成功`,
description: "提醒信息已发出!",
placement: "top",
duration: 4,
icon: <LikeTwoTone />,
});
//todo: 在这里情况输入框的内容,还未实现 values.FlightMemo_messages = "";
})
.catch(() => {
notification.error({
message: `错误`,
description: "提醒失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
}}
autoComplete="off">
<Divider orientation="left">车票图片</Divider>
<Row gutter={16}>
<Col md={24} lg={4} xxl={4}></Col>
<Col md={24} lg={16} xxl={16}>
<Form.Item name="ticketImages" valuePropName="fileList" getValueFromEvent={fileList => fileList}>
<ImageUploader osskey={`ghh/${trainInfo.GRI_SN}-${trainInfo.GRI_No}/trainticket/ticketimage/${trainInfo.CLF_SN}`} />
</Form.Item>
</Col>
<Col md={24} lg={4} xxl={4}></Col>
</Row>
<Divider orientation="left">出票完成通知</Divider>
<Row gutter={16}>
<Col md={24} lg={20} xxl={20}>
<Form.Item label="上下站提醒信息" name="FlightMemo_messages">
<Input placeholder="没有提醒请留空,信息会抄送给上下站地接" />
</Form.Item>
<Form.Item label="已发提醒" name="FlightMemo">
<Input.TextArea rows={4} readOnly disabled />
</Form.Item>
</Col>
<Col md={24} lg={4} xxl={4}>
<Button type="primary" htmlType="submit">
3. 通知顾问
</Button>
</Col>
</Row>
</Form>
</>
);
};
const detail_items = () => {
return planDetail
? planDetail.map(item => {
return {
key: item.id,
label: `${item.StartDate} ${item.FlightNo}(${item.FromAirport}${item.FlightStart}-${item.ToAirport}${item.FlightEnd})(${item.FlightCabin})`,
extra: (
<Popconfirm
title="请确认要删除车票记录"
description=""
onConfirm={() => {
delete_flight_info(item.CLF_SN); //删除记录
getPlanDetail(travelAgencyId, gri_sn); //更新页面计划详情,含费用列表
}}
okText="是"
cancelText="否">
<Button type="dashed" size="small" disabled={item.Flightcost_AsJOSN.length == 0 ? false : true}>
删除
</Button>
</Popconfirm>
),
children: Trainticket_form(item),
};
})
: [];
};
// 车票信息编辑表单 begin
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); //如果是出票类型,显示票号、折扣等选项
const isNew = isEmpty(ticket.CLC_SN); // 判断是否为新增状态
setisAddNew(isNew);
if (isNew) {
ticket.ServiceFee = "60"; // // 新增时设置服务费默认值为60
}
ticket_form.setFieldsValue(ticket);
if (isEmpty(ticket.Memo)) ticket_form.setFieldsValue({ Memo: "" });
};
const handleOk = (close_modal = true) => {
ticket_form
.validateFields()
.then(values => {
// 在这里处理表单提交逻辑,例如发送数据到服务器
postFlightCost(values)
.then(() => {
notification.success({
message: `成功`,
description: "保存成功!",
placement: "top",
duration: 4,
icon: <LikeTwoTone />,
});
getPlanDetail(travelAgencyId, gri_sn);
})
.catch(() => {
notification.error({
message: `错误`,
description: "保存失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
if (close_modal) setIsModalOpen(false);
})
.catch(info => {
console.log("Validate Failed:", info);
});
};
const handleCancel = () => {
ticket_form.resetFields();
setIsModalOpen(false);
};
const handleDelete = CLC_SN => {
deleteFlightCost(CLC_SN)
.then(() => {
getPlanDetail(travelAgencyId, gri_sn);
})
.catch(() => {
notification.error({
message: `错误`,
description: "删除失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
};
const onChangeType = value => {
if (value == "出票") {
setisTicketType(true);
} else {
setisTicketType(false);
}
};
//变更确认表单
const showModal_confirmInfo = ConfirmInfo => {
setisModalOpen_confirmInfo(true);
confirmInfo_form.setFieldsValue({ ConfirmInfo: ConfirmInfo });
};
const handleCancel_confirmInfo = () => {
setisModalOpen_confirmInfo(false);
confirmInfo_form.resetFields();
};
const handleOk_confirmInfo = () => {
confirmInfo_form
.validateFields()
.then(values => {
//console.log("Received values of form: ", values.ConfirmInfo);
postVeiFlightPlanConfirm(travelAgencyId, gri_sn, userId, values.ConfirmInfo)
.then(() => {
notification.success({
message: `成功`,
description: "保存成功!",
placement: "top",
duration: 4,
icon: <LikeTwoTone />,
});
getVeiPlanChange(travelAgencyId, gri_sn);
})
.catch(() => {
notification.error({
message: `错误`,
description: "保存失败",
placement: "top",
duration: 4,
icon: <FrownTwoTone />,
});
});
confirmInfo_form.resetFields();
setisModalOpen_confirmInfo(false);
})
.catch(info => {
console.log("Validate Failed:", info);
});
};
// 车票信息编辑表单 end
useEffect(() => {
getPlanDetail(travelAgencyId, gri_sn); //计划详情,含费用列表
getGuestList(coli_sn); //客人列表
getVeiPlanChange(travelAgencyId, gri_sn); //计划变更信息
}, []);
return (
<Space direction="vertical" style={{ width: "100%" }}>
<Row>
<Col md={20} lg={20} xxl={20}></Col>
<Col md={4} lg={4} xxl={4}>
<BackBtn to={"/trainticket"} />
</Col>
</Row>
<Row>
<Col md={24} lg={24} xxl={24} style={{ height: "100%" }}>
<iframe id="msdoc-iframe-reservation" title="msdoc-iframe-reservation" src={reservationPreviewUrl + "&v=" + Math.random()} style={{ width: "100%", height: "600px" }}></iframe>
<Button type="link" target="_blank" href={reservationUrl}>
下载
</Button>
</Col>
</Row>
<Row>
<Divider orientation="center">{planDetail ? `${planDetail[0].GRI_No} - ${planDetail[0].WL}` : ""}</Divider>
<Col md={24} lg={24} xxl={24}>
<Collapse items={detail_items()} />
</Col>
<Col md={24} lg={24} xxl={24}>
<br />
<p style={{ textAlign: "right" }}>
<Popconfirm
title="请确认要增加车票记录"
description=""
onConfirm={async () => {
const startDate = planDetail && planDetail.length > 0 && planDetail[planDetail.length - 1].StartDate ? planDetail[planDetail.length - 1].StartDate : "";
await postFlightDetail("", gri_sn, travelAgencyId, { FlightNo: "新的记录", FlightStatus: 1, ServiceType: 2 }, { StartDate: startDate }); //新增加一条记录
getPlanDetail(travelAgencyId, gri_sn); //计划详情,含费用列表
}}
okText="是"
cancelText="否">
<Button type="dashed" icon={<PlusOutlined />}>
新增车票记录
</Button>
</Popconfirm>
</p>
</Col>
</Row>
<Row>
<Divider orientation="left">计划变更</Divider>
<Col md={24} lg={12} xxl={12}>
<Space direction="vertical" style={{ width: "90%" }}>
<Input.TextArea rows={16} value={veiPlanChangeTxt && veiPlanChangeTxt.ChangeText} />
<Button
type="primary"
onClick={() => {
showModal_confirmInfo(veiPlanChangeTxt && veiPlanChangeTxt.ChangeText);
}}
disabled={isEmpty(veiPlanChangeTxt) || isEmpty(veiPlanChangeTxt.ChangeText)}>
确认变更
</Button>
</Space>
</Col>
<Col md={24} lg={12} xxl={12}>
<Input.TextArea rows={16} readOnly value={veiPlanChangeTxt && veiPlanChangeTxt.ConfirmInfo} />
</Col>
</Row>
<Modal title="变更" open={isModalOpen_confirmInfo} onOk={handleOk_confirmInfo} onCancel={handleCancel_confirmInfo}>
<Form
form={confirmInfo_form}
labelCol={{
span: 5,
}}>
<Form.Item label="确认信息" name="ConfirmInfo" rules={[{ required: true }]}>
<Input.TextArea rows={4} />
</Form.Item>
</Form>
</Modal>
<Modal
title="费用信息"
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
okText="保存"
cancelText="关闭"
footer={(_, { OkBtn, CancelBtn }) => (
<>
<CancelBtn />
{isAddNew ? (
<>
<Button type="primary" onClick={() => handleOk(false)}>
添加并继续新增
</Button>{" "}
<Button type="primary" onClick={() => handleOk(true)}>
添加并关闭
</Button>
</>
) : (
<OkBtn />
)}
</>
)}>
<Form
form={ticket_form}
labelCol={{
span: 5,
}}>
<Form.Item label="费用类型" name="CostType">
<Select
style={{
width: 160,
}}
onChange={onChangeType}
options={[
{
value: "出票",
label: "出票",
},
{
value: "改签",
label: "改签",
},
{
value: "取消",
label: "取消",
},
]}
/>
</Form.Item>
{isTicketType && (
<>
<Form.Item label="车厢" name="Cabin" rules={[{ required: true }]}>
<Select
style={{
width: 160,
}}
options={Array.from({ length: 16 }, (_, index) => ({
value: `${String(index + 1).padStart(2, "0")}`,
label: `${String(index + 1).padStart(2, "0")}`,
}))}
/>
</Form.Item>
<Form.Item label="座位号" name="SeatNo" rules={[{ required: true }]}>
<Input
style={{
width: 160,
}}
/>
</Form.Item>
<Form.Item label="座位类型" name="SeatClass" rules={[{ required: true }]}>
<Select
style={{
width: 160,
}}
options={seatTableList_select()}
/>
</Form.Item>
<Form.Item label="车票价格" name="Cost" rules={[{ required: true }]}>
<Input
prefix="¥"
style={{
width: 160,
}}
/>
</Form.Item>
</>
)}
<Form.Item label="服务费" name="ServiceFee" rules={[{ required: true }]}>
<Input
prefix="¥"
style={{
width: 160,
}}
/>
</Form.Item>
{isTicketType && (
<>
<Form.Item label="选择客人" name="MEI_Name66">
<Radio.Group
onChange={e => guestList_OnChange(e)}
style={{
minWidth: 320,
}}>
<List
bordered
dataSource={guestList_select()}
renderItem={item => (
<List.Item>
<Radio value={item.value}>{item.label}</Radio>
</List.Item>
)}></List>
</Radio.Group>
{/* <Select onChange={value => guestList_OnChange(value)} options={guestList_select()} placeholder="如果列表里面没有客人信息,请手动录到备注里" /> */}
</Form.Item>
</>
)}
<Form.Item label="客人信息/备注" name="Memo">
<Input.TextArea rows={4} disabled={isTicketType} />
</Form.Item>
<Form.Item name="CLF_SN" hidden>
<input />
</Form.Item>
<Form.Item name="GRI_SN" hidden>
<input />
</Form.Item>
<Form.Item name="VEI_SN" hidden>
<input />
</Form.Item>
<Form.Item name="CLC_SN" hidden>
<input />
</Form.Item>
</Form>
</Modal>
</Space>
);
};
export default TrainticketPlan;