Commit 946cea22 authored by 武广's avatar 武广

Merge branch 'feature/addr20221031' into 'master'

Feature/addr20221031

See merge request !64
parents baa19369 d8defddc
import React, { forwardRef } from 'react';
import { Checkbox } from 'antd';
import { RightOutlined, DownOutlined, LoadingOutlined } from '@ant-design/icons';
import debounce from 'lodash/debounce';
import styles from './index.less';
const CustomTree = forwardRef(props => {
const { treeData } = props;
const onChange = () => {
props.onChange(treeData.key, !treeData.checked, treeData.level, treeData.children);
};
const onVisible = debounce(e => {
e.persist();
if (treeData.isLoading) return;
props.onVisibleChildren(
treeData.key,
!treeData.visibleChildren,
treeData.children,
treeData.checked,
);
}, 100);
const renderIcon = () => {
if (treeData.children && treeData.isLoading) {
return <LoadingOutlined />;
}
if (treeData.isLeaf) {
return (
<div onClick={onVisible} className={styles.CBIcon}>
{treeData.visibleChildren ? <DownOutlined /> : <RightOutlined />}
</div>
);
}
return <span />;
};
return (
<div key={`key${treeData.key}`}>
<div className={styles['ccheck-box']}>
<div className={styles['ccheck-box--expand']}>{renderIcon()}</div>
<Checkbox
onChange={onChange}
indeterminate={!treeData.checked && treeData.indeterminate}
checked={treeData.checked}
/>
<div className={styles['ccheck-box--label']} onClick={onVisible}>
{props.label}
{treeData.isLeaf && treeData.value && treeData.value.length > 0
? `(${treeData.value.length})`
: ''}
</div>
</div>
</div>
);
});
export default CustomTree;
This diff is collapsed.
.tree-box {
position: relative;
:global(.ant-col) {
display: flex;
}
&--wrapper {
position: relative;
}
}
.ccheck-box {
position: relative;
display: flex;
box-sizing: border-box;
width: max-content;
padding-right: 0;
padding-left: 22px;
&--expand {
position: absolute;
left: 0;
z-index: 1;
cursor: pointer;
}
&--childrens {
position: relative;
left: 100%;
z-index: 2;
display: flex;
flex-direction: column;
box-sizing: border-box;
width: max-content;
padding-left: 4px;
background-color: #fff;
box-shadow: 0 0 3px #ccc;
:global(.ant-checkbox-wrapper) {
margin-left: 0;
}
}
&--label {
padding: 0 10px;
cursor: pointer;
}
}
.CBIcon {
font-size: 12px;
}
.tree-children-box {
position: absolute;
top: 0;
left: 100%;
z-index: 2;
display: flex;
padding: 0 10px;
background-color: #fff;
box-shadow: 0 0 3px #ccc;
}
.tree-children-wrapper {
display: flex;
flex-direction: column;
max-height: 220px;
padding-left: 5px;
overflow-y: auto;
border-left: 1px solid #ccc;
&:first-child {
border: 0;
}
}
...@@ -97,13 +97,16 @@ const LogModal = props => { ...@@ -97,13 +97,16 @@ const LogModal = props => {
useEffect(() => { useEffect(() => {
if (!props.id) return; if (!props.id) return;
handleSearch(); // 20221108 临时隐藏商品详情,默认切换到审核详情 by liteng
// handleSearch();
bundleOnTabChange('1');
}, [props.id]); }, [props.id]);
const { visible } = props; const { visible } = props;
return ( return (
<Modal title="日志详情" visible={visible} footer={null} onCancel={bundleOnCancel} width="800px"> <Modal title="日志详情" visible={visible} footer={null} onCancel={bundleOnCancel} width="800px">
<Tabs type="card" onChange={bundleOnTabChange} activeKey={tabActiveKey}> <Tabs type="card" onChange={bundleOnTabChange} activeKey={tabActiveKey}>
<Tabs.TabPane tab="商品详情" key="0"> {/* 20221108 临时隐藏商品详情 by liteng */}
{/* <Tabs.TabPane tab="商品详情" key="0">
<Table <Table
dataSource={tableData.records} dataSource={tableData.records}
bordered bordered
...@@ -122,7 +125,7 @@ const LogModal = props => { ...@@ -122,7 +125,7 @@ const LogModal = props => {
className={styles.pagination} className={styles.pagination}
/> />
)} )}
</Tabs.TabPane> </Tabs.TabPane> */}
<Tabs.TabPane tab="审核详情" key="1"> <Tabs.TabPane tab="审核详情" key="1">
<Table <Table
dataSource={merchantList} dataSource={merchantList}
......
import { Form } from '@ant-design/compatible'; import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css'; import '@ant-design/compatible/assets/index.css';
import { Modal, Input, Select, Cascader, Tag, notification } from 'antd'; import { Modal, Input, Select, Cascader, Tag, notification, Tree, Col, Row } from 'antd';
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { el } from 'date-fns/locale'; import { el } from 'date-fns/locale';
import { areaList, getAddTemplate, forbiddenAddress } from '../services'; import { areaList, getAddTemplate, forbiddenAddress } from '../services';
import CustomTree from '@/components/CustomTree';
const { Option } = Select;
const AddAreaModal = props => { const AddAreaModal = props => {
const { const {
...@@ -13,9 +12,9 @@ const AddAreaModal = props => { ...@@ -13,9 +12,9 @@ const AddAreaModal = props => {
form: { getFieldDecorator, validateFields, resetFields, setFieldsValue }, form: { getFieldDecorator, validateFields, resetFields, setFieldsValue },
templateData, templateData,
} = props; } = props;
const [addList, setAddList] = useState([]);
const [selectedList, setSelectedList] = useState([]); const [selectedList, setSelectedList] = useState([]);
const [selected, setSelect] = useState([]); const [treeData, setTreeData] = useState([]);
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
span: 6, span: 6,
...@@ -24,76 +23,46 @@ const AddAreaModal = props => { ...@@ -24,76 +23,46 @@ const AddAreaModal = props => {
span: 16, span: 16,
}, },
}; };
const getAreaList = async () => {
if (!addList.length) {
const data = await areaList();
const newData = [];
data.map(item =>
newData.push({
label: item.addrName,
value: item.addrId,
addressId: item.addrId,
addressLevel: item.addrLevel,
isLeaf: item.addrLevel === 4,
}),
);
setAddList(newData);
}
};
const onChange = (value, selectedOptions) => { const filterData = arr =>
setSelect([...selectedOptions]); arr.map(item => ({
}; label: item.addrName,
// 加载 key: Number(item.addrId),
const loadData = async selectedOptions => { level: item.addrLevel,
const targetOption = selectedOptions.slice(-1)[0]; children: [],
targetOption.loading = true; // value: props.templateData.list.filter(item => item.)
const data = await areaList({ parentId: targetOption.addressId }); }));
if (!data.length) { const loadProvice = async () => {
targetOption.loading = false; const data = await areaList();
} else { if (data && data.length) {
const newData = []; const arr = filterData(data);
data.map(itemData => setTreeData(arr);
newData.push({
label: itemData.addrName,
value: itemData.addrId,
addressId: itemData.addrId,
addressLevel: itemData.addrLevel,
isLeaf: false,
}),
);
targetOption.children = newData;
targetOption.loading = false;
setAddList([...addList]);
} }
}; };
// 限制区域删除
const preventDefault = val => {
const newArr = selectedList.filter(item => item !== val);
setSelectedList([...newArr]);
};
const onCancel = () => { const onCancel = () => {
setSelectedList([]);
resetFields(); resetFields();
setSelect([]);
props.onSubmit(); props.onSubmit();
}; };
const handleOk = async () => { const handleOk = () => {
const { length } = selectedList;
// if (!selectedList.length) {
// notification.error({ message: '请选择限制区域!' });
// return;
// }
validateFields(async (error, fieldsValue) => { validateFields(async (error, fieldsValue) => {
const newData = []; const newData = [];
selectedList.map(itemData => const getValues = (list, level) => {
newData.push({ list.forEach(itemData => {
addressId: itemData.addressId, if (itemData.checked) {
addressLevel: itemData.addressLevel, newData.push({
addressName: itemData.addressName, addressId: itemData.key,
}), addressLevel: itemData.level || level,
); addressName: itemData.label,
});
} else if (itemData.children && itemData.children.length) {
getValues(itemData.children, level + 1);
}
});
};
if (!error) { if (!error) {
console.log('fieldsValue :>> ', fieldsValue);
getValues(fieldsValue.list, 1);
if (props.templateData.status) { if (props.templateData.status) {
const data = await forbiddenAddress({ const data = await forbiddenAddress({
templateId: props.templateData.id, templateId: props.templateData.id,
...@@ -117,45 +86,38 @@ const AddAreaModal = props => { ...@@ -117,45 +86,38 @@ const AddAreaModal = props => {
} }
}); });
}; };
// 判断是否重复 const onLoadData = async ({ key }) => {
const getChilds = select => { const res = await areaList({ parentId: key });
const reslutData = selectedList.filter( return res || [];
item =>
!select.addressName.includes(item.addressName) &&
!item.addressName.includes(select.addressName),
);
reslutData.push(select);
return reslutData;
}; };
const onPopupVisibleChange = labels => {
if (!labels && selected?.length) {
const select = selected.slice(-1)[0];
const arr = selected.map(x => x.label);
select.addressName = arr.join('/');
const reslutData = getChilds(select);
// 用中文字符排序
const resultArray = reslutData.sort((param1, param2) =>
param1.addressName.localeCompare(param2.addressName, 'zh'),
);
setSelectedList([...resultArray]);
setSelect([]);
}
};
useEffect(() => { useEffect(() => {
getAreaList();
if (props.templateData) { if (props.templateData) {
setSelectedList(props.templateData.list); let arr = [];
const dealData = list =>
list.map(item => {
item.key = +item.addressId;
item.label = item.addressName;
item.indeterminate = !item.isForbidden;
item.checked = item.isForbidden;
item.children && item.children.length && dealData(item.children);
return item;
});
arr = dealData(props.templateData.list || []);
setSelectedList(arr);
} }
}, [props.templateData]); }, [props.templateData]);
useEffect(() => { useEffect(() => {
// console.log(selectedList) props.visible && loadProvice();
}, [selectedList]); }, [props.visible]);
return ( return (
<Modal <Modal
title={props.templateData.status ? '编辑限制区域配送模板' : '添加限制区域配送模板'} title={props.templateData.status ? '编辑限制区域配送模板' : '添加限制区域配送模板'}
maskClosable={false}
visible={visible} visible={visible}
width="500px" width="800px"
onCancel={() => onCancel()} onCancel={() => onCancel()}
onOk={() => handleOk()} onOk={() => handleOk()}
> >
...@@ -167,21 +129,10 @@ const AddAreaModal = props => { ...@@ -167,21 +129,10 @@ const AddAreaModal = props => {
})(<Input placeholder="请填写模板名称" maxLength={20} />)} })(<Input placeholder="请填写模板名称" maxLength={20} />)}
</Form.Item> </Form.Item>
<Form.Item label="限制配送区域"> <Form.Item label="限制配送区域">
{getFieldDecorator('name')( {getFieldDecorator('list', {
<Cascader rules: [{ required: true, message: '请选择限制配送区域!', type: 'array' }],
options={addList} initialValue: selectedList,
loadData={loadData} })(<CustomTree treeData={treeData} loadData={onLoadData} valueKey="addressId" />)}
onChange={(val, label) => onChange(val, label)}
allowClear={false}
changeOnSelect
onDropdownVisibleChange={onPopupVisibleChange}
/>,
)}
{selectedList?.map((selItem, selIndex) => (
<Tag closable key={selItem.addressId} onClose={() => preventDefault(selItem)}>
{selItem.addressName}
</Tag>
))}
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>
......
...@@ -55,7 +55,7 @@ const TableList = props => { ...@@ -55,7 +55,7 @@ const TableList = props => {
), ),
]} ]}
/> />
<AddArea visible={visible} onSubmit={reload} templateData={templateData} /> {visible && <AddArea visible={visible} onSubmit={reload} templateData={templateData} />}
</PageHeaderWrapper> </PageHeaderWrapper>
); );
}; };
......
...@@ -57,6 +57,41 @@ export function toThousands(data, num) { ...@@ -57,6 +57,41 @@ export function toThousands(data, num) {
export const formatTime = (time, crm = 'YYYY-MM-DD HH:mm:ss') => time.format(crm); export const formatTime = (time, crm = 'YYYY-MM-DD HH:mm:ss') => time.format(crm);
export const resetTime = (time, crm = 'YYYY-MM-DD HH:mm:ss') => moment(time, crm); export const resetTime = (time, crm = 'YYYY-MM-DD HH:mm:ss') => moment(time, crm);
// 返回传递给他的任意对象的类
export function isClass(o) {
if (o === null) return 'Null';
if (o === undefined) return 'Undefined';
return Object.prototype.toString.call(o).slice(8, -1);
}
// 深拷贝
export function deepClone(obj) {
let result;
const oClass = isClass(obj);
// 确定result的类型
if (oClass === 'Object') {
result = {};
} else if (oClass === 'Array') {
result = [];
} else {
return obj;
}
// eslint-disable-next-line no-restricted-syntax
for (const key in obj) {
if ({}.hasOwnProperty.call(obj, key)) {
const copy = obj[key];
if (isClass(copy) === 'Object') {
result[key] = deepClone(copy); // 递归调用
} else if (isClass(copy) === 'Array') {
result[key] = deepClone(copy);
} else {
result[key] = obj[key];
}
}
}
return result;
}
export const getClientInfo = () => { export const getClientInfo = () => {
if (window.innerHeight !== undefined) { if (window.innerHeight !== undefined) {
return { return {
......
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