Commit cde62b0c authored by XieZhiXiong's avatar XieZhiXiong

feat: 新增入库分类信息pro组件

parent c890010c
/**
* @Description 序号 Filed
*/
import React, { HTMLAttributes } from 'react';
import { FormPath } from '@formily/antd';
const IndexField: React.FC<any> & { isFieldComponent: boolean } = (props) => {
const { name } = props;
const xComponentProps: HTMLAttributes<HTMLDivElement> = props.props['x-component-props'] || {};
const index = FormPath.transform(name, /\d/, $1 => {
return `${$1 + 1}`
});
return (
<div {...xComponentProps}>{index}</div>
)
}
IndexField.isFieldComponent = true
export default IndexField;
\ No newline at end of file
@import '~antd/es/style/themes/default.less';
@import '../../../../../../global/styles/utils.less';
.pay-type {
width: 100%;
flex: 1 1 0%;
&-content {
padding: 0 @padding-xs;
display: flex;
position: relative;
height: 32px;
// border: 1px solid @background-color-base;
border: 1px solid @select-border-color;
background-color: @background-color-base;
border-radius: 4px;
&-text {
flex: 1;
padding-right: 15px;
.textOverflow();
}
&-arrow {
position: absolute;
top: 50%;
right: @padding-xs;
height: 12px;
margin-top: -6px;
color: @input-placeholder-color;
}
&-active,
&:hover {
border-color: @primary-color;
}
}
&-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
background-color: #FFFFFF;
padding: @padding-xs;
border-radius: 4px;
}
&-options {
margin-bottom: @margin-md;
border-bottom: 1px solid @background-color-base;
&-item {
display: inline-block;
margin-right: @margin-xs;
margin-bottom: @margin-xs;
&-btn {
border: none;
&-active {
color: @primary-color;
}
}
}
}
&-actions {
display: flex;
align-items: center;
padding-top: @padding-xss;
&-item {
flex: 1;
padding: 0 @padding-xss;
}
}
}
\ No newline at end of file
/**
* 结算方式Filed组件
*/
import React, { useEffect, useState } from 'react';
import { useIntl } from 'umi';
import { Select, Dropdown, Button, Form, Input, } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import { FieldData } from 'rc-field-form/lib/interface';
import classNames from 'classnames';
import { ISchema } from '@formily/antd';
import themeConfig from '@/../config/lingxi.theme.config';
import { PAY_TYPE_CASH, PAY_TYPE_MONTHLY_STATEMENT, PAY_TYPE_PAYMENT_DAYS_DAY, PAY_TYPE_PAYMENT_DAYS_MONTH } from '@/constants/settlement';
import { PATTERN_MAPS } from '@/constants/regExp';
import styles from './index.less';
type PayTypeEnum = {
label: string;
value: number;
}
export type PayTypeFiledValueType = {
/**
* 结算方式
*/
payType: number,
/**
* 账期,几月
*/
month?: string,
/**
* 结算日,每月几号
*/
monthDay?: string,
/**
* 结算天数
*/
days?: string,
}
interface PayTypeFiledProps {
/**
* 值
*/
value: PayTypeFiledValueType,
/**
* 自定义内容区块样式
*/
contentStyle?: React.CSSProperties,
}
const PayTypeFiled = (props) => {
const {
mutators,
editable,
} = props;
const xComponentProps: PayTypeFiledProps = props.props['x-component-props'] || {};
const { contentStyle } = xComponentProps;
const [visible, setVisible] = useState(false);
const [internalPayType, setInternalPaytype] = useState(undefined);
const [formValues, setFormValues] = useState<PayTypeFiledValueType | undefined>(undefined);
const [form] = Form.useForm();
const intl = useIntl();
const value = typeof props.value === 'object' ? props.value : {};
const options: PayTypeEnum[] = props.props.enum || [];
useEffect(() => {
if (typeof props.value === 'object') {
if ((value as PayTypeFiledValueType).payType !== internalPayType) {
setInternalPaytype((value as PayTypeFiledValueType).payType);
}
form.setFieldsValue(value);
}
}, [value]);
const triggerChange = (next: PayTypeFiledValueType) => {
mutators.change(next);
};
const handleVisibleChange = (flag: boolean) => {
setVisible(flag);
};
// TODO: 有时间再把支付类型抽成Fields组件
const handlePayTypeChange = (next: PayTypeEnum) => {
setInternalPaytype(next.value);
form.resetFields();
};
const handleFormValuesChange = (_: Omit<PayTypeFiledValueType, 'payType'>, allValues: Omit<PayTypeFiledValueType, 'payType'>) => {
// triggerChange({ ...value, payType: internalPayType, ...allValues });
setFormValues({ payType: internalPayType, ...allValues });
};
const renderSettlementDate = () => {
switch (internalPayType) {
case PAY_TYPE_CASH: {
break;
}
case PAY_TYPE_PAYMENT_DAYS_DAY: {
return (
<>
<Form.Item
label="账期 (几个月)"
name="month"
style={{ marginBottom: themeConfig['@margin-xs'] }}
rules={[
{
pattern: PATTERN_MAPS.quantity,
message: intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.month.legal' }, { default: '请输入正整数' }),
},
]}
>
<Input addonAfter={intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.month.addonAfter' }, { default: '个月' })} />
</Form.Item>
<Form.Item
label="结算日 (每月几号)"
name="monthDay"
style={{ marginBottom: themeConfig['@margin-xs'] }}
rules={[
{
pattern: PATTERN_MAPS.quantity,
message: intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.monthDay.legal' }, { default: '请输入正整数' }),
},
{
validator(value) {
const intVal = +value;
return intVal > 31 || intVal < 0 ? Promise.reject(new Error(intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.monthDay.limit' }, { default: '请输入大于0 小于等于 31的数值' }))) : Promise.resolve();
}
},
]}
>
<Input addonAfter={intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.monthDay.addonAfter' }, { default: '号' })} />
</Form.Item>
</>
);
}
case PAY_TYPE_PAYMENT_DAYS_MONTH: {
return (
<Form.Item
label="账期 (间隔多少天)"
name="days"
rules={[
{
pattern: PATTERN_MAPS.quantity,
message: intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.days.legal' }, { default: '请输入正整数' }),
},
]}
>
<Input addonAfter={intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.days.addonAfter' }, { default: '天' })} />
</Form.Item>
);
}
case PAY_TYPE_MONTHLY_STATEMENT: {
return (
<Form.Item
label="结算日 (每月几号)"
name="monthDay"
style={{ marginBottom: themeConfig['@margin-xs'] }}
rules={[
{
pattern: PATTERN_MAPS.quantity,
message: intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.monthDay.legal' }, { default: '请输入正整数' }),
},
{
validator(value) {
const intVal = +value;
return intVal > 31 || intVal < 0 ? Promise.reject(new Error(intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.monthDay.limit' }, { default: '请输入大于0 小于等于 31的数值' }))) : Promise.resolve();
}
},
]}
>
<Input addonAfter={intl.formatMessage({ id: 'member.management.memberPrComingClassify.drawer.form.classify.monthDay.addonAfter' }, { default: '号' })} />
</Form.Item>
);
}
default:
break;
}
};
const handleSubmit = () => {
triggerChange({
payType: internalPayType,
...form.getFieldsValue(),
});
setVisible(false);
};
const currentPayType = options?.find((item) => item.value === internalPayType);
const content = (
<div>
{`
${currentPayType ? currentPayType.label : ''}
${formValues?.month ? ':' + formValues.month + '个月' : ''}
${formValues?.monthDay ? ',结算日:' + formValues.monthDay + '号' : ''}
${formValues?.days ? ':' + formValues.days + '天' : ''}
`}
</div>
);
if (!editable) return content;
return (
<div className={styles['pay-type']}>
<Dropdown
visible={visible}
onVisibleChange={handleVisibleChange}
overlay={(
<div className={styles['pay-type-overlay']}>
<div className={styles['pay-type-options']}>
{options.map((item) => (
<div
key={item.value}
className={styles['pay-type-options-item']}
>
<Button
className={classNames(
styles['pay-type-options-item-btn'],
{
[styles['pay-type-options-item-btn-active']]: item.value === internalPayType,
}
)}
onClick={() => handlePayTypeChange(item)}
>
{item.label}
</Button>
</div>
))}
</div>
<Form
form={form}
layout="vertical"
onValuesChange={handleFormValuesChange}
>
{renderSettlementDate()}
</Form>
<div className={styles['pay-type-actions']}>
<div className={styles['pay-type-actions-item']}>
<Button onClick={() => setVisible(false)} block>取消</Button>
</div>
<div className={styles['pay-type-actions-item']}>
<Button
type="primary"
onClick={handleSubmit}
block
>
确定
</Button>
</div>
</div>
</div>
)}
trigger={['click']}
>
<div
className={classNames(styles['pay-type-content'], { [styles['pay-type-content-active']]: visible })}
style={contentStyle}
>
<div className={styles['pay-type-content-text']}>
{content}
</div>
<DownOutlined className={styles['pay-type-content-arrow']} />
</div>
{/* <Select
value={'账期(按月):3个月,结算日:1号'}
dropdownStyle={{ display: 'none' }}
onClick={(e) => { e.stopPropagation(); }}
disabled
/> */}
</Dropdown>
</div>
);
};
PayTypeFiled.isFieldComponent = true;
export default PayTypeFiled;
/**
* @Description TreeSelect Filed
*/
import React from 'react';
import { TreeSelect } from 'antd';
const TreeSelectField: React.FC<any> & { isFieldComponent: boolean } = (props) => {
const { mutators, value, editable } = props;
const xComponentProps: React.ComponentProps<typeof TreeSelect> = props.props['x-component-props'] || {};
const { disabled, ...restComponentProps } = xComponentProps;
const onChange = (value) => {
mutators.change(value);
}
return (
<TreeSelect
style={{ width: '100%' }}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
value={value}
onChange={onChange}
treeDefaultExpandAll
showSearch
allowClear
treeCheckable
disabled={!editable}
// showCheckedStrategy={TreeSelect.SHOW_PARENT}
{...restComponentProps}
/>
)
}
TreeSelectField.isFieldComponent = true
export default TreeSelectField;
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
export type CategoryItemType = {
/**
* 数据id
*/
id: string,
/**
* 父级id
*/
parentId: string,
/**
* 标题
*/
title: string,
/**
* 是否选中
*/
checked: boolean,
/**
* 图片url路径
*/
imageUrl: string,
/**
* 子元素
*/
children?: CategoryItemType[],
}
export function breakUpCategory(dataSource: CategoryItemType[]): {} {
const valueMap = {};
function loops(list, parent?) {
return (list || []).map(({ children, id, title }) => {
const node: any = (valueMap[id] = {
parent,
parentId: parent?.categoryId || 0,
categoryId: +id,
level: (parent?.level || 0) + 1,
name: title,
});
node.children = loops(children, node);
return node;
});
}
loops(dataSource);
return valueMap;
}
export type CategoryType = {
/**
* 层级
*/
level: number,
/**
* 品类id
*/
categoryId: number,
/**
* 品类名称
*/
name: string,
/**
* 子节点
*/
children?: CategoryType[],
/**
* 父级id
*/
parentId: number,
/**
* 父级
*/
parent?: CategoryType,
}
export function getCategoryPath(value: string, valueMap: {}): CategoryType[] {
const path: CategoryType[] = [];
let current = valueMap[value];
while (current) {
path.unshift({
level: current.level,
categoryId: current.categoryId,
name: current.name,
parentId: current.parentId,
});
current = current.parent;
}
return path;
}
export function getCategoryAllKeys(dataSource: CategoryType[]): string[] {
const ret: string[] = [];
function loops(list: CategoryType[]) {
list.forEach((item) => {
if (item.children && item.children.length) {
loops(item.children);
} else {
ret.push(`${item.categoryId}`);
}
});
}
loops(dataSource);
return ret;
};
export function nestedCategory(dataSource: CategoryType[]): CategoryType {
return dataSource.reduceRight((pre, now) => {
const { parent, ...rest } = now;
return [{
...rest,
children: pre,
}];
}, [])[0];
}
\ No newline at end of file
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