feat: order list

master
guofei 2024-06-17 16:33:25 +08:00
parent 5a885942f2
commit fc52444bd4
8 changed files with 411 additions and 27 deletions

View File

@ -32,6 +32,12 @@ export default defineConfig({
redirect: '/home', redirect: '/home',
routes: [], routes: [],
}, },
{
name: '订单详情',
path: '/OrderDetails/:id',
component: 'Order/OrderDetails',
hideInMenu: true,
},
], ],
npmClient: 'pnpm', npmClient: 'pnpm',
}); });

View File

@ -0,0 +1,79 @@
import { getOrderByIdAPI } from '@/services/system/order';
import { OrderPayType, OrderPayTypeStr, OrderStatus, UxOrderStatus, UxOrderStatusTag } from '@/utils/const';
import { AlipayCircleOutlined, ArrowLeftOutlined, WechatOutlined } from '@ant-design/icons';
import { history, useParams } from '@umijs/max';
import { Button, Card, Descriptions, Skeleton } from 'antd';
import { useEffect, useState } from 'react';
const OrderDetails = () => {
const { id } = useParams();
const [orderInfo, seatOrderInfo] = useState<EditRow<Order.OrderItem>>();
useEffect(() => {
getOrderByIdAPI(id!).then((result) => {
if (result.code === 200) {
seatOrderInfo(result.data);
}
});
}, []);
return (
<>
<Card
className="m-4"
title={'订单号: ' + `${orderInfo ? orderInfo.orderNo : ''}`}
extra={
<>
<Button
type="link"
key={'back'}
onClick={() => {
history.push('/order');
}}
>
<ArrowLeftOutlined />
</Button>
</>
}
>
{orderInfo ? (
<Descriptions size="small" column={{ xs: 1, sm: 2, md: 3, lg: 3 }} bordered>
<Descriptions.Item label="用户">{orderInfo?.userEmail}</Descriptions.Item>
<Descriptions.Item label="订单单号">{orderInfo.orderNo}</Descriptions.Item>
<Descriptions.Item label="试用套餐">{orderInfo.isApply ? '是' : '否'}</Descriptions.Item>
<Descriptions.Item label="套餐名称">{orderInfo.goodsName}</Descriptions.Item>
<Descriptions.Item label="支付类型">
{orderInfo.payType === OrderPayType.WX && <WechatOutlined color="green" style={{ fontSize: '18px' }} />}
{orderInfo.payType === OrderPayType.ZFB && (
<AlipayCircleOutlined color="blue" style={{ fontSize: '18px' }} />
)}
<span className="ml-2"> {Reflect.get(OrderPayTypeStr, orderInfo.payType)}</span>
</Descriptions.Item>
<Descriptions.Item label="订单状态">
<div style={{ color: Reflect.get(UxOrderStatusTag, orderInfo.orderStatus) }} className="font-bold">
{Reflect.get(UxOrderStatus, orderInfo.orderStatus as number)}
</div>
</Descriptions.Item>
<Descriptions.Item label="单价">{orderInfo.price}</Descriptions.Item>
<Descriptions.Item label="数量">{orderInfo.quantity}</Descriptions.Item>
<Descriptions.Item label="支付总金额">{orderInfo?.totalPrice}</Descriptions.Item>
<Descriptions.Item label="订单过期时间">
{orderInfo?.orderStatus === OrderStatus.NO_PAY ? orderInfo.payCodeExpired : '-'}
</Descriptions.Item>
<Descriptions.Item label="第三方订单单号">{orderInfo.platformNo}</Descriptions.Item>
<Descriptions.Item label="第三方订单状态">{orderInfo.platformOrderStatus}</Descriptions.Item>
<Descriptions.Item label="订单创建时间">{orderInfo.createdDateTime}</Descriptions.Item>
<Descriptions.Item label="订单修改时间">{orderInfo.lastUpdateDateTime}</Descriptions.Item>
<Descriptions.Item label="备注">{orderInfo.comment}</Descriptions.Item>
</Descriptions>
) : (
<Skeleton active />
)}
</Card>
</>
);
};
export default OrderDetails;

View File

