供应商搜索产品页面
parent
ca0edbd63a
commit
1142a1a893
@ -0,0 +1,26 @@
|
||||
{
|
||||
"type": {
|
||||
"Experience": "Experience",
|
||||
"Car": "Transport Services",
|
||||
"Guide": "Guide Services",
|
||||
"Package": "Package",
|
||||
"Attractions": "Attractions",
|
||||
"Meals": "Meals",
|
||||
"Extras": "Extras",
|
||||
"Special": "Special"
|
||||
},
|
||||
"auditState": {
|
||||
"New": "New",
|
||||
"Pending": "Pending",
|
||||
"Approve": "Approve",
|
||||
"Rejected": "Rejected",
|
||||
"Published": "Published"
|
||||
},
|
||||
"Title": "Title",
|
||||
"Vendor": "Vendor",
|
||||
"AuState": "Audit State",
|
||||
"CreatedBy": "Created By",
|
||||
"CreateDate": "Create Date",
|
||||
"Auditors": "Auditors",
|
||||
"AuditDate": "Audit Date"
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"type": {
|
||||
"Experience": "综费",
|
||||
"Car": "车费",
|
||||
"Guide": "导服",
|
||||
"Package": "包价线路",
|
||||
"Attractions": "景点",
|
||||
"Meals": "餐费",
|
||||
"Extras": "附加",
|
||||
"Special": "特殊项目"
|
||||
},
|
||||
"auditState": {
|
||||
"New": "新增",
|
||||
"Pending": "待审核",
|
||||
"Approve": "已通过",
|
||||
"Rejected": "已拒绝",
|
||||
"Published": "已发布"
|
||||
},
|
||||
"Title": "名称",
|
||||
"Vendor": "供应商",
|
||||
"AuState": "审核状态",
|
||||
"CreatedBy": "提交人员",
|
||||
"CreateDate": "提交时间",
|
||||
"Auditors": "审核人员",
|
||||
"AuditDate": "审核时间"
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { Select, Spin } from 'antd';
|
||||
import { debounce, objectMapper } from '@/utils/commons';
|
||||
|
||||
function DebounceSelect({ fetchOptions, debounceTimeout = 800, ...props }) {
|
||||
const [fetching, setFetching] = useState(false);
|
||||
const [options, setOptions] = useState([]);
|
||||
const fetchRef = useRef(0);
|
||||
const debounceFetcher = useMemo(() => {
|
||||
const loadOptions = (value) => {
|
||||
fetchRef.current += 1;
|
||||
const fetchId = fetchRef.current;
|
||||
setOptions([]);
|
||||
setFetching(true);
|
||||
fetchOptions(value).then((newOptions) => {
|
||||
const mapperOptions = newOptions.map(ele => objectMapper(ele, props.map));
|
||||
if (fetchId !== fetchRef.current) {
|
||||
// for fetch callback order
|
||||
return;
|
||||
}
|
||||
setOptions(mapperOptions);
|
||||
setFetching(false);
|
||||
});
|
||||
};
|
||||
return debounce(loadOptions, debounceTimeout);
|
||||
}, [fetchOptions, debounceTimeout]);
|
||||
return (
|
||||
<Select
|
||||
labelInValue
|
||||
filterOption={false}
|
||||
showSearch
|
||||
allowClear
|
||||
maxTagCount={1}
|
||||
{...props}
|
||||
onSearch={debounceFetcher}
|
||||
notFoundContent={fetching ? <Spin size='small' /> : null}
|
||||
optionFilterProp='label'
|
||||
>
|
||||
{options.map((d) => (
|
||||
<Select.Option key={d.value} title={d.label}>
|
||||
{d.label}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
export default DebounceSelect;
|
@ -0,0 +1,46 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
/**
|
||||
* 产品管理 相关的预设数据
|
||||
*/
|
||||
|
||||
export const useProductsTypes = () => {
|
||||
const [types, setTypes] = useState([]);
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
const newData = [
|
||||
{ label: t('products:type.Experience'), value: t('products:type.Experience') },
|
||||
{label: t("products:type.Car"), value: t("products:type.Car"),},
|
||||
{label: t("products:type.Guide"), value: t("products:type.Guide"),},
|
||||
{label: t("products:type.Package"), value: t("products:type.Package"),},
|
||||
{label: t("products:type.Attractions"), value: t("products:type.Attractions"),},
|
||||
{label: t("products:type.Meals"), value: t("products:type.Meals"),},
|
||||
{label: t("products:type.Extras"), value: t("products:type.Extras"),},
|
||||
{label: t("products:type.Special"), value: t("products:type.Special")},
|
||||
];
|
||||
setTypes(newData);
|
||||
}, [i18n.language]);
|
||||
|
||||
return types;
|
||||
};
|
||||
|
||||
|
||||
export const useProductsAuditStatus = () => {
|
||||
const [types, setTypes] = useState([]);
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
const newData = [
|
||||
{ value: '0', label: 'New' },
|
||||
{ value: '1', label: 'Pending' },
|
||||
{ value: '2', label: 'Approve' },
|
||||
{ value: '3', label: 'Rejected' },
|
||||
{ value: '4', label: 'Published' },
|
||||
];
|
||||
setTypes(newData);
|
||||
}, [i18n.language]);
|
||||
|
||||
return types;
|
||||
};
|
@ -0,0 +1,24 @@
|
||||
import { create } from 'zustand';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
|
||||
import { fetchJSON } from '@/utils/request';
|
||||
import { HT_HOST } from '@/config';
|
||||
|
||||
const initialState = {
|
||||
loading: false,
|
||||
productsList: [],
|
||||
};
|
||||
export const useProductsStore = create(
|
||||
devtools((set, get) => ({
|
||||
// 初始化状态
|
||||
...initialState,
|
||||
|
||||
// state actions
|
||||
setProductsList: (productsList) => set({ productsList }),
|
||||
|
||||
reset: () => set(initialState),
|
||||
|
||||
// side effects
|
||||
}))
|
||||
);
|
||||
export default useProductsStore;
|
@ -0,0 +1,55 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Row, Col, Space, Typography, Table, Button } from 'antd';
|
||||
import useProductsStore from '@/stores/Products/Index';
|
||||
import { usingStorage } from '@/hooks/usingStorage';
|
||||
import SearchForm from '@/components/SearchForm';
|
||||
import dayjs from 'dayjs';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useProductsTypes } from '@/hooks/useProductsSets';
|
||||
|
||||
function Index() {
|
||||
const { t } = useTranslation();
|
||||
const { userId } = usingStorage();
|
||||
const [loading, productsList] = useProductsStore((state) => state.productsList);
|
||||
|
||||
const [noticeList, setNoticeList] = useState([]);
|
||||
useEffect(() => {}, []);
|
||||
|
||||
const showTotal = (total) => `Total ${total} items`;
|
||||
const columns = [
|
||||
{ title: t('products:Vendor'), key: '', dataIndex: '' },
|
||||
{ title: t('products:AuState'), key: '', dataIndex: '' },
|
||||
{ title: t('products:CreatedBy'), key: '', dataIndex: '' },
|
||||
{ title: t('products:CreateDate'), key: '', dataIndex: '' },
|
||||
{ title: t('products:Auditors'), key: '', dataIndex: '' },
|
||||
{ title: t('products:AuditDate'), key: '', dataIndex: '' },
|
||||
{ title: '', key: 'action', render: () => <Button>{t('Edit')}</Button> },
|
||||
];
|
||||
return (
|
||||
<Space direction='vertical' style={{ width: '100%' }}>
|
||||
<SearchForm
|
||||
initialValue={{
|
||||
dates: [dayjs().subtract(2, 'M').startOf('M'), dayjs().endOf('M')],
|
||||
}}
|
||||
fieldsConfig={{
|
||||
shows: ['agency', 'auditState', 'dates', 'keyword'], // todo: 是否多选
|
||||
fieldProps: {
|
||||
dates: { label: t('products:CreateDate') },
|
||||
keyword: { label: t('products:Title')},
|
||||
},
|
||||
sort: { agency: 1, auditState: 2, keyword: 100},
|
||||
}}
|
||||
onSubmit={(err, formVal, filedsVal) => {
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Col md={24} lg={24} xxl={24}>
|
||||
<Table bordered={true} columns={columns} dataSource={productsList} pagination={{ defaultPageSize: 20, showTotal: showTotal }} loading={loading} />
|
||||
</Col>
|
||||
<Col md={24} lg={24} xxl={24}></Col>
|
||||
</Row>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
export default Index;
|
Loading…
Reference in New Issue