Merge branch 'main' of github.com:hainatravel/GHHub

perf/export-docx
Jimmy Liow 11 months ago
commit 16a40e6280

@ -30,8 +30,8 @@
"Published": "Publish" "Published": "Publish"
}, },
"PriceUnit": { "PriceUnit": {
"0": "Person", "0": "per Person",
"1": "Group", "1": "per Group",
"title": "Price Unit" "title": "Price Unit"
}, },
"Status": "Status", "Status": "Status",
@ -44,6 +44,7 @@
"CreateDate": "Create Date", "CreateDate": "Create Date",
"AuditedBy": "Audited By", "AuditedBy": "Audited By",
"AuditDate": "Audit Date", "AuditDate": "Audit Date",
"AuditRes": "Audit Result",
"OpenHours": "Open Hours", "OpenHours": "Open Hours",
"Duration": "Duration", "Duration": "Duration",
"KM": "KM", "KM": "KM",

@ -44,7 +44,7 @@
"CreateDate": "提交时间", "CreateDate": "提交时间",
"AuditedBy": "审核人员", "AuditedBy": "审核人员",
"AuditDate": "审核时间", "AuditDate": "审核时间",
"AuditRes": "审核结果",
"OpenHours": "游览时间", "OpenHours": "游览时间",
"Duration": "游览时长", "Duration": "游览时长",
"KM": "公里数", "KM": "公里数",

@ -71,7 +71,11 @@ const initRouter = async () => {
{ path: 'airticket/plan/:coli_sn/:gri_sn',element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketPlan /></RequireAuth>}, { path: 'airticket/plan/:coli_sn/:gri_sn',element:<RequireAuth subject={PERM_AIR_TICKET} result={true}><AirticketPlan /></RequireAuth>},
{ path: "products",element: <RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsManage /></RequireAuth>}, { path: "products",element: <RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsManage /></RequireAuth>},
{ path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsAudit /></RequireAuth>}, { path: "products/:travel_agency_id/:use_year/:audit_state/audit",element:<RequireAuth subject={PERM_PRODUCTS_MANAGEMENT} result={true}><ProductsAudit /></RequireAuth>},
{ path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT} result={true}><ProductsDetail /></RequireAuth>}, { path: "products/:travel_agency_id/:use_year/:audit_state/edit",element:<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT} result={true}><ProductsDetail /></RequireAuth>},
{ path: "products/audit",element:<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT} result={true}><ProductsAudit /></RequireAuth>},
{ path: "products/edit",element:<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT} result={true}><ProductsDetail /></RequireAuth>}, { path: "products/edit",element:<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT} result={true}><ProductsDetail /></RequireAuth>},
] ]
}, },

