feat: 产品管理: 客服审核产品, 价格

feature/price_manager
Lei OT 1 year ago
parent d24c34d4ac
commit f8ffaf899d

@ -16,6 +16,13 @@
"Rejected": "Rejected", "Rejected": "Rejected",
"Published": "Published" "Published": "Published"
}, },
"auditStateAction": {
"New": "New",
"Pending": "Pending",
"Approved": "Approve",
"Rejected": "Rejecte",
"Published": "Publish"
},
"Status": "Status", "Status": "Status",
"State": "State", "State": "State",

@ -16,6 +16,13 @@
"Rejected": "已拒绝", "Rejected": "已拒绝",
"Published": "已发布" "Published": "已发布"
}, },
"auditStateAction": {
"New": "新增",
"Pending": "待审核",
"Approved": "审核通过",
"Rejected": "审核拒绝",
"Published": "发布上线"
},
"Status": "状态", "Status": "状态",
"State": "状态", "State": "状态",

@ -1,32 +1,53 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { devtools } from 'zustand/middleware'; import { devtools } from 'zustand/middleware';
import { fetchJSON } from '@/utils/request'; import { fetchJSON, postForm } from '@/utils/request';
import { HT_HOST } from '@/config'; import { HT_HOST } from '@/config';
import { groupBy } from '@/utils/commons'; import { groupBy } from '@/utils/commons';
const searchAgencyAction = async (param) => { export const searchAgencyAction = async (param) => {
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param); const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param);
return errcode !== 0 ? [] : result; return errcode !== 0 ? [] : result;
}; };
const getAgencyProducts = async (param) => { export const getAgencyProductsAction = async (param) => {
const { errcode, Result, Result1 } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param); const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/travel-agency-products`, param);
return errcode !== 0 ? [] : result;
};
export const postProductsQuoteAudit = async (auditState, quoteRow) => {
const postbody = {
audit_state: auditState,
id: quoteRow.id,
travel_agency_id: quoteRow.info.travel_agency_id,
};
const formData = new FormData();
Object.keys(postbody).forEach((key) => {
formData.append(key, postbody[key]);
});
const json = await postForm(`${HT_HOST}/Service_BaseInfoWeb/travel-agency-products-quote-audit`, formData);
return json;
// return errcode !== 0 ? {} : result;
};
export const postProductsAudit = async (auditState, infoRow) => {
const postbody = {
audit_state: auditState,
id: infoRow.id,
travel_agency_id: infoRow.travel_agency_id,
};
const formData = new FormData();
Object.keys(postbody).forEach((key) => {
formData.append(key, postbody[key]);
});
const json = await postForm(`${HT_HOST}/Service_BaseInfoWeb/travel-agency-products-audit`, formData);
return json;
// const { errcode, result } = json;
// return errcode !== 0 ? {} : result;
}; };
const initialState = { const initialState = {
loading: false, loading: false,
agencyList: [ agencyList: [],
{
'audit_date': '2001-03-03',
'travel_agency_name': '新油低外',
'travel_agency_id': '650000200301029585',
'created_by': '冯丽',
'create_date': '1989-06-20',
'lastedit_memo': 'nostrud ad eu',
'audited_by': '黎静',
'audit_state': '1',
},
],
activeAgency: {}, activeAgency: {},
agencyProducts: groupBy([ agencyProducts: groupBy([
{ {
@ -280,6 +301,17 @@ export const useProductsStore = create(
setAgencyList(res); setAgencyList(res);
setLoading(false); setLoading(false);
}, },
getAgencyProducts: async (param) => {
const { setLoading, setActiveAgency, setAgencyProducts } = get();
setLoading(true);
const res = await getAgencyProductsAction(param);
const productsData = groupBy(res, row => row.info.type);
setAgencyProducts(productsData);
setActiveAgency(res[0].info);
setLoading(false);
},
})) }))
); );
export default useProductsStore; export default useProductsStore;

@ -1,14 +1,31 @@
import { createContext, useContext, useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Link, useLocation, } from 'react-router-dom'; import { useParams, } from 'react-router-dom';
import { Button, Collapse, Table, Tabs, Typography, Space, } from 'antd'; import { App, Button, Collapse, Table, Space, } from 'antd';
import { useProductsTypes, useProductsAuditStatesMapVal, useProductsAuditStates } from '@/hooks/useProductsSets'; import { useProductsTypes, useProductsAuditStatesMapVal } from '@/hooks/useProductsSets';
import SecondHeaderWrapper from '@/components/SecondHeaderWrapper'; import SecondHeaderWrapper from '@/components/SecondHeaderWrapper';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import useProductsStore from '@/stores/Products/Index'; import useProductsStore, { postProductsQuoteAudit } from '@/stores/Products/Index';
import { isEmpty } from '@/utils/commons'; import { isEmpty } from '@/utils/commons';
const Header = ({title, ...props}) => { const Header = ({ title, agency, ...props}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { message, notification } = App.useApp();
const handleAuditItem = (state, row) => {
postProductsQuoteAudit(state, row)
.then((json) => {
if (json.errcode === 0) {
message.success('✔');
}
})
.catch((ex) => {
notification.error({
message: 'Notification',
description: ex.message,
placement: 'top',
duration: 4,
});
});
};
return ( return (
<div className='flex justify-end items-center gap-4 h-full'> <div className='flex justify-end items-center gap-4 h-full'>
<div className='grow'> <div className='grow'>
@ -16,15 +33,37 @@ const Header = ({title, ...props}) => {
</div> </div>
{/* <Button size='small'>{t('Copy')}</Button> */} {/* <Button size='small'>{t('Copy')}</Button> */}
{/* <Button size='small'>{t('Import')}</Button> */} {/* <Button size='small'>{t('Import')}</Button> */}
<Button size='small' type={'primary'} ghost>{t('Export')} PDF</Button> <Button size='small' type={'primary'} ghost onClick={() => handleAuditItem('2', agency)}>
{t('products:auditStateAction.Approved')}
</Button>
{/* todo: export */}
<Button size='small'>{t('Export')} PDF</Button>
</div> </div>
); );
}; };
const PriceTable = ({dataSource, loading}) => { const PriceTable = ({dataSource, loading}) => {
const { t } = useTranslation('products'); const { t } = useTranslation('products');
const { message, notification } = App.useApp();
const stateMapVal = useProductsAuditStatesMapVal(); const stateMapVal = useProductsAuditStatesMapVal();
const handleAuditPriceItem = (state, row) => {
postProductsQuoteAudit(state, row)
.then((json) => {
if (json.errcode === 0) {
message.success('✔');
}
})
.catch((ex) => {
notification.error({
message: 'Notification',
description: ex.message,
placement: 'top',
duration: 4,
});
});
};
const columns = [ const columns = [
{ key: 'title', dataIndex: ['info', 'title'], title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan }) }, { key: 'title', dataIndex: ['info', 'title'], title: t('Title'), onCell: (r, index) => ({ rowSpan: r.rowSpan }) },
{ key: 'value', title: t('Quotation'), render: (_, { value, currency, unit }) => `${value} ${currency} / ${unit}` }, { key: 'value', title: t('Quotation'), render: (_, { value, currency, unit }) => `${value} ${currency} / ${unit}` },
@ -55,10 +94,10 @@ const PriceTable = ({dataSource, loading}) => {
{ {
title: '', title: '',
key: 'action', key: 'action',
render: () => ( render: (_, r) => (
<Space> <Space>
<Button></Button> <Button onClick={() => handleAuditPriceItem('2', r)}></Button>
<Button></Button> <Button onClick={() => handleAuditPriceItem('0', r)}></Button>
</Space> </Space>
), ),
}, },
@ -76,11 +115,19 @@ const TypesPanels = () => {
const [activeKey, setActiveKey] = useState([]); const [activeKey, setActiveKey] = useState([]);
const [showTypes, setShowTypes] = useState([]); const [showTypes, setShowTypes] = useState([]);
useEffect(() => { useEffect(() => {
// // ; ,
const hasDataTypes = Object.keys(agencyProducts); const hasDataTypes = Object.keys(agencyProducts);
const _show = productsTypes const _show = productsTypes
.filter((kk) => hasDataTypes.includes(kk.value)) .filter((kk) => hasDataTypes.includes(kk.value))
.map((ele) => ({ ...ele, children: <PriceTable loading={loading} dataSource={agencyProducts[ele.value].reduce((r, c) => r.concat(c.quotation.map((q, i) => ({ ...q, info: c.info, rowSpan: i=== 0 ? c.quotation.length : 0 }))), [])} /> })); .map((ele) => ({
...ele,
children: (
<PriceTable
loading={loading}
dataSource={agencyProducts[ele.value].reduce((r, c) => r.concat(c.quotation.map((q, i) => ({ ...q, info: c.info, rowSpan: i === 0 ? c.quotation.length : 0 }))), [])}
/>
),
}));
setShowTypes(_show); setShowTypes(_show);
setActiveKey(isEmpty(_show) ? [] : [_show[0].key]); setActiveKey(isEmpty(_show) ? [] : [_show[0].key]);
@ -97,14 +144,24 @@ const TypesPanels = () => {
} }
const Audit = ({ ...props }) => { const Audit = ({ ...props }) => {
// const [loading, agencyProducts] = useProductsStore((state) => [state.loading, state.agencyProducts]); const { agencyId: travel_agency_id } = useParams();
const [activeAgency, getAgencyProducts] = useProductsStore((state) => [state.activeAgency, state.getAgencyProducts]);
const handleGetAgencyProducts = () => {
getAgencyProducts({ travel_agency_id });
}
useEffect(() => {
handleGetAgencyProducts();
return () => {};
}, [travel_agency_id])
return ( return (
<> <>
<SecondHeaderWrapper header={<Header title={'{供应商名字}'} />}> <SecondHeaderWrapper header={<Header title={activeAgency.travel_agency_name} agency={activeAgency} />}>
<hr /> <hr />
<TypesPanels /> <TypesPanels />
{/* <PriceTable dataSource={agencyProductsList} /> */}
</SecondHeaderWrapper> </SecondHeaderWrapper>
</> </>
); );

Loading…
Cancel
Save