feat: 订单列表

This commit is contained in:
2025-10-16 16:32:59 +08:00
parent a5b7207f44
commit 3c7473f8d1
48 changed files with 1917 additions and 624 deletions

12
.github/FUNDING.yml vendored
View File

@@ -1,12 +0,0 @@
# These are supported funding model platforms
github: ant-design # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: ant-design
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -1,48 +0,0 @@
---
name: '报告 Bug | Report bug 🐛'
about: 报告 Ant Design Pro 的 bug
title: '🐛 [BUG]'
labels: '🐛 bug'
assignees: ''
---
### 🐛 bug 描述
<!--
详细地描述 bug让大家都能理解
Describe the bug in detail so that everyone can understand it
-->
### 📷 复现步骤 | Recurrence steps
<!--
清晰描述复现步骤,让别人也能看到问题
Clearly describe the recurrence steps so that others can see the problem
-->
### 🏞 期望结果 | Expected results
<!--
描述你原本期望看到的结果
Describe what you expected to see
-->
### 💻 复现代码 | Recurrence code
<!--
提供可复现的代码,仓库,或线上示例
Provide reproducible code, warehouse, or online examples
-->
### © 版本信息
- Ant Design Pro 版本: [e.g. 4.0.0]
- umi 版本
- 浏览器环境
- 开发环境 [e.g. mac OS]
### 🚑 其他信息
<!--
如截图等其他信息可以贴在这里
-->

View File

@@ -1,28 +0,0 @@
---
name: '功能需求 | Feature Requirements ✨'
about: 对 Ant Design Pro 的需求或建议
title: '👑 [需求 | Feature]'
labels: '👑 Feature Request'
assignees: ''
---
### 🥰 需求描述 | Requirements description
<!--
详细地描述需求,让大家都能理解
Describe the requirements in detail so that everyone can understand them
-->
### 🧐 解决方案 | Solution
<!--
如果你有解决方案,在这里清晰地阐述
If you have a solution, explain it clearly here
-->
### 🚑 其他信息 | Other information
<!--
如截图等其他信息可以贴在这里
Other information such as screenshots can be posted here
-->

View File

@@ -1,34 +0,0 @@
---
name: '疑问或需要帮助 | Questions or need help ❓'
about: 对 Ant Design Pro 使用的疑问或需要帮助
title: '🧐[问题 | question]'
labels: '🧐 question'
assignees: ''
---
### 🧐 问题描述 | Problem description
<!--
详细地描述问题,让大家都能理解
Describe the problem in detail so that everyone can understand it
-->
### 💻 示例代码 | Sample code
<!--
一个最小可重现的代码,让开发者可以快速的定位问题
A minimal reproducible code that allows developers to quickly locate problems
-->
### 🚑 其他信息 | Other information
<!--
如截图等其他信息可以贴在这里
Other information such as screenshots can be posted here
-->
OS:
Node
浏览器 | browser

View File

@@ -1,11 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: 'npm' # See documentation for possible values
directory: '/' # Location of package manifests
schedule:
interval: 'weekly'

View File

@@ -1,31 +0,0 @@
name: CI
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
if: false
runs-on: ${{ matrix.os }}
strategy:
matrix:
node_version: [20]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
- run: echo ${{github.ref}}
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run lint
- run: bun run build
env:
CI: true
PROGRESS: none
NODE_ENV: test
NODE_OPTIONS: --max_old_space_size=4096

View File

@@ -1,21 +0,0 @@
name: coverage CI
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
- run: echo ${{github.ref}}
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run test:coverage
- uses: codecov/codecov-action@v5

View File

@@ -1,30 +0,0 @@
name: Deploy to GitHub Pages
on:
push:
branches:
- all-blocks
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies with Bun
run: bun install
- name: Build project
run: bun run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
cname: preview.pro.ant.design

View File

@@ -1,14 +0,0 @@
name: Emoji Helper
on:
release:
types: [published]
jobs:
emoji:
runs-on: ubuntu-latest
steps:
- uses: actions-cool/emoji-helper@v1.0.0
with:
type: 'release'
emoji: '+1, laugh, heart, hooray, rocket, eyes'

View File

