Commit 9f96a4c6 authored by 武广's avatar 武广

feat: 添加分组

parent 41cdb462
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",
"react-sortable-hoc": "^2.0.0", "react-sortable-hoc": "^2.0.0",
"react-sortablejs": "^6.0.0", "react-sortablejs": "^6.0.0",
"react-window": "^1.8.8",
"slash2": "^2.0.0", "slash2": "^2.0.0",
"sortablejs": "^1.13.0", "sortablejs": "^1.13.0",
"umi": "^3.0.0", "umi": "^3.0.0",
...@@ -30770,6 +30771,23 @@ ...@@ -30770,6 +30771,23 @@
"tween-functions": "^1.0.1" "tween-functions": "^1.0.1"
} }
}, },
"node_modules/react-window": {
"version": "1.8.8",
"resolved": "http://npmprivate.quantgroups.com/react-window/-/react-window-1.8.8.tgz",
"integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.0.0",
"memoize-one": ">=3.1.1 <6"
},
"engines": {
"node": ">8.0.0"
},
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/read-pkg": { "node_modules/read-pkg": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "http://npmprivate.quantgroups.com/read-pkg/-/read-pkg-2.0.0.tgz", "resolved": "http://npmprivate.quantgroups.com/read-pkg/-/read-pkg-2.0.0.tgz",
...@@ -60769,6 +60787,15 @@ ...@@ -60769,6 +60787,15 @@
"tween-functions": "^1.0.1" "tween-functions": "^1.0.1"
} }
}, },
"react-window": {
"version": "1.8.8",
"resolved": "http://npmprivate.quantgroups.com/react-window/-/react-window-1.8.8.tgz",
"integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==",
"requires": {
"@babel/runtime": "^7.0.0",
"memoize-one": ">=3.1.1 <6"
}
},
"read-pkg": { "read-pkg": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "http://npmprivate.quantgroups.com/read-pkg/-/read-pkg-2.0.0.tgz", "resolved": "http://npmprivate.quantgroups.com/read-pkg/-/read-pkg-2.0.0.tgz",
import React from 'react';
import { Button, Dropdown, Menu } from 'antd';
import { PlusOutlined, DownOutlined } from '@ant-design/icons';
import { batchAction } from '../../staticdata';
import styles from '../../style.less';
const ActionBar = options => {
const menus = (
<Menu>
{batchAction.map(item => (
<Menu.Item>{item.label}</Menu.Item>
))}
</Menu>
);
return (
<div className={styles['action-bar-box']}>
<Button type="primary" icon={<PlusOutlined />}>
该分组下新增商品
</Button>
<Dropdown overlay={menus} className={styles['action-bar-box--down']} placement="bottomLeft">
<Button type="primary">
批量操作 <DownOutlined />
</Button>
</Dropdown>
</div>
);
};
export default ActionBar;
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Button, Modal, message, notification, Tag } from 'antd'; import { Button, Modal, Tag } from 'antd';
import { DndProvider } from 'react-dnd'; import { DndProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend'; import HTML5Backend from 'react-dnd-html5-backend';
import styles from '../../style.less'; import styles from '../../style.less';
import DragTag from './DragTag'; import DragTag from './DragTag';
import InsertTag from './InsertTag'; import InsertTag from './InsertTag';
import GroupInfo from './GroupInfo';
const GoodsGroup = options => { const GoodsGroup = options => {
const [groupEdit, setGroupEdit] = useState(false); const [groupEdit, setGroupEdit] = useState(false);
const [selected, setSelected] = useState(0); const [selected, setSelected] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
const [tags, setTags] = useState([ const [tags, setTags] = useState([
{ {
...@@ -37,6 +39,7 @@ const GoodsGroup = options => { ...@@ -37,6 +39,7 @@ const GoodsGroup = options => {
}, },
]); ]);
// 更换位置
const changePosition = (dragIndex, hoverIndex) => { const changePosition = (dragIndex, hoverIndex) => {
const data = tags.slice(); const data = tags.slice();
const temp = data[dragIndex]; const temp = data[dragIndex];
...@@ -68,7 +71,7 @@ const GoodsGroup = options => { ...@@ -68,7 +71,7 @@ const GoodsGroup = options => {
key={item.id} key={item.id}
/> />
))} ))}
<InsertTag /> <InsertTag handleOpen={setIsModalOpen} />
</div> </div>
</DndProvider> </DndProvider>
) : ( ) : (
...@@ -84,10 +87,11 @@ const GoodsGroup = options => { ...@@ -84,10 +87,11 @@ const GoodsGroup = options => {
<span className={styles['groupBox-body--tag__text']}>{item.text}</span> <span className={styles['groupBox-body--tag__text']}>{item.text}</span>
</Tag> </Tag>
))} ))}
<InsertTag /> <InsertTag handleOpen={setIsModalOpen} />
</div> </div>
)} )}
</div> </div>
<GroupInfo isModalOpen={isModalOpen} handleClose={setIsModalOpen} />
</div> </div>
); );
}; };
......
import React, { useState } from 'react';
import { Form, Modal, Input, Checkbox, Alert } from 'antd';
const GroupInfo = options => {
const [form] = Form.useForm();
// 关闭分组信息弹窗
const handleCancel = () => {
options.handleClose(false);
};
// 提交分组
const handleConfirm = async () => {
const values = await form.validateFields();
console.log('values :>> ', values);
handleCancel();
};
const extra = (
<Alert
message="选中后,顾客下单需至少选择1个“下单必选分组”商品每店仅可设置1个必点分组"
type="error"
/>
);
return (
<Modal
title="分组信息"
visible={options.isModalOpen}
onOk={handleConfirm}
onCancel={handleCancel}
>
<Form name="basic" form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 16 }}>
<Form.Item
label="分组名称"
name="name"
rules={[{ required: true, message: '请输入分组名称!' }]}
>
<Input />
</Form.Item>
<Form.Item label="下单必选分组" name="necessary" extra={extra}>
<Checkbox />
</Form.Item>
</Form>
</Modal>
);
};
export default GroupInfo;
import React, { useState, useRef } from 'react'; import React from 'react';
import { Input, Tag } from 'antd'; import { Tag } from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import styles from '../../style.less'; import styles from '../../style.less';
const InsertTag = options => { const InsertTag = options => {
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState('');
const refInput = useRef();
const showInput = () => { const showInput = () => {
setInputVisible(true); options.handleOpen(true);
const timer = setTimeout(() => {
if (refInput.current) {
refInput.current.focus();
}
clearTimeout(timer);
}, 1);
};
const handleInputChange = e => {
setInputValue(e.target.value || '');
};
const handleInputConfirm = () => {
setInputVisible(false);
setInputValue('');
}; };
return ( return (
<> <Tag
{inputVisible && ( className={[styles['groupBox-body--tag'], styles['groupBox-body--new']]}
<Input color="blue"
type="text" onClick={showInput}
size="small" >
ref={refInput} <PlusOutlined /> 添加
className={styles['groupBox-body--tag-input']} </Tag>
value={inputValue}
onChange={handleInputChange}
onBlur={handleInputConfirm}
onPressEnter={handleInputConfirm}
/>
)}
{!inputVisible && (
<Tag
className={[styles['groupBox-body--tag'], styles['groupBox-body--new']]}
color="blue"
onClick={showInput}
>
<PlusOutlined /> 添加
</Tag>
)}
</>
); );
}; };
......
...@@ -7,15 +7,18 @@ import GoodsGroup from './components/GoodsGroup'; ...@@ -7,15 +7,18 @@ import GoodsGroup from './components/GoodsGroup';
import { searchList } from '../service'; import { searchList } from '../service';
import styles from '../style.less'; import styles from '../style.less';
import { takeawayColumn } from '../staticdata'; import { takeawayColumn } from '../staticdata';
// import VirtualTable from './components/VirtualTable';
import ActionBar from './components/ActionBar';
const Takeaway = options => { const Takeaway = options => {
const actionRef = useRef(null);
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const rowSelection = {};
const DragHandle = SortableHandle(() => ( const rowSelection = {
<MenuOutlined style={{ cursor: 'grab', color: '#999' }} /> selectedRowKeys,
)); onChange: setSelectedRowKeys,
};
const onSortEnd = ({ oldIndex, newIndex }) => { const onSortEnd = ({ oldIndex, newIndex }) => {
if (oldIndex !== newIndex) { if (oldIndex !== newIndex) {
...@@ -37,6 +40,12 @@ const Takeaway = options => { ...@@ -37,6 +40,12 @@ const Takeaway = options => {
/> />
); );
const DraggableBodyRow = ({ className, style, ...restProps }) => {
// function findIndex base on Table rowKey props and should always be a right array index
const index = tableData.findIndex(x => x.skuId === restProps['data-row-key']);
return <SortableItem index={index} {...restProps} />;
};
const getDataList = async () => { const getDataList = async () => {
setLoading(true); setLoading(true);
const res = await searchList({ productType: 1 }); const res = await searchList({ productType: 1 });
...@@ -46,12 +55,6 @@ const Takeaway = options => { ...@@ -46,12 +55,6 @@ const Takeaway = options => {
} }
}; };
const DraggableBodyRow = ({ className, style, ...restProps }) => {
// function findIndex base on Table rowKey props and should always be a right array index
const index = tableData.findIndex(x => x.skuId === restProps['data-row-key']);
return <SortableItem index={index} {...restProps} />;
};
useEffect(() => { useEffect(() => {
getDataList(); getDataList();
}, []); }, []);
...@@ -60,14 +63,15 @@ const Takeaway = options => { ...@@ -60,14 +63,15 @@ const Takeaway = options => {
<div className={styles.takeawayBox}> <div className={styles.takeawayBox}>
<Spin spinning={loading}> <Spin spinning={loading}>
<GoodsGroup /> <GoodsGroup />
<ActionBar />
<Table <Table
dataSource={tableData} dataSource={tableData}
bordered bordered
columns={takeawayColumn.call(this)} columns={takeawayColumn.call(this)}
rowKey={record => record.skuId} rowKey={record => record.skuId}
pagination={false} pagination={false}
// scroll={{ x: '100%', y: 500 }} scroll={{ x: '100%', y: 1000 }}
// rowSelection={rowSelection} rowSelection={rowSelection}
components={{ components={{
body: { body: {
wrapper: DraggableContainer, wrapper: DraggableContainer,
...@@ -75,6 +79,15 @@ const Takeaway = options => { ...@@ -75,6 +79,15 @@ const Takeaway = options => {
}, },
}} }}
/> />
{/* <VirtualTable
columns={takeawayColumn.call(this)}
rowKey={record => record.skuId}
dataSource={tableData}
scroll={{
y: 300,
x: '100%',
}}
/> */}
</Spin> </Spin>
</div> </div>
); );
......
import React from 'react'; import React from 'react';
import { Button, Badge, Switch, Modal } from 'antd'; import { Button, Badge, Switch, Modal } from 'antd';
import { SortableHandle } from 'react-sortable-hoc';
import { ExclamationCircleOutlined, MenuOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined, MenuOutlined } from '@ant-design/icons';
import styles from './style.less'; import styles from './style.less';
import { resetTime } from '../../utils/utils'; import { resetTime } from '../../utils/utils';
import { apiChangeStateGoods, apiQueryLastAuditRecord } from './service'; import { apiChangeStateGoods } from './service';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
const { confirm } = Modal; const { confirm } = Modal;
...@@ -246,7 +246,7 @@ export function column() { ...@@ -246,7 +246,7 @@ export function column() {
]; ];
} }
export function takeawayColumn() { export function takeawayColumn(actions) {
const onChangeState = async ({ skuId, state }) => { const onChangeState = async ({ skuId, state }) => {
confirm({ confirm({
icon: <ExclamationCircleOutlined />, icon: <ExclamationCircleOutlined />,
...@@ -276,77 +276,32 @@ export function takeawayColumn() { ...@@ -276,77 +276,32 @@ export function takeawayColumn() {
{ {
title: '排序', title: '排序',
dataIndex: 'sort', dataIndex: 'sort',
width: 60,
align: 'center', align: 'center',
className: [styles['drag-visible'], styles['sort-td']], width: 70,
className: [styles['drag-visible']],
render: () => <DragHandle />, render: () => <DragHandle />,
}, },
{ {
title: 'SKU编码', title: 'SKU编码',
dataIndex: 'skuId', dataIndex: 'skuId',
width: 125, width: 180,
align: 'center', align: 'center',
render: (_, row) => {
if (row.type === 2) {
return (
<Badge
count={
<div
style={{
color: '#fff',
borderRadius: '3px',
background: '#f5222d',
padding: '2px',
fontSize: '10px',
opacity: 0.7,
}}
>
虚拟
</div>
}
>
<div
style={{
background: '#fbfbfb',
borderRadius: '3px',
padding: '2px',
}}
>
{row.skuId}
</div>
</Badge>
);
}
return (
<div
style={{
background: '#fbfbfb',
borderRadius: '3px',
padding: '2px',
}}
>
{row.skuId}
</div>
);
},
}, },
{ {
title: 'SKU商品名称', title: 'SKU商品名称',
width: 135, // width: 200,
align: 'center', align: 'center',
dataIndex: 'skuName', dataIndex: 'skuName',
}, },
{ {
title: '供应商价格', title: '售卖价格(元)',
dataIndex: 'marketPrice', dataIndex: 'marketPrice',
width: 150, width: 150,
align: 'center', align: 'center',
sorter: (a, b) => a.supplyPrice - b.supplyPrice,
render: (_, row) => ( render: (_, row) => (
<div className={styles.price}> <div className={styles.price}>
<p>供货价:{(row.supplyPrice || 0).toFixed(2)}</p> <div>供货价:{(row.supplyPrice || 0).toFixed(2)}</div>
<p>市场价:{(row.marketPrice || 0).toFixed(2)}</p> <div>市场价:{(row.marketPrice || 0).toFixed(2)}</div>
</div> </div>
), ),
}, },
...@@ -355,78 +310,80 @@ export function takeawayColumn() { ...@@ -355,78 +310,80 @@ export function takeawayColumn() {
width: 120, width: 120,
dataIndex: 'stock', dataIndex: 'stock',
align: 'center', align: 'center',
sorter: (a, b) => a.stock - b.stock,
render: (_, row) => {
// const stockView = row.productStock;
const stockView = (
<Button type="link" onClick={() => this.onShowStockModal(row)} style={{ padding: 0 }}>
{row.productStock}
</Button>
);
return (
<>
<p>当前库存:{stockView}</p>
<p>可售库存:{_}</p>
{row.type === 1 && row.productStockWarning > 0 && (
<p>预警值:{row.productStockWarning}</p>
)}
</>
);
},
},
{
title: '不支持配送区域',
dataIndex: 'areaTemplateName',
key: 'areaTemplateName',
width: 200,
align: 'center',
}, },
{ {
title: '上下架状态', title: '上下架状态',
dataIndex: 'stateDesc', // 5:未上架 ,6 :上架,7:下架 dataIndex: 'stateDesc', // 5:未上架 ,6 :上架,7:下架
width: 200, width: 200,
align: 'center', align: 'center',
render: (_, row) => (
<div>
{row.type === 4 && row.state >= 5 ? (
<>
<Switch
checkedChildren="已上架"
checked={row.state === 6}
unCheckedChildren="已下架"
onClick={() => onChangeState(row)}
defaultChecked
/>
</>
) : (
'-'
)}
</div>
),
}, },
{ {
title: '审核状态', title: '操作',
dataIndex: 'stateDesc', dataIndex: 'action',
width: 200, width: 400,
align: 'center', align: 'center',
render: (_, row) => ( render: (_, row, index) => (
<div> <div className={styles.actionBtn}>
<p>{row.state >= 5 ? '审核通过' : _}</p> {(row.state === 4 || (row.state >= 5 && row.updateState !== 1)) && (
<div> <Button key="edit" type="primary" className={styles.button}>
{row.updateState ? ( 编辑
<Button onClick={() => onShowAudit(row)} type="link"> </Button>
{row.updateStateDesc} )}
</Button> <Button key="viewP" type="primary" className={styles.button}>
) : ( 上架
'--' </Button>
)} <Button key="log" type="primary" className={styles.button}>
</div> 修改库存
</Button>
{index > 0 && (
<Button key="top" className={styles.button}>
置顶
</Button>
)}
</div> </div>
), ),
}, },
]; ];
} }
export const batchAction = [
{
key: 'up',
type: '2',
label: '上架',
},
{
key: 'down',
type: '2',
label: '下架',
},
{
key: 'stock',
type: '7',
label: '修改库存',
},
{
key: 'time',
type: '4',
label: '修改可售时间',
},
{
key: 'group',
type: '3',
label: '修改分组',
},
{
key: 'send',
type: '6',
label: '设置单点不送',
},
{
key: 'buy',
type: '5',
label: '修改最少购买数量',
},
];
export const disSelectStatus = [2, 5]; export const disSelectStatus = [2, 5];
export const stateList = [ export const stateList = [
{ value: 3, label: '待审核' }, { value: 3, label: '待审核' },
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
} }
.actionBtn { .actionBtn {
button { button {
width: 75px; min-width: 75px;
} }
} }
.pagination { .pagination {
...@@ -219,6 +219,23 @@ ...@@ -219,6 +219,23 @@
.drag-visible { .drag-visible {
visibility: visible; visibility: visible;
} }
.sort-td { .td-center {
text-align: center; display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0 10px;
word-break: break-all;
}
// .virtual-table {
// table-layout: auto !important;
// table {
// table-layout: auto !important;
// }
// }
.action-bar-box {
padding: 0 0 15px 24px;
&--down {
margin-left: 10px;
}
} }
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