Commit 02e874cc authored by 武广's avatar 武广

Merge branch 'feature-20240508-bidding' into 'master'

Feature 20240508 bidding

See merge request !109
parents 90f773af e8b38b09
...@@ -42,7 +42,8 @@ const ImportGoods = React.memo(props => { ...@@ -42,7 +42,8 @@ const ImportGoods = React.memo(props => {
if (result?.success) { if (result?.success) {
setImportFile([]); setImportFile([]);
notification.success({ notification.success({
message: '导入成功', message:
'已操作上传,稍后上传成功后,请在操作历史中,查看上传结果,如有未上传成功的数据,请根据返回原因,及时处理,修改后重新上传。',
}); });
} }
}; };
......
import { DeleteOutlined, EyeOutlined, PlusOutlined } from '@ant-design/icons'; import {
DeleteOutlined,
EyeOutlined,
PlusOutlined,
LoadingOutlined,
FileFilled,
} from '@ant-design/icons';
import { Modal, Upload, notification, Spin } from 'antd'; import { Modal, Upload, notification, Spin } from 'antd';
import React, { useState, useEffect, useRef, forwardRef } from 'react'; import React, { useState, useEffect, useRef, forwardRef } from 'react';
import lodash from 'lodash'; import lodash from 'lodash';
import { apiFileUpload } from './service.js';
import { ReactSortable } from 'react-sortablejs'; import { ReactSortable } from 'react-sortablejs';
import { merchantUpload } from './service.js';
import styles from './style.less'; import styles from './style.less';
import { checkIsImagePath } from '@/utils/utils';
const MAX_FILE_SIZE = 5; const MAX_FILE_SIZE = 5;
const UNIT = 1024 * 1024; const UNIT = 1024 * 1024;
...@@ -16,6 +23,27 @@ const UploadButton = ( ...@@ -16,6 +23,27 @@ const UploadButton = (
</div> </div>
); );
const renderFile = item => {
if (item.status === 'done') {
if (checkIsImagePath(item.url)) {
return <img width="100%" key={item.uid} src={item.url} alt="" />;
}
return (
<div className={styles.imgLoading}>
<a target="_blank" href={item.url} rel="noopener noreferrer">
<FileFilled />
</a>
</div>
);
}
return (
<div className={styles.imgLoading}>
<LoadingOutlined />
<div className={styles.imgLoadingText}>文件上传中</div>
</div>
);
};
const UploadImage = forwardRef((props, ref) => { const UploadImage = forwardRef((props, ref) => {
const { const {
name = `${Date.now()}`, name = `${Date.now()}`,
...@@ -26,6 +54,7 @@ const UploadImage = forwardRef((props, ref) => { ...@@ -26,6 +54,7 @@ const UploadImage = forwardRef((props, ref) => {
value, value,
width = 0, width = 0,
height = 0, height = 0,
canUploadFile = false, // 是否可以上传图片之外的文件
accept = ['jpg', 'jpeg', 'png'], accept = ['jpg', 'jpeg', 'png'],
} = props; } = props;
const [uploadLoading, setUploadLoading] = useState(false); const [uploadLoading, setUploadLoading] = useState(false);
...@@ -41,6 +70,7 @@ const UploadImage = forwardRef((props, ref) => { ...@@ -41,6 +70,7 @@ const UploadImage = forwardRef((props, ref) => {
url, url,
name: url, name: url,
uid: `${ind}`, uid: `${ind}`,
status: !url ? '' : 'done',
})); }));
fileListRef.current = [...newPictures]; fileListRef.current = [...newPictures];
setFileList([...newPictures]); setFileList([...newPictures]);
...@@ -49,9 +79,13 @@ const UploadImage = forwardRef((props, ref) => { ...@@ -49,9 +79,13 @@ const UploadImage = forwardRef((props, ref) => {
const handleCancel = () => setPreviewVisible(false); const handleCancel = () => setPreviewVisible(false);
const handlePreview = async file => { const handlePreview = async file => {
if (checkIsImagePath(file.url)) {
setPreviewImage(file.url); setPreviewImage(file.url);
setPreviewVisible(true); setPreviewVisible(true);
setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)); setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1));
} else if (file.url) {
window.open(file.url);
}
}; };
const bundleChange = imgFile => { const bundleChange = imgFile => {
...@@ -66,36 +100,28 @@ const UploadImage = forwardRef((props, ref) => { ...@@ -66,36 +100,28 @@ const UploadImage = forwardRef((props, ref) => {
const checkFile = file => const checkFile = file =>
new Promise(resolve => { new Promise(resolve => {
const curType = file.name.substr(file.name.lastIndexOf('.') + 1).toLowerCase(); const curType = file.name.substr(file.name.lastIndexOf('.') + 1).toLowerCase();
if (!accept.includes(curType)) { if (!canUploadFile && !accept.includes(curType)) {
notification.open({ notification.open({
message: file.name, message: file.name,
description: `图片格式须为${accept.join('')}!`, description: `文件格式须为${accept.join('')}!`,
}); });
return resolve(null); return resolve(null);
} }
if (file.size > MAX_FILE_SIZE * UNIT) { if (file.size > MAX_FILE_SIZE * UNIT) {
notification.open({ notification.open({
message: file.name, message: file.name,
description: `单个图片大小不能超过${MAX_FILE_SIZE}M!`, description: `单个文件大小不能超过${MAX_FILE_SIZE}M!`,
}); });
return resolve(null); return resolve(null);
} }
return resolve(file); return resolve(file);
}); });
const imageLoading = (file, ret) => const imageLoading = (file, ret) => ({
new Promise(resolve => { uid: file.uid,
const reader = new FileReader(); status: 'done',
// 监听图片转换完成 name: file.name,
reader.addEventListener( url: ret,
'load',
() => {
const temFile = { uid: file.uid, status: 'done', name: file.name, url: ret };
resolve(temFile);
},
false,
);
reader.readAsDataURL(file);
}); });
const getImageSize = async file => const getImageSize = async file =>
...@@ -153,23 +179,25 @@ const UploadImage = forwardRef((props, ref) => { ...@@ -153,23 +179,25 @@ const UploadImage = forwardRef((props, ref) => {
try { try {
if (checkFiles.length) { if (checkFiles.length) {
setUploadLoading(true); setUploadLoading(true);
const res = await merchantUpload(checkFiles); const res = await apiFileUpload(checkFiles);
if (res?.data) { console.log('res', res);
const proFiles = (res.data || []).map((urlItem, urlIndex) => if (res) {
imageLoading(checkFiles[urlIndex], urlItem), const proFiles = (res || []).map((urlItem, urlIndex) =>
imageLoading(checkFiles[urlIndex], urlItem.data),
); );
const imagList = await Promise.all(proFiles); // const imagList = await Promise.all(proFiles);
const newFiles = [...fileListRef.current, ...imagList]; const newFiles = [...fileListRef.current, ...proFiles];
bundleChange(newFiles); bundleChange(newFiles);
} else { } else {
notification.warning({ notification.warning({
message: '警告', message: '警告',
description: res?.msg || '上传失败,请重新尝试!', description: res.msg,
}); });
} }
setUploadLoading(false); setUploadLoading(false);
} }
} catch (error) { } catch (error) {
console.log('error', error);
setUploadLoading(false); setUploadLoading(false);
Modal.warning({ Modal.warning({
maskClosable: true, maskClosable: true,
...@@ -191,11 +219,9 @@ const UploadImage = forwardRef((props, ref) => { ...@@ -191,11 +219,9 @@ const UploadImage = forwardRef((props, ref) => {
onMouseEnter={() => setActiveImgIndex(index)} onMouseEnter={() => setActiveImgIndex(index)}
onMouseLeave={() => setActiveImgIndex(null)} onMouseLeave={() => setActiveImgIndex(null)}
> >
<div style={{ width: '100%', height: '100%', overflow: 'hidden' }}> <div className={styles.imgBox}>{renderFile(item)}</div>
<img width="100%" key={item.uid} src={item.url} alt="" />
</div>
{activeImgIndex === index && ( {activeImgIndex === index && (
<div className={styles.mask}> <div className={styles.mask} key={item.uid}>
<EyeOutlined className={styles.maskIcon} onClick={() => handlePreview(item)} /> <EyeOutlined className={styles.maskIcon} onClick={() => handlePreview(item)} />
<DeleteOutlined <DeleteOutlined
className={styles.maskIcon} className={styles.maskIcon}
......
import request from '@/utils/request'; import request from '@/utils/request';
import config from '@/../config/env.config'; import config from '@/../config/env.config';
import UUID from '@/utils/uuid';
const { goodsApi } = config; const { goodsApi } = config;
export const merchantUpload = async files => { // export const merchantUpload = async 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 const apiFileUpload = async files => {
const data = await Promise.all(
files.map(async file => {
const params = new FormData(); const params = new FormData();
files.forEach(file => params.append('file', file)); params.append('file', file);
const data = await request.post('/image/api/merchant/upload', { const uuid = UUID.createUUID();
if (file.name) {
const arr = file.name.split('.');
params.append('fileName', `${uuid}.${arr[arr.length - 1]}`);
}
const res = await request.post(`/api/merchants/images/uploadFile?id=${uuid}`, {
prefix: goodsApi, prefix: goodsApi,
data: params, data: params,
}); });
return res;
}),
);
console.log('data', data);
return data; return data;
}; };
...@@ -27,3 +27,9 @@ ...@@ -27,3 +27,9 @@
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
} }
.imgBox {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
...@@ -13,7 +13,7 @@ const BrandInfo = props => { ...@@ -13,7 +13,7 @@ const BrandInfo = props => {
const refForm = React.useRef(); const refForm = React.useRef();
const { actionStatus, brandId } = props; const { actionStatus, brandId } = props;
const closeModal = v => { const closeModal = v => {
refForm.current?.resetFields(); refForm?.current?.resetFields?.();
!v && props.onClose(false); !v && props.onClose(false);
}; };
const getAPI = () => { const getAPI = () => {
...@@ -62,7 +62,7 @@ const BrandInfo = props => { ...@@ -62,7 +62,7 @@ const BrandInfo = props => {
layoutType="ModalForm" layoutType="ModalForm"
title="品牌信息" title="品牌信息"
open={props.visible} open={props.visible}
width="600px" width="800px"
modalProps={{ modalProps={{
maskClosable: true, maskClosable: true,
destroyOnClose: true, destroyOnClose: true,
......
...@@ -142,7 +142,9 @@ export const brandInfoColumn = config => { ...@@ -142,7 +142,9 @@ export const brandInfoColumn = config => {
formItemProps: { formItemProps: {
rules: [{ required: true, message: '请选择资质证书' }], rules: [{ required: true, message: '请选择资质证书' }],
}, },
renderFormItem: () => <UploadImage limit={10} />, renderFormItem: () => (
<UploadImage limit={30} accept={['jpg', 'jpeg', 'png', 'zip', 'rar', 'pdf']} />
),
}, },
{ {
title: '授权证书', title: '授权证书',
...@@ -150,7 +152,9 @@ export const brandInfoColumn = config => { ...@@ -150,7 +152,9 @@ export const brandInfoColumn = config => {
formItemProps: { formItemProps: {
rules: [{ required: true, message: '请选择授权证书' }], rules: [{ required: true, message: '请选择授权证书' }],
}, },
renderFormItem: () => <UploadImage limit={5} />, renderFormItem: () => (
<UploadImage limit={30} accept={['jpg', 'jpeg', 'png', 'zip', 'rar', 'pdf']} />
),
}, },
{ {
title: '品牌名称', title: '品牌名称',
......
...@@ -12,6 +12,7 @@ const UpdatePriceStock = options => { ...@@ -12,6 +12,7 @@ const UpdatePriceStock = options => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [specArr, setSpecArr] = useState([]); // 规格列 const [specArr, setSpecArr] = useState([]); // 规格列
const [form] = Form.useForm(); const [form] = Form.useForm();
const [errorMsg, setErrorMsg] = useState([]); // 错误信息
const onSubmit = async () => { const onSubmit = async () => {
const value = await form.validateFields(); const value = await form.validateFields();
...@@ -21,10 +22,16 @@ const UpdatePriceStock = options => { ...@@ -21,10 +22,16 @@ const UpdatePriceStock = options => {
skus: value.data, skus: value.data,
}; };
setLoading(true); setLoading(true);
await apiProductBiddingUpdate(params); setErrorMsg([]);
const res = await apiProductBiddingUpdate(params);
setLoading(false); setLoading(false);
if (res?.success) {
options.refresh(); options.refresh();
options.onCancel(); options.onCancel();
} else {
const msg = res?.msg || '修改失败';
setErrorMsg(msg.split(';'));
}
}; };
const EditableContext = createContext(null); const EditableContext = createContext(null);
...@@ -69,7 +76,7 @@ const UpdatePriceStock = options => { ...@@ -69,7 +76,7 @@ const UpdatePriceStock = options => {
onCancel={options.onCancel} onCancel={options.onCancel}
onOk={onSubmit} onOk={onSubmit}
confirmLoading={loading} confirmLoading={loading}
width={800} width={900}
className={styles.priceStockTable} className={styles.priceStockTable}
destroyOnClose destroyOnClose
> >
...@@ -85,6 +92,13 @@ const UpdatePriceStock = options => { ...@@ -85,6 +92,13 @@ const UpdatePriceStock = options => {
/> />
</EditableContext.Provider> </EditableContext.Provider>
</Form> </Form>
{errorMsg && (
<div className={styles.errorMsg}>
{errorMsg.map(item => (
<div key={item}>{item}</div>
))}
</div>
)}
</Modal> </Modal>
); );
}; };
......
...@@ -225,7 +225,7 @@ class supplyPriceUpdate extends Component { ...@@ -225,7 +225,7 @@ class supplyPriceUpdate extends Component {
)} )}
<Drawer <Drawer
visible={this.state.previewVisible} open={this.state.previewVisible}
width="450" width="450"
onClose={() => { onClose={() => {
this.setState({ previewVisible: false }); this.setState({ previewVisible: false });
......
...@@ -5,6 +5,12 @@ import styles from './style.less'; ...@@ -5,6 +5,12 @@ import styles from './style.less';
export function column(specArr = []) { export function column(specArr = []) {
return [ return [
{
title: 'SKU编码',
dataIndex: 'id',
width: 200,
align: 'center',
},
...specArr, ...specArr,
{ {
title: '供货价', title: '供货价',
......
...@@ -22,3 +22,7 @@ ...@@ -22,3 +22,7 @@
.button { .button {
margin: 0 5px; margin: 0 5px;
} }
.errorMsg {
padding: 10px 25px;
color: red;
}
...@@ -409,6 +409,8 @@ export async function apiProductBiddingUpdate(params) { ...@@ -409,6 +409,8 @@ export async function apiProductBiddingUpdate(params) {
return request.post('/api/merchants/products/bidding/edit', { return request.post('/api/merchants/products/bidding/edit', {
prefix: goodsApi, prefix: goodsApi,
data: params, data: params,
duration: null,
notTip: true,
}); });
} }
......
...@@ -139,6 +139,7 @@ request.interceptors.response.use(async (response, options) => { ...@@ -139,6 +139,7 @@ request.interceptors.response.use(async (response, options) => {
if (data.businessCode && data.businessCode !== '0000' && !options.notTip) { if (data.businessCode && data.businessCode !== '0000' && !options.notTip) {
notification.warning({ notification.warning({
message: data.detail || data.msg || '操作失败', message: data.detail || data.msg || '操作失败',
duration: typeof options.duration === 'undefined' ? 4.5 : options.duration,
}); });
} }
return response; return response;
......
...@@ -223,3 +223,6 @@ export const getToUrlQuery = () => { ...@@ -223,3 +223,6 @@ export const getToUrlQuery = () => {
} }
return {}; return {};
}; };
// 判断是否图片类型
export const checkIsImagePath = name => /\.(gif|jpg|jpeg|png)$/i.test(name.toLocaleLowerCase());
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