@@ -1,37 +0,0 @@
name: Issue labeled
on:
issues:
types: [labeled]
jobs:
reply-helper:
runs-on: ubuntu-latest
steps:
- name: help wanted
if: github.event.label.name == '❤️ help wanted' || github.event.label.name == '🤝Welcome PR'
uses: actions-cool/issues-helper@v1.11
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to [send us a Pull Request](https://help.github.com/en/articles/creating-a-pull-request) for it. Please provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!
你好 @${{ github.event.issue.user.login }},我们完全同意你的提议/反馈,欢迎直接在此仓库 [创建一个 Pull Request](https://help.github.com/en/articles/creating-a-pull-request) 来解决这个问题。请务必提供改动所需相应的 changelog、TypeScript 定义、测试用例、文档等,并确保 CI 通过,我们会尽快进行 Review提前感谢和期待您的贡献。
![giphy](https://user-images.githubusercontent.com/507615/62342668-4735dc00-b51a-11e9-92a7-d46fbb1cc0c7.gif)
- name: Need Reproduce
if: github.event.label.name == '🤔 Need Reproduce'
uses: actions-cool/issues-helper@v1.11
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking this link https://codesandbox.io/ or a minimal GitHub repository.
你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 [此处](https://codesandbox.io/) 创建一个 codesandbox 或者提供一个最小化的 GitHub 仓库。
![](https://gw.alipayobjects.com/zos/antfincdn/y9kwg7DVCd/reproduce.gif)

View File

@@ -1,34 +0,0 @@
name: Issue Open Check
on:
issues:
types: [opened, edited]
jobs:
check-issue:
runs-on: ubuntu-latest
steps:
- uses: actions-cool/issues-helper@v2.2.0
id: check
with:
actions: 'check-issue'
issue-number: ${{ github.event.issue.number }}
title-excludes: '🐛 [BUG], 👑 [需求 | Feature], 🧐[问题 | question]'
- if: steps.check.outputs.check-result == 'false' && github.event.issue.state == 'open'
uses: actions-cool/issues-helper@v2.2.0
with:
actions: 'create-comment, close-issue'
issue-number: ${{ github.event.issue.number }}
body: |
当前 Issue 未检测到标题,请规范填写,谢谢!
The title of the current issue is not detected, please fill in according to the specifications, thank you!
- if: steps.check.outputs.check-result == 'true'
uses: actions-cool/issues-similarity-analysis@v1
with:
filter-threshold: 0.8
title-excludes: '🐛[BUG], 👑 [需求 | Feature], 🧐[问题 | question]'
comment-title: '### 以下的 Issues 可能会帮助到你 / The following issues may help you'
show-footer: false

View File

@@ -1,40 +0,0 @@
name: Preview Build
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
jobs:
build-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: build
run: |
yarn
yarn build
- name: upload dist artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 5
- name: Save PR number
if: ${{ always() }}
run: echo ${{ github.event.number }} > ./pr-id.txt
- name: Upload PR number
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: pr
path: ./pr-id.txt

View File

@@ -1,100 +0,0 @@
name: Preview Deploy
on:
workflow_run:
workflows: ['Preview Build']
types:
- completed
permissions:
contents: read
jobs:
success:
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
steps:
- name: download pr artifact
uses: dawidd6/action-download-artifact@v6
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: pr
- name: save PR id
id: pr
run: echo "::set-output name=id::$(<pr-id.txt)"
- name: download dist artifact
uses: dawidd6/action-download-artifact@v6
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
workflow_conclusion: success
name: dist
- name: upload surge service
id: deploy
run: |
export DEPLOY_DOMAIN=https://ant-design-pro-preview-pr-${{ steps.pr.outputs.id }}.surge.sh
npx surge --project ./ --domain $DEPLOY_DOMAIN --token ${{ secrets.SURGE_TOKEN }}
- name: update status comment
uses: actions-cool/maintain-one-comment@v1.2.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
🎊 PR Preview has been successfully built and deployed to https://ant-design-pro-preview-pr-${{ steps.pr.outputs.id }}.surge.sh
<img width="300" src="https://user-images.githubusercontent.com/507615/90250366-88233900-de6e-11ea-95a5-84f0762ffd39.png">
<!-- Sticky Pull Request Comment -->
body-include: '<!-- Sticky Pull Request Comment -->'
number: ${{ steps.pr.outputs.id }}
- name: The job failed
if: ${{ failure() }}
uses: actions-cool/maintain-one-comment@v1.2.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
😭 Deploy PR Preview failed.
<img width="300" src="https://user-images.githubusercontent.com/507615/90250824-4e066700-de6f-11ea-8230-600ecc3d6a6b.png">
<!-- Sticky Pull Request Comment -->
body-include: '<!-- Sticky Pull Request Comment -->'
number: ${{ steps.pr.outputs.id }}
failed:
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure'
steps:
- name: download pr artifact
uses: dawidd6/action-download-artifact@v6
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: pr
- name: save PR id
id: pr
run: echo "::set-output name=id::$(<pr-id.txt)"
- name: The job failed
uses: actions-cool/maintain-one-comment@v1.2.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
😭 Deploy PR Preview failed.
<img width="300" src="https://user-images.githubusercontent.com/507615/90250824-4e066700-de6f-11ea-8230-600ecc3d6a6b.png">
<!-- Sticky Pull Request Comment -->
body-include: '<!-- Sticky Pull Request Comment -->'
number: ${{ steps.pr.outputs.id }}

View File

@@ -1,24 +0,0 @@
name: Preview Start
on: pull_request_target
permissions:
contents: read
jobs:
preview:
permissions:
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
steps:
- name: create
uses: actions-cool/maintain-one-comment@v1.2.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
body: |
⚡️ Deploying PR Preview...
<img src="https://user-images.githubusercontent.com/507615/90240294-8d2abd00-de5b-11ea-8140-4840a0b2d571.gif" width="300" />
<!-- Sticky Pull Request Comment -->
body-include: '<!-- Sticky Pull Request Comment -->'

View File

@@ -83,7 +83,7 @@ export default defineConfig({
* @name layout 插件
* @doc https://umijs.org/docs/max/layout-menu
*/
title: 'Ant Design Pro',
title: '百业到家',
layout: {
locale: true,
...defaultSettings,

View File

@@ -1,4 +1,4 @@
import type { ProLayoutProps } from "@ant-design/pro-components";
import type { ProLayoutProps } from '@ant-design/pro-components';
/**
* @name
@@ -7,21 +7,26 @@ const Settings: ProLayoutProps & {
pwa?: boolean;
logo?: string;
} = {
navTheme: "light",
navTheme: 'light',
// 拂晓蓝
colorPrimary: "#1890ff",
layout: "mix",
contentWidth: "Fluid",
colorPrimary: '#1890ff',
layout: 'mix',
contentWidth: 'Fluid',
fixedHeader: true,
fixSiderbar: true,
colorWeak: false,
title: "百业到家云控台",
title: '百业到家云控台',
pwa: true,
logo: "/logo.svg",
iconfontUrl: "",
logo: '/logo.svg',
iconfontUrl: '',
splitMenus: true,
token: {
// 参见ts声明demo 见文档通过token 修改样式
// 设置内容区域的边距
pageContainer: {
paddingBlockPageContainerContent: 16,
paddingInlinePageContainerContent: 16,
},
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F
},
};

View File

@@ -15,7 +15,9 @@ export default {
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
'/admin-api/': {
// 要代理的地址
target: 'http://192.168.1.231:48080',
// http://192.168.1.231:48080 伟强
// https://petshy.tashowz.com/
target: 'http://192.168.1.231:48080/',
// 配置了这个可以从 http 代理到 https
// 依赖 origin 的功能可能需要这个,比如 cookie
changeOrigin: true,
@@ -28,7 +30,7 @@ export default {
test: {
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
'/api/': {
target: 'https://proapi.azurewebsites.net',
target: 'https://petshy.tashowz.com/',
changeOrigin: true,
pathRewrite: { '^': '' },
},

View File

@@ -13,70 +13,41 @@
export default [
{
path: "/user",
path: '/user',
layout: false,
routes: [
{
name: "login",
path: "/user/login",
component: "./user/login",
name: 'login',
path: '/user/login',
component: './user/login',
},
],
},
{
path: "/welcome",
name: "welcome",
icon: "smile",
component: "./Welcome",
path: '/welcome',
name: 'welcome',
icon: 'smile',
component: './Welcome',
},
// {
// path: "/system1",
// name: "system1",
// icon: "smile",
// routes: [
// {
// name: "tenant",
// path: "/system1/tenant",
// routes: [
// {
// name: "package",
// path: "/system1/tenant/package",
// component: "system/tenant/package",
// },
// ],
// },
// ],
// },
{
path: "/admin",
name: "admin",
icon: "crown",
access: "canAdmin",
path: '/',
redirect: '/welcome',
},
{
path: '/trade',
name: '交易管理',
routes: [
{
path: "/admin",
redirect: "/admin/sub-page",
},
{
path: "/admin/sub-page",
name: "sub-page",
component: "./Admin",
name: '订单管理',
path: '/trade',
component: './trade/order/index',
},
],
},
// {
// name: 'list.table-list',
// icon: 'table',
// path: '/list',
// component: './table-list',
// },
{
path: "/",
redirect: "/welcome",
},
{
component: "404",
component: '404',
layout: false,
path: "*",
path: '*',
},
];

23
mock/login.ts Normal file
View File

@@ -0,0 +1,23 @@
import type { Request, Response } from "express";
const logout = (_req: Request, res: Response) => {
res.json({
code: 0,
data: true,
msg: "",
});
};
export default {
"POST /system/auth/logout": logout,
"GET /system/tenant/get-id-by-name": {
data: 1,
},
"POST /system/auth/login": {
data: {
accessToken: "e0a58d5267d246d3a478e8c4c96051d9",
expiresTime: 1760583658965,
refreshToken: "9667e5f1a1c24c02814284aa116ea769",
userId: 1,
},
},
};

142
mock/order.ts Normal file
View File

@@ -0,0 +1,142 @@
import type { Request, Response } from "express";
const getOrderPage = (_req: Request, res: Response) => {
res.json({
data: {
list: [
{
id: 1,
orderNum: "BZ000548787",
createTime: "2025-10-1 14:00:00",
orderCategoryName: "宠物殡葬", // 订单类目
orderTerminal: 0, // 订单来源
userId: 0, // 用户编号
userName: "", // 用户姓名
userNickName: "张宁清", // 用户昵称
userAvatar: "", // 用户头像
userMobile: "18634556151", // 用户手机号
orderStatus: 2, // 订单状态
picUrl: "", // 商品图片
spuName:
"商品主标题商品主标题商品主标题商品主标题商品主题商品主标题商品主标题商品主", // 商品名称
skuName: "标准,单独火化,基础清洁", // 商品规格
count: 1, // 购买商品数量
price: 100, // 单价
handedPrice: 80, // 到手价
payPrice: "500", // 应付金额
unit: "", // 单位
subTime: "", // 预约时间
serveAddress: "张宁清,18659156151,福州 台江区 鳌峰路 万达中心甲",
userRemark: "你好呀你好元", // 用户备注
payType: "wx", // 微信
financeStatus: "1", // 财务状态
},
{
id: 2,
orderNum: "3214421412",
createTime: "",
orderCategoryName: "",
orderTerminal: 0,
userId: 0,
userName: "",
userNickName: "",
userAvatar: "",
userMobile: "",
orderStatus: 0,
picUrl: "",
spuName: "",
skuName: "",
count: 0,
price: 0,
handedPrice: 0,
payPrice: 0,
unit: "",
orderTime: "",
serveAddress: "",
userRemark: "",
payType: "",
financeStatus: "",
},
],
total: 0,
},
code: 0,
});
};
const getOrderDetail = (_req: Request, res: Response) => {
res.json({
data: {
code: 0,
data: {
tradeOrderInfoBase: {
id: "",
orderNo: "",
orderStatus: "",
orderType: "",
orderCategoryNameAndId: "",
orderTerminal: "",
userInfo: "",
cancelTime: "",
cancelReason: "",
merchantRemark: "",
refundTime: "",
propertyTime: "",
propertyStatus: "",
price: "",
discountPrice: "",
payPrice: 0,
refundPrice: "",
livePrice: "",
payType: "",
payChannelCode: "",
payOrderId: "",
payTime: "",
createTime: "",
finishTime: "",
},
tradeProductInfo: {
shopLogoUrl: "",
shopName: "",
spuId: 0,
skuId: 0,
skuPicUrl: "",
spuName: "",
skuName: "",
count: 0,
price: 0,
unit: "",
handedPrice: 0,
expensePrice: 0,
properties: [""],
serveContent: "",
totalPrice: 0,
discountPrice: 0,
payPrice: 0,
refundPrice: 0,
refundCount: 0,
},
tradeServeInfo: {
properties: {
"": {},
},
},
tradeExtendServeInfo: {
properties: {
"": {},
},
},
tradeExtendCostInfo: {
properties: {
"": {},
},
},
},
msg: "",
},
code: 0,
});
};
export default {
"GET /admin-api/trade/order/page": getOrderPage,
"GET /admin-api/trade/order/get-detail": getOrderDetail,
};

View File

@@ -45,6 +45,7 @@
"classnames": "^2.5.1",
"dayjs": "^1.11.13",
"jsencrypt": "^3.5.4",
"rc-resize-observer": "^1.4.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-infinite-scroll-component": "^6.1.0",

3
pnpm-lock.yaml generated
View File

@@ -35,6 +35,9 @@ importers:
jsencrypt:
specifier: ^3.5.4
version: 3.5.4
rc-resize-observer:
specifier: ^1.4.3
version: 1.4.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react:
specifier: ^19.1.0
version: 19.1.1

View File

@@ -193,10 +193,10 @@ export const request: RequestConfig = {
return { url, options: { ...options, headers } };
},
],
// 添加参数序列化配置
paramsSerializer: (params) => {
const searchParams = new URLSearchParams();
const appendParams = (key: string, value: any) => {
if (Array.isArray(value)) {
// 特殊处理 createTime 数组,转换为 createTime[0] 和 createTime[1] 格式

View File

@@ -1,17 +1,20 @@
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Button, type ColProps, Drawer, Space, Typography } from 'antd';
import { Button, type ColProps, Drawer, Space } from 'antd';
import type { FormInstance } from 'antd/lib';
import React, { forwardRef, useImperativeHandle } from 'react';
interface ConfigurableDrawerFormProps {
title?: string;
columns: ProFormColumnsType[];
columns?: ProFormColumnsType[];
onSubmit?: (values: any) => Promise<boolean>;
initialValues?: Record<string, any>;
width?: number | string;
labelCol?: ColProps;
wrapperCol?: ColProps;
footer: React.ReactNode;
children?: React.ReactNode;
bodyStyle: React.CSSProperties;
}
export interface ConfigurableDrawerFormRef {
@@ -32,6 +35,9 @@ const ConfigurableDrawerForm = forwardRef<
onSubmit,
initialValues,
width = 600,
footer,
children,
bodyStyle = {},
},
ref,
) => {
@@ -69,31 +75,7 @@ const ConfigurableDrawerForm = forwardRef<
setLoading(false);
}
};
// const customHeader = (
// <div
// style={{
// display: "flex",
// justifyContent: "space-between",
// alignItems: "center",
// padding: "0 0px 16px 0px",
// borderBottom: "1px solid #f0f0f0",
// marginBottom: "16px",
// }}
// >
// <Title level={4} style={{ margin: 0 }}>
// {title}
// </Title>
// <Button
// type="text"
// icon={<CloseOutlined />}
// onClick={() => setOpen(false)}
// style={{
// border: "none",
// boxShadow: "none",
// }}
// />
// </div>
// );
console.log(footer);
return (
<Drawer
title={title}
@@ -102,6 +84,11 @@ const ConfigurableDrawerForm = forwardRef<
textAlign: 'left',
position: 'relative',
},
body: {
background: 'var(--ant-background-color)',
padding: 'var(--ant-padding-lg)',
...bodyStyle,
},
}}
destroyOnHidden
closable={true} // 隐藏默认关闭按钮
@@ -110,24 +97,33 @@ const ConfigurableDrawerForm = forwardRef<
width={width}
footer={
<Space style={{ width: '100%', justifyContent: 'end' }}>
<Button onClick={() => setOpen(false)}></Button>
<Button loading={loading} type="primary" onClick={handleSubmit}>
</Button>
{footer ? (
footer
) : (
<>
<Button onClick={() => setOpen(false)}></Button>
<Button loading={loading} type="primary" onClick={handleSubmit}>
</Button>
</>
)}
</Space>
}
>
{/* {customHeader} */}
<BetaSchemaForm
initialValues={formData}
layoutType="Form"
formRef={formRef}
columns={columns}
layout="horizontal"
labelCol={labelCol}
wrapperCol={wrapperCol}
submitter={false}
/>
{columns ? (
<BetaSchemaForm
initialValues={formData}
layoutType="Form"
formRef={formRef}
columns={columns}
layout="horizontal"
labelCol={labelCol}
wrapperCol={wrapperCol}
submitter={false}
/>
) : (
children
)}
</Drawer>
);
},

View File

@@ -17,25 +17,11 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
const {
columns,
request,
// actions = [],
// permissions = [],
// checkPermission = () => true,
components,
search = {},
toolbarActions,
// showIndex = true,
// showActions = true,
// maxActionCount = 2,
// onAdd,
// onEdit,
// onDelete,
// onView,
// onExport,
// customToolbarRender,
// showSelection = true,
rowKey = 'id',
// onRow,
// rowClassName,
// enableRowClick = false,
// clickableRowClassName = "clickable-row", // 添加可点击样式
pagination = true,
...restProps
} = props;
@@ -120,25 +106,37 @@ function EnhancedProTable<T extends BaseRecord, U extends ParamsType = any>(
manualRequest={false}
showSorterTooltip
scroll={{ x: 'max-content' }}
search={{
labelWidth: 'auto',
defaultCollapsed: false,
...restProps.search,
}}
options={{
fullScreen: true,
reload: true,
setting: true,
density: true,
...restProps.options,
}}
pagination={{
showSizeChanger: true,
showQuickJumper: true,
pageSize: 10,
showTotal: formatPaginationTotal,
...restProps.pagination,
}}
components={components}
search={
search
? {
labelWidth: 'auto',
defaultCollapsed: false,
...search,
}
: false
}
options={
search
? {
fullScreen: true,
reload: true,
setting: true,
density: true,
...restProps.options,
}
: false
}
pagination={
pagination
? {
showSizeChanger: true,
showQuickJumper: true,
pageSize: 10,
showTotal: formatPaginationTotal,
}
: false
}
/>
);
}

View File

@@ -1,31 +1,31 @@
import { GithubOutlined } from "@ant-design/icons";
import { DefaultFooter } from "@ant-design/pro-components";
import React from "react";
import { GithubOutlined } from '@ant-design/icons';
import { DefaultFooter } from '@ant-design/pro-components';
import React from 'react';
const Footer: React.FC = () => {
return (
<DefaultFooter
style={{
background: "none",
background: 'none',
}}
copyright="20250923"
links={[
{
key: "by",
title: "百业到家",
href: "/welcome",
key: 'by',
title: '百业到家',
href: '/welcome',
blankTarget: true,
},
{
key: "github",
key: 'github',
title: <GithubOutlined />,
href: "https://github.com/ant-design/ant-design-pro",
href: 'https://github.com/ant-design/ant-design-pro',
blankTarget: true,
},
{
key: "Ant Design",
title: "Ant Design",
href: "https://ant.design",
key: 'bydj',
title: '宠悦',
href: 'https://ant.design',
blankTarget: true,
},
]}

View File

@@ -0,0 +1,96 @@
import type { ProFormColumnsType } from '@ant-design/pro-components';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { type ColProps, Popconfirm } from 'antd';
import type { FormInstance } from 'antd/lib';
import React, { forwardRef, useImperativeHandle } from 'react';
interface PopconfirmFormProps {
title?: string;
columns?: ProFormColumnsType[];
onSubmit?: (values: any) => Promise<boolean>;
initialValues?: Record<string, any>;
labelCol?: ColProps;
wrapperCol?: ColProps;
children?: React.ReactNode;
}
export interface PopconfirmFormRef {
open: (data?: Record<string, any>) => void;
close: () => void;
}
const PopconfirmForm = forwardRef<PopconfirmFormRef, PopconfirmFormProps>(
(
{
labelCol = { span: 4 },
wrapperCol = { span: 20 },
columns,
onSubmit,
initialValues,
children,
},
ref,
) => {
const [open, setOpen] = React.useState(false);
const [formData, setFormData] = React.useState(initialValues || {});
// const [loading, setLoading] = React.useState<boolean>(false);
// 添加表单实例引用
const formRef = React.useRef<FormInstance>(null);
useImperativeHandle(ref, () => ({
open: (data) => {
if (data) {
setFormData(data);
}
setOpen(true);
},
close: () => setOpen(false),
}));
const handleSubmit = async () => {
try {
if (onSubmit) {
await formRef.current?.validateFields();
// setLoading(true);
const values = formRef.current?.getFieldsValue();
const success = await onSubmit(values);
if (success) {
setOpen(false);
return true;
}
return false;
}
return true;
} finally {
// setLoading(false);
}
};
return (
<Popconfirm
title={null}
destroyOnHidden
icon={null}
open={open}
okText="确定"
cancelText="取消"
description={
<BetaSchemaForm
initialValues={formData}
layoutType="Form"
formRef={formRef}
columns={columns || []}
layout="horizontal"
labelCol={labelCol}
wrapperCol={wrapperCol}
submitter={false}
/>
}
onConfirm={handleSubmit}
onCancel={() => setOpen(false)}
>
{children}
</Popconfirm>
);
},
);
export default React.memo(PopconfirmForm);

View File

@@ -2,6 +2,7 @@ export const formStatusType: { [key: string]: string } = {
create: '创建',
update: '编辑',
test: '测试',
detail: '详情',
};
export const tenantStatus = [

0
src/constants/order.ts Normal file
View File

View File

@@ -92,3 +92,25 @@ ol {
}
}
}
.page-container {
background: #fff;
width: 100%;
height: 100%;
padding: 16px;
border-radius: 8px;
.ant-tabs {
.ant-pro-query-filter-container {
form {
padding-left: 0;
padding-right: 0;
padding-bottom: 0;
}
}
.ant-pro-table {
.ant-pro-card-body {
padding: 0px;
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "Ant Design Pro",
"short_name": "Ant Design Pro",
"name": "百业到家",
"short_name": "百业到家",
"display": "standalone",
"start_url": "./?utm_source=homescreen",
"theme_color": "#002140",

View File

@@ -116,7 +116,7 @@ const Welcome: React.FC = () => {
color: token.colorTextHeading,
}}
>
使 Ant Design Pro
使
</div>
<p
style={{
@@ -128,7 +128,7 @@ const Welcome: React.FC = () => {
width: '65%',
}}
>
Ant Design Pro umiAnt Design ProComponents
umiAnt Design ProComponents
//
</p>
<div

View File

@@ -25,7 +25,7 @@ export const baseTenantColumns: ProColumns<AiSampleRespVO>[] = [
{
title: '标签',
hideInTable: true,
dataIndex: 'tag_name',
dataIndex: 'tagIds',
valueType: 'select',
search: {
transform: (value) => {

View File

@@ -252,10 +252,6 @@ const SampleTagDetail = <T extends Record<string, any>>(
<span>: </span>
<span>{value.sampleMineType}</span>
</Space>
<Space size={10} style={{ width: '100%', marginBottom: 12 }}>
<span>: </span>
<span>{value.sampleTime}</span>
</Space>
{type === 'checkbox' && (
<>

View File

@@ -0,0 +1,140 @@
import type { ProColumns } from '@ant-design/pro-components';
import { Space, Typography } from 'antd';
import type { TradeOrderPageRespVO } from '@/services/trade/order';
const { Text } = Typography;
export const baseOrderColumns: ProColumns<TradeOrderPageRespVO>[] = [
{
title: '商品',
dataIndex: 'id',
width: '20%',
hideInSearch: true,
ellipsis: true,
render: (_, record) =>
// <Space style={{ width: "100%" }}>
// <Image
// src={record.picUrl}
// width={64}
// fallback="data:image/png;base64,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"
// />
record.spuName,
// <Paragraph ellipsis>
// <Paragraph ellipsis>{record.spuName}</Paragraph>
// <div>{record.skuName}</div>
// <Space>
// <div>
// <Text type="secondary">数量:</Text>
// <Text>{record.count}</Text>
// </div>
// <div>
// <Text type="secondary">单价:</Text>
// <Text>
// {record.price}/{record.unit}
// </Text>
// </div>
// <div>
// <Text type="secondary">到手价:</Text>
// <Text>
// {record.handedPrice}/{record.unit}
// </Text>
// </div>
// </Space>
// </Paragraph>
// </Space>
},
{
title: '服务',
dataIndex: 'serveAddress',
hideInSearch: true,
render: (_, record) => (
<Space direction="vertical">
<div>
<Text type="secondary"></Text>
<Text>{record.subTime}</Text>
</div>
<div>
<Text type="secondary"></Text>
<Text>{record.serveAddress}</Text>
</div>
<div>
<Text type="secondary"></Text>
<Text>{record.userRemark}</Text>
</div>
</Space>
),
},
{
title: '财务',
dataIndex: 'price',
hideInSearch: true,
render: (_, record) => (
<Space direction="vertical">
<div>
<Text type="secondary"></Text>
<Text>{record.payPrice}</Text>
</div>
<div>
<Text type="secondary"></Text>
<Text>{record.payType}</Text>
</div>
<div>
<Text type="secondary"></Text>
<Text>{record.financeStatus}</Text>
</div>
</Space>
),
},
{
title: '卖家名称',
dataIndex: 'merchantName',
hideInTable: true,
},
{
title: '买家昵称/手机号',
dataIndex: 'userSearch',
hideInTable: true,
},
{
title: '订单类目',
dataIndex: 'orderCategoryId',
valueType: 'select',
hideInTable: true,
},
{
title: '订单来源',
dataIndex: 'orderTerminal',
valueType: 'select',
hideInTable: true,
},
{
title: '财务状态',
dataIndex: 'financeStatus',
valueType: 'select',
hideInTable: true,
},
{
title: '售后状态',
dataIndex: 'afterSaleStatus',
valueType: 'select',
hideInTable: true,
},
{
title: '预约状态',
dataIndex: 'subType',
valueType: 'select',
hideInTable: true,
},
{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'dateRange',
hideInTable: true,
},
{
title: '预约时间',
dataIndex: 'subTime',
valueType: 'dateRange',
hideInTable: true,
},
];

View File

@@ -0,0 +1,90 @@
import { ProCard } from '@ant-design/pro-components';
import { Button, Card, Steps, Typography } from 'antd';
import RcResizeObserver from 'rc-resize-observer';
import React, { useCallback, useState } from 'react';
import styles from './index.module.less';
const { Title, Text } = Typography;
const BasicInfo: React.FC = () => {
const [responsive, setResponsive] = useState(false);
const renderTitle = useCallback(() => {
return <div></div>;
}, []);
return (
<div className={styles['order-info']}>
<Card title="基本信息">
<ProCard
size="small"
title={renderTitle()}
bordered
headerBordered
gutter={8}
className="order-info-card"
>
<ProCard colSpan="200px">
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: 10,
alignItems: 'center',
}}
>
<Title type="danger" level={4} style={{ margin: 0 }}>
</Title>
<span>
<Text type="secondary"></Text>
<Text>430</Text>
</span>
<Button type="primary" block>
</Button>
<Button block></Button>
</div>
</ProCard>
<ProCard layout="center">
<RcResizeObserver
key="resize-observer"
onResize={(offset) => {
setResponsive(offset.width < 460);
}}
>
<Steps
size="small"
progressDot
style={{ width: '100%' }}
current={1}
direction={responsive ? 'vertical' : 'horizontal'}
items={[
{
title: '创建订单',
description: 'This is a description.',
},
{
title: '等待付款',
},
{
title: '等待确定',
},
{
title: '等待服务',
},
{
title: '等待验收',
},
{
title: '完成',
},
]}
/>
</RcResizeObserver>
</ProCard>
</ProCard>
</Card>
</div>
);
};
export default React.memo(BasicInfo);

View File

@@ -0,0 +1,64 @@
import type { ProColumns } from '@ant-design/pro-components';
import { Tag } from 'antd';
import type { DeptVO } from '@/services/system/dept';
export const baseOrderColumns: ProColumns<DeptVO>[] = [
{
title: '商品',
dataIndex: 'name',
width: '33.33%',
render: (_, record) => (
<Tag color={record.status === 1 ? 'green' : 'red'}>{record.name}</Tag>
),
},
{
title: '服务',
dataIndex: 'leaderUserId',
hideInSearch: true,
},
{
title: '财务',
dataIndex: 'sort',
hideInSearch: true,
},
];
const sharedOnCell = (_: DeptVO, index?: number) => {
if (index === 3) {
return { colSpan: 0 };
}
return {};
};
export const surchargeInfoColumns: ProColumns<DeptVO>[] = [
{
title: '服务附加费',
dataIndex: 'name',
width: '33.33%',
render: (_, record, index) => {
if (index === 3) {
return 33333;
}
return (
<Tag color={record.status === 1 ? 'green' : 'red'}>{record.name}</Tag>
);
},
onCell: (_, index) => ({
colSpan: index === 3 ? 4 : 1,
}),
},
{
title: '费用详情',
dataIndex: 'leaderUserId',
onCell: sharedOnCell,
},
{
title: '付款信息',
dataIndex: 'sort',
onCell: sharedOnCell,
},
{
title: '退款信息',
dataIndex: 'leaderUserId1',
onCell: sharedOnCell,
},
];

View File

@@ -0,0 +1,25 @@
.order-info {
:global {
.ant-pro-card-header {
background: rgba(0, 0, 0, 0.02);
}
.ant-pro-card-col {
flex: 1 auto;
overflow: auto;
}
.order-info-card {
.ant-pro-card-col {
flex: 1 auto;
overflow: auto;
display: flex;
align-items: center;
}
}
.order-paragraph {
margin-bottom: 0;
}
.ant-pro-card-body {
padding: 0px;
}
}
}

View File

@@ -0,0 +1,134 @@
import { ProCard } from '@ant-design/pro-components';
import { Button, Card, Image, Space, Tag, Typography } from 'antd';
import React, { useCallback } from 'react';
import styles from './index.module.less';
const { Text, Paragraph } = Typography;
const ProdInfo: React.FC = () => {
const renderTitle = useCallback(() => {
return (
<Space style={{ height: '100%' }} size={16}>
<Paragraph className="order-paragraph"></Paragraph>
<Paragraph className="order-paragraph">
<Text type="secondary"> ID</Text>
<Text copyable>8877777</Text>
</Paragraph>
<Paragraph className="order-paragraph">
<Text type="secondary">SKU ID</Text>
<Text copyable>8877777</Text>
</Paragraph>
</Space>
);
}, []);
return (
<div className={styles['order-info']}>
<Card title="商品信息">
<ProCard
size="small"
title={renderTitle()}
bordered
headerBordered
gutter={8}
extra={<Button size="small"></Button>}
>
<ProCard
layout="default"
colSpan={'50%'}
style={{ borderRight: '1px solid rgba(5,5,5,0.06)' }}
>
<Space>
<Image
width={64}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
<div>
<Text></Text>
<Paragraph className="order-paragraph">
<Text></Text>
<Text type="secondary"> ,,</Text>
</Paragraph>
<Space wrap size={0} direction="horizontal">
<Paragraph
className="order-paragraph"
style={{ marginRight: 16 }}
>
<Text type="secondary"></Text>
<Text> 1</Text>
</Paragraph>
<Paragraph
className="order-paragraph"
style={{ marginRight: 16 }}
>
<Text type="secondary"></Text>
<Text> ¥100 </Text>
</Paragraph>
<Paragraph
className="order-paragraph"
style={{ marginRight: 16 }}
>
<Text type="secondary"></Text>
<Text> ¥80 </Text>
</Paragraph>
<Paragraph className="order-paragraph">
<Text type="secondary"></Text>
<Text> ¥50 /-</Text>
</Paragraph>
</Space>
</div>
</Space>
<Paragraph style={{ marginTop: 16 }}>
<Tag></Tag>
<Tag></Tag>
<Tag></Tag>
<Tag></Tag>
<Tag></Tag>
</Paragraph>
<Paragraph className="order-paragraph">
<Text type="secondary"></Text>
<Paragraph className="order-paragraph">
</Paragraph>
</Paragraph>
</ProCard>
<ProCard
style={{
borderRight: '1px solid rgba(5,5,5,0.06)',
height: '100%',
}}
>
<Space direction="vertical">
<Text></Text>
<Paragraph className="order-paragraph">
<Text type="secondary"></Text>
<Text>¥500</Text>
</Paragraph>
<Paragraph className="order-paragraph">
<Text type="secondary"></Text>
<Text>¥500</Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text>¥500</Text>
</Paragraph>
</Space>
</ProCard>
<ProCard>
<Space direction="vertical">
<Text>退</Text>
<Paragraph className="order-paragraph">
<Text type="secondary">退</Text>
<Text>¥500</Text>
</Paragraph>
<Paragraph className="order-paragraph">
<Text type="secondary">退</Text>
<Text>1</Text>
</Paragraph>
</Space>
</ProCard>
</ProCard>
</Card>
</div>
);
};
export default React.memo(ProdInfo);

View File

@@ -0,0 +1,76 @@
import { ProCard } from '@ant-design/pro-components';
import { Card, Space } from 'antd';
import React from 'react';
import EnhancedProTable from '@/components/EnhancedProTable';
import {
type DeptReqVO,
type DeptVO,
getDeptPage,
} from '@/services/system/dept';
import { baseOrderColumns } from '../../../config';
import styles from './index.module.less';
const SelectInfo: React.FC = () => {
const onFetch = async (
params: DeptReqVO & {
pageSize?: number;
current?: number;
},
) => {
const data = await getDeptPage({
...params,
pageNo: params.current,
pageSize: params.pageSize,
});
return {
data: data,
success: true,
total: data.total,
};
};
return (
<div className={styles['order-info']}>
<Card title="可选服务">
<Space direction="vertical" style={{ width: '100%' }} size={16}>
<ProCard split="vertical" bordered>
<ProCard size="small" title="服务" headerBordered>
1111
</ProCard>
<ProCard size="small" title="付款信息" headerBordered>
1111
</ProCard>
<ProCard size="small" title="退款信息" headerBordered>
1111
</ProCard>
</ProCard>
<EnhancedProTable<DeptVO>
columns={baseOrderColumns}
request={onFetch}
showIndex={false}
size="small"
search={false}
showActions={false}
showSelection={false}
bordered
pagination={false}
/>
<ProCard split="vertical" bordered>
<ProCard size="small" title="纪念品" headerBordered>
1111
</ProCard>
<ProCard size="small" title="付款信息" headerBordered>
1111
</ProCard>
<ProCard size="small" title="退款摘要" headerBordered>
1111
</ProCard>
</ProCard>
</Space>
</Card>
</div>
);
};
export default React.memo(SelectInfo);

View File

@@ -0,0 +1,98 @@
import { ProCard } from '@ant-design/pro-components';
import { Button, Card, Image, Space, Typography } from 'antd';
import React from 'react';
import styles from './index.module.less';
const { Text, Paragraph } = Typography;
const ServiceInfo: React.FC = () => {
return (
<div className={styles['order-info']}>
<Card title="服务信息">
<ProCard split="vertical">
<ProCard
title="遗体信息"
extra={<Button size="small"></Button>}
size="small"
colSpan="30%"
headerBordered
>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary">/</Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Space wrap>
<Image
width={48}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
<Image
width={48}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
<Image
width={48}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
<Image
width={48}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
<Image
width={48}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
</Space>
</Paragraph>
</ProCard>
<ProCard
size="small"
title="预约信息"
headerBordered
extra={<Button size="small"></Button>}
>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
<Paragraph>
<Text type="secondary"></Text>
<Text></Text>
</Paragraph>
</ProCard>
</ProCard>
</Card>
</div>
);
};
export default React.memo(ServiceInfo);

View File

@@ -0,0 +1,49 @@
import { Card } from 'antd';
import React from 'react';
import EnhancedProTable from '@/components/EnhancedProTable';
import {
type DeptReqVO,
type DeptVO,
getDeptPage,
} from '@/services/system/dept';
import { surchargeInfoColumns } from './config';
import styles from './index.module.less';
const SurchargeInfo: React.FC = () => {
const onFetch = async (
params: DeptReqVO & {
pageSize?: number;
current?: number;
},
) => {
const data = await getDeptPage({
...params,
pageNo: params.current,
pageSize: params.pageSize,
});
return {
data: data,
success: true,
total: data.total,
};
};
return (
<div className={styles['order-info']}>
<Card title="服务信息">
<EnhancedProTable<DeptVO>
columns={surchargeInfoColumns}
request={onFetch}
showIndex={false}
size="small"
search={false}
showActions={false}
showSelection={false}
bordered
pagination={false}
/>
</Card>
</div>
);
};
export default React.memo(SurchargeInfo);

View File

@@ -0,0 +1,26 @@
import { Tabs, type TabsProps } from 'antd';
import React from 'react';
import OrderInfo from './order-info';
const DetailCom: React.FC = () => {
const items: TabsProps['items'] = [
{
key: '1',
label: '订单信息 ',
children: <OrderInfo />,
},
{
key: '2',
label: '服务履约',
children: '服务履约',
},
{
key: '3',
label: '商品配送',
children: '商品配送',
},
];
return <Tabs defaultActiveKey="1" items={items} />;
};
export default React.memo(DetailCom);

View File

@@ -0,0 +1,21 @@
import { Space } from 'antd';
import React from 'react';
import BasicInfo from './component/info/basic-info'; //基本信息(通版)
import ProdInfo from './component/info/prod-info'; //商品信息(通版)
import SelectInfo from './component/info/select-info'; //可选服务(殡葬专属字段)
import ServiceInfo from './component/info/service-info';
import SurchargeInfo from './component/info/surcharge-info'; //服务附加费(殡葬专属字段)
const OrderDetail: React.FC = () => {
return (
<Space direction="vertical" size={24} style={{ width: '100%' }}>
<BasicInfo />
<ProdInfo />
<ServiceInfo />
<SelectInfo />
<SurchargeInfo />
</Space>
);
};
export default React.memo(OrderDetail);

View File

@@ -0,0 +1,9 @@
.trade-order {
:global {
.expanded-row-top {
order: -1; /* 在 Flex 布局中将元素移到前面 */
position: relative;
margin: 0 -16px 16px -16px; /* 调整边距以填满整行 */
}
}
}

View File

@@ -0,0 +1,37 @@
import type { TabsProps } from 'antd';
import { Tabs } from 'antd';
import React from 'react';
import styles from './index.module.less';
import OrderListItem from './list';
const onChange = (key: string) => {
console.log(key);
};
const status: string[] = [
'所有订单',
'等待付款',
'等待确定',
'等待服务',
'等待验收',
'等待评价',
'已完成',
'已取消',
'已退款',
];
const OrderList: React.FC = () => {
const items: TabsProps['items'] = status.map((item, index) => ({
key: `${index + 1}`,
label: item,
children: <OrderListItem />,
}));
return (
<div className={`${styles['trade-order']} "page-container" `}>
<Tabs defaultActiveKey="1" items={items} onChange={onChange} />
</div>
);
};
export default OrderList;

View File

@@ -0,0 +1,259 @@
import {
type ActionType,
ProCard,
type ProColumns,
} from '@ant-design/pro-components';
import {
Avatar,
Badge,
Button,
Divider,
Input,
message,
Space,
Statistic,
} from 'antd';
import React, { useCallback, useRef, useState } from 'react';
import ConfigurableDrawerForm, {
type ConfigurableDrawerFormRef,
} from '@/components/DrawerForm';
import EnhancedProTable from '@/components/EnhancedProTable';
import { baseOrderColumns } from './config';
const { Search } = Input;
import { DownOutlined, UpOutlined, UserOutlined } from '@ant-design/icons';
import PopconfirmForm, {
type PopconfirmFormRef,
} from '@/components/PopconfirmForm';
import {
getTradeOrderPage,
type TradeOrderPageRespVO,
type TradeReq,
} from '@/services/trade/order';
import DetailCom from './detail';
const OrderListItem: React.FC = () => {
const tableRef = useRef<ActionType>(null);
const configurableDrawerRef = useRef<ConfigurableDrawerFormRef>(null);
const [modalTitle, setModalTitle] = useState<string>('订单BZ000548787');
const [isShowTotal, setIsShowTotal] = useState<boolean>(false);
const popconfirmFormRef = useRef<PopconfirmFormRef>(null);
const onFetch = async (
params: TradeReq & {
pageSize?: number;
current?: number;
},
) => {
const data = await getTradeOrderPage({
...params,
pageNo: params.current,
pageSize: params.pageSize,
});
return {
data: data.list,
success: true,
total: data.total,
};
};
const handleDetail = useCallback((record: TradeOrderPageRespVO) => {
setModalTitle(`订单:${record.orderNum}`);
configurableDrawerRef.current?.open();
}, []);
const handleOrder = useCallback((id?: number) => {
console.log(id, '取消订单');
// await updateTradeOrder(values.id);
}, []);
const handleUpdate = async (_values: TradeOrderPageRespVO) => {
try {
// await updateTradeOrder(values.id);
return true;
} finally {
message.success('更新成功');
}
// await updateTradeOrder(values.id);
};
const actionColumns: ProColumns<TradeOrderPageRespVO> = {
title: '操作',
dataIndex: 'option',
valueType: 'option',
fixed: 'right',
width: 100,
render: (_text: React.ReactNode, record: TradeOrderPageRespVO) => [
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: 4,
justifyContent: 'center',
}}
key={record.id}
>
<a key="cancel" onClick={() => handleOrder(record.id)}>
</a>
<a key="detail" onClick={() => handleDetail(record)}>
</a>
<PopconfirmForm
ref={popconfirmFormRef}
columns={[
{
title: '备注',
name: 'userRemark',
valueType: 'textarea',
fieldProps: { rows: 4, autoFocus: false },
},
]}
onSubmit={handleUpdate}
>
<a
key="remark"
onClick={() => popconfirmFormRef.current?.open(record)}
>
</a>
</PopconfirmForm>
</div>,
],
};
const onClose = useCallback(() => {
configurableDrawerRef.current?.close();
}, []);
const handleRow = (record: TradeOrderPageRespVO) => {
return {
'data-record': JSON.stringify(record),
className: 'order-row-with-info',
};
};
const components = {
body: {
row: (props: any) => {
const { children, ...restProps } = props;
const record = props['data-record']
? JSON.parse(props['data-record'])
: {};
return (
<>
{record && (
<tr style={{ background: 'rgba(0, 0, 0, 0.06)' }}>
<td
colSpan={columns.length}
style={{
padding: '0px 8px',
borderBottom: '1px solid #f0f0f0',
fontSize: '12px',
color: '#666',
}}
>
<Space>
<span>
<Badge
status="success"
text={record.orderStatus}
size="small"
/>
</span>
<Divider />
<span> {record.orderCategoryName}</span>
<span> {record.createTime}</span>
<span>{record.orderNum}</span>
<span> {record.payType}</span>
<Space>
<Avatar icon={<UserOutlined />} />
{/* <Image src={record.picUrl} width={64} /> */}
</Space>
<Space>
{record.userAvatar ? (
<Avatar src={record.userAvatar} />
) : (
<Avatar icon={<UserOutlined />} />
)}
{record.userNickName || record.userName}
<span>{record.userMobile} </span>
</Space>
</Space>
</td>
</tr>
)}
<tr {...restProps}>{children}</tr>
</>
);
},
},
};
const columns = [...baseOrderColumns, actionColumns];
const handleIsTotal = useCallback(() => {
setIsShowTotal(!isShowTotal);
}, [isShowTotal]);
const handleSearch = useCallback((value: string) => {
console.log('搜索', value);
tableRef.current?.reload();
}, []);
return (
<>
<Space>
<Search
placeholder="商品名称/商品ID/订单号"
enterButton
onSearch={handleSearch}
/>
<Button
icon={isShowTotal ? <DownOutlined /> : <UpOutlined />}
onClick={handleIsTotal}
>
</Button>
</Space>
{isShowTotal && (
<ProCard.Group direction="row" bordered style={{ marginTop: 16 }}>
<ProCard layout="center" style={{ background: '#f5f5f5' }}>
<Statistic title="订单数量" value={79.0} precision={2} />
</ProCard>
<ProCard layout="center" style={{ background: '#f5f5f5' }}>
<Statistic title="实付金额" value={112893.0} precision={2} />
</ProCard>
<ProCard layout="center" style={{ background: '#f5f5f5' }}>
<Statistic title="实收金额" value={93} suffix="/ 100" />
</ProCard>
</ProCard.Group>
)}
<EnhancedProTable<TradeOrderPageRespVO>
ref={tableRef}
columns={columns}
request={onFetch}
headerTitle="销售管理"
showIndex={false}
showSelection={false}
search={{ defaultCollapsed: true }}
onRow={handleRow}
components={components}
/>
<ConfigurableDrawerForm
ref={configurableDrawerRef}
width="80vw"
title={modalTitle}
bodyStyle={{
background: '#f5f5f5',
paddingTop: 8,
}}
footer={<Button onClick={onClose}></Button>}
>
<DetailCom />
</ConfigurableDrawerForm>
</>
);
};
export default OrderListItem;

View File

@@ -0,0 +1,473 @@
import { request } from "@umijs/max";
export interface TradeReq {
/**
* 售后状态示例1
*/
afterSaleStatus?: number;
/**
* 创建时间
*/
createTime?: string[];
/**
* 财务状态示例1
*/
financeStatus?: number;
/**
* 卖家名称
*/
merchantName?: string;
/**
* 订单类目id示例1
*/
orderCategoryId?: number;
/**
* 订单状态示例1
*/
orderStatus?: number;
/**
* 订单来源示例1
*/
orderTerminal?: number;
/**
* 页码,从 1 开始", example = "1
*/
pageNo?: number;
/**
* 每页条数,最大值为 100"
*/
pageSize?: number;
/**
* 聚合检索字段商品名称商品id订单号
*/
prodSearch?: string;
/**
* 创建时间
*/
subTime?: string[];
/**
* 预约类型示例1
*/
subType?: number;
/**
* 聚合检索字段 买家昵称/手机号
*/
userSearch?: string;
}
export interface TradeOrderPageRespVO {
/**
* 购买的商品数量
*/
count?: number;
/**
* 下单时间
*/
createTime?: string;
/**
* 财务状态
*/
financeStatus?: string;
/**
* 到手价
*/
handedPrice?: number;
/**
* 订单编号
*/
id?: number;
/**
* 订单类目
*/
orderCategoryName?: string;
/**
* 订单流水号
*/
orderNum?: string;
/**
* 订单状态
*/
orderStatus?: number;
/**
* 订单来源
*/
orderTerminal?: number;
/**
* 预约时间
*/
subTime?: string;
/**
* 到手价
*/
payPrice?: number;
/**
* 支付方式
*/
payType?: string;
/**
* 商品图片
*/
picUrl?: string;
/**
* 单价
*/
price?: number;
/**
* 服务地址
*/
serveAddress?: string;
/**
* 商品规格
*/
skuName?: string;
/**
* 商品名称
*/
spuName?: string;
/**
* 单位
*/
unit?: string;
/**
* 用户头像
*/
userAvatar?: string;
/**
* 用户编号
*/
userId?: number;
/**
* 用户手机号
*/
userMobile?: string;
/**
* 用户姓名
*/
userName?: string;
/**
* 用户昵称
*/
userNickName?: string;
/**
* 用户备注 - 必填,示例:你猜
*/
userRemark?: string;
}
/**
* 返回数据
*
* TradeOrderDetailRespVO
*/
export interface TradeOrderDetailRespVO {
/**
* 购买的商品数量
*/
count?: number;
/**
* 下单时间 - 必填
*/
createTime?: string;
/**
* 财务状态
*/
financeStatus?: string;
/**
* 到手价
*/
handedPrice?: number;
/**
* 订单编号 - 必填示例1024
*/
id?: number;
/**
* 订单类目
*/
orderCategoryName?: string;
/**
* 订单流水号 - 必填示例1146347329394184195
*/
orderNum?: string;
/**
* 订单状态
*/
orderStatus?: number;
/**
* 订单来源
*/
orderTerminal?: number;
/**
* 预约时间
*/
orderTime?: string;
/**
* 应付金额(总) - 必填示例1000
*/
payPrice?: number;
/**
* 支付方式
*/
payType?: string;
/**
* 商品图片
*/
picUrl?: string;
/**
* 单价
*/
price?: number;
/**
* 服务地址
*/
serveAddress?: string;
/**
* 商品规格
*/
skuName?: string;
/**
* 商品名称
*/
spuName?: string;
/**
* 配送信息
*/
tradeDeliveryInfo?: TradeDeliveryInfo;
/**
* 附加费信息
*/
tradeExtendCostInfo?: string;
/**
* 扩展服务信息
*/
tradeExtendServeInfo?: string;
/**
* 基本信息
*/
tradeOrderInfoBase?: TradeOrderBaseInfo;
/**
* 商品信息
*/
tradeProductInfo?: string;
/**
* 单位
*/
unit?: string;
/**
* 用户头像
*/
userAvatar?: string;
/**
* 用户编号 - 必填示例2048
*/
userId?: number;
/**
* 用户手机号
*/
userMobile?: string;
/**
* 用户姓名
*/
userName?: string;
/**
* 用户昵称
*/
userNickName?: string;
/**
* 用户备注 - 必填,示例:你猜
*/
userRemark?: string;
}
/**
* 配送信息
*
* TradeDeliveryInfo
*/
export interface TradeDeliveryInfo {
/**
* 快递详情
*/
deliveryDetail?: string;
/**
* 承运方
*/
logisticsName?: string;
/**
* 送货上门
*/
logisticsNum?: string;
/**
* 送货方式
*/
logisticsType?: string;
/**
* 收货地址
*/
receiverDetailAddress?: string;
/**
* 收货手机
*/
receiverMobile?: string;
/**
* 收货人
*/
receiverName?: string;
}
/**
* 基本信息
*
* TradeOrderBaseInfo
*/
export interface TradeOrderBaseInfo {
/**
* 实收金额
*/
actualPrice?: string;
/**
* 售后编号 - 必填示例450878
*/
afterSaleCode?: string;
/**
* 售后类型 - 必填,示例:仅退款/退货退款/可扩展增加使用
*/
afterSaleType?: string;
/**
* 申请人 - 必填,示例:用户/商家/平台+ID
*/
applicant?: string;
/**
* 审核人 - 必填,示例:姓名+ID
*/
auditor?: string;
/**
* 审核时间 - 必填示例2025-07-01 12:00:00
*/
auditTime?: string;
/**
* 取消时间
*/
cancelTime?: string;
/**
* 关闭时间 - 必填示例2025-07-01 12:00:00
*/
closeTime?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 优惠金额
*/
discountPrice?: string;
/**
* 完成时间
*/
finishTime?: string;
/**
* 订单id
*/
id?: string;
/**
* 订单编号
*/
orderNo?: string;
/**
* 订单状态
*/
orderStatus?: string;
/**
* 订单来源
*/
orderTerminal?: string;
/**
* 订单类型
*/
orderType?: string;
/**
* 支付方式
*/
payChannel?: string;
/**
* 交易流水号
*/
payOrderId?: string;
/**
* 订单金额
*/
payPrice?: string;
/**
* 支付时间
*/
payTime?: string;
/**
* 退款金额 - 必填
*/
refundAmount?: number;
/**
* 退款方式 - 必填,示例:系统自动退款
*/
refundMethod?: string;
/**
* 退款金额
*/
refundPrice?: string;
/**
* 退款原因 - 必填,示例:不想要了
*/
refundReason?: string;
/**
* 退款说明 - 必填,示例:这里是用户填写的退款描述
*/
refundRemark?: string;
/**
* 退款状态 - 必填,示例:待审核/待退款/已退款/已拒绝
*/
refundStatus?: string;
/**
* 退款至 - 必填,示例:原支付方式返还
*/
refundTo?: string;
/**
* 退款类型 - 必填,示例:订单退款/差价退款/运费退款/可扩展增加
*/
refundType?: string;
/**
* 用户ID 示例666
*/
userId?: number;
/**
* 用户昵称 示例:钱多多
*/
userNickname?: string;
}
// /**
// * CommonResultTradeOrderDetailRespVO
// */
// export interface ApifoxModel {
// /**
// * 错误码
// */
// code?: number;
// /**
// * 返回数据
// */
// data?: TradeOrderDetailRespVO;
// /**
// * 错误提示,用户可阅读
// */
// msg?: string;
// }
export const getTradeOrderPage = async (params: TradeReq) => {
return request<PageResult<TradeOrderPageRespVO[]>>("/trade/order/page", {
method: "GET",
params,
});
};
export const getTradeOrderDetail = async (id: number) => {
return request<IResponse<TradeOrderDetailRespVO>>("/trade/order/get-detail", {
method: "GET",
params: { id },
});
};