@ -5,11 +5,14 @@ import { useProductsTypes, useProductsAuditStatesMapVal } from '@/hooks/useProdu
import SecondHeaderWrapper from '@/components/SecondHeaderWrapper'; import SecondHeaderWrapper from '@/components/SecondHeaderWrapper';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useProductsStore, { postProductsQuoteAuditAction, } from '@/stores/Products/Index'; import useProductsStore, { postProductsQuoteAuditAction, } from '@/stores/Products/Index';
import { cloneDeep, isEmpty } from '@/utils/commons'; import { cloneDeep, isEmpty, isNotEmpty } from '@/utils/commons';
import useAuthStore from '@/stores/Auth'; import useAuthStore from '@/stores/Auth';
import RequireAuth from '@/components/RequireAuth'; import RequireAuth from '@/components/RequireAuth';
import { PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from '@/config'; import { PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from '@/config';
import Header from './Detail/Header'; import Header from './Detail/Header';
import dayjs from 'dayjs';
import { usingStorage } from '@/hooks/usingStorage';
const PriceTable = ({ productType, dataSource, refresh }) => { const PriceTable = ({ productType, dataSource, refresh }) => {
const { t } = useTranslation('products'); const { t } = useTranslation('products');
const { travel_agency_id, use_year, audit_state } = useParams(); const { travel_agency_id, use_year, audit_state } = useParams();
@ -58,7 +61,8 @@ const PriceTable = ({ productType, dataSource, refresh }) => {
const columns = [ const columns = [
{ key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan, }), className: 'bg-white', render: (text, r) => { { key: 'title', dataIndex: ['info', 'title'], width: '16rem', title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan, }), className: 'bg-white', render: (text, r) => {
const title = text || r.lgc_details?.['2']?.title || r.lgc_details?.['1']?.title || ''; const title = text || r.lgc_details?.['2']?.title || r.lgc_details?.['1']?.title || '';
return isPermitted(PERM_PRODUCTS_OFFER_PUT) ? <span onClick={() => setEditingProduct({info: r.info})}><Link to={`/products/${travel_agency_id}/${use_year}/${audit_state}/edit`} >{title}</Link></span> : title; const itemLink = isPermitted(PERM_PRODUCTS_OFFER_AUDIT) ? `/products/${travel_agency_id}/${use_year}/${audit_state}/edit` : isPermitted(PERM_PRODUCTS_OFFER_PUT) ? `/products/edit` : '';
return isNotEmpty(itemLink) ? <span onClick={() => setEditingProduct({info: r.info})}><Link to={itemLink} >{title}</Link></span> : title;
} }, } },
// ...(productType === 'B' ? [{ key: 'km', dataIndex: ['info', 'km'], title: t('KM')}] : []), // ...(productType === 'B' ? [{ key: 'km', dataIndex: ['info', 'km'], title: t('KM')}] : []),
{ key: 'adult', title: t('AgeType.Adult'), render: (_, { adult_cost, currency, unit_id, unit_name }) => `${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}` }, { key: 'adult', title: t('AgeType.Adult'), render: (_, { adult_cost, currency, unit_id, unit_name }) => `${adult_cost} ${currency} / ${t(`PriceUnit.${unit_id}`)}` },
@ -161,10 +165,11 @@ const TypesPanels = (props) => {
const Audit = ({ ...props }) => { const Audit = ({ ...props }) => {
const { travel_agency_id, use_year, audit_state } = useParams(); const { travel_agency_id, use_year, audit_state } = useParams();
const [loading, activeAgency, getAgencyProducts] = useProductsStore((state) => [state.loading, state.activeAgency, state.getAgencyProducts]); const [loading, activeAgency, getAgencyProducts] = useProductsStore((state) => [state.loading, state.activeAgency, state.getAgencyProducts]);
const { travelAgencyId } = usingStorage();
const handleGetAgencyProducts = ({pick_year, pick_agency, pick_state}={}) => { const handleGetAgencyProducts = ({pick_year, pick_agency, pick_state}={}) => {
const year = pick_year || use_year; const year = pick_year || use_year || dayjs().year();
const agency = pick_agency || travel_agency_id; const agency = pick_agency || travel_agency_id || travelAgencyId;
const state = pick_state ?? audit_state; const state = pick_state ?? audit_state;
getAgencyProducts({ travel_agency_id: agency, use_year: year, audit_state: state }); getAgencyProducts({ travel_agency_id: agency, use_year: year, audit_state: state });
}; };

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { message, Divider, Empty, Flex } from 'antd'; import { message, Divider, Empty, Flex } from 'antd';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import Extras from './Detail/Extras'; import Extras from './Detail/Extras';
@ -9,7 +9,7 @@ import { useParams } from 'react-router-dom';
import useProductsStore from '@/stores/Products/Index'; import useProductsStore from '@/stores/Products/Index';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { HT_HOST } from '@/config'; import { HT_HOST } from '@/config';
import { postJSON, postForm } from '@/utils/request'; import { postForm } from '@/utils/request';
import { PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from '@/config'; import { PERM_PRODUCTS_OFFER_AUDIT, PERM_PRODUCTS_OFFER_PUT } from '@/config';
import { usingStorage } from '@/hooks/usingStorage'; import { usingStorage } from '@/hooks/usingStorage';
import ProductsTree from './Detail/ProductsTree'; import ProductsTree from './Detail/ProductsTree';
@ -20,18 +20,12 @@ import NewProductModal from './Detail/NewProductModal';
function Detail() { function Detail() {
// const { t } = useTranslation(); // const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const [quotation, setQuotation] = useState(null);
const [lgc_details, setLgc_details] = useState(null);
// const [languageLabel, setLanguageLabel] = useState(null);
const { travel_agency_id, audit_state, use_year } = useParams(); const { travel_agency_id, audit_state, use_year } = useParams();
// const HTLanguageSets = useHTLanguageSets();
// const { Search } = Input;
const [addProductVisible, setAddProductVisible] = useState(false); const [addProductVisible, setAddProductVisible] = useState(false);
const [editingProduct, setEditingProduct] = useProductsStore((state) => [state.editingProduct, state.setEditingProduct]); const [editingProduct, ] = useProductsStore((state) => [state.editingProduct]);
const [agencyProducts, setAgencyProducts, loading] = useProductsStore((state) => [state.agencyProducts, state.setAgencyProducts, state.loading]); const [agencyProducts, loading] = useProductsStore((state) => [state.agencyProducts, state.loading]);
const [getAgencyProducts, activeAgency] = useProductsStore((state) => [state.getAgencyProducts, state.activeAgency]); const [getAgencyProducts, activeAgency] = useProductsStore((state) => [state.getAgencyProducts, state.activeAgency]);
const [switchParams, setSwitchParams] = useProductsStore((state) => [state.switchParams, state.setSwitchParams]); const [setSwitchParams] = useProductsStore((state) => [state.setSwitchParams]);
const [info, setInfo] = useState();
const yearOptions = []; const yearOptions = [];
const currentYear = dayjs().year(); const currentYear = dayjs().year();
const baseYear = Number(use_year === 'all' ? currentYear : use_year); const baseYear = Number(use_year === 'all' ? currentYear : use_year);
@ -113,79 +107,79 @@ function Detail() {
}, [activeAgency, editingProduct]); }, [activeAgency, editingProduct]);
// //
const onSave = async (values) => { // const onSave = async (values) => {
let tempInfo; // let tempInfo;
if (info.id === '') { // if (info.id === '') {
tempInfo = { // tempInfo = {
...info, // ...info,
...values.info, // ...values.info,
city_name: values.info.city_name.label, // city_name: values.info.city_name.label,
audit_state: '-1', // audit_state: '-1',
}; // };
delete tempInfo.product_type_name; // delete tempInfo.product_type_name;
delete tempInfo.dept_name; // delete tempInfo.dept_name;
let tempQuotation = quotation.map((element) => { // let tempQuotation = quotation.map((element) => {
const updateData = { // const updateData = {
...element, // ...element,
audit_state: '-1', // audit_state: '-1',
}; // };
delete updateData.tempKey; // delete updateData.tempKey;
return updateData; // return updateData;
}); // });
let tempLgc_details = [{ ...lgc_details }]; // let tempLgc_details = [{ ...lgc_details }];
const tempData = { // const tempData = {
travel_agency_id, // travel_agency_id,
info: tempInfo, // info: tempInfo,
quotation: tempQuotation, // quotation: tempQuotation,
lgc_details: Object.values(lgc_details), // lgc_details: Object.values(lgc_details),
}; // };
console.log('tempData', tempData); // console.log('tempData', tempData);
const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, tempData); // const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, tempData);
console.log('result', result); // console.log('result', result);
if (errcode === 0) { // if (errcode === 0) {
message.success('保存成功'); // message.success('');
} else { // } else {
message.error(`保存失败: ${result}`); // message.error(`: ${result}`);
} // }
return; // return;
} // }
tempInfo = { // tempInfo = {
...info, // ...info,
...values.info, // ...values.info,
audit_state: '-1', // audit_state: '-1',
}; // };
console.log('tempInfo', tempInfo); // console.log('tempInfo', tempInfo);
let tempQuotation = quotation.map((element) => { // let tempQuotation = quotation.map((element) => {
const updateData = { // const updateData = {
...element, // ...element,
audit_state: '-1', // audit_state: '-1',
}; // };
return updateData; // return updateData;
}); // });
const tempData = { // const tempData = {
travel_agency_id, // travel_agency_id,
info: tempInfo, // info: tempInfo,
quotation: tempQuotation, // quotation: tempQuotation,
lgc_details: Object.values(lgc_details), // lgc_details: Object.values(lgc_details),
}; // };
console.log('tempData', tempData); // console.log('tempData', tempData);
// const { errcode, result } = await postProductsSave(tempData); // // const { errcode, result } = await postProductsSave(tempData);
const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, tempData); // const { errcode, result } = await postJSON(`${HT_HOST}/Service_BaseInfoWeb/agency_product_save`, tempData);
if (errcode === 0) { // if (errcode === 0) {
message.success('保存成功'); // message.success('');
} else { // } else {
message.error(`保存失败: ${result}`); // message.error(`: ${result}`);
} // }
return; // return;
}; // };
// //
const submitReview = async () => { const submitReview = async () => {

@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useParams, Link, useNavigate } from 'react-router-dom'; import { useParams, Link, useNavigate, useLocation } from 'react-router-dom';
import { App, Button, Divider, Select } from 'antd'; import { App, Button, Divider, Select } from 'antd';
import { useProductsAuditStatesMapVal } from '@/hooks/useProductsSets'; import { useProductsAuditStatesMapVal } from '@/hooks/useProductsSets';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -13,6 +13,10 @@ import dayjs from 'dayjs';
import VendorSelector from '@/components/VendorSelector'; import VendorSelector from '@/components/VendorSelector';
import AuditStateSelector from '@/components/AuditStateSelector'; import AuditStateSelector from '@/components/AuditStateSelector';
const Header = ({ refresh, editable, ...props }) => { const Header = ({ refresh, editable, ...props }) => {
const location = useLocation();
console.log(location);
const showEditA = !location.pathname.includes('edit');
const showAuditA = !location.pathname.includes('audit');
const { travel_agency_id, use_year, audit_state } = useParams(); const { travel_agency_id, use_year, audit_state } = useParams();
const { t } = useTranslation(); const { t } = useTranslation();
const isPermitted = useAuthStore((state) => state.isPermitted); const isPermitted = useAuthStore((state) => state.isPermitted);
@ -107,15 +111,16 @@ const Header = ({ refresh, editable, ...props }) => {
{(use_year || '').replace('all', '')} */} {(use_year || '').replace('all', '')} */}
</h2> </h2>
</div> </div>
{/* <Button size='small'>{t('Copy')}</Button> */} {showEditA && (
{/* <Button size='small'>{t('Import')}</Button> */} <Link className='px-2' to={isPermitted(PERM_PRODUCTS_OFFER_AUDIT) ? `/products/${activeAgency.travel_agency_id}/${pickYear}/${audit_state}/edit` : `/products/edit`}>
{/* PERM_PRODUCTS_OFFER_PUT */}
<RequireAuth subject={PERM_PRODUCTS_OFFER_AUDIT}>
<Link className='px-2' to={`/products/${activeAgency.travel_agency_id}/${pickYear}/${audit_state}/edit`}>
{t('Edit')} {t('Edit')}
</Link> </Link>
</RequireAuth> )}
{/* todo: edit/audit 链接 */} {showAuditA && (
<Link className='px-2' to={isPermitted(PERM_PRODUCTS_OFFER_AUDIT) ? `/products/${activeAgency.travel_agency_id}/${pickYear}/${audit_state}/audit` : `/products/audit`}>
{t('products:AuditRes')}
</Link>
)}
<RequireAuth subject={PERM_PRODUCTS_OFFER_AUDIT}> <RequireAuth subject={PERM_PRODUCTS_OFFER_AUDIT}>
<Button size='small' type={'primary'} onClick={() => handleAuditItem('2', activeAgency)}> <Button size='small' type={'primary'} onClick={() => handleAuditItem('2', activeAgency)}>
{t('products:auditStateAction.Published')} {t('products:auditStateAction.Published')}
@ -136,19 +141,22 @@ const Header = ({ refresh, editable, ...props }) => {
</RequireAuth> </RequireAuth>
{/* 编辑 */} {/* 编辑 */}
<Divider type='vertical' /> <Divider type='vertical' />
{editable && {editable && (
<><RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}> <>
<Button size='small' type={'primary'} onClick={props.handleNewProduct}> <RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}>
{t('New')}{t('products:#')} <Button size='small' type={'primary'} onClick={props.handleNewProduct}>
</Button> {t('New')}
</RequireAuth> {t('products:#')}
<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}> </Button>
<Button size='small' type={'primary'} onClick={props.handleSubmitForAudit}> </RequireAuth>
{t('Submit')}{t('Audit')} <RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}>
</Button> <Button size='small' type={'primary'} onClick={props.handleSubmitForAudit}>
</RequireAuth> {t('Submit')}
</> {t('Audit')}
} </Button>
</RequireAuth>
</>
)}
</div> </div>
); );
}; };

