diff --git a/packages/xgen/components/edit/Upload/components/Audio.tsx b/packages/xgen/components/edit/Upload/components/Audio.tsx
new file mode 100644
index 0000000..f70c0fa
--- /dev/null
+++ b/packages/xgen/components/edit/Upload/components/Audio.tsx
@@ -0,0 +1,19 @@
+import { getFileSrc } from '@/knife'
+import { DeleteOutlined } from '@ant-design/icons'
+
+import type { IPropsCustomRender } from '../types'
+
+const Index = (props: IPropsCustomRender) => {
+ const { file, remove } = props
+
+ return (
+
+ )
+}
+
+export default window.$app.memo(Index)
diff --git a/packages/xgen/components/edit/Upload/components/UploadBtn.tsx b/packages/xgen/components/edit/Upload/components/UploadBtn.tsx
index a76622f..7df0fd4 100644
--- a/packages/xgen/components/edit/Upload/components/UploadBtn.tsx
+++ b/packages/xgen/components/edit/Upload/components/UploadBtn.tsx
@@ -1,27 +1,17 @@
import clsx from 'clsx'
-
-import { CloudUploadOutlined } from '@ant-design/icons'
-import { getLocale } from '@umijs/max'
-
-import filemap from '../filemap'
-
import type { IPropsUploadBtn } from '../types'
+import { Icon } from '@/widgets'
const Index = (props: IPropsUploadBtn) => {
- const { length, filetype, maxCount, desc } = props
- const locale = getLocale()
-
+ const { filetype, placeholder, placeholderIcon } = props
+ const iconProps = {
+ name: typeof placeholderIcon === 'string' ? placeholderIcon : placeholderIcon?.name || 'cloud-upload',
+ size: typeof placeholderIcon === 'string' ? 14 : placeholderIcon?.size || 14
+ }
return (
-
-
-
{desc ?? filemap[filetype].desc[locale]}
+
+
+ {placeholder}
)
}
diff --git a/packages/xgen/components/edit/Upload/filemap.tsx b/packages/xgen/components/edit/Upload/filemap.tsx
index 53d9279..11185f9 100644
--- a/packages/xgen/components/edit/Upload/filemap.tsx
+++ b/packages/xgen/components/edit/Upload/filemap.tsx
@@ -1,31 +1,82 @@
import Video from './components/Video'
+import Audio from './components/Audio'
+import Image from './components/Image'
-import type { FileType } from './types'
+import type { FileType, PreviewProps } from './types'
+import { UploadFile } from 'antd'
export default {
image: {
listType: 'picture-card',
className: 'image',
- desc: {
+ placeholder: {
'zh-CN': '上传图片',
'en-US': 'Upload Image'
+ },
+ placeholderIcon: 'icon-upload',
+ preview: (props: PreviewProps, file: UploadFile
, remove: () => void) => {
+ return
+ }
+ },
+
+ audio: {
+ listType: 'picture-card',
+ className: 'image',
+ placeholder: {
+ 'zh-CN': '上传音频',
+ 'en-US': 'Upload Audio'
+ },
+ placeholderIcon: 'icon-upload',
+ preview: (props: PreviewProps, file: UploadFile, remove: () => void) => {
+ return Image
}
},
+
file: {
- listType: 'text',
- className: 'file',
- desc: {
+ listType: 'picture-card',
+ className: 'image',
+ placeholder: {
'zh-CN': '上传文件',
'en-US': 'Upload File'
+ },
+ placeholderIcon: 'icon-upload',
+ preview: (props: PreviewProps, file: UploadFile, remove: () => void) => {
+ return File
}
},
+
video: {
listType: 'picture-card',
- className: 'video',
- desc: {
+ className: 'image',
+ placeholder: {
'zh-CN': '上传视频',
'en-US': 'Upload Video'
},
- render: (_, file, fileList, { remove }) =>
+ placeholderIcon: 'icon-upload',
+ preview: (props: PreviewProps, file: UploadFile, remove: () => void) => {
+ return Video
+ }
}
} as FileType
+
+function getSize(size: PreviewProps['size']): PreviewProps['size'] {
+ const defaultSize: PreviewProps['size'] = {
+ width: size?.width || '90px',
+ height: size?.height || '90px',
+ ratio: size?.ratio || 1
+ }
+
+ if (defaultSize.ratio && defaultSize.ratio != 1) {
+ const width = parseInt(defaultSize.width as string)
+ const height = parseInt(defaultSize.height as string)
+ if (!width && !height) {
+ defaultSize.width = '100%'
+ defaultSize.height = `${100 * defaultSize.ratio}%`
+ }
+ if (width) {
+ defaultSize.width = `${width * defaultSize.ratio}px`
+ } else if (height) defaultSize.height = `${width * defaultSize.ratio}px`
+ }
+
+ return defaultSize
+}
diff --git a/packages/xgen/components/edit/Upload/index.less b/packages/xgen/components/edit/Upload/index.less
index db441e0..a1d6224 100644
--- a/packages/xgen/components/edit/Upload/index.less
+++ b/packages/xgen/components/edit/Upload/index.less
@@ -3,130 +3,173 @@
&.image {
:global {
+ @min_width: 90px;
+ @min_height: 90px;
+ @width: 90px;
+ @height: 90px;
+
+ .form_item_upload_wrap {
+ padding-top: 11px;
+ padding-left: 10px;
+ padding-right: 10px;
+
+ .xgen-upload-select-picture-card {
+ min-height: @min_height;
+ width: @width;
+ height: auto;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .xgen-upload-list-picture-card-container {
+ min-height: @min_height;
+ min-width: @min_width;
+ width: auto;
+ height: auto;
+ .image {
+ max-width: 100%;
+ object-fit: cover;
+ }
+ }
+ }
+ }
+ }
+
+ &.video {
+ :global {
+ @min_width: 160px;
+ @min_height: 90px;
+ @width: 160px;
+ @height: 100px;
+
.form_item_upload_wrap {
padding-top: 11px;
padding-left: 10px;
&.custom {
@image_size: unset;
- @min_image_size: 83px;
-
.xgen-upload-select-picture-card {
- min-width: @min_image_size;
- min-height: @min_image_size;
- width: @image_size;
- height: @image_size;
+ min-width: @min_width;
+ min-height: @min_height;
+ width: @width;
+ height: @height;
}
.xgen-upload-list-picture-card-container {
- min-width: @min_image_size;
- min-height: @min_image_size;
+ min-width: @min_width;
+ min-height: @min_height;
width: @image_size;
- height: @image_size;
+ height: @height;
}
}
- @image_size: 83px;
-
.xgen-upload-select-picture-card {
- width: @image_size;
- height: @image_size;
- display: inline-flex;
- align-items: center;
- justify-content: center;
+ width: @width;
+ height: @height;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
}
.xgen-upload-list-picture-card-container {
- width: @image_size;
- height: @image_size;
+ width: @width;
+ height: @height;
}
}
}
}
- &.file {
+ &.file,
+ &.audio {
:global {
+ @min_width: 160px;
+ @min_height: 36px;
+ @width: 150px;
+ @height: 36px;
+
.form_item_upload_wrap {
- display: flex;
- flex-direction: column-reverse;
- border-radius: 6px;
- background-color: var(--color_bg_nav);
+ padding-top: 11px;
+ padding-left: 10px;
- .xgen-upload-list-text-container {
- .xgen-upload-list-item {
- margin: 0;
- height: 36px;
+ &.custom {
+ @image_size: unset;
+ @min_image_size: 100px;
- .xgen-upload-list-item-info {
- padding: 0 9px;
- border-radius: 6px;
- }
+ .xgen-upload-select-picture-card {
+ min-width: @min_width;
+ min-height: @min_height;
+ width: @width;
+ height: @height;
+ }
+
+ .xgen-upload-list-picture-card-container {
+ min-width: @min_width;
+ min-height: @min_height;
+ width: @width;
+ height: @height;
}
}
- .btn_upload_wrap {
- padding: 0 9px;
+ .xgen-upload-select-picture-card {
+ width: @width;
+ height: @height;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
}
- }
- }
- }
- &.video {
- :global {
- .form_item_upload_wrap {
- .xgen-upload-select-picture-card,
.xgen-upload-list-picture-card-container {
- width: 300px;
- height: 160px;
+ width: @width;
+ height: @height;
}
}
}
}
:global {
- .upload_custom_wrap {
- &:hover {
- .icon_delete {
- display: flex;
- }
- }
-
- .video {
- width: 100%;
- height: 160px;
- border-radius: 6px;
-
- object-fit: fill;
- }
-
- .icon_delete {
- right: -1px;
- bottom: -1px;
- z-index: 1;
- display: none;
- width: 27px;
- height: 27px;
- border-top-left-radius: 6px;
- border-bottom-right-radius: 6px;
- background-color: white;
- color: black;
- cursor: pointer;
-
- &:hover {
- background-color: var(--color_danger);
-
- .icon {
- color: white;
- }
- }
-
- .icon {
- color: var(--color_danger);
- font-size: 15px;
- }
- }
- }
-
+ .upload_custom_wrap {
+ &:hover {
+ .icon_delete {
+ display: flex;
+ }
+ }
+
+ .video {
+ width: 100%;
+ height: 160px;
+ border-radius: 6px;
+ object-fit: fill;
+ }
+
+ .icon_delete {
+ right: -1px;
+ bottom: -1px;
+ z-index: 1;
+ display: none;
+ width: 27px;
+ height: 27px;
+ border-top-left-radius: 6px;
+ border-bottom-right-radius: 6px;
+ background-color: white;
+ color: black;
+ cursor: pointer;
+
+ &:hover {
+ background-color: var(--color_danger);
+
+ .icon {
+ color: white;
+ }
+ }
+
+ .icon {
+ color: var(--color_danger);
+ font-size: 15px;
+ }
+ }
+ }
+
.xgen-upload.xgen-upload-select-picture-card {
margin-right: 11px;
margin-bottom: 11px;
@@ -142,27 +185,22 @@
display: flex;
flex-direction: column;
- &.file {
- align-items: center;
- flex-direction: row;
-
- &.has_data {
- margin-bottom: 12px;
- }
+ .desc {
+ margin-top: 6px;
+ font-size: 12px;
+ }
+ &.file,
+ &.audio {
.desc {
- margin-top: 0;
- margin-left: 9px;
+ margin-left: 6px;
+ margin-top: 0px;
}
- }
- &.one_file {
- justify-content: center;
- height: 150px;
- }
-
- .desc {
- margin-top: 6px;
+ margin-top: 0;
+ align-items: center;
+ flex-direction: row;
+ align-items: center;
}
}
@@ -182,7 +220,6 @@
.xgen-upload-list-picture-card .xgen-upload-list-item-thumbnail,
.xgen-upload-list-picture-card .xgen-upload-list-item-thumbnail img {
opacity: 1;
-
object-fit: cover;
}
}
diff --git a/packages/xgen/components/edit/Upload/index.tsx b/packages/xgen/components/edit/Upload/index.tsx
index 329efc9..419106f 100644
--- a/packages/xgen/components/edit/Upload/index.tsx
+++ b/packages/xgen/components/edit/Upload/index.tsx
@@ -13,12 +13,14 @@ import useList from './hooks/useList'
import useVisibleBtn from './hooks/useVisibleBtn'
import styles from './index.less'
import handleFileList from './utils/handleFileList'
+import { getLocale } from '@umijs/max'
import type { UploadProps } from 'antd'
-import type { IProps, CustomProps, IPropsUploadBtn } from './types'
+import type { IProps, CustomProps, IPropsUploadBtn, PreviewProps } from './types'
const Custom = window.$app.memo((props: CustomProps) => {
- const { api, maxCount, desc, imageSize, onChange: trigger } = props
+ const locale = getLocale()
+ const { api, maxCount, desc, previewSize, imageSize, onChange: trigger } = props
const { list, setList } = useList(props.value)
const visible_btn = useVisibleBtn(list.length, maxCount || 1)
const filetype = filemap[props.filetype] ? props.filetype : 'image'
@@ -37,7 +39,7 @@ const Custom = window.$app.memo((props: CustomProps) => {
const action = useMemo(() => {
if (typeof api === 'string') return api
-
+ if (typeof api === 'undefined') return ''
return `${api.api}?${new URLSearchParams(api.params).toString()}`
}, [api])
@@ -45,11 +47,7 @@ const Custom = window.$app.memo((props: CustomProps) => {
...props,
name: 'file',
listType: filemap[filetype].listType,
- className: clsx([
- 'form_item_upload_wrap',
- filemap[filetype].className,
- filetype === 'image' && imageSize && 'custom'
- ]),
+ className: clsx(['form_item_upload_wrap', filemap[filetype].className]),
action,
headers: { authorization: getToken() },
fileList: list,
@@ -57,41 +55,23 @@ const Custom = window.$app.memo((props: CustomProps) => {
onChange
}
- if (filemap[filetype]?.render) {
- props_upload['itemRender'] = filemap[filetype].render
- }
-
- if (filetype === 'image' && imageSize) {
- if (!imageSize.width && !imageSize.height) {
- imageSize.height = '92px'
- }
-
- // If the ratio is set, the width will be 100% and the height will be calculated based on the ratio
- if (imageSize.ratio) {
- imageSize.width = `100%`
- imageSize.height = `calc(100% / ${imageSize.ratio})`
- }
-
- props_upload['itemRender'] = (_, file, _fileList, { remove }) => (
-
- )
+ const preview_props: PreviewProps = { size: previewSize || imageSize || undefined }
+ props_upload['itemRender'] = (_, file, fileList, { remove }) => {
+ return filemap[filetype].preview(preview_props, file, remove)
}
const props_upload_btn: IPropsUploadBtn = {
length: list.length,
filetype,
maxCount,
- desc
+ placeholder:
+ props.placeholder || filemap[filetype].placeholder[locale] || filemap['file'].placeholder['en-US'],
+ placeholderIcon:
+ props.placeholderIcon || filemap[filetype].placeholderIcon || filemap['file'].placeholderIcon
}
return (
-
+
1 && 'multiple')}>
{visible_btn && }
)
diff --git a/packages/xgen/components/edit/Upload/types.ts b/packages/xgen/components/edit/Upload/types.ts
index 93ced14..81ce5a0 100644
--- a/packages/xgen/components/edit/Upload/types.ts
+++ b/packages/xgen/components/edit/Upload/types.ts
@@ -4,9 +4,10 @@ import type { Component } from '@/types'
interface CommonProps {
value: Array
- filetype: 'image' | 'file' | 'video'
+ filetype: 'image' | 'file' | 'video' | 'audio'
desc?: string
- imageSize?: { width: string; height: string; ratio?: number }
+ imageSize?: { width?: string | number; height?: string | number; ratio?: number } // will be deprecated, use previewSize instead
+ previewSize?: { width?: string | number; height?: string | number; ratio?: number }
}
export interface Storage {
@@ -23,6 +24,12 @@ export interface IProps extends UploadProps, Component.PropsEditComponent, Commo
export interface CustomProps extends UploadProps, CommonProps {
api: string | { api: string; params: any }
+ placeholder?: string // the placeholder for the upload
+ placeholderIcon?: string | { name: string; size: number } // the placeholder icon for the upload
+ height?: number | string // the height for the upload
+ rows?: number // the rows for the upload. if set, height will be ignored
+ chunkSize?: number | string // the chunk size for the upload, if set, will use the chunk upload
+ previewURL?: string // the url for the preview image, if set, will use the preview image or video
appRoot?: boolean // if false, use the data root, else use the app root, default is false
storage?: Storage // storage option for the upload to the storage server directly (e.g. firebase, s3, etc)
aigc?: AIGC // aigc option for the upload. if set, will use the ai generated image
@@ -32,8 +39,9 @@ export interface FileType {
[key: string]: {
listType: UploadProps['listType']
className: string
- desc: { [key: string]: string }
- render?: UploadProps['itemRender']
+ placeholder: { [key: string]: CustomProps['placeholder'] }
+ placeholderIcon: CustomProps['placeholderIcon']
+ preview: (props: PreviewProps, file: UploadFile, remove: () => void) => JSX.Element
}
}
@@ -52,5 +60,10 @@ export interface IPropsUploadBtn {
length: number
filetype: IProps['filetype']
maxCount: IProps['maxCount']
- desc: IProps['desc']
+ placeholder: CustomProps['placeholder']
+ placeholderIcon: CustomProps['placeholderIcon']
+}
+
+export interface PreviewProps {
+ size?: CommonProps['previewSize']
}
diff --git a/packages/xgen/knife/yao/getFileSrc.ts b/packages/xgen/knife/yao/getFileSrc.ts
index 7400afa..6c5bc9d 100644
--- a/packages/xgen/knife/yao/getFileSrc.ts
+++ b/packages/xgen/knife/yao/getFileSrc.ts
@@ -1,9 +1,9 @@
import getToken from './getToken'
const Index = (name: string, appRoot: boolean = false) => {
- if (name && name.startsWith('http')) return name
+ if (typeof name === 'string' && name.startsWith('http')) return name
const token = getToken()
- const c = name.includes('?') ? '&' : '?'
+ const c = typeof name == 'string' && (name.includes('?') ? '&' : '?')
return appRoot ? `${name}${c}token=${token}&app=1` : `${name}${c}token=${token}`
}