Commit a7c7aec2 authored by GuanHua's avatar GuanHua

feat:售后部分页面

parent 36936f8c
......@@ -3,7 +3,7 @@
* @Author: ghua
* @Date: 2020-10-29 11:10:30
* @Last Modified by: ghua
* @Last Modified time: 2020-10-30 14:34:01
* @Last Modified time: 2020-11-02 14:50:06
*/
export default {
......@@ -61,14 +61,14 @@ export default {
{
// 新增退货发货单
path: '/memberCenter/afterService/exchange/waitAddReturnOrder/add',
name: 'waitAddReturnOrder',
name: 'waitAddReturnOrderToAdd',
hideInMenu: true,
component: '@/pages/afterService/exchangeGoods/waitAddReturnOrder/opration/add'
},
{
// 退货发货单详情
path: '/memberCenter/afterService/exchange/waitAddReturnOrder/detail',
name: 'waitAddReturnOrder',
name: 'waitAddReturnOrderToAdd',
hideInMenu: true,
component: '@/pages/afterService/exchangeGoods/waitAddReturnOrder/opration/add'
},
......
......@@ -3,7 +3,7 @@ import {StandardTable} from 'god'
import NestTable from '@/components/NestTable'
import { IStandardTableProps } from 'god/dist/src/standard-table'
import { Row, Col, Modal } from 'antd'
import { productModalSchema, productModalByMemberSchema, memberModalSchema, inquirySchema, demandSchema,enquirySchema, mergeOrderSchema } from './schema'
import { productModalSchema, productModalByMemberSchema, memberModalSchema, inquirySchema, demandSchema, enquirySchema, mergeOrderSchema, goodsModalSchema } from './schema'
import Search from '../NiceForm/components/Search'
import SearchSelect from '../NiceForm/components/SearchSelect'
import Submit from '../NiceForm/components/Submit'
......@@ -18,7 +18,7 @@ export interface ModalTableProps extends IStandardTableProps<any> {
cancel?(),
visible?: boolean,
resetModal?: object,
modalType?: 'productByDefault' | 'productByMember' | 'memberByDefault' | 'inquiryByDefault' | 'demandByDefault' | 'enquiryModel' | 'MergeOrderByDefault' | 'none' ,
modalType?: 'productByDefault' | 'productByMember' | 'memberByDefault' | 'inquiryByDefault' | 'demandByDefault' | 'enquiryModel' | 'MergeOrderByDefault' | 'goodsModalSchema' | 'none' ,
useNestTable?: boolean, // 是否使用嵌套表格
nestColumns?: any[],
nestTableProps?: any,
......@@ -67,6 +67,9 @@ const ModalTable:React.FC<ModalTableProps> = (props) => {
case 'MergeOrderByDefault': {
return mergeOrderSchema
}
case 'goodsModalSchema': {
return goodsModalSchema
}
case 'none': {
return {}
}
......@@ -93,7 +96,7 @@ const ModalTable:React.FC<ModalTableProps> = (props) => {
<StandardTable
tableType='small'
currentRef={selfRef}
formRender={(child, ps) => <Row justify='space-between'>
formRender={(child, ps) => <Row justify='space-between' style={{marginBottom: 16}}>
<Col span={18} style={{ zIndex: 99 }}>{child}</Col>
<Col style={{ marginTop: 4 }}>{ps}</Col>
</Row >}
......
......@@ -128,6 +128,89 @@ export const productModalSchema: ISchema = {
}
}
/**
* 货品列表筛选
*/
export const goodsModalSchema: 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: {
code: {
type: 'string',
'x-component-props': {
placeholder: '货号',
style: {
width: 160
}
},
},
customerCategoryId: {
type: 'string',
"x-component": 'SearchSelect',
'x-component-props': {
placeholder: '品类',
fetchSearch: PublicApi.getProductSelectGetSelectCustomerCategory,
style: {
width: 160
}
},
},
brandId: {
type: 'string',
"x-component": 'SearchSelect',
'x-component-props': {
placeholder: '品牌',
fetchSearch: PublicApi.getProductSelectGetSelectBrand,
style: {
width: 160
}
},
},
type: {
type: 'string',
'x-component-props': {
placeholder: '规格型号',
style: {
width: 160
}
},
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
},
}
}
export const memberModalSchema: ISchema = {
type: 'object',
properties: {
......
......@@ -476,6 +476,7 @@ export default {
'menu.afterService.exchange.waitSubmitOrderListToAdd': '新增换货申请单',
'menu.afterService.exchange.waitSubmitOrderListToEdit': '编辑换货申请单',
'menu.afterService.exchange.waitAddReturnOrder': '待新增退货发货单',
'menu.afterService.exchange.waitAddReturnOrderToAdd': '新增退货发货单',
'menu.afterService.exchange.waitAddLogisticsOrder': '待新增物流单',
'menu.afterService.exchange.waitAddLogisticsOrderToAdd': '新增物流单',
'menu.afterService.exchange.waitReturnDeliveryOrder': '待退货发货',
......@@ -491,6 +492,7 @@ export default {
'menu.afterService.handleExchange.waitExamineLevelTwo': '待审核换货申请单(二级)',
'menu.afterService.handleExchange.waitConfirmExchangeOrder': '待确认换货申请单',
'menu.afterService.handleExchange.waitAddReturnOrder': '待新增退货入库单',
'menu.afterService.handleExchange.waitAddReturnOrderToAdd': '新增退货入库单',
'menu.afterService.handleExchange.waitReturnReceivingOrder': '待退货收货',
'menu.afterService.handleExchange.waitSendOutOrder': '待新增换货发货单',
'menu.afterService.handleExchange.waitAddLogisticsOrder': '待新增物流单',
......
......@@ -7,8 +7,6 @@
.common_comfirm {
position: relative;
}
.common_tb {
......@@ -42,4 +40,29 @@
position: relative;
padding: 5.6px 0;
}
}
.form_tabs {
position: relative;
:global {
.ant-tabs-nav {
margin-bottom: 24px;
}
.ant-tabs-tab {
border: 1px solid #FFFFFF !important;
border-bottom: 1px solid #f0f0f0 !important;
&-active {
border: 1px solid #DCDFE6 !important;
border-bottom: 1px solid #ffffff !important;
}
}
.ant-form-item-label>label {
font-size: 12px !important;
color: #909399;
}
}
}
\ No newline at end of file
import React from 'react'
import { formatTimeString } from '@/utils'
import { ORDER_TYPE } from '@/constants'
import StatusColors from '../components/StatusColors'
import { ORDER_TYPE, PurchaseOrderOutWorkStateTexts } from '@/constants'
import EyePreview from '@/components/EyePreview'
......@@ -103,13 +103,17 @@ export const baseWaitAddReturnOrderColumns: any[] = [
title: '外部状态',
dataIndex: 'outerStatus',
key: 'outerStatus',
render: text => <StatusColors status={text} type='out' />
render: text => <StatusColors status={text} type='out' />,
filters: Object.entries(PurchaseOrderOutWorkStateTexts).map(([key, value]) => ({ text: value, value: Number(key) })),
onFilter: (value, record) => value === record.externalState,
},
{
title: '内部状态',
dataIndex: 'innerStatus',
key: 'innerStatus',
render: (text) => <StatusColors status={text} type='inside' />
render: (text) => <StatusColors status={text} type='inside' />,
filters: Object.entries(PurchaseOrderOutWorkStateTexts).map(([key, value]) => ({ text: value, value: Number(key) })),
onFilter: (value, record) => value === record.externalState,
},
]
......
import React, { useRef } from 'react'
import { baseOrderListColumns } from '../../../common/columns'
import { baseOrderListColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
import EyePreview from '@/components/EyePreview'
......
import React, { useRef } from 'react'
import { baseWaitAddReturnOrderColumns } from '../../../common/columns'
import { baseWaitAddReturnOrderColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
// 业务hooks
......
import React, { useRef } from 'react'
import { Button } from 'antd'
import { Link } from 'umi'
import { baseWaitAddReturnOrderColumns } from '../../../common/columns'
import { baseWaitAddReturnOrderColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
import styles from '../opration/orderForm/index.less'
......
import { PublicApi } from '@/services/api'
export const fetchOrderApi = {
// 弹窗获取商品列表
async getProductList(params) {
const { data } = await PublicApi.getProductCommodityCommonGetCommodityListByBuyer(params)
return data
},
}
\ No newline at end of file
......@@ -59,7 +59,7 @@ export const ProductTableCell:React.FC<ProductTableCellProps> = ({
const chooseFormItem = (type) => {
switch(type) {
case 'input': {
return <Input style={{width: 140}} type='number' ref={formItemRef} onChange={save} {...formItemProps} id={dataIndex + record.id}/>
return <Input style={{width: 128}} type='number' ref={formItemRef} onChange={save} {...formItemProps} id={dataIndex + record.id}/>
}
}
}
......
......@@ -31,35 +31,35 @@ export const replaceGoodsTableColumn: any[] = [
{
title: '数量',
dataIndex: 'amount',
ellipsis: true,
key: 'amount',
formItem: 'input',
editable: true,
width: 128
width: 150
},
{
title: '箱数',
dataIndex: 'carton',
ellipsis: true,
key: 'carton',
formItem: 'input',
editable: true,
forceEdit: true,
width: 128
width: 150
},
{
title: '重量(KG)',
dataIndex: 'weight',
ellipsis: true,
key: 'weight',
formItem: 'input',
editable: true,
width: 128
width: 150
},
{
title: '体积(M3)',
dataIndex: 'volume',
ellipsis: true,
key: 'volume',
formItem: 'input',
editable: true,
width: 128
width: 150
},
{
title: '操作',
......
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 React, { useState, useRef} from 'react'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { Button } from 'antd'
import { useModalTable } from './useModalTable'
import ProductTableCell, { ProductEditableRow } from '../component/productTableCell';
import { PlusOutlined } from '@ant-design/icons'
import { replaceGoodsTableColumn } from '../constant'
import styles from '../orderForm/index.less'
export const useProductTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const [visible, setVisible] = useState<boolean>(false)
// const [visible, setVisible] = useState<boolean>(false)
const productRef = useRef<any>({})
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({ type: 'checkbox' })
const [productColumns] = useState(() => {
replaceGoodsTableColumn[replaceGoodsTableColumn.length - 1].render = (text, record) => {
......@@ -42,12 +43,48 @@ export const useProductTable = (ctx: ISchemaFormActions | ISchemaFormAsyncAction
}
}
const handleSave = row => {
return new Promise((resolve, reject) => {
const newData = [...ctx.getFieldValue('detailList')];
const index = newData.findIndex(item => row.id === item.id);
const item = newData[index];
// row['money'] = getUnitPriceTotal(row)
row['productId'] = row.id
newData.splice(index, 1, {
...item,
...row,
});
ctx.setFieldValue('detailList', 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,
addReplaceGoodsButton,
productColumns: productColumns,
productColumns: productMergeColumns,
productComponents,
visible,
setVisible
setVisible,
rowSelection,
rowSelectionCtl
}
}
\ No newline at end of file
@import '../../../../common/styles.less';
.form_tabs {
position: relative;
:global {
.ant-tabs-nav {
margin-bottom: 24px;
}
.ant-tabs-tab {
border: 1px solid #FFFFFF !important;
border-bottom: 1px solid #f0f0f0 !important;
&-active {
border: 1px solid #DCDFE6 !important;
border-bottom: 1px solid #ffffff !important;
}
}
.ant-form-item-label>label {
font-size: 12px !important;
color: #909399;
}
}
}
......@@ -38,54 +38,28 @@ const RowStyle = styled(props => <Row style={{ marginTop: 12 }} justify='end' {.
font-weight: bold;
}
`
// 总计金额联动框
export const MoneyTotalBox = registerVirtualBox('moneyTotalBox', props => {
// @todo 由于缺乏商品字段, 目前选用假数据
// const { form } = useFormSpy({ selector: [['onFieldValueChange', 'orderProductRequests']], reducer: v => v })
// const data = form.getFieldValue('orderProductRequests')
// const receiverAddressId = form.getFieldValue('deliveryAddresId')
// const sum = data.reduce((prev, next) => prev + (next.money || 0), 0)
// const [freePrice, setFreePrice] = useState<number>(0)
// useEffect(() => {
// if (sum + freePrice) {
// form.notify('sumPrice', sum + freePrice)
// }
// }, [sum, freePrice])
// useEffect(() => {
// // 存在商品 并且有选择收货地址,则开始计算运费
// if (data && data.length > 0 && receiverAddressId) {
// // 筛选配送方式为物流的商品并且使用了运费模板
// const logsiticsDataMaps = data.filter(v => v.logistics && v.logistics.useTemplate && v.logistics.deliveryType === 1)
// if (logsiticsDataMaps.length > 0) {
// PublicApi.postLogisticsFreightRemoteAddDetail({
// orderProductList: logsiticsDataMaps.map(v => ({
// templateId: v.logistics.templateId,
// weight: v.logistics.weight
// })),
// receiverAddressId: typeof receiverAddressId === 'object' ? receiverAddressId.id : receiverAddressId
// }, { ttl: 10 * 1000, useCache: true, ctlType: 'none' }).then(res => {
// if (res.code === 1000) {
// setFreePrice(res.data)
// }
// })
// }
// }
// }, [data])
// 总计联动框
export const TotalBox = registerVirtualBox('totalBox', props => {
const { form } = useFormSpy({ selector: [['onFieldValueChange', 'detailList']], reducer: v => v })
const data = form.getFieldValue('detailList')
console.log(data, "data")
const cartonSum = data.reduce((prev, next) => prev + (next.carton || 0), 0)
const weightSum = data.reduce((prev, next) => prev + (next.weight || 0), 0)
const volumeSum = data.reduce((prev, next) => prev + (next.volume || 0), 0)
return <RowStyle>
<Col span={2}>
<div className="title">总箱数(箱)</div>
<div className="count">{0}</div>
<div className="count">{cartonSum}</div>
</Col>
<Col span={2}>
<div className="title">总重量(KG)</div>
<div className="count">{0}</div>
<div className="count">{weightSum}</div>
</Col>
<Col span={2}>
<div className="title">总体积(M3)</div>
<div className="count">{0}</div>
<div className="count">{volumeSum}</div>
</Col>
</RowStyle>
})
......@@ -104,7 +78,7 @@ const OrderForm: React.FC<OrderFormPropsType> = (props) => {
setInitFormValue({
deliveryType: 1,
applyAbstract: "进口头层黄牛皮荔枝纹",
replaceGoodsList: [
detailList: [
{
id: 1,
productId: '1110',
......@@ -227,7 +201,7 @@ const OrderForm: React.FC<OrderFormPropsType> = (props) => {
AddressSelect
}}
/>
<SelectProdcutModal currentRef={productRef} sectionProps={sectionProps} />
<SelectProdcutModal currentRef={productRef} schemaAction={addSchemaAction} sectionProps={sectionProps} />
</Card>
</WaitAddLogisticsOrderContext.Provider>
</PageHeaderWrapper>
......
......@@ -135,20 +135,21 @@ const logisticsInfo: ISchema = {
children: '{{addReplaceGoodsButton}}',
},
},
replaceGoodsList: {
detailList: {
type: 'array',
"x-component": 'MultTable',
"x-component-props": {
rowKey: 'id',
columns: "{{productColumns}}",
// components: "{{productComponents}}",
components: "{{productComponents}}",
className: "common_tb",
pagination: false,
rowClassName: (_, index) => (index % 2) === 0 && "tb_bg"
},
},
NO_SUBMIT_SPY: {
type: 'object',
"x-component": "moneyTotalBox"
"x-component": "totalBox"
}
},
},
......@@ -179,7 +180,6 @@ const historyRecord: ISchema = {
'x-component-props': {
rowKey: 'id',
columns: "{{historyCloumn}}",
components: "{{productComponents}}",
className: "common_tb",
rowClassName: (_, index) => (index % 2) === 0 && "tb_bg"
}
......
import { createContext } from 'react';
export const waitAddReturnOrder = createContext<any>({})
\ No newline at end of file
import React, { useRef } from 'react'
import { Button, Modal } from 'antd'
import { baseWaitAddReturnOrderColumns } from '../../../common/columns'
import { baseWaitAddReturnOrderColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
import EyePreview from '@/components/EyePreview'
import styles from '../opration/orderForm/index.less'
......
import { PublicApi } from '@/services/api'
export const fetchOrderApi = {
// 弹窗获取商品列表
async getProductList(params) {
const { data } = await PublicApi.getProductCommodityCommonGetCommodityListByBuyer(params)
return data
},
// 弹窗获取货品列表
async getGoodsList(params) {
const { data } = await PublicApi.getProductGoodsGetGoodsList(params)
return data
},
}
\ No newline at end of file
import React, { useState, useEffect } from 'react'
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'
import { Row, Col } from 'antd'
import styled from 'styled-components'
import cx from 'classnames'
const SelectStyles = styled((props) => <div className='select-list' {...props}></div>)`
.select_style_border {
border: 1px solid #EEF0F3;
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 14px;
width: 549px;
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 AddressSelect = (props) => {
const [showMore, setShowMore] = useState<boolean>(true)
const [dataSource, setDataSource] = useState<any[]>([])
const { value = {} } = props
const showCount = 3
useEffect(() => {
const componentProps = props.props['x-component-props']
const addressList = componentProps.addressList
if (addressList) {
setDataSource(addressList)
}
}, [props])
useEffect(() => {
if (dataSource && dataSource.length > 0) {
let initItem = dataSource[0] || {}
props.mutators.change(initItem)
}
}, [dataSource])
const showDataSource = showMore ? [...dataSource].splice(0, showCount) : dataSource
const handleCheck = (v) => {
if (v.id !== value.id) {
props.mutators.change(v)
}
}
const toogleMore = () => {
setShowMore(!showMore)
}
return (
<div style={{ width: '100%' }}>
<SelectStyles>
{
showDataSource && showDataSource.map(v => <div key={v.id} onClick={() => handleCheck(v)} className={cx('select_style_border', value.id === v.id ? 'active' : '')}>
<div>
<Row style={{ color: '#303133' }}>
<Col>{v.receiverName || v.shipperName}</Col>
<Col> / </Col>
<Col>{v.phone}</Col>
</Row>
<div style={{ color: '#909399' }}>{v.fullAddress}</div>
</div>
</div>)
}
</SelectStyles>
{dataSource.length > showCount &&
<div onClick={toogleMore} style={{ textAlign: 'center', cursor: 'pointer' }}>
显示更多{showMore ? <CaretDownOutlined /> : <CaretUpOutlined />}
</div>
}
</div>
)
}
AddressSelect.defaultProps = {}
AddressSelect.isFieldComponent = true
export default AddressSelect
import React, { useState, useRef, useContext, useEffect } from 'react'
import { Form, Input, Select } from 'antd';
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) => {
switch(type) {
case 'input': {
return <Input style={{width: 128}} type='number' ref={formItemRef} onChange={save} {...formItemProps} id={dataIndex + record.id}/>
}
}
}
let childNode = children;
if (editable) {
childNode =
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
initialValue={record[dataIndex] || ''}
rules={[
{
required: true,
message: `${title}必须填写`,
},
]}
>
{chooseFormItem(formItem)}
</Form.Item>
}
return <td {...restProps}>{childNode}</td>;
}
ProductTableCell.defaultProps = {}
export default ProductTableCell
\ No newline at end of file
.upload_tip {
font-size: 12px;
color: #909399;
margin-top: 12px;
}
.flexStart {
position: relative;
align-self: flex-start;
}
.upload_btn {
margin-top: 8px;
}
.file_list {
&_item {
width: 572px;
height: 32px;
display: flex;
align-items: center;
background: #F4F5F7;
border-radius: 4px;
margin-bottom: 8px;
color: #00B37A;
padding: 0 8px;
.file_type {
margin-right: 4px;
&>img {
width: 20px;
height: 20px;
}
}
.del_btn {
color: #909399;
font-size: 14px;
cursor: pointer;
margin-left: auto;
}
}
}
\ No newline at end of file
import React, { useState } from 'react'
import { Button, Upload, message } from 'antd'
import { UploadFile, UploadChangeParam } from 'antd/lib/upload/interface'
import { UploadOutlined, DeleteOutlined } from '@ant-design/icons'
import { UPLOAD_TYPE } from '@/constants'
import fileTypeDoc from './imgs/file_type_doc.png'
import fileTypeOther from './imgs/file_type_other.png'
import fileTypePhoto from './imgs/file_type_photo.png'
import styles from './index.less'
const ProoFileUpload = (props) => {
const [loading, setLoading] = useState<boolean>(false)
const fileMaxSize = 1024 * 20
const beforeUpload = (file: UploadFile) => {
const isSizeLimit = file.size / 1024 < fileMaxSize;
if (!isSizeLimit) {
message.error(`附件大小不能超过 20M`);
}
return isSizeLimit;
}
const uploadProps = {
name: 'file',
action: '/api/file/file/upload',
headers: {},
data: {
fileType: UPLOAD_TYPE
},
disabled: loading,
showUploadList: false,
onChange(info: UploadChangeParam) {
if (info.file.status === 'uploading') {
setLoading(true)
return;
}
if (info.file.status === 'done') {
// 图片回显
const { code, data } = info.file.response
if (code === 1000) {
console.log('upload success')
let newFileArr = [...props.value]
newFileArr.push({
fileName: info.file.name,
filePath: data
})
props.mutators.change(newFileArr)
}
setLoading(false)
}
},
beforeUpload
};
const docFileTypeList = ['doc', 'docx', 'docm', 'xlsx', 'xlsm', 'pptx', 'xls']
const photoFileTypeList = ['png', 'jpg', 'jpeg', 'gif']
const getFileTypeByName = (fileName: string) => {
if (fileName && typeof fileName === 'string') {
let fileType = fileName.split('.')[1]
if (fileType) {
if (docFileTypeList.includes(fileType)) {
return <img src={fileTypeDoc} />
} else if (photoFileTypeList.includes(fileType)) {
return <img src={fileTypePhoto} />
} else {
return <img src={fileTypeOther} />
}
}
}
}
const handleDeleteFileItem = (index: number) => {
let newFileList = [...props.value]
newFileList.splice(index, 1)
props.mutators.change(newFileList)
}
return (
<div>
<div className={styles.file_list}>
{
props.value && props.value.map((item, index) => (
<div key={`file_list_item_${index}`} className={styles.file_list_item}>
<i className={styles.file_type}>
{
getFileTypeByName(item.fileName)
}
</i>
<span>{item.fileName}</span>
<DeleteOutlined className={styles.del_btn} onClick={() => handleDeleteFileItem(index)} />
</div>
))
}
</div>
<Upload {...uploadProps}>
<Button icon={<UploadOutlined />} className={styles.upload_btn}>上传文件</Button>
</Upload>
<p className={styles.upload_tip}>一次上传一个文件,每个附件大小不能超过 20M</p>
</div>
)
}
ProoFileUpload.defaultProps = {};
ProoFileUpload.isFieldComponent = true;
export default ProoFileUpload;
import React, { useEffect } from 'react'
import ModalTable, { ModalTableProps } from '@/components/ModalTable'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
import { fetchOrderApi } from '../../apis'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { DELIVERY_TYPE, OrderModalType } from '@/constants'
import { PublicApi } from '@/services/api'
import { EnvironmentOutlined } from '@ant-design/icons'
import { Popover, Space, Row } from 'antd'
export interface ProductModalTableProps extends ModalTableProps {
type?: 'radio' | 'checkbox',
schemaAction: ISchemaFormActions | ISchemaFormAsyncActions,
currentRef?: any,
sectionProps: any,
confirmModal?()
}
export const productColumns: any[] = [
{
title: '货号',
dataIndex: 'code',
align: 'center',
key: 'code',
},
{
title: '货品名称',
dataIndex: 'name',
align: 'center',
key: 'name',
},
{
title: '规格型号',
dataIndex: 'type',
align: 'center',
key: 'type',
},
{
title: '品类',
dataIndex: 'customerCategory',
align: 'center',
key: 'category',
render: (customerCategory) => customerCategory.name
},
{
title: '品牌',
dataIndex: 'brand',
align: 'center',
render: (brand) => brand.name
},
]
// 下单类型->商城类型映射
const orderProductShopTypeMaps = {
[OrderModalType.HAND_ORDER]: 1,
[OrderModalType.CONSOLIDATED_ORDER]: 1,
[OrderModalType.CHANNEL_DIRECT_MINING_ORDER]: 3,
[OrderModalType.CHANNEL_SPOT_MANUAL_ORDER]: 4
}
export const AddressPop = (props) => {
const { pickInfo = null, children } = props
return pickInfo && pickInfo.deliveryType === 2 ? <Space>
<EnvironmentOutlined style={{ marginRight: 8 }} />
<Popover content={
<Row>
<EnvironmentOutlined />
<div>
<h3>自提地址</h3>
<p>{pickInfo.receiverName} / {pickInfo.phone}</p>
<p>{pickInfo.fullAddress}</p>
</div>
</Row>
}>
{children}
</Popover>
</Space> : children
}
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
if (logistics.deliveryType === 2) {
const { code, data } = await PublicApi.getLogisticsShipperAddressGet({
id: logistics.sendAddress
}, { ttl: 60 * 1000, useCache: true })
logistics.render = code === 1000 ? <AddressPop pickInfo={data}>{DELIVERY_TYPE[logistics.deliveryType]}</AddressPop> : DELIVERY_TYPE[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 () => {
console.log(rowSelectionCtl)
// 判断所选择的商品是否属于同一个工作流
// const { code, data } = await PublicApi.postOrderIsWorkFlow({ productIds: rowSelectionCtl.selectedRowKeys }, { ctlType: 'none' })
// if (code === 1000) {
// const productData = schemaAction.getFieldValue('orderProductRequests')
// schemaAction.setFieldValue('orderProductRequests', await filterProductDataById(productData, rowSelectionCtl.selectRow))
// confirmModal && confirmModal()
// setVisible(false)
// }
}
const fetchGoodsList = (values) => {
const modelType = schemaAction.getFieldValue('orderModel')
const supplyMembersId = schemaAction.getFieldValue('supplyMembersId')
const params = {
...values,
shopType: orderProductShopTypeMaps[modelType],
environment: 1,
memberId: supplyMembersId,
// 手工下单/合并订单下单时,查询现货价格商品
priceTypeList: modelType === (OrderModalType.CONSOLIDATED_ORDER || OrderModalType.HAND_ORDER) ? [1] : undefined
}
return fetchOrderApi.getGoodsList(params)
}
return (
<ModalTable
modalTitle='选择货品'
width={800}
columns={productColumns}
visible={visible}
confirm={handleConfirmProduct}
cancel={() => setVisible(false)}
fetchTableData={fetchGoodsList}
rowSelection={rowSelection}
modalType='goodsModalSchema'
tableProps={{
rowKey: 'id',
className: "common_tb",
rowClassName: (_, index) => (index % 2) === 0 && "tb_bg",
onRow: (record) => ({
onClick: () => {
rowSelectionCtl.appendSelectRow(record);
rowSelectionCtl.appendSelectRowKeys(record.id);
},
})
}}
{...restProps}
/>
)
}
ProductModalTable.defaultProps = {}
export default ProductModalTable
\ No newline at end of file
import React from 'react'
import EyePreview from '@/components/EyePreview'
// 货品列表
export const replaceGoodsTableColumn: any[] = [
{
title: '货号',
dataIndex: 'code',
ellipsis: true,
},
{
title: '货品名称',
dataIndex: 'name',
ellipsis: true,
},
{
title: '规格/型号',
dataIndex: 'type',
ellipsis: true,
},
{
title: '品类',
dataIndex: 'customerCategory',
ellipsis: true,
render: (customerCategory) => customerCategory ? customerCategory.name : ''
},
{
title: '品牌',
dataIndex: 'brand',
ellipsis: true,
render: (brand) => brand ? brand.name : ''
},
{
title: '单位',
dataIndex: 'unitName',
key: 'unitName',
ellipsis: true,
},
{
title: '退货商品名称',
dataIndex: 'productName',
key: 'productName',
ellipsis: true,
},
{
title: '商品ID',
dataIndex: 'productId',
key: 'productId',
ellipsis: true,
},
{
title: '单价',
dataIndex: 'volume1',
key: 'volume',
ellipsis: true,
},
{
title: '退货数量',
dataIndex: 'volume2',
key: 'volume',
ellipsis: true,
},
{
title: '退货金额',
dataIndex: 'volume3',
key: 'volume',
ellipsis: true,
},
{
title: '操作',
dataIndex: 'ctl',
key: 'ctl',
},
]
export const exchangeGoodsModalTableColumn: any[] = [
{
title: '订单号',
dataIndex: 'orderNo',
key: 'orderNo'
},
{
title: '订单摘要',
dataIndex: 'applyAbstract',
key: 'applyAbstract',
},
{
title: '供应会员',
dataIndex: 'supplierName',
key: 'supplierName',
// render: text => formatTimeString(text)
},
{
title: '下单时间',
dataIndex: 'createTime',
key: 'createTime',
},
{
title: '订单状态',
dataIndex: 'orderStatus',
key: 'orderStatus'
},
{
title: '订单类型',
dataIndex: 'orderType',
key: 'orderType',
},
]
export const exchangeGoodsModalChildTableColumn: any[] = [
{
title: 'ID',
dataIndex: 'productId',
key: 'productId',
},
{
title: '商品名称',
dataIndex: 'productName',
key: 'productName',
},
{
title: '品类',
dataIndex: 'category',
key: 'category',
},
{
title: '品牌',
dataIndex: 'brand',
key: 'brand',
},
{
title: '单位',
dataIndex: 'unit',
key: 'unit',
},
{
title: '订单数量',
dataIndex: 'purchaseCount',
key: 'purchaseCount',
},
{
title: '采购单价',
dataIndex: 'purchasePrice',
key: 'purchasePrice',
},
{
title: '采购金额',
dataIndex: 'purchaseAmount',
key: 'purchaseAmount',
},
{
title: '已换货数量',
dataIndex: 'replaceCount',
key: 'replaceCount',
},
]
/**
* 内部流转记录
*/
export const innerHistoryColumns: any[] = [
{
title: '序号',
dataIndex: 'step',
ellipsis: true,
},
{
title: '操作人',
dataIndex: 'operator',
ellipsis: true,
},
{
title: '部门',
dataIndex: 'department',
ellipsis: true,
},
{
title: '职位',
dataIndex: 'jobTitle',
ellipsis: true,
},
{
title: '状态',
dataIndex: 'status',
ellipsis: true,
},
{
title: '操作',
dataIndex: 'operate',
ellipsis: true,
},
{
title: '操作时间',
dataIndex: 'operateTime',
ellipsis: true,
},
{
title: '审核意见',
dataIndex: 'opinion',
ellipsis: true,
},
]
/**
* 外部流转记录
*/
export const outerHistoryColumns: any[] = [
{
title: '序号',
dataIndex: 'step',
ellipsis: true,
},
{
title: '操作角色',
dataIndex: 'operator',
ellipsis: true,
},
{
title: '状态',
dataIndex: 'status',
ellipsis: true,
},
{
title: '操作',
dataIndex: 'operate',
ellipsis: true,
},
{
title: '操作时间',
dataIndex: 'operateTime',
ellipsis: true,
},
{
title: '审核意见',
dataIndex: 'opinion',
ellipsis: true,
},
]
import React, { useState, useEffect } from 'react'
import { Radio } from 'antd'
import { innerHistoryColumns, outerHistoryColumns } from '../constant'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { GetLogisticsReceiverAddressPageResponseDetail, GetLogisticsShipperAddressPageResponseDetail } from '@/services/LogisticsApi'
import { PublicApi } from '@/services/api'
export const useHistoryTabble = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const [historyCloumn, setHistoryCloumn] = useState<any>(outerHistoryColumns)
const [historyType, setHistoryType] = useState<number>(1)
const handleChange = (e) => {
const value = e.target.value
if (historyType !== value) {
setHistoryType(value)
switch (value) {
case 1:
setHistoryCloumn(outerHistoryColumns)
break
case 2:
setHistoryCloumn(innerHistoryColumns)
break
default:
break
}
}
}
// 流转记录
const historySelectBtnGroup = (
<Radio.Group
value={historyType}
onChange={handleChange}
options={
[
{ label: '外部流转(0)', value: 1 },
{ label: '内部流转(0)', value: 2 }
]
}
optionType="button"
/>
)
return {
historySelectBtnGroup,
historyCloumn
}
}
\ No newline at end of file
import React, { useState, useEffect } from 'react'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd'
import { GetLogisticsReceiverAddressPageResponseDetail, GetLogisticsShipperAddressPageResponseDetail } from '@/services/LogisticsApi'
import { PublicApi } from '@/services/api'
export const useLogistics= (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
const [receivingAddressList, setReceivingAddressList] = useState<GetLogisticsReceiverAddressPageResponseDetail[]>([]) // 收货地址
const [deliverAddressList, setDeliverAddressList] = useState<GetLogisticsShipperAddressPageResponseDetail[]>([]) // 发货地址
useEffect(() => {
getReceivingAddressList()
getDeliverAddressList()
},[])
/**
* 获取收货地址
*/
const getReceivingAddressList = () => {
let param = {
current: 1,
pageSize: 50
}
//@ts-ignore
PublicApi.getLogisticsReceiverAddressPage(param).then(res => {
if (res.code === 1000) {
setReceivingAddressList(res.data.data)
}
})
}
/**
* 获取发货地址
*/
const getDeliverAddressList = () => {
let param = {
current: 1,
pageSize: 50
}
//@ts-ignore
PublicApi.getLogisticsShipperAddressPage(param).then(res => {
if (res.code === 1000) {
setDeliverAddressList(res.data.data)
}
})
}
return {
receivingAddressList,
deliverAddressList
}
}
\ No newline at end of file
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 React, { useState, useRef} from 'react'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { Button } from 'antd'
import { useModalTable } from './useModalTable'
import ProductTableCell, { ProductEditableRow } from '../component/productTableCell';
import { PlusOutlined } from '@ant-design/icons'
import { replaceGoodsTableColumn } from '../constant'
import styles from '../orderForm/index.less'
export const useProductTable = (ctx: ISchemaFormActions | ISchemaFormAsyncActions) => {
// const [visible, setVisible] = useState<boolean>(false)
const productRef = useRef<any>({})
const { visible, setVisible, rowSelection, rowSelectionCtl } = useModalTable({ type: 'checkbox' })
const [productColumns] = useState(() => {
replaceGoodsTableColumn[replaceGoodsTableColumn.length - 1].render = (text, record) => {
return <div className={styles.operation_btn_group}>
<Button type="link" className={styles.operation_btn}>删除</Button>
</div>
}
return replaceGoodsTableColumn
})
const handleSelectProduct = () => {
productRef.current.setVisible(true)
}
const TableAddButton = (
<Button
style={{ backgroundColor: '#FAFBFC' }}
block
icon={<PlusOutlined />}
onClick={handleSelectProduct}
type="dashed"
>
新建单据明细
</Button>
)
const productComponents = {
body: {
row: ProductEditableRow,
cell: ProductTableCell
}
}
const handleSave = row => {
return new Promise((resolve, reject) => {
const newData = [...ctx.getFieldValue('detailList')];
const index = newData.findIndex(item => row.id === item.id);
const item = newData[index];
// row['money'] = getUnitPriceTotal(row)
row['productId'] = row.id
newData.splice(index, 1, {
...item,
...row,
});
ctx.setFieldValue('detailList', 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,
TableAddButton,
productColumns: productMergeColumns,
productComponents,
visible,
setVisible,
rowSelection,
rowSelectionCtl
}
}
\ No newline at end of file
import React, { useRef } from 'react'
import { baseWaitAddReplaceOrderColumns } from '../../../common/columns'
import { baseWaitAddReplaceOrderColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
// 业务hooks
......
import React, { useRef } from 'react'
import { baseOrderListColumns } from '../../../common/columns'
import { baseOrderListColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
// 业务hooks
......
import React, { useRef } from 'react'
import { baseWaitAddReplaceOrderColumns } from '../../../common/columns'
import { baseWaitAddReplaceOrderColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
// 业务hooks
......
import React, { useRef } from 'react'
import { baseWaitAddReturnOrderColumns } from '../../../common/columns'
import { baseWaitAddReturnOrderColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
// 业务hooks
......
import React, { useRef } from 'react'
import { baseOrderListColumns } from '../../../common/columns'
import { baseOrderListColumns } from '../../../contants/replaceGoodsColumns'
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable'
// 业务hooks
......
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