Commit f0ca9683 authored by beisir's avatar beisir

feat: 商品库页面

parent 610a8d03
This diff is collapsed.
/* eslint-disable no-param-reassign */
import React from 'react';
import { Cascader, Select, InputNumber, Button } from 'antd';
import { stateList } from './staticdata';
const filterOption = (input, op) => op.props.children.includes(input);
export const toolBarList = () => [
<Button key="getOffGoodsShelf" type="primary">
新增商品
</Button>,
<Button key="putGoodsShelf">模版</Button>,
<Button key="tags" type="primary">
批量修改库存
</Button>,
];
export const Goodscolumns = ({
categoryData,
supplyPrice,
setSupplyPrice,
supplyPriceRef,
onModifyForm,
}) => [
{
title: 'SKU编码',
dataIndex: 'skuId',
key: 'skuId',
},
{
title: 'SKU商品名称',
dataIndex: 'skuName',
key: 'skuName',
},
{
title: '供应商名称',
dataIndex: 'shopId',
key: 'shopId',
hideInTable: true,
valueType: 'cascader',
renderFormItem: () => (
<Cascader
changeOnSelect
fieldNames={{ label: 'name', value: 'id', children: 'children' }}
options={categoryData}
/>
),
},
{
title: '审核状态',
dataIndex: 'state',
key: 'state',
hideInTable: true,
valueType: 'select',
renderFormItem: () => (
<Select allowClear showSearch filterOption={filterOption}>
{stateList?.map(item => (
<Select.Option key={item.value} value={item.value}>
{item.label}
</Select.Option>
))}
</Select>
),
},
{
title: '供货价区间',
hideInTable: true,
dataIndex: 'supplyPrice',
modalHide: true,
renderFormItem: () => [
<div key="supplyPrice" className="search-profit-margin">
<InputNumber
key="min"
placeholder="请输入"
onChange={value => {
supplyPrice[0] = value;
setSupplyPrice(supplyPrice);
}}
/>
<span className="line">-</span>
<InputNumber
ref={supplyPriceRef}
key="max"
placeholder="请输入"
onChange={value => {
supplyPrice[1] = value;
setSupplyPrice(supplyPrice);
}}
/>
</div>,
],
},
{
title: '第三方SKU编码',
dataIndex: 'thirdSkuNo',
key: 'thirdSkuNo',
hideInTable: true,
},
{
title: '价格',
dataIndex: 'supplyPrice',
key: 'supplyPrice',
hideInSearch: true,
render: (value, row) => (
<>
<p>
供货价:<a>{value}</a>
</p>
<p>
市场价:<a>{row.marketPrice}</a>
</p>
</>
),
},
{
title: '库存',
dataIndex: 'stock',
key: 'stock',
hideInSearch: true,
render: (value, row) => (
<>
<p>
当前库存:<a>{row.productStock}</a>
</p>
<p>可售库存:{value}</p>
{row.type === 1 && row.productStockWarning > -1 && <p>预警值:{row.productStockWarning}</p>}
</>
),
},
{
title: '商品状态',
dataIndex: 'stateDesc',
key: 'stateDesc',
hideInSearch: true,
},
{
title: '操作',
key: 'option',
dataIndex: 'option',
valueType: 'option',
fixed: 'right',
modalHide: true,
render: (value, row) => (
<>
<Button key="update" type="link" onClick={() => onModifyForm(row)}>
修改
</Button>
<Button key="preview" type="link" onClick={() => {}}>
预览
</Button>
<Button key="seelog" type="link" onClick={() => {}}>
查看日志
</Button>
</>
),
},
];
import { Modal, Table, Button, Pagination } from 'antd';
import React, { useState, useEffect } from 'react';
import styles from '../style.less';
import { changeLog } from '../service';
const LogModal = props => {
const [tableData, setTableData] = useState([]);
const [pageNo, setPageNo] = useState(1);
const [pageSize] = useState(20);
const columns = [
{
title: '时间',
dataIndex: 'createdAt',
align: 'center',
},
{
title: '变更字段',
align: 'center',
dataIndex: 'changeType',
},
{
title: '变更后内容',
dataIndex: 'afterChangeValue',
align: 'center',
},
{
title: '变更前内容',
dataIndex: 'beforeChangeValue',
align: 'center',
},
{
title: '变更原因',
dataIndex: 'reason',
align: 'center',
},
{
title: '操作账号',
dataIndex: 'operator',
align: 'center',
},
];
const handleSearch = async (page = 1) => {
setPageNo(page);
const [data] = await changeLog({ id: props.id, pageNo: page, pageSize });
setTableData(data);
};
const onPageChange = page => {
handleSearch(page);
};
useEffect(() => {
if (!props.id) return;
handleSearch();
}, [props.id]);
const { visible } = props;
return (
<Modal title="日志详情" visible={visible} footer={null} onCancel={props.onCancel} width="800px">
<Table
dataSource={tableData.records}
bordered
columns={columns}
rowKey={record => record.id}
pagination={false}
scroll={{ y: 300 }}
/>
{tableData.records && (
<Pagination
onChange={onPageChange}
total={tableData.total}
showTotal={total => `共${total}条`}
current={pageNo}
pageSize={pageSize}
className={styles.pagination}
/>
)}
<Button type="primary" onClick={props.onCancel} className={styles.logBtn}>
关闭
</Button>
</Modal>
);
};
export default LogModal;
import React from 'react';
import { Form, Select, Button } from 'antd';
import { cleanArray } from './utils';
import { getInput } from './libs';
const columnsRest = { style: { width: 135 } };
const formItemColumns = () => {
console.log('==========');
return [
{
title: '供货价',
key: 'supplyPrice',
placeholder: '请先选择二级规格',
inputType: 'number',
rest: columnsRest,
},
{
title: '市场价',
key: 'marketPrice',
placeholder: '请选择市场价',
inputType: 'number',
rest: columnsRest,
},
{
title: '重量(kg)',
key: 'weight',
inputType: 'number',
rest: columnsRest,
role: [1, 2],
},
{
title: '库存',
key: 'productStock',
inputType: 'number',
rest: columnsRest,
},
];
};
const formItemStyle = {
style: {
display: 'inline-block',
marginRight: 5,
marginBottom: 0,
},
};
const createSpecSelect = ({ specId, list, placeholder }) => (
<Select allowClear style={{ width: 120 }} placeholder={specId?.label || placeholder}>
{list.map(item => (
<Select.Option key={item} value={item}>
{item}
</Select.Option>
))}
</Select>
);
const createFormItems = (productType = 1, { getFieldDecorator }) => {
const formItems = formItemColumns()
.filter(item => !item.role || item?.role.includes(productType))
.map(item => (
<Form.Item {...formItemStyle}>
{getFieldDecorator(`batchItem[${item.key}]`, {})(getInput(item))}
</Form.Item>
));
return formItems;
};
export const BatchSettings = ({ form, settingTable }) => {
const { getFieldDecorator, getFieldsValue, getFieldValue } = form;
const values = getFieldsValue();
const { firstSpecId, secondSpecId, firstValues = [], secondValues = [] } = values;
const cleanFirstValues = cleanArray(firstValues);
const cleanSecondValues = cleanArray(secondValues);
const renderFormItem = createFormItems(2, { getFieldDecorator });
return (
<div>
<Form.Item {...formItemStyle}>
{getFieldDecorator('batchItem[batchFirst]', {})(
createSpecSelect({
list: cleanFirstValues,
specId: firstSpecId,
placeholder: '请先选择一级规格',
}),
)}
</Form.Item>
<Form.Item {...formItemStyle}>
{getFieldDecorator('batchItem[batchSecond]', {})(
createSpecSelect({
list: cleanSecondValues,
specId: secondSpecId,
placeholder: '请先选择二级规格',
}),
)}
</Form.Item>
{renderFormItem}
<Form.Item style={{ display: 'inline-block' }}>
<Button type="primary" onClick={() => settingTable(getFieldValue('batchItem'))}>
批量设置
</Button>
</Form.Item>
</div>
);
};
import React, { useState } from 'react';
import { Table, Form, InputNumber, Input, Popconfirm, Button, notification } from 'antd';
import { getInput } from './libs';
import { cleanArray } from './utils';
import { BatchSettings } from './BatchSettings';
const initData = {
weight: null,
productStockWarning: null,
marketPrice: null,
supplyPrice: null,
productStock: null,
thirdSkuNo: null,
skuLink: null,
imageList: [],
};
const createSecondProduct = (secondValues, initItem, secondSpecId, dataSource, callback) => {
secondValues.forEach(secondItem => {
const specSecond = { ...initItem };
if (callback) {
callback(specSecond);
}
specSecond.secondSpecId = secondSpecId.key;
specSecond.secondSpecValue = secondItem;
dataSource.push(specSecond);
});
};
const createProductData = ({ firstValues, secondValues, firstSpecId, secondSpecId }) => {
const countRowSpan = {};
const dataSource = [];
if (firstValues.length) {
firstValues.forEach((fisrtItem, index) => {
const specFirst = { ...initData };
specFirst.firstSpecId = firstSpecId.key;
specFirst.firstSpecValue = fisrtItem;
if (secondValues.length) {
createSecondProduct(secondValues, specFirst, secondSpecId, dataSource, specSecond => {
if (!countRowSpan[specFirst.firstSpecValue]) {
countRowSpan[specFirst.firstSpecValue] = true;
specSecond.rowSpanCount = secondValues.length;
}
});
return;
}
dataSource.push(specFirst);
});
} else if (secondValues.length) {
createSecondProduct(secondValues, initData, secondSpecId, dataSource);
} else {
dataSource.push(initData);
}
return dataSource;
};
const isRepeatProduct = (list, message) => {
const isRepeat = [...new Set(list)].length !== list.length;
if (isRepeat) {
notification.warning({ message });
}
return isRepeat;
};
const EditableContext = React.createContext();
const EditableCell = tableProps => {
const renderCell = form => {
const { getFieldDecorator } = form;
const {
editable,
dataIndex,
title,
inputType,
record,
index,
children,
rules = [],
required,
...restProps
} = tableProps;
console.log(record[dataIndex]);
return (
<td {...restProps}>
<Form.Item style={{ margin: 0 }}>
{getFieldDecorator(`tableArray[${index}][${dataIndex}]`, {
rules: [
{
required,
message: `请输入${title}!`,
},
...rules,
],
initialValue: record[dataIndex],
})(getInput(tableProps))}
</Form.Item>
</td>
);
};
return <EditableContext.Consumer>{renderCell}</EditableContext.Consumer>;
};
const ProductInfoColumns = (
{ firstSpecId, secondSpecId, firstValues, secondValues },
productData,
) => {
const productColData = [
{
title: firstSpecId?.label,
dataIndex: 'firstSpecValue',
key: 'firstSpecValue',
editable: false,
render: (val, row) => ({
children: val,
props: {
// eslint-disable-next-line no-nested-ternary
rowSpan: secondValues?.length ? (row.rowSpanCount ? row.rowSpanCount : 0) : true,
},
}),
hidden: !firstValues?.length,
},
{
title: secondSpecId?.label,
dataIndex: 'secondSpecValue',
key: 'secondSpecValue',
editable: false,
hidden: !secondValues?.length,
},
{
title: '供货价',
key: 'supplyPrice',
dataIndex: 'supplyPrice',
editable: true,
inputType: 'number',
required: true,
rules: [],
},
{
title: '市场价',
key: 'marketPrice',
dataIndex: 'marketPrice',
editable: true,
inputType: 'number',
required: true,
},
{
title: '重量(kg)',
key: 'weight',
dataIndex: 'weight',
editable: true,
inputType: 'number',
required: true,
},
{
title: '库存',
dataIndex: 'productStock',
key: 'productStock',
editable: true,
inputType: 'number',
required: true,
},
{
title: '库存预警',
dataIndex: 'productStockWarning',
key: 'productStockWarning',
editable: true,
inputType: 'number',
required: true,
},
{
title: '商品自编码',
dataIndex: 'thirdSkuNo',
key: 'thirdSkuNo',
editable: true,
inputType: 'input',
required: true,
},
{
title: '京东链接',
dataIndex: 'skuLink',
key: 'skuLink',
inputType: 'input',
editable: true,
},
];
return productData.length ? productColData : [];
};
const createProductColumns = (values, productData) => {
const columns = ProductInfoColumns(values, productData)
.map(col => {
console.log('=================>');
return {
...col,
onCell: (record, index) => ({
index,
record,
inputType: col.inputType,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
rules: col.rules,
required: col.required,
}),
};
})
.filter(col => !col.hidden);
return columns;
};
export const GenerateProductInfo = ({ form }) => {
const [productData, setProductData] = useState([]);
const [columns, setColumns] = useState([]);
const components = {
body: {
cell: EditableCell,
},
};
const handleAddProduct = () => {
const values = form.getFieldsValue();
const { firstValues = [], secondValues = [], firstSpecId, secondSpecId } = values;
const cleanFirstValues = cleanArray(firstValues); // 清楚空属性
const cleanSecondValues = cleanArray(secondValues);
// 校验是否有重复的一级规格
const fisrtIsRepeat = isRepeatProduct(cleanFirstValues, '一级规格不可重复');
const secondIsRepeat = isRepeatProduct(cleanSecondValues, '二级规格不可重复');
if ([fisrtIsRepeat, secondIsRepeat].includes(true)) {
setProductData([]);
return;
}
const cleanValues = {
firstValues: cleanFirstValues,
secondValues: cleanSecondValues,
firstSpecId,
secondSpecId,
};
const newData = createProductData(cleanValues);
console.log(newData);
setProductData(newData);
form.setFieldsValue({
tableArray: newData,
});
const columnsData = createProductColumns(cleanValues, newData);
setColumns(columnsData);
};
const settingTable = batchItem => {
const productKey = Object.keys(batchItem);
console.log(productKey);
const newData = productData.map(item => {
productKey.forEach(key => {
item[key] = batchItem[key] || null;
});
return item;
});
console.log(newData);
setProductData(newData);
form.setFieldsValue({
tableArray: newData,
});
};
return (
<EditableContext.Provider value={form}>
<div style={{ textAlign: 'center' }}>
<Button onClick={() => handleAddProduct()} type="primary" style={{ marginBottom: 16 }}>
生成商品信息
</Button>
</div>
<BatchSettings form={form} settingTable={settingTable} />
<Table
rowKey="id"
pagination={false}
components={components}
bordered
dataSource={productData}
columns={columns}
rowClassName="editable-row"
/>
</EditableContext.Provider>
);
};
import React, { useState } from 'react';
import { Form, notification, Col, Input, Icon, Row, Button, Select } from 'antd';
import { filterSpecId } from './utils';
export const SelectSpecifications = ({
form,
keys,
formKey,
labelName,
specList,
formValue,
labelKey,
}) => {
const { getFieldValue, getFieldDecorator, setFieldsValue } = form;
const [countNumber, setCountNumber] = useState(0); // 添加计数器
getFieldDecorator(keys, { initialValue: [] });
const remove = k => {
const valueKey = getFieldValue(keys);
const removeItem = valueKey.filter(i => i !== k);
setFieldsValue({
[keys]: removeItem,
});
setCountNumber(removeItem.length);
};
const add = () => {
const specValue = getFieldValue(formKey);
if (!specValue) {
notification.warning({ message: `请先选择${labelName}数据` });
return;
}
const valueKey = getFieldValue(keys);
const nextKeys = [...valueKey, countNumber];
setCountNumber(countNumber + 1);
setFieldsValue({
[keys]: nextKeys,
});
};
const onChange = option => {
// setFieldsValue({
// [labelKey]: option.props.children,
// });
};
const formItemList = getFieldValue(keys);
const formItems = formItemList.map((k, index) => (
<Col style={{ marginRight: 20 }} key={k}>
<Form.Item style={{ width: 200 }} required={false}>
{getFieldDecorator(`${formValue}[${index}]`, {
validateTrigger: ['onChange', 'onBlur'],
rules: [{ required: true, whitespace: true, message: 'Please input passenger' }],
})(<Input placeholder="passenger name" style={{ width: 150, marginRight: 8 }} />)}
<Icon className="dynamic-delete-button" type="minus-circle-o" onClick={() => remove(k)} />
</Form.Item>
</Col>
));
return (
<>
<Form.Item label={labelName}>
{getFieldDecorator(formKey)(
<Select
labelInValue
allowClear
showSearch
onChange={(_, option) => onChange(option)}
filterOption={filterSpecId}
>
{specList.map(item => (
<Select.Option key={item.specId} value={item.specId}>
{item.specName}
</Select.Option>
))}
</Select>,
)}
</Form.Item>
<Row type="flex">
{formItems}
<Col>
<Button type="dashed" style={{ marginTop: 5 }} onClick={() => add()}>
<Icon type="plus" />
</Button>
</Col>
</Row>
</>
);
};
import React, { useEffect } from 'react';
import SuperSelect from 'antd-virtual-select';
import {
Form,
Modal,
Card,
Cascader,
Select,
Radio,
Popover,
Input,
Icon,
Button,
Row,
Col,
notification,
} from 'antd';
import { productTypeList } from '../staticdata';
import { useModalTitle, useSpecList, formItemLayout, filterSpecId } from './utils';
import { RadioComponent, CascaderComponent } from './libs';
import { productTypeRules, categoryIdRules, brandIdRules } from './rules';
import { SelectSpecifications } from './SelectSpecifications';
import { GenerateProductInfo } from './GenerateProductInfo';
// import GenerateProductInfo from './GenerateProductInfo';
const { Option } = Select;
const filterOption = (input, op) => op.props.children.includes(input);
const OperationForm = props => {
const {
isEdit,
operationVisible,
setOperationVisible,
categoryData,
// virtualTreeData,
shopList,
barndList,
// virtualBarndList,
form,
} = props;
const {
getFieldDecorator,
setFieldsValue,
getFieldsValue,
validateFields,
resetFields,
getFieldValue,
} = form;
const [title] = useModalTitle(isEdit);
const [specList] = useSpecList();
useEffect(() => {
console.log(isEdit);
if (isEdit) {
setFieldsValue({
productType: 2,
});
} else {
setFieldsValue({
productType: 1,
});
}
}, [isEdit, operationVisible]);
const onSubmitGoodsForm = () => {
validateFields(async (errors, values) => {
const { firstKeys = [], firstValues = [], secondKeys = [], secondValues = [] } = values;
console.log(values);
console.log(firstKeys.map(key => firstValues[key]));
console.log(secondKeys.map(key => secondValues[key]));
if (!errors) {
const formData = {
id: '', // 有id是编辑
name: values.name,
items: [], // sku表格
brandId: values.brandId, // 商品品牌
supplierId: '',
detailImageList: [], // 详情图片列表
commonImageList: [], // 公共滑动图
categoryId: values.categoryId, // 类目id
type: values.productType, // 商品类型
};
}
});
};
const onCancelModalForm = () => {
setOperationVisible(false);
resetFields();
};
const { name } = getFieldsValue();
return (
<Modal
title={title}
width="1050px"
visible={operationVisible}
onCancel={onCancelModalForm}
onOk={() => onSubmitGoodsForm()}
>
<Form {...formItemLayout}>
<Card>
<Form.Item label="商品类型:">
{getFieldDecorator('productType', productTypeRules())(
RadioComponent({ productTypeList }),
)}
</Form.Item>
<Form.Item label="类目:">
{getFieldDecorator('categoryId', categoryIdRules())(
CascaderComponent({ categoryData }),
)}
</Form.Item>
<Form.Item label="商品品牌">
{getFieldDecorator('brandId', brandIdRules())(
<SuperSelect allowClear showSearch filterOption={filterOption}>
{barndList.map(item => (
<Option key={item.id} value={item.id}>
{item.name}
</Option>
))}
</SuperSelect>,
)}
</Form.Item>
<Form.Item label="商品名称">
<Popover content={name} trigger="hover">
{getFieldDecorator('name', {
rules: [{ required: true, message: '请输入商品名称' }],
})(<Input allowClear />)}
</Popover>
</Form.Item>
</Card>
<Card>
<SelectSpecifications
form={form}
keys="firstKeys"
formKey="firstSpecId"
formValue="firstValues"
labelKey="firstSpecName"
labelName="一级规格"
specList={specList}
/>
<SelectSpecifications
form={form}
keys="secondKeys"
formKey="secondSpecId"
formValue="secondValues"
labelKey="secondSpecName"
labelName="二级规格"
specList={specList}
/>
</Card>
<Card>
<GenerateProductInfo form={form} />
</Card>
</Form>
</Modal>
);
};
export default Form.create()(OperationForm);
import React from 'react';
import { Radio, Cascader, InputNumber, Input } from 'antd';
export const RadioComponent = ({ productTypeList }) => (
<Radio.Group>
{productTypeList.map(item => (
<Radio key={item.value} value={item.value} disabled={item.disabled}>
{item.label}
</Radio>
))}
</Radio.Group>
);
export const CascaderComponent = ({ categoryData }) => (
<Cascader
changeOnSelect
showSearch
fieldNames={{ label: 'name', value: 'id', children: 'children' }}
options={categoryData}
/>
);
export const getInput = ({ inputType, title, children, rest = {} }) => {
let renderElement = null;
switch (inputType) {
case 'number':
renderElement = <InputNumber {...rest} placeholder={`请输入${title}`} />;
break;
case 'input':
renderElement = <Input {...rest} placeholder={`请输入${title}`} />;
break;
default:
renderElement = (
<span {...rest} className="ant-form-text">
{children}
</span>
);
}
return renderElement;
};
export const productTypeRules = () => ({
rules: [{ required: true, message: '请选择商品类型' }],
});
export const categoryIdRules = () => ({
rules: [{ required: true, message: '请选择类目' }],
});
export const brandIdRules = () => ({
rules: [{ required: true, message: '请选择商品品牌' }],
});
import React, { useEffect, useState } from 'react';
import { getSpecList } from '../service';
export const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 2 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 22 },
},
};
export const useModalTitle = isEdit => {
const titleText = isEdit ? '修改商品' : '新增商品';
return [titleText];
};
export const useSpecList = () => {
const [specList, setSpecList] = useState([]);
useEffect(() => {
const featchData = async () => {
const { data = [] } = await getSpecList();
setSpecList(data);
};
featchData();
}, []);
return [specList];
};
export const filterSpecId = (input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0;
export const useEditProduct = () => [1];
export const dataInit = list => {
if (!list || !list.length) return;
const obj = {};
let finialList = [];
list.forEach(item => {
obj[item.firstSpecValue] = [];
});
list.forEach(item => obj[item.firstSpecValue].push(item));
const keys = Object.keys(obj);
keys.forEach(key => {
obj[key].forEach((i, index) => {
if (index === 0) {
i.length = obj[key].length;
}
});
finialList = finialList.concat(obj[key]);
return finialList;
});
};
export const cleanArray = actual => {
const newArray = [];
// eslint-disable-next-line no-plusplus
for (let i = 0; i < actual.length; i++) {
if (actual[i]) {
newArray.push(actual[i]);
}
}
return newArray;
};
This diff is collapsed.
import { Modal, Table, Button } from 'antd';
import React, { Component } from 'react';
import styles from '../style.less';
class DetailModal extends Component {
getColumns = (firstSpe, secondSpe, type) => {
const arr = [
{
title: '供应商',
dataIndex: 'supplierName',
key: 'supplierName',
align: 'center',
width: 50,
render: (val, row) => {
const obj = {
children: val,
props: {},
};
if (row.listLength) {
obj.props.rowSpan = row.listLength;
} else {
obj.props.rowSpan = 0;
}
return obj;
},
},
];
if (firstSpe) {
arr.push({
title: firstSpe,
dataIndex: 'firstSpecValue',
key: 'firstSpecValue',
align: 'center',
width: 50,
render: (val, row) => {
const obj = {
children: val,
props: {},
};
if (row.length) {
obj.props.rowSpan = row.length;
} else {
obj.props.rowSpan = 0;
}
return obj;
},
});
}
if (secondSpe) {
arr.push({
title: secondSpe,
align: 'center',
key: 'secondSpecValue',
dataIndex: 'secondSpecValue',
width: 50,
});
}
const newTable = arr.concat([
{
title: '供应商编码',
align: 'center',
key: 'supplierCode',
dataIndex: 'supplierCode',
width: 50,
},
{
title: '库存',
align: 'center',
key: 'stock',
dataIndex: 'stock',
width: 50,
},
{
title: '供货价',
align: 'center',
key: 'supplyPrice',
dataIndex: 'supplyPrice',
width: 50,
},
{
title: '市场价',
align: 'center',
key: 'marketPrice',
dataIndex: 'marketPrice',
width: 50,
},
{
title: '国际编码',
align: 'center',
key: 'thirdSkuNo',
dataIndex: 'thirdSkuNo',
width: 50,
},
]);
if (type === 1) {
newTable.splice(newTable.length - 1, 0, {
title: '重量(kg)',
align: 'center',
key: 'weight',
dataIndex: 'weight',
width: 90,
});
}
return newTable;
};
updateStatus = (row, productState) => {
this.props.updateStatus(row, productState);
};
dataInit = list => {
const obj = {};
let finialList = [];
list.map(item => {
obj[item.firstSpecValue] = [];
return obj;
});
list.map(item => obj[item.firstSpecValue].push(item));
const keys = Object.keys(obj);
// eslint-disable-next-line no-return-assign
keys.map(key => {
obj[key].forEach((i, index) => {
if (index === 0) {
i.length = obj[key].length;
}
});
finialList = finialList.concat(obj[key]);
return finialList;
});
if (finialList.length) {
finialList[0].listLength = finialList.length;
}
return finialList;
};
render() {
const { visible, data = [], type } = this.props;
const initdata = this.dataInit(data);
const firstName = data.length ? data[0].firstSpec : '';
const secondName = data.length ? data[0].secondSpec : '';
return (
<Modal
title="供货详情"
visible={visible}
footer={null}
onCancel={this.props.onCancel}
width="900px"
>
<Table
dataSource={initdata}
bordered
columns={this.getColumns(firstName, secondName, type)}
rowKey="id"
pagination={false}
scroll={{ x: '100%' }}
/>
<Button type="primary" onClick={this.props.onCancel} className={styles.logBtn}>
关闭
</Button>
</Modal>
);
}
}
export default DetailModal;
import { Modal, InputNumber, notification } from 'antd';
import React, { useState, useEffect } from 'react';
import { updatePrice } from '../service';
import styles from './style.less';
export default function UpdatePrice(props) {
const [visible, setVisible] = useState(props.visible);
const [supplyPrice, setSupplyPrice] = useState(props.info.supplyPrice);
const [marketPrice, setMarketPrice] = useState(props.info.marketPrice);
// const [salePrice, setSalePrice] = useState(props.info.salePrice);
useEffect(() => {
setVisible(props.visible);
setSupplyPrice(props.info.supplyPrice);
setMarketPrice(props.info.marketPrice);
// setSalePrice(props.info.salePrice);
}, [props]);
const submit = async () => {
if (!supplyPrice || !marketPrice) {
notification.error({ message: '价格不可为空!' });
return;
}
const error = await updatePrice({
// salePrice,
supplyPrice,
marketPrice,
id: props.info.id,
supplierId: props.info.supplierId,
});
if (!error) {
notification.success({ message: '修改成功' });
props.onCancel('success');
}
};
return (
<Modal
title="修改价格"
visible={visible}
onCancel={() => props.onCancel()}
onOk={submit}
width={400}
>
<div className={styles.center}>
供货价:
<InputNumber
min={0}
precision={2}
value={supplyPrice}
onChange={value => setSupplyPrice(value)}
className={styles.inputNW}
/>
<br />
<br />
市场价:
<InputNumber
min={0}
precision={2}
value={marketPrice}
onChange={value => setMarketPrice(value)}
className={styles.inputNW}
/>
<br />
<br />
{/* 销售价:
<InputNumber
min={0}
precision={2}
value={salePrice}
onChange={value => setSalePrice(value)}
className={styles.inputNW}
/> */}
</div>
</Modal>
);
}
.inputNW {
width: 200px;
}
.center {
text-align: center;
}
import { Modal, InputNumber, notification, Form, Input, Radio } from 'antd';
import React from 'react';
import { updateStock } from '../service';
import styles from '../UpdatePrice/style.less';
const UpdateStock = props => {
const { getFieldDecorator, validateFields, resetFields, getFieldValue } = props.form;
const valueInfo = props.info;
getFieldDecorator('stockChangeType', { initialValue: 1 });
const submit = async () => {
validateFields(async (err, { stock, changeReason, stockChangeType }) => {
if (err) return;
const error = await updateStock({
stock,
id: valueInfo.id,
supplierId: valueInfo.supplierId,
stockChangeType,
changeReason,
});
if (!error) {
notification.success({ message: '操作成功!' });
props.onCancel('success');
resetFields();
}
});
};
const onCancel = () => {
props.onCancel();
resetFields();
};
const formItemLayout = {
labelCol: {
span: 8,
},
wrapperCol: {
span: 16,
},
};
const validatorCallback = (rule, value, callback) => {
// 减库存存时,校验可售库存-输入值>=0,即可售库存不可为负;
const stockChangeType = getFieldValue('stockChangeType');
const increment = valueInfo.marketableStock - value;
return !stockChangeType && increment < 0 ? callback(new Error(rule.message)) : callback();
};
return (
<Modal title="修改库存" visible={props.visible} onCancel={onCancel} onOk={submit} width={400}>
<Form {...formItemLayout}>
<Form.Item label="变更类型:">
{getFieldDecorator('stockChangeType', {
rules: [{ required: true, message: '请选择类型!' }],
})(
<Radio.Group>
<Radio value={1}>增库存</Radio>
<Radio value={0}>减库存</Radio>
</Radio.Group>,
)}
</Form.Item>
<Form.Item label="库存数:">
{getFieldDecorator('stock', {
rules: [
{ required: true, message: '请输入库存!' },
{ validator: validatorCallback, message: '减库存,输入库存数不可大于可售库存!' },
],
validateTrigger: ['onSubmit'],
})(
<InputNumber
min={0}
precision={0}
placeholder="请输入库存"
className={styles.inputNW}
/>,
)}
</Form.Item>
<Form.Item label="变更原因:">
{getFieldDecorator('changeReason', {
rules: [{ required: true, message: '请输入变更原因!' }],
initialValue: valueInfo.changeReason,
})(<Input.TextArea />)}
</Form.Item>
</Form>
</Modal>
);
};
export default Form.create()(UpdateStock);
import { Modal, Form, Select, Input, InputNumber } from 'antd';
import React, { Component } from 'react';
const FormItem = Form.Item;
class formModal extends Component {
componentDidMount() {
this.props.onRef(this);
}
handleOk = () => {
this.props.form.validateFields((err, fieldsValue) => {
if (err) return;
const value = {
...fieldsValue,
id: this.props.initForm.id ?? '',
};
this.props.submit(value);
});
};
resetFields = () => {
this.props.form.resetFields();
};
render() {
const {
visible,
form: { getFieldDecorator },
statusList = [],
initForm = {},
} = this.props;
const InputNumStyle = { width: '100%' };
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 17 },
},
};
const options =
statusList.length &&
statusList.map(d => (
<Select.Option value={d.status} key={d.status}>
{d.statusDesc}
</Select.Option>
));
return (
<Modal
title="商品信息修改"
visible={visible}
onCancel={this.props.onCancel}
onOk={this.handleOk}
>
<Form name="detail" {...formItemLayout}>
<FormItem label="sku编码">
{getFieldDecorator('skuNo', {
initialValue: initForm.skuNo,
})(<Input readOnly />)}
</FormItem>
<FormItem label="商品名称">
{getFieldDecorator('skuName', {
initialValue: initForm.skuName,
rules: [{ required: true, message: '请输入商品名称' }],
})(<Input allowClear />)}
</FormItem>
<FormItem label="商品规格">
{getFieldDecorator('attValue', {
initialValue: initForm.attValue,
rules: [{ message: '请输入商品规格' }],
})(<Input allowClear />)}
</FormItem>
<FormItem label="成本价">
{getFieldDecorator('costPrice', {
initialValue: initForm.costPrice,
rules: [{ required: true, message: '请输入成本价' }],
})(<InputNumber allowClear precision={2} style={InputNumStyle} />)}
</FormItem>
{/* <FormItem label="市场价">
{getFieldDecorator('marketPrice', {
initialValue: initForm.marketPrice,
rules: [{ required: true, message: '请输入市场价' }],
})(<InputNumber allowClear style={InputNumStyle} precision={2} />)}
</FormItem>
<FormItem label="销售价">
{getFieldDecorator('salePrice', {
initialValue: initForm.salePrice,
rules: [{ required: true, message: '请输入销售价' }],
})(<InputNumber allowClear style={InputNumStyle} precision={2} />)}
</FormItem> */}
<FormItem label="库存">
{getFieldDecorator('stock', {
initialValue: initForm.stock,
rules: [{ required: true, message: '请输入库存' }],
})(<InputNumber allowClear style={InputNumStyle} />)}
</FormItem>
<FormItem label="商品状态">
{getFieldDecorator('status', {
initialValue: initForm.status,
rules: [{ required: true, message: '请输入商品状态' }],
})(<Select allowClear>{options}</Select>)}
</FormItem>
</Form>
</Modal>
);
}
}
export default Form.create()(formModal);
/* eslint-disable no-param-reassign */
import { Form, Select, Input, InputNumber, Button } from 'antd';
import React, { Component } from 'react';
// import styles from '../style.less';
const { Option } = Select;
const FormItem = Form.Item;
class goodsManage extends Component {
componentDidMount() {
this.props.onRef(this);
}
setFiled = flag => {
const { form } = this.props;
if (flag === 'firstKeys') {
form.setFieldsValue({ firstSpecValue: '' });
return;
}
form.setFieldsValue({ secondSpecValue: '' });
};
batchSetting = () => {
const { form, editData, isEdit } = this.props;
const data = form.getFieldsValue();
if (!data.firstSpecValue && !data.secondSpecValue) {
editData.forEach(item => {
item.marketPrice = data.marketPrice;
// item.salePrice = data.salePrice;
if (!isEdit) item.productStock = data.productStock; // 编辑状态不可修改库存
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
});
}
if (data.firstSpecValue && !data.secondSpecValue) {
editData.forEach(item => {
if (item.firstSpecValue === data.firstSpecValue) {
item.marketPrice = data.marketPrice;
// item.salePrice = data.salePrice;
if (!isEdit) item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
}
});
}
if (!data.firstSpecValue && data.secondSpecValue) {
editData.forEach(item => {
if (item.secondSpecValue === data.secondSpecValue) {
item.marketPrice = data.marketPrice;
// item.salePrice = data.salePrice;
if (!isEdit) item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
}
});
}
if (data.firstSpecValue && data.secondSpecValue) {
editData.forEach(item => {
if (
item.firstSpecValue === data.firstSpecValue &&
item.secondSpecValue === data.secondSpecValue
) {
item.marketPrice = data.marketPrice;
// item.salePrice = data.salePrice;
if (!isEdit) item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
}
});
}
this.props.batchSetting(editData);
};
render() {
const {
firstSpes = [],
secondSpecs = [],
firstSpesName = '',
secondSpesName = '',
productType,
isEdit,
} = this.props;
const { getFieldDecorator } = this.props.form;
return (
<Form layout="inline" onSubmit={this.handleSubmit}>
<FormItem>
{getFieldDecorator('firstSpecValue', {})(
<Select allowClear style={{ width: 120 }} placeholder={firstSpesName}>
{firstSpes.length > 0 &&
firstSpes.map(
item =>
item &&
typeof item === 'string' && (
<Option key={item} value={item}>
{item}
</Option>
),
)}
</Select>,
)}
</FormItem>
<FormItem>
{getFieldDecorator('secondSpecValue', {})(
<Select allowClear style={{ width: 120 }} placeholder={secondSpesName}>
{secondSpecs.length &&
secondSpecs.map(
item =>
item &&
typeof item === 'string' && (
<Option key={item} value={item}>
{item}
</Option>
),
)}
</Select>,
)}
</FormItem>
<FormItem>
{getFieldDecorator('supplyPrice', {})(
<Input placeholder="供货价" style={{ width: 100 }} />,
)}
</FormItem>
<FormItem>
{getFieldDecorator('marketPrice', {})(
<Input placeholder="市场价" style={{ width: 100 }} />,
)}
</FormItem>
{/* <FormItem>
{getFieldDecorator('salePrice', {})(
<Input placeholder="销售价" style={{ width: 100 }} />,
)}
</FormItem> */}
{productType === 1 && (
<FormItem>
{getFieldDecorator('weight', {})(
<InputNumber
precision={3}
max={999999.999}
// eslint-disable-next-line radix
placeholder="重量"
style={{ width: 150 }}
/>,
)}
</FormItem>
)}
{!isEdit && (
<FormItem>
{getFieldDecorator('productStock', {})(
<InputNumber
precision={0}
step={1}
// eslint-disable-next-line radix
formatter={val => parseInt(val, '10') || ''}
placeholder="库存"
style={{ width: 100 }}
/>,
)}
</FormItem>
)}
<FormItem>
<Button type="primary" htmlType="submit" onClick={this.batchSetting}>
批量设置
</Button>
</FormItem>
</Form>
);
}
}
export default Form.create()(goodsManage);
import { Row, Col, Button } from 'antd';
import React, { Component } from 'react';
import styles from '../style.less';
// eslint-disable-next-line react/prefer-stateless-function
class ButtonGroup extends Component {
render() {
const { initData, confirmLoading } = this.props;
return (
<Row type="flex" justify="center" align="middle" gutter={20}>
<Col>
<Button type="primary" onClick={() => this.props.onCancel()} className={styles.logBtn}>
取消
</Button>
</Col>
<Col key="submit">
<Button
type="primary"
onClick={() => this.props.confirm()}
className={styles.logBtn}
loading={confirmLoading}
disabled={confirmLoading}
>
提交
</Button>
</Col>
{initData && !Object.keys(initData).length && (
<Col key="submit-add">
<Button
type="primary"
onClick={() => this.props.confirm(true)}
className={styles.logBtn}
loading={confirmLoading}
disabled={confirmLoading}
>
提交并继续添加
</Button>
</Col>
)}
</Row>
);
}
}
export default ButtonGroup;
This diff is collapsed.
This diff is collapsed.
import { Form, Input, Modal } from 'antd';
import React, { Component } from 'react';
const { TextArea } = Input;
const FormItem = Form.Item;
// import styles from '../style.less';
class goodsManage extends Component {
// componentDidMount() {
// this.props.onRef(this);
// }
handleOk = () => {
const { form } = this.props;
form.validateFields((err, values) => {
if (!err) {
this.props.changeSkuName(values.name);
this.props.form.resetFields();
}
});
};
handleCancel = () => {
this.props.form.resetFields();
this.props.onCancle();
};
render() {
const { data, visible, form } = this.props;
const { getFieldDecorator } = form;
return (
<Modal title="" visible={visible} onOk={this.handleOk} onCancel={this.handleCancel}>
<Form>
<FormItem label="sku名称">
{getFieldDecorator('name', {
initialValue: data,
rules: [
{
required: true,
message: '请输入',
},
],
})(<TextArea autoSize={{ minRows: 2, maxRows: 6 }} allowClear />)}
</FormItem>
</Form>
</Modal>
);
}
}
export default Form.create()(goodsManage);
import React, { useEffect, useState, useRef } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import ProTable from '@ant-design/pro-table';
import { Button } from 'antd';
import { categoryList, query, getVirtualCategory, getSupplierList, getBrandList } from './service';
import { Goodscolumns } from './Goodscolumns';
import styled from './style.less';
// eslint-disable-next-line import/extensions
import OperationModal from './OperationModal/index.jsx';
export default () => {
/**
* @name screenLoading
* @type boolean
* @desc 整个页面的加载状态
*/
const [isEdit, setIsEdit] = useState(false);
const [categoryData, setCategoryData] = useState([]);
const [operationVisible, setOperationVisible] = useState(true);
const actionRef = useRef();
const supplyPriceRef = useRef();
const [supplyPrice, setSupplyPrice] = useState([]);
const [virtualTreeData, setVirtualTreeData] = useState([]);
const [shopList, setShopList] = useState([]);
const [barndList, setBarndList] = useState([]);
const [virtualBarndList, setVirtualBarndList] = useState([]);
useEffect(() => {
const featchData = async () => {
const { data = [] } = await categoryList();
const { data: virtualData = [] } = await getVirtualCategory();
const { data: shopData = [] } = await getSupplierList();
const { data: barndData = [] } = await getBrandList();
const virtualBarndData = barndData.filter(item => item.name === '虚拟商品');
setCategoryData(data);
setVirtualTreeData(virtualData);
setShopList(shopData);
setBarndList(barndData);
setVirtualBarndList(virtualBarndData);
};
featchData();
}, []);
const onAddGoodsForm = () => {
setIsEdit(false);
setOperationVisible(true);
};
const onModifyForm = () => {
// 修改form表单事件
setIsEdit(true);
setOperationVisible(true);
};
const toolBarList = [
<Button key="getOffGoodsShelf" type="primary" onClick={() => onAddGoodsForm()}>
新增商品
</Button>,
<Button key="putGoodsShelf">模版</Button>,
<Button key="tags" type="primary">
批量修改库存
</Button>,
];
return (
<PageHeaderWrapper>
<ProTable
className={styled.protable}
actionRef={actionRef}
columns={Goodscolumns({
categoryData,
supplyPrice,
setSupplyPrice,
supplyPriceRef,
onModifyForm,
})}
params={{ ...supplyPrice }}
request={params => {
// 表单搜索项会从 params 传入,传递给后端接口。
const [supplyPriceMin, supplyPriceMax] = supplyPrice;
return query({ supplyPriceMin, supplyPriceMax, ...params });
}}
rowKey="skuId"
bordered
scroll={{ x: 1500 }}
search={{
collapsed: false,
}}
toolBarRender={() => toolBarList}
pagination={{
showQuickJumper: true,
defaultPageSize: 10,
size: 'default',
showTitle: false,
showTotal: () => null,
}}
onReset={() => {
setSupplyPrice([]);
}}
options={{
density: false,
fullScreen: false,
setting: false,
reload: false,
}}
/>
<OperationModal
isEdit={isEdit}
operationVisible={operationVisible}
setOperationVisible={setOperationVisible}
categoryData={categoryData} // 实体商品类目
virtualTreeData={virtualTreeData} // 虚拟商品类目
shopList={shopList} // 供货商数据
barndList={barndList}
virtualBarndList={virtualBarndList}
/>
{/* rowSelection={rowSelection} */}
{/* <div>helloworld</div> */}
</PageHeaderWrapper>
);
};
import * as api from './service';
const Model = {
namespace: 'GoodsManage-new',
state: {
tableData: {},
shopList: [],
statusList: [],
cid1List: [],
cid2List: [],
cid3List: [],
treeData: [],
},
effects: {
*getList({ payload }, { call, put }) {
const params = payload;
const productCategoryId = payload?.productCategoryId || [];
params.productCategoryId =
(productCategoryId.length && productCategoryId[productCategoryId.length - 1]) || '';
const { data } = yield call(api.searchList, params);
if (!data) return;
yield put({
type: 'saveData',
payload: {
tableData: data,
},
});
},
*getDataList({ payload }, { call, put, all }) {
const [[shopList], [statusList]] = yield all([
yield call(api.shopList, payload),
yield call(api.statusList, payload),
]);
if (!shopList && !statusList) return;
yield put({
type: 'dataList',
payload: {
shopList,
statusList,
},
});
},
*categoryList({ payload }, { call, put }) {
const [data] = yield call(api.categoryList, payload.value);
if (!data) return;
yield put({
type: 'saveCategory',
payload: {
[payload.categoryNum]: data,
},
});
},
},
reducers: {
saveData(state, action) {
const data = action.payload;
return { ...state, ...data };
},
dataList(state, action) {
const data = action.payload;
return { ...state, ...data };
},
saveCategory(state, action) {
const data = action.payload;
return { ...state, ...data };
},
},
};
export default Model;
import { Modal, Input, notification } from 'antd';
import React, { Component } from 'react';
const { TextArea } = Input;
// eslint-disable-next-line react/prefer-stateless-function
class reasonModal extends Component {
state = {
remarks: '',
};
inputChange = ({ target: { value } }) => {
this.setState({ remarks: value });
};
onCancel = () => {
this.setState({ remarks: '' });
this.props.onCancel();
};
submit = () => {
if (!this.state.remarks) {
notification.error({
message: '请输入下架原因',
});
return;
}
this.props.submit(this.state.remarks);
this.setState({ remarks: '' });
};
render() {
const { visible } = this.props;
return (
<Modal
title="下架原因"
visible={visible}
onOk={this.submit}
onCancel={() => this.onCancel()}
width="700px"
>
<div>
<TextArea value={this.state.remarks} rows={4} onChange={this.inputChange} />
</div>
</Modal>
);
}
}
export default reasonModal;
// import fileSaver from 'file-saver';
import request from '@/utils/request';
import config from '../../../config/env.config';
import { stringify } from 'qs';
import _ from 'lodash';
const { kdspApi } = config;
// const kdspApi = 'http://yapi.quantgroups.com/mock/389';
// 分页查询所有数据
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
};
export const query = async params => {
const tempParams = {
...params,
startDate: params.dateRange?.[0],
endDate: params.dateRange?.[1],
pageNo: params.current,
};
delete tempParams.dateRange;
delete tempParams.current;
try {
const {
data: { current, records, total, size },
} = await request.post('/product/page', {
prefix: config.kdspApi,
data: stringify(_.omitBy(tempParams, v => !v)),
headers,
});
return {
current,
data: records,
total,
pageSize: size,
};
} catch (error) {
return {};
}
};
// export async function searchList(params) {
// return request.post('/product/page', {
// prefix: kdspApi,
// data: stringify(_.omitBy(params, v => !v)),
// headers,
// });
// }
// 新增商品
export async function addGoods(params) {
return request.post('/product/add', {
prefix: kdspApi,
params,
});
}
// 编辑商品
export async function editGoods(params) {
return request.post('/product/edit', {
prefix: kdspApi,
params,
});
}
// 供应商列表
export async function getSupplierList() {
return request.post('/channel/supplier/list', {
prefix: kdspApi,
});
}
// 获取商品品牌
export async function getBrandList() {
return request.post('/product/brand/list', {
prefix: kdspApi,
});
}
// 编辑--获取详情
export async function spuDetail(params) {
return request.post('/product/detail', {
prefix: kdspApi,
params,
headers,
});
}
// 商品规格
export async function getSpecList() {
return request.post('/product/spec/list', {
prefix: kdspApi,
});
}
// 查询图片素材
export async function getImageInfo(spuNo) {
return request.post('/product/imageInfo', {
params: { spuNo },
prefix: kdspApi,
headers,
});
}
// 状态
export async function statusList() {
return request.post('/api/kdsp/op/mch_sku/status_list');
}
// 商品来源
export async function skuSource() {
return request.post('/api/kdsp/sku/sku-info/getSkuSource');
}
// 商品分类
export async function categoryList() {
return request.post('/product/category/getAll', {
prefix: kdspApi,
headers,
});
}
// 批量修改
export async function uploadFile(file) {
const params = new FormData();
params.append('file', file);
const data = await request.post('/product/item/batchUpdate', params, {
rawData: true,
});
return data;
}
// 批量倒入京东skus
export async function importJdSkus(file, sourceType) {
const params = new FormData();
params.append('file', file);
params.append('sourceType', sourceType);
const data = await request.post('/product/importJdSkus', params, {
rawData: true,
});
return data;
}
// 批量上架
export async function pushed(data) {
return request.post('/api/kdsp/op/mch_sku/pushed', data);
}
// 批量下架
export async function offline(data) {
return request.post('/api/kdsp/op/mch_sku/offline', data);
}
// 最新批量上下架
export async function batchPushedOrOffline(data) {
return request.post('/product/pushedOrOffline/batch', data, {
emulateJSON: true,
});
}
// 商品修改
export async function update(params) {
return request.post('/api/kdsp/op/mch_sku/update', params, {
emulateJSON: true,
});
}
// 商品修改日志
export async function changeLog(params) {
return request.post('/product/logs/page', params, {
emulateJSON: true,
});
}
// 商品详情
export async function detail(params) {
return request.post('/product/supply/list', params, {
emulateJSON: true,
});
}
// 拉去京东图片
export async function getJdPicList(params) {
const [data] = await request.post('/product/item/getJdPicList', params, {
emulateJSON: true,
});
return data;
}
// 添加商品
export async function addSku(params) {
const [, error] = await request.post('/api/kdsp/op/mch_sku/add_sku', params);
return error;
}
// 修改商品
export async function updateSku(params) {
const [, error] = await request.post('/api/kdsp/op/mch_sku/update', params);
return error;
}
// 图片上传
export async function uploadImg(files) {
const params = new FormData();
files.map(file => params.append('file', file));
const data = await request.post('/image/upload', params, {
rawData: true,
});
return data;
}
// 修改商品价格
export async function updatePrice(params) {
const [, error] = await request.post('/product/item/updatePrice', params, {
emulateJSON: true,
});
return error;
}
// 修改商品库存
export async function updateStock(params) {
const [, error] = await request.post('/product/item/updateStock', params, {
emulateJSON: true,
});
return error;
}
// 获取虚拟商品类目
export async function getVirtualCategory() {
const data = await request.post('/product/category/getByParentId', {
prefix: kdspApi,
params: { id: 100018 },
headers,
});
return data;
}
import React from 'react';
import { Button, Popconfirm, Badge } from 'antd';
import styles from './style.less';
export const productType = [
{
value: 1,
title: '自营',
},
{
value: 2,
title: '京东开普勒',
},
{
value: 3,
title: '京东联盟',
},
{
value: 4,
title: '众联',
},
{
value: 5,
title: '企业购',
},
{
value: 6,
title: '企业购直连',
},
];
export function column() {
return [
{
title: 'SKU编码',
dataIndex: 'skuId',
width: 125,
align: 'center',
render: (_, row) => {
if (row.type !== 1) {
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,
align: 'center',
dataIndex: 'skuName',
},
{
title: '价格',
dataIndex: 'marketPrice',
width: 150,
align: 'center',
sorter: (a, b) => a.supplyPrice - b.supplyPrice,
render: (_, row) => (
<div className={styles.price} onClick={() => this.openModal(row)}>
<p>
供货价:<a>{row.supplyPrice.toFixed(2)}</a>
</p>
<p>
市场价:<a>{(row.marketPrice || 0).toFixed(2)}</a>
</p>
</div>
),
},
{
title: '库存',
width: 120,
dataIndex: 'stock',
align: 'center',
sorter: (a, b) => a.stock - b.stock,
render: (_, row) => (
<>
<p>
当前库存:<a onClick={() => this.openModal(row, 'productStock')}>{row.productStock}</a>
</p>
<p>可售库存:{_}</p>
{row.type === 1 && row.productStockWarning > -1 && (
<p>预警值:{row.productStockWarning}</p>
)}
</>
),
},
{
title: '商品状态',
dataIndex: 'stateDesc',
width: 200,
align: 'center',
},
{
title: '操作',
dataIndex: 'action',
width: 120,
align: 'center',
render: (_, row) => (
<div className={styles.actionBtn}>
{row.state !== 6 && (
<Popconfirm
key="up"
placement="topLeft"
title="确定要上架吗?"
onConfirm={() => this.updateStatus(row.skuId, 6, '')}
okText="确定"
cancelText="取消"
>
<Button key="up" size="small" type="primary" className={styles.button}>
上架
</Button>
</Popconfirm>
)}
{row.state === 6 && (
<Button
key="down"
size="small"
type="primary"
className={styles.button}
disabled={row.state !== 6}
onClick={() => this.offLine(row.skuId, 7)}
>
下架
</Button>
)}
<Button
key="edit"
type="primary"
size="small"
className={styles.button}
onClick={() => this.onUpdateInfo(row)}
>
编辑
</Button>
<Button
key="detail"
size="small"
type="primary"
className={styles.button}
onClick={() => this.showSupply(row.spuId, row.type)}
>
供货详情
</Button>
<Button
key="viewP"
type="primary"
size="small"
className={styles.button}
onClick={() => this.audit(row.skuId)}
>
预览
</Button>
<Button
key="log"
size="small"
type="primary"
className={styles.button}
onClick={() => this.viewLog(row.skuId)}
>
查看日志
</Button>
</div>
),
},
];
}
export const disSelectStatus = [2, 5];
export const stateList = [
{ value: 5, label: '未上架' },
{ value: 6, label: '已上架' },
{ value: 7, label: '已下架' },
];
export const productTypeList = [
{ value: 1, label: '实体商品' },
{ value: 2, label: '虚拟充值' },
{ value: 3, label: '虚拟卡券', disabled: true },
];
export const JDSHOPID = [3, 5, 6];
.formItem {
width: 300px;
}
.itemSection {
display: inline-block;
width: calc(50% - 12px);
margin-right: 0 !important;
}
.itemLine {
display: inline-block;
width: 24px;
text-align: center;
}
.button {
margin: 5px;
}
.selectWidth {
width: 200px;
}
.btngroup {
margin: 10px;
}
.filterModal {
margin: 20px 0;
}
.footerButton {
position: absolute;
bottom: 20px;
left: 0;
}
.tabletop {
margin-top: 20px;
}
.logBtn {
display: inherit;
margin: 20px auto;
}
.linkInput {
width: 310px !important;
}
.picBtn {
margin-top: 5px;
margin-left: 10px;
}
.pullBtn {
position: absolute;
top: -30px;
left: 700px;
}
.price {
// text-align: left;
cursor: pointer;
}
.searchForm {
:global {
.ant-form-item-label {
width: 120px;
}
}
}
.queryBtn {
margin-left: 45px;
}
.actionBtn {
button {
width: 75px;
}
}
.pagination {
margin-top: 10px;
}
.imgBorder {
margin: 5px 0;
padding-left: 20px;
background: #fff;
border: 1px solid #efefef;
border-radius: 10px;
}
.state {
font-size: 13px;
}
.card {
margin-top: 15px;
margin-bottom: 15px;
}
.modal {
background: #ddd;
}
.warning {
margin-top: -20px;
color: red;
}
.iptNumRight {
margin-right: 0 !important;
}
import React, { useEffect } from 'react';
import { categoryList } from './service';
// export const useCategory = () => {
// useEffect(() => {
// const { data } = await categoryList();
// return [data];
// }, [])
// };
......@@ -375,7 +375,6 @@ export function editColumns(methods, firstData, firstSpec, secondSpec, isJDGoods
align: 'center',
width: 100,
render: (val, row) => {
console.log(row);
const obj = {
children: val,
props: {},
......
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