From a15bda739adcb0785e2e9fb9793325ccfd9c32ad Mon Sep 17 00:00:00 2001 From: wuxichen <17301714657@163.com> Date: Fri, 31 Oct 2025 16:04:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8F=96=E6=B6=88=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 16 ++ .../AdvancedImageGallery/index.module.less | 73 +++++++++ src/components/AdvancedImageGallery/index.tsx | 71 +++++++++ .../DangerouslySetInnerHTML/index.module.less | 7 + .../DangerouslySetInnerHTML/index.tsx | 16 ++ src/components/EnhancedProTable/index.tsx | 3 +- src/components/Upload/UploadImages/index.tsx | 23 ++- src/pages/prod/list/components/prod-info.tsx | 2 +- .../order/components/cancleOrderModal.tsx | 83 +++++++++++ src/pages/trade/order/config.tsx | 4 +- src/pages/trade/order/detail/index.tsx | 2 +- src/pages/trade/order/detail/order-info.tsx | 12 +- .../{component => src}/info/basic-info.tsx | 0 .../detail/{component => src}/info/config.tsx | 27 ++-- .../{component => src}/info/extend-cost.tsx | 0 .../info/extend-service.tsx | 0 .../{component => src}/info/index.module.less | 0 .../{component => src}/info/prod-info.tsx | 118 ++++++++++++++- .../{component => src}/info/service-info.tsx | 4 +- .../info/uis/pets/config.tsx | 22 ++- .../info/uis/pets/extend-cost.tsx | 0 .../info/uis/pets/extend-service.tsx | 0 .../info/uis/pets/service.tsx | 74 ++++++++- src/pages/trade/order/index.tsx | 2 +- src/pages/trade/order/list.tsx | 141 +++++++++++++----- src/services/trade/order/detail.ts | 71 +++++++++ src/services/trade/order/index.ts | 82 +++++++++- src/services/trade/order/list.ts | 6 + 29 files changed, 767 insertions(+), 93 deletions(-) create mode 100644 src/components/AdvancedImageGallery/index.module.less create mode 100644 src/components/AdvancedImageGallery/index.tsx create mode 100644 src/components/DangerouslySetInnerHTML/index.module.less create mode 100644 src/components/DangerouslySetInnerHTML/index.tsx create mode 100644 src/pages/trade/order/components/cancleOrderModal.tsx rename src/pages/trade/order/detail/{component => src}/info/basic-info.tsx (100%) rename src/pages/trade/order/detail/{component => src}/info/config.tsx (91%) rename src/pages/trade/order/detail/{component => src}/info/extend-cost.tsx (100%) rename src/pages/trade/order/detail/{component => src}/info/extend-service.tsx (100%) rename src/pages/trade/order/detail/{component => src}/info/index.module.less (100%) rename src/pages/trade/order/detail/{component => src}/info/prod-info.tsx (62%) rename src/pages/trade/order/detail/{component => src}/info/service-info.tsx (67%) rename src/pages/trade/order/detail/{component => src}/info/uis/pets/config.tsx (90%) rename src/pages/trade/order/detail/{component => src}/info/uis/pets/extend-cost.tsx (100%) rename src/pages/trade/order/detail/{component => src}/info/uis/pets/extend-service.tsx (100%) rename src/pages/trade/order/detail/{component => src}/info/uis/pets/service.tsx (65%) diff --git a/package.json b/package.json index 146d678..312a02e 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "browser-id3-writer": "^6.3.1", "classnames": "^2.5.1", "dayjs": "^1.11.13", + "dompurify": "^3.3.0", "jsencrypt": "^3.5.4", "rc-resize-observer": "^1.4.3", "react": "^19.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b27c85d..7a98afd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.18 + dompurify: + specifier: ^3.3.0 + version: 3.3.0 jsencrypt: specifier: ^3.5.4 version: 3.5.4 @@ -2818,6 +2821,9 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -4807,6 +4813,9 @@ packages: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} + dompurify@3.3.0: + resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} + domutils@1.7.0: resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} @@ -15041,6 +15050,9 @@ snapshots: '@types/tough-cookie@4.0.5': {} + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/use-sync-external-store@0.0.3': {} @@ -17939,6 +17951,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.3.0: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@1.7.0: dependencies: dom-serializer: 0.2.2 diff --git a/src/components/AdvancedImageGallery/index.module.less b/src/components/AdvancedImageGallery/index.module.less new file mode 100644 index 0000000..f2161bc --- /dev/null +++ b/src/components/AdvancedImageGallery/index.module.less @@ -0,0 +1,73 @@ +/* index.less */ + +.productImages { + padding: 16px; + + .mainImage { + margin-bottom: 16px; + text-align: center; + + .largeImage { + border: 1px solid #f0f0f0; + border-radius: 4px; + } + } + + .thumbnailList { + .thumbnail { + padding: 2px; + border: 2px solid transparent; + border-radius: 4px; + cursor: pointer; + transition: all 0.3s; + + &:hover { + border-color: #d9d9d9; + } + + &.active { + border-color: #ff4d4f; + } + } + } +} + +.advancedGallery { + .mainImageContainer { + margin-bottom: 16px; + text-align: center; + } + + .thumbnailContainer { + display: flex; + align-items: center; + gap: 8px; + + .scrollBtn { + flex-shrink: 0; + } + + .thumbnailWrapper { + display: flex; + gap: 8px; + overflow-x: auto; + scroll-behavior: smooth; + + &::-webkit-scrollbar { + display: none; + } + } + + .thumbnailItem { + flex-shrink: 0; + padding: 2px; + border: 2px solid transparent; + border-radius: 4px; + cursor: pointer; + + &.active { + border-color: #1890ff; + } + } + } +} diff --git a/src/components/AdvancedImageGallery/index.tsx b/src/components/AdvancedImageGallery/index.tsx new file mode 100644 index 0000000..6cb4ab4 --- /dev/null +++ b/src/components/AdvancedImageGallery/index.tsx @@ -0,0 +1,71 @@ +import { LeftOutlined, RightOutlined } from '@ant-design/icons'; +import { Button, Image } from 'antd'; +import React, { useRef, useState } from 'react'; +import styles from './index.module.less'; + +const AdvancedImageGallery: React.FC<{ images: string[] }> = ({ images }) => { + const [currentIndex, setCurrentIndex] = useState(0); + const thumbnailRef = useRef(null); + + // 缩略图滚动 + const scrollThumbnails = (direction: 'left' | 'right') => { + if (thumbnailRef.current) { + const scrollAmount = direction === 'left' ? -100 : 100; + thumbnailRef.current.scrollLeft += scrollAmount; + } + }; + + return ( +
+ {/* 大图区域 */} +
+ 主图 +
+ + {/* 缩略图区域 */} +
+
+
+ ); +}; + +export default React.memo(AdvancedImageGallery); diff --git a/src/components/DangerouslySetInnerHTML/index.module.less b/src/components/DangerouslySetInnerHTML/index.module.less new file mode 100644 index 0000000..ed256d0 --- /dev/null +++ b/src/components/DangerouslySetInnerHTML/index.module.less @@ -0,0 +1,7 @@ +.dangerouslySetInnerHTML { + :global { + p { + margin-bottom: 12px; + } + } +} diff --git a/src/components/DangerouslySetInnerHTML/index.tsx b/src/components/DangerouslySetInnerHTML/index.tsx new file mode 100644 index 0000000..c64048b --- /dev/null +++ b/src/components/DangerouslySetInnerHTML/index.tsx @@ -0,0 +1,16 @@ +import DOMPurify from 'dompurify'; +import React from 'react'; +import styles from './index.module.less'; + +const DangerouslySetInnerHTML = (props: { content?: string }) => { + const { content = '' } = props; + return ( +
+ ); +}; + +export default React.memo(DangerouslySetInnerHTML); diff --git a/src/components/EnhancedProTable/index.tsx b/src/components/EnhancedProTable/index.tsx index da176da..6519421 100644 --- a/src/components/EnhancedProTable/index.tsx +++ b/src/components/EnhancedProTable/index.tsx @@ -22,6 +22,7 @@ function EnhancedProTable( toolbarActions, rowKey = 'id', pagination = true, + scroll, ...restProps } = props; @@ -55,7 +56,7 @@ function EnhancedProTable( manualRequest={false} showSorterTooltip // scroll={{ x: "max-content" }} - scroll={{ x: 1200 }} + scroll={scroll ? scroll : { x: 1200 }} components={components} search={ search diff --git a/src/components/Upload/UploadImages/index.tsx b/src/components/Upload/UploadImages/index.tsx index a5dc845..4c269e2 100644 --- a/src/components/Upload/UploadImages/index.tsx +++ b/src/components/Upload/UploadImages/index.tsx @@ -35,7 +35,15 @@ const UploadImages: React.FC<{ const [uploading, setUploading] = useState(false); useEffect(() => { if (value) { - setFileList([{ uid: '-1', url: value, status: 'done', name: value }]); + console.log(value.split(',')); + const list = value.split(',').map((item, index) => ({ + uid: index.toString(), + url: item, + thumbUrl: item, + status: 'done', + name: item, + })); + setFileList(list as UploadFile[]); } else { setFileList([]); } @@ -63,7 +71,7 @@ const UploadImages: React.FC<{ const handleRemove = (file: UploadFile): boolean => { const newFileList = fileList.filter((item) => item.uid !== file.uid); const newUrl = newFileList.map((item) => item.url) as string[]; - onChange?.(newUrl[0]); + onChange?.(newUrl.join(',')); return true; }; @@ -101,8 +109,15 @@ const UploadImages: React.FC<{ const url = await uploadFile(file as File); onProgress?.({ percent: 100 }); if (url) { - onChange?.(url); - onSuccess?.({ url }); + if (maxCount === 1) { + onChange?.(url); + onSuccess?.({ url }); + } else { + const res = value?.split(',') || []; + console.log([...res, url].join(',')); + onChange?.([...res, url].join(',')); + } + message.success('上传成功'); } else { throw new Error('上传失败'); diff --git a/src/pages/prod/list/components/prod-info.tsx b/src/pages/prod/list/components/prod-info.tsx index 2f4b55c..eb5c94b 100644 --- a/src/pages/prod/list/components/prod-info.tsx +++ b/src/pages/prod/list/components/prod-info.tsx @@ -74,7 +74,7 @@ const ProdInfo = >(props: ProdInfoProps) => { extra="仅支持.jpg .png 格式,建议图片比例1:1,限7张" // getValueFromEvent={(e) => e.fileList} > - + void; +}> = (props) => { + const formRef = useRef(null); + const [loading, setLoading] = useState(false); + const columns: ProFormColumnsType[] = [ + { + title: '', + dataIndex: 'cancelReason', + valueType: 'radio', + fieldProps: { + options: [ + { value: '用户主动取消', label: '用户主动取消' }, + { value: '选项二', label: '选项二' }, + { value: '选项三', label: '选项三' }, + { value: '选项四', label: '选项四' }, + { value: '选项五', label: '选项五' }, + { value: '选项六', label: '选项六' }, + { value: '选项七', label: '选项七' }, + ], + style: { + display: 'flex', + flexDirection: 'column', + gap: '8px', + marginTop: '6px', + background: '#f0f0f0', + padding: '8px', + borderRadius: '8px', + }, + }, + }, + { + title: '取消备注', + dataIndex: 'cancelRemark', + valueType: 'textarea', + }, + ]; + + const handleOk = useCallback(async () => { + try { + setLoading(true); + const values = formRef.current?.getFieldsValue(); + console.log(values, props.id, 'ok'); + await cancelOrder({ id: props.id, ...values }); + message.success('取消成功'); + props.onClose?.(); + } finally { + setLoading(false); + } + }, [open, props.id]); + return ( + + 是否确认取消订单? + + + ); +}; + +export default React.memo(CancleOrderModal); diff --git a/src/pages/trade/order/config.tsx b/src/pages/trade/order/config.tsx index 18b423d..4d53747 100644 --- a/src/pages/trade/order/config.tsx +++ b/src/pages/trade/order/config.tsx @@ -14,10 +14,10 @@ export const baseOrderColumns: ProColumns[] = [ if (!record.items) { return _; } - return record.items.map((item) => ( + return record.items.map((item, index) => (
diff --git a/src/pages/trade/order/detail/index.tsx b/src/pages/trade/order/detail/index.tsx index 56b2b2b..1e36030 100644 --- a/src/pages/trade/order/detail/index.tsx +++ b/src/pages/trade/order/detail/index.tsx @@ -21,7 +21,7 @@ const DetailCom: React.FC<{ data?: TradeOrderPageRespVO }> = (props) => { children: '商品配送', }, ]; - return ; + return ; }; export default React.memo(DetailCom); diff --git a/src/pages/trade/order/detail/order-info.tsx b/src/pages/trade/order/detail/order-info.tsx index 64a4be5..6d0aa1d 100644 --- a/src/pages/trade/order/detail/order-info.tsx +++ b/src/pages/trade/order/detail/order-info.tsx @@ -5,16 +5,17 @@ import { type TradeOrderDetailRespVO, type TradeOrderPageRespVO, } from '@/services/trade/order'; -import BasicInfo from './component/info/basic-info'; //基本信息(通版) -import ExtendCostInfo from './component/info/extend-cost'; //服务附加费(殡葬专属字段) -import ExtendService from './component/info/extend-service'; //可选服务(殡葬专属字段) -import ProdInfo from './component/info/prod-info'; //商品信息(通版) -import ServiceInfo from './component/info/service-info'; +import BasicInfo from './src/info/basic-info'; //基本信息(通版) +import ExtendCostInfo from './src/info/extend-cost'; //服务附加费(殡葬专属字段) +import ExtendService from './src/info/extend-service'; //可选服务(殡葬专属字段) +import ProdInfo from './src/info/prod-info'; //商品信息(通版) +import ServiceInfo from './src/info/service-info'; export interface ItemConfig { data?: T; loading?: boolean; orderCategoryId?: number; + id?: number; } const OrderDetail: React.FC<{ data?: TradeOrderPageRespVO }> = (props) => { const { data } = props; @@ -43,6 +44,7 @@ const OrderDetail: React.FC<{ data?: TradeOrderPageRespVO }> = (props) => { )} {detais?.tradeExtendServeInfo && ( diff --git a/src/pages/trade/order/detail/component/info/basic-info.tsx b/src/pages/trade/order/detail/src/info/basic-info.tsx similarity index 100% rename from src/pages/trade/order/detail/component/info/basic-info.tsx rename to src/pages/trade/order/detail/src/info/basic-info.tsx diff --git a/src/pages/trade/order/detail/component/info/config.tsx b/src/pages/trade/order/detail/src/info/config.tsx similarity index 91% rename from src/pages/trade/order/detail/component/info/config.tsx rename to src/pages/trade/order/detail/src/info/config.tsx index 12950c0..b02f20b 100644 --- a/src/pages/trade/order/detail/component/info/config.tsx +++ b/src/pages/trade/order/detail/src/info/config.tsx @@ -73,10 +73,13 @@ export const renderBaseInfoOrder = ( > {data?.orderStatus && orderStatusObj.label} - - 剩余 - 4分30秒 - + {data.orderStatus === 10 && ( + + 剩余 + 4分30秒 + + )} + {data.orderStatus && Number(data.orderStatus) === OrderStatus.Refunded && ( @@ -121,18 +124,18 @@ export const renderBaseInfoOrder = ( {data.orderStatus && Number(data.orderStatus) === OrderStatus.Cancelled && ( <> - +
取消时间: - 取消时间 - - + {data.cancelTime} +
+
取消原因: {data.cancelReason} - - +
+
备注: - {data?.merchantRemark} - + {data?.cancelRemark} +
)} {data.orderStatus && diff --git a/src/pages/trade/order/detail/component/info/extend-cost.tsx b/src/pages/trade/order/detail/src/info/extend-cost.tsx similarity index 100% rename from src/pages/trade/order/detail/component/info/extend-cost.tsx rename to src/pages/trade/order/detail/src/info/extend-cost.tsx diff --git a/src/pages/trade/order/detail/component/info/extend-service.tsx b/src/pages/trade/order/detail/src/info/extend-service.tsx similarity index 100% rename from src/pages/trade/order/detail/component/info/extend-service.tsx rename to src/pages/trade/order/detail/src/info/extend-service.tsx diff --git a/src/pages/trade/order/detail/component/info/index.module.less b/src/pages/trade/order/detail/src/info/index.module.less similarity index 100% rename from src/pages/trade/order/detail/component/info/index.module.less rename to src/pages/trade/order/detail/src/info/index.module.less diff --git a/src/pages/trade/order/detail/component/info/prod-info.tsx b/src/pages/trade/order/detail/src/info/prod-info.tsx similarity index 62% rename from src/pages/trade/order/detail/component/info/prod-info.tsx rename to src/pages/trade/order/detail/src/info/prod-info.tsx index 8fbecf0..913f3c2 100644 --- a/src/pages/trade/order/detail/component/info/prod-info.tsx +++ b/src/pages/trade/order/detail/src/info/prod-info.tsx @@ -1,14 +1,22 @@ import { ProCard } from '@ant-design/pro-components'; -import { Button, Card, Image, Space, Tag, Typography } from 'antd'; -import React, { useCallback } from 'react'; +import { Button, Card, Image, Modal, Space, Tag, Typography } from 'antd'; +import React, { useCallback, useEffect, useState } from 'react'; +import AdvancedImageGallery from '@/components/AdvancedImageGallery'; +import DangerouslySetInnerHTML from '@/components/DangerouslySetInnerHTML'; import { fallback } from '@/constants/antd/image'; -import type { Item } from '@/services/trade/order/detail'; +import { getfastPhoto } from '@/services/trade/order'; +import type { + Item, + TradeOrderFastPhotoRespVo, +} from '@/services/trade/order/detail'; import type { ItemConfig } from '../../order-info'; import styles from './index.module.less'; -const { Text, Paragraph } = Typography; +const { Text, Paragraph, Title } = Typography; const ProdInfo: React.FC> = (props) => { const { data = [] } = props; + const [visible, setVisible] = useState(false); + const [item, setItem] = useState(); const renderTitle = useCallback((item: Item) => { return ( @@ -24,6 +32,14 @@ const ProdInfo: React.FC> = (props) => { ); }, []); + const onPhoto = useCallback( + async (item: Item) => { + setVisible(true); + setItem(item); + }, + [item, visible], + ); + return (
@@ -35,7 +51,11 @@ const ProdInfo: React.FC> = (props) => { bordered headerBordered gutter={8} - extra={} + extra={ + + } > > = (props) => { > 到手价: - {' '} ¥{item.handedPrice} {item.unit} 成本价: - {' '} ¥{item.expensePrice} {item.unit}/- @@ -141,8 +159,94 @@ const ProdInfo: React.FC> = (props) => { ))} + setVisible(false)} + item={item} + />
); }; +// 交易快照 +const PhotoModal: React.FC<{ + open: boolean; + onCancel: () => void; + item?: Item; +}> = (props) => { + const [photo, setPhoto] = useState(); + const { item } = props; + console.log(item, 'item'); + const onPhoto = useCallback(async () => { + const res = await getfastPhoto({ + itemId: item?.id as number, + spuId: item?.spuId as number, + }); + setPhoto(res); + }, [item]); + useEffect(() => { + if (props.open && item) { + onPhoto(); + } + }, [props.open, item]); + + return ( + +
+
+ +
+
+ {photo?.spuName} + + {photo?.brief} + +
+ + 当前页面为订单快照,包含订单创建时的商品描述和下单信息,买卖双方和平台在发生交易争议时,将作为判断依据。 + +
+
+ 已选:{photo?.skuName}(已选的SKU规格) +
+ +
+
+
+ ); +}; + export default React.memo(ProdInfo); diff --git a/src/pages/trade/order/detail/component/info/service-info.tsx b/src/pages/trade/order/detail/src/info/service-info.tsx similarity index 67% rename from src/pages/trade/order/detail/component/info/service-info.tsx rename to src/pages/trade/order/detail/src/info/service-info.tsx index 03708d8..1a7fcef 100644 --- a/src/pages/trade/order/detail/component/info/service-info.tsx +++ b/src/pages/trade/order/detail/src/info/service-info.tsx @@ -4,8 +4,8 @@ import type { ItemConfig } from '../../order-info'; import ServicePetUI from './uis/pets/service'; const ServiceInfo: React.FC> = (props) => { - const { data = {}, orderCategoryId } = props; - return <>{orderCategoryId === 1 && }; //宠物服务ui + const { data = {}, orderCategoryId, id } = props; + return <>{orderCategoryId === 1 && }; //宠物服务ui }; export default React.memo(ServiceInfo); diff --git a/src/pages/trade/order/detail/component/info/uis/pets/config.tsx b/src/pages/trade/order/detail/src/info/uis/pets/config.tsx similarity index 90% rename from src/pages/trade/order/detail/component/info/uis/pets/config.tsx rename to src/pages/trade/order/detail/src/info/uis/pets/config.tsx index 4b02a6e..b06a161 100644 --- a/src/pages/trade/order/detail/component/info/uis/pets/config.tsx +++ b/src/pages/trade/order/detail/src/info/uis/pets/config.tsx @@ -77,15 +77,23 @@ export const baseOrderColumns: ProColumns[] = [ />
{serve.serveName}
- {serve.serveDesc}
- 数量: - {serve.count} - 单价: - {serve.price} - 到手价: - {serve.handPrice} + {serve.serveDesc}
+ +
+ 数量: + {serve.count} +
+
+ 单价: + {serve.price} +
+
+ 到手价: + {serve.handPrice} +
+
))} diff --git a/src/pages/trade/order/detail/component/info/uis/pets/extend-cost.tsx b/src/pages/trade/order/detail/src/info/uis/pets/extend-cost.tsx similarity index 100% rename from src/pages/trade/order/detail/component/info/uis/pets/extend-cost.tsx rename to src/pages/trade/order/detail/src/info/uis/pets/extend-cost.tsx diff --git a/src/pages/trade/order/detail/component/info/uis/pets/extend-service.tsx b/src/pages/trade/order/detail/src/info/uis/pets/extend-service.tsx similarity index 100% rename from src/pages/trade/order/detail/component/info/uis/pets/extend-service.tsx rename to src/pages/trade/order/detail/src/info/uis/pets/extend-service.tsx diff --git a/src/pages/trade/order/detail/component/info/uis/pets/service.tsx b/src/pages/trade/order/detail/src/info/uis/pets/service.tsx similarity index 65% rename from src/pages/trade/order/detail/component/info/uis/pets/service.tsx rename to src/pages/trade/order/detail/src/info/uis/pets/service.tsx index 38cd7e9..d0bf65b 100644 --- a/src/pages/trade/order/detail/component/info/uis/pets/service.tsx +++ b/src/pages/trade/order/detail/src/info/uis/pets/service.tsx @@ -1,16 +1,22 @@ import { ClockCircleOutlined, EnvironmentOutlined } from '@ant-design/icons'; -import { ProCard } from '@ant-design/pro-components'; -import { Button, Card, Image, Space, Timeline, Typography } from 'antd'; -import React from 'react'; +import { ProCard, type ProColumns } from '@ant-design/pro-components'; +import { Button, Card, Image, Modal, Space, Timeline, Typography } from 'antd'; +import React, { useCallback, useEffect, useState } from 'react'; +import EnhancedProTable from '@/components/EnhancedProTable'; import { fallback } from '@/constants/antd/image'; -import type { TradeServeInfo } from '@/services/trade/order/detail'; +import { getSubTimeLog } from '@/services/trade/order'; +import type { + TradeOrderSubLogDO, + TradeServeInfo, +} from '@/services/trade/order/detail'; import type { ItemConfig } from '../../../../order-info'; import styles from '../../index.module.less'; const { Text, Paragraph } = Typography; const ServicePetUI: React.FC> = (props) => { - const { data = {} } = props; + const { data = {}, id } = props; const { boneInfo, subInfo } = data; + const [open, setOpen] = useState(false); return (
@@ -54,7 +60,11 @@ const ServicePetUI: React.FC> = (props) => { size="small" title="预约信息" headerBordered - extra={} + extra={ + + } >
@@ -99,8 +109,60 @@ const ServicePetUI: React.FC> = (props) => { + setOpen(false)} />
); }; +//修改记录 +const SubTimeLogModal: React.FC<{ + id?: number; + open?: boolean; + onCancel: () => void; +}> = (props) => { + const { id, open = false } = props; + const [log, setLog] = useState([]); + const fetchSubTimeLog = useCallback( + async (id: number) => { + const res = await getSubTimeLog(id); + console.log(res); + setLog(res); + }, + [id], + ); + const columns: ProColumns[] = [ + { + title: '预约时间', + dataIndex: 'subTime', + valueType: 'dateTime', + }, + { + title: '修改时间', + dataIndex: 'updateTime', + valueType: 'dateTime', + }, + ]; + useEffect(() => { + if (open && id) fetchSubTimeLog(id); + }, [open, id]); + return ( + + + columns={columns} + dataSource={log} + showIndex={false} + search={false} + scroll={{ x: 'max-content' }} + showSelection={false} + pagination={false} + /> + + ); +}; export default React.memo(ServicePetUI); diff --git a/src/pages/trade/order/index.tsx b/src/pages/trade/order/index.tsx index a259190..9e7c844 100644 --- a/src/pages/trade/order/index.tsx +++ b/src/pages/trade/order/index.tsx @@ -20,7 +20,7 @@ const OrderList: React.FC = () => { return (
- +
); }; diff --git a/src/pages/trade/order/list.tsx b/src/pages/trade/order/list.tsx index 0f96c16..33bb684 100644 --- a/src/pages/trade/order/list.tsx +++ b/src/pages/trade/order/list.tsx @@ -12,9 +12,8 @@ import { message, Space, Statistic, - Typography, } from 'antd'; -import React, { useCallback, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import ConfigurableDrawerForm, { type ConfigurableDrawerFormRef, } from '@/components/DrawerForm'; @@ -29,14 +28,18 @@ import PopconfirmForm, { } from '@/components/PopconfirmForm'; import { mapOrderStatusToBadgeStatus, - type OrderStatus, + OrderStatus, OrderStatusLabels, } from '@/constants/trade'; import { getTradeOrderPage, + getTradeSummary, type TradeOrderPageRespVO, type TradeReq, + type TradeSummaryRespVO, + updateOrderRemark, } from '@/services/trade/order'; +import CancleOrderModal from './components/cancleOrderModal'; import DetailCom from './detail'; const OrderListItem: React.FC<{ orderStatus: number }> = (props) => { @@ -46,6 +49,16 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => { const [modalData, setModalData] = useState(); const [isShowTotal, setIsShowTotal] = useState(false); const popconfirmFormRef = useRef(null); + const [summary, setSummary] = useState(); + const [cancleOrderVisible, setCancleOrderVisible] = useState(false); + + const fetchSummary = async () => { + const res = await getTradeSummary(); + setSummary(res); + }; + useEffect(() => { + fetchSummary(); + }, []); const onFetch = async ( params: TradeReq & { pageSize: number; @@ -74,14 +87,24 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => { [modalData], ); - const handleOrder = useCallback((id?: number) => { - console.log(id, '取消订单'); - // await updateTradeOrder(values.id); - }, []); - - const handleUpdate = async (_values: TradeOrderPageRespVO) => { - try { + const handleOrder = useCallback( + (type: string, record?: TradeOrderPageRespVO) => { + setModalData(record); + if (type === 'order') { + setCancleOrderVisible(true); + } + if (type === 'order') { + setCancleOrderVisible(true); + } // await updateTradeOrder(values.id); + }, + [], + ); + + const handleUpdate = async (values: TradeOrderPageRespVO, id?: number) => { + try { + await updateOrderRemark({ remark: values.userRemark || '', id: id }); + tableRef.current?.reload(); return true; } finally { message.success('更新成功'); @@ -105,37 +128,56 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => { }} key={record.id} > - handleOrder(record.id)}> - 取消订单 - - handleOrder(record.id)}> - 开始服务 - - handleOrder(record.id)}> - 新建售后 - + {record.orderStatus !== OrderStatus.Cancelled && ( + handleOrder('order', record)}> + 取消订单 + + )} + {record.orderStatus === OrderStatus.PendingService && ( + handleOrder('service', record)}> + 开始服务 + + )} + {record.orderStatus === OrderStatus.PendingConfirmation && ( + handleOrder('service', record)}> + 接单确定 + + )} + {(record.orderStatus as number) > OrderStatus.PendingPayment && + record.orderStatus !== OrderStatus.Cancelled && ( + handleOrder('sales', record)}> + 新建售后 + + )} + {record.orderStatus === OrderStatus.PendingAcceptance && ( + handleOrder('sales', record)}> + 服务上报 + + )} handleDetail(record)}> 订单详情 - - popconfirmFormRef.current?.open(record)} + {record.orderStatus === OrderStatus.PendingPayment && ( + handleUpdate(value, record.id)} > - 添加备注 - - + popconfirmFormRef.current?.open(record)} + > + 添加备注 + + + )}
, ], }; @@ -251,13 +293,25 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => { {isShowTotal && ( - + - + - + )} @@ -286,8 +340,13 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => { > + setCancleOrderVisible(false)} + id={modalData?.id} + /> ); }; -export default OrderListItem; +export default React.memo(OrderListItem); diff --git a/src/services/trade/order/detail.ts b/src/services/trade/order/detail.ts index fd8afaf..b301484 100644 --- a/src/services/trade/order/detail.ts +++ b/src/services/trade/order/detail.ts @@ -65,6 +65,7 @@ export interface TradeExtendServeInfo { } export interface TradeOrderDetailRespVO { + cancelRemark?: string; /** * 取消原因 */ @@ -346,3 +347,73 @@ export interface TradeOrderStatusRespVo { */ orderId?: number; } + +export interface TradeOrderFastPhotoRespVo { + /** + * 商品概述 + */ + brief?: string; + /** + * 商品详细描述 + */ + content?: string; + /** + * 产品轮播图 + */ + imgs?: string; + /** + * 产品主图 + */ + pic?: string; + /** + * sku + */ + skuName?: string; + /** + * 商品名称 + */ + spuName?: string; +} + +export interface TradeOrderSubLogDO { + /** + * 创建时间 + */ + createTime?: string; + /** + * 创建者,目前使用 SysUser 的 id 编号 + * + * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。 + */ + creator?: string; + /** + * 是否删除 + */ + deleted?: number; + /** + * 编号 + */ + id?: number; + /** + * 订单号 + */ + orderId?: number; + /** + * 预约时间 + */ + subTime?: string; + /** + * 更新者,目前使用 SysUser 的 id 编号 + * + * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。 + */ + updater?: string; + /** + * 最后更新时间 + */ + updateTime?: string; + /** + * 用户编号 + */ + userId?: number; +} diff --git a/src/services/trade/order/index.ts b/src/services/trade/order/index.ts index 6768c55..a70c1ed 100644 --- a/src/services/trade/order/index.ts +++ b/src/services/trade/order/index.ts @@ -1,6 +1,10 @@ import { request } from "@umijs/max"; -import { TradeOrderPageRespVO, TradeReq } from "./list"; -import { TradeOrderDetailRespVO } from "./detail"; +import { TradeOrderPageRespVO, TradeReq, TradeSummaryRespVO } from "./list"; +import { + TradeOrderDetailRespVO, + TradeOrderFastPhotoRespVo, + TradeOrderSubLogDO, +} from "./detail"; export const getTradeOrderPage = async (params: TradeReq) => { return request>("/trade/order/page", { @@ -16,4 +20,76 @@ export const getTradeOrderDetail = async (id: number) => { }); }; -export { TradeOrderPageRespVO, TradeOrderDetailRespVO, TradeReq }; +//获得交易订单统计 +export const getTradeSummary = async () => { + return request("/trade/order/summary", { + method: "GET", + }); +}; + +//交易快照 + +export const getfastPhoto = async (params: { + itemId: number; + spuId: number; +}) => { + return request("/trade/order/fastPhoto", { + method: "GET", + params, + }); +}; + +//服务信息修改记录 + +export const getSubTimeLog = async (id: number) => { + return request(`/trade/order/subTimeLog/${id}`, { + method: "GET", + }); +}; + +//取消订单 +export const cancelOrder = async (data: { + id: number; + cancelReason: string; + cancelRemark: string; +}) => { + return request(`/trade/order/cancel`, { + method: "PUT", + data, + }); +}; +//接单确认 +export const acceptConfirm = async (id: number) => { + return request(`/trade/order/acceptConfirm`, { + method: "PUT", + params: { id }, + }); +}; + +//服务上报 +export const reportServe = async (id: number) => { + return request(`/trade/order/reportServe`, { + method: "PUT", + params: { id }, + }); +}; + +//商家备注 +export const updateOrderRemark = async (params: { + id?: number; + remark?: string; +}) => { + return request(`/trade/order/update-remark`, { + method: "PUT", + data: params, + }); +}; + +export { + TradeOrderPageRespVO, + TradeOrderDetailRespVO, + TradeReq, + TradeSummaryRespVO, + TradeOrderFastPhotoRespVo, + TradeOrderSubLogDO, +}; diff --git a/src/services/trade/order/list.ts b/src/services/trade/order/list.ts index 997eb09..cf6b2ea 100644 --- a/src/services/trade/order/list.ts +++ b/src/services/trade/order/list.ts @@ -192,3 +192,9 @@ export interface TradeReq { */ userSearch?: string; } + +export interface TradeSummaryRespVO { + orderCount?: number; + livePrice?: number; + payPrice?: number; +}