Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(uploader): Upoader 3.0 重构 & 多端适配 #2660

Open
wants to merge 39 commits into
base: V3.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
543e0d6
fix: save
Alex-huxiyang Oct 23, 2024
b3fcf31
fix: save
Alex-huxiyang Oct 23, 2024
6e1016b
chore: taro save
Alex-huxiyang Oct 23, 2024
6b5d38c
fix: s
Alex-huxiyang Oct 23, 2024
fe74b6f
fix: save
Alex-huxiyang Oct 23, 2024
2334e78
fix: test
Alex-huxiyang Oct 24, 2024
2983242
fix: taro save
Alex-huxiyang Oct 24, 2024
563e918
fix: simple
Alex-huxiyang Oct 24, 2024
4cf5f7a
fix: update
Alex-huxiyang Oct 24, 2024
58bf2f9
feat: doc update
Alex-huxiyang Oct 24, 2024
ec4bc8a
fix: delete useless
Alex-huxiyang Oct 24, 2024
c2cb152
fix: delete useless
Alex-huxiyang Oct 24, 2024
cf1e6e6
fix: test
Alex-huxiyang Oct 24, 2024
7085e76
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 24, 2024
3b5034e
feat: harmony
Alex-huxiyang Oct 25, 2024
797099a
fix: save
Alex-huxiyang Oct 25, 2024
707919f
fix: doc mistakes
Alex-huxiyang Oct 25, 2024
da4221e
fix: doc mistakes
Alex-huxiyang Oct 25, 2024
3cf2df5
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 25, 2024
4346fb6
fix(uploader): resolve conflicts
Alex-huxiyang Oct 28, 2024
9f572df
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 28, 2024
ccc30e7
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 29, 2024
15986bd
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 30, 2024
9d813b1
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 30, 2024
b9588fd
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 31, 2024
5ee6d66
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Oct 31, 2024
22594ba
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 1, 2024
d59de4c
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 4, 2024
d902a65
fix: default key
Alex-huxiyang Nov 4, 2024
22c6899
fix: ts export
Alex-huxiyang Nov 4, 2024
4cf906b
chore: cr fix
Alex-huxiyang Nov 7, 2024
1763890
chore: update
Alex-huxiyang Nov 7, 2024
bde9cbc
chore: cr
Alex-huxiyang Nov 7, 2024
b6dea57
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 9, 2024
beb6a3c
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 10, 2024
d22c927
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 11, 2024
3c7f4b5
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 11, 2024
589ccd5
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 14, 2024
b3267a0
Merge branch 'V3.0' into hxy/uploader/refactor
Alex-huxiyang Nov 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@
"@vitest/ui": "^2.0.4",
"autoprefixer": "^10.4.17",
"axios": "^1.6.7",
"cypress": "^13.15.0",
"del": "^7.1.0",
"eslint": "^8.56.0",
"cypress": "^13.15.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
Expand Down Expand Up @@ -210,6 +210,7 @@
"rollup": "^4.12.0",
"sass": "^1.71.1",
"shelljs": "^0.8.5",
"simple-git": "^3.25.0",
"turndown": "^7.1.2",
"turndown-plugin-gfm": "^1.0.2",
"typescript": "^5.3.3",
Expand All @@ -219,7 +220,6 @@
"vite-plugin-dts": "4.2.1",
"vitest": "^2.0.4",
"vitest-canvas-mock": "^0.3.3",
"simple-git": "^3.25.0",
"yargs": "^17.7.2"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@
"author": "VickyYe"
},
{
"version": "2.0.0",
"version": "3.0.0",
"name": "Uploader",
"type": "component",
"tarodoc": true,
Expand Down
9 changes: 3 additions & 6 deletions src/packages/uploader/__tests__/uploader.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ test('should render base uploader other props', () => {
<Uploader
deletable
defaultValue={defaultFileList}
headers={{}}
multiple
preview
uploadIcon="dongdong"
Expand Down Expand Up @@ -200,7 +199,7 @@ test('before-delete prop return true', () => {
})

test('ready file list', () => {
const list = new FileItem()
const list: any = {}
list.name = '文件1.png'
list.url =
'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif'
Expand Down Expand Up @@ -232,6 +231,7 @@ test('preview component', () => {
status: 'success',
message: '上传成功',
uid: '12',
url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
},
]

Expand All @@ -242,7 +242,6 @@ test('preview component', () => {
deletable
onDeleteItem={delFunc}
handleItemClick={clickFunc}
previewUrl="https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif"
/>
)
fireEvent.click(container.querySelectorAll('.close')[0])
Expand All @@ -260,9 +259,7 @@ test('preview component', () => {
handleItemClick={clickFunc}
/>
)
fireEvent.click(
container1.querySelectorAll('.nut-uploader-preview-img-file-name')[0]
)
fireEvent.click(container1.querySelectorAll('.nut-uploader-preview-img-c')[0])
expect(clickFunc).toBeCalled()

const { container: container2 } = render(
Expand Down
66 changes: 19 additions & 47 deletions src/packages/uploader/demo.taro.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React from 'react'
import Taro from '@tarojs/taro'
import { ScrollView, View } from '@tarojs/components'
import { View, ScrollView } from '@tarojs/components'
import { useTranslate } from '@/sites/assets/locale/taro'
import Header from '@/sites/components/header'

import Demo1 from './demos/taro/demo1'
import Demo2 from './demos/taro/demo2'
import Demo3 from './demos/taro/demo3'
Expand All @@ -13,56 +11,39 @@ import Demo6 from './demos/taro/demo6'
import Demo7 from './demos/taro/demo7'
import Demo8 from './demos/taro/demo8'
import Demo9 from './demos/taro/demo9'
import Demo10 from './demos/taro/demo10'
import Demo11 from './demos/taro/demo11'
import Demo12 from './demos/taro/demo12'
import Demo13 from './demos/taro/demo13'
import Demo14 from './demos/taro/demo14'
import Header from '@/sites/components/header'

const UploaderDemo = () => {
const [translated] = useTranslate({
'zh-CN': {
basic: '基础用法',
uploadListDefault: '基础用法-上传列表展示',
uploadDefaultProgress: '自定义上传使用默认进度条',
uploadStatus: '上传状态',
camera: '直接调起摄像头(移动端生效)',
limitedQuantity: '限制上传数量5个',
limitedQuantity: '限制上传数量',
limitSize: '限制上传大小(每个文件最大不超过50kb)',
videoUploader: '使用前摄像头拍摄3s视频并上传(仅支持微信小程序)',
custom: '自定义数据 FormData、headers',
uploadXhrCustom: '自定义 Taro.uploadFile 上传方式(before-xhr-upload)',
beforeUpload: '自定义上传前的处理',
manualExecution: '选中文件后,通过按钮手动执行上传',
disabled: '禁用状态',
customDeleteIcon: '自定义删除icon',
},
'zh-TW': {
basic: '基础用法',
uploadListDefault: '基础用法-上傳列表展示',
uploadDefaultProgress: '自定義上傳使用默認進度條',
uploadStatus: '上傳狀態',
camera: '直接調起攝像頭(移動端生效)',
limitedQuantity: '限制上傳數量5個',
limitSize: '限制上傳大小(每個檔案最大不超過50kb)',
videoUploader: '使用前鏡頭拍攝3s影片並上傳(僅支援微信小程式)',
custom: '自定義數據 FormData、headers',
uploadXhrCustom: '自定義 Taro.uploadFile 上傳方式(before-xhr-upload)',
limitedQuantity: '限制上傳數量',
beforeUpload: '自定義上傳前的處理',
limitSize: '限制上傳大小',
manualExecution: '選取檔後,通過按鈕手動執行上傳',
disabled: '禁用狀態',
customDeleteIcon: '自定義刪除icon',
},
'en-US': {
basic: 'Basic usage',
uploadListDefault: 'Basic usage - upload list dispaly',
uploadDefaultProgress: 'Custom upload uses default progress bar',
uploadStatus: 'Upload status',
camera: 'Direct camera up (mobile)',
limitedQuantity: 'Limit the number of uploads to 5',
beforeUpload: 'Beforeupload Usage',
limitedQuantity: 'Limit the number of uploads',
limitSize: 'Limit upload size (maximum 50kb per file)',
videoUploader:
'Use the front camera to shoot 3s video and upload it (only support wechat mini program)',
custom: 'Custom data FormData, headers',
uploadXhrCustom: 'Custom xhr Taro.uploadFile method (before-xhr-upload)',
manualExecution:
'After selecting Chinese, manually perform the upload via the button',
disabled: 'Disabled state',
Expand All @@ -74,36 +55,27 @@ const UploaderDemo = () => {
<>
<Header />
<ScrollView
className={`demo ${Taro.getEnv() === 'WEB' ? 'web' : ''} bg-w`}
className={`demo ${Taro.getEnv() === 'WEB' ? 'web' : ''} padding`}
>
{' '}
<View className="h2">{translated.basic}</View>
<Demo1 />
<View className="h2">{translated.basic}</View>
<Demo2 />
<View className="h2">{translated.uploadStatus}</View>
<Demo2 />
<View className="h2">{translated.limitedQuantity}</View>
<Demo3 />
<View className="h2">{translated.uploadListDefault}</View>
<View className="h2">{translated.limitSize}</View>
<Demo4 />
<View className="h2">{translated.uploadDefaultProgress}</View>
<View className="h2">{translated.beforeUpload}</View>
<Demo5 />
<View className="h2">{translated.camera}</View>
<View className="h2">{translated.disabled}</View>
<Demo6 />
<View className="h2">{translated.videoUploader}</View>
<View className="h2">{translated.customDeleteIcon}</View>
<Demo7 />
<View className="h2">{translated.limitedQuantity}</View>
<View className="h2">{translated.manualExecution}</View>
<Demo8 />
<View className="h2">{translated.limitSize}</View>
<View className="h2">{translated.uploadListDefault}</View>
<Demo9 />
<View className="h2">{translated.custom}</View>
<Demo10 />
<View className="h2">{translated.uploadXhrCustom}</View>
<Demo11 />
<View className="h2">{translated.manualExecution}</View>
<Demo12 />
<View className="h2">{translated.disabled}</View>
<Demo13 />
<h2>{translated.customDeleteIcon}</h2>
<Demo14 />
</ScrollView>
</>
)
Expand Down
53 changes: 16 additions & 37 deletions src/packages/uploader/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,41 @@ import Demo7 from './demos/h5/demo7'
import Demo8 from './demos/h5/demo8'
import Demo9 from './demos/h5/demo9'
import Demo10 from './demos/h5/demo10'
import Demo11 from './demos/h5/demo11'
import Demo12 from './demos/h5/demo12'
import Demo13 from './demos/h5/demo13'
import Demo14 from './demos/h5/demo14'

const UploaderDemo = () => {
const [translated] = useTranslate({
'zh-CN': {
basic: '基础用法',
uploadListDefault: '基础用法-上传列表展示',
uploadDefaultProgress: '自定义上传使用默认进度条',
uploadStatus: '上传状态',
camera: '直接调起摄像头(移动端生效)',
limitedQuantity: '限制上传数量5个',
limitedQuantity: '限制上传数量',
limitSize: '限制上传大小(每个文件最大不超过50kb)',
compress: '图片压缩(在beforeupload钩子中处理)',
custom: '自定义数据 FormData、headers',
uploadXhrCustom: '自定义 xhr 上传方式(before-xhr-upload)',
beforeUpload: '自定义上传前的处理',
manualExecution: '选中文件后,通过按钮手动执行上传',
disabled: '禁用状态',
customDeleteIcon: '自定义删除icon',
},
'zh-TW': {
basic: '基础用法',
uploadListDefault: '基础用法-上傳列表展示',
uploadDefaultProgress: '自定義上傳使用默認進度條',
uploadStatus: '上傳狀態',
camera: '直接調起攝像頭(移動端生效)',
limitedQuantity: '限制上傳數量5個',
limitSize: '限制上傳大小(每個檔案最大不超過50kb)',
compress: '圖片壓縮(在beforeupload鉤子中處理)',
custom: '自定義數據 FormData、headers',
uploadXhrCustom: '自定義 xhr 上傳方式(before-xhr-upload)',
limitedQuantity: '限制上傳數量',
beforeUpload: '自定義上傳前的處理',
limitSize: '限制上傳大小',
manualExecution: '選取檔後,通過按鈕手動執行上傳',
disabled: '禁用狀態',
customDeleteIcon: '自定義刪除icon',
},
'en-US': {
basic: 'Basic usage',
uploadListDefault: 'Basic usage - upload list dispaly',
uploadDefaultProgress: 'Custom upload uses default progress bar',
uploadStatus: 'Upload status',
beforeUpload: 'Beforeupload Usage',
camera: 'Direct camera up (mobile)',
limitedQuantity: 'Limit the number of uploads to 5',
limitedQuantity: 'Limit the number of uploads',
limitSize: 'Limit upload size (maximum 50kb per file)',
compress: 'Image compression (handled in a foreupload hook)',
custom: 'Custom data FormData, headers',
uploadXhrCustom: 'Custom xhr upload method (before-xhr-upload)',
manualExecution:
'After selecting Chinese, manually perform the upload via the button',
disabled: 'Disabled state',
Expand All @@ -71,32 +58,24 @@ const UploaderDemo = () => {
<div className="demo bg-w">
<h2>{translated.basic}</h2>
<Demo1 />
<h2>{translated.basic}</h2>
<Demo2 />
<h2>{translated.uploadStatus}</h2>
<Demo2 />
<h2>{translated.limitedQuantity}</h2>
<Demo3 />
<h2>{translated.uploadListDefault}</h2>
<h2>{translated.limitSize}</h2>
<Demo4 />
<h2>{translated.uploadDefaultProgress}</h2>
<h2>{translated.beforeUpload}</h2>
<Demo5 />
<h2>{translated.camera}</h2>
<h2>{translated.disabled}</h2>
<Demo6 />
<h2>{translated.limitedQuantity}</h2>
<h2>{translated.customDeleteIcon}</h2>
<Demo7 />
<h2>{translated.limitSize}</h2>
<h2>{translated.camera}</h2>
<Demo8 />
<h2>{translated.compress}</h2>
<h2>{translated.manualExecution}</h2>
<Demo9 />
<h2>{translated.custom}</h2>
<h2>{translated.uploadListDefault}</h2>
<Demo10 />
<h2>{translated.uploadXhrCustom}</h2>
<Demo11 />
<h2>{translated.manualExecution}</h2>
<Demo12 />
<h2>{translated.disabled}</h2>
<Demo13 />
<h2>{translated.customDeleteIcon}</h2>
<Demo14 />
</div>
</>
)
Expand Down
66 changes: 36 additions & 30 deletions src/packages/uploader/demos/h5/demo1.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,51 @@
import React from 'react'
import { Uploader, Cell } from '@nutui/nutui-react'
import React, { useState } from 'react'
import { Uploader, Cell, FileItem } from '@nutui/nutui-react'
import { Dongdong } from '@nutui/icons-react'

const Demo1 = () => {
const uploadUrl = 'https://my-json-server.typicode.com/linrufeng/demo/posts'
const onStart = () => {
console.log('start触发')
const [list, setList] = useState<FileItem[]>([
{
url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
uid: 133,
},
])

const uploaderStyle = {
marginInlineEnd: '10px',
marginBottom: '10px',
}
function sleep(time: number) {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, time)
})
}
async function upload(file: File) {
await sleep(2000)
return {
url: URL.createObjectURL(file),
}
}
Alex-huxiyang marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +24 to +28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

建议增强上传函数的实现

当前的上传函数缺少必要的错误处理和类型校验:

async function upload(file: File) {
+ if (!file) {
+   throw new Error('文件不能为空')
+ }
+ if (file.size > 5 * 1024 * 1024) {
+   throw new Error('文件大小不能超过5MB')
+ }
  await sleep(2000)
  return {
    url: URL.createObjectURL(file),
+   status: 'success' as const,
+   type: file.type.startsWith('image/') ? 'image' : 'file',
+   name: file.name,
+   uid: Date.now()
  }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function upload(file: File) {
await sleep(2000)
return {
url: URL.createObjectURL(file),
}
async function upload(file: File) {
if (!file) {
throw new Error('文件不能为空')
}
if (file.size > 5 * 1024 * 1024) {
throw new Error('文件大小不能超过5MB')
}
await sleep(2000)
return {
url: URL.createObjectURL(file),
status: 'success' as const,
type: file.type.startsWith('image/') ? 'image' : 'file',
name: file.name,
uid: Date.now()
}

const beforeUpload = async (files: File[]) => {
const allowedTypes = ['image/png']
const filteredFiles = Array.from(files).filter((file) =>
allowedTypes.includes(file.type)
)
return filteredFiles
async function uploadFail(file: File): Promise<FileItem> {
await sleep(2000)
throw new Error('Fail to upload')
}
return (
<>
<Cell style={{ flexWrap: 'wrap', paddingBottom: '0px' }}>
<Uploader
beforeUpload={beforeUpload}
url={uploadUrl}
onStart={onStart}
style={{
marginInlineEnd: '10px',
marginBottom: '10px',
}}
onChange={(v) => {
console.log('outer onChange', v)
}}
/>
<Cell style={{ flexWrap: 'wrap' }}>
<Uploader
url={uploadUrl}
uploadLabel="商品主图"
onStart={onStart}
style={{ marginInlineEnd: '2px', marginBottom: '10px' }}
value={list}
onChange={setList}
upload={(file: File) => upload(file)}
style={uploaderStyle}
/>
<Uploader style={uploaderStyle} upload={(file: File) => upload(file)} />
<Uploader
url={uploadUrl}
uploadIcon={<Dongdong />}
onStart={onStart}
style={{ marginBottom: '10px' }}
upload={(file: File) => uploadFail(file)}
style={uploaderStyle}
/>
</Cell>
Comment on lines +36 to 49
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

建议增强组件的可访问性和类型安全性

  1. 添加必要的 ARIA 属性以提升可访问性
  2. 为上传失败的情况添加错误提示
  3. 使用更严格的类型定义
<Cell style={{ flexWrap: 'wrap' }}>
  <Uploader
    uploadLabel="商品主图"
    value={list}
    onChange={setList}
    upload={(file: File) => upload(file)}
    style={uploaderStyle}
+   aria-label="上传商品主图"
+   maxCount={5}
+   onError={(error) => console.error('上传失败:', error)}
  />
  <Uploader 
    style={uploaderStyle} 
    upload={(file: File) => upload(file)} 
+   aria-label="普通上传"
  />
  <Uploader
    uploadIcon={<Dongdong />}
    upload={(file: File) => uploadFail(file)}
    style={uploaderStyle}
+   aria-label="测试上传失败"
+   onError={(error) => console.error('预期的上传失败:', error)}
  />
</Cell>

Committable suggestion skipped: line range outside the PR's diff.

</>
Expand Down
Loading
Loading