feat: ✨️ 新增图片上传类型校验及错误提示
This commit is contained in:
parent
116c171249
commit
a2b5df22f8
12
.prettierignore
Normal file
12
.prettierignore
Normal file
@ -0,0 +1,12 @@
|
||||
/node_modules
|
||||
package*.json
|
||||
.gitignore
|
||||
*.local
|
||||
*_local
|
||||
__test__
|
||||
.ide
|
||||
.vscode
|
||||
.idea
|
||||
test
|
||||
dist
|
||||
public
|
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100
|
||||
}
|
@ -2,12 +2,14 @@ import React, {useState} from "react";
|
||||
import {Input, Popconfirm, Spin, Upload, UploadProps} from "antd";
|
||||
import {CloseOutlined} from "@ant-design/icons";
|
||||
import {clsx} from "clsx";
|
||||
import {useTranslation} from "react-i18next";
|
||||
|
||||
import styles from './article.module.scss'
|
||||
import {getOssPolicy} from "@/service/api/common.ts";
|
||||
import {showToast} from "@/components/message.ts";
|
||||
import {IconAddImage, IconWarningCircle} from "@/components/icons";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {IconAddImage} from "@/components/icons";
|
||||
import {ModalWarningIcon, ModalWarningTitle} from "@/components/icons/ModalWarning.tsx";
|
||||
import { BizError } from '@/service/types.ts';
|
||||
|
||||
type Props = {
|
||||
children?: React.ReactNode;
|
||||
@ -37,6 +39,10 @@ export function BlockImage({data, editable, onChange, onlyUpload, onRemove}: Ima
|
||||
});
|
||||
const beforeUpload = async (file: any) => {
|
||||
try {
|
||||
// 判断文件类型
|
||||
if (!MimeTypes.includes(file.type)) {
|
||||
throw new Error('upload_file_type_error')
|
||||
}
|
||||
// 因为有超时问题,所以每次上传都重新获取参数
|
||||
Data.uploadConfig = await getOssPolicy();
|
||||
const suffix = file.name.slice(file.name.lastIndexOf('.'));
|
||||
@ -52,17 +58,22 @@ export function BlockImage({data, editable, onChange, onlyUpload, onRemove}: Ima
|
||||
const onUploadChange = async (info) => {
|
||||
if (info.fileList.length == 0) return;
|
||||
const file = info.fileList[0];
|
||||
console.log('onChange', file);
|
||||
console.log('onUploadChange', file);
|
||||
if (file.status == 'done') {
|
||||
setLoading(-1)
|
||||
onChange?.({type: 'image', content: Data.uploadConfig?.host + '/' + file.url})
|
||||
setLoading(-1);
|
||||
onChange?.({ type: 'image', content: Data.uploadConfig?.host + '/' + file.url });
|
||||
} else if (file.status == 'error') {
|
||||
setLoading(-1)
|
||||
showToast(t('upload.upload_failed'), 'warning')
|
||||
|
||||
if (!MimeTypes.includes(file.type)) {
|
||||
showToast(t('upload.upload_file_type_error'), 'warning');
|
||||
return;
|
||||
}
|
||||
setLoading(-1);
|
||||
showToast(t('upload.upload_failed'), 'warning');
|
||||
} else if (file.status == 'uploading') {
|
||||
setLoading(file.percent)
|
||||
setLoading(file.percent);
|
||||
}
|
||||
}
|
||||
};
|
||||
//
|
||||
return <div className={styles.image}>
|
||||
{editable && onlyUpload ? <div className={'relative'}>
|
||||
@ -104,8 +115,9 @@ export function BlockImage({data, editable, onChange, onlyUpload, onRemove}: Ima
|
||||
rootClassName={'popconfirm-main'}
|
||||
placement={'right'}
|
||||
arrow={false}
|
||||
icon={<IconWarningCircle/>}
|
||||
title={<div style={{minWidth: 150}}><span>{t('upload.delete_confirm')}</span></div>}
|
||||
icon={<ModalWarningIcon/>}
|
||||
title={<ModalWarningTitle/>}
|
||||
description={<div style={{minWidth: 150}}><span>{t('upload.delete_confirm')}</span></div>}
|
||||
onConfirm={onRemove}
|
||||
okText={t('delete')}
|
||||
cancelText={t('cancel')}
|
||||
|
@ -185,6 +185,7 @@
|
||||
"upload": {
|
||||
"delete_confirm": "Are you sure delete the picture?",
|
||||
"upload_failed": "Upload failed",
|
||||
"upload_file_type_error": "Only support upload image",
|
||||
"upload_image": "Upload Image"
|
||||
},
|
||||
"user": {
|
||||
|
@ -185,6 +185,7 @@
|
||||
"upload": {
|
||||
"delete_confirm": "请确认删除此图片?",
|
||||
"upload_failed": "上传图片失败,请重试",
|
||||
"upload_file_type_error": "仅支持上传图片",
|
||||
"upload_image": "上传图片"
|
||||
},
|
||||
"user": {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Checkbox, Popconfirm, Space} from "antd";
|
||||
import {Checkbox, Space} from "antd";
|
||||
|
||||
import React, {useRef, useState} from "react";
|
||||
import {useRequest} from "ahooks";
|
||||
@ -10,13 +10,12 @@ import ButtonPush2Video, {ProcessResult} from "@/pages/news/components/button-pu
|
||||
|
||||
import styles from './components/style.module.scss'
|
||||
import InfiniteScroller, {InfiniteScrollerRef} from "@/components/scoller/infinite-scroller.tsx";
|
||||
import {IconDelete, IconEdit, IconWarningCircle} from "@/components/icons";
|
||||
import {IconDelete, IconEdit} from "@/components/icons";
|
||||
import {clsx} from "clsx";
|
||||
import ButtonToTop from "@/components/scoller/button-to-top.tsx";
|
||||
import ButtonDeleteBatch from "@/pages/news/components/button-delete-batch.tsx";
|
||||
import {showErrorToast, showToast} from "@/components/message.ts";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {ModalWarningTitle,ModalWarningIcon} from "@/components/icons/ModalWarning.tsx";
|
||||
import {DeleteItemPopoverConfirm} from "@/components/message/confirm.tsx";
|
||||
|
||||
const FilterCache: Partial<ApiArticleSearchParams> = {
|
||||
@ -125,12 +124,12 @@ export default function NewEdit() {
|
||||
...prev,
|
||||
pagination: {page, limit: 10}
|
||||
}))
|
||||
}} onScroll={(top) => setState({showToTop: top > 30})} loading={loading}
|
||||
}} onScroll={(top) => setState(s=>({...s,showToTop: top > 30}))} loading={loading}
|
||||
pagination={data?.pagination}>
|
||||
<div className="body">
|
||||
{data?.list?.map((item, i) => {
|
||||
const checked = selectedRowKeys.includes(item.id)
|
||||
return <div key={i} className={clsx("row flex", {checked})}>
|
||||
return <div key={item.id} className={clsx("row flex", {checked})}>
|
||||
<div className="col title cursor-pointer" onClick={() => setEditId(item.id)}>
|
||||
<div className="flex-1">
|
||||
<div className="text-base line-clamp-1">{item.title}</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, {useMemo, useRef, useState} from "react";
|
||||
import {Checkbox, Divider, Empty, Modal, Space} from "antd";
|
||||
import {useRequest} from "ahooks";
|
||||
import { useRequest, useSetState } from 'ahooks';
|
||||
import {CloseOutlined} from "@ant-design/icons"
|
||||
import {clsx} from "clsx";
|
||||
|
||||
@ -30,7 +30,7 @@ export default function NewsIndex() {
|
||||
|
||||
const [activeNews, setActiveNews] = useState<NewsInfo>()
|
||||
|
||||
const [state, setState] = useState<{
|
||||
const [state, setState] = useSetState<{
|
||||
checkAll?: boolean;
|
||||
showToTop?: boolean;
|
||||
}>({})
|
||||
@ -43,10 +43,10 @@ export default function NewsIndex() {
|
||||
FilterCache.tag_level_2_id = params.tag_level_2_id;
|
||||
FilterCache.title = params.title;
|
||||
FilterCache.time_flag = params.time_flag;
|
||||
setCheckedId([])
|
||||
if (params.pagination.page === 1) {
|
||||
setCheckedId([])
|
||||
setData(_data)
|
||||
setState({checkAll: checkedId && _data.list && checkedId.length === _data.list.length})
|
||||
setState({checkAll: false,showToTop: false})
|
||||
} else {
|
||||
setData({
|
||||
pagination: _data.pagination,
|
||||
|
Loading…
x
Reference in New Issue
Block a user