refactor(dealer): 重构经销商模块配置面板

- 使用 BetaSchemaForm 替代原有 Form 组件
- 移除冗余的表单配置渲染逻辑
- 动态生成模块配置表单结构
- 优化模块配置项的展示与交互
- 统一配置面板的数据流处理方式
- 提升配置面板的可维护性和扩展性
This commit is contained in:
shenyifei 2025-11-07 00:36:09 +08:00
parent f7425f5961
commit 0c39c005bd
14 changed files with 933 additions and 628 deletions

View File

@ -15,7 +15,7 @@ import {
RouteContext, RouteContext,
RouteContextType, RouteContextType,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { Col, message, Row, Space } from 'antd'; import { Col, message, Row } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
// 默认模块配置 // 默认模块配置
@ -33,57 +33,446 @@ type DealerIdAndTemplate = Pick<
'dealerId' | 'deliveryTemplate' 'dealerId' | 'deliveryTemplate'
>; >;
const getDefaultModuleConfig = (moduleType: string): ModuleConfig => { // 定义各模块的表单配置
const defaults = { const getModuleFormSchema = (moduleType: string) => {
title: { const schemas = {
text: '西瓜发货清单', title: [
align: 'center', {
size: 'large', title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'title',
title: '标题文本',
valueType: 'text',
fieldProps: {
placeholder: '例如:西瓜发货清单',
}, },
},
],
},
],
dealerInfo: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showDealerName',
title: '显示经销商名称',
valueType: 'switch',
},
{
dataIndex: 'dealerName',
title: '经销商名称',
valueType: 'text',
fieldProps: {
placeholder: '请输入经销商名称',
},
},
{
dataIndex: 'showVehicleNumber',
title: '显示车次信息',
valueType: 'switch',
},
{
dataIndex: 'showDestination',
title: '显示收货地',
valueType: 'switch',
},
{
dataIndex: 'showWatermelonGrade',
title: '显示西瓜品级',
valueType: 'switch',
tooltip: '单条报价有效',
},
],
},
{
title: '内容配置',
valueType: 'group',
columns: [
{
dataIndex: 'requiredWatermelonGrade',
title: '填写西瓜品级',
valueType: 'switch',
tooltip: '单条报价有效',
},
],
},
],
shippingInfo: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showShippingFrom',
title: '显示发货地',
valueType: 'switch',
},
{
dataIndex: 'showDate',
title: '显示发货日期',
valueType: 'switch',
},
],
},
{
title: '内容配置',
valueType: 'group',
columns: [
{
dataIndex: 'requiredShippingFrom',
title: '填写发货地',
valueType: 'switch',
},
],
},
],
weightInfo: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showGrossWeight',
title: '显示毛重',
valueType: 'switch',
},
{
dataIndex: 'grossWeightUnit',
title: '单位',
valueType: 'select',
valueEnum: {
1: '斤',
2: '公斤',
},
},
{
dataIndex: 'showBoxWeight',
title: '显示箱重',
valueType: 'switch',
},
{
dataIndex: 'boxWeightUnit',
title: '单位',
valueType: 'select',
valueEnum: {
1: '斤',
2: '公斤',
},
},
{
dataIndex: 'showNetWeight',
title: '显示净重',
valueType: 'switch',
},
{
dataIndex: 'netWeightUnit',
title: '单位',
valueType: 'select',
valueEnum: {
1: '斤',
2: '公斤',
},
},
{
dataIndex: 'showUnitPrice',
title: '显示单价',
valueType: 'switch',
},
{
dataIndex: 'unitPriceUnit',
title: '单位',
valueType: 'select',
valueEnum: {
1: '元/斤',
2: '元/公斤',
},
},
{
dataIndex: 'showAmount',
title: '显示金额',
valueType: 'switch',
},
{
dataIndex: 'showGrade',
title: '显示品级',
valueType: 'switch',
},
{
dataIndex: 'showAccountCompany',
title: '显示入账公司',
valueType: 'switch',
},
{
dataIndex: 'showSumAmount',
title: '显示总计',
valueType: 'switch',
tooltip: '多条报价之和',
},
],
},
{
title: '内容配置',
valueType: 'group',
columns: [
{
dataIndex: 'requiredGrade',
title: '填写西瓜品级',
valueType: 'switch',
},
],
},
],
packingSpec: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showBoxType',
title: '显示箱号',
valueType: 'switch',
},
{
dataIndex: 'showQuantity',
title: '显示数量',
valueType: 'switch',
},
{
dataIndex: 'showUnitPrice',
title: '显示单价',
valueType: 'switch',
},
{
dataIndex: 'showAmount',
title: '显示金额',
valueType: 'switch',
},
{
dataIndex: 'showUnitWeight',
title: '显示单重',
valueType: 'switch',
},
{
dataIndex: 'showWeight',
title: '显示重量',
valueType: 'switch',
},
],
},
],
vehicleInfo: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showDriverPhone',
title: '显示司机号码',
valueType: 'switch',
},
{
dataIndex: 'showLicensePlate',
title: '显示车牌',
valueType: 'switch',
},
{
dataIndex: 'showEstimatedArrivalTime',
title: '显示预计到仓时间',
valueType: 'switch',
},
{
dataIndex: 'showFreightDebt',
title: '显示运费欠',
valueType: 'switch',
},
{
dataIndex: 'showStrawMatDebt',
title: '显示草帘欠',
valueType: 'switch',
},
{
dataIndex: 'showRemarks',
title: '显示备注',
valueType: 'switch',
},
{
dataIndex: 'freightDebtTitle',
title: '运费欠标题',
valueType: 'text',
fieldProps: {
placeholder: '请输入运费欠标题',
},
},
],
},
{
title: '内容配置',
valueType: 'group',
columns: [
{
dataIndex: 'requiredEstimatedArrivalTime',
title: '填写预计到仓时间',
valueType: 'switch',
},
{
dataIndex: 'requiredRemarks',
title: '填写备注',
valueType: 'switch',
},
],
},
],
otherFees: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'feeItems',
title: '显示费用项目',
valueType: 'checkbox',
valueEnum: {
trademark: '商标',
labor: '人工',
paperBox: '纸箱',
fee: '费用',
codingFee: '打码费',
},
},
],
},
],
totalAmount: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showTotalAmount',
title: '显示合计金额',
valueType: 'switch',
},
{
dataIndex: 'showFarmer',
title: '信息瓜农',
valueType: 'switch',
},
{
dataIndex: 'sumTitle',
title: '合计金额标题',
valueType: 'text',
fieldProps: {
placeholder: '请输入合计金额标题',
},
},
],
},
],
otherInfo: [
{
title: '显示配置',
valueType: 'group',
columns: [
{
dataIndex: 'showOrigin',
title: '显示产地',
valueType: 'switch',
},
{
dataIndex: 'showSupplier',
title: '显示供应商',
valueType: 'switch',
},
{
dataIndex: 'showDepartureTime',
title: '显示发车时间',
valueType: 'switch',
},
{
dataIndex: 'showArrivalTime',
title: '显示预计到达',
valueType: 'switch',
},
{
dataIndex: 'showProductName',
title: '显示品名',
valueType: 'switch',
},
],
},
],
} as any;
return schemas[moduleType] || [];
};
// 模块结构配置 - 定义每个模块的字段和默认显示设置
const getModuleStructure = (moduleType: string) => {
const structures = {
title: {},
dealerInfo: { dealerInfo: {
dealerName: '盛京水果',
vehicleNumber: '第188车',
destination: '宁夏',
watermelonGrade: 'A级',
showDealerName: true, showDealerName: true,
showVehicleNumber: true, showVehicleNumber: true,
showDestination: true, showDestination: true,
showWatermelonGrade: true, showWatermelonGrade: true,
requiredWatermelonGrade: true,
}, },
shippingInfo: { shippingInfo: {
shippingFrom: '宁夏',
date: '2025年8月18日',
showShippingFrom: true, showShippingFrom: true,
showDate: true, showDate: true,
requiredShippingFrom: true,
}, },
weightInfo: { weightInfo: {
grossWeight: '56960',
boxWeight: '3391',
netWeight: '53569',
unitPrice: '1.60',
amount: '85710',
grade: 'A',
accountCompany: '公司名称',
sumAmount: '85710',
showGrossWeight: true, showGrossWeight: true,
grossWeightUnit: '1',
showBoxWeight: true, showBoxWeight: true,
boxWeightUnit: '1',
showNetWeight: true, showNetWeight: true,
netWeightUnit: '1',
showUnitPrice: true, showUnitPrice: true,
unitPriceUnit: '1',
showAmount: true, showAmount: true,
showGrade: true, showGrade: true,
showAccountCompany: true, showAccountCompany: true,
showSumAmount: true, showSumAmount: true,
requiredGrade: true,
}, },
packingSpec: { packingSpec: {
columns: [ columns: [
'boxCategory', {
'boxType', dataIndex: 'boxCategory',
'quantity', title: '',
'unitPrice', },
'amount', {
'unitWeight', dataIndex: 'boxType',
'weight', title: '箱号',
},
{
dataIndex: 'quantity',
title: '数量',
},
{
dataIndex: 'unitPrice',
title: '单价',
},
{
dataIndex: 'amount',
title: '金额',
},
{
dataIndex: 'unitWeight',
title: '单重',
},
{
dataIndex: 'weight',
title: '重量',
},
], ],
showBoxCategory: true, showBoxCategory: true,
showBoxType: true, showBoxType: true,
showQuantity: true, showQuantity: true,
@ -91,6 +480,85 @@ const getDefaultModuleConfig = (moduleType: string): ModuleConfig => {
showAmount: true, showAmount: true,
showUnitWeight: true, showUnitWeight: true,
showWeight: true, showWeight: true,
},
vehicleInfo: {
freightDebtTitle: '运费欠',
showDriverPhone: true,
showLicensePlate: true,
showEstimatedArrivalTime: true,
showFreightDebt: true,
showStrawMatDebt: true,
showRemarks: true,
requiredEstimatedArrivalTime: true,
requiredRemarks: true,
},
otherFees: {
feeItems: ['trademark', 'labor', 'paperBox', 'fee', 'codingFee'],
feeLabels: {
trademark: '商标',
labor: '人工',
paperBox: '纸箱',
fee: '费用',
codingFee: '打码费',
},
},
totalAmount: {
sumTitle: '合计金额',
showTotalAmount: true,
showFarmer: true,
},
otherInfo: {
showOrigin: true,
showSupplier: true,
showDepartureTime: true,
showArrivalTime: true,
showProductName: true,
format: 'list',
},
};
return structures[moduleType as keyof typeof structures] || {};
};
// 模块示例数据 - 用于模板编辑时的预览
const getModuleExampleData = (moduleType: string) => {
const examples = {
title: {
title: '西瓜发货清单',
},
dealerInfo: {
dealerName: '盛京水果',
vehicleNumber: '第188车',
destination: '宁夏',
watermelonGrade: 'A级',
},
shippingInfo: {
shippingFrom: '宁夏',
date: '2025年8月18日',
},
weightInfo: {
data: [
{
grossWeight: '56960',
boxWeight: '3391',
netWeight: '53569',
unitPrice: '1.60',
amount: '85710',
grade: 'A',
},
{
grossWeight: '56960',
boxWeight: '3391',
netWeight: '53569',
unitPrice: '1.60',
amount: '85710',
grade: 'A',
},
],
accountCompany: '公司名称',
sumAmount: '85710',
},
packingSpec: {
data: [ data: [
{ {
boxCategory: '4粒', boxCategory: '4粒',
@ -126,52 +594,36 @@ const getDefaultModuleConfig = (moduleType: string): ModuleConfig => {
licensePlate: '京A12345', licensePlate: '京A12345',
estimatedArrivalTime: '2025年9月24日', estimatedArrivalTime: '2025年9月24日',
freightDebt: '11000', freightDebt: '11000',
seller: '卖货',
strawMatDebt: '100', strawMatDebt: '100',
remarks: '备注', remarks: '备注',
freightDebtTitle: '运费欠',
showDriverPhone: true,
showLicensePlate: true,
showEstimatedArrivalTime: true,
showFreightDebt: true,
showSeller: true,
showStrawMatDebt: true,
showRemarks: true,
}, },
otherFees: { otherFees: {
enabled: true,
feeItems: ['trademark', 'labor', 'paperBox', 'fee', 'codingFee'],
trademark: '400', trademark: '400',
labor: '600', labor: '600',
paperBox: '13,253', paperBox: '13,253',
fee: '2,000', fee: '2,000',
codingFee: '300', codingFee: '300',
laborDetails: false,
}, },
totalAmount: { totalAmount: {
enabled: true,
sumTitle: '合计金额',
amount: '102,263', amount: '102,263',
farmer: '李荣赞', farmer: '李荣赞',
showTotalAmount: true,
showFarmer: true,
}, },
otherInfo: { otherInfo: {
enabled: false,
origin: '内蒙古', origin: '内蒙古',
supplier: '北京新发龙盛商贸有限公司', supplier: '北京新发龙盛商贸有限公司',
departureTime: '9月2号', departureTime: '9月2号',
arrivalTime: '9月3号', arrivalTime: '9月3号',
productName: 'A级-麒麟爪', productName: 'A级-麒麟爪',
showOrigin: true,
showSupplier: true,
showDepartureTime: true,
showArrivalTime: true,
showProductName: true,
format: 'list',
}, },
} as any; };
return { ...defaults[moduleType] };
return examples[moduleType as keyof typeof examples] || {};
};
const getDefaultModuleConfig = (moduleType: string): ModuleConfig => {
const structure = getModuleStructure(moduleType);
const exampleData = getModuleExampleData(moduleType);
return { ...structure, ...exampleData };
}; };
export default function DeliveryTemplate(props: IDeliveryTemplateProps) { export default function DeliveryTemplate(props: IDeliveryTemplateProps) {
@ -199,13 +651,15 @@ export default function DeliveryTemplate(props: IDeliveryTemplateProps) {
const newModule = { const newModule = {
id: `module_${Date.now()}`, id: `module_${Date.now()}`,
type: moduleType, type: moduleType,
title: intl.formatMessage({ id: `${intlPrefix}.module.${moduleType}` }),
config: getDefaultModuleConfig(moduleType), config: getDefaultModuleConfig(moduleType),
schemas: getModuleFormSchema(moduleType),
}; };
// 如果有选中的模块,则将新模块插入到选中模块的下方 // 如果有选中的模块,则将新模块插入到选中模块的下方
if (selectedModule) { if (selectedModule) {
const selectedIndex = modules.findIndex( const selectedIndex = modules.findIndex(
(module) => module.id === selectedModule.id (module) => module.id === selectedModule.id,
); );
if (selectedIndex !== -1) { if (selectedIndex !== -1) {

View File

@ -1,4 +1,5 @@
import { Card, Checkbox, Empty, Form, Input, Switch } from 'antd'; import { BetaSchemaForm } from '@ant-design/pro-components';
import { Card, Empty } from 'antd';
import React from 'react'; import React from 'react';
interface ConfigPanelProps { interface ConfigPanelProps {
@ -10,14 +11,6 @@ const ConfigPanel: React.FC<ConfigPanelProps> = ({
selectedModule, selectedModule,
onConfigChange, onConfigChange,
}) => { }) => {
const [form] = Form.useForm();
React.useEffect(() => {
if (selectedModule) {
form.setFieldsValue(selectedModule.config);
}
}, [selectedModule, form]);
const handleValuesChange = (changedValues: any, allValues: any) => { const handleValuesChange = (changedValues: any, allValues: any) => {
if (selectedModule) { if (selectedModule) {
onConfigChange(selectedModule.id, { onConfigChange(selectedModule.id, {
@ -27,309 +20,6 @@ const ConfigPanel: React.FC<ConfigPanelProps> = ({
} }
}; };
const renderTitleConfig = () => (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item name="text" label="标题文本">
<Input placeholder="例如:西瓜发货清单" />
</Form.Item>
</div>
);
const renderDealerInfoConfig = () => (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="showDealerName"
valuePropName="checked"
label="显示经销商名称"
>
<Switch />
</Form.Item>
<Form.Item name="dealerName" label="经销商名称">
<Input placeholder="请输入经销商名称" />
</Form.Item>
<Form.Item
name="showVehicleNumber"
valuePropName="checked"
label="显示车次信息"
>
<Switch />
</Form.Item>
<Form.Item
name="showDestination"
valuePropName="checked"
label="显示收货地"
>
<Switch />
</Form.Item>
<Form.Item
name="showWatermelonGrade"
valuePropName="checked"
label="填写西瓜品级"
extra="单条报价有效"
>
<Switch />
</Form.Item>
</div>
);
const renderWeightInfoConfig = () => (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="showGrossWeight"
valuePropName="checked"
label="显示毛重"
>
<Switch />
</Form.Item>
<Form.Item name="showBoxWeight" valuePropName="checked" label="显示箱重">
<Switch />
</Form.Item>
<Form.Item name="showNetWeight" valuePropName="checked" label="显示净重">
<Switch />
</Form.Item>
<Form.Item name="showUnitPrice" valuePropName="checked" label="显示单价">
<Switch />
</Form.Item>
<Form.Item name="showAmount" valuePropName="checked" label="显示金额">
<Switch />
</Form.Item>
<Form.Item name="showGrade" valuePropName="checked" label="填写品级">
<Switch />
</Form.Item>
<Form.Item
name="showAccountCompany"
valuePropName="checked"
label="显示入账公司"
>
<Switch />
</Form.Item>
<Form.Item
name="showSumAmount"
valuePropName="checked"
label="显示总计"
extra={'多条报价之和'}
>
<Switch />
</Form.Item>
</div>
);
const renderPackingSpecConfig = () => (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="showBoxCategory"
valuePropName="checked"
label="显示品牌"
>
<Switch />
</Form.Item>
<Form.Item name="showBoxType" valuePropName="checked" label="显示箱号">
<Switch />
</Form.Item>
<Form.Item name="showQuantity" valuePropName="checked" label="显示数量">
<Switch />
</Form.Item>
<Form.Item name="showUnitPrice" valuePropName="checked" label="显示单价">
<Switch />
</Form.Item>
<Form.Item name="showAmount" valuePropName="checked" label="显示金额">
<Switch />
</Form.Item>
<Form.Item name="showUnitWeight" valuePropName="checked" label="显示单重">
<Switch />
</Form.Item>
<Form.Item name="showWeight" valuePropName="checked" label="显示重量">
<Switch />
</Form.Item>
</div>
);
const renderOtherFeesConfig = () => (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item name="enabled" valuePropName="checked" label="启用费用模块">
<Switch />
</Form.Item>
<Form.Item name="feeItems" label="显示费用项目">
<Checkbox.Group className="flex flex-col gap-1">
<div className="checkbox-item">
<Checkbox value="trademark"></Checkbox>
</div>
<div className="checkbox-item">
<Checkbox value="labor"></Checkbox>
</div>
<div className="checkbox-item">
<Checkbox value="paperBox"></Checkbox>
</div>
<div className="checkbox-item">
<Checkbox value="fee"></Checkbox>
</div>
<div className="checkbox-item">
<Checkbox value="codingFee"></Checkbox>
</div>
</Checkbox.Group>
</Form.Item>
<Form.Item
name="laborDetails"
valuePropName="checked"
label="人工费用细分"
>
<Switch />
</Form.Item>
</div>
);
const renderModuleConfig = () => {
if (!selectedModule) return null;
const configs = {
title: renderTitleConfig(),
dealerInfo: renderDealerInfoConfig(),
shippingInfo: (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="showShippingFrom"
valuePropName="checked"
label="显示发货地"
>
<Switch />
</Form.Item>
<Form.Item
name="showDate"
valuePropName="checked"
label="显示发货日期"
>
<Switch />
</Form.Item>
</div>
),
weightInfo: renderWeightInfoConfig(),
packingSpec: renderPackingSpecConfig(),
vehicleInfo: (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="showDriverPhone"
valuePropName="checked"
label="显示司机号码"
>
<Switch />
</Form.Item>
<Form.Item
name="showLicensePlate"
valuePropName="checked"
label="显示车牌"
>
<Switch />
</Form.Item>
<Form.Item
name="showEstimatedArrivalTime"
valuePropName="checked"
label="填写预计到仓时间"
>
<Switch />
</Form.Item>
<Form.Item
name="showFreightDebt"
valuePropName="checked"
label="显示运费欠"
>
<Switch />
</Form.Item>
<Form.Item name="showSeller" valuePropName="checked" label="填写卖货">
<Switch />
</Form.Item>
<Form.Item
name="showStrawMatDebt"
valuePropName="checked"
label="显示草帘欠"
>
<Switch />
</Form.Item>
<Form.Item
name="showRemarks"
valuePropName="checked"
label="填写备注"
>
<Switch />
</Form.Item>
<Form.Item name="freightDebtTitle" label="运费欠标题">
<Input placeholder="请输入运费欠标题" />
</Form.Item>
</div>
),
otherFees: renderOtherFeesConfig(),
totalAmount: (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="showTotalAmount"
valuePropName="checked"
label="显示合计金额"
>
<Switch />
</Form.Item>
<Form.Item name="showFarmer" valuePropName="checked" label="信息瓜农">
<Switch />
</Form.Item>
<Form.Item name="sumTitle" label="合计金额标题">
<Input placeholder="请输入合计金额标题" />
</Form.Item>
</div>
),
otherInfo: (
<div className="mb-4 pb-4 border-b border-gray-200">
<div className="font-bold mb-2 text-blue-500"></div>
<Form.Item
name="enabled"
valuePropName="checked"
label="启用其他信息"
>
<Switch />
</Form.Item>
<Form.Item name="showOrigin" valuePropName="checked" label="显示产地">
<Switch />
</Form.Item>
<Form.Item
name="showSupplier"
valuePropName="checked"
label="显示供应商"
>
<Switch />
</Form.Item>
<Form.Item
name="showDepartureTime"
valuePropName="checked"
label="显示发车时间"
>
<Switch />
</Form.Item>
<Form.Item
name="showArrivalTime"
valuePropName="checked"
label="显示预计到达"
>
<Switch />
</Form.Item>
<Form.Item
name="showProductName"
valuePropName="checked"
label="显示品名"
>
<Switch />
</Form.Item>
</div>
),
} as any;
return configs[selectedModule.type] || <div></div>;
};
if (!selectedModule) { if (!selectedModule) {
return ( return (
<Card <Card
@ -348,9 +38,25 @@ const ConfigPanel: React.FC<ConfigPanelProps> = ({
size="small" size="small"
className="bg-white rounded-lg p-4 h-full" className="bg-white rounded-lg p-4 h-full"
> >
<Form form={form} layout="horizontal" onValuesChange={handleValuesChange}> {selectedModule.config && selectedModule.schemas && (
{renderModuleConfig()} <BetaSchemaForm
</Form> key={selectedModule.id}
layoutType="Form"
layout={'horizontal'}
rowProps={{
gutter: [16, 16],
}}
colProps={{
span: 24,
}}
request={() => {
return Promise.resolve(selectedModule.config);
}}
onValuesChange={handleValuesChange}
columns={selectedModule.schemas}
submitter={false}
/>
)}
</Card> </Card>
); );
}; };

View File

@ -89,7 +89,7 @@ const DealerInfoModule: React.FC<ModuleProps> = ({
> >
<div className="col-span-1"></div> <div className="col-span-1"></div>
{config.showDealerName || config.showWatermelonGrade ? ( {config.showDealerName || config.showWatermelonGrade ? (
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.showWatermelonGrade {config.showWatermelonGrade
? `${config.dealerName}-${config.watermelonGrade}` ? `${config.dealerName}-${config.watermelonGrade}`
: config.dealerName} : config.dealerName}
@ -98,7 +98,7 @@ const DealerInfoModule: React.FC<ModuleProps> = ({
<div className="col-span-3"></div> <div className="col-span-3"></div>
)} )}
{config.showDestination || config.showVehicleNumber ? ( {config.showDestination || config.showVehicleNumber ? (
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.destination} {config.destination}
{config.vehicleNumber} {config.vehicleNumber}
</div> </div>

View File

@ -32,13 +32,6 @@ const OtherFeesModule: React.FC<ModuleProps> = ({
canMoveDown, canMoveDown,
previewMode = false, // 默认为false previewMode = false, // 默认为false
}) => { }) => {
const feeLabels = {
trademark: '商标',
labor: '人工',
paperBox: '纸箱',
fee: '费用',
codingFee: '打码费',
} as any;
return ( return (
<div <div
@ -96,9 +89,9 @@ const OtherFeesModule: React.FC<ModuleProps> = ({
<div className={'preview grid grid-cols-8 gap-0 w-full text-base'}> <div className={'preview grid grid-cols-8 gap-0 w-full text-base'}>
{config.feeItems.map((feeType: any) => ( {config.feeItems.map((feeType: any) => (
<React.Fragment key={feeType}> <React.Fragment key={feeType}>
<div className="col-span-1 flex items-center justify-center">{feeLabels[feeType]}</div> <div className="col-span-1 flex items-end justify-center">{config?.feeLabels?.[feeType] || ''}</div>
<div <div
className="col-span-1 border-b border-black flex items-center justify-center" className="col-span-1 border-b border-black flex items-end justify-center"
> >
{config[feeType]} {config[feeType]}
</div> </div>

View File

@ -1,11 +1,12 @@
import React from 'react';
import { Button, Typography } from 'antd';
import { import {
MenuOutlined,
ArrowUpOutlined,
ArrowDownOutlined, ArrowDownOutlined,
DeleteOutlined ArrowUpOutlined,
DeleteOutlined,
MenuOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Button, Typography } from 'antd';
import classNames from 'classnames';
import React from 'react';
const { Text } = Typography; const { Text } = Typography;
@ -32,14 +33,17 @@ const PackingSpecModule: React.FC<ModuleProps> = ({
canMoveDown, canMoveDown,
previewMode = false, // 默认为false previewMode = false, // 默认为false
}) => { }) => {
const columns = []; // 计算需要显示的列数
if (config.showBoxCategory) columns.push(''); const visibleColumnCount =
if (config.showBoxType) columns.push('箱号'); [
if (config.showQuantity) columns.push('数量'); config.showBoxType,
if (config.showUnitPrice) columns.push('单价'); config.showQuantity,
if (config.showAmount) columns.push('金额'); config.showUnitPrice,
if (config.showUnitWeight) columns.push('单重'); config.showAmount,
if (config.showWeight) columns.push('重量'); config.showUnitWeight,
config.showWeight,
].filter(Boolean).length + 1; // +1 是因为"规格:"列总是显示
console.log('visibleColumnCount', visibleColumnCount);
return ( return (
<div <div
@ -93,29 +97,146 @@ const PackingSpecModule: React.FC<ModuleProps> = ({
</div> </div>
</div> </div>
)} )}
<div className="py-2 flex flex-col gap-2.5 text-base">
<table className="w-full border-collapse text-lg leading-4"> <div
<thead> className={classNames(`grid w-full gap-0 text-base `, {
<tr> 'grid-cols-1': visibleColumnCount === 1,
{columns.map((col) => ( 'grid-cols-2': visibleColumnCount === 2,
<th key={col} className="font-bold p-2 text-center">{col}</th> 'grid-cols-3': visibleColumnCount === 3,
'grid-cols-4': visibleColumnCount === 4,
'grid-cols-5': visibleColumnCount === 5,
'grid-cols-6': visibleColumnCount === 6,
'grid-cols-7': visibleColumnCount === 7,
'grid-cols-8': visibleColumnCount === 8,
})}
>
<div className={`flex items-end justify-center grid-span-1`}>
</div>
</div>
<div
className={classNames(`grid w-full gap-0 text-base `, {
'grid-cols-1': visibleColumnCount === 1,
'grid-cols-2': visibleColumnCount === 2,
'grid-cols-3': visibleColumnCount === 3,
'grid-cols-4': visibleColumnCount === 4,
'grid-cols-5': visibleColumnCount === 5,
'grid-cols-6': visibleColumnCount === 6,
'grid-cols-7': visibleColumnCount === 7,
'grid-cols-8': visibleColumnCount === 8,
})}
>
{config.columns.map((column: any, index: number) => {
if (index === 0) {
return (
<div key={'title' + index} className="">
&nbsp;
</div>
);
}
if (
(column.dataIndex === 'boxType' && config.showBoxType) ||
(column.dataIndex === 'quantity' && config.showQuantity) ||
(column.dataIndex === 'unitPrice' && config.showUnitPrice) ||
(column.dataIndex === 'amount' && config.showAmount) ||
(column.dataIndex === 'unitWeight' && config.showUnitWeight) ||
(column.dataIndex === 'weight' && config.showWeight)
) {
return (
<div
key={'title' + index}
className="flex items-end justify-center"
>
{column.title}
</div>
);
}
return <></>;
})}
</div>
<div className={'table-border'}>
{config.data?.map((item: any, index: number) => (
<div
key={index}
className={classNames(`grid w-full gap-0 text-base`, {
'grid-cols-1': visibleColumnCount === 1,
'grid-cols-2': visibleColumnCount === 2,
'grid-cols-3': visibleColumnCount === 3,
'grid-cols-4': visibleColumnCount === 4,
'grid-cols-5': visibleColumnCount === 5,
'grid-cols-6': visibleColumnCount === 6,
'grid-cols-7': visibleColumnCount === 7,
'grid-cols-8': visibleColumnCount === 8,
' border-t-0': index > 0,
})}
>
<div className={'flex items-end justify-center'}>
{item.boxCategory}
</div>
{config.showBoxType && (
<div className={'flex items-end justify-center'}>
{item.boxType}
</div>
)}
{config.showQuantity && (
<div className={'flex items-end justify-center'}>
{item.quantity}
</div>
)}
{config.showUnitPrice && (
<div className={'flex items-end justify-center'}>
{item.unitPrice}
</div>
)}
{config.showAmount && (
<div className={'flex items-end justify-center'}>
{item.amount}
</div>
)}
{config.showUnitWeight && (
<div className={'flex items-end justify-center'}>
{item.unitWeight}
</div>
)}
{config.showWeight && (
<div className={'flex items-end justify-center'}>
{item.weight}
</div>
)}
</div>
))} ))}
</tr>
</thead> <div
<tbody> className={classNames(`grid w-full gap-0 text-base `, {
{config.data.map((row: any, index: any) => ( 'grid-cols-1': visibleColumnCount === 1,
<tr key={index}> 'grid-cols-2': visibleColumnCount === 2,
{config.showBoxCategory && <td className="p-2 text-center border border-black">{row.boxCategory}</td>} 'grid-cols-3': visibleColumnCount === 3,
{config.showBoxType && <td className="p-2 text-center border border-black">{row.boxType}</td>} 'grid-cols-4': visibleColumnCount === 4,
{config.showQuantity && <td className="p-2 text-center border border-black">{row.quantity}</td>} 'grid-cols-5': visibleColumnCount === 5,
{config.showUnitPrice && <td className="p-2 text-center border border-black">{row.unitPrice}</td>} 'grid-cols-6': visibleColumnCount === 6,
{config.showAmount && <td className="p-2 text-center border border-black">{row.amount}</td>} 'grid-cols-7': visibleColumnCount === 7,
{config.showUnitWeight && <td className="p-2 text-center border border-black">{row.unitWeight}</td>} 'grid-cols-8': visibleColumnCount === 8,
{config.showWeight && <td className="p-2 text-center border border-black">{row.weight}</td>} })}
</tr> >
))} <div className={`flex items-end justify-center col-span-2`}>
</tbody>
</table> </div>
<div className={`flex items-end justify-center col-span-1`}>
{config.data?.reduce(
(acc: any, cur: any) => acc + Number(cur.quantity),
0,
)}
</div>
</div>
</div> </div>
</div> </div>
); );

View File

@ -569,7 +569,6 @@ const PreviewCanvas: React.FC<PreviewCanvasProps> = ({
style={{ style={{
width: '21cm', width: '21cm',
margin: '0 auto', margin: '0 auto',
height: 'calc(100vh - 280px)',
}} }}
> >
<div ref={canvasRef} id={'preview-canvas'}> <div ref={canvasRef} id={'preview-canvas'}>

View File

@ -89,20 +89,20 @@ const ShippingInfoModule: React.FC<ModuleProps> = ({
> >
{config.showShippingFrom && ( {config.showShippingFrom && (
<> <>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.shippingFrom} {config.shippingFrom}
</div> </div>
</> </>
)} )}
{config.showDate && ( {config.showDate && (
<> <>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.date} {config.date}
</div> </div>
</> </>

View File

@ -87,8 +87,8 @@ const TitleModule: React.FC<ModuleProps> = ({
<div <div
className={'preview grid grid-cols-8 gap-0 w-full text-2xl font-bold'} className={'preview grid grid-cols-8 gap-0 w-full text-2xl font-bold'}
> >
<div className="col-span-8 flex items-center justify-center"> <div className="col-span-8 flex items-end justify-center">
{config.text} {config.title}
</div> </div>
</div> </div>
</div> </div>

View File

@ -88,23 +88,23 @@ const TotalAmountModule: React.FC<ModuleProps> = ({
<div className={'preview grid grid-cols-8 gap-0 w-full text-base'}> <div className={'preview grid grid-cols-8 gap-0 w-full text-base'}>
{config.showTotalAmount && ( {config.showTotalAmount && (
<> <>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
{config.sumTitle || '合计金额'}: {config.sumTitle || '合计金额'}:
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.amount} {config.amount}
</div> </div>
<div className="col-span-1 border-b border-black flex items-center justify-center"> <div className="col-span-1 border-b border-black flex items-end justify-center">
</div> </div>
</> </>
)} )}
{config.showFarmer && ( {config.showFarmer && (
<> <>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.farmer} {config.farmer}
</div> </div>
</> </>

View File

@ -88,71 +88,65 @@ const VehicleInfoModule: React.FC<ModuleProps> = ({
<div className={'preview grid grid-cols-8 gap-0 w-full text-base'}> <div className={'preview grid grid-cols-8 gap-0 w-full text-base'}>
{config.showDriverPhone && ( {config.showDriverPhone && (
<> <>
<div className="col-span-2 flex items-center justify-center"> <div className="col-span-2 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-6 border-b border-black flex items-center justify-center"> <div className="col-span-6 border-b border-black flex items-end justify-center">
{config.driverPhone} {config.driverPhone}
</div> </div>
</> </>
)} )}
{config.showLicensePlate && ( {config.showLicensePlate && (
<> <>
<div className="col-span-2 flex items-center justify-center"> <div className="col-span-2 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-6 border-b border-black flex items-center justify-center"> <div className="col-span-6 border-b border-black flex items-end justify-center">
{config.licensePlate} {config.licensePlate}
</div> </div>
</> </>
)} )}
{config.showEstimatedArrivalTime && ( {config.showEstimatedArrivalTime && (
<> <>
<div className="col-span-2 flex items-center justify-center"> <div className="col-span-2 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-6 border-b border-black flex items-center justify-center"> <div className="col-span-6 border-b border-black flex items-end justify-center">
{config.estimatedArrivalTime} {config.estimatedArrivalTime}
</div> </div>
</> </>
)} )}
{config.showRemarks && (
<>
<div className="col-span-2 flex items-end justify-center">
:
</div>
<div className="col-span-6 border-b border-black flex items-end justify-center">
{config.remarks}
</div>
</>
)}
{config.showFreightDebt && ( {config.showFreightDebt && (
<> <>
<div className="col-span-2 flex items-center justify-center"> <div className="col-span-2 flex items-end justify-center">
{config.freightDebtTitle || '运费欠'}: {config.freightDebtTitle || '运费欠'}:
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.freightDebt} {config.freightDebt}
</div> </div>
</> </>
)} )}
{config.showStrawMatDebt && ( {config.showStrawMatDebt && (
<> <>
<div className="col-span-2 flex items-center justify-center"> <div className="col-span-2 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.strawMatDebt} {config.strawMatDebt}
</div> </div>
</> </>
)} )}
</div> </div>
{/*<div className="py-2 text-center flex flex-col gap-2.5">*/}
{/* <div className="grid grid-cols-2 gap-2.5 text-base leading-4 my-0 mx-auto">*/}
{/* {config.showRemarks && (*/}
{/* <div className="flex items-center mb-2">*/}
{/* <span className="min-w-[120px] text-center py-0 px-1.5">*/}
{/* 备注:*/}
{/* </span>*/}
{/* <div className="flex min-w-[180px] py-0 px-2.5 items-center justify-around border-b border-black">*/}
{/* <span className="text-center inline-block">*/}
{/* {config.remarks}*/}
{/* </span>*/}
{/* </div>*/}
{/* </div>*/}
{/* )}*/}
{/* </div>*/}
{/*</div>*/}
</div> </div>
); );
}; };

View File

@ -84,104 +84,114 @@ const WeightInfoModule: React.FC<ModuleProps> = ({
</div> </div>
</div> </div>
)} )}
<div className={'preview grid grid-cols-8 gap-0 w-full text-base'}>
{config.showGrossWeight && ( {config.data?.map((item: any, index: number) => {
<> return (
<div className="col-span-1 flex items-center justify-center"> <div
: key={'data' + index}
</div> className={'preview grid grid-cols-2 gap-0 w-full text-base'}
<div className="col-span-2 border-b border-black flex items-center justify-center"> >
{config.grossWeight}
</div>
<div className="col-span-1 border-b border-black flex items-center justify-center">
</div>
</>
)}
{config.showBoxWeight && (
<>
<div className="col-span-1 flex items-center justify-center">
:
</div>
<div className="col-span-2 border-b border-black flex items-center justify-center">
{config.boxWeight}
</div>
<div className="col-span-1 border-b border-black flex items-center justify-center">
</div>
</>
)}
{config.showNetWeight && ( {config.showNetWeight && (
<> <div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.netWeight} {item.netWeight}
</div>
<div className="col-span-1 border-b border-black flex items-end justify-center">
{config.netWeightUnit === '1' ? '斤' : '公斤'}
</div>
</div>
)}
{config.showBoxWeight && (
<div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-end justify-center">
:
</div>
<div className="col-span-2 border-b border-black flex items-end justify-center">
{item.boxWeight}
</div>
<div className="col-span-1 border-b border-black flex items-end justify-center">
{config.boxWeightUnit === '1' ? '斤' : '公斤'}
</div>
</div>
)}
{config.showGrossWeight && (
<div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-end justify-center">
:
</div>
<div className="col-span-2 border-b border-black flex items-end justify-center">
{item.grossWeight}
</div>
<div className="col-span-1 border-b border-black flex items-end justify-center">
{config.grossWeightUnit === '1' ? '斤' : '公斤'}
</div> </div>
<div className="col-span-1 border-b border-black flex items-center justify-center">
</div> </div>
</>
)} )}
{config.showUnitPrice && ( {config.showUnitPrice && (
<> <div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.unitPrice} {item.unitPrice}
</div>
<div className="col-span-1 border-b border-black flex items-end justify-center">
{config.unitPriceUnit === '1' ? '元/斤' : '元/公斤'}
</div> </div>
<div className="col-span-1 border-b border-black flex items-center justify-center">
/
</div> </div>
</>
)} )}
{config.showAmount && ( {config.showAmount && (
<> <div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.amount} {item.amount}
</div> </div>
<div className="col-span-1 border-b border-black flex items-center justify-center"> <div className="col-span-1 border-b border-black flex items-end justify-center">
</div> </div>
</> </div>
)} )}
{config.showGrade && ( {config.showGrade && (
<> <div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.grade} {item.grade}
</div>
</div> </div>
</>
)} )}
</div>
);
})}
<div className={'preview grid grid-cols-2 gap-0 w-full text-base'}>
{config.showAccountCompany && ( {config.showAccountCompany && (
<> <div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-3 border-b border-black flex items-center justify-center"> <div className="col-span-3 border-b border-black flex items-end justify-center">
{config.accountCompany} {config.accountCompany}
</div> </div>
</> </div>
)} )}
{config.showSumAmount && ( {config.showSumAmount && (
<> <div className={'col-span-1 grid grid-cols-4'}>
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-1 flex items-end justify-center">
: :
</div> </div>
<div className="col-span-2 border-b border-black flex items-center justify-center"> <div className="col-span-2 border-b border-black flex items-end justify-center">
{config.sumAmount} {config.sumAmount}
</div> </div>
<div className="col-span-1 border-b border-black flex items-center justify-center"> <div className="col-span-1 border-b border-black flex items-end justify-center">
</div> </div>
</> </div>
)} )}
</div> </div>
</div> </div>

View File

@ -50,10 +50,27 @@ body::-webkit-scrollbar {
.preview { .preview {
width: 19cm; width: 19cm;
table-layout: fixed;
td { div {
text-align: center; height: 1.1cm;
vertical-align: middle;
} }
} }
.table-border {
border: 2px solid #000;
}
.table-border > div {
border-bottom: 1px solid #000;
}
.table-border > div > div {
border-right: 1px solid #000;
}
.table-border > div > div:last-child {
border-right: none;
}
.table-border > div:last-child {
border-bottom: none;
}

View File

@ -671,6 +671,17 @@ export default {
}, },
dealer: { dealer: {
module: {
title: '标题模块',
dealerInfo: '经销商信息模块',
shippingInfo: '发货地信息模块',
weightInfo: '重量金额信息模块',
packingSpec: '装箱规格模块',
vehicleInfo: '车辆信息模块',
otherFees: '其他费用模块',
totalAmount: '合计金额模块',
otherInfo: '其他信息模块',
},
column: { column: {
shortName: '经销商简称', shortName: '经销商简称',
dealerPaymentAccountVOList: '付款账户', dealerPaymentAccountVOList: '付款账户',
@ -680,11 +691,11 @@ export default {
'enableShare.tooltip': '是否开启诚信志远分成', 'enableShare.tooltip': '是否开启诚信志远分成',
shareRatio: '分成比例', shareRatio: '分成比例',
shareRatioTitle: '分成', shareRatioTitle: '分成',
'freightCostFlag': '运费成本', freightCostFlag: '运费成本',
'freightCostFlag.tooltip': '运费是否作为成本', 'freightCostFlag.tooltip': '运费是否作为成本',
'strawMatCostFlag': '草帘成本', strawMatCostFlag: '草帘成本',
'strawMatCostFlag.tooltip': '草帘是否作为成本', 'strawMatCostFlag.tooltip': '草帘是否作为成本',
'includePackingFlag': '含包装费', includePackingFlag: '含包装费',
'includePackingFlag.tooltip': '发货单合计金额是否含包装费', 'includePackingFlag.tooltip': '发货单合计金额是否含包装费',
documentTypes: '单据类型', documentTypes: '单据类型',
remark: '备注', remark: '备注',