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

feat: 添加代客下单和参数配置页面

parent 83d73031
...@@ -131,6 +131,12 @@ const AuthConfigRoute: RouterChild = { ...@@ -131,6 +131,12 @@ const AuthConfigRoute: RouterChild = {
name: 'message', name: 'message',
component: '@/pages/systemSetting/message' component: '@/pages/systemSetting/message'
}, },
/** 参数配置 */
{
path: '/memberCenter/systemSetting/parameterSetting',
name: 'parameterSetting',
component: '@/pages/systemSetting/parameterSetting'
},
], ],
......
...@@ -11,7 +11,7 @@ import MemberRoute from './memberRoute' // 会员能力路由 ...@@ -11,7 +11,7 @@ import MemberRoute from './memberRoute' // 会员能力路由
// import TranactionRoute from './tranactionRoute' // 交易能力路由 // import TranactionRoute from './tranactionRoute' // 交易能力路由
// import LogisticsRoute from './logisticsRoutes' // 物流能力路由 // import LogisticsRoute from './logisticsRoutes' // 物流能力路由
// import PayandSettleRoute from './payandSettle' //支付与结算 // import PayandSettleRoute from './payandSettle' //支付与结算
// import AuthConfigRoute from './authConfigRoute' import AuthConfigRoute from './authConfigRoute'
// import AfterService from './afterServiceRoute' // 售后 // import AfterService from './afterServiceRoute' // 售后
// import HandlingRoute from './handlingRoute'; // 加工能力 // import HandlingRoute from './handlingRoute'; // 加工能力
import DealAbilityRoute from './dealAbilityRoute'; // import DealAbilityRoute from './dealAbilityRoute'; //
...@@ -79,7 +79,7 @@ const memberCenterRoute = { ...@@ -79,7 +79,7 @@ const memberCenterRoute = {
// ProcurementRoute, // ProcurementRoute,
// // 合同能力 // // 合同能力
// contracRoute, // contracRoute,
// AuthConfigRoute, AuthConfigRoute,
// MemberRoute, // MemberRoute,
// HandlingRoute, // HandlingRoute,
// PayandSettleRoute, // PayandSettleRoute,
......
...@@ -19,6 +19,12 @@ export default [ ...@@ -19,6 +19,12 @@ export default [
noMargin: true, noMargin: true,
component: '@/pages/transaction/saleOrder/orderPreview' component: '@/pages/transaction/saleOrder/orderPreview'
}, },
// 代客下单
{
path: '/memberCenter/tranactionAbility/saleOrder/agentOrder',
name: 'AgentOrder',
component: '@/pages/transaction/saleOrder/agentOrder'
},
// 待审核订单 // 待审核订单
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyApprovedOrder', path: '/memberCenter/tranactionAbility/saleOrder/readyApprovedOrder',
...@@ -37,11 +43,11 @@ export default [ ...@@ -37,11 +43,11 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyApprovedOrder/detail', path: '/memberCenter/tranactionAbility/saleOrder/readyApprovedOrder/detail',
name: 'readyApprovedOrderDetail', name: 'readyApprovedOrderDetail',
component: '@/pages/transaction/saleOrder/readyApprovedOrder/detail', component: '@/pages/transaction/saleOrder/readyApprovedOrder/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 一级审核 // 一级审核
{ {
path: '/memberCenter/tranactionAbility/saleOrder/firstApprovedOrder', path: '/memberCenter/tranactionAbility/saleOrder/firstApprovedOrder',
...@@ -60,9 +66,9 @@ export default [ ...@@ -60,9 +66,9 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/firstApprovedOrder/detail', path: '/memberCenter/tranactionAbility/saleOrder/firstApprovedOrder/detail',
name: 'firstApprovedOrderDetail', name: 'firstApprovedOrderDetail',
component: '@/pages/transaction/saleOrder/firstApprovedOrder/detail', component: '@/pages/transaction/saleOrder/firstApprovedOrder/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 二级审核 // 二级审核
{ {
...@@ -82,9 +88,9 @@ export default [ ...@@ -82,9 +88,9 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/secondApprovedOrder/detail', path: '/memberCenter/tranactionAbility/saleOrder/secondApprovedOrder/detail',
name: 'secondApprovedOrderDetail', name: 'secondApprovedOrderDetail',
component: '@/pages/transaction/saleOrder/secondApprovedOrder/detail', component: '@/pages/transaction/saleOrder/secondApprovedOrder/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 待确认订单 // 待确认订单
{ {
...@@ -104,9 +110,9 @@ export default [ ...@@ -104,9 +110,9 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmOrder/detail', path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmOrder/detail',
name: 'readyConfirmOrderDetail', name: 'readyConfirmOrderDetail',
component: '@/pages/transaction/saleOrder/readyConfirmOrder/detail', component: '@/pages/transaction/saleOrder/readyConfirmOrder/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 待确认支付结果 // 待确认支付结果
{ {
...@@ -126,9 +132,9 @@ export default [ ...@@ -126,9 +132,9 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyPayResult/detail', path: '/memberCenter/tranactionAbility/saleOrder/readyPayResult/detail',
name: 'readyPayResultDetail', name: 'readyPayResultDetail',
component: '@/pages/transaction/saleOrder/readyPayResult/detail', component: '@/pages/transaction/saleOrder/readyPayResult/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 新增销售发货单列表 // 新增销售发货单列表
{ {
...@@ -176,15 +182,15 @@ export default [ ...@@ -176,15 +182,15 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmDelevedOrder/detail', path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmDelevedOrder/detail',
name: 'readyConfirmDelevedOrderDetail', name: 'readyConfirmDelevedOrderDetail',
component: '@/pages/transaction/saleOrder/readyConfirmDelevedOrder/detail', component: '@/pages/transaction/saleOrder/readyConfirmDelevedOrder/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 待确认回单 // 待确认回单
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmReturnOrder', path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmReturnOrder',
name: 'readyConfirmReturnOrder', name: 'readyConfirmReturnOrder',
component: '@/pages/transaction/saleOrder/readyConfirmReturnOrder', component: '@/pages/transaction/saleOrder/readyConfirmReturnOrder',
}, },
// 待确认回单-查看 // 待确认回单-查看
{ {
...@@ -198,9 +204,9 @@ export default [ ...@@ -198,9 +204,9 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmReturnOrder/detail', path: '/memberCenter/tranactionAbility/saleOrder/readyConfirmReturnOrder/detail',
name: 'readyConfirmReturnOrderDetail', name: 'readyConfirmReturnOrderDetail',
component: '@/pages/transaction/saleOrder/readyConfirmReturnOrder/detail', component: '@/pages/transaction/saleOrder/readyConfirmReturnOrder/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
// 待归档订单 // 待归档订单
{ {
...@@ -220,10 +226,10 @@ export default [ ...@@ -220,10 +226,10 @@ export default [
{ {
path: '/memberCenter/tranactionAbility/saleOrder/readyReturnDocument/detail', path: '/memberCenter/tranactionAbility/saleOrder/readyReturnDocument/detail',
name: 'readyReturnDocumentDetail', name: 'readyReturnDocumentDetail',
component: '@/pages/transaction/saleOrder/readyReturnDocument/detail', component: '@/pages/transaction/saleOrder/readyReturnDocument/detail',
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
] ]
} }
] ]
\ No newline at end of file
...@@ -101,14 +101,6 @@ const ProductDescFormDefualt: React.FC<{}> = () => { ...@@ -101,14 +101,6 @@ const ProductDescFormDefualt: React.FC<{}> = () => {
...fileImageList, ...fileImageList,
...tempObject ...tempObject
})) }))
// setFileImageList(
// update(fileImageList, {
// $splice: [
// [dragIndex, 1],
// [hoverIndex, 0, dragImage],
// ],
// }),
// )
}, [fileImageList]) }, [fileImageList])
const commonImgProps = { const commonImgProps = {
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
//图片画廊 //图片画廊
.picture-card-box{ .picture-card-box{
margin-bottom: 30px; margin-bottom: 30px;
// display: flex; // display: flex;
.card-add-box{ .card-add-box{
width: 196px; width: 196px;
height: 196px; height: 196px;
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
} }
.right-btn{ .right-btn{
...@@ -155,8 +155,12 @@ ...@@ -155,8 +155,12 @@
padding: 12px 0; padding: 12px 0;
border:1px solid rgba(235,236,240,1); border:1px solid rgba(235,236,240,1);
display: flex; display: flex;
flex-flow: wrap; // flex-flow: wrap;
flex-direction: column;
justify-content: left; justify-content: left;
& > div {
display: flex;
}
.imgItem{ .imgItem{
width:180px; width:180px;
height:180px; height:180px;
...@@ -170,7 +174,7 @@ ...@@ -170,7 +174,7 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
} }
.videoItem{ .videoItem{
...@@ -207,7 +211,7 @@ ...@@ -207,7 +211,7 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
} }
} }
...@@ -264,4 +268,4 @@ ...@@ -264,4 +268,4 @@
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
\ No newline at end of file
...@@ -15,7 +15,7 @@ import { ...@@ -15,7 +15,7 @@ import {
GetProductCommodityGetCommodityResponse, GetProductCommodityGetCommodityResponse,
GetProductCommodityGetCommodityCheckRecordResponse, GetProductCommodityGetCommodityCheckRecordResponse,
} from '@/services/ProductApi' } from '@/services/ProductApi'
import { carriageTypeLabel, columns, customerCategoryTypeLabel, deliveryTypeLabel, orderlyLadderPrice, priceTypeLabel, productStatusColor, productStatusLabel } from './constant' import { carriageTypeLabel, columns, CommodityImagesType, customerCategoryTypeLabel, deliveryTypeLabel, orderlyLadderPrice, priceTypeLabel, productStatusColor, productStatusLabel } from './constant'
interface IAttributeByValue { interface IAttributeByValue {
groupName: string; groupName: string;
...@@ -593,11 +593,30 @@ const viewProducts: React.FC<{}> = () => { ...@@ -593,11 +593,30 @@ const viewProducts: React.FC<{}> = () => {
{ {
productDetail?.commodityRemark?.imageList?.length>0 && productDetail?.commodityRemark?.imageList?.length>0 &&
<div className={styles.descriptionBox}> <div className={styles.descriptionBox}>
<div>
<p>商品图片:</p>
{ {
productDetail?.commodityRemark?.imageList.map((_item, _index)=> _item && <div key={_index} className={styles.imgItem}> productDetail?.commodityRemark?.imageList.filter(item => item.imageType === CommodityImagesType.DESCRIPTION_IMAGES).map((_item, _index)=> _item && <div key={_index} className={styles.imgItem}>
<img src={_item.url} /> <img src={_item.url} />
</div>) </div>)
} }
</div>
<div>
<p>厂商资质图片:</p>
{
productDetail?.commodityRemark?.imageList.filter(item => item.imageType === CommodityImagesType.CERTIFICATION_IMAGES).map((_item, _index)=> _item && <div key={_index} className={styles.imgItem}>
<img src={_item.url} />
</div>)
}
</div>
<div>
<p>商品检测报告:</p>
{
productDetail?.commodityRemark?.imageList.filter(item => item.imageType === CommodityImagesType.REPORT_IMAGES).map((_item, _index)=> _item && <div key={_index} className={styles.imgItem}>
<img src={_item.url} />
</div>)
}
</div>
</div> </div>
} }
{ {
......
import React, {useState, useEffect, useCallback} from 'react';
import { Card, List, Avatar, Button, Row, Col } from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { PublicApi } from '@/services/api';
import auto_receive from '@/assets/imgs/auto_receive.png'
import express_time from '@/assets/imgs/express_time.png';
import forcast_time from '@/assets/imgs/forcast_time.png'
import price_line from '@/assets/imgs/price_line.png';
import MellowCard from '@/components/MellowCard';
const ParameterSetting: React.FC<{}> = () => {
return (
<PageHeaderWrapper>
<Row gutter={16}>
<Col span={2}>
<MellowCard title='类型' fullHeight>
<div>
<Button>全部</Button>
<Button>商品相关</Button>
<Button>订单相关</Button>
</div>
</MellowCard>
</Col>
<Col span={10}>
<MellowCard fullHeight>
666
</MellowCard>
</Col>
</Row>
</PageHeaderWrapper>
)
}
export default ParameterSetting;
import { PublicApi } from '@/services/api'
export const fetchOrderApi = {
/** 弹窗获取商品列表 */
async getProductList(params) {
const { data } = await PublicApi.getProductCommodityCommonGetCommodityListByBuyer(params, { useCache: true, ttl: 10 * 1000 })
return data
},
/** 弹窗获取询价报价单列表 */
async getQuotationList(params) {
const { data } = await PublicApi.getTransactionProductQuotationList(params)
return data
},
/** 根据询价报价id查询商品列表 */
async getProductListByQuotationOrderId(params) {
const { data } = await PublicApi.getTransactionEnquiryProductAll(params)
return data
},
/** 根据下单类型获取会员列表 */
async getMemberListByModelType(params) {
const { data } = await PublicApi.getMemberManageAllPageByordertype(params)
return data
},
/** 获取所有商品收货地址 */
async getProductAddressAll() {
const { data } = await PublicApi.getLogisticsSelectListReceiverAddress()
return data
},
/** 获取发票列表 */
async getInvoicesList() {
const { data } = await PublicApi.getSettleAccountsInvoiceMessageList()
return data
},
/** 获取支付信息列表 */
async getPayInfoList(params) {
const { data } = await PublicApi.postOrderBuyerCreateB2bPaymentFind(params, { ctlType: 'none' })
return data
},
/** 查询当前订单工作流 */
async getOrderWorkFlow(params) {
const { data } = await PublicApi.getOrderTradingRulesByProductId(params)
return data
},
}
.noMarbottom {
margin-bottom: 0 !important;
}
\ No newline at end of file
import React, { useRef, useEffect, useMemo } from 'react'
import ModalForm from '@/components/ModalForm'
import { createFormActions, useValueLinkageEffect, ISchemaFormActions } from '@formily/antd'
import addressSchema from './schema'
import './index.less'
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect'
import { PublicApi } from '@/services/api'
import { useLinkEnumEffect } from '@/components/NiceForm/linkages/linkEnum'
export interface AddressModalProps {
mode: 'add' | 'edit' | 'preview' | 'default',
currentRef?: any,
formInitValue?: any,
reloadAddress?()
}
const titleMaps = {
add: '新建收货地址',
edit: '编辑收货地址',
preview: '查看收货地址'
}
const addressSchemaAction = createFormActions()
// 获取手机区号
const fetchTelCode = async () => {
const { data } = await PublicApi.getManageCountryAreaGetTelCode()
return data
}
const AddressModal:React.FC<AddressModalProps> = (props) => {
const addressData = useRef<any[]>([])
const { mode, formInitValue } = props
const selfInitValue = useMemo(() => mode === 'add' ? null : formInitValue, [mode, formInitValue])
// 由于默认是number类型, 但switch组件只接收boolean
if (selfInitValue) {
selfInitValue.isDefault = !!selfInitValue.isDefault
}
const resetForm = () => {
addressSchemaAction.reset({validate: false})
}
const handleConfirm = () => {
if (mode === 'preview') {
props.currentRef.current.setVisible(false)
return false
}
addressSchemaAction.submit()
}
const findAreaNameByCode = (dataSource, code) => {
return dataSource.find(v => v.code === code).name
}
const handleSubmit = async (value) => {
const provinceCode = addressSchemaAction.getFieldValue('provinceCode')
const cityCode = addressSchemaAction.getFieldValue('cityCode')
const districtCode = addressSchemaAction.getFieldValue('districtCode')
const provinceData = addressData.current
const cityData = provinceData.find(v => v.code === provinceCode).areaResponses
const districtData = cityData.find(v => v.code === cityCode).areaResponses
const provinceName = findAreaNameByCode(provinceData, provinceCode)
const cityName = findAreaNameByCode(cityData, cityCode)
const districtName = findAreaNameByCode(districtData, districtCode)
const params = {
...value,
isDefault: Number(!!value.isDefault),
provinceName,
cityName,
districtName
}
const fn = mode === 'edit' ? PublicApi.postLogisticsReceiverAddressUpdate : PublicApi.postLogisticsReceiverAddressAdd
await fn(params)
resetForm()
props.currentRef.current.setVisible(false)
props.reloadAddress && props.reloadAddress()
}
return (
<ModalForm
modalTitle={titleMaps[mode]}
confirm={handleConfirm}
cancel={resetForm}
initialValues={selfInitValue}
previewPlaceholder=' '
editable={mode !== 'preview'}
modalProps={{
destroyOnClose: true
}}
effects={($, { setFieldState, setFieldValue }) => {
$('onFormMount').subscribe(() => {
PublicApi.getManageAreaAll().then(res => {
if (res.code === 1000) {
const { data } = res;
addressData.current = data
setFieldState('provinceCode', targetState => {
targetState.originData = data;
targetState.props.enum = data.map(v => ({
label: v.name,
value: v.code,
}));
});
if (selfInitValue) {
const { provinceCode, cityCode } = selfInitValue
const cityData: any[] = data.find(v => v.code === provinceCode).areaResponses || []
setFieldState('cityCode', targetState => {
targetState.originData = cityData
targetState.props.enum = cityData.map(v => ({
label: v.name,
value: v.code,
}))
})
setFieldState('districtCode', targetState => {
const districtData: any[] = cityData.find(v => v.code === cityCode).areaResponses || []
targetState.originData = districtData
targetState.props.enum = districtData.map(v => ({
label: v.name,
value: v.code,
}))
})
}
}
});
})
useLinkEnumEffect('areaResponses', result =>
result.map(v => ({
label: v.name,
value: v.code,
})),
'code'
);
useAsyncSelect('areaCode', fetchTelCode)
$('onFieldChange', 'areaCode').subscribe(result => {
if(result.props.enum.length) {
setFieldValue('areaCode', '86')
}
})
}}
currentRef={props.currentRef}
actions={addressSchemaAction}
schema={addressSchema}
onSubmit={handleSubmit}
/>
)
}
AddressModal.defaultProps = {}
export default AddressModal
import { ISchema } from "@formily/antd";
import { PATTERN_MAPS } from '@/constants/regExp';
import { PublicApi } from '@/services/api';
const addressSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT_LAYOUT_ADDRESS: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'top',
},
properties: {
receiverName: {
type: 'string',
title: '收货人',
"x-rules": [
{
required: true,
message: '请输入收货人姓名'
},
{
limitByte: true,
maxByte: 40
}
]
},
NO_SUBMIT_LAYOUT_EFFECT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
grid: true,
label: '收货地区',
required: true,
columns: 3,
enableSafeWidth: false,
className: 'noMarbottom',
},
properties: {
provinceCode: {
type: 'string',
enum: [],
required: true,
"x-component-props": {
placeholder: '-省份/直辖市-'
},
"x-mega-props": {
span: 1
},
'x-linkages': [
{
type: 'value:linkage',
condition: '{{!!$value}}',
origin: 'provinceCode',
target: 'cityCode',
},
],
},
cityCode: {
type: 'string',
enum: [],
required: true,
"x-component-props": {
placeholder: '-市-'
},
"x-mega-props": {
span: 1
},
'x-linkages': [
{
type: 'value:linkage',
condition: '{{!!$value}}',
origin: 'cityCode',
target: 'districtCode',
},
],
},
districtCode: {
type: 'string',
enum: [],
required: true,
"x-component-props": {
placeholder: '-区-'
},
"x-mega-props": {
span: 1
}
}
}
},
address: {
type: 'string',
"x-component": 'textarea',
"x-component-props": {
rows: 3,
placeholder: '请填写详细地址、路名、门牌号等'
},
title: '详细地址',
"x-rules": [
{
required: true,
message: '请输入详细地址'
},
{
limitByte: true,
maxByte: 60
}
]
},
postalCode: {
type: 'string',
title: '邮编',
"x-rules": [
{
limitByte: true,
maxByte: 12
}
]
},
NO_SUBMIT_LAYOUT_PHONE: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
grid: true,
label: '手机号',
columns: 6,
enableSafeWidth: false,
className: 'noMarbottom',
required: true,
},
properties: {
areaCode: {
type: 'string',
enum: [],
"x-component-props": {
placeholder: '+86'
},
"x-mega-props": {
span: 2,
},
"x-rules": [
{
required: true,
message: '请选择区号'
}
]
},
phone: {
type: 'number',
"x-mega-props": {
span: 4
},
"x-rules": [
{
pattern: PATTERN_MAPS.phone,
message: '请输入正确的手机号'
},
{
required: true,
message: '请输入手机号'
}
],
"x-component-props": {
placeholder: '输入你的手机号码',
style: { width: '100%' }
}
}
}
},
tel: {
title: '电话号码',
type: 'string'
},
isDefault: {
title: '是否默认',
type: 'boolean',
"x-mega-props": {
wrapperWidth: 36
}
}
}
}
}
}
export default addressSchema
.noMarbottom {
margin-bottom: 0 !important;
}
\ No newline at end of file
import React, { useRef, useEffect, useMemo } from 'react'
import ModalForm from '@/components/ModalForm'
import { createFormActions } from '@formily/antd'
import addressSchema from './schema'
import './index.less'
import { PublicApi } from '@/services/api'
export interface InvoiceModalProps {
mode: 'add' | 'edit' | 'preview' | 'default' | 'delete',
currentRef?: any,
formInitValue?: any,
reload?()
}
const schemaActions = createFormActions()
const modelTitle = {
'add': '新增发票',
'edit': "编辑发票",
'preview': '查看发票'
}
const InvoiceModal:React.FC<InvoiceModalProps> = (props) => {
const { mode, formInitValue } = props
const selfInitValue = useMemo(() => mode === 'add' ? null : formInitValue, [mode, formInitValue])
// 由于默认是number类型, 但switch组件只接收boolean
if (selfInitValue) {
selfInitValue.isDefault = !!selfInitValue.isDefault
}
const resetForm = () => {
schemaActions.reset({validate: false})
}
const handleConfirm = () => {
if (mode === 'preview') {
props.currentRef.current.setVisible(false)
return ;
}
schemaActions.submit()
}
const handleSubmit = async (value) => {
const params = {
...value,
isDefault: value?.isDefault ? 1 : 0
}
const fn = mode === 'edit' ? PublicApi.postSettleAccountsInvoiceMessageUpdate : PublicApi.postSettleAccountsInvoiceMessageAdd
await fn(params)
resetForm()
props.currentRef.current.setVisible(false)
// @tofix bug 添加发票后 重载了列表导致选中失效
props.reload && props.reload()
}
return (
<ModalForm
modalTitle={modelTitle[mode]}
previewPlaceholder=" "
confirm={handleConfirm}
cancel={resetForm}
value={selfInitValue}
editable={mode !== 'preview'}
effects={($, { setFieldState }) => {
$('onFormMount').subscribe(() => {
})
}}
currentRef={props.currentRef}
actions={schemaActions}
schema={addressSchema}
onSubmit={handleSubmit}
modalProps={{
destroyOnClose: true
}}
/>
)
}
InvoiceModal.defaultProps = {}
export default InvoiceModal
import { ISchema } from "@formily/antd";
import { PATTERN_MAPS } from '@/constants/regExp';
import { PublicApi } from '@/services/api';
const addressSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT_LAYOUT_ADDRESS: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'left',
labelCol: 4,
wrapperCol: 20,
full: true,
},
properties: {
type: {
type: 'radio',
required: true,
title: '开具类型',
enum: [
{
label: '企业(默认)',
value: 1
},
{
label: '个人',
value: 2
}
],
default: 1,
// "x-linkages": [
// {
// type: 'value:visible',
// target: 'taxNo',
// condition: "{{$value === 1}}"
// }
// ]
},
kind: {
type: 'radio',
required: true,
title: '发票种类',
enum: [
{
label: '增值税普通发票(默认)',
value: 1
},
{
label: '增值税专用发票',
value: 2
}
],
default: 1,
},
invoiceTitle: {
type: 'string',
required: true,
title: '发票抬头',
"x-rules": [
{
required: true,
message: '请输入发票抬头'
},
{
limitByte: true,
maxByte: 40
},
]
},
taxNo: {
type: 'string',
required: true,
title: '纳税号',
"x-rules": [
{
required: true,
message: '请输入纳税号'
},
{
limitByte: true,
maxByte: 20
},
]
},
bankOfDeposit: {
type: 'string',
title: '开户行',
"x-rules": [
{
limitByte: true,
maxByte: 40
}
]
},
account: {
type: 'string',
title: '账号',
maxLength: 20
},
address: {
type: 'string',
title: '地址',
"x-rules": [
{
limitByte: true,
maxByte: 80
}
]
},
tel: {
type: 'string',
title: '电话号码',
"x-rules": [
{
pattern: PATTERN_MAPS.tel,
message: '请输入正确的电话号码'
}
]
},
isDefault: {
title: '是否默认',
type: 'boolean',
"x-mega-props": {
wrapperWidth: 36
}
}
}
}
}
}
export default addressSchema
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { fetchOrderApi } from '../../apis'
import { useModalTable } from '../../model/useModalTable'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { memberColumns } from '../../constant'
export interface MemberModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions | ISchemaFormAsyncActions,
currentRef?: any,
confirmModal?(),
productRef?: any,
}
const MemberModalTable:React.FC<MemberModalTableProps> = (props) => {
const { type = 'radio', schemaAction, confirmModal, currentRef, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type, customKey: 'id'})
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const handleConfirm = () => {
const rowItem = rowSelectionCtl.selectRow[0]
if (rowItem) {
schemaAction.setFieldValue('supplyMembersName', rowItem.name)
schemaAction.setFieldValue('supplyMembersId', rowItem.memberId)
schemaAction.setFieldValue('supplyMembersRoleId', rowItem.roleId)
}
confirmModal && confirmModal()
setVisible(false)
// 清空之前可能存在的商品支付信息数据
schemaAction.setFieldValue('orderProductRequests', [])
schemaAction.setFieldValue('paymentInformationResponses', [])
if(props?.productRef) {
props.productRef.current.rowSelectionCtl.setSelectRow([])
props.productRef.current.rowSelectionCtl.setSelectedRowKeys([])
}
}
return (
<ModalTable
modalTitle='选择采购会员'
columns={memberColumns}
visible={visible}
confirm={handleConfirm}
cancel={() => setVisible(false)}
fetchTableData={(params) => fetchOrderApi.getMemberListByModelType({...params, orderType: schemaAction.getFieldValue('orderModel')})}
rowSelection={rowSelection}
modalType='memberByDefault'
tableProps={{
rowKey: 'id'
}}
{...restProps}
/>
)
}
MemberModalTable.defaultProps = {}
export default MemberModalTable
import React, { useState, useRef, useContext, useEffect } from 'react'
import { Form, Input, Select } from 'antd';
import { history } from 'umi'
import styles from "../../index.less"
export interface PayInfoCellProps {
title: React.ReactNode;
editable: boolean;
children: React.ReactNode;
dataIndex: string;
record: any;
colIndex: number,
handleChange(record: any, value: any)
handleSave: (record: any) => Promise<any>;
forceEdit: boolean,
formItem: string,
formItemProps: any
}
const EditableContext = React.createContext<any>({});
export const EditableRow: React.FC<any> = (props) => {
const [form] = Form.useForm();
const { options = [] } = props?.children[5]?.props.additionalProps.formItemProps || {}
const [childOptions, setChildOptions] = useState<any[]>(() => {
const { payType } = props?.children[5]?.props.record || {}
if (payType) {
return options.find(v => v.payType === payType)?.payChannels.map(v => ({
label: v.payChannelName,
value: v.payChannel
})) || []
} else {
return []
}
})
const ctx = {
form,
childOptions,
setChildOptions,
originOptions: options
}
return (
<Form form={form} component={false}>
<EditableContext.Provider value={ctx}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
export const PayInfoCell:React.FC<PayInfoCellProps> = ({
title,
editable,
children,
dataIndex,
record,
colIndex,
handleChange,
handleSave,
forceEdit,
formItem,
formItemProps={},
...restProps
}) => {
const formItemRef = useRef<any>();
const { form, childOptions, setChildOptions, originOptions } = useContext(EditableContext);
let _childOptions = null;
if(history.location.query?.id && title === "支付渠道") {
let payList = originOptions.filter(item => item.payType === record.payType) || []
if(payList.length) {
_childOptions = payList[0].payChannels.map(_item => ({
label: _item.payChannelName,
value: _item.payChannel,
}))
}
}
const validatorNumber = (rule, value, callback) => {
try {
if(formItem !== 'input') {
callback()
}
let n = Number(value);
if(isNaN(n)) {
throw new Error('请正确输入支付比例');
} else if(n < 0 || !Number.isInteger(n)) {
throw new Error('支付比例为大于0的整数');
} else {
callback()
}
} catch (err) {
callback(err)
}
}
const save = async e => {
try {
const values = await form.validateFields();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
const handleInputChange = (e) => {
handleChange(record, e.target.value)
}
const chooseFormItem = (type) => {
const formId = dataIndex + colIndex
switch(type) {
case 'input': {
return <Input className="payRate" ref={formItemRef} onPressEnter={save} onBlur={save} onChange={handleInputChange} {...formItemProps} id={formId}/>
}
case 'select': {
const { options, ...rest } = formItemProps
// 支付方式
if (dataIndex === 'payType') {
return <Select ref={formItemRef}
options={originOptions.map(v => ({label: v.payTypeName, value: v.payType, disabled: v?.disabled}))}
onChange={e => {
const result = originOptions.find(v => e === v.payType)
setChildOptions(result.payChannels.map(v => ({label: v.payChannelName, value: v.payChannel})))
form.setFieldsValue({payChannel: ''})
save(e)
}}
{...rest}
id={formId}
/>
}
// 需联动的内容
if (dataIndex === 'payChannel') {
return <Select
ref={formItemRef}
onChange={save}
options={childOptions.length ? childOptions : _childOptions}
{...rest}
id={formId}
/>
}
}
}
}
let childNode = children;
if (editable) {
// console.log(dataIndex, record)
childNode = (forceEdit) ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
initialValue={record[dataIndex] || ''}
rules={[
{
required: true,
message: `${title}必须填写`,
},
// 支付比例大于0
{
validator: validatorNumber
}
]}
>
{chooseFormItem(formItem)}
</Form.Item>
) : (
null
);
}
return <td {...restProps} style={{height: 90}}>{childNode}</td>;
}
PayInfoCell.defaultProps = {}
export default PayInfoCell
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 { PublicApi } from '@/services/api'
import { EnvironmentOutlined } from '@ant-design/icons'
import { Popover, Space, Row, message } from 'antd'
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 { action } from 'mobx'
import { searchCustomerCategoryOptionEffect } from '../../effects'
import CustomCategorySearch from '@/components/NiceForm/components/CustomCategorySearch'
export interface ProductModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions | ISchemaFormAsyncActions,
currentRef?: any,
sectionProps: any,
confirmModal?()
}
export const productColumns: any[] = [
{
title: '商品ID',
dataIndex: 'id',
align: 'center',
key: 'id',
},
{
title: '商品名称',
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: '品类',
dataIndex: 'customerCategoryName',
align: 'center',
key: 'customerCategoryName',
},
{
title: '品牌',
dataIndex: 'brandName',
align: 'center',
key: 'brandName',
},
{
title: '单位',
dataIndex: 'unitName',
align: 'center',
key: 'unitName'
},
{
title: '库存数量',
dataIndex: 'stockCount',
align: 'center',
key: 'stockCount'
},
]
// 下单类型->商城类型映射
const orderProductShopTypeMaps = {
[OrderModalType.HAND_ORDER]: 1,
[OrderModalType.CONSOLIDATED_ORDER]: 1,
[OrderModalType.CHANNEL_DIRECT_MINING_ORDER]: 3,
[OrderModalType.CHANNEL_SPOT_MANUAL_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 PublicApi.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 () => {
// 判断所选择的商品是否属于同一个工作流
// @ts-ignore
const res = await PublicApi.postOrderIsWorkFlow({
memberId: rowSelectionCtl.selectRow[0].memberId,
memberRoleId: rowSelectionCtl.selectRow[0].memberRoleId,
productIds: rowSelectionCtl.selectedRowKeys,
orderMode: schemaAction.getFieldValue('orderMode')
}, { ctlType: 'none' })
if (res.code === 1000) {
const productData = schemaAction.getFieldValue('orderProductRequests')
schemaAction.setFieldValue('orderProductRequests', await filterProductDataById(productData, rowSelectionCtl.selectRow))
confirmModal && confirmModal()
setVisible(false)
}
// else {
// message.error(res.message)
// }
}
const fetchProductList = (values) => {
const modelType = schemaAction.getFieldValue('orderMode')
const supplyMembersId = schemaAction.getFieldValue('supplyMembersId')
const params = {
...values,
shopType: orderProductShopTypeMaps[modelType],
environment: 1,
memberId: supplyMembersId,
// 手工下单/合并订单下单时,查询现货价格商品
priceTypeList: (modelType === OrderModalType.CONSOLIDATED_ORDER || modelType === OrderModalType.HAND_ORDER) ? [1] : undefined,
shopId: schemaAction.getFieldValue('shopId')
}
return fetchOrderApi.getProductList(params)
}
return (
<ModalTable
modalTitle='选择订单商品'
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 },
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
// actions.setFieldState('customerCategoryId', state => {
// state.props['x-component-props'].queryParams = {
// memberId: schemaAction.getFieldValue('supplyMembersId'),
// memberRoleId: schemaAction.getFieldValue('supplyMembersRoleId')
// }
// })
FormEffectHooks.onFieldChange$('customerCategoryId').subscribe(state => {
searchCustomerCategoryOptionEffect(schemaAction, actions, 'customerCategoryId')
})
actions.setFieldState('brandId', state => {
state.props['x-component-props'].queryParams = {
memberId: schemaAction.getFieldValue('supplyMembersId'),
memberRoleId: schemaAction.getFieldValue('supplyMembersRoleId')
}
})
}
}
}}
{...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, { useState, useRef, useContext, useEffect } from 'react'
import { Form, Input, Select } from 'antd';
import { has } from 'lodash';
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 save = async e => {
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': {
// 用于判断是否是合并下单
let hasSelectMergeBtn = document.getElementsByClassName("selectMerge")
// 用于合并订单采购数量回显
if(hasSelectMergeBtn.length) {
let keyValue = {}
keyValue[dataIndex] = v
form.setFieldsValue(keyValue)
}
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(`数量不小于最小起订数${record["minOrder"]}`)
}
if(_value > Number.MAX_SAFE_INTEGER) {
throw new Error('数值精度溢出')
}
callback()
} catch (err) {
callback(err)
}
}
let childNode = children;
if (editable) {
childNode =
<Form.Item
className="customFormItem"
name={dataIndex}
initialValue={record[dataIndex] || ''}
rules={[
{
required: true,
message: `${title}必须填写`,
},
{
pattern: /^\d+(\.\d{1,3})?$/,
message: '采购数量仅限三位小数',
},
{
validator: validatorNumber
}
]}
>
{chooseFormItem(formItem, record[dataIndex] || '')}
</Form.Item>
}
return <td {...restProps}>{childNode}</td>;
}
ProductTableCell.defaultProps = {}
export default ProductTableCell
import React, { useState, useRef, useEffect } from 'react'
import styled from 'styled-components'
import { ISchemaFormProps, ISchemaFieldProps, ISchemaFieldComponentProps, createFormActions, useFieldState } from '@formily/antd'
import { Button, Space, Row, Col, Tag } from 'antd'
import { PlusOutlined, DeleteColumnOutlined, EditOutlined, DeleteOutlined, CaretUpOutlined, CaretDownOutlined, EyeOutlined } from '@ant-design/icons'
import cx from 'classnames'
import AddressModal from '../addressModal'
import { fetchOrderApi } from '../../apis'
import { PublicApi } from '@/services/api'
const SelectStyles = styled((props) => <div className='select-list' {...props}></div>)`
.select_style_border {
border: 1px solid #EEF0F3;
margin-top: 20px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 14px;
cursor: pointer;
line-height: 28px;
position:relative;
}
.select_style_border.active {
border: 1px solid #00B382;
}
.select_style_border.active::after {
content: '';
position: absolute;
width: 0;
height: 0;
border-bottom: 12px solid #00B37A;
border-left: 12px solid transparent;
bottom: 0;
right: 0;
z-index: 5;
}
`
const transformDefaultData = (data: any[]) => {
if (data.length === 0) return data
const hasDefault = data.some(v => v.isDefault === 1)
return hasDefault ? data : data.map((v, i) => {
if (i === 0) {
v.isDefault = 1
}
return v
})
}
const SelectAddress = (props: ISchemaFieldComponentProps) => {
const [formInitValue, setFormInitValue] = useState<any>(null)
const [mode, setMode] = useState<'add' | 'edit' | 'default'>('default')
const [state, setFieldState] = useFieldState({
dataSource: [],
showMore: false
})
const modalRef = useRef<any>({})
const { dataSource, showMore } = state
let { value = {}, mutators, editable } = props
const transformData = transformDefaultData(dataSource)
const showDataSource = showMore ? [...transformData].splice(0, 3) : transformData
if (typeof value === 'number') {
value = dataSource.find(v => v.id === value) || {}
}
// 当前选中的id
const checkedId = value.id || dataSource[0]?.id
const handleAdd = () => {
setMode('add')
modalRef.current.setVisible(true)
}
const handleCheck = (item) => {
if (editable) {
mutators.change(item)
}
}
const reloadAddress = () => {
fetchOrderApi.getProductAddressAll().then(data => {
setFieldState({
dataSource: data,
showMore
})
})
}
const toogleMore = () => {
setFieldState({
dataSource,
showMore: !showMore
})
}
const handleDelete = async (id, e) => {
e.stopPropagation()
try {
const result = await PublicApi.postLogisticsReceiverAddressDelete({ id })
reloadAddress()
} catch (error) {
}
}
const handleEdit = async (item, e, mode?) => {
e.stopPropagation()
const { data } = await PublicApi.getLogisticsReceiverAddressGet({ id: item.id })
setFormInitValue({ ...data, isDefault: item.isDefault })
setMode(mode || 'edit')
modalRef.current.setVisible(true)
}
return (
<div style={{ width: '100%' }}>
{editable && <Button block onClick={handleAdd} icon={<PlusOutlined />}>新建地址</Button>}
<SelectStyles>
{
showDataSource.map(v => <div key={v.id} onClick={() => handleCheck(v)} className={cx('select_style_border', checkedId === v.id ? 'active' : '')}>
<div>
<Row style={{ color: '#303133' }}>
<Col>{v.receiverName}</Col>
<Col> / </Col>
<Col>{v.phone}</Col>
{v.isDefault ? <Col style={{ marginLeft: 6 }}><Tag color='default'>默认</Tag></Col> : null}
</Row>
<div style={{ color: '#909399' }}>{v.fullAddress}</div>
</div>
<Space size={12}>
{
editable ? <>
<EditOutlined onClick={(e) => handleEdit(v, e)} />
<DeleteOutlined onClick={(e) => handleDelete(v.id, e)} />
</>
:
<EyeOutlined onClick={(e) => handleEdit(v, e, 'preview')} />
}
</Space>
</div>)
}
</SelectStyles>
{transformData.length > 3 &&
<div onClick={toogleMore} style={{ textAlign: 'center', cursor: 'pointer' }}>
显示更多{showMore ? <CaretDownOutlined /> : <CaretUpOutlined />}
</div>
}
<AddressModal mode={mode} formInitValue={formInitValue} currentRef={modalRef} reloadAddress={reloadAddress} />
</div>
)
}
SelectAddress.defaultProps = {}
SelectAddress.isFieldComponent = true;
export default SelectAddress
import React, { useState, useRef, useEffect } from 'react'
import {history} from "umi"
import { Button, Radio, Row, Col, Tag, Checkbox, Modal } from 'antd'
import { ISchemaFormProps, ISchemaFieldProps, ISchemaFieldComponentProps, createFormActions, useFieldState } from '@formily/antd'
import { FilePdfFilled } from '@ant-design/icons'
import { PublicApi } from '@/services/api'
const SelectContract = (props: ISchemaFieldComponentProps) => {
let { form, value = {}, mutators, editable } = props
const popConfirm = () => {
history.push(`/memberCenter/tranactionAbility/electronicContracts/apply`)
}
const onChange = (e) => {
if(e.target.checked) {
PublicApi.getContractSignatureAuthAuthState().then(({data}) => {
if(data.state !== 1) {
// 未认证
Modal.confirm({
title: '提示',
content: '未签约电子合同, 是否要立即前往?',
onOk: popConfirm,
maskClosable: true
})
} else {
mutators.change(1)
}
})
} else {
mutators.change(0)
}
}
return (
<div style={{display: "flex", flexDirection: "column"}}>
<Checkbox onChange={onChange}>同意</Checkbox>
<Button
type="link"
icon={<FilePdfFilled />}
style={{color: "#7178ea"}}
href={`/api/order/contractTemplate/downloadContract?contractName=${props.props["x-component-props"].contract.contractName}&contractUrl=${props.props["x-component-props"].contract.contractUrl}`}
>
{
props.props["x-component-props"].contract?.contractName
}
</Button>
</div>
)
}
SelectContract.defaultProps = {}
SelectContract.isFieldComponent = true;
export default SelectContract
.invoice {
padding-bottom: 16px;
.raido_group {
position: relative;
display: block;
width: 100%;
.list_radio {
border: 1px solid #FFF;
}
.invoice_list {
position: relative;
display: flex;
margin: 0 -10px;
flex-wrap: wrap;
.invoice_list_item {
display: flex;
align-items: center;
&_content {
padding-left: 10px;
&_tag {
display: inline-block;
background-color: #909399;
padding: 0 6px;
height: 16px;
line-height: 16px;
color: #FFF;
font-size: 12px;
&.special {
background-color: #5377CE;
}
}
&_name {
display: flex;
align-items: center;
.default {
width: 64px;
height: 16px;
line-height: 16px;
text-align: center;
background: rgba(238, 238, 238, 1);
font-size: 12px;
color: #606266;
}
&>span {
margin-right: 20px;
}
}
}
&_btn_group {
display: flex;
margin-left: auto;
line-height: 14px;
// height: 14px;
.invoice_list_item_btn {
margin: 0 10px;
}
}
}
:global {
span.ant-radio+* {
display: block;
width: 100%;
}
.ant-radio-wrapper {
display: flex;
width: 100%;
align-items: center;
height: 72px;
background-color: #FAFAFA;
margin: 10px;
padding-left: 16px;
}
.ant-radio-wrapper.ant-radio-wrapper-checked {
border: 1px solid @main-color;
&::after {
content: '';
position: absolute;
width: 0;
height: 0;
border-bottom: 12px solid @main-color;
border-left: 12px solid transparent;
bottom: 0;
right: 0;
z-index: 5;
}
}
}
}
}
}
\ No newline at end of file
import React, { useState, useRef, useMemo } from 'react'
import { ISchemaFieldComponentProps, useFieldState, FormEffectHooks, createFormActions } from '@formily/antd'
import { Button, Radio } from 'antd'
import { PlusOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons'
import cx from 'classnames'
import { fetchOrderApi } from '../../apis'
import { PublicApi } from '@/services/api'
import InvoiceModal from '../invoiceModal'
import styles from './index.less'
import { PageStatus, usePageStatus } from '@/hooks/usePageStatus'
const TheInvoiceList = (props: ISchemaFieldComponentProps) => {
const [formInitValue, setFormInitValue] = useState<any>(null)
const [mode, setMode] = useState<'add' | 'edit' | 'default' | 'preview' | 'delete'>('default')
const modalRef = useRef<any>({})
let { value, mutators, form, editable } = props
const [state, setFieldState] = useFieldState({
dataSource: [],
showMore: false,
useValue: null
})
const { dataSource, showMore, useValue } = state
const { pageStatus, id } = usePageStatus()
// const [useValue, setUseValue] = useState(() => typeof value === 'object' ? value : dataSource.find(v => v.id === value))
// let useValue = typeof value === 'object' ? value : dataSource.find(v => v.id === value)
if(pageStatus === PageStatus.ADD) {
if(typeof value === 'object') {
setFieldState({
dataSource,
showMore,
useValue: value
})
}
} else if(pageStatus === PageStatus.EDIT){
// @bug todo 编辑情况下 默认显示有问题 固定第一个
// console.log(value, mode, dataSource, 'EDIT')
if(typeof value === 'object') {
// let target = (mode === 'add' || mode === 'delete') ? dataSource[0] : value
let target = value;
if(mode === 'add' || mode === 'delete') {
target = dataSource[0]
} else if(mode === 'edit') {
target = dataSource.find(v => v.id === value.id)
}
setFieldState({
dataSource,
showMore,
useValue: target
})
// console.log('isObject', target)
mutators.change(target)
} else {
let target = dataSource.length ? dataSource.find(v => v.id === value) : value
setFieldState({
dataSource,
showMore,
useValue: target
})
// console.log('notObject', target)
mutators.change(target)
}
}
const transformDefaultData = (data: any[]) => {
if (data.length === 0) return data
const hasDefault = data.some(v => v.isDefault === 1)
return hasDefault ? data : data.map((v,i) => {
if (i === 0) {
v.isDefault = 1
}
return v
})
}
const transformData = transformDefaultData(dataSource)
const showDataSource = showMore ? [...transformData].splice(0, 3) : transformData
const handleAdd = () => {
setMode('add')
modalRef.current.setVisible(true)
}
const handleCheck = (item) => {
// 选中的id
mutators.change(item)
}
const reload = () => {
fetchOrderApi.getInvoicesList().then(data => {
if(!data.length) {
form.setFieldValue("needTheInvoice", 0)
}
// 订单新增 重载全部置为第一个
let _data = data.sort((a, b) => b.id - a.id)
if(pageStatus === PageStatus.ADD) {
setFieldState({
dataSource: _data,
showMore,
useValue: _data[0],
})
mutators.change(_data[0])
} else if(pageStatus === PageStatus.EDIT) {
setFieldState({
dataSource: _data,
showMore,
useValue,
})
}
})
}
const toogleMore = () => {
setFieldState({
dataSource,
showMore: !showMore,
useValue,
})
}
const handleDelete = async (id, e) => { // 选中当前的删除
e.stopPropagation()
try {
const result = await PublicApi.postSettleAccountsInvoiceMessageDelete({id})
if(result.code === 1000) {
reload()
setMode('delete')
}
} catch (error) {
}
}
const handleEdit = async (item, e, mode?) => {
e.stopPropagation()
const { data } = await PublicApi.getSettleAccountsInvoiceMessageDetails({id: item.id})
setFormInitValue({...data, isDefault: item.isDefault})
setMode(mode || 'edit')
modalRef.current.setVisible(true)
}
const handleSetDefault = async (item, e) => {
e.stopPropagation()
const { data } = await PublicApi.postSettleAccountsInvoiceMessageUpdate({...item, isDefault: item.isDefault ? 0 : 1})
reload()
}
// @tofix bug 添加或删除发票后 useValue Radio默认值是操作的数据 导致无法选中
// console.log(useValue, 'useValue', dataSource, 'dataSource', mode, value, 'value')
return (
<div style={{width: '100%'}} className={styles.invoice}>
{ editable && <Button block onClick={handleAdd} icon={<PlusOutlined/>}>新增发票</Button> }
<Radio.Group className={styles.raido_group} value={useValue} onChange={e => handleCheck(e)}>
<div className={styles.invoice_list}>
{
showDataSource.map((item, index) => (
<Radio className={styles.list_radio} value={item} key={`address_list_radio_${item?.id}`}>
<div className={styles.invoice_list_item} key={`invoice_list_item_${index}`}>
<div className={styles.invoice_list_item_content}>
<div className={cx(styles.invoice_list_item_content_tag, item.kind !== 1 ? styles.special : '')}>{item.kind === 1 ? '增值税普通发票' : '增值税专用发票'}</div>
<div className={styles.invoice_list_item_content_name}>
<span>{item.invoiceTitle}</span>
<span>({item.type === 1 ? '企业' : '个人'})</span>
{
item.isDefault === 1 ? <div className={styles.default}>默认</div> :
<div className={styles.set_default} onClick={e => handleSetDefault(item, e)}>设为默认</div>
}
</div>
</div>
{
useValue?.id === item?.id && (
editable ?
<div className={styles.invoice_list_item_btn_group}>
<div className={styles.invoice_list_item_btn} onClick={(e) => handleEdit(item, e)}>编辑</div>
<div className={styles.invoice_list_item_btn} onClick={(e) => handleDelete(item?.id, e)}>删除</div>
</div>
:
<div className={styles.invoice_list_item_btn_group}>
<div className={styles.invoice_list_item_btn} onClick={(e) => handleEdit(item, e, 'preview')}>查看</div>
</div>
)
}
</div>
</Radio>
))
}
</div>
</Radio.Group>
{ transformData.length > 3 &&
<div onClick={toogleMore} style={{textAlign: 'center', cursor: 'pointer'}}>
显示更多{showMore ? <CaretDownOutlined /> : <CaretUpOutlined/>}
</div>
}
<InvoiceModal mode={mode} formInitValue={formInitValue} currentRef={modalRef} reload={reload}/>
</div>
)
}
TheInvoiceList.defaultProps = {}
TheInvoiceList.isFieldComponent = true;
export default TheInvoiceList
import React from 'react'
import { formatTimeString } from '@/utils'
import { Row } from 'antd'
import { DELIVERY_TYPE, OrderModalType } from '@/constants/order'
import { AddressPop } from '@/pages/transaction/components/addressPop'
// 简单控制价格区间的组件
// @todo 后续需要优化, 样式,目录文件等。
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>
}
/** 修改b2b询价报价下单 初始值转换 */
export const procurmentRenderInit = (initValue: any) => {
return {
...initValue.requirement.detail,
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,
}
}
/** 修改b2b询价报价下单 回显商品字段转换 */
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,
}
})
}
/** B2B询价报价下单 字段转换 */
export const procurementProcessField = (value) => {
value.products = value.products.map(item => {
return {
...item,
productId: item.commodityId,
skuId: item.productId,
name: item.productName,
logo: item.imgUrl,
quantity: item.purchaseCount,
logisticsTemplateId: item.logistics.templateId,
weight: item.logistics.weight,
stockId: item.upperCommoditySkuId,
stock: item.stockCount,
// 上游字段
supplyMemberId: item.upperMemberId,
supplyRoleId: item.upperMemberRoleId,
supplyMemberName: item.upperMemberName,
}
})
return value
}
/***********控制订单模式联动其他字段的数组集合 *******/
export const orderCombination = {
// 是否显示报价单字段
showQuotationField: [
OrderModalType.INQUIRY_QUOTATION_ORDER,
],
// 是否显示报价单按钮
showQuotationSelectBtn: [
OrderModalType.INQUIRY_QUOTATION_ORDER,
],
// 是否显示采购合同字段
showPurchaseContractField: [
OrderModalType.PURCHASE_ENQUIRY_CONTRACT_ORDER,
OrderModalType.PURCHASE_TENDER_CONTRACT_ORDER,
OrderModalType.PURCHASE_BIDDING_CONTRACT_ORDER
],
// 是否显示选择采购合同按钮
showPurchaseContractBtn: [
OrderModalType.PURCHASE_ENQUIRY_CONTRACT_ORDER,
OrderModalType.PURCHASE_TENDER_CONTRACT_ORDER,
OrderModalType.PURCHASE_BIDDING_CONTRACT_ORDER
],
}
export const orderTypeLabelMap = {
'3': '询价采购',
'12': '采购询价合同',
'13': '采购竞价合同',
'14': '采购招标合同',
}
// 支付方式
export const payTypeLabel = [
{
label: '线上支付',
value: 1
},
{
label: '线下支付',
value: 2
},
{
label: '授信支付',
value: 3
},
{
label: '货到付款',
value: 4
},
{
label: '账期',
value: 5
},
{
label: '月结',
value: 6
},
{
label: '合同内清算',
value: 7
},
]
export const memberColumns: any[] = [
{
title: '会员ID',
dataIndex: 'memberId',
align: 'center',
key: 'memberId',
},
{
title: '会员名称',
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: '公司类型',
dataIndex: 'memberTypeName',
align: 'center',
key: 'memberTypeName',
},
{
title: '公司角色',
dataIndex: 'roleName',
align: 'center',
key: 'roleName',
},
{
title: '公司等级',
dataIndex: 'levelTag',
align: 'center',
key: 'levelTag',
},
]
export const inquiryColumns: any[] = [
{
title: '报价单号',
dataIndex: 'quotationNo',
align: 'center',
key: 'quotationNo',
},
{
title: '询价单号',
dataIndex: 'inquiryListNo',
align: 'center',
key: 'inquiryListNo',
},
{
title: '报价单摘要',
dataIndex: 'details',
align: 'center',
key: 'details',
},
{
title: '报价会员',
dataIndex: 'offerMemberName',
align: 'center',
key: 'offerMemberName',
},
{
title: '单据时间',
dataIndex: 'voucherTime',
align: 'center',
key: 'voucherTime',
render: _ => formatTimeString(_)
}
]
export const paymentInformationColumns: any[] = [
{
title: '支付次数',
dataIndex: 'batchNo',
key: 'batchNo'
},
{
title: '支付环节',
dataIndex: 'payNode',
key: 'payNode'
},
{
title: '外部状态',
dataIndex: 'outerStatusName',
key: 'outerStatusName',
},
{
title: '支付比例',
dataIndex: 'payRate',
key: 'payRate',
editable: true,
forceEdit: true,
formItem: 'input',
formItemProps: {
addonAfter: '%',
disabled: true
},
width: 200,
render: text => text + '%'
},
{
title: '支付金额',
dataIndex: 'payPrice',
key: 'payPrice'
},
{
title: '支付方式',
dataIndex: 'payType',
key: 'payType',
formItem: 'select',
editable: true,
forceEdit: true,
formItemProps: {
options: []
},
width: 200
},
{
title: '支付渠道',
dataIndex: 'payChannel',
key: 'payChannel',
formItem: 'select',
editable: true,
forceEdit: true,
width: 200
},
]
// 商品列表
export const productInfoColumns: any[] = [
{
title: 'ID',
dataIndex: 'productId',
align: 'center',
key: 'productId',
},
{
title: '商品名称',
dataIndex: 'productName',
align: 'center',
key: 'productName',
},
{
title: '品类',
dataIndex: 'category',
align: 'center',
key: 'category',
},
{
title: '品牌',
dataIndex: 'brand',
align: 'center',
key: 'brand',
},
{
title: '单位',
dataIndex: 'unit',
align: 'center',
key: 'unit',
},
{
title: '单价(元)',
dataIndex: 'unitPrice',
align: 'left',
key: 'unitPrice',
},
{
title: '库存',
dataIndex: 'stockCount',
align: 'center',
key: 'stockCount',
},
{
title: '采购数量',
dataIndex: 'purchaseCount',
align: 'center',
key: 'purchaseCount',
formItem: 'input',
editable: true,
width: 140
},
{
title: '含税',
dataIndex: 'taxInclusive',
align: 'center',
key: 'taxInclusive',
render: (t, r) => r.taxRate ? '是' : '否'
},
{
title: '税率',
dataIndex: 'taxRate',
align: 'center',
key: 'taxRate',
render: (t, r) => t ? `${t}%` : null
},
{
title: '金额',
dataIndex: 'money',
align: 'center',
key: 'money',
},
// 接口调用
{
title: '配送方式',
dataIndex: 'deliveryType',
align: 'center',
key: 'deliveryType',
render: (t, r) => {
if(t === 1)
return "物流(默认)"
else if(t === 2)
return <AddressPop pickInfo={r.logistics.render}>自提</AddressPop>
else if(t === 3)
return "无需配送"
}
},
{
title: '操作',
dataIndex: 'ctl',
align: 'center',
key: 'ctl',
},
]
import { ISchemaFormActions, FormEffectHooks, ISchemaFormAsyncActions } from '@formily/antd';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import { useLinkageUtils } from '@/utils/formEffectUtils';
import { fetchOrderApi } from '../apis';
import { PublicApi } from '@/services/api';
// 异步填充表格字段
const asyncPadDataForProduct = async (ctx: ISchemaFormActions | ISchemaFormAsyncActions, productValue: any) => {
const productData = productValue.value
const loading = productValue.loading
if (productData.length === 0 || loading) {
return false
}
ctx.setFieldState(productValue.path, state => {
state.loading = true
})
const newData = productData.map((v, i) => {
//@ b2b订单不考虑会员折扣 字段固定100
v.discount = 100
return v
})
ctx.setFieldValue('products', newData)
ctx.setFieldState(productValue.path, state => {
state.loading = false
})
}
export const useModelTypeChange = (callback) => {
// 下单模式发生改变时
FormEffectHooks.onFieldValueChange$('orderMode').subscribe(state => {
callback(state)
})
}
export const useEditHideField = () => {
const { pageStatus } = usePageStatus()
const utils = useLinkageUtils()
FormEffectHooks.onFormInit$().subscribe(() => {
if (pageStatus === PageStatus.ADD) {
utils.hide('orderNo')
utils.hide('createTime')
}
})
}
export const useProductTableChangeForPay = (ctx: ISchemaFormActions | ISchemaFormAsyncActions, update) => {
const { pageStatus } = usePageStatus()
let sumPrice = 0;
FormEffectHooks.onFieldValueChange$('sumPrice').subscribe(state => {
sumPrice = state.value
})
FormEffectHooks.onFieldValueChange$('products').subscribe(state => {
const { value } = state
// 强制渲染一次, 用于触发金额总数
update()
const orderMode = ctx.getFieldValue('orderMode')
if (value && value.length > 0 && !state.loading){ // 添加loading判断避免二次调用
// 请求一次并复制给支付信息
const productItem = value[0]
if(pageStatus === PageStatus.ADD) { // 新增下 需要支付信息生成支付次数
ctx.setFieldValue('payments', []) // 变动后先 清空支付信息
const shopId = ctx.getFieldValue('shopId')
const products = value.map(item => ({ productId: item.commodityId, skuId: item.productId }))
if(shopId && products?.length) {
// 判断不存在物流 隐藏交付地址
if(!value.some(item => item.logistics.deliveryType === 1)) {
ctx.setFieldState('deliveryAddresId', state => state.visible = false )
} else {
ctx.setFieldState('deliveryAddresId', state => state.visible = true )
}
fetchOrderApi.getPayInfoList({
products: products,
memberId: productItem?.memberId,
roleId: productItem?.memberRoleId,
orderMode: orderMode,
shopId: shopId
}).then(data => {
ctx.setFieldValue('payments', data.map(item => ({
...item,
payPrice: (sumPrice * Number(item.payRate) / 100).toFixed(2)
})))
}).catch(err => { })
}
}
}
// 确认后 需根据商品id请求会员折扣接口,以及配送方式
// 由于商品存在多个, 需对接口做一定缓存
asyncPadDataForProduct(ctx, state)
const numberInputs = document.getElementsByClassName("purchase_amount_input")
if(numberInputs?.length) {
for(let i = 0; i < numberInputs.length; i++) {
numberInputs[i].removeAttribute("disabled")
}
}
})
}
// 表单初始化时,对应操作
export const useOrderFormInitEffect = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
FormEffectHooks.onFormMount$().subscribe(async () => {
// 写入收货地址数据
useProductAddress(ctx)
})
FormEffectHooks.onFieldValueChange$('hasInvoice').subscribe(state => {
if (state.value) {
useInvoiceList(ctx)
}
})
}
export const useProductAddress = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
fetchOrderApi.getProductAddressAll().then(data => {
ctx.setFieldState('deliveryAddresId', state => {
if (data.length > 0 && !state.value) {
// 初始化时存在数据, 默认帮用户选中第一个(默认地址)
state.value = data[0]
}
state.dataSource = data
state.showMore = data.length > 3
})
})
}
// 获取发票信息
export const useInvoiceList = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
fetchOrderApi.getInvoicesList().then(data => {
ctx.setFieldState('theInvoiceId', state => {
if (data.length > 0 && !state.value) {
// 初始化时存在数据, 默认帮用户选中第一个
state.value = data[0]
}
state.dataSource = data
state.showMore = data.length > 3
})
})
}
// 高级筛选schema中用于输入搜索商品品类的Effect
/**
* @param ctx 外部表单action
* @param mctx 模态框表单action
* @param fieldName 字段名称
*/
export const searchCustomerCategoryOptionEffect = (ctx: any, mctx: any, fieldName: string) => {
const params: any = {}
params['memberId'] = ctx.getFieldValue('vendorMemberId')
params['memberRoleId'] = ctx.getFieldValue('vendorRoleId')
mctx.getFieldState(fieldName, state => {
PublicApi.getProductCustomerGetMemberCustomerCategoryTree(params).then(res => {
mctx.setFieldState(fieldName, state => {
state.props['x-component-props'].dataoption = res.data
})
})
})
}
This diff is collapsed.
import React, { useState, useEffect } from 'react'
import { OrderModalType } from '@/constants/order'
import { PublicApi } from '@/services/api'
import { useLocation, history } from 'umi'
import { ISchemaFormActions } from '@formily/antd'
import { useLinkageUtils } from '@/utils/formEffectUtils'
interface DetailOrderLocationState {
// 进货单商品列表
productList?: any[],
// 下单模式
modelType?: OrderModalType
}
interface DetailOptionsProps {
addSchemaAction: ISchemaFormActions
}
const mockDefaultValue: DetailOrderLocationState = {
productList: [
{
id: 1,
name: '甲商品',
customerCategoryName: '假品类',
brandName: '假品牌'
}
],
modelType: 5
}
export const useDetailOrder = (options: DetailOptionsProps) => {
const { addSchemaAction } = options
const formilyUtils = useLinkageUtils()
// const [productDataSource, setProductDataSource] = useState
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])
// 唤起新增订单
const fetchAddOrder = async (params) => {
await PublicApi.postOrderProcurementOrderAdd(params)
}
return {
showProBtn,
setShowProBtn,
showMemberType,
setShowMemberType,
fetchAddOrder,
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 { paymentInformationColumns } from '../constant'
import { PayInfoCell, EditableRow } from '../components/payInfoTableCell'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { useEffect, useState, useRef } from 'react'
import { PublicApi } from '@/services/api'
export const usePaymentInfo = (ctx: ISchemaFormActions | ISchemaFormAsyncActions, products: any = []): any => {
const paywayData = useRef<any>({})
const [columns, setColumns] = useState<any[]>(paymentInformationColumns)
const markRef = useRef<boolean>(true)
// const { schemaActions, detailData } = useContext(ReadyAddOrderDetailContext)
const components = {
body: {
row: EditableRow,
cell: PayInfoCell
},
}
useEffect(() => {
// 商品有传入时 调用支付方式api
if(products.length && markRef.current) {
getPayLists(products[0].memberId, products[0].memberRoleId)
markRef.current = false
}
}, [products])
const initPayWayList = (memberId, memberRoleId) => {
let result = []
PublicApi.getOrderBuyerCreateB2bPayTypes({vendorMemberId: memberId, vendorRoleId: memberRoleId}).then(res => {
const { data = [], code } = res
for (let item of data) {
result.push({
payTypeName: item.payTypeName,
payType: item.payType,
payChannels: [...item.payChannels]
})
}
})
return result
}
const getPayLists = (memberId, memberRoleId) => {
PublicApi.postOrderBuyerCreateB2bPaymentFind({
memberId,
roleId: memberRoleId,
shopId: products[0]['shopId'],
orderMode: products[0]['orderMode'],
products: products.map(item => ({ productId: item.commodityId, skuId: item.productId }))
}, { ctlType: 'none' }).then(res => {
const { code, data } = res
// const sumPrice = ctx.getFieldValue('sumPrice')
if (code === 1000) {
// // 设置支付信息
// ctx.setFieldValue('payments', data.map(item => ({
// ...item,
// payPrice: (sumPrice * Number(item.payRate) / 100).toFixed(2)
// })))
// 设置支付方式
const newColumns = [...columns]
newColumns[5].formItemProps.options = initPayWayList(memberId, memberRoleId)
paywayData.current = data
setColumns(newColumns)
}
})
}
const handleSave = row => {
return new Promise((resolve, reject) => {
const newData = [...ctx.getFieldValue('payments')];
const index = newData.findIndex(item => row.batchNo === item.batchNo);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
ctx.setFieldValue('payments', newData)
resolve({item, newData})
})
};
return [
columns,
components,
handleSave
]
}
import React, { 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 { OrderModalType } from '@/constants/order';
const { pageStatus } = usePageStatus()
let orderMode = null;
// 对象按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
return Number((record.price * purchaseCount).toFixed(2))
}
/**
* @param ctx schemaAction
*/
export const useProductTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const productRef = useRef<any>({})
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type: 'checkbox'})
orderMode = ctx.getFieldValue('orderMode')
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('paymentInformationResponses', [])
}
}
const [productColumns, setProductColumns] = useState(() => {
if (pageStatus === PageStatus.ADD) {
// 渲染操作
productInfoColumns[productInfoColumns.length - 1].render = (text, record) => <Button type='link' onClick={() => handleDelete(record)}>删除</Button>
// 渲染单价
productInfoColumns[5].render = (t, r) => {
if(orderMode === OrderModalType["HAND_ORDER"]) {
return <PriceComp priceSection={r.unitPrice}/>
} else {
return r.price ? <span style={{color: 'red'}}>{r.price}</span> : <PriceComp priceSection={r.unitPrice}/>
}
}
// 渲染商品ID
productInfoColumns[0].render = (t, r) => {
if(orderMode === OrderModalType["HAND_ORDER"]) {
return r.id
} else {
return r.productId || 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 supplyMembersId = ctx.getFieldValue('supplyMembersId')
if (supplyMembersId) {
productRef.current.setVisible(true)
} else {
message.error('请先选择供应会员')
}
}
const productAddButton = <Button onClick={handleShowProduct} block type='default' style={{margin: '24px auto'}}>选择订单商品</Button>
const productComponents = {
body: {
row: ProductEditableRow,
cell: ProductTableCell
}
}
const handleSave = row => {
const { pageStatus } = usePageStatus()
// 商品采购数量变动 清空之前的支付信息
if (pageStatus === PageStatus.ADD) {
ctx.setFieldValue('paymentInformationResponses', [])
}
return new Promise((resolve, reject) => {
const newData = [...ctx.getFieldValue('products')];
console.log(newData, row)
const index = newData.findIndex(item => row.productId === item.productId);
const item = newData[index];
row['money'] = getUnitPriceTotal(row)
row['productId'] = row.productId
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 { GlobalConfig } from '@/global/config';
import moment from 'moment'
// 将获取的商城转化为可用类型
const getShopTypeMap = (() => {
return GlobalConfig.web.shopInfo.filter(item => (item.type === 1) && (item.environment === 1)).map(item => ({
label: item.name,
value: item.id,
type: item.type,
environment: item.environment,
}))
})()
// 基本信息
const basicInfo: ISchema = {
"x-index": 0,
type: 'object',
"x-component": 'tabpane',
"x-component-props": {
tab: '基本信息',
className: 'useConnectBtnWrapper'
},
properties: {
NO_SUBMIT_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 4,
labelAlign: 'left',
wrapperCol: 10
},
properties: {
orderMode: {
type: 'number',
required: true,
default: 5,
enum: [{
label: '进货单下单',
value: 5
}],
title: '下单模式',
readOnly: true,
},
shopId: {
type: 'number',
enum: getShopTypeMap,
title: '适应商城',
required: true,
},
digest: {
type: 'string',
title: '订单摘要',
"x-rules": [
{
required: true,
message: '请输入订单摘要'
},
{
limitByte: true,
maxByte: 60
}
]
},
supplyMembersName: {
type: 'string',
title: '采购会员',
"x-component-props": {
disabled: true,
addonAfter: "{{orderMember}}"
},
required: true,
},
vendorMemberName: {
type: 'string',
title: '供应会员',
"x-component-props": {
disabled: true,
},
required: true,
},
vendorMemberId: {
type: 'string',
display: false
},
vendorRoleId: {
type: 'string',
display: false
},
idList: {
type: 'array',
display: false
},
productType: {
type: 'number',
display: false
},
orderNo: {
type: 'string',
title: '订单编号',
"x-component": 'text',
visible: false
},
type: {
type: 'string',
title: '订单类型',
"x-component": 'text',
},
createTime: {
type: 'string',
title: '下单时间',
visible: false
},
interiorState: {
type: 'string',
title: '内部状态',
visible: false
},
externalState: {
type: 'string',
title: '外部状态',
visible: false
},
sumPrice: {
type: 'number',
title: '总价',
visible: false,
},
freight: {
type: 'number',
title: '运费',
visible: false,
}
}
},
}
}
// 订单商品
export const orderProduct: ISchema = {
"x-index": 2,
type: 'object',
"x-component": 'tabpane',
"x-component-props": {
tab: '订单商品'
},
properties: {
products: {
type: 'array',
"x-component": 'MultTable',
"x-component-props": {
rowKey: 'id',
columns: "{{productColumns}}",
components: "{{productComponents}}",
},
},
NO_SUBMIT_SPY: {
type: 'object',
"x-component": "moneyTotalBox"
}
}
}
// 支付信息
export const payInfo: ISchema = {
"x-index": 3,
type: 'object',
"x-component": 'tabpane',
"x-component-props": {
tab: '支付信息',
},
properties: {
payments: {
type: 'array',
"x-component": 'MultTable',
"x-component-props": {
rowKey: 'payCount',
columns: "{{paymentColumns}}",
components: "{{paymentComponents}}"
},
// default: [
// {
// payCount: 1,
// id: 1,
// payRatio: 123
// }
// ]
}
}
}
// 交付信息
const submitInfo: ISchema = {
"x-index": 1,
type: 'object',
"x-component": 'tabpane',
"x-component-props": {
tab: '交付信息'
},
properties: {
NO_SUBMIT_LAYOUT_2: {
type: 'object',
"x-component": 'mega-layout',
'x-component-props': {
labelCol: 6,
labelAlign: 'left',
grid: true,
columns: 2,
// full: true
},
properties: {
FLEX_LAYOUT_LEFT: {
type: 'object',
"x-component": 'mega-layout',
properties: {
deliverDate: {
type: 'string',
"x-component": 'date',
title: '交付日期',
required: true,
"x-component-props": {
disabledDate: current => {
return current && current < moment().startOf('day')
},
style: { width: 400 }
}
},
}
},
deliveryAddresId: {
type: 'string',
"x-component": 'SelectAddress',
// "x-mega-props": {
// style: {
// full: true
// }
// },
"x-component-props": {
dataSource: [],
times: 0,
},
"x-rules": [
{
required: true,
message: '请选择收货方式'
}
],
title: '收货方式'
}
}
}
}
}
// 其他信息
const ortherInfo: ISchema = {
"x-index": 4,
type: 'object',
"x-component": 'tabpane',
"x-component-props": {
tab: '其他信息'
},
properties: {
NO_SUBMIT_LAYOUT_ORTHER: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'left',
labelCol: 4,
wrapperCol: 10
},
properties: {
hasInvoice: {
type: 'boolean',
"x-component": 'CheckboxSingle',
"x-component-props": {
children: '需要发票',
style: {
marginTop: 4,
}
},
title: '发票',
default: false,
"x-linkages": [
{
type: 'value:visible',
target: 'theInvoiceId',
condition: "{{!!$value}}"
}
]
},
theInvoiceId: {
type: 'number',
title: ' ',
"x-component": "theInvoiceList",
"x-component-props": {
times: 0,
}
},
pageRequire: {
type: 'string',
"x-component": 'textarea',
"x-component-props": {
rows: 4
},
title: '包装要求',
"x-rules": [
{
limitByte: true,
maxByte: 100
}
]
},
restsRequire: {
type: 'string',
"x-component": 'textarea',
"x-component-props": {
rows: 4
},
title: '其他要求',
"x-rules": [
{
limitByte: true,
maxByte: 100
}
]
},
}
}
}
}
// 新增订单详情
export const orderDetailSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT_TABS: {
type: 'object',
"x-component": 'tab',
properties: {
basicInfo,
submitInfo,
orderProduct,
payInfo,
ortherInfo,
}
}
}
}
// 一级审核详情
export const auditOneSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT_TABS: {
type: 'object',
"x-component": 'tab',
properties: {
basicInfo,
submitInfo,
orderProduct,
payInfo,
ortherInfo,
}
}
}
}
// 新增时使用的schema
export const orderAddSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT_TABS: {
type: 'object',
"x-component": 'tab',
properties: {
basicInfo,
submitInfo,
orderProduct,
payInfo,
ortherInfo,
}
}
}
}
// 确认电子合同
export const orderElectronicSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT_TABS: {
type: 'object',
"x-component": 'tab',
properties: {
basicInfo,
submitInfo,
orderProduct,
payInfo,
ortherInfo,
}
}
}
}
// 根据传入的query参数 判断当前使用哪个schema
export const mergeAllSchemas = {
// 新增订单详情
"-1": orderDetailSchema,
0: orderAddSchema,
// 一级审核详情
1: auditOneSchema,
// 二级审核详情
2: auditOneSchema,
// 待提交订单详情
3: orderDetailSchema,
// 电子合同详情
4: orderElectronicSchema,
// 订单支付
5: orderDetailSchema
}
import { ISchema } from '@formily/antd';
export const memberSchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
"x-component": 'Search',
"x-component-props": {
placeholder: '请输入会员名称'
}
}
}
}
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