feat: 产品管理: 客服首页

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

@ -25,6 +25,10 @@
"Export": "Export",
"Copy": "Copy",
"Table": {
"Total": "Total {{total}} items"
},
"Login": "Login",
"Username": "Username",
"Password": "Password",

@ -12,11 +12,12 @@
"auditState": {
"New": "New",
"Pending": "Pending",
"Approve": "Approve",
"Approved": "Approved",
"Rejected": "Rejected",
"Published": "Published"
},
"Status": "Status",
"State": "State",
"Title": "Title",
"Vendor": "Vendor",
@ -27,6 +28,8 @@
"AuditDate": "Audit Date",
"Quotation": "Quotation",
"Offer": "Offer",
"Unit": "Unit",
"GroupSize": "Group Size",
"UseDates": "Use Dates",

@ -25,6 +25,10 @@
"Export": "导出",
"Copy": "复制",
"Table": {
"Total": "共 {{total}} 条"
},
"Login": "登录",
"Username": "账号",
"Password": "密码",

@ -12,11 +12,12 @@
"auditState": {
"New": "新增",
"Pending": "待审核",
"Approve": "已通过",
"Approved": "已通过",
"Rejected": "已拒绝",
"Published": "已发布"
},
"Status": "状态",
"State": "状态",
"Title": "名称",
"Vendor": "供应商",
@ -27,6 +28,7 @@
"AuditDate": "审核时间",
"Quotation": "报价",
"Offer": "报价",
"Unit": "单位",
"GroupSize": "人等",
"UseDates": "使用日期",

@ -50,7 +50,7 @@ const SearchForm = ({ initialValue, onSubmit, onReset, ...props }) => {
{ key: 'endtime', transform: (arrVal) => (arrVal ? arrVal[1].format(SMALL_DATETIME_FORMAT) : '') },
],
'invoiceStatus': { key: 'invoiceStatus', transform: (value) => value?.value || value?.key || '', default: '' },
'auditState': { key: 'auditState', transform: (value) => value?.value || value?.key || '', default: '' },
'audit_state': { key: 'audit_state', transform: (value) => value?.value || value?.key || '', default: '' },
'agency': {
key: 'agency',
transform: (value) => {
@ -217,12 +217,12 @@ function getFields(props) {
fieldProps?.agency?.col || 6
),
item(
'auditState',
'audit_state',
99,
<Form.Item name={`auditState`} initialValue={at(props, 'initialValue.auditState')[0] || { value: '', label: 'Status' }}>
<Form.Item name={`audit_state`} initialValue={at(props, 'initialValue.audit_state')[0] || { value: '', label: 'Status' }}>
<AuditStateSelector />
</Form.Item>,
fieldProps?.auditState?.col || 3
fieldProps?.audit_state?.col || 3
),
];

@ -33,14 +33,20 @@ export const useProductsAuditStates = () => {
useEffect(() => {
const newData = [
{ key: '0', value: '0', label: t('products:auditState.New') },
{ key: '1', value: '1', label: t('products:auditState.Pending') },
{ key: '2', value: '2', label: t('products:auditState.Approve') },
{ key: '3', value: '3', label: t('products:auditState.Rejected') },
{ key: '4', value: '4', label: t('products:auditState.Published') },
{ key: '-1', value: '-1', label: t('products:auditState.New') },
{ key: '0', value: '0', label: t('products:auditState.Pending') },
{ key: '2', value: '2', label: t('products:auditState.Approved') },
// { key: '3', value: '3', label: t('products:auditState.Rejected') },
{ key: '1', value: '1', label: t('products:auditState.Published') },
];
setTypes(newData);
}, [i18n.language]);
return types;
};
export const useProductsAuditStatesMapVal = (value) => {
const stateSets = useProductsAuditStates();
const stateMapVal = stateSets.reduce((r, c) => ({ ...r, [`${c.value}`]: c }), {});
return stateMapVal;
};

@ -5,9 +5,9 @@ import { fetchJSON } from '@/utils/request';
import { HT_HOST } from '@/config';
import { groupBy } from '@/utils/commons';
const searchAgency = async (param) => {
const searchAgencyAction = async (param) => {
const { errcode, result } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param);
return errcode !== 0 ? [] : result;
};
const getAgencyProducts = async (param) => {
const { errcode, Result, Result1 } = await fetchJSON(`${HT_HOST}/Service_BaseInfoWeb/products_search`, param);
@ -265,6 +265,7 @@ export const useProductsStore = create(
...initialState,
// state actions
setLoading: loading => set({ loading }),
setAgencyList: (agencyList) => set({ agencyList }),
setActiveAgency: activeAgency => set({ activeAgency }),
setAgencyProducts: agencyProducts => set({ agencyProducts }),
@ -272,6 +273,13 @@ export const useProductsStore = create(
reset: () => set(initialState),
// side effects
searchAgency: async (param) => {
const { setLoading, setAgencyList } = get();
setLoading(true);
const res = await searchAgencyAction(param);
setAgencyList(res);
setLoading(false);
},
}))
);
export default useProductsStore;

@ -1,7 +1,7 @@
import { createContext, useContext, useEffect, useState } from 'react';
import { Link, useLocation, } from 'react-router-dom';
import { Button, Collapse, Table, Tabs, Typography, Space, } from 'antd';
import { useProductsTypes } from '@/hooks/useProductsSets';
import { useProductsTypes, useProductsAuditStatesMapVal, useProductsAuditStates } from '@/hooks/useProductsSets';
import SecondHeaderWrapper from '@/components/SecondHeaderWrapper';
import { useTranslation } from 'react-i18next';
import useProductsStore from '@/stores/Products/Index';
@ -21,26 +21,10 @@ const Header = ({title, ...props}) => {
);
};
const TypesTabs = () => {
const productsTypes = useProductsTypes();
return (
<Tabs items={productsTypes} type='card' />
)
}
const subjectComponents = {
// 'sum_profit': ProfitTable,
// 'in_order_count': Count,
// 'confirm_order_count': Count,
// 'depart_order_count': Count,
// 'confirm_rates': Rates,
// 'praise_rates': Rates,
// 'sum_person_num': Count,
};
const PriceTable = ({dataSource}) => {
const PriceTable = ({dataSource, loading}) => {
const { t } = useTranslation('products');
// console.log(dataSource, );
const stateMapVal = useProductsAuditStatesMapVal();
const columns = [
{ 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}` },
@ -52,23 +36,29 @@ const PriceTable = ({dataSource}) => {
key: 'groupSize',
dataIndex: ['group_size_min'],
title: t('GroupSize'),
render: (_, { group_size_min, group_size_max} ) => `${group_size_min} - ${group_size_max}`,
render: (_, { group_size_min, group_size_max }) => `${group_size_min} - ${group_size_max}`,
},
{
key: 'useDates',
dataIndex: ['use_dates_start'],
title: t('UseDates'),
render: (_, { use_dates_start, use_dates_end} ) => `${use_dates_start} ~ ${use_dates_end}`,
render: (_, { use_dates_start, use_dates_end }) => `${use_dates_start} ~ ${use_dates_end}`,
},
{ key: 'weekdays', dataIndex: ['weekdays'], title: t('Weekdays') },
{
key: 'state',
title: t('State'),
render: (_, r) => {
return stateMapVal[`${r.info.audit_state}`]?.label;
},
},
{ key: 'weekdays', dataIndex: ['weekdays'], title: t('Weekdays'), },
{key: 'status', title: t('Status'), render: () => '已通过'},
{
title: '',
key: 'action',
render: () => (
<Space>
<Button ></Button>
<Button ></Button>
<Button></Button>
<Button></Button>
</Space>
),
},
@ -90,7 +80,7 @@ const TypesPanels = () => {
const hasDataTypes = Object.keys(agencyProducts);
const _show = productsTypes
.filter((kk) => hasDataTypes.includes(kk.value))
.map((ele) => ({ ...ele, children: <PriceTable 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);
setActiveKey(isEmpty(_show) ? [] : [_show[0].key]);

@ -1,22 +1,29 @@
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Row, Col, Space, Typography, Table, Button } from 'antd';
import { usingStorage } from '@/hooks/usingStorage';
import { Row, Col, Space, Table } from 'antd';
import SearchForm from '@/components/SearchForm';
import dayjs from 'dayjs';
import { useTranslation } from 'react-i18next';
import useProductsStore from '@/stores/Products/Index';
import { useProductsTypes } from '@/hooks/useProductsSets';
import useFormStore from '@/stores/Form';
import { objectMapper } from '@/utils/commons';
function Index() {
const { t } = useTranslation();
const { userId } = usingStorage();
const [loading, agencyList, ] = useProductsStore((state) => [state.loading, state.agencyList, ]);
const [loading, agencyList, searchAgency] = useProductsStore((state) => [state.loading, state.agencyList, state.searchAgency]);
const formValuesToSub = useFormStore(state => state.formValuesToSub);
const [noticeList, setNoticeList] = useState([]);
useEffect(() => {}, []);
const handleSearchAgency = (formVal = undefined) => {
const { starttime, endtime, ...param } = formVal || formValuesToSub;
const searchParam = objectMapper(param, { agency: 'travel_agency_id', startdate: 'edit_date1', enddate: 'edit_date2' });
searchAgency(searchParam);
}
const showTotal = (total) => `Total ${total} items`;
useEffect(() => {
handleSearchAgency();
}, []);
const showTotal = (total) => t('Table.Total', { total });
const columns = [
{ title: t('products:Vendor'), key: 'vendor', dataIndex: 'travel_agency_name' },
@ -40,18 +47,22 @@ function Index() {
<Space direction='vertical' style={{ width: '100%' }}>
<SearchForm
fieldsConfig={{
shows: ['agency', 'auditState', 'dates', 'keyword'], // todo:
shows: ['agency', 'audit_state', 'dates', 'keyword'], // todo:
fieldProps: {
dates: { label: t('products:CreateDate') },
keyword: { label: t('products:Title')},
},
sort: { agency: 1, auditState: 2, keyword: 100},
fieldComProps: {
agency: { mode: null }, //
},
sort: { agency: 1, audit_state: 2, keyword: 100},
}}
initialValue={{
dates: [dayjs().subtract(2, 'M').startOf('M'), dayjs().endOf('M')],
auditState: { value: '', label: t('products:Status')},
audit_state: { value: '', label: t('products:State')},
}}
onSubmit={(err, formVal, filedsVal) => {
handleSearchAgency(formVal);
}}
/>
<Row>

Loading…
Cancel
Save