Commit ebe93517 authored by 前端-钟卫鹏's avatar 前端-钟卫鹏

feat: 添加新增物流单页面

parent 9a22d812
......@@ -82,9 +82,7 @@ registerValidationRules({
// 全局注册card布局组件
registerVirtualBox("MellowCard", ({ children, schema }) => {
const props = schema['x-component-props']
console.log(props, 10086)
return (
<FormItemCard {...props}>
......
......@@ -485,6 +485,12 @@ export default {
'saleOrder.dexiaoshoufahuo': 'The sales invoice',
'saleOrder.xuanzeleixin': 'selective type',
'saleOrder.xiaochengxu': 'mini program',
'saleOrder.xinzengxiaoshoufahuodan': 'New sales invoices',
'saleOrder.bianjixiaoshoufahuodan': 'Edit sales invoices',
'saleOrder.baocun': 'save',
'saleOrder.xuanze': 'select',
'saleOrder.xiangguanxinxi': 'relevant information',
// Requisitions
......
......@@ -323,4 +323,6 @@ export default {
'transaction_components.yiwanchengzhifu': 'Payment completed',
'transaction_components.weiwanchengzhifu': 'Outstanding payment',
'transaction_components.fukuanqianqingbuyaoguanbi': 'Please do not close this window until payment is completed. After completing the payment, please click the button below according to your situation.',
'transaction_components.jianhangzhifuqueren': 'CCB payment confirmation',
'transaction_components.jianhangzhifu': 'CCB',
}
......@@ -483,6 +483,11 @@ export default {
'saleOrder.dexiaoshoufahuo': '의 판매 송장',
'saleOrder.xuanzeleixin': '선택 형식:',
'saleOrder.xiaochengxu': '애플릿',
'saleOrder.xinzengxiaoshoufahuodan': '신규 판매 인보이스',
'saleOrder.bianjixiaoshoufahuodan': '판매 인보이스 편집',
'saleOrder.baocun': '간수하다',
'saleOrder.xuanze': '고르다',
'saleOrder.xiangguanxinxi': '관련 정보',
// 请购单
......
......@@ -323,4 +323,6 @@ export default {
'transaction_components.yiwanchengzhifu': '지불이 완료되다',
'transaction_components.weiwanchengzhifu': '미지급',
'transaction_components.fukuanqianqingbuyaoguanbi': '결제가 완료되기 전에는이 창을 닫지 마십시오. 결제 완료 후 귀하의 상황에 맞게 아래 단추를 클릭해 주십시오. ',
'transaction_components.jianhangzhifuqueren': '건설은행의 지불 확인',
'transaction_components.jianhangzhifu': '건설 은행',
}
......@@ -483,6 +483,12 @@ export default {
'saleOrder.dexiaoshoufahuo': '的销售发货单',
'saleOrder.xuanzeleixin': '选择类型:',
'saleOrder.xiaochengxu': '小程序',
'saleOrder.xinzengxiaoshoufahuodan': '新增销售发货单',
'saleOrder.bianjixiaoshoufahuodan': '编辑销售发货单',
'saleOrder.baocun': '保存',
'saleOrder.xuanze': '选择',
'saleOrder.danjumingxi': '单据明细',
'saleOrder.xiangguanxinxi': '相关信息',
// 请购单
......
......@@ -323,4 +323,6 @@ export default {
'transaction_components.yiwanchengzhifu': '已完成支付',
'transaction_components.weiwanchengzhifu': '未完成支付',
'transaction_components.fukuanqianqingbuyaoguanbi': '付款完成前请不要关闭此窗口。完成付款后请根据您的情况点击下面的按钮。',
'transaction_components.jianhangzhifuqueren': '建行支付确认',
'transaction_components.jianhangzhifu': '建行支付',
}
......@@ -38,7 +38,7 @@ const OrderPayModal: React.FC<OrderPayModalProps> = (props) => {
const [formCode] = Form.useForm()
const [visible, setVisible] = useState(false)
const [checked, setChecked] = useState<any>({})
const [current, setCurrent] = useState(0) // 0选择方式 1线下支付方式 2授信支付 3余额支付 4微信支付 5货到付款 6支付宝 9账期 8月结 99通联 1000清除
const [current, setCurrent] = useState(0) // 0选择方式 1线下支付方式 2授信支付 3余额支付 4微信支付(通联微信) 5货到付款 6支付宝(通联支付宝) 9账期 8月结 99通联 100建行 1000清除
const [tonglian, setTonglian] = useState<boolean>(false) // 是否通联标识
const [payStep, setPayStep] = useState(0) // 支付模态框的步骤 0选方式 1下一步的具体操作 2输入支付密码 3验证码确认支付
const mobilePayFlag = useRef(0) // 用于判断移动支付类型 4微信6支付宝
......@@ -286,6 +286,12 @@ const OrderPayModal: React.FC<OrderPayModalProps> = (props) => {
mobilePayFlag.current = 0
setCurrent(99)
setPayStep(1)
} else if(checked.id === 16) {
console.log('选择了建行【b2b】模式')
setTonglian(false)
mobilePayFlag.current = 0
setCurrent(100)
setPayStep(1)
}
} else {
message.error(intl.formatMessage({id: 'transaction_components.qingxianxuanzezhifufangshi'}))
......@@ -337,6 +343,9 @@ const OrderPayModal: React.FC<OrderPayModalProps> = (props) => {
} else if(current === 99) {
// 提交通联支付
handleSubmitPay()
} else if(current === 100) {
// 提交建行支付
handleSubmitPay()
}
confirm && confirm()
......@@ -397,6 +406,13 @@ const OrderPayModal: React.FC<OrderPayModalProps> = (props) => {
setVisible(false)
setPayResultVisible(true)
window.open(res.data.codeUrl, '_blank')
} else if(checked.id === 16) {
console.log(current, checked, '建行b2b跳转')
console.log(res.data)
// setCurrent(1000)
// setVisible(false)
// setPayResultVisible(true)
// window.open(res.data.codeUrl, '_blank')
} else {
history.goBack()
}
......@@ -862,6 +878,37 @@ const OrderPayModal: React.FC<OrderPayModalProps> = (props) => {
</Form>
</div>
}
{/* 建行 B2B支付 */}
{
current === 100 &&
<div>
<p style={{fontWeight: "bold"}}>{intl.formatMessage({id: 'transaction_components.jianhangzhifuqueren'})}</p>
<p>
<span className={style.title}>
{intl.formatMessage({id: 'transaction_components.zhifufangshi'})}
</span>
<span className={style.amount}>
{intl.formatMessage({id: 'transaction_components.jianhangzhifu'})}
</span>
</p>
<p>
<span className={style.title}>
{intl.formatMessage({id: 'transaction_components.zhifuqudao'})}
</span>
<span className={style.amount}>
{checked?.channel}
</span>
</p>
<p>
<span className={style.title}>
{intl.formatMessage({id: 'transaction_components.zhifujineyuan'})}
</span>
<span className={cx(style.amount, style.amount2)}>
{Number(paymentAmount).toFixed(2)}
</span>
</p>
</div>
}
</Modal>
<Modal
title={intl.formatMessage({id: 'transaction_components.zhifu'})}
......
import { postMemberManageLowerProviderPage } from "@/services/MemberV2Api"
import { getProductCommodityCommonGetCommodityListByBuyer, getProductGoodsGetGoodsList } from "@/services/ProductV2Api"
export const fetchOrderApi = {
/** 弹窗获取商品列表 */
async getProductList(params) {
const { data } = await getProductCommodityCommonGetCommodityListByBuyer(params, { useCache: true, ttl: 10 * 1000 })
return data
},
/** 获取下架服务提供者会员列表 */
async getMemberListByMemberName(params) {
const { data } = await postMemberManageLowerProviderPage({...params}, { ctlType: 'none' })
return data
},
/** 请购单物料 获取商品货品列表 */
async getPurchaseRequesitionMaterielList(params) {
const { data } = await getProductGoodsGetGoodsList(params)
return data
},
}
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { fetchOrderApi } from '../../apis'
import { FormEffectHooks, ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { DELIVERY_TYPE, OrderModalType } from '@/constants/order'
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch'
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { addOrderModalSchema } from '@/components/ModalTable/schema'
import Search from '@/components/NiceForm/components/Search'
import SearchSelect from '@/components/NiceForm/components/SearchSelect';
import Submit from '@/components/NiceForm/components/Submit';
import DateSelect from '@/components/NiceForm/components/DateSelect';
import { searchBrandOptionEffect, searchCustomerCategoryOptionEffect } from '../../effects'
import CustomCategorySearch from '@/components/NiceForm/components/CustomCategorySearch'
import CustomInputSearch from '@/components/NiceForm/components/CustomInputSearch'
import { getLogisticsShipperAddressGet } from '@/services/LogisticsV2Api'
import { getIntl } from 'umi'
export interface ProductModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions | ISchemaFormAsyncActions,
currentRef?: any,
sectionProps: any,
confirmModal?()
}
export const productColumns: any[] = [
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.id'}),
dataIndex: 'id',
align: 'center',
key: 'id',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.name'}),
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.customerCategoryName'}),
dataIndex: 'customerCategoryName',
align: 'center',
key: 'customerCategoryName',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.brandName'}),
dataIndex: 'brandName',
align: 'center',
key: 'brandName',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.unitName'}),
dataIndex: 'unitName',
align: 'center',
key: 'unitName'
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.stockCount'}),
dataIndex: 'stockCount',
align: 'center',
key: 'stockCount'
},
]
// 下单类型->商城类型映射
const orderProductShopTypeMaps = {
[OrderModalType.PURCHASE_ORDER]: 1,
[OrderModalType.CHANNEL_DIRECT_PURCHASE_ORDER]: 3,
[OrderModalType.CHANNEL_EXISTING_PURCHASE_ORDER]: 4
}
export const filterProductDataById = (data, targetData) => {
return targetData.reduce(async (prev: any[], next) => {
const { logistics } = next
// 由于自选商品和进货单商品字段不一致,需手动同步
next.brand = next.brand || next.brandName
next.category = next.category || next.customerCategoryName
next.unit = next.unit || next.unitName
next.productName = next.productName || next.name
next.deliverType = next.logistics.sendAddress // 保证和详情编辑字段一致
if (logistics.deliveryType === 2 && logistics.sendAddress) {
const { code, data } = await getLogisticsShipperAddressGet({
id: logistics.sendAddress
}, { ttl: 60 * 1000, useCache: true })
logistics.render = {...data, deliveryType: logistics.deliveryType}
} else {
logistics.render = DELIVERY_TYPE[logistics.deliveryType]
}
// 配送方式外置, 用于接口字段冗余
next.deliveryType = logistics.deliveryType
// id 存在集合中, 采用target中的数据, 否则采用data中的数据
const findResult = data.find(v => v.id === next.id)
// 由于迭代时,会出现promise的 已完成状态, 需转换一下,实现异步转同步化
if (!Array.isArray(prev)) {
prev = await prev
}
if (findResult) {
// 已经选中过这一项, 则需要采用原有的商品列表
prev.push(findResult)
} else {
prev.push(next)
}
return prev
}, [])
}
const ProductModalTable:React.FC<ProductModalTableProps> = (props) => {
const { type = 'checkbox', schemaAction, confirmModal, currentRef, sectionProps, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = sectionProps
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const handleConfirmProduct = async () => {
const newData = rowSelectionCtl.selectRow.map(v => {
v.orderMode = schemaAction.getFieldValue('orderMode')
v.shopId = schemaAction.getFieldValue('shopId')
v.buyerMemberId = schemaAction.getFieldValue('buyerMemberId')
v.buyerRoleId = schemaAction.getFieldValue('buyerRoleId')
return v
})
schemaAction.setFieldValue('products', await filterProductDataById([], newData))
confirmModal && confirmModal()
setVisible(false)
}
const fetchProductList = (values) => {
const modelType = schemaAction.getFieldValue('orderMode')
const buyerMembersId = schemaAction.getFieldValue('buyerMemberId')
const shopId = schemaAction.getFieldValue('shopId')
const params = {
...values,
shopType: orderProductShopTypeMaps[modelType],
environment: 1,
memberId: buyerMembersId,
priceTypeList: [1],
shopId: schemaAction.getFieldValue('shopId')
}
return fetchOrderApi.getProductList(params)
}
return (
<ModalTable
modalTitle={getIntl().formatMessage({id: 'purchaseOrder.orderCollect.productModalTable.title'})}
width={900}
columns={productColumns}
visible={visible}
confirm={handleConfirmProduct}
cancel={() => setVisible(false)}
fetchTableData={fetchProductList}
rowSelection={rowSelection}
resetModal={{destroyOnClose: true, forceRender: true}}
modalType='none'
tableProps={{
rowKey: 'id',
onRow: (record) => ({
onClick: () => {
rowSelectionCtl.appendSelectRow(record);
rowSelectionCtl.appendSelectRowKeys(record.id);
},
})
}}
formilyProps={{
ctx: {
schema: addOrderModalSchema,
components: { ModalSearch: Search, SearchSelect, Submit, DateSelect, CustomCategorySearch, CustomInputSearch },
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
FormEffectHooks.onFieldChange$('customerCategoryId').subscribe(state => {
searchCustomerCategoryOptionEffect(schemaAction, actions, 'customerCategoryId')
})
FormEffectHooks.onFieldChange$('brandId').subscribe(state => {
searchBrandOptionEffect(schemaAction, actions, 'brandId')
})
}
}
}}
{...restProps}
/>
)
}
ProductModalTable.defaultProps = {}
export default ProductModalTable
.customeFormItem {
margin: 0;
position: 'relative';
.ant-form-item-control {
.ant-form-item-explain-error {
position: absolute;
left: 0;
bottom: 0;
}
}
}
import React, { useRef, useContext } from 'react'
import { Form, Input } from 'antd';
import { useIntl } from 'umi';
export interface ProductTableCellProps {
title: React.ReactNode;
editable: boolean;
children: React.ReactNode;
dataIndex: string;
record: any;
handleSave: (record: any) => Promise<any>;
forceEdit: boolean,
formItem: string,
formItemProps: any
}
const EditableContext = React.createContext<any>({});
export const ProductEditableRow: React.FC<any> = ({...props }) => {
const [form] = Form.useForm();
const ctx = {
form
}
return (
<Form form={form} component={false}>
<EditableContext.Provider value={ctx}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
export const ProductTableCell:React.FC<ProductTableCellProps> = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
forceEdit,
formItem,
formItemProps={},
...restProps
}) => {
const formItemRef = useRef<any>();
const { form } = useContext(EditableContext);
const intl = useIntl()
const save = async () => {
try {
const values = await form.validateFields();
values.purchaseCount = Number(values.purchaseCount) || 0
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
const chooseFormItem = (type, v) => {
switch(type) {
case 'input': {
return <Input
style={{width: 140}}
type='number'
ref={formItemRef}
onChange={save}
{...formItemProps}
id={dataIndex + record.id}
className="purchase_amount_input"
/>
}
}
}
// 校验最小起订
const validatorNumber = (rule, value, callback) => {
try {
let _value = Number(value)
if(isNaN(_value) || _value < Number(record["minOrder"])) {
throw new Error(intl.formatMessage({id: 'purchaseOrder.orderCollect.productTableCell.validator3'}).replaceAll('x', record["minOrder"]))
}
if(_value > Number.MAX_SAFE_INTEGER) {
throw new Error(intl.formatMessage({id: 'purchaseOrder.orderCollect.productTableCell.validator1'}))
}
callback()
} catch (err) {
callback(err)
}
}
let childNode = children;
if (editable) {
childNode =
<Form.Item
className="customFormItem"
name={dataIndex}
initialValue={record[dataIndex] || ''}
rules={[
{
required: true,
message: intl.formatMessage({id: 'purchaseOrder.orderCollect.productTableCell.validator4'}).replaceAll('x', `${title}`),
},
{
pattern: /^\d+(\.\d{1,3})?$/,
message: intl.formatMessage({id: 'purchaseOrder.orderCollect.productTableCell.validator2'}),
},
{
validator: validatorNumber
}
]}
>
{chooseFormItem(formItem, record[dataIndex] || '')}
</Form.Item>
}
return <td {...restProps}>{childNode}</td>;
}
ProductTableCell.defaultProps = {}
export default ProductTableCell
import { AddressPop } from "@/pages/transaction/components/addressPop"
import { Row } from "antd"
import { getIntl } from "umi"
// 简单控制价格区间的组件
export const PriceComp = (props) => {
const { priceSection = {} } = props
const priceTransKeys = Object.keys(priceSection || {})
// 出现0-0 表示没有单价区间范围
if (priceTransKeys.length === 1 && priceTransKeys[0] === '0-0') {
return <span style={{color: '#E63F3B'}}>{'¥' + priceSection[priceTransKeys[0]]}</span>
}
return <div>
{
priceTransKeys.map(v => <Row key={v} justify='space-between'>
<span style={{color: '#606266'}}>{v.replace('-', '~')}:</span>
<span style={{color: '#E63F3B', marginLeft: 40}}>{priceSection[v]}</span>
</Row>)
}
</div>
}
/**代客下单 初始值转换 */
export const procurmentRenderInit = (initValue: any) => {
return {
...initValue.requirement,
vendorMemberId: initValue.vendorMemberId,
vendorMemberName: initValue.vendorMemberName,
vendorRoleId: initValue.vendorRoleId,
product: initValue.product,
deliveryAddresId: initValue.consignee.consigneeId,
hasInvoice: initValue.hasInvoice,
orderId: initValue.orderId,
orderKind: initValue.orderKind,
orderMode: initValue.orderMode,
orderModeName: initValue.orderModeName,
type: initValue.orderTypeName,
digest: initValue.digest,
deliverDate: initValue.consignee.deliverDate,
theInvoiceId: initValue.invoice?.invoiceId || null,
quoteNo: initValue.quoteNo,
quoteId: initValue.quoteId,
shopId: initValue.shopId,
payments: initValue.payments,
}
}
/** 代客下单 回显商品字段转换 */
export const procurementRenderField = (data) => {
const _orderProductRequests = data.product.products
return _orderProductRequests.map(item => {
return {
...item,
commodityId: item.productId,
productId: item.skuId,
productName: item.name,
logistics: item.deliverType,
deliveryType: item.deliverType,
unitPrice: item.price,
purchaseCount: item.quantity,
taxInclusive: item.tax,
money: item.amount,
imgUrl: item.logo,
stockCount: item.stock,
// 冗余memberId memberRoleId查询自提地址使用
memberId: data.vendorMemberId,
memberRoleId: data.vendorRoleId,
// 冗余运费
freight: data.product.freight,
// 冗余shopId orderMode查询支付方式使用
shopId: data.shopId,
orderMode: data.orderMode,
// 转换上游字段
upperMemberId: item.supplyMemberId,
upperMemberName: item.supplyMemberName,
upperMemberRoleId: item.supplyRoleId,
}
})
}
/** 代客下单提交 字段转换 */
export const procurementProcessField = (value) => {
value.products = value.products.map(item => {
return {
...item,
productId: item.commodityId,
skuId: item.id,
logo: item.mainPic,
quantity: item.purchaseCount,
logisticsTemplateId: item.logistics.templateId,
weight: item.logistics.weight,
stock: item.stockCount,
discount: item.isMemberPrice ? item.memberPrice : 1, // 字段需求 无折扣为1
price: item.isMemberPrice ? Number((item.money / item.purchaseCount / item.memberPrice).toFixed(2)) : Number((item.money / item.purchaseCount).toFixed(2)),
tax: item.taxRate > 0,
vendorMemberId: item.memberId,
vendorRoleId: item.memberRoleId,
vendorMemberName: item.memberName,
// 上游字段
supplyMemberId: item.upperMemberId,
supplyRoleId: item.upperMemberRoleId,
supplyMemberName: item.upperMemberName,
}
})
return value
}
// 商品列表
export const productInfoColumns: any[] = [
{
title: 'ID',
dataIndex: 'id',
align: 'center',
key: 'id',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.productName'}),
dataIndex: 'productName',
align: 'center',
key: 'productName',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.category'}),
dataIndex: 'category',
align: 'center',
key: 'category',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.brand'}),
dataIndex: 'brand',
align: 'center',
key: 'brand',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.unit'}),
dataIndex: 'unit',
align: 'center',
key: 'unit',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.unitPrice'}),
dataIndex: 'unitPrice',
align: 'left',
key: 'unitPrice',
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.memberPrice'}),
dataIndex: 'memberPrice',
key: 'memberPrice',
render: (text, record) => record.isMemberPrice && text ? text * 100 + '%' : null
},
// {
// title: '库存',
// dataIndex: 'stockCount',
// align: 'center',
// key: 'stockCount',
// },
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.purchaseCount'}),
dataIndex: 'purchaseCount',
align: 'center',
key: 'purchaseCount',
formItem: 'input',
editable: true,
width: 140
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.taxInclusive'}),
dataIndex: 'taxInclusive',
align: 'center',
key: 'taxInclusive',
render: (t, r) => r.taxRate ? getIntl().formatMessage({id: 'purchaseOrder.yes'}) : getIntl().formatMessage({id: 'purchaseOrder.no'}),
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.taxRate'}),
dataIndex: 'taxRate',
align: 'center',
key: 'taxRate',
render: (t, r) => t ? `${t}%` : null
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.money'}),
dataIndex: 'money',
align: 'center',
key: 'money',
},
// 接口调用
{
title: getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.deliveryType'}),
dataIndex: 'deliveryType',
align: 'center',
key: 'deliveryType',
render: (t, r) => {
if(t === 1)
return getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.deliveryType1'})
else if(t === 2)
return <AddressPop pickInfo={r.logistics.render}>{getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.deliveryType2'})}</AddressPop>
else if(t === 3)
return getIntl().formatMessage({id: 'purchaseOrder.orderCollect.constant.deliveryType3'})
}
},
{
title: getIntl().formatMessage({id: 'purchaseOrder.operation'}),
dataIndex: 'ctl',
align: 'center',
key: 'ctl',
},
]
import { FormEffectHooks, ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { getProductCustomerGetCustomerCategoryTree, getProductSelectGetSelectBrand } from '@/services/ProductV2Api';
import { PageStatus, usePageStatus } from '@/hooks/usePageStatus';
import { useLinkageUtils } from '@/utils/formEffectUtils';
export const useMaterialTableChangeForAmount = (ctx: ISchemaFormActions | ISchemaFormAsyncActions, update) => {
FormEffectHooks.onFieldValueChange$('products').subscribe(state => {
// 强制渲染一次, 用于触发金额总数
update()
})
}
export const useInitShowField = () => {
const { pageStatus } = usePageStatus()
const utils = useLinkageUtils()
FormEffectHooks.onFormInit$().subscribe(() => {
// 初始化一些详情数据
// if (pageStatus === PageStatus.ADD) {
// utils.hide('orderNo')
// utils.hide('createTime')
// }
})
}
// 高级筛选schema中用于输入搜索品牌的Effect
export const searchBrandOptionEffect = (context: any, fieldName: string) => {
context.getFieldState(fieldName, state => {
getProductSelectGetSelectBrand({ name: state.props['x-component-props'].searchValue }).then(res => {
context.setFieldState(fieldName, state => {
state.props['x-component-props'].dataoption = res.data
})
})
})
}
// 高级筛选schema中用于输入搜索商品品类的Effect
export const searchCustomerCategoryOptionEffect = (context: any, fieldName: string) => {
context.getFieldState(fieldName, state => {
getProductCustomerGetCustomerCategoryTree().then(res => {
context.setFieldState(fieldName, state => {
state.props['x-component-props'].dataoption = res.data
})
})
})
}
import React, { useState, useEffect } from 'react'
import { history, useIntl } from 'umi'
import { usePageStatus } from '@/hooks/usePageStatus'
import { Button, Col, message, Row } from 'antd'
import { createFormActions, registerVirtualBox, useFormSpy } from '@formily/antd'
import { SaveOutlined } from '@ant-design/icons'
import NiceForm from '@/components/NiceForm'
import { increaseSchema } from './schema'
import { useMaterialTableChangeForAmount } from './effects'
import { procurementProcessField, procurementRenderField, procurmentRenderInit } from './constant'
import { useUpdate } from '@umijs/hooks'
import { help } from '../../common'
import styled from 'styled-components'
import FormDetailHeader from '@/components/FormDetailHeader'
import FormDetailWrapper from '@/components/FormDetailWrapper'
import { FormDetailContext } from '@/formSchema/context'
import { useProductTable } from './model/useProductTable'
import { useFormDetail } from '@/formSchema/effects/useFormDetail'
import { getPurchaseRequisitionDetail, postPurchaseRequisitionCreate, postPurchaseRequisitionUpdate } from '@/services/PurchaseV2Api'
import ProductModalTable from './components/productModalTable'
const addSchemaAction = createFormActions()
const RowStyle = styled(props => <Row style={{marginTop: 12, justifyContent: "flex-end"}} justify='end' {...props}>
{props.children}
</Row>)`
.ant-col {
text-align: center
}
.ant-col div {
margin-bottom: 12px;
}
`
// 总计金额联动框
export const MoneyTotalBox = registerVirtualBox('moneyTotalBox', () => {
const intl = useIntl()
const { form } = useFormSpy({ selector: [['onFieldValueChange', 'products']], reducer: v => v })
const data = form.getFieldValue('products')
const sum = data.reduce((prev, next) => (prev*1000 + (next.amount || 0)*1000)/1000, 0)
const total = data.reduce((prev, next) => (prev*1000 + (next.quantity || 0)*1000)/1000, 0)
return <RowStyle>
<Col span={2}>
<div>{intl.formatMessage({ id: 'purchaseRequisition.shuliangheji', defaultMessage: '数量合计' })}</div>
<div>{total.toFixed(2)}</div>
</Col>
<Col span={2}>
<div>{intl.formatMessage({ id: 'purchaseRequisition.jinezongji', defaultMessage: '金额总计' })}</div>
<div>{`${intl.formatMessage({id: 'commodity.products.directChannel.columns.currency'})}${(sum).toFixed(2)}`}</div>
</Col>
</RowStyle>
})
/** 新增物流单 */
const AddLogisticsOrder:React.FC<{}> = () => {
const [formLoading, setFormLoading] = useState(false)
const [btnLoading, setBtnLoading] = useState(false)
const update = useUpdate()
const { id } = usePageStatus()
const [initFormValue, setInitFormValue] = useState<any>({})
const { formContext } = useFormDetail()
const intl = useIntl()
useEffect(() => {
if (id) {
setFormLoading(true)
getPurchaseRequisitionDetail({ id }).then(res => {
const { data } = res
const _orderProductRequests = procurementRenderField(data)
setInitFormValue(() => procurmentRenderInit(data))
setTimeout(() => {
addSchemaAction.setFieldValue('products', _orderProductRequests)
}, 1000)
setFormLoading(false)
})
}
}, [])
const handleSubmit = async (value) => {
try {
let fnResult = null
// 新增订单/编辑订单
const params = { ...value }
console.log(value)
if(formContext.innerFormErrors) {
throw new Error(intl.formatMessage({ id: 'purchaseRequisition.qingwanshandingdan', defaultMessage: '请完善订单物料数据' }))
}
// 校验采购数量
const judgementByCount = params.products?.length && params.products.map(item => {
if(item.quantity){
return true
} else {
return false
}
})
if(!judgementByCount || judgementByCount.includes(false)){
throw new Error(intl.formatMessage({ id: 'purchaseRequisition.qingtianxieshangpin', defaultMessage: '请填写商品采购数量' }))
}
setBtnLoading(true)
const _params = procurementProcessField(params)
console.log(_params)
if(id) {
fnResult = await postPurchaseRequisitionUpdate({..._params, id})
} else {
fnResult = await postPurchaseRequisitionCreate(_params)
}
if (fnResult.code === 1000) {
setTimeout(() => {
history.push("/memberCenter/procurementAbility/purchaseRequisition/readyAddBill")
}, 1000)
} else {
setBtnLoading(false)
}
} catch (error) {
setBtnLoading(false)
error?.message && message.error(error.message)
console.log(error)
}
}
// 订单商品
const { productAddButton, productRef, productColumns, productComponents, ...sectionProps } = useProductTable(addSchemaAction)
const providerValue = {
schemaActions: addSchemaAction,
formContext,
}
return (<div>
<FormDetailContext.Provider value={providerValue}>
<FormDetailHeader
title={id ? intl.formatMessage({ id: 'saleOrder.bianjixiaoshoufahuodan', defaultMessage: '编辑销售发货单' }) : intl.formatMessage({ id: 'saleOrder.xinzengxiaoshoufahuodan', defaultMessage: '新增销售发货单' })}
schema={increaseSchema}
extraRight={[
<Button key="1" onClick={() => addSchemaAction.submit()} loading={btnLoading} type="primary" icon={<SaveOutlined />}>
{intl.formatMessage({ id: 'saleOrder.baocun', defaultMessage: '保存' })}
</Button>,
]}
/>
<FormDetailWrapper>
<NiceForm
loading={formLoading}
previewPlaceholder=' '
value={initFormValue}
actions={addSchemaAction}
schema={increaseSchema}
onSubmit={handleSubmit}
effects={($, ctx) => {
$('onFormMount').subscribe(() => { })
// 物料信息的改动 渲染总额
useMaterialTableChangeForAmount(ctx, update)
// 注入表单完成进度
formContext.useAttachmentChangeForContext(ctx)
}}
expressionScope={{
productColumns,
productComponents,
productAddButton,
help,
}}
/>
</FormDetailWrapper>
</FormDetailContext.Provider>
<ProductModalTable currentRef={productRef} schemaAction={addSchemaAction} sectionProps={sectionProps} forceRender/>
</div>)
}
AddLogisticsOrder.defaultProps = {}
export default AddLogisticsOrder
import React, { useState, useEffect } from 'react'
import { OrderModalType } from '@/constants/order'
import { useLocation, history } from 'umi'
import { ISchemaFormActions } from '@formily/antd'
interface DetailOrderLocationState {
// 进货单商品列表
productList?: any[],
// 下单模式
modelType?: OrderModalType
}
interface DetailOptionsProps {
addSchemaAction: ISchemaFormActions
}
export const useDetailOrder = (options: DetailOptionsProps) => {
const { addSchemaAction } = options
const locationState = useLocation<DetailOrderLocationState>().state || {}
const { productList } = locationState
const { modelType } = history.location.query
// 是否显示选择商品按钮
const [showProBtn, setShowProBtn] = useState(false)
// 是否显示供应会员字段
const [showMemberType, setShowMemberType] = useState(false)
const [visibleMember, setVisibleMember] = useState(false)
// 商品列表, 如果路由state中 带有productList, 说明是进货单下单, 需要回显进货单商品数据
const [proList, setProList] = useState<any[]>(() => productList || [])
// 回显数据写在这
useEffect(() => {
// 页面中有传入下单模式, 需要手动回显数据
if (modelType) {
addSchemaAction.setFieldValue('orderMode', parseInt(modelType))
}
// 在有传入商品列表时 需手动回显
if (proList.length > 0) {
addSchemaAction.setFieldValue('orderProductRequests', proList)
addSchemaAction.setFieldValue('orderThe', proList[0].name)
}
}, [modelType, productList])
return {
showProBtn,
setShowProBtn,
showMemberType,
setShowMemberType,
proList,
modelType,
visibleMember,
setVisibleMember
}
}
import { useState } from 'react'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
export const useModalTable = (options?) => {
const [visible, setVisible] = useState(false)
const [rowSelection, rowSelectionCtl] = useRowSelectionTable(options)
return {
visible,
setVisible,
rowSelection,
rowSelectionCtl
}
}
\ No newline at end of file
import { useRef, useState } from 'react'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { Button, message } from 'antd';
import { PriceComp, productInfoColumns } from '../constant';
import ProductTableCell, { ProductEditableRow } from '../components/productTableCell';
import { useModalTable } from './useModalTable';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import { useIntl } from 'umi';
const { pageStatus } = usePageStatus()
// 对象按key排序(运用于商城传过来的阶梯价格排序)
export const sortByKey = (params) => {
let keys = Object.keys(params).sort((x,y)=> parseInt(x) - parseInt(y));
let newParams = {};
keys.forEach((key) => {
newParams[key] = params[key];
});
return newParams;
}
export const getUnitPriceTotal = (record) => {
const purchaseCount = Number(record['purchaseCount']) || 0
// fix 当没有传递unitPrice字段时 自动容错, 单价显示为0
// fix 编辑订单取price
record.unitPrice = pageStatus === PageStatus.EDIT ? record.price : record.unitPrice || record.price || 0
if (typeof record.unitPrice === 'number') {
return record.isMemberPrice ?
Number((record.unitPrice * purchaseCount * record.memberPrice).toFixed(2))
:
Number((record.unitPrice * purchaseCount).toFixed(2))
}
if(record.unitPrice) {
record.unitPrice = sortByKey(record.unitPrice)
}
// fix 当没有传递unitPrice字段时 但有price字段时 补全unitPrice字段
if(record.price && JSON.stringify(record.unitPrice) === "{}") {
record.unitPrice = {'0-0': record.price}
}
// fix 当有unitPrice字段时 没有price字段时 补全price字段
if(!record?.price && JSON.stringify(record.unitPrice) !== "{}") {
if(Object.keys(record.unitPrice)[0] === '0-0') record.price = record.unitPrice['0-0']
}
let unitPrice = 0
Object.entries(record.unitPrice).forEach(([key, value]) => {
const [min, max] = key.split('-').map(v => Number(v))
if (min === 0 && max === 0) {
unitPrice = Number(value)
return false
}
if ((purchaseCount >= min && purchaseCount <= max) || (purchaseCount > max)) {
// 处于该区间或者大于该区间
unitPrice = Number(value)
return false
}
})
// 考虑会员折扣
let memberPrice = record.memberPrice
if(record.isMemberPrice) {
return Number((unitPrice * purchaseCount * memberPrice).toFixed(2))
} else {
return Number((unitPrice * purchaseCount).toFixed(2))
}
}
/**
* @param ctx schemaAction
*/
export const useProductTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const productRef = useRef<any>({})
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type: 'checkbox'})
const intl = useIntl()
const handleDelete = (record) => {
const newData = [...ctx.getFieldValue('products')]
// 删除formvalue
const colIndex = newData.findIndex(v => v.id === record.id)
newData.splice(colIndex, 1)
// 删除选中的项
rowSelectionCtl.setSelectRow(newData)
rowSelectionCtl.setSelectedRowKeys(newData.map(v => v.id))
ctx.setFieldValue('products', newData)
// 商品行数变动 清空之前的支付信息
if (pageStatus === PageStatus.ADD) {
ctx.setFieldValue('payments', [])
}
}
const [productColumns, setProductColumns] = useState(() => {
if (pageStatus === PageStatus.ADD) {
// 渲染操作
productInfoColumns[productInfoColumns.length - 1].render = (text, record) => <Button type='link' onClick={() => handleDelete(record)}>{intl.formatMessage({id: 'purchaseOrder.delete'})}</Button>
// 渲染单价
productInfoColumns[5].render = (t, r) => {
return r.price ? <span style={{color: 'red'}}>{r.price}</span> : <PriceComp priceSection={r.unitPrice}/>
}
// 渲染商品ID
productInfoColumns[0].render = (t, r) => {
return r.id
}
} else {
// 渲染单价
productInfoColumns[5].render = (t, r) => <span style={{color: 'red'}}>{r.price}</span>
// 渲染商品ID
productInfoColumns[0].render = (t, r) => r.productId
return [...productInfoColumns].slice(0, productInfoColumns.length - 1)
}
return productInfoColumns
})
const handleShowProduct = () => {
const buyerMemberId = ctx.getFieldValue('buyerMemberId')
const shopId = ctx.getFieldValue('shopId')
if (buyerMemberId && shopId) {
productRef.current.setVisible(true)
} else {
message.error(intl.formatMessage({id: 'purchaseOrder.orderCollect.model.message'}))
}
}
const productAddButton = <Button onClick={handleShowProduct} block type='default' style={{margin: '24px auto'}}>{intl.formatMessage({id: 'purchaseOrder.orderCollect.model.button1'})}</Button>
const productComponents = {
body: {
row: ProductEditableRow,
cell: ProductTableCell
}
}
const handleSave = row => {
const { pageStatus } = usePageStatus()
// 商品采购数量变动 清空之前的支付信息
if (pageStatus === PageStatus.ADD) {
ctx.setFieldValue('payments', [])
}
return new Promise((resolve, reject) => {
const newData = [...ctx.getFieldValue('products')];
const index = newData.findIndex(item => row.id === item.id);
const item = newData[index];
row['money'] = getUnitPriceTotal(row)
row['productId'] = row.commodityId
newData.splice(index, 1, {
...item,
...row,
});
ctx.setFieldValue('products', newData)
resolve({item, newData})
})
};
const productMergeColumns = productColumns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
editable: ctx.getFormState().editable === false ? false : col.editable,
dataIndex: col.dataIndex,
title: col.title,
formItem: col.formItem,
formItemProps: col.formItemProps,
handleSave
}),
};
})
return {
productRef,
productAddButton,
productColumns: productMergeColumns,
productComponents,
visible,
setVisible,
rowSelection,
rowSelectionCtl
}
}
import { ISchema } from '@formily/antd';
import moment from 'moment'
import { getIntl } from 'umi';
// 基本信息
const basicInfo: ISchema = {
"x-index": 0,
type: 'object',
"x-component": 'MellowCard',
"x-component-props": {
title: getIntl().formatMessage({ id: 'purchaseRequisition.jibenxinxi', defaultMessage: '基本信息' }),
id: 'basicInfo',
},
properties: {
NO_SUBMIT_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 6,
wrapperCol: 16,
labelAlign: "left",
grid: true,
full: true,
autoRow: true,
columns: 2,
},
properties: {
digest: {
type: 'string',
title: '单据摘要',
"x-rules": [
{
required: true,
message: '请输入单据摘要'
},
{
limitByte: true,
maxByte: 60
}
],
"x-mega-props": {
span: 1
}
},
logisticProvider: {
type: 'string',
title: '物流服务商',
enum: [
'顺丰',
'逆风',
'东南风'
]
},
deliverAddress: {
type: 'string',
title: '发货地址',
enum: [
'长津湖',
'水门桥',
'金刚杵'
],
},
}
},
}
}
// 相关信息
const relatedInfo: ISchema = {
"x-index": 1,
type: 'object',
"x-component": 'MellowCard',
"x-component-props": {
title: getIntl().formatMessage({ id: 'saleOrder.xiangguanxinxi', defaultMessage: '相关信息' }),
id: 'relatedInfo',
},
properties: {
NO_SUBMIT_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 6,
wrapperCol: 16,
labelAlign: "left",
grid: true,
full: true,
autoRow: true,
columns: 2,
},
properties: {
deliveryNo: {
type: 'string',
title: '对应发货单号',
"x-component": 'text',
},
receiveAddress: {
type: 'string',
title: '收货地址',
"x-component": 'text',
},
orderNo: {
type: 'string',
title: '对应订单号/售后单',
"x-component": 'text',
},
receiver: {
type: 'string',
title: '收货方',
"x-component": 'text',
},
}
},
}
}
// 单据明细
const material: ISchema = {
"x-index": 2,
type: 'object',
"x-component": 'MellowCard',
"x-component-props": {
title: '物流单明细',
id: 'orderMaterial',
},
properties: {
products: {
type: 'array',
"x-component": 'MultTable',
required: true,
"x-component-props": {
rowKey: 'id',
columns: "{{productColumns}}",
components: "{{productComponents}}",
prefix: "{{productAddButton}}",
},
},
NO_SUBMIT_SPY: {
type: 'object',
"x-component": "moneyTotalBox"
}
}
}
// 运费信息
const freightInfo: ISchema = {
"x-index": 3,
type: 'object',
"x-component": 'MellowCard',
"x-component-props": {
title: '运费信息',
id: 'freightInfo',
},
properties: {
NO_SUBMIT_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 6,
wrapperCol: 16,
labelAlign: "left",
grid: true,
full: true,
autoRow: true,
columns: 2,
},
properties: {
freight: {
type: 'string',
title: '运费',
"x-component": 'text',
},
settlement: {
type: 'string',
title: '结算方式',
"x-component": 'text',
},
}
},
}
}
export const increaseSchema: ISchema = {
type: 'object',
properties: {
basicInfo,
relatedInfo,
material,
freightInfo,
}
}
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { ISchema } from '@formily/antd';
import { getIntl } from 'umi';
/**
* 新增采购请购单 选择物料的筛选
*/
export const addRequesitionMaterialSchema: ISchema = {
type: 'object',
properties: {
code: {
type: 'string',
'x-component': 'ModalSearch',
'x-component-props': {
placeholder: getIntl().formatMessage({ id: 'purchaseRequisition.qingshuruhuohao', defaultMessage: '请输入货号' }),
align: 'flex-start',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
// flexWrap: 'nowrap',
justifyContent: 'flex-start',
style: {
marginRight: 0,
}
},
colStyle: {
marginTop: 20,
},
},
properties: {
name: {
type: 'string',
'x-component-props': {
placeholder: getIntl().formatMessage({ id: 'purchaseRequisition.huopinmingcheng', defaultMessage: '货品名称' }),
style: { width: '174px' },
},
},
brandId: {
type: 'string',
'x-component': 'CustomInputSearch',
'x-component-props': {
placeholder: getIntl().formatMessage({ id: 'purchaseRequisition.shangpinpinpai', defaultMessage: '商品品牌' }),
showSearch: true,
showArrow: true,
defaultActiveFirstOption: false,
filterOption: false,
notFoundContent: null,
style: { width: '174px' },
searchValue: null,
dataoption: [],
},
},
customerCategoryId: {
type: 'string',
'x-component': 'CustomCategorySearch',
'x-component-props': {
placeholder: getIntl().formatMessage({ id: 'purchaseRequisition.shangpinpinlei', defaultMessage: '商品品类' }),
showSearch: true,
notFoundContent: null,
style: { width: '174px' },
dataoption: [],
fieldNames: { label: 'title', value: 'id', children: 'children' },
},
},
type: {
type: 'string',
"x-component-props": {
placeholder: getIntl().formatMessage({ id: 'purchaseRequisition.guigexinghao', defaultMessage: '规格型号' }),
style: { width: '174px' },
}
},
submit: {
"x-component": 'Submit',
"x-mega-props": {
span: 1
},
"x-component-props": {
children: getIntl().formatMessage({ id: 'purchaseRequisition.chaxun', defaultMessage: '查询' })
}
},
submit1: {
"x-component": 'Children',
"x-component-props": {
children: '{{otherHandle}}'
}
}
}
}
}
}
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { useModalTable } from '../../model/useModalTable'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { departmentColumns } from '../../constant'
import { getMemberBusinessOrganizationPage } from '@/services/MemberV2Api'
import { useIntl } from 'umi'
export interface DepartmentModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions | ISchemaFormAsyncActions,
currentRef?: any,
confirmModal?()
}
// 选择部门弹窗
const DepartmentModalTable:React.FC<DepartmentModalTableProps> = (props) => {
const { type = 'radio', schemaAction, confirmModal, currentRef, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type})
const intl = useIntl()
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
useEffect(() => {
if(visible) {
const departmentId = schemaAction.getFieldValue('departmentId')
rowSelectionCtl.setSelectedRowKeys([departmentId])
}
}, [visible])
const handleConfirm = async () => {
const item = rowSelectionCtl.selectRow[0]
if (item) {
schemaAction.setFieldValue('departmentId', item['id'])
schemaAction.setFieldValue('department', item['title'])
}
confirmModal && confirmModal()
setVisible(false)
}
return (
<ModalTable
modalTitle={intl.formatMessage({ id: 'purchaseRequisition.xuanzezuzhiji', defaultMessage: '选择组织机构' })}
columns={departmentColumns}
visible={visible}
confirm={handleConfirm}
cancel={() => setVisible(false)}
fetchTableData={async (params) => (await getMemberBusinessOrganizationPage({...params}, {useCache: true, ttl: 10 * 1000})).data}
rowSelection={rowSelection}
modalType='departmentSchema'
searchName="code"
tableProps={{
rowKey: 'id'
}}
resetModal={{
destroyOnClose: true,
}}
{...restProps}
/>
)
}
DepartmentModalTable.defaultProps = {}
export default DepartmentModalTable
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { fetchOrderApi } from '../../apis'
import { FormEffectHooks, ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch'
import { FORM_FILTER_PATH } from '@/formSchema/const';
import Search from '@/components/NiceForm/components/Search'
import Submit from '@/components/NiceForm/components/Submit';
import Children from '@/components/NiceForm/components/Children';
import { addRequesitionMaterialSchema } from '../../schema/modal'
import { Tooltip } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { clearModalParams } from '@/utils'
import CustomCategorySearch from '@/components/NiceForm/components/CustomCategorySearch'
import CustomInputSearch from '@/components/NiceForm/components/CustomInputSearch'
import { searchBrandOptionEffect, searchCustomerCategoryOptionEffect } from '../../effects'
import { useIntl, getIntl } from 'umi'
export interface MaterialModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions | ISchemaFormAsyncActions,
currentRef?: any,
sectionProps: any,
confirmModal?()
}
export const materialColumns: any[] = [
{
title: 'ID',
dataIndex: 'id',
align: 'center',
key: 'id',
className: 'commonHide'
},
// 货号 货品名称 规格型号 品类 品牌 单位
{
title: getIntl().formatMessage({ id: 'purchaseRequisition.huohao', defaultMessage: '货号' }),
dataIndex: 'code',
align: 'center',
key: 'code',
},
{
title: getIntl().formatMessage({ id: 'purchaseRequisition.huopinmingcheng', defaultMessage: '货品名称' }),
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: getIntl().formatMessage({ id: 'purchaseRequisition.guigexinghao', defaultMessage: '规格型号' }),
dataIndex: 'type',
align: 'center',
key: 'type',
},
{
title: getIntl().formatMessage({ id: 'purchaseRequisition.pinlei', defaultMessage: '品类' }),
dataIndex: ['customerCategory', 'name'],
align: 'center',
key: ['customerCategory', 'name'],
},
{
title: getIntl().formatMessage({ id: 'purchaseRequisition.pinpai', defaultMessage: '品牌' }),
dataIndex: ['brand', 'name'],
align: 'center',
key: ['brand', 'name'],
},
{
title: getIntl().formatMessage({ id: 'purchaseRequisition.danwei', defaultMessage: '单位' }),
dataIndex: 'unitName',
align: 'center',
key: 'unitName'
},
]
const MaterialModalTable:React.FC<MaterialModalTableProps> = (props) => {
const intl = useIntl()
const { type = 'checkbox', schemaAction, confirmModal, currentRef, sectionProps, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = sectionProps
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const addMaterialProcessField = (value, origin) => {
let tempOriginData = [...origin]
// 对选中值去重
const _value = Object.values(value.reduce((item, next)=>{
item[next.id] = next
return item
},{}))
if(Array.isArray(_value)) {
let processData = _value.map(v => {
let temp: any = {};
temp.id = v.id;
temp.code = v.code;
temp.name = v.name;
temp.type = v.type;
// 处理两套不同字段
temp.category = v?.customerCategory?.name || v?.category || null;
temp.brand = v?.brand?.name || v?.brand || null;
temp.unit = v?.unitName || v?.unit || null;
return temp
})
let originIds = tempOriginData.map(item => item.id)
processData.map(item => {
if(!originIds.includes(item.id)) {
tempOriginData.push(item)
}
})
return tempOriginData
}
}
const handleConfirm = async () => {
const materialData = schemaAction.getFieldValue('products')
schemaAction.setFieldValue('products', addMaterialProcessField(rowSelectionCtl.selectRow, materialData))
confirmModal && confirmModal()
setVisible(false)
clearModalParams()
}
const handleCancel = () => {
setVisible(false)
clearModalParams()
}
const otherHandle = <>
<a className="ant-btn" href="/memberCenter/commodityAbility/commodity/goods/add" target="_blank" style={{marginRight: 16}}>{intl.formatMessage({ id: 'purchaseRequisition.xinzenghuopin', defaultMessage: '新增货品' })}</a>
<Tooltip title={intl.formatMessage({ id: 'purchaseRequisition.dianjichaxun', defaultMessage: '点击查询,列表可显示新增的货品' })}>
<QuestionCircleOutlined />
</Tooltip>
</>
return (
<ModalTable
modalTitle={intl.formatMessage({ id: 'purchaseRequisition.xuanzehuopin', defaultMessage: '选择货品' })}
width={900}
columns={materialColumns}
visible={visible}
confirm={handleConfirm}
cancel={handleCancel}
fetchTableData={fetchOrderApi.getPurchaseRequesitionMaterielList}
rowSelection={rowSelection}
resetModal={{destroyOnClose: true}}
modalType='none'
tableProps={{
rowKey: 'id',
onRow: (record) => ({
onClick: () => {
rowSelectionCtl.appendSelectRow(record);
rowSelectionCtl.appendSelectRowKeys(record.id);
},
})
}}
formilyProps={{
ctx: {
schema: addRequesitionMaterialSchema,
components: {
ModalSearch: Search,
Submit,
Children,
CustomInputSearch,
CustomCategorySearch
},
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'code',
FORM_FILTER_PATH,
);
FormEffectHooks.onFieldChange$('brandId').subscribe(() => {
searchBrandOptionEffect(actions, 'brandId')
})
FormEffectHooks.onFieldChange$('customerCategoryId').subscribe(() => {
searchCustomerCategoryOptionEffect(actions, 'customerCategoryId')
})
},
expressionScope: {
otherHandle
}
}
}}
{...restProps}
/>
)
}
MaterialModalTable.defaultProps = {}
export default MaterialModalTable
import { FormEffectHooks, ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import { useLinkageUtils } from '@/utils/formEffectUtils';
import { getProductCustomerGetCustomerCategoryTree, getProductSelectGetSelectBrand } from '@/services/ProductV2Api';
export const useEditHideField = () => {
const { pageStatus } = usePageStatus()
const utils = useLinkageUtils()
FormEffectHooks.onFormInit$().subscribe(() => {
if (pageStatus === PageStatus.ADD) {
utils.hide('orderNo')
utils.hide('createTime')
}
})
}
import { PageStatus, usePageStatus } from '@/hooks/usePageStatus';
import { useLinkageUtils } from '@/utils/formEffectUtils';
export const useMaterialTableChangeForAmount = (ctx: ISchemaFormActions | ISchemaFormAsyncActions, update) => {
FormEffectHooks.onFieldValueChange$('products').subscribe(state => {
......@@ -21,8 +10,20 @@ export const useMaterialTableChangeForAmount = (ctx: ISchemaFormActions | ISchem
})
}
// 高级筛选schema中用于输入搜索品牌的Effect
export const useInitShowField = () => {
const { pageStatus } = usePageStatus()
const utils = useLinkageUtils()
FormEffectHooks.onFormInit$().subscribe(() => {
// 初始化一些详情数据
// if (pageStatus === PageStatus.ADD) {
// utils.hide('orderNo')
// utils.hide('createTime')
// }
})
}
// 高级筛选schema中用于输入搜索品牌的Effect
export const searchBrandOptionEffect = (context: any, fieldName: string) => {
context.getFieldState(fieldName, state => {
getProductSelectGetSelectBrand({ name: state.props['x-component-props'].searchValue }).then(res => {
......@@ -34,7 +35,6 @@ export const searchBrandOptionEffect = (context: any, fieldName: string) => {
}
// 高级筛选schema中用于输入搜索商品品类的Effect
export const searchCustomerCategoryOptionEffect = (context: any, fieldName: string) => {
context.getFieldState(fieldName, state => {
getProductCustomerGetCustomerCategoryTree().then(res => {
......
......@@ -6,13 +6,11 @@ import { createFormActions, registerVirtualBox, useFormSpy } from '@formily/antd
import { SaveOutlined, LinkOutlined } from '@ant-design/icons'
import NiceForm from '@/components/NiceForm'
import { increaseSchema } from './schema'
import { useEditHideField, useMaterialTableChangeForAmount } from './effects'
import { useMaterialTableChangeForAmount } from './effects'
import { procurementProcessField, procurementRenderField, procurmentRenderInit } from './constant'
import { useUpdate } from '@umijs/hooks'
import { help } from '../../common'
import { useMaterialTable } from './model/useMaterialTable'
import MaterialModalTable from './components/materialModalTable'
import DepartmentModalTable from './components/departmentModalTable'
import MemberModalTable from './components/memberModalTable'
import styled from 'styled-components'
import FormDetailHeader from '@/components/FormDetailHeader'
......@@ -54,9 +52,8 @@ export const MoneyTotalBox = registerVirtualBox('moneyTotalBox', () => {
</RowStyle>
})
/** 采购请购单 新增 */
const IncreaseRequisition:React.FC<{}> = () => {
const departmentRef = useRef<any>({}) // 选部门
/** 销售发货单 新增 */
const AddSaleDelevedOrder:React.FC<{}> = () => {
const memberRef = useRef<any>({})
const [formLoading, setFormLoading] = useState(false)
const [btnLoading, setBtnLoading] = useState(false)
......@@ -67,7 +64,7 @@ const IncreaseRequisition:React.FC<{}> = () => {
const intl = useIntl()
// 请购单物料
const { materialAddButton, materialRef, materialColumns, materialComponents, ...surplusProps } = useMaterialTable(addSchemaAction)
const { materialColumns, materialComponents } = useMaterialTable(addSchemaAction)
useEffect(() => {
if (id) {
......@@ -133,14 +130,7 @@ const IncreaseRequisition:React.FC<{}> = () => {
memberRef.current.setVisible(true)
}
const memberBtn = <div className='connectBtn' onClick={handleOrderMember}><LinkOutlined style={{marginRight: 4}}/>{intl.formatMessage({ id: 'purchaseRequisition.xuanze', defaultMessage: '选择' })}</div>
// 选择合同
const handleDepartment = () => {
departmentRef.current.setVisible(true)
}
const departmentBtn = <div className='connectBtn' onClick={handleDepartment}><LinkOutlined style={{marginRight: 4}}/>{intl.formatMessage({ id: 'purchaseRequisition.xuanze', defaultMessage: '选择' })}</div>
const memberBtn = <div className='connectBtn' onClick={handleOrderMember}><LinkOutlined style={{marginRight: 4}}/>{intl.formatMessage({ id: 'saleOrder.xuanze', defaultMessage: '选择' })}</div>
const providerValue = {
schemaActions: addSchemaAction,
......@@ -150,11 +140,11 @@ const IncreaseRequisition:React.FC<{}> = () => {
return (<div>
<FormDetailContext.Provider value={providerValue}>
<FormDetailHeader
title={id ? intl.formatMessage({ id: 'purchaseRequisition.bianjiqinggoudan', defaultMessage: '编辑请购单' }) : intl.formatMessage({ id: 'purchaseRequisition.xinzengqinggoudan', defaultMessage: '新增请购单' })}
title={id ? intl.formatMessage({ id: 'saleOrder.bianjixiaoshoufahuodan', defaultMessage: '编辑销售发货单' }) : intl.formatMessage({ id: 'saleOrder.xinzengxiaoshoufahuodan', defaultMessage: '新增销售发货单' })}
schema={increaseSchema}
extraRight={[
<Button key="1" onClick={() => addSchemaAction.submit()} loading={btnLoading} type="primary" icon={<SaveOutlined />}>
{intl.formatMessage({ id: 'purchaseRequisition.baocun', defaultMessage: '保存' })}
{intl.formatMessage({ id: 'saleOrder.baocun', defaultMessage: '保存' })}
</Button>,
]}
/>
......@@ -169,8 +159,6 @@ const IncreaseRequisition:React.FC<{}> = () => {
onSubmit={handleSubmit}
effects={($, ctx) => {
$('onFormMount').subscribe(() => { })
useEditHideField()
// 物料信息的改动 渲染总额
useMaterialTableChangeForAmount(ctx, update)
......@@ -180,9 +168,7 @@ const IncreaseRequisition:React.FC<{}> = () => {
}}
expressionScope={{
memberBtn,
departmentBtn,
materialColumns,
materialAddButton,
materialComponents,
help,
}}
......@@ -191,17 +177,11 @@ const IncreaseRequisition:React.FC<{}> = () => {
</FormDetailWrapper>
</FormDetailContext.Provider>
{/* 选择部门 */}
<DepartmentModalTable currentRef={departmentRef} schemaAction={addSchemaAction}/>
{/* 选择采购物料 */}
<MaterialModalTable currentRef={materialRef} schemaAction={addSchemaAction} sectionProps={surplusProps} />
{/* 选择供应会员 */}
<MemberModalTable currentRef={memberRef} schemaAction={addSchemaAction}/>
{/* </PageHeaderWrapper> */}
{/* 选择供应会员 */}
<MemberModalTable currentRef={memberRef} schemaAction={addSchemaAction}/>
</div>)
}
IncreaseRequisition.defaultProps = {}
AddSaleDelevedOrder.defaultProps = {}
export default IncreaseRequisition
export default AddSaleDelevedOrder
import { useRef, useState } from 'react'
import { useState } from 'react'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { Button } from 'antd';
import { materialInfoColumns } from '../constant';
import MaterialTableCell, { MaterialEditableRow } from '../components/materialTableCell';
import { useModalTable } from './useModalTable';
import { useIntl } from 'umi';
......@@ -16,21 +15,14 @@ export const getUnitPriceTotal = (record) => {
* @param ctx schemaAction
*/
export const useMaterialTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const materialRef = useRef<any>({})
const intl = useIntl()
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type: 'checkbox'})
const handleDelete = (record) => {
const newData = [...ctx.getFieldValue('products')]
// 删除formvalue
const colIndex = newData.findIndex(v => v.id === record.id)
newData.splice(colIndex, 1)
// 删除选中的项
rowSelectionCtl.setSelectRow(newData)
rowSelectionCtl.setSelectedRowKeys(newData.map(v => v.id))
ctx.setFieldValue('products', newData)
}
const [materialColumns, setMaterialColumns] = useState(() => {
......@@ -39,15 +31,7 @@ export const useMaterialTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActio
materialInfoColumns[materialInfoColumns.length - 2].render = (t, r) => r.amount && <span style={{color: 'red'}}>{intl.formatMessage({ id: 'commodity.products.directChannel.columns.currency'})} {Number(r.amount).toFixed(2)}</span>
return materialInfoColumns
})
const handleShowMaterial = () => {
const products = ctx.getFieldValue('products')
materialRef.current.setVisible(true)
if(products && products.length) {
materialRef.current.rowSelectionCtl.setSelectedRowKeys(() => products.map(item => item.id))
}
}
const materialAddButton = <Button onClick={handleShowMaterial} block type='default' style={{margin: '24px auto'}}>{intl.formatMessage({ id: 'purchaseRequisition.xuanzecaigouwu', defaultMessage: '选择采购物料' })}</Button>
const materialComponents = {
body: {
row: MaterialEditableRow,
......@@ -90,13 +74,7 @@ export const useMaterialTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActio
})
return {
materialRef,
materialAddButton,
materialColumns: materialMergeColumns,
materialComponents,
visible,
setVisible,
rowSelection,
rowSelectionCtl
}
}
......@@ -25,19 +25,19 @@ const basicInfo: ISchema = {
columns: 2,
},
properties: {
requisitionNo: {
receiptsType: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.qinggoudanhao', defaultMessage: '请购单号' }),
title: '单据类型',
"x-component": 'text',
visible: false,
default: '销售发货单',
},
digest: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.dingdanzhaiyao', defaultMessage: '订单摘要' }),
title: '单据摘要',
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'purchaseRequisition.qingshurudingdan', defaultMessage: '请输入订单摘要' })
message: '请输入单据摘要'
},
{
limitByte: true,
......@@ -51,7 +51,7 @@ const basicInfo: ISchema = {
deliverTime: {
type: 'string',
"x-component": 'date',
title: getIntl().formatMessage({ id: 'purchaseRequisition.yujiaoriqi', defaultMessage: '预交日期' }),
title: '单据时间',
required: true,
"x-component-props": {
disabledDate: current => {
......@@ -63,66 +63,95 @@ const basicInfo: ISchema = {
span: 1
}
},
department: {
purpose: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.qinggoubumen', defaultMessage: '请购部门' }),
required: true,
"x-component-props": {
disabled: true,
addonAfter: "{{departmentBtn}}"
},
title: '对应仓库',
"x-rules": [
{
limitByte: true,
maxByte: 60
}
],
"x-mega-props": {
span: 1
}
},
departmentId: {
purpose1: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.qinggoubumenID', defaultMessage: '请购部门ID' }),
visible: false,
},
purpose: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.qinggouyongtu', defaultMessage: '请购用途' }),
title: '仓库人员',
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'purchaseRequisition.qingshuruqinggou', defaultMessage: '请输入请购用途' })
},
{
limitByte: true,
maxByte: 100
maxByte: 24
}
],
"x-mega-props": {
span: 1
}
},
vendorMemberName: {
remark: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.gongyinghuiyuan', defaultMessage: '供应会员' }),
"x-component-props": {
disabled: true,
addonAfter: "{{memberBtn}}"
},
required: true,
title: '备注',
"x-rules": [
{
limitByte: true,
maxByte: 200
}
],
},
vendorMemberId: {
}
},
}
}
// 相关信息
const relatedInfo: ISchema = {
"x-index": 1,
type: 'object',
"x-component": 'MellowCard',
"x-component-props": {
title: getIntl().formatMessage({ id: 'saleOrder.xiangguanxinxi', defaultMessage: '相关信息' }),
id: 'relatedInfo',
},
properties: {
NO_SUBMIT_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 6,
wrapperCol: 16,
labelAlign: "left",
grid: true,
full: true,
autoRow: true,
columns: 2,
},
properties: {
receipts: {
type: 'string',
visible: false
title: '对应单据',
"x-component": 'text',
},
vendorRoleId: {
delivery: {
type: 'string',
visible: false
title: '配送方式',
"x-component": 'text',
},
orderNo: {
type: 'string',
title: '关联单据',
"x-component": 'text',
},
createTime: {
address: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.danjushijian', defaultMessage: '单据时间' }),
visible: false
title: '收货地址',
"x-component": 'text',
},
interiorStateName: {
memberName: {
type: 'string',
title: getIntl().formatMessage({ id: 'purchaseRequisition.neibuzhuangtai', defaultMessage: '内部状态' }),
visible: false
title: '会员名称',
"x-component": 'text',
},
}
},
......@@ -130,13 +159,13 @@ const basicInfo: ISchema = {
}
}
// 请购单物料
// 单据明细
const material: ISchema = {
"x-index": 2,
type: 'object',
"x-component": 'MellowCard',
"x-component-props": {
title: getIntl().formatMessage({ id: 'purchaseRequisition.dingdanwuliao', defaultMessage: '订单物料' }),
title: getIntl().formatMessage({ id: 'saleOrder.danjumingxi', defaultMessage: '单据明细' }),
id: 'orderMaterial',
},
properties: {
......@@ -148,7 +177,6 @@ const material: ISchema = {
rowKey: 'id',
columns: "{{materialColumns}}",
components: "{{materialComponents}}",
prefix: "{{materialAddButton}}",
},
},
NO_SUBMIT_SPY: {
......@@ -163,6 +191,7 @@ export const increaseSchema: ISchema = {
type: 'object',
properties: {
basicInfo,
relatedInfo,
material,
}
}
......@@ -12,15 +12,14 @@ import { useSelfTable } from './model/useSelfTable'
// 待新增物流单
export interface FirstApprovedOrderProps {}
export interface ReadyAddLogisticsOrderProps {}
const fetchTableData = async (params) => {
// const { data } = await getOrderLogisticsOrderList(params)
return []
}
// TODO
const FirstApprovedOrder:React.FC<FirstApprovedOrderProps> = (props) => {
const ReadyAddLogisticsOrder:React.FC<ReadyAddLogisticsOrderProps> = (props) => {
const {
columns
} = useSelfTable()
......@@ -57,6 +56,6 @@ const FirstApprovedOrder:React.FC<FirstApprovedOrderProps> = (props) => {
</PageHeaderWrapper>
}
FirstApprovedOrder.defaultProps = {}
ReadyAddLogisticsOrder.defaultProps = {}
export default FirstApprovedOrder
export default ReadyAddLogisticsOrder
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment