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