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

feat: 添加分组

parent 41cdb462
......@@ -37,6 +37,7 @@
"react-router-dom": "^5.1.2",
"react-sortable-hoc": "^2.0.0",
"react-sortablejs": "^6.0.0",
"react-window": "^1.8.8",
"slash2": "^2.0.0",
"sortablejs": "^1.13.0",
"umi": "^3.0.0",
......@@ -30770,6 +30771,23 @@
"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": {
"version": "2.0.0",
"resolved": "http://npmprivate.quantgroups.com/read-pkg/-/read-pkg-2.0.0.tgz",
......@@ -60769,6 +60787,15 @@
"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": {
"version": "2.0.0",
"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 { Button, Modal, message, notification, Tag } from 'antd';
import { Button, Modal, Tag } from 'antd';
import { DndProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import styles from '../../style.less';
import DragTag from './DragTag';
import InsertTag from './InsertTag';
import GroupInfo from './GroupInfo';
const GoodsGroup = options => {
const [groupEdit, setGroupEdit] = useState(false);
const [selected, setSelected] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
const [tags, setTags] = useState([
{
......@@ -37,6 +39,7 @@ const GoodsGroup = options => {
},
]);
// 更换位置
const changePosition = (dragIndex, hoverIndex) => {
const data = tags.slice();
const temp = data[dragIndex];
......@@ -68,7 +71,7 @@ const GoodsGroup = options => {
key={item.id}
/>
))}
<InsertTag />
<InsertTag handleOpen={setIsModalOpen} />
</div>
</DndProvider>
) : (
......@@ -84,10 +87,11 @@ const GoodsGroup = options => {
<span className={styles['groupBox-body--tag__text']}>{item.text}</span>
</Tag>
))}
<InsertTag />
<InsertTag handleOpen={setIsModalOpen} />
</div>
)}
</div>
<GroupInfo isModalOpen={isModalOpen} handleClose={setIsModalOpen} />
</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 { Input, Tag } from 'antd';
import React from 'react';
import { Tag } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import styles from '../../style.less';
const InsertTag = options => {
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState('');
const refInput = useRef();
const showInput = () => {
setInputVisible(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('');
options.handleOpen(true);
};
return (
<>
{inputVisible && (
<Input
type="text"
size="small"
ref={refInput}
className={styles['groupBox-body--tag-input']}
value={inputValue}
onChange={handleInputChange}
onBlur={handleInputConfirm}
onPressEnter={handleInputConfirm}
/>
)}
{!inputVisible && (
<Tag
className={[styles['groupBox-body--tag'], styles['groupBox-body--new']]}
color="blue"
......@@ -46,8 +16,6 @@ const InsertTag = options => {
>
<PlusOutlined /> 添加
</Tag>
)}
</>
);
};
......
......@@ -7,15 +7,18 @@ import GoodsGroup from './components/GoodsGroup';
import { searchList } from '../service';
import styles from '../style.less';
import { takeawayColumn } from '../staticdata';
// import VirtualTable from './components/VirtualTable';
import ActionBar from './components/ActionBar';
const Takeaway = options => {
const actionRef = useRef(null);
const [tableData, setTableData] = useState([]);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [loading, setLoading] = useState(false);
const rowSelection = {};
const DragHandle = SortableHandle(() => (
<MenuOutlined style={{ cursor: 'grab', color: '#999' }} />
));
const rowSelection = {
selectedRowKeys,
onChange: setSelectedRowKeys,
};
const onSortEnd = ({ oldIndex, newIndex }) => {
if (oldIndex !== newIndex) {
......@@ -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 () => {
setLoading(true);
const res = await searchList({ productType: 1 });
......@@ -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(() => {
getDataList();
}, []);
......@@ -60,14 +63,15 @@ const Takeaway = options => {
<div className={styles.takeawayBox}>
<Spin spinning={loading}>
<GoodsGroup />
<ActionBar />
<Table
dataSource={tableData}
bordered
columns={takeawayColumn.call(this)}
rowKey={record => record.skuId}
pagination={false}
// scroll={{ x: '100%', y: 500 }}
// rowSelection={rowSelection}
scroll={{ x: '100%', y: 1000 }}
rowSelection={rowSelection}
components={{
body: {
wrapper: DraggableContainer,
......@@ -75,6 +79,15 @@ const Takeaway = options => {
},
}}
/>
{/* <VirtualTable
columns={takeawayColumn.call(this)}
rowKey={record => record.skuId}
dataSource={tableData}
scroll={{
y: 300,
x: '100%',
}}
/> */}
</Spin>
</div>
);
......
import React from 'react';
import { Button, Badge, Switch, Modal } from 'antd';
import { SortableHandle } from 'react-sortable-hoc';
import { ExclamationCircleOutlined, MenuOutlined } from '@ant-design/icons';
import styles from './style.less';
import { resetTime } from '../../utils/utils';
import { apiChangeStateGoods, apiQueryLastAuditRecord } from './service';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
import { apiChangeStateGoods } from './service';
const { confirm } = Modal;
......@@ -246,7 +246,7 @@ export function column() {
];
}
export function takeawayColumn() {
export function takeawayColumn(actions) {
const onChangeState = async ({ skuId, state }) => {
confirm({
icon: <ExclamationCircleOutlined />,
......@@ -276,77 +276,32 @@ export function takeawayColumn() {
{
title: '排序',
dataIndex: 'sort',
width: 60,
align: 'center',
className: [styles['drag-visible'], styles['sort-td']],
width: 70,
className: [styles['drag-visible']],
render: () => <DragHandle />,
},
{
title: 'SKU编码',
dataIndex: 'skuId',
width: 125,
width: 180,
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商品名称',
width: 135,
// width: 200,
align: 'center',
dataIndex: 'skuName',
},
{
title: '供应商价格',
title: '售卖价格(元)',
dataIndex: 'marketPrice',
width: 150,
align: 'center',
sorter: (a, b) => a.supplyPrice - b.supplyPrice,
render: (_, row) => (
<div className={styles.price}>
<p>供货价:{(row.supplyPrice || 0).toFixed(2)}</p>
<p>市场价:{(row.marketPrice || 0).toFixed(2)}</p>
<div>供货价:{(row.supplyPrice || 0).toFixed(2)}</div>
<div>市场价:{(row.marketPrice || 0).toFixed(2)}</div>
</div>
),
},
......@@ -355,78 +310,80 @@ export function takeawayColumn() {
width: 120,
dataIndex: 'stock',
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: '上下架状态',
dataIndex: 'stateDesc', // 5:未上架 ,6 :上架,7:下架
width: 200,
align: 'center',
render: (_, row) => (
<div>
{row.type === 4 && row.state >= 5 ? (
<>
<Switch
checkedChildren="已上架"
checked={row.state === 6}
unCheckedChildren="已下架"
onClick={() => onChangeState(row)}
defaultChecked
/>
</>
) : (
'-'
)}
</div>
),
},
{
title: '审核状态',
dataIndex: 'stateDesc',
width: 200,
title: '操作',
dataIndex: 'action',
width: 400,
align: 'center',
render: (_, row) => (
<div>
<p>{row.state >= 5 ? '审核通过' : _}</p>
<div>
{row.updateState ? (
<Button onClick={() => onShowAudit(row)} type="link">
{row.updateStateDesc}
render: (_, row, index) => (
<div className={styles.actionBtn}>
{(row.state === 4 || (row.state >= 5 && row.updateState !== 1)) && (
<Button key="edit" type="primary" className={styles.button}>
编辑
</Button>
)}
<Button key="viewP" type="primary" className={styles.button}>
上架
</Button>
<Button key="log" type="primary" className={styles.button}>
修改库存
</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 stateList = [
{ value: 3, label: '待审核' },
......
......@@ -63,7 +63,7 @@
}
.actionBtn {
button {
width: 75px;
min-width: 75px;
}
}
.pagination {
......@@ -219,6 +219,23 @@
.drag-visible {
visibility: visible;
}
.sort-td {
text-align: center;
.td-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