Commit 4ebdcb61 authored by 郭志伟's avatar 郭志伟

Merge branch 'feature/goodsManage' into 'master'

商户管理后台-新增商品管理--商品库页面

See merge request !18
parents 648a86d8 5f31f16c
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
/scripts /scripts
/config /config
.history .history
/src/utils/qiniu.min.js /src/utils/qiniu.min.js
\ No newline at end of file
...@@ -7,6 +7,9 @@ module.exports = { ...@@ -7,6 +7,9 @@ module.exports = {
}, },
rules: { rules: {
'max-len': ['error', { code: 200 }], 'max-len': ['error', { code: 200 }],
'no-param-reassign': 0,
'no-console': 0,
'@typescript-eslint/camelcase': ['off'], '@typescript-eslint/camelcase': ['off'],
'@typescript-eslint/no-unused-vars': ['off'],
}, },
}; };
...@@ -150,6 +150,17 @@ export default { ...@@ -150,6 +150,17 @@ export default {
name: 'cancelBillManage', name: 'cancelBillManage',
component: './cancelBillManage', component: './cancelBillManage',
}, },
{
path: '/goodsManage',
name: 'goodsManage',
icon: 'smile',
component: './GoodsManage',
},
// {
// path: '/GoodsManage-new',
// name: 'GoodsManageNew',
// component: './GoodsManage-new',
// },
{ {
component: './404', component: './404',
}, },
...@@ -169,6 +180,7 @@ export default { ...@@ -169,6 +180,7 @@ export default {
'primary-color': primaryColor, 'primary-color': primaryColor,
}, },
define: { define: {
'process.env.PRE_ENV': process.env.PRE_ENV,
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION:
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION || '', // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION || '', // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
}, },
......
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production';
const isPre = process.env.PRE_ENV === 'pre';
let envAPi = { const envAPi = {
api: '//backstms-gyl.liangkebang.net', api: '//backstms-test1.liangkebang.net',
kdspOpApi: 'https://kdsp-operation-gyl.liangkebang.net', kdspOpApi: 'https://kdsp-operation-test1.liangkebang.net',
kdspApi: 'https://sc-op-api-gyl.liangkebang.net', kdspApi: 'https://sc-op-api-test1.liangkebang.net',
goodsApi: 'https://sc-op-api-test1.liangkebang.net',
// goodsApi: '//192.168.28.107:7000',
prologueDomain: 'https://prologue-test1.liangkebang.net',
qiniuHost: 'https://appsync.lkbang.net', qiniuHost: 'https://appsync.lkbang.net',
opapiHost: 'https://opapi-gyl.liangkebang.net', opapiHost: 'https://opapi-test1.liangkebang.net',
// opapiHost: 'http://192.168.29.45:7000',
}; };
let prodApi = { const prodApi = {
api: '//backstms.q-gp.com', api: '//backstms.q-gp.com',
kdspOpApi: '//kdsp-operation.q-gp.com', kdspOpApi: '//kdsp-operation.q-gp.com',
prologueDomain: '//prologue.q-gp.com',
kdspApi: '//sc-op-api.q-gp.com', kdspApi: '//sc-op-api.q-gp.com',
// goodsApi: 'https://sc-op-api.q-gp.com', // 测试环境打包域名,
goodsApi: 'https://sc-merchant-api.q-gp.com', // 线上环境打包域名
qiniuHost: 'https://appsync.lkbang.net', qiniuHost: 'https://appsync.lkbang.net',
opapiHost: 'https://opapi.xyqb.com', opapiHost: 'https://opapi.xyqb.com',
}; };
let exportApi; const preProdApi = {
isProduction ? (exportApi = prodApi) : (exportApi = envAPi); api: '//backstms-pre.xyqb.com',
kdspOpApi: '//kdsp-operation-pre.q-gp.com',
prologueDomain: '//prologue.q-gp.com',
kdspApi: '//sc-op-api-pre.q-gp.com',
goodsApi: 'https://sc-merchant-api-pre.q-gp.com',
qiniuHost: 'https://appsync.lkbang.net',
opapiHost: 'https://opapi-pre.q-gp.com',
};
let exportApi = envAPi;
if (isPre) {
exportApi = preProdApi;
} else if (isProduction) {
exportApi = prodApi;
}
module.exports = exportApi;
// let exportApi;
// isProduction ? (exportApi = prodApi) : (exportApi = envAPi);
export default exportApi; // export default exportApi;
...@@ -4809,6 +4809,14 @@ ...@@ -4809,6 +4809,14 @@
} }
} }
}, },
"antd-virtual-select": {
"version": "1.1.2",
"resolved": "http://npmprivate.quantgroups.com/antd-virtual-select/-/antd-virtual-select-1.1.2.tgz",
"integrity": "sha512-GejZ/ihog9ZwSn16GsfABPBjeM/X9XMktndu570q9kCe1D/LieO07xNME/dLx4x8IaqGxh6yW4eTUzR83+gkKw==",
"requires": {
"moment": "^2.22.2"
}
},
"any-observable": { "any-observable": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "http://npmprivate.quantgroups.com/any-observable/-/any-observable-0.3.0.tgz", "resolved": "http://npmprivate.quantgroups.com/any-observable/-/any-observable-0.3.0.tgz",
...@@ -20109,6 +20117,15 @@ ...@@ -20109,6 +20117,15 @@
"resize-observer-polyfill": "^1.5.0" "resize-observer-polyfill": "^1.5.0"
} }
}, },
"react-sortablejs": {
"version": "6.0.0",
"resolved": "http://npmprivate.quantgroups.com/react-sortablejs/-/react-sortablejs-6.0.0.tgz",
"integrity": "sha512-vzi+TWOnofcYg+dYnC/Iz/ZZkBGG76uM6KaLwuAqBk0349JQxIy3PZizbK0TJdLlK6NnLt4CiEyyQXSSnVYvEw==",
"requires": {
"classnames": "^2.2.6",
"tiny-invariant": "^1.1.0"
}
},
"react-test-renderer": { "react-test-renderer": {
"version": "16.14.0", "version": "16.14.0",
"resolved": "http://npmprivate.quantgroups.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz", "resolved": "http://npmprivate.quantgroups.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz",
...@@ -21811,6 +21828,11 @@ ...@@ -21811,6 +21828,11 @@
} }
} }
}, },
"sortablejs": {
"version": "1.13.0",
"resolved": "http://npmprivate.quantgroups.com/sortablejs/-/sortablejs-1.13.0.tgz",
"integrity": "sha512-RBJirPY0spWCrU5yCmWM1eFs/XgX2J5c6b275/YyxFRgnzPhKl/TDeU2hNR8Dt7ITq66NRPM4UlOt+e5O4CFHg=="
},
"source-list-map": { "source-list-map": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "http://npmprivate.quantgroups.com/source-list-map/-/source-list-map-2.0.1.tgz", "resolved": "http://npmprivate.quantgroups.com/source-list-map/-/source-list-map-2.0.1.tgz",
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"scripts": { "scripts": {
"analyze": "cross-env ANALYZE=1 umi build", "analyze": "cross-env ANALYZE=1 umi build",
"build": "umi build", "build": "umi build",
"build:pre": "cross-env PRE_ENV=pre umi build",
"deploy": "npm run site && npm run gh-pages", "deploy": "npm run site && npm run gh-pages",
"fetch:blocks": "pro fetch-blocks && npm run prettier", "fetch:blocks": "pro fetch-blocks && npm run prettier",
"format-imports": "cross-env import-sort --write '**/*.{js,jsx,ts,tsx}'", "format-imports": "cross-env import-sort --write '**/*.{js,jsx,ts,tsx}'",
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
"@ant-design/pro-table": "^1.0.31", "@ant-design/pro-table": "^1.0.31",
"@antv/data-set": "^0.10.2", "@antv/data-set": "^0.10.2",
"antd": "^3.23.6", "antd": "^3.23.6",
"antd-virtual-select": "^1.1.2",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"date-fns": "^2.16.1", "date-fns": "^2.16.1",
"dva": "^2.4.1", "dva": "^2.4.1",
...@@ -65,8 +67,10 @@ ...@@ -65,8 +67,10 @@
"react-copy-to-clipboard": "^5.0.1", "react-copy-to-clipboard": "^5.0.1",
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-helmet": "^5.2.1", "react-helmet": "^5.2.1",
"react-sortablejs": "^6.0.0",
"redux": "^4.0.1", "redux": "^4.0.1",
"slash2": "^2.0.0", "slash2": "^2.0.0",
"sortablejs": "^1.13.0",
"umi": "^2.13.0", "umi": "^2.13.0",
"umi-plugin-pro-block": "^1.3.4", "umi-plugin-pro-block": "^1.3.4",
"umi-plugin-react": "^1.10.1", "umi-plugin-react": "^1.10.1",
......
import { Modal, Table, Button, Pagination, Tabs } from 'antd';
import React, { useState, useEffect } from 'react';
import styles from '../style.less';
import { changeLog, productMerchantLog } from '../service';
const LogModal = props => {
const [tabActiveKey, setTabActiveKey] = useState('0');
const [tableData, setTableData] = useState([]);
const [pageNo, setPageNo] = useState(1);
const [pageSize] = useState(20);
const [merchantList, setMerchantList] = useState([]);
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 columnsMerchant = [
{
title: '时间',
dataIndex: 'createdAt',
align: 'center',
},
{
title: '审核结果',
align: 'center',
dataIndex: 'operation',
render: value => ([5, 6, 7].includes(value) ? '审核通过' : '驳回'),
},
{
title: '驳回原因',
dataIndex: 'rejectReason',
align: 'center',
},
{
title: '操作账号',
dataIndex: 'createdBy',
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);
};
const getProductMerchantLog = async () => {
const { data = [] } = await productMerchantLog(props.spuId);
setMerchantList(data); // merchantList
};
const bundleOnTabChange = key => {
if (key === '1') {
getProductMerchantLog();
} else {
onPageChange(1);
}
setTabActiveKey(key);
};
const bundleOnCancel = () => {
setMerchantList([]);
setTabActiveKey('0');
props.onCancel();
};
useEffect(() => {
if (!props.id) return;
handleSearch();
}, [props.id]);
const { visible } = props;
return (
<Modal title="日志详情" visible={visible} footer={null} onCancel={bundleOnCancel} width="800px">
<Tabs type="card" onChange={bundleOnTabChange} activeKey={tabActiveKey}>
<Tabs.TabPane tab="商品详情" key="0">
<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}
/>
)}
</Tabs.TabPane>
<Tabs.TabPane tab="审核详情" key="1">
<Table
dataSource={merchantList}
bordered
columns={columnsMerchant}
rowKey={record => record.id}
pagination={false}
scroll={{ y: 300 }}
/>
</Tabs.TabPane>
</Tabs>
<Button type="primary" onClick={bundleOnCancel} className={styles.logBtn}>
关闭
</Button>
</Modal>
);
};
export default LogModal;
import { Button, Form, Input, Select, notification, Upload, Cascader, InputNumber } from 'antd';
import React, { Component } from 'react';
import { connect } from 'dva';
import styles from '../style.less';
import { stateList } from '../staticdata';
// import { uploadFile } from '../service';
const FormItem = Form.Item;
const { Option } = Select;
@connect(({ goodsManage }) => ({
goodsManage,
}))
class goodsManage extends Component {
componentDidMount() {
this.props.onRef(this);
this.handleSearch();
}
getFieldsValue() {
const { form } = this.props;
return form.getFieldsValue();
}
handleSearch = () => {
this.props.handleSearch(1);
};
onReset = () => {
this.props.form.resetFields();
this.props.onReset();
};
addSpu = () => {
this.props.addSpu();
};
render() {
const {
form: { getFieldDecorator, getFieldValue },
treeData,
} = this.props;
const selectW = { width: 250 };
const iptNumWidth = { width: 118 };
const that = this;
// const uploadProps = {
// name: 'file',
// async customRequest(info) {
// const result = await uploadFile(info.file);
// if (result && result.businessCode === '0000') {
// that.handleSearch();
// notification.success({
// message: '操作成功',
// });
// } else {
// notification.warning({
// message: result.msg,
// description: (
// <div>
// {result.data?.length &&
// result.data.map(item => <p>{item.skuNo + item.errSkuMessage}</p>)}
// </div>
// ),
// duration: 6,
// });
// }
// },
// accept: '.xlsx',
// showUploadList: false,
// };
const filterOption = (input, op) => op.props.children.includes(input);
return (
<Form name="horizontal_login" layout="inline" className={styles.searchForm}>
<FormItem label="SKU编码">
{getFieldDecorator('skuId', {})(
<Input placeholder="请输入SKU编码" allowClear style={selectW} />,
)}
</FormItem>
<FormItem label="商品名称">
{getFieldDecorator('skuName', {})(
<Input placeholder="请输入商品名称" allowClear style={selectW} />,
)}
</FormItem>
<FormItem label="类目">
{getFieldDecorator('productCategoryId', {})(
<Cascader
placeholder="请选择类目"
style={selectW}
showSearch
changeOnSelect
fieldNames={{ label: 'name', value: 'id', children: 'children' }}
options={treeData}
/>,
)}
</FormItem>
<FormItem label="审核状态">
{getFieldDecorator('state', {})(
<Select
style={selectW}
placeholder="请选择审核状态"
allowClear
filterOption={filterOption}
>
{stateList?.map(item => (
<Option key={item.value} value={item.value}>
{item.label}
</Option>
))}
</Select>,
)}
</FormItem>
<FormItem label="供货价区间">
<FormItem className={styles.iptNumRight}>
{getFieldDecorator('supplyPriceMin', {})(
<InputNumber placeholder="请输入" style={iptNumWidth} />,
)}
</FormItem>
<span>--</span>
<FormItem className={styles.iptNumRight}>
{getFieldDecorator('supplyPriceMax', {})(
<InputNumber
style={iptNumWidth}
placeholder="请输入"
min={getFieldValue('supplyPriceMin')}
/>,
)}
</FormItem>
</FormItem>
<FormItem label="第三方SKU编码">
{getFieldDecorator('thirdSkuNo', {})(
<Input placeholder="请输入第三方SKU编码" allowClear style={selectW} />,
)}
</FormItem>
<FormItem className={styles.queryBtn}>
<Button onClick={() => this.handleSearch()} type="primary" className={styles.button}>
查询
</Button>
<Button onClick={() => this.onReset()} type="primary" className={styles.button}>
重置
</Button>
</FormItem>
<FormItem style={{ float: 'right' }}>
<Button type="primary" className={styles.button} onClick={this.addSpu}>
新增商品
</Button>
{/* <Button
className={styles.button}
type="primary"
icon="download"
ghost
onClick={() => {
window.location.href = 'https://kdspstatic.q-gp.com/批量修改库存模板.xlsx';
}}
>
模版
</Button>
<Upload {...uploadProps}>
<Button type="primary" className={styles.button}>
批量库存修改
</Button>
</Upload> */}
</FormItem>
</Form>
);
}
}
export default Form.create()(goodsManage);
import { Modal, InputNumber, notification, Form, Input, Radio } from 'antd';
import React from 'react';
import { updateStock } from '../service';
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="请输入库存" style={{ width: 200 }} />)}
</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);
/* 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;
// if (!isEdit) item.productStock = data.productStock; // 编辑状态不可修改库存
item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
item.productStockWarning = data.productStockWarning;
});
}
if (data.firstSpecValue && !data.secondSpecValue) {
editData.forEach(item => {
if (item.firstSpecValue === data.firstSpecValue) {
item.marketPrice = data.marketPrice;
item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
item.productStockWarning = data.productStockWarning;
}
});
}
if (!data.firstSpecValue && data.secondSpecValue) {
editData.forEach(item => {
if (item.secondSpecValue === data.secondSpecValue) {
item.marketPrice = data.marketPrice;
item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
item.productStockWarning = data.productStockWarning;
}
});
}
if (data.firstSpecValue && data.secondSpecValue) {
editData.forEach(item => {
if (
item.firstSpecValue === data.firstSpecValue &&
item.secondSpecValue === data.secondSpecValue
) {
item.marketPrice = data.marketPrice;
item.productStock = data.productStock;
item.supplyPrice = data.supplyPrice;
item.weight = data.weight;
item.productStockWarning = data.productStockWarning;
}
});
}
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: 130 }}
/>,
)}
</FormItem>
)}
<FormItem>
{getFieldDecorator('productStock', {})(
<InputNumber
precision={0}
step={1}
// eslint-disable-next-line radix
formatter={val => parseInt(val, '10') || ''}
placeholder="库存"
style={{ width: 100 }}
/>,
)}
</FormItem>
{productType === 1 && (
<FormItem>
{getFieldDecorator('productStockWarning', {})(
<InputNumber
placeholder="库存预警"
maxLength={5}
min={0}
precision={0}
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 { Card, Form, Pagination, Table, notification, Drawer, Spin } from 'antd';
import React, { Component } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { connect } from 'dva';
import { sortBy } from 'lodash';
import styles from './style.less';
import LocalStroage from '@/utils/localStorage';
import configApi from '../../../config/env.config';
import UpdateStock from './UpdateStock';
import { spuDetail, categoryList, getVirtualCategory } from './service';
import LogModal from './LogModal';
import CreateModal from './createModal';
import { column, JDSHOPID } from './staticdata';
import SearchForm from './SearchForm';
@connect(({ goodsManage }) => ({
goodsManage,
}))
class goodsManage extends Component {
state = {
pageNo: 1,
loading: false,
treeData: [],
virtualTreeData: [],
pageSize: 20,
priceInfo: {},
logVisible: false,
previewVisible: false,
createVisible: false, // 新增or编辑普通商品modal
selectedRowKeys: [],
updateStockVisible: false,
initData: {},
createloading: false,
};
currentLog = null;
supplierId = null;
shopList = [];
componentDidMount() {
this.props.goodsManage.tableData = {};
this.categoryList();
this.getVirtualCategory();
}
handleSearch = page => {
const currentPage = this.state.pageNo;
this.setState(
{
pageNo: page || currentPage,
loading: true,
},
() => {
const { dispatch } = this.props;
const { pageSize, pageNo } = this.state;
dispatch({
type: 'goodsManage/getList',
payload: {
pageNo,
pageSize,
...this.searchForm.getFieldsValue(),
},
}).finally(() => {
this.setState({
loading: false,
});
});
},
);
};
onPageChange = page => {
this.handleSearch(page);
};
onPageSizeChange = (current, size) => {
this.setState(
{
pageSize: size,
},
() => this.handleSearch(),
);
};
onSelectChange = selectedRowKeys => {
this.setState({ selectedRowKeys });
};
onReset = () => {
this.setState({
pageNo: 1,
pageSize: 20,
selectedRowKeys: [],
});
this.handleSearch();
};
onUpdateInfo = async ({ spuId, productType }) => {
this.setState({
createloading: true,
});
const { data, msg } = await spuDetail({ id: spuId });
if (data) {
data.pageProductType = productType;
data.categoryId = data.thirdCategoryId;
data.firstSpecId = data.skuList[0].firstSpecId;
data.secondSpecId = data.skuList[0].secondSpecId;
data.firstSpecName = data.skuList[0].firstSpec;
data.secondSpecName = data.skuList[0].secondSpec;
data.firstSpecList = [];
data.secondSpecList = [];
data.colorKeys = [];
data.carouseList.forEach(i => {
if (i.specValue) {
data.colorKeys.push(i.specValue);
}
});
data.skuList.forEach(i => {
if (data.firstSpecList.indexOf(i.firstSpecValue) === -1) {
data.firstSpecList.push(`${i.firstSpecValue}`);
}
if (i.secondSpecValue && data.secondSpecList.indexOf(i.secondSpecValue) === -1) {
data.secondSpecList.push(i.secondSpecValue);
}
});
data.imageList = [];
data.carouseList.forEach(i => {
data.imageList[`${i.specValue}`] = i.skuSpecImageList || [];
});
data.editData = sortBy(data.skuList, item => item.firstSpecValue);
this.setState({
initData: data,
createVisible: true,
createloading: false,
});
} else {
this.setState({
createloading: false,
});
notification.warning({
message: msg,
});
}
};
onLoad = error => {
if (!error) {
notification.success({ message: '操作成功' });
this.setState({
selectedRowKeys: [],
});
this.handleSearch();
}
};
viewLog = async rows => {
this.currentLog = rows;
this.setState({
logVisible: true,
});
};
audit = skuId => {
this.setState({
previewVisible: true,
src: `${configApi.prologueDomain}/goods/${skuId}?h=0&token=${LocalStroage.get(
'token',
)}&hideReport=1&time=${Date.now()}`,
});
};
filterShopList = (list = [], isEdit) =>
list.filter(item => isEdit || !JDSHOPID.includes(item.id));
openModal = (
{
skuId,
supplyPrice,
marketPrice,
salePrice,
marketableStock,
supplierId,
stock,
productStock,
},
isStock,
) => {
let visible = {};
if (isStock) {
visible = { updateStockVisible: true };
}
this.setState({
...visible,
priceInfo: {
id: skuId,
stock,
productStock,
marketableStock,
supplyPrice,
marketPrice,
salePrice,
supplierId,
},
});
};
cancel = query => {
this.setState({ updateStockVisible: false });
if (query) {
this.handleSearch();
}
};
categoryList = async () => {
try {
const { data: treeData } = await categoryList();
if (!treeData) return;
this.setState({ treeData });
} catch (e) {
console.log(e);
}
};
getVirtualCategory = async () => {
try {
const { data: virtualTreeData } = await getVirtualCategory();
if (!virtualTreeData) return;
this.setState({ virtualTreeData });
} catch (e) {
console.log(e);
}
};
render() {
const {
goodsManage: { tableData = {} },
} = this.props;
const { pageNo, pageSize, selectedRowKeys } = this.state;
return (
<PageHeaderWrapper>
<Spin spinning={this.state.createloading}>
<Card>
<SearchForm
handleSearch={this.handleSearch}
onReset={this.onReset}
onLoad={this.onLoad}
// selectedRowKeys={this.state.selectedRowKeys}
onRef={ref => {
this.searchForm = ref;
}}
treeData={this.state.treeData}
shopList={this.shopList}
addSpu={() => this.setState({ createVisible: true, initData: {} })}
/>
</Card>
<Spin spinning={this.state.loading}>
<Table
dataSource={tableData?.records}
bordered
columns={column.call(this)}
rowKey={record => record.skuId}
pagination={false}
className={styles.tabletop}
scroll={{ x: '100%', y: 500 }}
/>
</Spin>
<br />
{tableData && (
<Pagination
style={{ marginBottom: 10 }}
onChange={this.onPageChange}
total={tableData.total}
showTotal={total => `共${total}条`}
current={pageNo}
pageSize={pageSize}
showSizeChanger
onShowSizeChange={this.onPageSizeChange}
/>
)}
<LogModal
visible={this.state.logVisible}
spuId={this.currentLog?.spuId}
id={this.currentLog?.skuId}
onCancel={() => {
this.currentLog = null;
this.setState({ logVisible: false });
}}
/>
<Drawer
visible={this.state.previewVisible}
width="450"
onClose={() => {
this.setState({ previewVisible: false });
}}
title="商品预览"
bodyStyle={{ height: '90%' }}
>
<iframe
src={this.state.src}
frameBorder="0"
height="100%"
width="375"
title="商品预览"
></iframe>
</Drawer>
<CreateModal
initData={this.state.initData}
visible={this.state.createVisible}
onCancel={() => {
this.setState({ createVisible: false, initData: {} });
}}
query={() => this.handleSearch()}
shopList={this.filterShopList(this.shopList, Object.keys(this.state.initData).length)}
treeData={this.state.treeData}
virtualTreeData={this.state.virtualTreeData}
></CreateModal>
<UpdateStock
visible={this.state.updateStockVisible}
info={this.state.priceInfo}
onCancel={this.cancel}
/>
</Spin>
</PageHeaderWrapper>
);
}
}
export default Form.create()(goodsManage);
import * as api from './service';
const Model = {
namespace: 'goodsManage',
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,
},
});
},
*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 fileSaver from 'file-saver';
import request from '@/utils/request';
import config from '../../../config/env.config';
import { stringify } from 'qs';
import _ from 'lodash';
const { goodsApi } = config;
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
};
export async function searchList(params) {
return request.post('/product/api/merchant/page', {
prefix: goodsApi,
data: stringify(params),
headers,
role: true,
});
}
// 新增商品
export async function addGoods(params) {
return request.post('/product/api/merchant/add', {
prefix: goodsApi,
data: params,
});
}
// 编辑商品
export async function editGoods(params) {
return request.post('/product/api/merchant/edit', {
prefix: goodsApi,
data: params,
});
}
// 获取商品品牌
export async function getBrandList() {
return request.post('/product/brand/api/merchant/list', {
prefix: goodsApi,
});
}
// 编辑--获取详情
export async function spuDetail(params) {
return request.post('/product/api/merchant/detail', {
prefix: goodsApi,
params,
headers,
});
}
// 商品规格
export async function getSpecList() {
return request.post('/product/spec/api/merchant/list', {
prefix: goodsApi,
});
}
// 查询图片素材
export async function getImageInfo(spuNo) {
return request.post('/product/api/merchant/imageInfo', {
params: { spuNo },
prefix: goodsApi,
headers,
});
}
// 商品分类
export async function categoryList() {
return request.post('/product/category/api/merchant/getAll', {
prefix: goodsApi,
});
}
// 批量修改
export async function uploadFile(file) {
const params = new FormData();
params.append('file', file);
const data = await request.post('/product/api/merchant/BatchUpdateStock', {
prefix: goodsApi,
data: params,
notTip: true,
});
return data;
}
// 商品修改日志
export async function changeLog(params) {
return request.post('/product/logs/api/merchant/page', {
data: stringify(params),
prefix: goodsApi,
headers,
});
}
// 审核详情日志
export async function productMerchantLog(productId) {
return request.get('/product/api/merchant/auditLog', {
params: {
productId,
},
prefix: goodsApi,
});
}
// 拉去京东图片
export async function getJdPicList(params) {
const { data } = await request.post('/product/api/merchant/item/getJdPicList', {
data: stringify(params),
prefix: goodsApi,
headers,
});
return data;
}
// 图片上传
export async function uploadImg(files) {
const params = new FormData();
files.forEach(file => params.append('file', file));
const data = await request.post('/image/api/merchant/upload', {
prefix: goodsApi,
data: params,
});
return data;
}
// 修改商品库存
export async function updateStock(params) {
const data = await request.post('/product/item/api/merchant/updateStock', {
prefix: goodsApi,
data: stringify(params),
headers,
});
if (data.businessCode === '0000') {
return null;
}
return data.msg;
}
// 获取虚拟商品类目
export async function getVirtualCategory() {
const data = await request.post('/product/category/api/merchant/getByParentId', {
prefix: goodsApi,
data: stringify({ id: 100018 }),
headers,
});
return data;
}
import React from 'react';
import { Button, 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}>
<p>供货价:{(row.supplyPrice || 0).toFixed(2)}</p>
<p>市场价:{(row.marketPrice || 0).toFixed(2)}</p>
</div>
),
},
{
title: '库存',
width: 120,
dataIndex: 'stock',
align: 'center',
sorter: (a, b) => a.stock - b.stock,
render: (_, row) => {
// const stockView =
// row.state !== 4 ? (
// <a onClick={() => this.openModal(row, 'productStock')}>{row.productStock}</a>
// ) : (
// <span>{row.productStock}</span>
// );
const stockView = row.productStock;
return (
<>
<p>当前库存:{stockView}</p>
<p>可售库存:{_}</p>
{row.type === 1 && row.productStockWarning > 0 && (
<p>预警值:{row.productStockWarning}</p>
)}
</>
);
},
},
{
title: '审核状态',
dataIndex: 'stateDesc',
width: 200,
align: 'center',
render: (_, row) => <span>{row.state >= 5 ? '审核通过' : _}</span>,
},
{
title: '操作',
dataIndex: 'action',
width: 120,
align: 'center',
render: (_, row) => (
<div className={styles.actionBtn}>
{row.state === 4 && (
<Button
key="edit"
type="primary"
size="small"
className={styles.button}
onClick={() => this.onUpdateInfo(row)}
>
修改
</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)}
>
查看日志
</Button>
</div>
),
},
];
}
export const disSelectStatus = [2, 5];
export const stateList = [
{ value: 3, label: '待审核' },
{ value: 4, label: '驳回' },
{ value: 5, label: '审核通过' },
];
// AUDITING(3, "待审核"),REJECTED(4, "驳回"),WAIT_SELL(5, "未上架"),ON_SELL(6, "已上架"),OFF_SHELVES(7, "已下架"))
export const productTypeList = [
{ value: 1, label: '实体商品' },
{ value: 2, label: '虚拟充值' },
{ value: 3, label: '虚拟卡券', disabled: true },
];
export const JDSHOPID = [3, 5, 6];
.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 { Upload, Icon, Modal, notification } from 'antd';
import React from 'react';
import { ReactSortable } from 'react-sortablejs';
import lodash from 'lodash';
import { uploadImg } from '../../GoodsManage/service';
import styles from './styles.less';
const DETAIL_IMG_MAX_WIDTH = 750;
const LOOP_IMG_WIDTH_HEIGHT = 1200;
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;
};
const warningTip = description => {
notification.warning({
// duration: null,
message: '图片上传失败',
description,
});
};
const getBase64 = (img, callback) => {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
};
const ImageInfo = file =>
new Promise((resolve, reject) => {
const LtMB = file.size / 1024 / 1024;
if (LtMB > 2) {
warningTip(`[${file.name}] 图片不可以大于2MB`);
resolve(null);
}
getBase64(file, url => {
const image = new Image();
image.addEventListener('load', () => {
const { width } = image;
const { height } = image;
file.width = width;
file.height = height;
file.LtMB = LtMB;
console.log(file);
resolve(file);
});
image.addEventListener('error', () => {
warningTip(`${file.name}图片上传失败!`);
resolve(null);
});
image.src = url;
});
});
const CheckImageInfoList = async files => {
const promiseImage = files.map(file => ImageInfo(file));
const clearImage = await Promise.all(promiseImage);
return cleanArray(clearImage);
};
const isUploadNext = async (imgFileList, id) => {
const filterImage = imgFileList.filter(({ width, height, name }) => {
if (id === 'detailImageList') {
if (width > DETAIL_IMG_MAX_WIDTH) {
warningTip(`[${name}] 详情图宽度不可大于${DETAIL_IMG_MAX_WIDTH}`);
return false;
}
return true;
}
if (width > LOOP_IMG_WIDTH_HEIGHT || height > LOOP_IMG_WIDTH_HEIGHT) {
warningTip(`[${name}] 滑动图尺寸不可大于 ${LOOP_IMG_WIDTH_HEIGHT}*${LOOP_IMG_WIDTH_HEIGHT}`);
return false;
}
return true;
});
return filterImage;
};
class PicturesWall extends React.Component {
state = {
previewVisible: false,
previewImage: '',
fileList: [],
newFile: [],
activeImgIndex: null,
};
async componentDidMount() {
this.initFileList(this.props.fileList || []);
}
componentWillReceiveProps(nextProps) {
this.initFileList(nextProps.fileList || []);
}
initFileList = fileList => {
const fileLists =
fileList.map((item, index) => ({
url: item,
name: index,
uid: index,
status: 'done',
})) || [];
this.setState({ fileList: fileLists });
};
handleCancel = () => this.setState({ previewVisible: false });
handlePreview = async img => {
this.setState({
previewImage: img.url,
previewVisible: true,
});
};
clearFileList = () => {
this.setState({
fileList: [],
});
};
sortChange = list => {
this.setState({ fileList: list });
const urlList = list.map(item => item.url);
this.props.onChange(urlList);
};
onRemoveImg = file => {
this.setState(
state => {
const index = state.fileList.indexOf(file);
const newFileList = state.fileList.slice();
newFileList.splice(index, 1);
return {
fileList: newFileList,
};
},
() => {
const urlList = this.state.fileList.map(item => item.url);
this.props.onChange(urlList);
},
);
};
render() {
// TODO 图片限制大小
const { previewVisible, previewImage, fileList } = this.state;
const uploadButton = (
<div>
<Icon type="plus" />
<div className="ant-upload-text">上传图片</div>
</div>
);
const { max } = this.props;
const that = this;
const uploadProps = {
beforeUpload: lodash.debounce(async (file, files) => {
const optionsArray = await CheckImageInfoList(files);
const onRightImgList = await isUploadNext(optionsArray, that.props.id);
if (!onRightImgList.length) {
return;
}
console.log('校验通过的队列=======>', onRightImgList);
this.setState(
state => ({
newFile: [...state.newFile, ...onRightImgList],
}),
async () => {
const data = await uploadImg(that.state.newFile);
this.setState({ newFile: [] });
if (!data || !data.data) return;
const { length } = this.state.fileList;
const list = data.data.map((img, index) => ({
url: img,
uid: index + length,
name: index + length,
status: 'done',
}));
this.setState(
state => ({ fileList: [...state.fileList, ...list] }),
() => {
const urlList = this.state.fileList.map(item => item.url);
this.props.onChange(urlList);
},
);
},
);
// eslint-disable-next-line consistent-return
return false;
}, 500),
listType: 'picture-card',
};
return (
<div className="clearfix">
<div className={styles.imgContent}>
{fileList.length > 0 && (
<ReactSortable list={fileList} setList={list => this.sortChange(list)}>
{fileList.map((item, index) => (
<div
// eslint-disable-next-line react/no-array-index-key
key={index}
className={styles.sortImg}
onMouseEnter={() => this.setState({ activeImgIndex: index })}
onMouseLeave={() => this.setState({ activeImgIndex: null })}
>
<div style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
<img width="100%" key={item.uid} src={item.url} alt="" />
</div>
{this.state.activeImgIndex === index && (
<div className={styles.mask}>
<Icon
type="eye"
className={styles.maskIcon}
onClick={() => this.handlePreview(item)}
/>
<Icon
type="delete"
className={styles.maskIcon}
onClick={() => this.onRemoveImg(item)}
/>
</div>
)}
</div>
))}
</ReactSortable>
)}
</div>
<Upload multiple {...uploadProps} fileList={fileList} showUploadList={false}>
{max && fileList.length >= max ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
);
}
}
export default PicturesWall;
.sortImg {
position: relative;
display: inline-block;
width: 105px;
height: 105px;
margin-right: 10px;
margin-bottom: 10px;
padding: 9px;
border: 1px solid #ddd;
border-radius: 6px;
}
.mask {
position: absolute;
top: 9px;
right: 9px;
bottom: 9px;
left: 9px;
padding-top: 27%;
text-align: center;
// width: 100%;
// height: 100%;
background: #000;
opacity: 0.5;
}
.maskIcon {
margin-right: 5px;
color: #efefef;
font-size: 16px;
cursor: pointer;
}
...@@ -60,16 +60,16 @@ ...@@ -60,16 +60,16 @@
width: 78%; width: 78%;
} }
.logistics { .logistics {
width: 100%; display: flex;
display: flex; align-items: center;
justify-content: center; justify-content: center;
height: 30px; width: 100%;
align-items: center; height: 30px;
margin-top: 24px; margin-top: 24px;
} }
.logisticsIcon { .logisticsIcon {
font-size: 25px; font-size: 25px;
&:first-child { &:first-child {
margin-right: 10px; margin-right: 10px;
} }
} }
import * as api from './service'; import * as api from './service';
const tableDate = [{ const tableDate = [{}];
}];
const Model = { const Model = {
namespace: 'pendingDeliveryOrder', namespace: 'pendingDeliveryOrder',
...@@ -13,12 +11,12 @@ const Model = { ...@@ -13,12 +11,12 @@ const Model = {
}, },
effects: { effects: {
*getSubjectList({ payload }, { call, put }) { *getSubjectList({ payload }, { call, put }) {
yield put({ yield put({
type: 'saveData', type: 'saveData',
payload: { payload: {
tableData: tableDate, tableData: tableDate,
}, },
}); });
// const response = yield call(api.subjectList, payload); // const response = yield call(api.subjectList, payload);
// if (response.code === 2000) { // if (response.code === 2000) {
// yield put({ // yield put({
......
...@@ -102,6 +102,12 @@ request.interceptors.response.use(async (response, options) => { ...@@ -102,6 +102,12 @@ request.interceptors.response.use(async (response, options) => {
} }
const data = await response.clone().json(); const data = await response.clone().json();
if (data.code === 4033) { if (data.code === 4033) {
// TODO 该接口是否需要提示权限信息
if (options.role) {
notification.warning({
message: '没有权限访问!',
});
}
// token过期 // token过期
const url = response.url.split(config.api)[1]; const url = response.url.split(config.api)[1];
return refreshRequest(url, options); return refreshRequest(url, options);
...@@ -116,7 +122,7 @@ request.interceptors.response.use(async (response, options) => { ...@@ -116,7 +122,7 @@ request.interceptors.response.use(async (response, options) => {
}); });
window.location.href = loginPath; window.location.href = loginPath;
} }
if (data.businessCode && data.businessCode !== '0000') { if (data.businessCode && data.businessCode !== '0000' && !options.notTip) {
notification.warning({ notification.warning({
message: data.detail || data.msg || '操作失败', message: data.detail || data.msg || '操作失败',
}); });
......
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