From ecdba1ee09700341d4f27257605bf88868dfd5cf Mon Sep 17 00:00:00 2001 From: YCC Date: Wed, 21 Aug 2024 17:24:34 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B4=A6=E5=8D=95=E9=A1=B5=E9=9D=A2=EF=BC=8C?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locales/en/common.json | 24 +- public/locales/zh/common.json | 24 +- src/components/SearchForm.jsx | 655 ++++++++++++++++---------------- src/config.js | 2 +- src/hooks/useDatePresets.js | 8 + src/main.jsx | 2 + src/stores/Airticket.js | 34 +- src/views/airticket/Index.jsx | 50 +-- src/views/airticket/Invoice.jsx | 151 ++++++++ src/views/airticket/Plan.jsx | 203 ++++------ 10 files changed, 644 insertions(+), 509 deletions(-) create mode 100644 src/views/airticket/Invoice.jsx diff --git a/public/locales/en/common.json b/public/locales/en/common.json index a8a131c..ebc8ee7 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -25,46 +25,40 @@ "Import": "Import", "Export": "Export", "Copy": "Copy", - "sureCancel": "Are you sure to cancel?", - "sureDelete":"Are you sure to delete?", - "sureSubmit":"Are you sure to submit?", + "sureDelete": "Are you sure to delete?", + "sureSubmit": "Are you sure to submit?", "Yes": "Yes", "No": "No", - "Success": "Success", "Failed": "Failed", - "All": "All", - "Table": { "Total": "Total {{total}} items" }, - "Login": "Login", "Username": "Username", "Realname": "Realname", "Password": "Password", - "ChangePassword": "Change password", "Profile": "Profile", "Logout": "Logout", "LoginTimeout": "Login timeout", "LoginTimeoutTip": "Please input your password", - "userProfile": "User Profile", "Telephone": "Telephone", "Email": "Email address", "Address": "Address", "Company": "Company", "Department": "Department", - "datetime": { "thisWeek": "This Week", "lastWeek": "Last Week", "thisMonth": "This Month", "lastMonth": "Last Month", + "nextMonth": "Next Month", "lastThreeMonth": "Last Three Month", + "nextThreeMonth": "Next Three Month", "firstHalfYear": "First Half Year", "latterHalfYear": "Latter Half Year", "thisYear": "This Year" @@ -101,5 +95,13 @@ "LoginFailed": "Incorrect password, Login failed.", "UsernameIsEmpty": "Please input your username", "PasswordIsEmpty": "Please input your password" + }, + "invoiceStatus": { + "Status": "Status", + "Not_submitted": "Not submitted", + "Submitted": "Submitted", + "Travel_advisor_approved": "Travel advisor approved", + "Finance_Dept_arrproved": "Finance Dept arrproved", + "Paid": "Paid" } -} +} \ No newline at end of file diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index 977f98f..e28688f 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -25,46 +25,40 @@ "Import": "导入", "Export": "导出", "Copy": "复制", - "sureCancel": "确定取消?", - "sureDelete":"确定删除?", - "sureSubmit":"确定提交?", + "sureDelete": "确定删除?", + "sureSubmit": "确定提交?", "Yes": "是", "No": "否", - "Success": "成功", "Failed": "失败", - "All": "所有", - "Table": { "Total": "共 {{total}} 条" }, - "Login": "登录", "Username": "账号", "Realname": "姓名", "Password": "密码", - "ChangePassword": "修改密码", "Profile": "账户中心", "Logout": "退出", "LoginTimeout": "登录超时", "LoginTimeoutTip": "请输入密码", - "userProfile": "账号信息", "Telephone": "联系电话", "Email": "电子邮箱", "Address": "公司地址", "Company": "公司名称", "Department": "部门", - "datetime": { "thisWeek": "本周", "lastWeek": "上周", "thisMonth": "本月", "lastMonth": "上月", + "nextMonth": "下月", "lastThreeMonth": "前三个月", + "nextThreeMonth": "后三个月", "firstHalfYear": "上半年", "latterHalfYear": "下半年", "thisYear": "今年" @@ -101,5 +95,13 @@ "LoginFailed": "密码错误,登陆失败。", "UsernameIsEmpty": "请输入账号", "PasswordIsEmpty": "请输入密码" + }, + "invoiceStatus": { + "Status": "审核状态", + "Not_submitted": "待提交", + "Submitted": "待审核", + "Travel_advisor_approved": "顾问已审核", + "Finance_Dept_arrproved": "财务已审核", + "Paid": "已打款" } -} +} \ No newline at end of file diff --git a/src/components/SearchForm.jsx b/src/components/SearchForm.jsx index 54174ff..5fc1fa1 100644 --- a/src/components/SearchForm.jsx +++ b/src/components/SearchForm.jsx @@ -1,350 +1,347 @@ -import { useEffect } from 'react'; -import { Form, Input, Row, Col, Select, DatePicker, Space, Button, Checkbox } from 'antd'; -import { objectMapper, at } from '@/utils/commons'; -import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from '@/config'; -import useFormStore from '@/stores/Form'; -import { useDatePresets } from '@/hooks/useDatePresets'; -import { useTranslation } from 'react-i18next'; +import { useEffect } from "react"; +import { Form, Input, Row, Col, Select, DatePicker, Space, Button, Checkbox } from "antd"; +import { objectMapper, at } from "@/utils/commons"; +import { DATE_FORMAT, SMALL_DATETIME_FORMAT } from "@/config"; +import useFormStore from "@/stores/Form"; +import { useDatePresets } from "@/hooks/useDatePresets"; +import { useTranslation } from "react-i18next"; -import SearchInput from './SearchInput'; -import AuditStateSelector from './AuditStateSelector'; -import DeptSelector from './DeptSelector'; -import ProductsTypesSelector from './ProductsTypesSelector'; -import CitySelector from '@/components/CitySelector'; -import VendorSelector from '@/components/VendorSelector'; +import SearchInput from "./SearchInput"; +import AuditStateSelector from "./AuditStateSelector"; +import DeptSelector from "./DeptSelector"; +import ProductsTypesSelector from "./ProductsTypesSelector"; +import CitySelector from "@/components/CitySelector"; +import VendorSelector from "@/components/VendorSelector"; const { RangePicker } = DatePicker; const SearchForm = ({ initialValue, onSubmit, onReset, onMounted, confirmText, formName, formLayout, loading, ...props }) => { - const { t } = useTranslation(); - const presets = useDatePresets(); - const [formValues, setFormValues] = useFormStore((state) => [state.formValues, state.setFormValues]); - const [formValuesToSub, setFormValuesToSub] = useFormStore((state) => [state.formValuesToSub, state.setFormValuesToSub]); - const [form] = Form.useForm(); - const { sort, hides, shows, fieldProps, fieldComProps } = { - sort: '', - // initialValue: '', - fieldProps: '', - fieldComProps: '', - hides: [], - shows: [], - ...props.fieldsConfig, - }; - const readValues = { ...initialValue, ...formValues }; + const { t } = useTranslation(); + const presets = useDatePresets(); + const [formValues, setFormValues] = useFormStore(state => [state.formValues, state.setFormValues]); + const [formValuesToSub, setFormValuesToSub] = useFormStore(state => [state.formValuesToSub, state.setFormValuesToSub]); + const [form] = Form.useForm(); + const { sort, hides, shows, fieldProps, fieldComProps } = { + sort: "", + // initialValue: '', + fieldProps: "", + fieldComProps: "", + hides: [], + shows: [], + ...props.fieldsConfig, + }; + const readValues = { ...initialValue, ...formValues }; - const formValuesMapper = (values) => { - const destinationObject = { - 'keyword': { key: 'keyword', transform: (value) => value || '' }, - 'username': { key: 'username', transform: (value) => value || '' }, - 'referenceNo': { key: 'referenceNo', transform: (value) => value || '' }, - 'dates': [ - { key: 'startdate', transform: (arrVal) => (arrVal ? arrVal[0].format(DATE_FORMAT) : '') }, - { key: 'enddate', transform: (arrVal) => (arrVal ? arrVal[1].format(DATE_FORMAT) : '') }, - { key: 'starttime', transform: (arrVal) => (arrVal ? arrVal[0].format(DATE_FORMAT) : '') }, - { key: 'endtime', transform: (arrVal) => (arrVal ? arrVal[1].format(SMALL_DATETIME_FORMAT) : '') }, - ], - 'invoiceStatus': { key: 'invoiceStatus', transform: (value) => value?.value || value?.key || '', default: '' }, - 'audit_state': { key: 'audit_state', transform: (value) => value?.value || value?.key || '', default: '' }, - 'agency': { - key: 'agency', - transform: (value) => { - return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : ''; - }, - }, - 'year': [ - { key: 'year', transform: (arrVal) => (arrVal ? arrVal.format('YYYY') : '') }, - ], - 'products_types': { - key: 'products_types', - transform: (value) => { - return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : ''; - }, - }, - 'dept': { - key: 'dept', - transform: (value) => { - console.log(value); - return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : ''; - }, - }, - 'city': { - key: 'city', - transform: (value) => { - return Array.isArray(value) ? value.map((ele) => ele.key).join(',') : value ? value.value : ''; - }, - }, - 'unconfirmed': { key: 'unconfirmed', transform: (value) => value ? 1 : 0 }, - }; - let dest = {}; - const { dates, ...omittedValue } = values; - dest = { ...omittedValue, ...objectMapper(values, destinationObject) }; - for (const key in dest) { - if (Object.prototype.hasOwnProperty.call(dest, key)) { - dest[key] = typeof dest[key] === 'string' ? (dest[key] || '').trim() : dest[key]; - } - } - // omit empty - // Object.keys(dest).forEach((key) => (dest[key] == null || dest[key] === '' || dest[key].length === 0) && delete dest[key]); - return dest; - }; + const formValuesMapper = values => { + const destinationObject = { + keyword: { key: "keyword", transform: value => value || "" }, + username: { key: "username", transform: value => value || "" }, + referenceNo: { key: "referenceNo", transform: value => value || "" }, + dates: [ + { key: "startdate", transform: arrVal => (arrVal ? arrVal[0].format(DATE_FORMAT) : "") }, + { key: "enddate", transform: arrVal => (arrVal ? arrVal[1].format(DATE_FORMAT) : "") }, + { key: "starttime", transform: arrVal => (arrVal ? arrVal[0].format(DATE_FORMAT) : "") }, + { key: "endtime", transform: arrVal => (arrVal ? arrVal[1].format(SMALL_DATETIME_FORMAT) : "") }, + ], + invoiceStatus: { key: "invoiceStatus", transform: value => value?.value || value?.key || "", default: "" }, + audit_state: { key: "audit_state", transform: value => value?.value || value?.key || "", default: "" }, + agency: { + key: "agency", + transform: value => { + return Array.isArray(value) ? value.map(ele => ele.key).join(",") : value ? value.value : ""; + }, + }, + year: [{ key: "year", transform: arrVal => (arrVal ? arrVal.format("YYYY") : "") }], + products_types: { + key: "products_types", + transform: value => { + return Array.isArray(value) ? value.map(ele => ele.key).join(",") : value ? value.value : ""; + }, + }, + dept: { + key: "dept", + transform: value => { + console.log(value); + return Array.isArray(value) ? value.map(ele => ele.key).join(",") : value ? value.value : ""; + }, + }, + city: { + key: "city", + transform: value => { + return Array.isArray(value) ? value.map(ele => ele.key).join(",") : value ? value.value : ""; + }, + }, + unconfirmed: { key: "unconfirmed", transform: value => (value ? 1 : 0) }, + }; + let dest = {}; + const { dates, ...omittedValue } = values; + dest = { ...omittedValue, ...objectMapper(values, destinationObject) }; + for (const key in dest) { + if (Object.prototype.hasOwnProperty.call(dest, key)) { + dest[key] = typeof dest[key] === "string" ? (dest[key] || "").trim() : dest[key]; + } + } + // omit empty + // Object.keys(dest).forEach((key) => (dest[key] == null || dest[key] === '' || dest[key].length === 0) && delete dest[key]); + return dest; + }; - useEffect(() => { - setFormValues(readValues); - const dest = formValuesMapper(readValues); - setFormValuesToSub(dest); + useEffect(() => { + setFormValues(readValues); + const dest = formValuesMapper(readValues); + setFormValuesToSub(dest); - if (typeof onMounted === 'function') { - onMounted(dest) - } + if (typeof onMounted === "function") { + onMounted(dest); + } - return () => {}; - }, []); + return () => {}; + }, []); - const onFinish = (values) => { - console.log('Received values of form, origin form value: \n', values); - const dest = formValuesMapper(values); - console.log('form value send to onSubmit:\n', dest); - const str = new URLSearchParams(dest).toString(); - setFormValues(values); - setFormValuesToSub(dest); - if (typeof onSubmit === 'function') { - onSubmit(null, dest, values, str); - } - }; + const onFinish = values => { + console.log("Received values of form, origin form value: \n", values); + const dest = formValuesMapper(values); + console.log("form value send to onSubmit:\n", dest); + const str = new URLSearchParams(dest).toString(); + setFormValues(values); + setFormValuesToSub(dest); + if (typeof onSubmit === "function") { + onSubmit(null, dest, values, str); + } + }; - const handleReset = () => { - form.setFieldsValue({ - // 'DateType': undefined, - }); - if (typeof onReset === 'function') { - onReset(); - } - }; - const onValuesChange = (changedValues, allValues) => { + const handleReset = () => { + form.setFieldsValue({ + // 'DateType': undefined, + }); + if (typeof onReset === "function") { + onReset(); + } + }; + const onValuesChange = (changedValues, allValues) => { + const dest = formValuesMapper(allValues); + setFormValues(allValues); + setFormValuesToSub(dest); + // console.log('form onValuesChange', Object.keys(changedValues), args); + }; - const dest = formValuesMapper(allValues); - setFormValues(allValues); - setFormValuesToSub(dest); - // console.log('form onValuesChange', Object.keys(changedValues), args); - }; + const onFinishFailed = ({ values, errorFields }) => { + console.log("form validate failed", "\nform values:", values, "\nerrorFields", errorFields); + }; - const onFinishFailed = ({ values, errorFields }) => { - console.log('form validate failed', '\nform values:', values, '\nerrorFields', errorFields); - }; - - return ( - <> -
- {/* */} - - {getFields({ sort, initialValue: readValues, hides, shows, fieldProps, fieldComProps, form, presets, t })} - {/* 'textAlign': 'right' */} - - - - {/* + {/* */} - - - - {/* */} -
- - ); + + + + {/* */} + + + ); }; function getFields(props) { - const { fieldProps, fieldComProps, form, presets, t } = props; - const bigCol = 4 * 2; - const midCol = 6; - const layoutProps = { - // gutter: { xs: 8, sm: 8, lg: 16 }, - lg: { span: 4 }, - md: { span: 8 }, - sm: { span: 12 }, - xs: { span: 24 }, - }; - const item = (name, sort = 0, render, col) => { - const customCol = col || 4; - const mdCol = customCol * 2; - return { - 'key': '', - sort, - name, - render, - 'hide': false, - 'col': { lg: { span: customCol }, md: { span: mdCol < 8 ? 10 : mdCol }, flex: mdCol < 8 ? '1 0' : '' }, - }; - }; - let baseChildren = []; - baseChildren = [ - item( - 'keyword', - 99, - - - , - fieldProps?.keyword?.col || 6 - ), - item( - 'referenceNo', - 99, - - - , - fieldProps?.referenceNo?.col || 6 - ), - item( - 'PNR', - 99, - - - , - fieldProps?.PNR?.col || 4 - ), - item( - 'invoiceStatus', - 99, - - - , - fieldProps?.username?.col || 4 - ), - /** - * - */ - item( - 'year', - 99, - - - , - fieldProps?.year?.col || 3 - ), - item( - 'agency', - 99, - - - , - fieldProps?.agency?.col || 6 - ), - item( - 'audit_state', - 99, - - - , - fieldProps?.audit_state?.col || 3 - ), - item( - 'products_types', - 99, - - - , - fieldProps?.products_types?.col || 6 - ), - item( - 'dept', - 99, - - - , - fieldProps?.dept?.col || 6 - ), - item( - 'city', - 99, - - - , - fieldProps?.city?.col || 4 - ), - item( - 'unconfirmed', - 99, - - {t('group:unconfirmed')} - , - fieldProps?.unconfirmed?.col || 2 - ), - ]; - baseChildren = baseChildren - .map((x) => { - x.hide = false; - if (props.sort === undefined) { - return x; - } - const tmpSort = props.sort; - for (const key in tmpSort) { - if (Object.prototype.hasOwnProperty.call(tmpSort, key)) { - if (x.name === key) { - x.sort = tmpSort[key]; - } - } - } - return x; - }) - .map((x) => { - if (props.hides.length === 0 && props.shows.length === 0) { - return x; - } - if (props.hides.length === 0) { - x.hide = !props.shows.includes(x.name); - } else if (props.shows.length === 0) { - x.hide = props.hides.includes(x.name); - } - return x; - }) - .filter((x) => !x.hide) - .sort((a, b) => { - return a.sort < b.sort ? -1 : 1; - }); - const children = []; - const leftStyle = {}; // { borderRight: '1px solid #dedede' }; - for (let i = 0; i < baseChildren.length; i++) { - let style = {}; // { padding: '0px 2px' }; - style = i % 2 === 0 && baseChildren[i].col === 12 ? { ...style, ...leftStyle } : style; - style = !baseChildren[i].hide ? { ...style, display: 'block' } : { ...style, display: 'none' }; - const Item = ( - - {baseChildren[i].render} - - ); - children.push(Item); - } - return children; + const { fieldProps, fieldComProps, form, presets, t } = props; + const bigCol = 4 * 2; + const midCol = 6; + const layoutProps = { + // gutter: { xs: 8, sm: 8, lg: 16 }, + lg: { span: 4 }, + md: { span: 8 }, + sm: { span: 12 }, + xs: { span: 24 }, + }; + const item = (name, sort = 0, render, col) => { + const customCol = col || 4; + const mdCol = customCol * 2; + return { + key: "", + sort, + name, + render, + hide: false, + col: { lg: { span: customCol }, md: { span: mdCol < 8 ? 10 : mdCol }, flex: mdCol < 8 ? "1 0" : "" }, + }; + }; + let baseChildren = []; + baseChildren = [ + item( + "keyword", + 99, + + + , + fieldProps?.keyword?.col || 6 + ), + item( + "referenceNo", + 99, + + + , + fieldProps?.referenceNo?.col || 6 + ), + item( + "PNR", + 99, + + + , + fieldProps?.PNR?.col || 4 + ), + item( + "invoiceStatus", + 99, + + + , + fieldProps?.username?.col || 4 + ), + /** + * + */ + item( + "year", + 99, + + + , + fieldProps?.year?.col || 3 + ), + item( + "agency", + 99, + + + , + fieldProps?.agency?.col || 6 + ), + item( + "audit_state", + 99, + + + , + fieldProps?.audit_state?.col || 3 + ), + item( + "products_types", + 99, + + + , + fieldProps?.products_types?.col || 6 + ), + item( + "dept", + 99, + + + , + fieldProps?.dept?.col || 6 + ), + item( + "city", + 99, + + + , + fieldProps?.city?.col || 4 + ), + item( + "unconfirmed", + 99, + + {t("group:unconfirmed")} + , + fieldProps?.unconfirmed?.col || 2 + ), + ]; + baseChildren = baseChildren + .map(x => { + x.hide = false; + if (props.sort === undefined) { + return x; + } + const tmpSort = props.sort; + for (const key in tmpSort) { + if (Object.prototype.hasOwnProperty.call(tmpSort, key)) { + if (x.name === key) { + x.sort = tmpSort[key]; + } + } + } + return x; + }) + .map(x => { + if (props.hides.length === 0 && props.shows.length === 0) { + return x; + } + if (props.hides.length === 0) { + x.hide = !props.shows.includes(x.name); + } else if (props.shows.length === 0) { + x.hide = props.hides.includes(x.name); + } + return x; + }) + .filter(x => !x.hide) + .sort((a, b) => { + return a.sort < b.sort ? -1 : 1; + }); + const children = []; + const leftStyle = {}; // { borderRight: '1px solid #dedede' }; + for (let i = 0; i < baseChildren.length; i++) { + let style = {}; // { padding: '0px 2px' }; + style = i % 2 === 0 && baseChildren[i].col === 12 ? { ...style, ...leftStyle } : style; + style = !baseChildren[i].hide ? { ...style, display: "block" } : { ...style, display: "none" }; + const Item = ( + + {baseChildren[i].render} + + ); + children.push(Item); + } + return children; } export default SearchForm; diff --git a/src/config.js b/src/config.js index 256e171..149a9f9 100644 --- a/src/config.js +++ b/src/config.js @@ -1,7 +1,7 @@ export const PROJECT_NAME = "GHHub"; // mode: test,内部测试使用 -export const HT_HOST = import.meta.env.MODE === 'test' ? 'http://202.103.68.144:890' : import.meta.env.PROD ? "https://p9axztuwd7x8a7.mycht.cn" : 'http://202.103.68.144:890' +export const HT_HOST = import.meta.env.MODE === 'test' ? 'http://202.103.68.144:891' : import.meta.env.PROD ? "https://p9axztuwd7x8a7.mycht.cn" : 'http://202.103.68.144:891' export const DATE_FORMAT = "YYYY-MM-DD"; diff --git a/src/hooks/useDatePresets.js b/src/hooks/useDatePresets.js index 05e251c..aa1d553 100644 --- a/src/hooks/useDatePresets.js +++ b/src/hooks/useDatePresets.js @@ -25,10 +25,18 @@ export const useDatePresets = () => { label: t("datetime.lastMonth"), value: [dayjs().subtract(1, "M").startOf("M"), dayjs().subtract(1, "M").endOf("M")], }, + { + label: t("datetime.nextMonth"), + value: [dayjs().add(1, "M").startOf("M"), dayjs().add(1, "M").endOf("M")], + }, { label: t("datetime.lastThreeMonth"), value: [dayjs().subtract(2, "M").startOf("M"), dayjs().endOf("M")], }, + { + label: t("datetime.nextThreeMonth"), + value: [dayjs().startOf("M"), dayjs().add(3,"M").endOf("M")], + }, { label: t("datetime.firstHalfYear"), value: [dayjs().startOf("y"), dayjs().endOf("y").subtract(6, "M")], diff --git a/src/main.jsx b/src/main.jsx index b675476..25a7270 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -29,6 +29,7 @@ import InvoicePaid from '@/views/invoice/Paid' import InvoicePaidDetail from '@/views/invoice/PaidDetail' import Airticket from '@/views/airticket/Index' import AirticketPlan from '@/views/airticket/Plan' +import AirticketInvoice from '@/views/airticket/Invoice' import { ThemeContext } from '@/stores/ThemeContext' import { usingStorage } from '@/hooks/usingStorage' import useAuthStore from './stores/Auth' @@ -69,6 +70,7 @@ const initRouter = async () => { { path: 'invoice/paid/detail/:flid', element: }, { path: 'airticket',element: }, { path: 'airticket/plan/:coli_sn/:gri_sn',element:}, + { path: 'airticket/invoice',element:}, { path: "products",element: }, { path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:}, diff --git a/src/stores/Airticket.js b/src/stores/Airticket.js index cd8ada5..23c8a5f 100644 --- a/src/stores/Airticket.js +++ b/src/stores/Airticket.js @@ -10,6 +10,7 @@ const airTicketStore = create((set, get) => ({ setPlanList: planList => set({ planList }), setPlanDetail: planDetail => set({ planDetail }), setGuestList: guestList => set({ guestList }), + setVEIFlightBill: vEIFlightBill => set({ vEIFlightBill }), async getPlanList(vei_sn, GRI_Name, TimeStart, TimeEnd) { const { setLoading, setPlanList } = get(); @@ -68,15 +69,21 @@ const airTicketStore = create((set, get) => ({ const _result = errcode !== 0 ? [] : result; setGuestList(_result); }, - // async getFlightCostList(CLF_SN) { - // const searchParams = { - // CLF_SN: CLF_SN, - // }; - // const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/Get_flight_cost`, searchParams); - // const _result = errcode !== 0 ? [] : result; - // console.log(_result); - // return _result; - // }, + //获取账单列表 + async getVEIFlightBill(VEI_SN, GRI_Name, CheckStatus, FlightDate1, FlightDate2) { + const { setVEIFlightBill } = get(); + const searchParams = { + VEI_SN: VEI_SN, + GRI_Name: GRI_Name, + CheckStatus: CheckStatus, + FlightDate1: FlightDate1, + FlightDate2: FlightDate2, + }; + const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/GetVEIFlightBill`, searchParams); + const _result = errcode !== 0 ? [] : result; + console.log(_result); + setVEIFlightBill(_result); + }, async postFlightCost(values) { const formData = new FormData(); for (const [key, value] of Object.entries(values)) { @@ -91,6 +98,15 @@ const airTicketStore = create((set, get) => ({ } }); }, + + async deleteFlightCost(CLC_SN) { + const searchParams = { + CLC_SN: CLC_SN, + }; + const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/Delete_flight_cost`, searchParams); + const _result = errcode !== 0 ? [] : result; + return _result; + }, })); export default airTicketStore; diff --git a/src/views/airticket/Index.jsx b/src/views/airticket/Index.jsx index 09b0d87..52c4f05 100644 --- a/src/views/airticket/Index.jsx +++ b/src/views/airticket/Index.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; -import { Grid, Divider, Layout, Spin, Input, Col, Row, Space, List, Table } from "antd"; -import { PhoneOutlined, CustomerServiceOutlined, AudioOutlined } from "@ant-design/icons"; +import { Grid, Divider, Layout, Spin, Input, Col, Row, Space, List, Table, Button } from "antd"; +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"; @@ -14,6 +14,7 @@ const planListColumns = [ title: "团名", key: "GRI_No", dataIndex: "GRI_No", + // sorter: (a, b) => b.GRI_No - a.GRI_No, }, { title: "组团人", @@ -77,35 +78,40 @@ const planListColumns = [ ]; const Airticket = props => { - const href = useHref(); const navigate = useNavigate(); - const { phonenumber } = useParams(); const { travelAgencyId } = usingStorage(); const [getPlanList, planList, loading] = airTicketStore(state => [state.getPlanList, state.planList, state.loading]); - const [phone_number, setPhone_number] = useState(phonenumber); const showTotal = total => `合计 ${total} `; useEffect(() => {}, []); - const oncall = () => {}; - return ( - { - getPlanList(travelAgencyId, formVal.referenceNo, formVal.startdate, formVal.endtime); - }} - /> + + + { + getPlanList(travelAgencyId, formVal.referenceNo, formVal.startdate, formVal.endtime); + }} + /> + + + + + + diff --git a/src/views/airticket/Invoice.jsx b/src/views/airticket/Invoice.jsx new file mode 100644 index 0000000..2d0bb2b --- /dev/null +++ b/src/views/airticket/Invoice.jsx @@ -0,0 +1,151 @@ +import { useState, useEffect } from "react"; +import { Grid, Divider, Layout, Spin, Input, Col, Row, Space, Checkbox, Table, Button } from "antd"; +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 BackBtn from "@/components/BackBtn"; + +import airTicketStore from "@/stores/Airticket"; +import { usingStorage } from "@/hooks/usingStorage"; + +const Invoice = props => { + const navigate = useNavigate(); + const { travelAgencyId } = usingStorage(); + const [getVEIFlightBill, vEIFlightBill, loading] = airTicketStore(state => [state.getVEIFlightBill, state.vEIFlightBill, state.loading]); + const showTotal = total => `合计 ${total} `; + + //统计总的费用 + const totalFee = vEIFlightBill.reduce((acc, curr) => acc + curr.ServiceFee, 0); + const vEIFlightBillColumns = [ + { + title: "团名", + key: "GRI_No", + dataIndex: "GRI_No", + render: (text, record) => `${record.GRI_No} ${record.WL}`, + }, + { + title: "费用类型", + key: "CostType", + dataIndex: "CostType", + }, + { + title: "手续费/费用", + children: [ + { + title: totalFee, + dataIndex: "ServiceFee", + }, + ], + }, + { + title: "出发日期", + key: "StartDate", + dataIndex: "StartDate", + sorter: (a, b) => { + const dateA = new Date(a.StartDate); + const dateB = new Date(b.StartDate); + return dateB.getTime() - dateA.getTime(); + }, + }, + { + title: "城市", + key: "FromCity", + dataIndex: "FromCity", + render: (text, record) => (record.CostType == "出票" ? `${record.FromCity} - ${record.ToCity}` : "-"), + }, + { + title: "航班", + key: "FlightNo", + dataIndex: "FlightNo", + render: (text, record) => (record.CostType == "出票" ? text : "-"), + }, + + { + title: "PNR", + key: "PNR", + dataIndex: "PNR", + render: (text, record) => (record.CostType == "出票" ? text : "-"), + }, + { + title: "票号", + key: "TicketNo", + dataIndex: "TicketNo", + render: (text, record) => (record.CostType == "出票" ? text : "-"), + }, + { + title: "机票类型", + key: "FlightType", + dataIndex: "FlightType", + render: (text, record) => (record.CostType == "出票" ? text : "-"), + }, + { + title: "机票价格", + key: "Cost", + dataIndex: "Cost", + render: (text, record) => (record.CostType == "出票" ? text : "-"), + }, + { + title: "折扣", + key: "Discount", + dataIndex: "Discount", + render: (text, record) => (record.CostType == "出票" ? text : "-"), + }, + { + title: "备注", + key: "Memo", + dataIndex: "Memo", + }, + { + title: "审核状态", + children: [ + { + title: , + dataIndex: "CheckStatus", //状态小于2,表示还未提交审核 + render: (text, record) => (record.CheckStatus < 2 ? 待提交 : record.CheckStatusName), + }, + ], + sorter: (a, b) => { + return b.CheckStatus - a.CheckStatus; + }, + }, + ]; + + useEffect(() => {}, []); + + return ( + + + + { + getVEIFlightBill(travelAgencyId, formVal.referenceNo, formVal.invoiceStatus, formVal.startdate, formVal.endtime); + }} + /> + + + + + + + + +
+ + + + + ); +}; +export default Invoice; diff --git a/src/views/airticket/Plan.jsx b/src/views/airticket/Plan.jsx index 71a07c6..3641d4a 100644 --- a/src/views/airticket/Plan.jsx +++ b/src/views/airticket/Plan.jsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { Grid, Divider, Layout, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, App, Typography } from "antd"; +import { Grid, Divider, Layout, Modal, Form, Input, Col, Row, Space, Collapse, Table, Button, Select, App, Popconfirm } from "antd"; import { PhoneOutlined, FrownTwoTone, LikeTwoTone, ArrowUpOutlined, ArrowDownOutlined } from "@ant-design/icons"; import { useParams, useHref, useNavigate, NavLink } from "react-router-dom"; import { isEmpty, formatColonTime } from "@/utils/commons"; @@ -7,106 +7,41 @@ import { OFFICEWEBVIEWERURL } from "@/config"; import airTicketStore from "@/stores/Airticket"; import { usingStorage } from "@/hooks/usingStorage"; +import BackBtn from "@/components/BackBtn"; const AirticketPlan = props => { const { coli_sn, gri_sn } = useParams(); const { travelAgencyId, loginToken } = usingStorage(); - const [getPlanDetail, planDetail, getGuestList, guestList, loading, postFlightDetail, getFlightCostList, postFlightCost] = airTicketStore(state => [ + const [getPlanDetail, planDetail, getGuestList, guestList, loading, postFlightDetail, postFlightCost, deleteFlightCost] = airTicketStore(state => [ state.getPlanDetail, state.planDetail, state.getGuestList, state.guestList, state.loading, state.postFlightDetail, - state.getFlightCostList, state.postFlightCost, + state.deleteFlightCost, ]); - const reservationUrl = `https://p9axztuwd7x8a7.mycht.cn/Service_BaseInfoWeb/FlightPlanDocx?GRI_SN=${gri_sn}&VEI_SN=${travelAgencyId}`; + 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(); //console.log(reservationPreviewUrl); //乘客列表 - const guestListColumns = [ - { - title: "姓名", - key: "MEI_Name", - dataIndex: "MEI_Name", - }, - { - title: "证件类型", - key: "MEI_PassportType", - dataIndex: "MEI_PassportType", - }, - { - title: "证件号", - key: "MEI_PassportNo", - dataIndex: "MEI_PassportNo", - }, - { - title: "证件有效期", - key: "MEI_PassportValidDate", - dataIndex: "MEI_PassportValidDate", - }, - { - title: "性别", - key: "MEI_Gender", - dataIndex: "MEI_Gender", - }, - { - title: "年龄", - key: "MEI_age", - dataIndex: "MEI_age", - }, - { - title: "国籍", - key: "MEI_Country", - dataIndex: "MEI_Country", - }, - { - title: "票号", - key: "MEI_SN", - dataIndex: "MEI_SN", - }, - { - title: "PNR", - key: "MEI_SN", - dataIndex: "MEI_SN", - }, - { - title: "机票费用(RMB)含基建和税", - key: "MEI_SN", - dataIndex: "MEI_SN", - }, - { - title: "折扣", - key: "MEI_SN", - dataIndex: "MEI_SN", - }, - { - title: "手续费", - key: "MEI_SN", - dataIndex: "MEI_SN", - }, - { - title: "机票类型(成人/儿童/婴儿)", - key: "MEI_SN", - dataIndex: "MEI_SN", - }, - { - title: "操作", - key: "MEI_SN", - dataIndex: "MEI_SN", - render: (_, record) => { - return ( - - showModal(record)}>编辑 | console.log("del")}>删除 - - ); - }, - }, - ]; + 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 guestList_OnChange = value => { + console.log(value); + ticket_form.setFieldsValue({ Memo: `${value}` }); + }; //费用列表 const costListColumns = [ @@ -117,8 +52,8 @@ const AirticketPlan = props => { }, { title: "手续费/费用", - key: "Cost", - dataIndex: "Cost", + key: "ServiceFee", + dataIndex: "ServiceFee", }, { title: "PNR", @@ -128,8 +63,8 @@ const AirticketPlan = props => { }, { title: "票号", - key: "FlightCost", - dataIndex: "FlightCost", + key: "TicketNo", + dataIndex: "TicketNo", render: (text, record) => (record.CostType == "出票" ? text : "-"), }, { @@ -140,8 +75,8 @@ const AirticketPlan = props => { }, { title: "机票价格", - key: "FlightCost", - dataIndex: "FlightCost", + key: "Cost", + dataIndex: "Cost", render: (text, record) => (record.CostType == "出票" ? text : "-"), }, { @@ -157,9 +92,20 @@ const AirticketPlan = props => { }, { title: "编辑", - key: "CLF_SN", - dataIndex: "CLF_SN", - render: (text, record) => showModal(record)}>编辑, + key: "CLC_SN", + dataIndex: "CLC_SN", + render: (text, record) => ( + <> + + showModal(record)}>编辑 + handleDelete(record.CLC_SN)} okText="是" cancelText="否"> + + + + + ), }, ]; @@ -228,7 +174,7 @@ const AirticketPlan = props => { - + @@ -241,7 +187,7 @@ const AirticketPlan = props => { - + @@ -300,7 +246,7 @@ const AirticketPlan = props => { ? planDetail.map(item => { return { key: item.id, - label: `${item.StartDate}`, + label: `${item.StartDate} ${item.FlightNo}(${item.FromAirport}${item.FlightStart}-${item.ToAirport}${item.FlightEnd})(${item.FlightCabin})`, children: , }; }) @@ -314,7 +260,8 @@ const AirticketPlan = props => { const showModal = ticket => { setIsModalOpen(true); - ticket.CostType == "出票" ? setisTicketType(true) : setisTicketType(false);//如果是出票类型,显示票号、折扣等选项 + if (isEmpty(ticket.CostType)) ticket.CostType = "出票"; + ticket.CostType == "出票" ? setisTicketType(true) : setisTicketType(false); //如果是出票类型,显示票号、折扣等选项 ticket_form.setFieldsValue(ticket); }; @@ -357,6 +304,29 @@ const AirticketPlan = props => { setIsModalOpen(false); }; + const handleDelete = CLC_SN => { + deleteFlightCost(CLC_SN) + .then(() => { + notification.success({ + message: `成功`, + description: "删除成功!", + placement: "top", + duration: 4, + icon: , + }); + getPlanDetail(travelAgencyId, gri_sn); + }) + .catch(() => { + notification.error({ + message: `错误`, + description: "删除失败", + placement: "top", + duration: 4, + icon: , + }); + }); + }; + const onChangeType = value => { if (value == "出票") { setisTicketType(true); @@ -413,7 +383,7 @@ const AirticketPlan = props => { - + @@ -437,8 +407,7 @@ const AirticketPlan = props => { ]} /> - - + { }} /> - - guestList_OnChange(value)} options={guestList_select()} /> )} @@ -508,14 +453,20 @@ const AirticketPlan = props => { useEffect(() => { getPlanDetail(travelAgencyId, gri_sn); - getGuestList(travelAgencyId, coli_sn); + getGuestList(coli_sn); }, []); return ( + + + + + + - + {/* */}