@ -1,5 +1,297 @@
const page = () => { import { getOrderListAPI } from '@/services/system/order';
return <></>; import { getPackageAPI } from '@/services/system/package';
import { OrderPayType, OrderPayTypeStr, OrderStatus, UxOrderStatus, UxOrderStatusTag } from '@/utils/const';
import { AlipayCircleOutlined, WechatOutlined } from '@ant-design/icons';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { history } from '@umijs/max';
import { Button, Select, TableProps } from 'antd';
import { useEffect, useRef, useState } from 'react';
const Page = () => {
const tableRef = useRef<ActionType>();
const [pkgOptions, setPkg] = useState<Package.PackageItem[]>([]);
const [tableParams, setTableParams] = useState<TableParams>({
pagination: {
current: 1,
pageSize: 10,
},
});
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter) => {
setTableParams({
pagination,
filters,
...sorter,
});
}; };
export default page; useEffect(() => {
getPackageAPI().then((result) => {
setPkg(result.data);
});
}, []);
const handleOrderDetails = (record: Order.OrderItem) => {
history.push('/orderDetails/' + `${record.id}`);
};
const searchForm: ProColumns[] = [
{
title: '订单号',
hideInTable: true,
align: 'center',
formItemProps: {
name: 'orderNo',
},
valueType: 'text',
},
{
title: '套餐',
hideInTable: true,
align: 'center',
formItemProps: {
name: 'packageId',
},
renderFormItem: () => {
return (
<Select
showSearch
allowClear
filterOption={false}
options={pkgOptions.map((item) => {
return {
label: item.name,
value: item.id,
};
})}
></Select>
);
},
},
{
title: '用户',
hideInTable: true,
align: 'center',
formItemProps: {
name: 'userEmail',
},
valueType: 'text',
},
{
title: '订单状态',
hideInTable: true,
align: 'center',
formItemProps: {
name: 'orderStatus',
},
renderFormItem: () => {
return (
<Select
showSearch
allowClear
filterOption={false}
mode="multiple"
maxTagCount={1}
options={Object.keys(UxOrderStatus).map((key) => {
return {
label: UxOrderStatus[key as unknown as number],
value: key,
};
})}
></Select>
);
},
},
{
title: '支付类型',
hideInTable: true,
align: 'center',
formItemProps: {
name: 'payType',
},
renderFormItem: () => {
return (
<Select
showSearch
allowClear
filterOption={false}
mode="multiple"
maxTagCount={1}
options={Object.keys(OrderPayTypeStr).map((key) => {
return {
// @ts-ignore
label: OrderPayTypeStr[key as unknown as any],
value: key,
};
})}
></Select>
);
},
},
];
const columns: ProColumns[] = [
...searchForm,
{
title: '订单号',
dataIndex: 'orderNo',
align: 'center',
fixed: 'left',
hideInSearch: true,
width: 230,
render: (_, record: Order.OrderItem) => {
if (record.isApply === true) {
return record.orderNo + '(试用)';
}
return record.orderNo;
},
},
{
title: '订单状态',
dataIndex: 'orderStatus',
fixed: 'left',
width: 140,
align: 'center',
hideInSearch: true,
render: (_, record: Order.OrderItem) => {
const color = Reflect.get(UxOrderStatusTag, record.orderStatus);
return (
<div className="flex items-center justify-start">
<div className="w-[10px] h-[10px] mr-2" style={{ background: color }}></div>
{Reflect.get(UxOrderStatus, record.orderStatus)}
</div>
);
},
},
{
title: '支付总金额',
dataIndex: 'totalPrice',
width: 120,
hideInSearch: true,
align: 'center',
},
{
title: '支付类型',
dataIndex: 'payType',
hideInSearch: true,
width: 100,
align: 'center',
render: (_, record: Order.OrderItem) => {
// 支付类型 1. 微信 2. 支付宝 3. paypal -1: 后台创建
if ([OrderPayType.WX, OrderPayType.ZFB].includes(record.payType)) {
return (
<div className="flex justify-center items-center">
{record.payType === OrderPayType.WX ? (
<WechatOutlined color="green" style={{ fontSize: '18px' }} />
) : (
<AlipayCircleOutlined color="blue" style={{ fontSize: '18px' }} />
)}
<span className="ml-1">{Reflect.get(OrderPayTypeStr, record.payType)}</span>
</div>
);
}
if (record.payType === OrderPayType.PAYPAL) {
return Reflect.get(OrderPayTypeStr, OrderPayType.PAYPAL);
}
return record.isApply ? '试用' : '-';
},
},
{
title: '第三方订单号',
dataIndex: 'platformNo',
hideInSearch: true,
align: 'center',
},
{
title: '第三方订单状态',
dataIndex: 'platformOrderStatus',
hideInSearch: true,
width: 150,
align: 'center',
},
{
title: '套餐',
dataIndex: 'goodsName',
hideInSearch: true,
width: 80,
align: 'center',
},
{
title: '订单创建时间',
hideInSearch: true,
dataIndex: 'createdDateTime',
width: 200,
align: 'center',
},
{
title: '订单完成时间',
hideInSearch: true,
dataIndex: 'lastUpdateDateTime',
width: 200,
align: 'center',
render: (_, record: Order.OrderItem) => {
if (record.orderStatus === OrderStatus.HAVE_PAY) {
return record.lastUpdateDateTime;
}
return '';
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
align: 'center',
render: (_: React.ReactNode, record: Order.OrderItem) => {
return (
<Button
key={'order-details'}
type="primary"
onClick={() => {
handleOrderDetails(record);
}}
>
</Button>
);
},
},
];
return (
<>
<ProTable
actionRef={tableRef}
columns={columns}
rowKey={'id'}
pagination={tableParams.pagination}
onChange={handleTableChange}
search={{
labelWidth: 75,
span: { xs: 24, sm: 24, md: 12, lg: 12, xl: 4, xxl: 4 },
}}
request={async (params) => {
const { current, pageSize, ...other } = params;
const query = {
current,
pageSize,
orderNo: other.orderNo,
packageId: other.packageId,
orderStatus: other.orderStatus ? other.orderStatus.join(',') : [],
payType: other.payType ? other.payType.join(',') : [],
};
const { meta, code, data } = await getOrderListAPI(query);
return {
data: data ?? [],
total: meta.total,
success: code === 200,
};
}}
></ProTable>
</>
);
};
export default Page;

