Commit a1bd8ef1 authored by Bill's avatar Bill

refactor: 重构加工

parent eb1c4aa8
import moment from 'moment';
import React from 'react';
import { ORDER_TYPE } from '@/constants/order'
export const orderColumns = [
{
title: '订单号/摘要',
dataIndex: 'orderNoAndDesc',
render: (text, record) => {
return (
<div>
<p>{record.orderNo}</p>
<p>{record.orderThe}</p>
</div>
)
}
},
{
title: "采购会员",
dataIndex: 'memberName'
},
{
title: '下单时间',
dataIndex: 'createTime',
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '订单状态',
dataIndex: 'externalStateName',
},
{
title: '订单类型',
dataIndex: 'type',
render: (text, record) => {
// :1.询价采购2.需求采购3.现货采购4.集采5.渠道直采6.渠道现货7.积分兑换8.渠道积分兑换
return (
<span>{ORDER_TYPE[text] || ''}</span>
)
}
}
]
export const orderProductColumns = [
{
title: '商品ID/名称',
dataIndex: 'id'
},
{
title: '品类',
dataIndex: 'category',
},
{
title: '品牌',
dataIndex: 'brand'
},
{
title: '单位',
dataIndex: 'unit'
},
{
title: '订单数量',
dataIndex: 'purchaseCount'
},
{
title: '剩余加工数量',
dataIndex: 'restNum',
render: (text, record) => +record.purchaseCount - (+record.processNum || 0)
},
{
title: '已加工数量',
dataIndex: 'processNum',
render: (text) => text || 0
}
]
/**
* 加工商品schema
*/
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { ISchema } from '@formily/antd';
export const orderSchema: ISchema = {
type: 'object',
properties: {
megaLayout: {
type: 'object',
'x-component': 'mega-layout',
properties: {
name: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
placeholder: '搜索商品名称',
align: 'flex-left',
tip: '输入商品名称进行搜索',
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
full: true,
columns: 3,
},
properties: {
customerCategoryId: {
type: 'string',
'x-component': 'Cascader',
'x-component-props': {
placeholder: '请选择商品品类',
allowClear:true,
style: {
width: '160px',
// margin: '0 20px 0 0'
},
fieldNames: { label: 'title', value: 'id', children: 'children' }
}
},
brandId: {
type: 'string',
// 'x-component': 'Select',
enum: [],
'x-component-props': {
placeholder: '请选择商品品牌',
allowClear:true,
showSearch: true,
optionFilterProp: "children",
}
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
},
},
},
},
};
import React, { useMemo } from 'react';
import {
SchemaMarkupField as Field,
} from '@formily/antd'
import { Row, Col } from 'antd';
type ValueType = {
name: string,
value: string | number
}
interface Iprops {
value: ValueType[],
}
const FormilyProductAttrsLayout: React.FC<Iprops> & { isFieldComponent: boolean } = (props: Iprops) => {
const { value } = props;
const titleStyle = useMemo(() => {
return {
paddingLeft: '8px',
marginBottom: '24px',
lineHeight: '14px',
fontSize: '14px',
fontWeight: 500,
borderLeft: '2px solid #00B37A',
}
}, [])
const cacheValue = useMemo(() => value, [value])
return (
<>
{
cacheValue?.map((item, key) => {
return (
<div key={key} style={key < value.length - 1 ? {marginBottom: '24px'} : {}}>
<div style={titleStyle}>{item.name}</div>
<Row>
<Col span={4} style={{color: '#909399'}}>{item.name}</Col>
<Col span={18}>{item.value}</Col>
</Row>
</div>
)
})
}
</>
)
}
FormilyProductAttrsLayout.isFieldComponent = true;
export default FormilyProductAttrsLayout
.container {
display: flex;
flex-direction: row;
height: 100%;
.menu {
flex-basis: 159px;
display: flex;
flex-direction: column;
justify-content: start;
height: 100%;
.menuItem {
font-size: 12px;
font-weight: 500;
// color: #303133;
line-height: 12px;
padding: 18px 0px;
cursor: pointer;
// border-left: 2px solid transparent;
transition: all 0.2s ease-in-out;
.menuTitle {
border-left: 2px solid transparent;
padding-left: 16px;
}
.active {
color: #303133;
border-left: 2px solid #00B37A;
}
}
}
.body {
flex: 1;
display: flex;
flex-direction: column;
border-left: 1px solid #EEF0F3;
overflow: scroll;
overflow-x: hidden;
padding: 12px;
// .common {
// padding: 24px 24px 0 16px;
// .header {
// border-left: 2px solid #00B37A;
// color: #606266;
// padding: 0 10px;
// line-height: 14px;
// margin-bottom: 24px;
// font-size: 14px;
// // &:before {
// // content: '';
// // display: inline-block;
// // height: 8px;
// // width: 2px;
// // background-color: #00B37A;
// // }
// }
// .info {
// .infoRow {
// margin-bottom: 24px;
// .label {
// color: #909399;
// }
// }
// }
// }
}
}
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Drawer, Row, Col, Space, Button } from 'antd'
import { useScroll } from '@umijs/hooks';
import styles from './index.less';
// import useGetClientRect from './useGetClientRect';
import { createFormActions, FormEffectHooks, registerVirtualBox } from '@formily/antd';
import classnames from 'classnames'
import NiceForm from '@/components/NiceForm';
import schema from './schema';
import FormilyProductAttrsLayout from './formilyProductAttrsLayout';
const formActions = createFormActions();
/**
* 查看加工明细
*/
/** 查看或编辑 加工商品, 商品的属性 */
export type productInfo = {
/** 当加工订单时,拥有id 唯一 */
id?: number,
/** 当加工订单时,拥有orderid 订单id */
orderId?: number,
/** 当加工订单时,拥有orderNo 订单👌 */
orderNo?: number
/** skuid 属于唯一值 */
skuid: number,
commodityId: number,
/** 商品名 */
name: string,
/** 品类 */
category: string,
/** 品牌 */
brand: string,
/** 单位 */
unitName: string,
/** 含税跟税率合在一起的文字显示 */
isHasTaxAndTaxRate?: string,
/** 是否含税 */
isHasTax?: 0 | 1,
/** 税率 */
taxRate?: string,
/** 加工数量 */
processNum?: string,
/** 加工单价 */
processUnitPrice?: string,
/** 加工数量 * 加工单价 */
processTotalPrice?: number,
/** 附件 */
enclosure?: {
name: string,
url: string
}[],
/** 商品属性 */
productProps: {
name: string,
value: string
}[]
}
interface Iprops {
visible: boolean,
onClose?: (() => void) | null,
onSubmit?: ((values: any) => void) | null,
/**
* 当前商品值
*/
value: productInfo
// dataProps: DataPropsType
}
/**
* 修改商品 提交数据
*/
export type productSubmitType = {
/** 当加工订单时,拥有id 唯一 */
id?: number,
/** 当加工订单时,拥有orderid 订单id */
orderId?: number,
/** 当加工订单时,拥有orderNo 订单👌 */
orderNo?: number
/** skuid, 用这个去判断工作流 */
skuid: number,
commodityId: number,
brand: string,
category: string,
/** 商品名 */
name: string,
enclosure: {
name: string,
url: string,
status: "done"
type: "image/jpeg"
}[],
/** 是否含税 */
isHasTax: (0 | 1) & number,
/** 税率 */
taxRate: string,
/** 加工数量 */
processNum: string,
/** 商品属性 */
productProps: { name: string, value: string }[],
unitName: string,
/** 加工单价 */
processUnitPrice: string,
}
const ProductDrawer: React.FC<Iprops> = (props: Iprops) => {
const { visible, onClose, onSubmit, value } = props;
const [scroll, ref] = useScroll<HTMLDivElement>();
const [menu, setMenu] = useState<string[]>([])
const [rangeHeight, setRangeHeight] = useState<number[]>([])
const [activeIndex, setActiveIndex] = useState<number>(0);
const activeAndScroll = (index: number) => {
setActiveIndex(index);
ref.current.scrollTop = rangeHeight[index]
}
/**
* @tofix 这里有个bug,就是上面点击了之后,然后滚动,然后再做了一次计算,会有问题
*/
useEffect(() => {
const { top } = scroll;
let activeKey = 0;
for (let i = 0; i < rangeHeight.length - 1; i++) {
if (top >= rangeHeight[i] && top < rangeHeight[i + 1]) {
activeKey = i;
break;
}
activeKey = i + 1;
}
// console.log(activeKey)
setActiveIndex(activeKey)
}, [scroll])
useEffect(() => {
if (!visible) {
return;
}
const childNodes = ref.current.childNodes;
if (!childNodes) {
return
}
const formNode = childNodes[0].childNodes[0].childNodes[0].childNodes
const menuData = [];
let sum = 0;
const ranges = [0];
formNode.forEach((_item) => {
const { title, offsetHeight } = getMenuAndHeight(_item);
if ((_item as any).className.includes("ant-row")) {
const attributes = _item.childNodes[0].childNodes[0].childNodes[0].childNodes;
attributes.forEach((_row) => {
const { title, offsetHeight } = getMenuAndHeight(_row);
saveRangeAndMenuData(menuData, ranges, title, sum += offsetHeight);
})
return;
}
saveRangeAndMenuData(menuData, ranges, title, sum += offsetHeight);
})
setMenu(menuData.filter(Boolean));
setRangeHeight(ranges);
}, [visible, ref])
const getMenuAndHeight = (node) => {
const title = (node.firstChild as any)?.innerText || ''
const offsetHeight = (node as any).offsetHeight;
return { title, offsetHeight }
}
const saveRangeAndMenuData = (menuData: string[], ranges: number[], title: string, resultHeight: number) => {
menuData.push(title)
// sum += offsetHeight;
ranges.push(resultHeight);
}
const handleConfirm = () => {
formActions.submit()
}
const handleSubmit = (values: productSubmitType) => {
onSubmit?.(values)
}
return (
<Drawer
visible={visible}
onClose={onClose}
width={800}
title="查看加工明细"
bodyStyle={{padding: '0px'}}
footer={
(
<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'flex-end'}} >
<Space>
<Button onClick={onClose}>取消</Button>
<Button type="primary" onClick={handleConfirm}>确认</Button>
</Space>
</div>
)
}
>
<div className={styles.container}>
<div className={styles.menu}>
{
menu.map((item,key) => {
return (
<div key={item} className={classnames(styles.menuItem)} onClick={() => activeAndScroll(key)}>
<span className={classnames(styles.menuTitle, { [styles.active]: activeIndex === key })} >
{item}
</span>
</div>
)
})
}
</div>
<div className={styles.body} ref={ref}>
<NiceForm
value={value}
schema={schema}
components={{
FormilyProductAttrsLayout
}}
actions={formActions}
onSubmit={handleSubmit}
/>
</div>
</div>
</Drawer>
)
}
export default ProductDrawer
import { ISchema } from '@formily/antd';
const schema: ISchema = {
type: 'object',
properties: {
basicInfo: {
type: 'string',
'x-component': 'FlagBox',
"x-component-props": {
title: '单据审核',
},
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
labelCol: 4,
wrapperCol: 18,
labelAlign: 'left',
},
properties: {
skuid: {
type: 'string',
title: 'skuId',
display: false,
},
commodityId: {
type: 'string',
title: '商品id',
editable: false,
},
name: {
title: "商品名称",
type: 'string',
editable: false,
},
category: {
title: "商品品类",
type: 'string',
editable: false,
},
brand: {
title: '商品品牌',
type: 'string',
editable: false,
},
},
},
}
},
productProps: {
type: 'string',
'x-component': 'formilyProductAttrsLayout'
},
files: {
type: 'string',
'x-component': 'FlagBox',
"x-component-props": {
title: '附件',
},
properties: {
enclosure: {
'x-component': 'FormilyUploadFiles'
}
}
},
processRequire: {
type: 'string',
'x-component': 'FlagBox',
"x-component-props": {
title: '加工要求',
},
properties: {
MEGA_LAYOUT: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
labelCol: 4,
wrapperCol: 18,
labelAlign: 'left',
},
properties: {
unitName: {
type: 'string',
title: '单位',
editable: false,
},
processNum: {
type: 'string',
title: '加工数量',
},
processUnitPrice: {
title: "单价",
type: 'string'
},
isHasTax: {
title: "是否含税",
type: 'radio',
enum: [
{
label: '是',
value: 1,
},
{
label: '否',
value: 0,
}
]
},
taxRate: {
title: '税率',
type: 'string'
},
},
},
}
}
}
}
export default schema
import React from 'react'
interface Iprops {
value: any,
props: {
'x-component-props': {
isImage?: boolean,
[key: string]: any
}
}
}
const ReadOnly: React.FC<Iprops> & { isFieldComponent: boolean } = (props: Iprops) => {
const { value } = props;
const componentProps = props.props?.['x-component-props'] || {}
return (
<>
{
value && componentProps?.isImage && (
<img src={value} style={{width: '32px', height: '32px'}} />
) || (
<div>{value}</div>
)
}
</>
)
}
ReadOnly.isFieldComponent = true
export default ReadOnly
import React from 'react'
import { connect, IConnectProps, MergedFieldComponentProps, registerFormField } from '@formily/antd'
import { Input } from 'antd'
const PreviewText = ({ value }: { value: string | number }) => {
return (
<span>{value}</span>
)
}
export const mapTextComponent = (
Target: React.JSXElementConstructor<any>,
props: any = {},
fieldProps: any = {}
): React.JSXElementConstructor<any> => {
const { editable } = fieldProps
// console.log("props", props, "fieldProps", fieldProps);
if (editable !== undefined) {
if (editable === false) {
return PreviewText
}
}
return Target
}
export const mapStyledProps = (
props: IConnectProps,
fieldProps: MergedFieldComponentProps
) => {
const { loading, errors } = fieldProps
if (loading) {
props.state = props.state || 'loading'
} else if (errors && errors.length) {
props.state = 'error'
}
}
export default connect({
// getProps: mapStyledProps, //处理状态映射
getComponent: mapTextComponent //处理详情态
})((props) => {
const { dataSource, value, onChange } = props;
return <Input value={value} onChange={onChange} />
})
This diff is collapsed.
......@@ -246,6 +246,7 @@ const createSchema: ISchema = {
'x-component-props': {
renderAddition: () => null,
renderRemove: () => null,
renderExtraOperations: '{{renderProductListTableRemove}}',
renderMoveDown: () => null,
renderMoveUp: () => null,
operations: {
......@@ -259,16 +260,6 @@ const createSchema: ISchema = {
message: '请选择要加工的商品'
}
],
default: [
{
commodityId: 1,
name: '我的123'
},
{
commodityId: 2,
name: '我的3'
}
],
items: {
type: 'object',
properties: {
......@@ -280,9 +271,13 @@ const createSchema: ISchema = {
width: 65,
},
},
pic: {
mainPic: {
title: '商品图片',
type: "string",
"x-component": 'ReadOnly',
'x-component-props': {
isImage: true,
},
editable: false,
},
name: {
......@@ -300,29 +295,31 @@ const createSchema: ISchema = {
type: 'string',
editable: false,
},
orderNumAndUnit: {
unitName: {
title: '单位',
type: 'string',
editable: false,
"x-component": 'ReadOnly',
},
surplusAndProcessNum: {
title: '剩余/加工数量',
processNum: {
title: '加工数量',
type: 'string',
"x-component": 'ReadOnly',
},
tax: {
isHasTaxAndTaxRate: {
title: '含税/税率',
type: 'string',
editable: false,
"x-component": 'ReadOnly',
},
processUnitPrice: {
title: '加工单价',
type: 'string',
"x-component": 'ReadOnly',
},
processTotalPrice: {
title: '加工费',
type: 'string',
editable: false,
"x-component": 'ReadOnly',
"x-rules": [
{
required: true,
......@@ -330,10 +327,11 @@ const createSchema: ISchema = {
}
],
},
deliveryDate: {
title: "交期",
type: 'string'
}
// deliveryDate: {
// title: "交期",
// type: 'string',
// "x-component": 'ReadOnly',
// }
}
}
},
......@@ -348,6 +346,7 @@ const createSchema: ISchema = {
renderRemove: () => null,
renderMoveDown: () => null,
renderMoveUp: () => null,
renderExtraOperations: '{{renderProductListTableRemove}}',
operations: {
title: '操作'
},
......@@ -359,16 +358,6 @@ const createSchema: ISchema = {
message: '请选择要加工的商品'
}
],
default: [
{
commodityId: 1,
name: '我的'
},
{
commodityId: 2,
name: '我的3'
}
],
items: {
type: 'object',
properties: {
......@@ -388,10 +377,14 @@ const createSchema: ISchema = {
width: 65,
},
},
pic: {
mainPic: {
title: '商品图片',
type: "string",
editable: false,
"x-component": 'ReadOnly',
'x-component-props': {
isImage: true,
},
},
name: {
title: '商品名称',
......@@ -408,29 +401,33 @@ const createSchema: ISchema = {
type: 'string',
editable: false,
},
orderNumAndUnit: {
purchaseCountAndUnit: {
title: '订单数量/单位',
type: 'string',
editable: false,
"x-component": 'ReadOnly',
},
surplusAndProcessNum: {
title: '剩余/加工数量',
type: 'string',
"x-component": 'ReadOnly',
},
tax: {
isHasTaxAndTaxRate: {
title: '含税/税率',
type: 'string',
editable: false,
"x-component": 'ReadOnly',
},
processUnitPrice: {
title: '加工单价',
type: 'string',
"x-component": 'ReadOnly',
},
processTotalPrice: {
title: '加工费',
type: 'string',
editable: false,
"x-component": 'ReadOnly',
"x-rules": [
{
required: true,
......@@ -438,10 +435,6 @@ const createSchema: ISchema = {
}
],
},
deliveryDate: {
title: "交期",
type: 'string'
}
}
}
},
......
......@@ -28,7 +28,8 @@ interface Iprops {
columns: ColumnsType,
footer?: React.ReactNode,
tableProps?: {
rowKey: string | ((record) => any)
rowKey: string | ((record) => any),
expandable?: any,
},
width?: number,
mode: 'checkbox' | 'radio',
......@@ -50,11 +51,35 @@ interface Iprops {
fetchData: (params: any) => any,
onClose: () => void,
onOk: (selectRow: number[] | string[], selectedRows: {[key: string]: any}[]) => void,
/**
* 勾选前操作,
*/
beforeChecked?: ((record: any, selected: boolean, selectedRows: any[]) => boolean) | ((record: any, selected: boolean, selectedRows: any[]) => Promise<any>)
}
const TableModal: React.FC<Iprops> = (props: Iprops) => {
const { title, visible, schema, columns, effects, tableProps, mode, expressionScope, fetchData, onClose, onOk, value, format, customizeRadio, modalType, footer, width, components } = props;
const {
title,
visible,
schema,
columns,
effects,
tableProps,
mode,
expressionScope,
fetchData,
onClose,
onOk,
value,
format,
customizeRadio,
modalType,
footer,
width,
components,
beforeChecked
} = props;
const ref = useRef<any>({});
const isFirstLoad = useRef<boolean>(true)
const [selectRow, setSelectRow] = useState<number[] | string[]>(() => {
......@@ -97,9 +122,16 @@ const TableModal: React.FC<Iprops> = (props: Iprops) => {
isFirstLoad.current = false;
}, [visible])
const onSelectChange = (record, selected: boolean, selectedRows) => {
const onSelectChange = async (record, selected: boolean, selectedRows) => {
const recordRows = customizeRadio || mode === 'radio' ? selectedRows.slice(-1) : selectedRows;
const keys = recordRows.map((_item) => typeof tableProps.rowKey === 'string' ? _item[tableProps.rowKey as string] : tableProps.rowKey(_item));
// if (selected) {
const returnValue =await beforeChecked(record, selected, selectedRows);
if (returnValue === false) {
return;
}
// }
setSelectRowRecord(selectedRows)
setSelectRow(keys)
};
......@@ -190,7 +222,8 @@ TableModal.defaultProps = {
modalType: "Modal",
footer: null,
width: 840,
components: {}
components: {},
beforeChecked: () => true
}
export default TableModal;
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