Commit 02f58e41 authored by 前端-许佳敏's avatar 前端-许佳敏

交易-采购订单-新增

parent 4817eb3c
import React, { useState, useEffect } from 'react'
import { IAntdSchemaFormProps } from '@formily/antd'
import { Modal } from 'antd'
import NiceForm from '../NiceForm'
export interface ModalFormProps extends IAntdSchemaFormProps {
confirm?(),
cancel?(),
closeabled?: boolean
modalTitle?: string,
currentRef?: any,
width?: number
}
const ModalForm:React.FC<ModalFormProps> = (props) => {
const { width = 704, confirm, cancel, modalTitle, currentRef, closeabled = true, actions, ...restProps } = props
const [visible, setVisible] = useState<boolean>(false)
useEffect(() => {
if (currentRef) {
currentRef.current = {
visible,
setVisible
}
}
}, [])
const handleConfirm = () => {
// 是否需要关闭弹窗, 默认关闭
confirm && confirm()
}
const handleCancel = () => {
setVisible(false)
cancel && cancel()
}
return (
<Modal
width={width}
title={modalTitle}
onOk={handleConfirm}
onCancel={handleCancel}
visible={visible}
>
<NiceForm
actions={actions}
{...restProps}
/>
</Modal>
)
}
ModalForm.defaultProps = {}
export default ModalForm
\ No newline at end of file
...@@ -2,6 +2,13 @@ import React, { ReactText, useRef, useEffect } from 'react' ...@@ -2,6 +2,13 @@ import React, { ReactText, useRef, useEffect } from 'react'
import {StandardTable} from 'god' import {StandardTable} from 'god'
import { IStandardTableProps } from 'god/dist/src/standard-table' import { IStandardTableProps } from 'god/dist/src/standard-table'
import { Row, Col, Modal } from 'antd' import { Row, Col, Modal } from 'antd'
import { productModalSchema, productModalByMemberSchema, memberModalSchema, inquirySchema, demandSchema } from './schema'
import Search from '../NiceForm/components/Search'
import SearchSelect from '../NiceForm/components/SearchSelect'
import Submit from '../NiceForm/components/Submit'
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch'
import { FORM_FILTER_PATH } from '@/formSchema/const'
import DateSelect from '../NiceForm/components/DateSelect'
export interface ModalTableProps extends IStandardTableProps<any> { export interface ModalTableProps extends IStandardTableProps<any> {
width?: number, width?: number,
...@@ -9,11 +16,12 @@ export interface ModalTableProps extends IStandardTableProps<any> { ...@@ -9,11 +16,12 @@ export interface ModalTableProps extends IStandardTableProps<any> {
confirm?(), confirm?(),
cancel?(), cancel?(),
visible?: boolean, visible?: boolean,
resetModal?: object resetModal?: object,
modalType?: 'productByDefault' | 'productByMember' | 'memberByDefault' | 'inquiryByDefault' | 'demandByDefault' | 'none'
} }
const ModalTable:React.FC<ModalTableProps> = (props) => { const ModalTable:React.FC<ModalTableProps> = (props) => {
const { width = 704,modalTitle, confirm, cancel, visible, currentRef, resetModal, ...resetTable } = props const { width = 704,modalTitle, confirm, cancel, visible, currentRef, resetModal, modalType = 'none', ...resetTable } = props
const selfRef = currentRef || useRef<any>({}) const selfRef = currentRef || useRef<any>({})
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
...@@ -25,6 +33,31 @@ const ModalTable:React.FC<ModalTableProps> = (props) => { ...@@ -25,6 +33,31 @@ const ModalTable:React.FC<ModalTableProps> = (props) => {
}) })
} }
}, [visible, selfRef.current]) }, [visible, selfRef.current])
const modelSchemaRender = () => {
switch (modalType) {
case 'productByDefault': {
return productModalSchema
}
case 'productByMember': {
return productModalByMemberSchema
}
case 'memberByDefault': {
return memberModalSchema
}
case 'inquiryByDefault': {
return inquirySchema
}
case 'demandByDefault': {
return demandSchema
}
case 'none': {
return {}
}
}
}
return ( return (
<Modal <Modal
width={width} width={width}
...@@ -41,6 +74,22 @@ const ModalTable:React.FC<ModalTableProps> = (props) => { ...@@ -41,6 +74,22 @@ const ModalTable:React.FC<ModalTableProps> = (props) => {
<Col span={18}>{child}</Col> <Col span={18}>{child}</Col>
<Col style={{marginTop: 4}}>{ps}</Col> <Col style={{marginTop: 4}}>{ps}</Col>
</Row>} </Row>}
formilyProps={
modalType === 'none' ? null : {
ctx: {
schema: modelSchemaRender(),
components: { ModalSearch: Search, SearchSelect, Submit, DateSelect } ,
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
actions,
'name',
FORM_FILTER_PATH,
);
}
}
}
}
{...resetTable} {...resetTable}
> >
</StandardTable> </StandardTable>
......
import { ISchema } from '@formily/antd';
import { PublicApi } from '@/services/api';
import { FORM_FILTER_PATH } from '@/formSchema/const';
export const productModalByMemberSchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
'x-component': 'ModalSearch',
'x-component-props': {
placeholder: '请输入商品名称/ID',
align: 'flex-left',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
flexWrap: 'nowrap',
style: {
marginRight: 0
}
},
colStyle: {
marginTop: 20,
},
},
properties: {
categoryId: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '请选择品类',
className: 'fixed-ant-selected-down', // 该类强制将显示的下拉框出现在select下, 只有这里出现问题, ??
fetchSearch: PublicApi.getProductSelectGetSelectCustomerCategory,
style: {
width: 160
}
}
},
brandId: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '请选择品牌',
fetchSearch: PublicApi.getProductSelectGetSelectBrand,
style: {
width: 160
}
}
},
submit: {
"x-component": 'Submit',
"x-mega-props": {
span: 1
},
"x-component-props": {
children: '查询'
}
}
}
}
}
}
export const productModalSchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
'x-component': 'ModalSearch',
'x-component-props': {
placeholder: '请输入商品名称/ID',
align: 'flex-left',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
flexWrap: 'nowrap',
style: {
marginRight: 0
}
},
colStyle: {
marginTop: 20,
},
},
properties: {
categoryId: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '请选择品类',
className: 'fixed-ant-selected-down', // 该类强制将显示的下拉框出现在select下, 只有这里出现问题, ??
fetchSearch: PublicApi.getProductSelectGetSelectCategory,
style: {
width: 160
}
}
},
brandId: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '请选择品牌',
fetchSearch: PublicApi.getProductSelectGetSelectBrand,
style: {
width: 160
}
}
},
submit: {
"x-component": 'Submit',
"x-mega-props": {
span: 1
},
"x-component-props": {
children: '查询'
}
}
}
}
}
}
export const memberModalSchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
"x-component": 'Search',
"x-component-props": {
placeholder: '请输入会员名称'
}
}
}
}
export const inquirySchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
'x-component': 'ModalSearch',
'x-component-props': {
placeholder: '报价单号/需求单号/报价单摘要',
align: 'flex-left',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
flexWrap: 'nowrap',
style: {
marginRight: 0
}
},
colStyle: {
marginTop: 20,
},
},
properties: {
// @todo 需调整字段名
categoryId: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '报价会员(全部)',
className: 'fixed-ant-selected-down', // 该类强制将显示的下拉框出现在select下, 只有这里出现问题, ??
fetchSearch: PublicApi.getProductSelectGetSelectCategory,
style: {
width: 160
}
}
},
"[startDocumentsTime,endDocumentsTime]": {
type: 'string',
"x-component": "dateSelect",
"x-component-props": {
placeholder: '单据时间(全部)',
}
},
submit: {
"x-component": 'Submit',
"x-mega-props": {
span: 1
},
"x-component-props": {
children: '查询'
}
}
}
}
}
}
export const demandSchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
'x-component': 'ModalSearch',
'x-component-props': {
placeholder: '报价单号/需求单号/报价单摘要',
align: 'flex-left',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
flexWrap: 'nowrap',
style: {
marginRight: 0
}
},
colStyle: {
marginTop: 20,
},
},
properties: {
// @todo 需调整字段名
categoryId: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '报价会员(全部)',
className: 'fixed-ant-selected-down', // 该类强制将显示的下拉框出现在select下, 只有这里出现问题, ??
fetchSearch: PublicApi.getProductSelectGetSelectCategory,
style: {
width: 160
}
}
},
"[startDocumentsTime,endDocumentsTime]": {
type: 'string',
"x-component": "dateSelect",
"x-component-props": {
placeholder: '单据时间(全部)',
}
},
submit: {
"x-component": 'Submit',
"x-mega-props": {
span: 1
},
"x-component-props": {
children: '查询'
}
}
}
}
}
}
\ No newline at end of file
...@@ -16,7 +16,7 @@ const getPrevTime = (num, flag) => { ...@@ -16,7 +16,7 @@ const getPrevTime = (num, flag) => {
} }
const DateSelect = (props) => { const DateSelect = (props) => {
const { value = [], mutators } = props const { value, mutators } = props
const todayStartTime = moment().startOf('day').format('x') const todayStartTime = moment().startOf('day').format('x')
const nowTime = moment().format('x').valueOf() const nowTime = moment().format('x').valueOf()
const dateMemo = useMemo(() => [ const dateMemo = useMemo(() => [
...@@ -39,7 +39,7 @@ const DateSelect = (props) => { ...@@ -39,7 +39,7 @@ const DateSelect = (props) => {
style={{minWidth: 160}} style={{minWidth: 160}}
placeholder={placeholder} placeholder={placeholder}
onChange={handleChange} onChange={handleChange}
value={value.join()} value={value.length > 0 ? value.join() : undefined}
options={dataSource} options={dataSource}
/> />
) )
......
...@@ -3,7 +3,7 @@ import { Input, Space, Button, Table } from 'antd' ...@@ -3,7 +3,7 @@ import { Input, Space, Button, Table } from 'antd'
import { PlusOutlined } from '@ant-design/icons' import { PlusOutlined } from '@ant-design/icons'
const MultTable = (props) => { const MultTable = (props) => {
const { columns, prefix, rowKey } = props.props['x-component-props'] const { columns, prefix, suffix, rowKey } = props.props['x-component-props']
const value = props.value || [] const value = props.value || []
return ( return (
<div style={{width: '100%'}}> <div style={{width: '100%'}}>
...@@ -13,6 +13,7 @@ const MultTable = (props) => { ...@@ -13,6 +13,7 @@ const MultTable = (props) => {
columns={columns} columns={columns}
dataSource={value} dataSource={value}
/> />
{suffix}
</div> </div>
) )
} }
......
import React from 'react'
import { ISchemaFieldProps } from '@formily/antd'
const VirtualChildren = (props) => {
// console.log(props)
const { children } = props
// const componentProps = schema.getExtendsComponentProps()
// const { children } = componentProps
return (
children ? children : <div>virtual</div>
)
}
VirtualChildren.defaultProps = {}
VirtualChildren.isVirtualFieldComponent = true;
export default VirtualChildren
\ No newline at end of file
...@@ -24,6 +24,8 @@ import TableTagList from './components/TableTagList'; ...@@ -24,6 +24,8 @@ import TableTagList from './components/TableTagList';
import './index.less' import './index.less'
import { Checkbox } from '@formily/antd-components'; import { Checkbox } from '@formily/antd-components';
import DateSelect from './components/DateSelect'; import DateSelect from './components/DateSelect';
import VirtualChildren from './components/VirtualChildren'
import { useLinkComponentProps } from './linkages/linkComponentProps';
export interface NiceFormProps extends IAntdSchemaFormProps {} export interface NiceFormProps extends IAntdSchemaFormProps {}
...@@ -89,15 +91,28 @@ export const componentExport = { ...@@ -89,15 +91,28 @@ export const componentExport = {
SearchSelect, SearchSelect,
DateRangePicker: DatePicker.RangePicker, DateRangePicker: DatePicker.RangePicker,
TableTagList, TableTagList,
DateSelect DateSelect,
VirtualChildren
} }
const NiceForm: React.FC<NiceFormProps> = props => { const NiceForm: React.FC<NiceFormProps> = props => {
const { children, components, ...reset } = props; const { children, components, effects, expressionScope, ...reset } = props;
const defineComponents = Object.assign(componentExport, components); const defineComponents = Object.assign(componentExport, components);
return ( return (
<SchemaForm colon={false} components={defineComponents} {...reset}> <SchemaForm
colon={false}
components={defineComponents}
effects={($, ctx) => {
// 自定义联动scope收集器
useLinkComponentProps(expressionScope)
// 组件联动
effects && effects($, ctx)
}}
expressionScope={expressionScope}
{...reset}
>
{children} {children}
</SchemaForm> </SchemaForm>
); );
......
import { FormEffectHooks, useValueLinkageEffect } from '@formily/antd'
export const useLinkComponentProps = (scope) => {
useValueLinkageEffect({
type: 'value:componentProps',
resolve: ({ origin, target }, { setFieldState, getFieldState }) => {
console.log('xxx')
getFieldState(origin, state => {
const { componentProps = {} } = state
setFieldState(target, targetState => {
const extendsProps = targetState.props["x-component-props"] || {}
targetState.props["x-component-props"] = {
...extendsProps,
...componentProps
}
})
})
},
reject: ({ target }, { setFieldState, getFieldState }) => {
getFieldState(origin, state => {
const { disComponentProps = {} } = state
setFieldState(target, targetState => {
const extendsProps = targetState.props["x-component-props"] || {}
targetState.props["x-component-props"] = {
...extendsProps,
...disComponentProps
}
})
})
},
// 需收集所有传入的expressionScope数据, 否则无法获取到依赖监听
scope
})
}
\ No newline at end of file
...@@ -65,20 +65,19 @@ import { useValueLinkageEffect, FormPath, FormEffectHooks } from '@formily/antd' ...@@ -65,20 +65,19 @@ import { useValueLinkageEffect, FormPath, FormEffectHooks } from '@formily/antd'
* *
* ` * `
*/ */
export const useLinkEnumEffect = (childKey, transformFn?) => { export const useLinkEnumEffect = (childKey, transformFn?, findKey = 'id') => {
const { onFieldValueChange$ } = FormEffectHooks const { onFieldValueChange$ } = FormEffectHooks
useValueLinkageEffect({ useValueLinkageEffect({
type: 'value:linkage', type: 'value:linkage',
resolve: ({ origin, target }, { setFieldState, getFieldState }) => { resolve: ({ origin, target }, { setFieldState, getFieldState }) => {
getFieldState(origin, state => { getFieldState(origin, state => {
console.log('origin', origin, 'state', state)
const { originData = [] } = state const { originData = [] } = state
setFieldState(target, targetState => { setFieldState(target, targetState => {
if (state.value === undefined) { if (state.value === undefined) {
} else { } else {
if (originData.length > 0) { if (originData.length > 0) {
const result = originData.find(v => v.id === state.value)[childKey] || [] const result = originData.find(v => v[findKey] === state.value)[childKey] || []
if (state.modified) { if (state.modified && state.initialValue) {
targetState.value = undefined targetState.value = undefined
} }
targetState.originData = result targetState.originData = result
......
...@@ -246,3 +246,16 @@ export const ORDER_TYPE = ['', ...@@ -246,3 +246,16 @@ export const ORDER_TYPE = ['',
'渠道现货', '渠道现货',
'渠道积分兑换', '渠道积分兑换',
] ]
// 提货方式
export const DELIVERY_TYPE = ['',
'物流',
'自提',
'无需配送'
]
export const DELIVERY_TYPE_ENUM = [
{ label: '物流', value: 1 },
{ label: '自提', value: 2 },
{ label: '无需配送', value: 3 },
]
\ No newline at end of file
...@@ -7,8 +7,9 @@ const { onFormInit$ } = FormEffectHooks ...@@ -7,8 +7,9 @@ const { onFormInit$ } = FormEffectHooks
* @param name 待处理的表单路径 * @param name 待处理的表单路径
* @param service 触发的异步函数, 需返回一个{label: any, value: any}形式的数组 * @param service 触发的异步函数, 需返回一个{label: any, value: any}形式的数组
*/ */
export const useAsyncSelect = async (name, service: () => Promise<any[]>) => { export const useAsyncSelect = async (name, service: () => Promise<any[]>, format?: [string, string]) => {
const { dispatch, setFieldState } = createFormActions() const { dispatch, setFieldState } = createFormActions()
const linkage = useLinkageUtils() const linkage = useLinkageUtils()
onFormInit$().subscribe(() => { onFormInit$().subscribe(() => {
setFieldState(name, state => { setFieldState(name, state => {
...@@ -20,6 +21,13 @@ export const useAsyncSelect = async (name, service: () => Promise<any[]>) => { ...@@ -20,6 +21,13 @@ export const useAsyncSelect = async (name, service: () => Promise<any[]>) => {
state.originAsyncData = res state.originAsyncData = res
}) })
linkage.loaded(name) linkage.loaded(name)
if (format) {
const [labelString, valueString] = format
res = res.map(v => ({
label: v[labelString],
value: v[valueString]
}))
}
linkage.enum(name, res) linkage.enum(name, res)
//请求结束可以dispatch一个自定义事件收尾,方便后续针对该事件做联动 //请求结束可以dispatch一个自定义事件收尾,方便后续针对该事件做联动
dispatch('requestAsyncSelect', { dispatch('requestAsyncSelect', {
......
import { GetProductChannelCommodityGetCommodityListResponseDetail, GetProductChannelCommodityGetCommodityUnitPriceResponse } from '@/services'; import { GetProductChannelCommodityGetCommodityUnitPriceResponse } from '@/services';
export interface IRole { export interface IRole {
key: string; key: string;
...@@ -12,7 +12,7 @@ export interface IChannel { ...@@ -12,7 +12,7 @@ export interface IChannel {
} }
export interface IChannelProductModule { export interface IChannelProductModule {
productSelectRowInStore: GetProductChannelCommodityGetCommodityListResponseDetail; productSelectRowInStore: any;
priceType: number; priceType: number;
productName: string; productName: string;
currentActiveKey: string; currentActiveKey: string;
...@@ -20,7 +20,7 @@ export interface IChannelProductModule { ...@@ -20,7 +20,7 @@ export interface IChannelProductModule {
selectedRole: IRole; selectedRole: IRole;
tableDataInSetPrice: GetProductChannelCommodityGetCommodityUnitPriceResponse[]; tableDataInSetPrice: GetProductChannelCommodityGetCommodityUnitPriceResponse[];
setProductSelectRowInStore(data: GetProductChannelCommodityGetCommodityListResponseDetail): void; setProductSelectRowInStore(data: any): void;
setPriceType(data: number): void; setPriceType(data: number): void;
setProductName(data: string): void; setProductName(data: string): void;
setCurrentActiveKey(data: string): void; setCurrentActiveKey(data: string): void;
......
.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'
import { fetchOrderApi } from '../../readyAddOrder/apis'
export interface AddressModalProps {
mode: 'add' | 'edit' | 'default',
currentRef?: any,
formInitValue?: any,
reloadAddress?()
}
const addressSchemaAction = createFormActions()
// 获取手机区号
const fetchTelCode = async () => {
const { data } = await PublicApi.getManageGetTelCode()
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 = () => {
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)
props.currentRef.current.setVisible(false)
props.reloadAddress && props.reloadAddress()
}
return (
<ModalForm
modalTitle={mode === 'add' ? '新建收货地址' : '编辑收货地址'}
confirm={handleConfirm}
cancel={resetForm}
value={selfInitValue}
effects={($, { setFieldState }) => {
$('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)
}}
currentRef={props.currentRef}
actions={addressSchemaAction}
schema={addressSchema}
onSubmit={handleSubmit}
/>
)
}
AddressModal.defaultProps = {}
export default AddressModal
\ No newline at end of file
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: '输入你的手机号码'
}
}
}
},
tel: {
title: '电话号码',
type: 'string'
},
isDefault: {
title: '是否默认',
type: 'boolean',
"x-mega-props": {
wrapperWidth: 36
}
}
}
}
}
}
export default addressSchema
\ No newline at end of file
.com-switch-btn-group {
display: flex;
.switch-btn {
width: 112px;
line-height: 32px;
text-align: center;
background: #FAFBFC;
border: 1px solid #EBECF0;
color: #42526E;
cursor: pointer;
&.active {
background: #6B778C;
color: #fff;
border: none;
}
}
}
\ No newline at end of file
import React, { useRef, useEffect, useState } from 'react'
import { Button, Table } from 'antd'
import { StandardTable } from 'god'
import { formatTimeString } from '@/utils'
import './index.less'
import cx from 'classnames'
export interface CirculationRecordProps {}
/**
* 流转记录控制
*/
const outOrderCols: any[] = [
{
title: '流转顺序号',
dataIndex: 'no',
align: 'center',
key: 'no',
render: (_, __, index: number) => index + 1
},
{
title: '操作角色',
dataIndex: 'roleName',
align: 'center',
key: 'roleName',
},
{
title: '状态',
dataIndex: 'state',
align: 'center',
key: 'state',
// @todo 需传递工作流状态重新render
},
{
title: '操作',
dataIndex: 'operation',
align: 'center',
key: 'operation',
},
{
title: '操作时间',
dataIndex: 'operationTime',
align: 'center',
key: 'operationTime',
render: time => formatTimeString(time)
},
{
title: '审核意见',
dataIndex: 'auditOpinion',
align: 'center',
key: 'auditOpinion',
},
]
const sideOrderCols: any[] = [
{
title: '流转记录',
dataIndex: 'no',
align: 'center',
key: 'no',
render: (_, __, index: number) => index + 1
},
{
title: '操作人',
dataIndex: 'roleName',
align: 'center',
key: 'roleName',
},
{
title: '部门',
dataIndex: 'department',
align: 'center',
key: 'department',
},
{
title: '职位',
dataIndex: 'position',
align: 'center',
key: 'position',
},
{
title: '状态',
dataIndex: 'state',
align: 'center',
key: 'state',
},
{
title: '操作',
dataIndex: 'operation',
align: 'center',
key: 'operation',
},
{
title: '操作时间',
dataIndex: 'operationTime',
align: 'center',
key: 'operationTime',
},
{
title: '审核意见',
dataIndex: 'auditOpinion',
align: 'center',
key: 'auditOpinion',
},
]
const CirculationRecord:React.FC<CirculationRecordProps> = (props) => {
const colRef = useRef<any[]>(outOrderCols)
const [orderState, setOrderState] = useState<number>(0)
useEffect(() => {
colRef.current = orderState === 1 ? outOrderCols : sideOrderCols
}, [colRef, orderState])
return (
<div>
<div className='com-switch-btn-group' style={{margin: '20px 0'}}>
<div className={cx('switch-btn', orderState === 0 ? 'active' : '')} onClick={() => setOrderState(0)}>外部单据</div>
<div className={cx('switch-btn', orderState === 1 ? 'active' : '')} onClick={() => setOrderState(1)}>内部单据</div>
</div>
<Table
columns={colRef.current}
dataSource={[]}
/>
</div>
)
}
CirculationRecord.defaultProps = {}
export default CirculationRecord
\ No newline at end of file
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { fetchOrderApi } from '../../readyAddOrder/apis'
import { useModalTable } from '../../readyAddOrder/model/useModalTable'
import { ISchemaFormActions } from '@formily/antd'
import { inquiryColumns } from '../../readyAddOrder/constant'
export interface DemandModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions,
currentRef?: any,
confirmModal?()
}
// 需求报价单弹窗
const DemandModalTable:React.FC<DemandModalTableProps> = (props) => {
const { type = 'radio', schemaAction, confirmModal, currentRef, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type})
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const handleConfirm = async () => {
const item = rowSelectionCtl.selectRow[0]
if (item) {
schemaAction.setFieldValue('quotationNo', item.quotationNo)
const data = await fetchOrderApi.getProductListByQuotationOrderId({
id: item.id
})
schemaAction.setFieldValue('orderProductRequests', data)
}
confirmModal && confirmModal()
setVisible(false)
}
return (
<ModalTable
modalTitle='选择需求报价单'
columns={inquiryColumns}
visible={visible}
confirm={handleConfirm}
cancel={() => setVisible(false)}
fetchTableData={(params) => fetchOrderApi.getOrderQuotationDemandList(params)}
rowSelection={rowSelection}
modalType='demandByDefault'
tableProps={{
rowKey: 'id'
}}
{...restProps}
/>
)
}
DemandModalTable.defaultProps = {}
export default DemandModalTable
\ No newline at end of file
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { fetchOrderApi } from '../../readyAddOrder/apis'
import { useModalTable } from '../../readyAddOrder/model/useModalTable'
import { ISchemaFormActions } from '@formily/antd'
import { inquiryColumns } from '../../readyAddOrder/constant'
export interface InquiryModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions,
currentRef?: any,
confirmModal?()
}
// 报价单弹窗
const InquiryModalTable:React.FC<InquiryModalTableProps> = (props) => {
const { type = 'radio', schemaAction, confirmModal, currentRef, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type})
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const handleConfirm = async () => {
const item = rowSelectionCtl.selectRow[0]
if (item) {
schemaAction.setFieldValue('quotationNo', item.quotationNo)
const data = await fetchOrderApi.getProductListByQuotationOrderId({
id: item.id
})
schemaAction.setFieldValue('orderProductRequests', data)
schemaAction.setFieldValue('supplyMembersName', item.memberName || '后端没有返回会员名称')
}
confirmModal && confirmModal()
setVisible(false)
}
return (
<ModalTable
modalTitle='选择询价报价单'
columns={inquiryColumns}
visible={visible}
confirm={handleConfirm}
cancel={() => setVisible(false)}
fetchTableData={(params) => fetchOrderApi.getQuotationList(params)}
rowSelection={rowSelection}
modalType='inquiryByDefault'
tableProps={{
rowKey: 'id'
}}
{...restProps}
/>
)
}
InquiryModalTable.defaultProps = {}
export default InquiryModalTable
\ No newline at end of file
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { fetchOrderApi } from '../../readyAddOrder/apis'
import { useModalTable } from '../../readyAddOrder/model/useModalTable'
import { ISchemaFormActions } from '@formily/antd'
import { memberColumns } from '../../readyAddOrder/constant'
export interface MemberModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions,
currentRef?: any,
confirmModal?()
}
const MemberModalTable:React.FC<MemberModalTableProps> = (props) => {
const { type = 'radio', schemaAction, confirmModal, currentRef, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type})
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const handleConfirm = () => {
schemaAction.setFieldValue('supplyMembersName', rowSelectionCtl.selectRow)
confirmModal && confirmModal()
setVisible(false)
}
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
\ No newline at end of file
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
import { fetchOrderApi } from '../../readyAddOrder/apis'
import { useModalTable } from '../../readyAddOrder/model/useModalTable'
import { ISchemaFormActions } from '@formily/antd'
export interface ProductModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions,
currentRef?: 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',
},
]
const ProductModalTable:React.FC<ProductModalTableProps> = (props) => {
const { type = 'checkbox', schemaAction, confirmModal, currentRef, ...restProps } = props
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({type})
useEffect(() => {
if (currentRef) {
currentRef.current = {
setVisible,
visible,
rowSelectionCtl
}
}
}, [])
const handleConfirmProduct = () => {
schemaAction.setFieldValue('orderProductRequests', rowSelectionCtl.selectRow)
confirmModal && confirmModal()
setVisible(false)
}
return (
<ModalTable
modalTitle='选择订单商品'
columns={productColumns}
visible={visible}
confirm={handleConfirmProduct}
cancel={() => setVisible(false)}
fetchTableData={(params) => fetchOrderApi.getProductList(params)}
rowSelection={rowSelection}
modalType='productByDefault'
tableProps={{
rowKey: 'id',
onRow: (record) => ({
onClick: () => {
rowSelectionCtl.setSelectRow([record]);
rowSelectionCtl.setSelectedRowKeys([record.id]);
},
})
}}
{...restProps}
/>
)
}
ProductModalTable.defaultProps = {}
export default ProductModalTable
\ No newline at end of file
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 } from '@ant-design/icons'
import cx from 'classnames'
import AddressModal from '../addressModal'
import { fetchOrderApi } from '../../readyAddOrder/apis'
import { PublicApi } from '@/services/api'
const SelectStyles = styled((props) => <div className='select-list' {...props}></div>)`
.select_style_border {
border: 1px solid #EBECF0;
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
const { value, mutators, form } = props
const transformData = transformDefaultData(dataSource)
const showDataSource = showMore ? [...transformData].splice(0, 3) : transformData
const handleAdd = () => {
setMode('add')
modalRef.current.setVisible(true)
}
const handleCheck = (id) => {
// 选中的id
mutators.change(id)
}
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) => {
e.stopPropagation()
const { data } = await PublicApi.getLogisticsReceiverAddressGet({id: item.id})
setFormInitValue({...data, isDefault: item.isDefault})
setMode('edit')
modalRef.current.setVisible(true)
}
return (
<div style={{width: '100%'}}>
<Button block onClick={handleAdd} icon={<PlusOutlined/>}>新建地址</Button>
<SelectStyles>
{
showDataSource.map(v => <div key={v.id} onClick={() => handleCheck(v.id)} className={cx('select_style_border', value === v.id ? 'active' : '')}>
<div>
<Row style={{color: '#172B4D'}}>
<Col>{v.receiverName}</Col>
<Col> / </Col>
<Col>{v.phone}</Col>
{v.isDefault && <Col style={{marginLeft: 6}}><Tag color='default'>默认</Tag></Col>}
</Row>
<div style={{color: '#6B778C'}}>{v.fullAddress}</div>
</div>
<Space size={12}>
<EditOutlined onClick={(e) => handleEdit(v, e)}/>
<DeleteOutlined onClick={(e) => handleDelete(v.id, e)}/>
</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
\ No newline at end of file
import { PublicApi } from '@/services/api'
export const fetchOrderApi = {
// 弹窗获取商品列表
async getProductList(params) {
const { data } = await PublicApi.getProductCommodityGetCommodityDetailList(params)
return data
},
// 弹窗获取询价报价单列表
async getQuotationList(params) {
const { data } = await PublicApi.getOrderProductQuotationList(params)
return data
},
// 弹窗获取需求报价单列表
async getOrderQuotationDemandList(params) {
const { data } = await PublicApi.getOrderQuotationList(params)
return data
},
// 根据询价报价id查询商品列表
async getProductListByQuotationOrderId(params) {
const { data } = await PublicApi.getOrderEnquiryProductAll(params)
return data
},
async getProductListByDemandOrderId(params) {
const { data } = await PublicApi.getOrderRequisitionFormProductList(params)
return data
},
// 根据下单类型获取会员列表
async getMemberListByModelType(params) {
const { data } = await PublicApi.getMemberManageAllPageByordertype(params)
return data
},
// 获取所有商品收货地址
async getProductAddressAll() {
const { data } = await PublicApi.getLogisticsSelectListReceiverAddress()
return data
}
}
\ No newline at end of file
import { formatTimeString } from '@/utils'
export enum OrderModalType { export enum OrderModalType {
/** /**
...@@ -44,6 +46,35 @@ export enum OrderModalType { ...@@ -44,6 +46,35 @@ export enum OrderModalType {
CHANNEL_SPOT_MANUAL_ORDER, CHANNEL_SPOT_MANUAL_ORDER,
} }
/***********控制订单模式联动其他字段的数组集合 *******/
export const orderCombination = {
// 需从外部页面传入参数生成的订单联动, 用于禁用下单模式的手动选择
queryPageOrderModal: [
OrderModalType.PURCHASE_ORDER,
OrderModalType.CHANNEL_DIRECT_PURCHASE_ORDER,
OrderModalType.CHANNEL_SPOT_PURCHASE_ORDER
],
// 是否显示报价单字段
showQuotationNoOrder: [
OrderModalType.INQUIRY_QUOTATION_ORDER,
OrderModalType.DEMAND_QUOTATION_ORDER,
OrderModalType.CONSOLIDATED_ORDER
],
// 是否显示报价单按钮
showQuotationNoOrderBtn: [
OrderModalType.INQUIRY_QUOTATION_ORDER,
OrderModalType.DEMAND_QUOTATION_ORDER,
OrderModalType.CONSOLIDATED_ORDER,
],
// 是否显示供应会员按钮
showSupplyMembersNameBtn: [
OrderModalType.HAND_ORDER,
OrderModalType.CHANNEL_DIRECT_MINING_ORDER,
OrderModalType.CHANNEL_SPOT_MANUAL_ORDER,
OrderModalType.CONSOLIDATED_ORDER
]
}
export const orderTypeLabel = ['', export const orderTypeLabel = ['',
'询价采购', '询价采购',
'需求采购', '需求采购',
...@@ -75,3 +106,82 @@ export const memberColumns: any[] = [ ...@@ -75,3 +106,82 @@ export const memberColumns: any[] = [
key: 'address', key: 'address',
}, },
] ]
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: 'memberName',
align: 'center',
key: 'memberName',
},
{
title: '单据时间',
dataIndex: 'voucherTime',
align: 'center',
key: 'voucherTime',
render: _ => formatTimeString(_)
}
]
export const paymentInformationColumns: any[] = [
{
title: '支付次数',
dataIndex: 'payCount',
align: 'center',
key: 'payCount'
},
{
title: '支付环节',
dataIndex: 'payNode',
align: 'center',
key: 'payNode'
},
{
title: '外部状态',
dataIndex: 'externalState',
align: 'center',
key: 'externalState'
},
{
title: '支付比例',
dataIndex: 'payRatio',
align: 'center',
key: 'payRatio'
},
{
title: '支付金额',
dataIndex: 'payPrice',
align: 'center',
key: 'payPrice'
},
{
title: '支付方式',
dataIndex: 'payWay',
align: 'center',
key: 'payWay'
},
{
title: '支付渠道',
dataIndex: 'channel',
align: 'center',
key: 'channel'
},
]
\ No newline at end of file
import React from 'react' import React, { useRef } from 'react'
import { history } from 'umi' import { history } from 'umi'
import { PageHeaderWrapper } from '@ant-design/pro-layout' import { PageHeaderWrapper } from '@ant-design/pro-layout'
import ReutrnEle from '@/components/ReturnEle' import ReutrnEle from '@/components/ReturnEle'
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus' import { usePageStatus, PageStatus } from '@/hooks/usePageStatus'
import { Button, Card } from 'antd' import { Button, Card } from 'antd'
import { createFormActions } from '@formily/antd' import { createFormActions } from '@formily/antd'
import { SaveOutlined, LinkOutlined } from '@ant-design/icons' import { SaveOutlined, LinkOutlined, PlusOutlined } from '@ant-design/icons'
import NiceForm from '@/components/NiceForm' import NiceForm from '@/components/NiceForm'
import { orderDetailSchema } from './schema' import { orderDetailSchema } from './schema'
import { useDetailOrder } from './model/useDetailOrder' import { useDetailOrder } from './model/useDetailOrder'
import ModalTable from '@/components/ModalTable' import ModalTable from '@/components/ModalTable'
import { useModelTypeChange, useEditHideField } from './effects' import { useModelTypeChange, useEditHideField, useOrderFormInitEffect } from './effects'
import { OrderModalType, orderTypeLabel, memberColumns } from './constant' import { OrderModalType, orderTypeLabel, memberColumns, orderCombination, paymentInformationColumns } from './constant'
import { useLinkageUtils } from '@/utils/formEffectUtils' import { useLinkageUtils } from '@/utils/formEffectUtils'
import { useModalTable } from './model/useModalTable'
import { memberSchema } from './schema/modal'
import { fetchOrderApi } from './apis'
import ProductModalTable, { productColumns } from '../components/productModalTable'
import MemberModalTable from '../components/memberModalTable'
import InquiryModalTable from '../components/inquiryModalTable'
import DemandModalTable from '../components/demandModalTable'
import { useLinkComponentProps } from '@/components/NiceForm/linkages/linkComponentProps'
import CirculationRecord from '../components/circulationRecord'
import SelectAddress from '../components/selectAddress'
export interface PurchaseOrderDetailProps {} export interface PurchaseOrderDetailProps {}
const addSchemaAction = createFormActions() const addSchemaAction = createFormActions()
// 采购订单详情页. 包含新增和编辑 // 采购订单详情页. 包含新增和编辑
const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => { const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => {
const { productColumns, setShowProBtn, showProBtn, visibleMember, setVisibleMember } = useDetailOrder({ const productRef = useRef<any>({})
const memberRef = useRef<any>({})
const inquiryRef = useRef<any>({})
const demandRef = useRef<any>({})
const {setShowProBtn, showProBtn } = useDetailOrder({
addSchemaAction addSchemaAction
}) })
// 页面进入时, 当前所处的下单模式 // 页面进入时, 当前所处的下单模式
const { pageStatus } = usePageStatus() const { pageStatus } = usePageStatus()
const handleOrderNo = () => {}
// 唤起报价单弹窗
const handleOrderNo = () => {
// @todo 未完整实现功能, 缺少商品接口
// 询价报价单, 合并订单需要唤起询价弹窗
const orderModel = addSchemaAction.getFieldValue('orderModel')
if (orderModel === OrderModalType.INQUIRY_QUOTATION_ORDER || orderModel === OrderModalType.CONSOLIDATED_ORDER) {
inquiryRef.current.setVisible(true)
} else {
demandRef.current.setVisible(true)
}
}
// 选择会员弹窗 // 选择会员弹窗
const handleOrderMember = () => { const handleOrderMember = () => {
setVisibleMember(true) memberRef.current.setVisible(true)
} }
const orderNoPrice = pageStatus !== PageStatus.PREVIEW && <div className='connectBtn' onClick={handleOrderNo}><LinkOutlined style={{marginRight: 4}}/>选择</div> const orderNoPrice = pageStatus !== PageStatus.PREVIEW && <div className='connectBtn' onClick={handleOrderNo}><LinkOutlined style={{marginRight: 4}}/>选择</div>
const orderMember = pageStatus !== PageStatus.PREVIEW && <div className='connectBtn' onClick={handleOrderMember}><LinkOutlined style={{marginRight: 4}}/>选择</div> const orderMember = pageStatus !== PageStatus.PREVIEW && <div className='connectBtn' onClick={handleOrderMember}><LinkOutlined style={{marginRight: 4}}/>选择</div>
const productAddButton = showProBtn && <Button block type='default' style={{margin: '24px auto'}}>选择订单商品</Button> const productAddButton = <Button onClick={() => productRef.current.setVisible(true)} block type='default' style={{margin: '24px auto'}}>选择订单商品</Button>
// @todo 未实现金额合计
const couponAddButton = <Button onClick={() => productRef.current.setVisible(true)} block type='default' style={{margin: '24px auto'}}>选择优惠券</Button>
// 新增收货地址
const addNewAddress = <Button block icon={<PlusOutlined/>}>新增收货地址</Button>
return ( return (
<PageHeaderWrapper <PageHeaderWrapper
onBack={() => history.goBack()} onBack={() => history.goBack()}
...@@ -52,8 +84,12 @@ const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => { ...@@ -52,8 +84,12 @@ const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => {
actions={addSchemaAction} actions={addSchemaAction}
schema={orderDetailSchema} schema={orderDetailSchema}
className='useConnectBtnWrapper' className='useConnectBtnWrapper'
components={{
SelectAddress
}}
effects={($, ctx) => { effects={($, ctx) => {
const formUtils = useLinkageUtils() // useLinkComponentProps()
useOrderFormInitEffect(ctx)
useModelTypeChange(state => { useModelTypeChange(state => {
const { value } = state const { value } = state
// 报价单的值 等同于是否填写过报价单 // 报价单的值 等同于是否填写过报价单
...@@ -66,17 +102,27 @@ const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => { ...@@ -66,17 +102,27 @@ const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => {
value === OrderModalType.CHANNEL_SPOT_MANUAL_ORDER || value === OrderModalType.CHANNEL_SPOT_MANUAL_ORDER ||
(value === OrderModalType.CONSOLIDATED_ORDER && quotationOrderValue) (value === OrderModalType.CONSOLIDATED_ORDER && quotationOrderValue)
) { ) {
setShowProBtn(true) addSchemaAction.setFieldState('orderProductRequests', productState => {
productState.props["x-component-props"] = {
...productState.props["x-component-props"],
prefix: productAddButton,
}
})
} else { } else {
setShowProBtn(false) addSchemaAction.setFieldState('orderProductRequests', productState => {
productState.props["x-component-props"] = {
...productState.props["x-component-props"],
prefix: "",
}
})
} }
// if (value === OrderModalType.HAND_ORDER) {
// formUtils.visible('supplyMembersName', true)
// }
// 选择某种类型时, 需显示对应的订单类型 // 选择某种类型时, 需显示对应的订单类型
ctx.setFieldValue('type', orderTypeLabel[value - 4]) // -4 获得对应的数组下标, 由于id是固定的 ctx.setFieldValue('type', orderTypeLabel[value - 4]) // -4 获得对应的数组下标, 由于id是固定的
ctx.reset({
validate: false,
selector: '*(quotationNo,supplyMembersName,orderProductRequests)'
})
}) })
useEditHideField() useEditHideField()
...@@ -84,38 +130,23 @@ const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => { ...@@ -84,38 +130,23 @@ const PurchaseOrderDetail:React.FC<PurchaseOrderDetailProps> = (props) => {
expressionScope={{ expressionScope={{
orderNoPrice, orderNoPrice,
orderMember, orderMember,
paymentInformationColumns,
productColumns, productColumns,
productAddButton productAddButton,
couponAddButton,
orderCombination,
addNewAddress,
CirculationRecord: <CirculationRecord/>,
handleQuotation: (value) => addSchemaAction.getFieldValue('orderModel') === OrderModalType.CONSOLIDATED_ORDER && !!value
}} }}
/> />
</Card> </Card>
<ModalTable <ProductModalTable currentRef={productRef} schemaAction={addSchemaAction}/>
modalTitle='选择订单商品' <MemberModalTable currentRef={memberRef} schemaAction={addSchemaAction}/>
columns={productColumns} {/* 询价报价单弹窗 */}
/> <InquiryModalTable currentRef={inquiryRef} schemaAction={addSchemaAction}/>
<ModalTable
modalTitle='选择供应会员' <DemandModalTable currentRef={demandRef} schemaAction={addSchemaAction}/>
visible={visibleMember}
confirm={() => setVisibleMember(false)}
cancel={() => setVisibleMember(false)}
columns={memberColumns}
formilyProps={{
ctx: {
schema: {
type: 'object',
properties: {
name: {
type: 'string',
"x-component": 'Search',
"x-component-props": {
placeholder: '请输入会员名称'
}
}
}
}
}
}}
/>
</PageHeaderWrapper> </PageHeaderWrapper>
) )
} }
......
import { ISchemaFormActions, FormEffectHooks } from '@formily/antd'; import { ISchemaFormActions, FormEffectHooks, IFieldState, ISchemaFormAsyncActions, createEffectHook } from '@formily/antd';
import { usePageStatus, PageStatus } from '@/hooks/usePageStatus'; import { usePageStatus, PageStatus } from '@/hooks/usePageStatus';
import { useLinkageUtils } from '@/utils/formEffectUtils'; import { useLinkageUtils } from '@/utils/formEffectUtils';
import { OrderModalType, orderCombination } from '../constant';
import { history } from 'umi';
import { fetchOrderApi } from '../apis';
export const createEffects = context => () => {
}
export const useModelTypeChange = (callback) => { export const useModelTypeChange = (callback) => {
const utils = useLinkageUtils()
// 下单模式发生改变时 // 下单模式发生改变时
FormEffectHooks.onFieldValueChange$('orderModel').subscribe(state => { FormEffectHooks.onFieldValueChange$('orderModel').subscribe(state => {
callback(state) callback(state)
...@@ -19,3 +28,37 @@ export const useEditHideField = () => { ...@@ -19,3 +28,37 @@ export const useEditHideField = () => {
} }
}) })
} }
// 表单初始化时,对应操作
export const useOrderFormInitEffect = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const { orderModel = 0 } = history.location.query
FormEffectHooks.onFormMount$().subscribe(() => {
// query中存在orderModel参数, 则是从其他页面跳转而来,需禁用其余query选项
const typeEnums = parseInt(orderModel)
ctx.setFieldState('orderModel', state => {
state.props.enum = state.props.enum.map(v => {
const assign: any = Object.assign({}, v)
if (orderCombination.queryPageOrderModal.includes(assign.value) && typeEnums !== assign.value) {
assign.disabled = true
}
return assign
}).sort((prev, next) => prev.disabled ? prev.value : next.value - prev.value)
})
// 写入收货地址数据
useProductAddress(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].id
}
state.dataSource = data
state.showMore = data.length > 3
})
})
}
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { OrderModalType } from '../constant' import { OrderModalType } from '../constant'
import { PublicApi } from '@/services/api' import { PublicApi } from '@/services/api'
import { useLocation } from 'umi' import { useLocation, history } from 'umi'
import { ISchemaFormActions } from '@formily/antd' import { ISchemaFormActions } from '@formily/antd'
import { useLinkageUtils } from '@/utils/formEffectUtils' import { useLinkageUtils } from '@/utils/formEffectUtils'
...@@ -33,7 +33,8 @@ export const useDetailOrder = (options: DetailOptionsProps) => { ...@@ -33,7 +33,8 @@ export const useDetailOrder = (options: DetailOptionsProps) => {
const formilyUtils = useLinkageUtils() const formilyUtils = useLinkageUtils()
// const [productDataSource, setProductDataSource] = useState // const [productDataSource, setProductDataSource] = useState
const locationState = useLocation<DetailOrderLocationState>().state || {} const locationState = useLocation<DetailOrderLocationState>().state || {}
const { productList, modelType } = locationState const { productList } = locationState
const { modelType } = history.location.query
// 是否显示选择商品按钮 // 是否显示选择商品按钮
const [showProBtn, setShowProBtn] = useState(false) const [showProBtn, setShowProBtn] = useState(false)
// 是否显示供应会员字段 // 是否显示供应会员字段
...@@ -48,7 +49,7 @@ export const useDetailOrder = (options: DetailOptionsProps) => { ...@@ -48,7 +49,7 @@ export const useDetailOrder = (options: DetailOptionsProps) => {
useEffect(() => { useEffect(() => {
// 页面中有传入下单模式, 需要手动回显数据 // 页面中有传入下单模式, 需要手动回显数据
if (modelType) { if (modelType) {
addSchemaAction.setFieldValue('orderModel', modelType) addSchemaAction.setFieldValue('orderModel', parseInt(modelType))
} }
// 在有传入商品列表时 需手动回显 // 在有传入商品列表时 需手动回显
if (proList.length > 0) { if (proList.length > 0) {
...@@ -62,35 +63,7 @@ export const useDetailOrder = (options: DetailOptionsProps) => { ...@@ -62,35 +63,7 @@ export const useDetailOrder = (options: DetailOptionsProps) => {
await PublicApi.postOrderProcurementOrderAdd(params) await PublicApi.postOrderProcurementOrderAdd(params)
} }
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',
},
]
return { return {
productColumns,
showProBtn, showProBtn,
setShowProBtn, setShowProBtn,
showMemberType, showMemberType,
......
import { useState } from 'react' import { useState } from 'react'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
export const useModalTable = () => { export const useModalTable = (options?) => {
const [visible, setVisible] = useState(false) const [visible, setVisible] = useState(false)
const [rowSelection, rowSelectionCtl] = useRowSelectionTable(options)
return { return {
visible, visible,
setVisible setVisible,
rowSelection,
rowSelectionCtl
} }
} }
\ No newline at end of file
import { ISchema } from '@formily/antd'; import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const'; import { FORM_FILTER_PATH } from '@/formSchema/const';
import { GlobalConfig } from '@/global/config'; import { GlobalConfig } from '@/global/config';
import { OrderModalType } from '../constant'; import { OrderModalType, orderCombination } from '../constant';
import moment from 'moment'
import { DELIVERY_TYPE_ENUM } from '@/constants';
/** /**
* 除了订单必填字段, 默认 * 除了订单必填字段, 默认
...@@ -56,9 +58,6 @@ export const tableListSchema: ISchema = { ...@@ -56,9 +58,6 @@ export const tableListSchema: ISchema = {
}, },
} }
} }
/**
* 订单详情(新增订单, 编辑订单)
*/
// 基本信息 // 基本信息
const basicInfo: ISchema = { const basicInfo: ISchema = {
...@@ -83,11 +82,50 @@ const basicInfo: ISchema = { ...@@ -83,11 +82,50 @@ const basicInfo: ISchema = {
enum: GlobalConfig.web.orderMode.map(v => { delete v.platformType ;return v}), enum: GlobalConfig.web.orderMode.map(v => { delete v.platformType ;return v}),
title: '下单模式', title: '下单模式',
"x-linkages": [ "x-linkages": [
// 联动显示单据字段
{ {
type: 'value:visible', type: 'value:visible',
"target": "quotationNo",
"condition": `{{orderCombination.showQuotationNoOrder.includes($value)}}`
},
// 联动显示单据按钮
{
type: "value:schema",
"target": "quotationNo",
condition: `{{!!$value && orderCombination.showQuotationNoOrderBtn.includes($value)}}`,
schema: {
"x-component-props": {
disabled: true,
addonAfter: "{{orderNoPrice}}"
}
},
otherwise: {
visible: true,
"x-component-props": {
disabled: true,
addonAfter: ""
}
}
},
// 联动显示供应会员按钮
{
type: "value:schema",
"target": "supplyMembersName", "target": "supplyMembersName",
"condition": `{{ $self.value === ${OrderModalType.HAND_ORDER} }}` condition: `{{$value && orderCombination.showSupplyMembersNameBtn.includes($value)}}`,
schema: {
"x-component-props": {
disabled: true,
addonAfter: "{{orderMember}}"
}
},
otherwise: {
visible: true,
"x-component-props": {
disabled: true,
addonAfter: ""
}
} }
},
], ],
}, },
orderThe: { orderThe: {
...@@ -104,22 +142,31 @@ const basicInfo: ISchema = { ...@@ -104,22 +142,31 @@ const basicInfo: ISchema = {
quotationNo: { quotationNo: {
type: 'string', type: 'string',
title: '对应报价单号', title: '对应报价单号',
visible: false,
"x-component-props": { "x-component-props": {
disabled: true, disabled: true,
addonAfter: "{{orderNoPrice}}"
}, },
visible: false "x-linkages": [
{
type: 'value:schema',
target: "supplyMembersName",
condition: `{{handleQuotation($value)}}`,
schema: {
"x-component-props": {
disabled: true,
addonAfter: ""
}
}
}
],
}, },
supplyMembersName: { supplyMembersName: {
type: 'string', type: 'string',
title: '供应会员', title: '供应会员',
"x-component-props": { "x-component-props": {
disabled: true, disabled: true,
addonAfter: "{{orderMember}}"
}, },
required: true, required: true,
visible: false
}, },
orderNo: { orderNo: {
type: 'string', type: 'string',
...@@ -166,7 +213,8 @@ const orderProduct: ISchema = { ...@@ -166,7 +213,8 @@ const orderProduct: ISchema = {
"x-component-props": { "x-component-props": {
rowKey: 'id', rowKey: 'id',
columns: "{{productColumns}}", columns: "{{productColumns}}",
prefix: "{{productAddButton}}" prefix: "{{productAddButton}}",
suffix: "{{couponAddButton}}"
} }
} }
} }
...@@ -179,40 +227,172 @@ const payInfo = { ...@@ -179,40 +227,172 @@ const payInfo = {
tab: '支付信息' tab: '支付信息'
}, },
properties: { properties: {
paymentInformationResponses: {
type: 'array',
"x-component": 'MultTable',
"x-component-props": {
rowKey: 'id',
columns: "{{paymentInformationColumns}}",
}
}
} }
} }
// 交付信息 // 交付信息
const submitInfo = { const submitInfo: ISchema = {
type: 'object', type: 'object',
"x-component": 'tabpane', "x-component": 'tabpane',
"x-component-props": { "x-component-props": {
tab: '交付信息' tab: '交付信息'
}, },
properties: { 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: {
deliveryTime: {
type: 'string',
"x-component": 'date',
title: '交付日期',
required: true,
"x-component-props": {
disabledDate: current => {
return current && current < moment().startOf('day')
}
}
},
// deliveryType: {
// type: 'string',
// enum: DELIVERY_TYPE_ENUM,
// title: '提货方式',
// required: true,
// "x-linkages": [
// {
// type: 'value:visible',
// target: 'selfAddress',
// condition: "{{$value === 2}}"
// },
// {
// type: 'value:visible',
// target: 'money',
// condition: "{{$value === 1}}"
// }
// ]
// },
// selfAddress: {
// type: 'string',
// "x-component": 'text',
// title: '自提地址',
// default: 'xxx',
// visible: false
// },
// money: {
// type: 'string',
// "x-component": 'text',
// title: '运费',
// default: 10,
// visible: false
// }
}
},
deliveryAddresId: {
type: 'string',
"x-component": 'SelectAddress',
"x-mega-props": {
style: {
full: true
}
},
"x-component-props": {
dataSource: []
},
"x-rules": [
{
required: true,
message: '请选择收货方式'
}
],
title: '收货方式'
}
}
}
} }
} }
// 其他信息 // 其他信息
const ortherInfo = { const ortherInfo: ISchema = {
type: 'object', type: 'object',
"x-component": 'tabpane', "x-component": 'tabpane',
"x-component-props": { "x-component-props": {
tab: '其他信息' tab: '其他信息'
}, },
properties: { properties: {
NO_SUBMIT_LAYOUT_ORTHER: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'left',
labelCol: 4,
wrapperCol: 10
},
properties: {
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
}
]
}
}
}
} }
} }
// 流转记录 // 流转记录
const transformRecord = { const transformRecord: ISchema = {
type: 'object', type: 'object',
"x-component": 'tabpane', "x-component": 'tabpane',
"x-component-props": { "x-component-props": {
tab: '流转记录' tab: '流转记录'
}, },
properties: { properties: {
RECORD: {
type: 'object',
"x-component": 'VirtualChildren',
"x-component-props": {
children: "{{CirculationRecord}}"
}
}
} }
} }
// 新增订单详情 // 新增订单详情
......
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { PublicApi } from '@/services/api';
export const memberSchema: ISchema = {
type: 'object',
properties: {
name: {
type: 'string',
"x-component": 'Search',
"x-component-props": {
placeholder: '请输入会员名称'
}
}
}
}
\ No newline at end of file
import {action, computed, observable, runInAction} from 'mobx' import {action, computed, observable, runInAction} from 'mobx'
import { IChannelProductModule, IRole, IChannel } from '@/module/channelProductModule'; // mobx要用到的数据类型 import { IChannelProductModule, IRole, IChannel } from '@/module/channelProductModule'; // mobx要用到的数据类型
import { GetProductChannelCommodityGetCommodityListResponseDetail, GetProductChannelCommodityGetCommodityUnitPriceResponse } from '@/services'; import { GetProductChannelCommodityGetCommodityUnitPriceResponse } from '@/services';
/** /**
* 渠道直采商品 * 渠道直采商品
...@@ -8,7 +8,7 @@ import { GetProductChannelCommodityGetCommodityListResponseDetail, GetProductCha ...@@ -8,7 +8,7 @@ import { GetProductChannelCommodityGetCommodityListResponseDetail, GetProductCha
class ChannelProductStore implements IChannelProductModule { class ChannelProductStore implements IChannelProductModule {
// 选择商品区块 // 选择商品区块
@observable public productSelectRowInStore: GetProductChannelCommodityGetCommodityListResponseDetail = null; @observable public productSelectRowInStore: any = null;
@observable public priceType: number = null @observable public priceType: number = null
@observable public productName: string = null @observable public productName: string = null
@observable public currentActiveKey: string = '1' @observable public currentActiveKey: string = '1'
...@@ -26,7 +26,7 @@ class ChannelProductStore implements IChannelProductModule { ...@@ -26,7 +26,7 @@ class ChannelProductStore implements IChannelProductModule {
// } // }
@action.bound @action.bound
public setProductSelectRowInStore(data: GetProductChannelCommodityGetCommodityListResponseDetail) { public setProductSelectRowInStore(data: any) {
this.productSelectRowInStore = data; this.productSelectRowInStore = data;
} }
......
...@@ -4,6 +4,11 @@ export const useLinkageUtils = () => { ...@@ -4,6 +4,11 @@ export const useLinkageUtils = () => {
const { setFieldState } = createFormActions() const { setFieldState } = createFormActions()
const linkage = (key, defaultValue?) => (path, value?) => const linkage = (key, defaultValue?) => (path, value?) =>
setFieldState(path, state => { setFieldState(path, state => {
const componentProps = state.props['x-component-props'] || {}
// 对象浅合并
if (key === 'props["x-component-props"]') {
value = Object.assign({}, componentProps, value)
}
FormPath.setIn(state, key, value !== undefined ? value : defaultValue) FormPath.setIn(state, key, value !== undefined ? value : defaultValue)
}) })
return { return {
...@@ -14,5 +19,6 @@ export const useLinkageUtils = () => { ...@@ -14,5 +19,6 @@ export const useLinkageUtils = () => {
loading: linkage('loading', true), loading: linkage('loading', true),
loaded: linkage('loading', false), loaded: linkage('loading', false),
value: linkage('value'), value: linkage('value'),
componentProps: linkage('props["x-component-props"]', {})
} }
} }
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