@ -163,7 +163,7 @@ function getFields(props) {
fieldProps?.code?.col || midCol fieldProps?.code?.col || midCol
), ),
item( item(
'city', // todo: 'city',
99, 99,
<Form.Item name='city' label={t('City')} {...fieldProps.city}> <Form.Item name='city' label={t('City')} {...fieldProps.city}>
<CitySelector {...styleProps} {...editableProps('city_id')} /> <CitySelector {...styleProps} {...editableProps('city_id')} />
@ -171,7 +171,7 @@ function getFields(props) {
fieldProps?.city?.col || midCol fieldProps?.city?.col || midCol
), ),
item( item(
'dept', // todo: 'dept',
99, 99,
<Form.Item name='dept' label={t('Dept')} {...fieldProps.dept}> <Form.Item name='dept' label={t('Dept')} {...fieldProps.dept}>
<DeptSelector labelInValue={false} isLeaf {...styleProps} {...editableProps('dept')} /> <DeptSelector labelInValue={false} isLeaf {...styleProps} {...editableProps('dept')} />
@ -196,7 +196,7 @@ function getFields(props) {
fieldProps?.km?.col || midCol fieldProps?.km?.col || midCol
), ),
item( item(
'recommends_rate', // todo: 'recommends_rate',
99, 99,
<Form.Item name='recommends_rate' label={t('RecommendsRate')} {...fieldProps.recommends_rate}> <Form.Item name='recommends_rate' label={t('RecommendsRate')} {...fieldProps.recommends_rate}>
{/* <Input placeholder={t('RecommendsRate')} allowClear /> */} {/* <Input placeholder={t('RecommendsRate')} allowClear /> */}

Loading…
Cancel
Save