View File

@ -143,7 +143,7 @@ const UserDetailsModal = (props: PropTypes) => {
render: (_, record: Order.OrderItem) => { render: (_, record: Order.OrderItem) => {
const color = Reflect.get(UxOrderStatusTag, record.orderStatus); const color = Reflect.get(UxOrderStatusTag, record.orderStatus);
return ( return (
<div className="flex items-center justify-center"> <div className="flex items-center justify-start">
<div className="w-[10px] h-[10px] mr-2" style={{ background: color }}></div> <div className="w-[10px] h-[10px] mr-2" style={{ background: color }}></div>
{Reflect.get(UxOrderStatus, record.orderStatus)} {Reflect.get(UxOrderStatus, record.orderStatus)}
</div> </div>
@ -279,17 +279,18 @@ const UserDetailsModal = (props: PropTypes) => {
onCancel={handleOnCancel} onCancel={handleOnCancel}
> >
<Spin spinning={loading}> <Spin spinning={loading}>
<Tabs activeKey={tabType} onChange={(activeKey) => setTabType(activeKey)}> <Tabs
<Tabs.TabPane key={'details'} tab={'用户详情'}> activeKey={tabType}
<RenderUserDetails /> onChange={(activeKey) => setTabType(activeKey)}
</Tabs.TabPane> items={[
<Tabs.TabPane key={'handleLogs'} tab={'扩容记录'}> { label: '用户详情', key: 'details' },
<RenderDilatationLogs /> { label: '扩容记录', key: 'handleLogs' },
</Tabs.TabPane> { label: '订单信息', key: 'orderInfo' },
<Tabs.TabPane key={'orderInfo'} tab={'订单信息'}> ]}
<RenderUserOrders /> ></Tabs>
</Tabs.TabPane> {tabType === 'details' && <RenderUserDetails />}
</Tabs> {tabType === 'handleLogs' && <RenderDilatationLogs />}
{tabType === 'orderInfo' && <RenderUserOrders />}
</Spin> </Spin>
</Modal> </Modal>
); );

View File

@ -0,0 +1,10 @@
import request from '@/utils/request';
import qs from 'qs';
export const getOrderListAPI = (params: Record<string, any>): Promise<API.ResponstList<Order.OrderItem[]>> => {
return request.get(`/system/order?` + qs.stringify(params));
};
export const getOrderByIdAPI = (id: string): Promise<API.ResponstList<Order.OrderItem>> => {
return request.get(`/system/order/` + id);
};

View File

@ -27,5 +27,6 @@ declare namespace Order {
lastUpdateDateTime?: string; lastUpdateDateTime?: string;
comment?: string; comment?: string;
isApply: boolean; isApply: boolean;
totalPrice?: number;
}; };
} }

View File

@ -4,7 +4,8 @@ export const UxOrderStatus: Record<number, string> = {
2: '已支付', 2: '已支付',
3: '订单取消', 3: '订单取消',
4: '支付失败', 4: '支付失败',
5: '订单超时支付(二维码过期)', 5: '订单超时支付',
999: '超时支付失败',
}; };
export const UxOrderStatusTag: Record<number, string> = { export const UxOrderStatusTag: Record<number, string> = {
@ -12,7 +13,8 @@ export const UxOrderStatusTag: Record<number, string> = {
2: '#27ae60', // 绿色 2: '#27ae60', // 绿色
3: '#c8d6e5', // 灰色 3: '#c8d6e5', // 灰色
4: '#e74c3c', // 红色 4: '#e74c3c', // 红色
5: '订单超时支付(二维码过期)', // 5: '#c0392b', //
999: '#c0392b',
}; };
// 1: 待支付 2. 已支付 3. 订单取消 4. 支付失败 5. 订单超时支付(二维码过期) // 1: 待支付 2. 已支付 3. 订单取消 4. 支付失败 5. 订单超时支付(二维码过期)
@ -28,10 +30,13 @@ export enum OrderPayType {
WX = 1, WX = 1,
ZFB = 2, ZFB = 2,
PAYPAL = 3, PAYPAL = 3,
BACK = -1,
} }
export const OrderPayTypeStr = { export const OrderPayTypeStr = {
1: '微信', 1: '微信',
2: '支付宝', 2: '支付宝',
3: 'PayPal', 3: 'PayPal',
[-1]: '管理员创建',
[-2]: '前端创建',
}; };

View File

@ -38,16 +38,6 @@ export const routes: any[] = [
}, },
], ],
}, },
// {
// name: '权限演示',
// path: '/access',
// component: '/Access',
// },
// {
// name: ' CRUD 示例',
// path: '/table',
// component: '/Table',
// },
]; ];
export type MenuItem = { export type MenuItem = {