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

Merged
merged 61 commits into from
Dec 24, 2024

Conversation

Alex-huxiyang
Copy link
Collaborator

@Alex-huxiyang Alex-huxiyang commented Oct 24, 2024

🤔 这个变动的性质是?

  • 新特性提交
  • 日常 bug 修复
  • 站点、文档改进
  • 演示代码改进
  • 组件样式/交互改进
  • TypeScript 定义更新
  • 包体积优化
  • 性能优化
  • 功能增强
  • 国际化改进
  • 重构
  • 代码风格优化
  • 测试用例
  • 分支合并
  • 其他改动(是关于什么的改动?)

🔗 相关 Issue

💡 需求背景和解决方案

☑️ 请求合并前的自查清单

⚠️ 请自检并全部勾选全部选项⚠️

  • 文档已补充或无须补充
  • 代码演示已提供或无须提供
  • TypeScript 定义已补充或无须补充
  • fork仓库代码是否为最新避免文件冲突
  • Files changed 没有 package.json lock 等无关文件

Summary by CodeRabbit

发布说明

  • 新特性

    • 更新了多个组件至版本 3.0.0,包括 UploaderEmptyResultPageNotifyPopupPullToRefreshSkeletonSwipeAnimatingNumbersAvatarAvatarGroupCountDownImagePreviewIndicatorPaginationPriceProgressSwiperSwiperItemTagVideoTrendArrow
    • 新增组件 EmptyResultPageNotifyPopupPullToRefreshSkeletonSwipe
  • 文档

    • 更新了 Uploader 组件的文档,增强了可读性和组织性,添加了新属性说明,修改了现有属性描述,移除了与文件上传相关的潜在编码问题的讨论,更新了多个标题以提高清晰度。

Copy link

coderabbitai bot commented Oct 24, 2024

Walkthrough

本次变更主要涉及 src/config.json 文件中多个组件的版本更新,特别是将 Uploader 组件的版本从 2.0.0 更新至 3.0.0。同时,引入了多个新组件并更新了其版本,包括 EmptyResultPageNotify 等。此外,某些组件的可见性被修改,show 属性被设置为 false,表示这些组件当前不在用户界面中显示。整体 JSON 结构保持不变。

Changes

文件路径 修改摘要
src/config.json 更新 Uploader 组件版本至 3.0.0,新增多个组件(EmptyResultPageNotify 等)并将其版本更新至 3.0.0,修改某些组件的 show 属性为 false
src/packages/uploader/__tests__/uploader.spec.tsx 修改 UploaderPreview 组件的测试用例,调整 list 变量类型,更新点击事件处理选择器,增加对 beforeDelete 属性的检查。
src/packages/uploader/demo.taro.tsx 修改 UploaderDemo 组件,更新翻译对象,调整 JSX 结构,改变某些 View 元素的顺序和样式。
src/packages/uploader/demo.tsx 修改 UploaderDemo 组件,移除多个演示组件的导入,更新多语言翻译字符串,调整演示组件的顺序和标题。
src/packages/uploader/demos/h5/demo1.tsx 实现状态管理,移除静态 uploadUrlonStart 函数,更新 Uploader 组件的 props 以绑定状态。
src/packages/uploader/demos/h5/demo10.tsx 引入新的 Demo10 组件,使用状态管理,更新上传逻辑,添加上传按钮。
src/packages/uploader/demos/h5/demo11.tsx 删除 Demo11 组件。
src/packages/uploader/demos/h5/demo12.tsx 删除 Demo12 组件。
src/packages/uploader/demos/h5/demo13.tsx 删除 Demo13 组件。
src/packages/uploader/demos/h5/demo14.tsx 删除 Demo14 组件。
src/packages/uploader/demos/h5/demo2.tsx 修改 Demo1 组件为 Demo2,更新组件内部逻辑和 props。
src/packages/uploader/demos/h5/demo3.tsx 更新 Demo3 组件,使用状态管理,添加上传功能。
src/packages/uploader/demos/h5/demo4.tsx 修改 Demo4 组件,使用状态管理,更新上传逻辑。
src/packages/uploader/demos/h5/demo5.tsx 修改 Demo5 组件,添加文件类型过滤和状态管理。
src/packages/uploader/demos/h5/demo6.tsx 更新 Demo6 组件,设置为禁用状态。
src/packages/uploader/demos/h5/demo7.tsx 修改 Demo7 组件,允许多个 Uploader 实例。
src/packages/uploader/demos/h5/demo8.tsx 修改 Demo8 组件,添加延迟模拟和上传逻辑。
src/packages/uploader/demos/h5/demo9.tsx 更新 Demo9 组件,添加状态管理和上传逻辑。
src/packages/uploader/demos/taro/demo1.tsx 修改 Demo1 组件,增强状态管理和上传过程。
src/packages/uploader/demos/taro/demo10.tsx 删除 Demo10 组件。
src/packages/uploader/demos/taro/demo11.tsx 删除 Demo11 组件。
src/packages/uploader/demos/taro/demo12.tsx 删除 Demo12 组件。
src/packages/uploader/demos/taro/demo13.tsx 删除 Demo13 组件。
src/packages/uploader/demos/taro/demo14.tsx 删除 Demo14 组件。
src/packages/uploader/demos/taro/demo2.tsx 修改 Demo2 组件,更新文件管理逻辑。
src/packages/uploader/demos/taro/demo3.tsx 更新 Demo3 组件,使用状态管理和动态上传。
src/packages/uploader/demos/taro/demo4.tsx 修改 Demo4 组件,更新上传逻辑和状态管理。
src/packages/uploader/demos/taro/demo5.tsx 修改 Demo5 组件,添加文件类型过滤和状态管理。
src/packages/uploader/demos/taro/demo6.tsx 更新 Demo6 组件,设置为禁用状态。
src/packages/uploader/demos/taro/demo7.tsx 修改 Demo7 组件,允许多个 Uploader 实例。
src/packages/uploader/demos/taro/demo8.tsx 修改 Demo8 组件,添加延迟模拟和上传逻辑。
src/packages/uploader/demos/taro/demo9.tsx 更新 Demo9 组件,添加状态管理和上传逻辑。
src/packages/uploader/doc.en-US.md 更新文档,修改标题和内容,添加新属性,更新现有属性描述。
src/packages/uploader/doc.md 更新文档,修改标题和内容,添加新属性,更新现有属性描述。
src/packages/uploader/doc.taro.md 更新文档,修改标题和内容,添加新属性,更新现有属性描述。
src/packages/uploader/doc.zh-TW.md 更新文档,修改标题和内容,添加新属性,更新现有属性描述。
src/packages/uploader/file-item.taro.ts 删除 FileItem 类及相关类型定义。
src/packages/uploader/file-item.ts 删除 FileItem 类及相关类型定义。
src/packages/uploader/index.taro.ts 更新类型导出路径。
src/packages/uploader/preview.taro.tsx 更新 Preview 组件,改进错误处理和渲染逻辑。
src/packages/uploader/preview.tsx 更新 Preview 组件,改进错误处理和渲染逻辑。
src/packages/uploader/uploader.taro.tsx 修改 UploaderProps 接口,移除多个属性,添加新的上传方法。
src/packages/uploader/uploader.tsx 修改 UploaderProps 接口,移除多个属性,添加新的上传方法。
src/packages/uploader/index.ts 添加新的类型定义,更新导出语句。
migrate-from-v2.md 更新迁移文档,详细说明从版本 2.x 升级到 3.x 的过程。

Possibly related PRs

Suggested labels

size/L

Suggested reviewers

  • oasis-cloud
  • xiaoyatong

兔子在草地上跳跃,
新版本来报道,
上传组件更强大,
功能齐全又好用,
让我们一起欢呼吧! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

🛑 Comments failed to post (58)
src/packages/uploader/demos/h5/demo6.tsx (1)

4-11: 🛠️ Refactor suggestion

Enhance demo clarity and user experience.

As a demo component, this implementation could be improved in several ways:

  1. Add explanatory text within the Cell to describe the purpose of a disabled uploader
  2. Include a default file list or preview to demonstrate how disabled state affects existing uploads
  3. Consider adding props like maxCount or previewType to showcase more features even in disabled state

Consider this enhancement:

 const Demo6 = () => {
   return (
-    <Cell style={{ flexWrap: 'wrap' }}>
-      <Uploader disabled />
+    <Cell style={{ flexWrap: 'wrap' }}>
+      <Cell.Description>Disabled uploader state demonstration</Cell.Description>
+      <Uploader
+        disabled
+        defaultFileList={[
+          {
+            name: 'example.png',
+            url: 'https://example.com/example.png',
+            status: 'success'
+          }
+        ]}
+        maxCount={3}
+        previewType="list"
+      />
     </Cell>
   )
 }
📝 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.

const Demo6 = () => {
  return (
    <Cell style={{ flexWrap: 'wrap' }}>
      <Cell.Description>Disabled uploader state demonstration</Cell.Description>
      <Uploader
        disabled
        defaultFileList={[
          {
            name: 'example.png',
            url: 'https://example.com/example.png',
            status: 'success'
          }
        ]}
        maxCount={3}
        previewType="list"
      />
    </Cell>
  )
}
export default Demo6
src/packages/uploader/demos/taro/demo6.tsx (1)

6-8: 🛠️ Refactor suggestion

Consider enhancing the UX for disabled state.

The disabled uploader might benefit from additional visual cues or explanatory text to inform users why uploads are not allowed.

 return (
   <Cell style={{ flexWrap: 'wrap' }}>
-    <Uploader disabled />
+    <Uploader 
+      disabled 
+      placeholder="Uploads are currently disabled"
+    />
   </Cell>
 )
📝 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.

    <Cell style={{ flexWrap: 'wrap' }}>
      <Uploader 
        disabled 
        placeholder="Uploads are currently disabled"
      />
    </Cell>
src/packages/uploader/demos/h5/demo8.tsx (2)

12-17: ⚠️ Potential issue

Add error handling and cleanup URL object references.

The current implementation has potential memory leaks and lacks error handling.

Consider implementing these improvements:

   async function upload(file: File) {
-    await sleep(2000)
-    return {
-      url: URL.createObjectURL(file),
-    }
+    try {
+      await sleep(2000)
+      const objectUrl = URL.createObjectURL(file)
+      // Consider adding this cleanup function to component's cleanup logic
+      // window.addEventListener('unload', () => URL.revokeObjectURL(objectUrl))
+      return {
+        url: objectUrl,
+      }
+    } catch (error) {
+      console.error('Upload failed:', error)
+      throw new Error('Upload failed')
+    }
   }

Committable suggestion was skipped due to low confidence.


19-21: 🛠️ Refactor suggestion

Enhance user experience with loading and error states.

The current implementation lacks visual feedback during upload and error handling.

Consider these improvements:

   <Cell style={{ flexWrap: 'wrap' }}>
-    <Uploader capture upload={(file: File) => upload(file)} />
+    <Uploader
+      capture
+      upload={(file: File) => upload(file)}
+      onProgress={(event) => {
+        // Show upload progress
+        console.log('Upload progress:', event.percent)
+      }}
+      onError={(error) => {
+        // Handle and display upload errors
+        console.error('Upload error:', error)
+      }}
+    />
   </Cell>

Also, consider adding a comment explaining the purpose of the capture prop for better documentation.

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demos/taro/demo8.tsx (4)

5-11: 🛠️ Refactor suggestion

Consider improving type safety of the sleep utility function.

The sleep function could benefit from better type definitions and error handling.

-  function sleep(time: number) {
-    return new Promise<void>((resolve) => {
+  function sleep(time: number): Promise<void> {
+    if (time < 0) throw new Error('Sleep time cannot be negative')
+    return new Promise<void>((resolve) => {
       setTimeout(() => {
         resolve()
       }, time)
     })
   }
📝 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.

  function sleep(time: number): Promise<void> {
    if (time < 0) throw new Error('Sleep time cannot be negative')
    return new Promise<void>((resolve) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

19-21: 🛠️ Refactor suggestion

Improve type safety and documentation of component props.

Several improvements could be made to enhance type safety and maintainability:

-    <Cell style={{ flexWrap: 'wrap' }}>
-      <Uploader capture upload={(file: File) => upload(file)} />
+    <Cell style={{ flexWrap: 'wrap' as const }}>
+      <Uploader
+        capture // Consider documenting the purpose of this prop
+        upload={(file: File): Promise<{ url: string }> => upload(file)}
+      />

Committable suggestion was skipped due to low confidence.


12-17: ⚠️ Potential issue

Address potential memory leak in upload function.

The URL.createObjectURL creates a new object URL that should be revoked when no longer needed to prevent memory leaks. Also, consider adding proper typing for the return value.

-  async function upload(file: File) {
+  async function upload(file: File): Promise<{ url: string }> {
     await sleep(2000)
+    const url = URL.createObjectURL(file)
+    // In a real implementation, you might want to store this URL to revoke it later
+    // Consider implementing a cleanup mechanism or documenting the need to call URL.revokeObjectURL
     return {
-      url: URL.createObjectURL(file),
+      url,
     }
   }

Committable suggestion was skipped due to low confidence.


1-22: 💡 Codebase verification

Based on the documentation files and demo content reviewed, I can now provide the final response:

Documentation improvements needed for Demo8's capture functionality

The review comment is valid. While the documentation does explain the capture prop in the Props table, the demo itself lacks proper documentation. Here's why this needs attention:

  1. The documentation shows that Demo8 specifically demonstrates "直接调起摄像头" (Directly activate the camera) functionality, but the demo code lacks comments explaining this important use case.
  2. The current implementation with a 2-second delay is indeed not representative of real upload scenarios and lacks error handling.
  3. Other demos in the codebase also lack proper documentation, making this a consistent issue across demo files.

Suggested improvements:

  • Add comments explaining that the capture prop is used to directly activate the device camera on mobile devices
  • Include error handling in the upload function to demonstrate proper error management
  • Consider adding a more realistic upload simulation or at least a comment explaining that the delay is for demonstration purposes only
🔗 Analysis chain

Consider enhancing this demo with additional documentation and error handling.

As this is a demo file showcasing the Uploader 3.0 functionality:

  1. Add comments explaining the purpose of the capture prop and its use cases
  2. Consider showing error handling scenarios
  3. The 2-second delay might not be representative of real upload scenarios

Let's check if other demo files include proper documentation:


Let me modify the search pattern to correctly check for documentation in demo files.

This will help us:

  1. Identify all demo files in the directory
  2. Look for both single-line and multi-line comments in these files to understand the documentation patterns

Let me try a different approach to check the content of these demo files, focusing on their structure and any existing documentation.


Let me check the documentation files to understand how the demos are documented in the component's documentation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check documentation patterns in other demo files
rg -l "\/\*\*|\* @" "src/packages/uploader/demos/taro/"

Length of output: 133


Script:

#!/bin/bash
# Check documentation patterns in other demo files
# First, let's see all demo files
fd "demo\d+\.tsx$" "src/packages/uploader/demos/taro/"

# Then check for comments in these files
rg -U "(/\*\*|//)" "src/packages/uploader/demos/taro/"

Length of output: 2713


Script:

#!/bin/bash
# Let's examine the content of a few demo files to understand their structure
echo "=== Demo1 Content ==="
cat src/packages/uploader/demos/taro/demo1.tsx

echo -e "\n=== Demo8 Content (the one under review) ==="
cat src/packages/uploader/demos/taro/demo8.tsx

# Let's also check if there's any documentation in the parent directory
echo -e "\n=== Checking for documentation files in parent directory ==="
ls src/packages/uploader/

Length of output: 2746


Script:

#!/bin/bash
# Check the documentation files for any mention of the capture prop and demo documentation
echo "=== Checking doc.taro.md ==="
cat src/packages/uploader/doc.taro.md

echo -e "\n=== Checking doc.en-US.md ==="
cat src/packages/uploader/doc.en-US.md

Length of output: 12935

src/packages/uploader/demos/h5/demo7.tsx (1)

24-29: 🛠️ Refactor suggestion

Consider enhancing the demo with different configurations.

Both uploaders currently share identical defaultValue. Consider differentiating them to better showcase the component's versatility.

 <Uploader
-  defaultValue={defaultFileList}
+  defaultValue={[{
+    name: 'custom-icon-demo-2.jpg',
+    url: 'https://m.360buyimg.com/babel/different-image-url.jpg',
+    message: '使用自定义图标上传',
+  }]}
   uploadIcon={<Star />}
   deleteIcon={<Dongdong />}
 />
📝 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.

      <Uploader
        defaultValue={[{
          name: 'custom-icon-demo-2.jpg',
          url: 'https://m.360buyimg.com/babel/different-image-url.jpg',
          message: '使用自定义图标上传',
        }]}
        uploadIcon={<Star />}
        deleteIcon={<Dongdong />}
      />
    </Cell>
src/packages/uploader/demos/taro/demo7.tsx (1)

15-29: 🛠️ Refactor suggestion

Consider enhancing the demo's educational value.

While the implementation effectively demonstrates icon customization, consider these improvements:

  1. Each Uploader instance could use different defaultValue data to better demonstrate independence
  2. Add comments explaining the purpose of each configuration
 <Cell style={{ flexWrap: 'wrap' }}>
+  {/* Example: Custom upload and delete icons */}
   <Uploader
-    defaultValue={defaultFileList}
+    defaultValue={[{ name: 'custom-upload-icon.png', url: '...', message: 'Using Dongdong icon' }]}
     uploadIcon={<Dongdong />}
     deleteIcon={<Star />}
     style={{
       marginInlineEnd: '10px',
     }}
   />
+  {/* Example: Reversed icon configuration */}
   <Uploader
-    defaultValue={defaultFileList}
+    defaultValue={[{ name: 'custom-delete-icon.png', url: '...', message: 'Using Star icon' }]}
     uploadIcon={<Star />}
     deleteIcon={<Dongdong />}
   />
 </Cell>

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demos/h5/demo4.tsx (2)

24-33: 🛠️ Refactor suggestion

Enhance component configuration and accessibility.

Consider these improvements:

  1. Extract inline styles to constants or CSS
  2. Define maxFileSize as a named constant
  3. Add accessibility attributes

Here's the suggested implementation:

+ const MAX_FILE_SIZE = 1024 * 50 // 50KB
+ const cellStyles = { flexWrap: 'wrap' as const }

  return (
-   <Cell style={{ flexWrap: 'wrap' }}>
+   <Cell style={cellStyles}>
      <Uploader
        value={list}
        onChange={setList}
        upload={(file: File) => upload(file)}
        multiple
-       maxFileSize={1024 * 50}
+       maxFileSize={MAX_FILE_SIZE}
        onOversize={onOversize}
+       aria-label="File uploader"
+       role="button"
      />
    </Cell>
  )

Committable suggestion was skipped due to low confidence.


10-22: 🛠️ Refactor suggestion

Improve helper functions implementation.

Consider these enhancements:

  1. Add JSDoc comments for better documentation
  2. Clean up object URLs to prevent memory leaks
  3. Consider reducing the delay time for better demo experience

Here's the suggested implementation:

+ /**
+  * Utility function to create a delayed promise
+  * @param time - Delay time in milliseconds
+  * @returns Promise that resolves after the specified time
+  */
  function sleep(time: number) {
    return new Promise<void>((resolve) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

+ /**
+  * Simulates file upload with artificial delay
+  * @param file - File to be uploaded
+  * @returns Promise with upload result containing URL
+  */
  async function upload(file: File) {
-   await sleep(2000)
+   await sleep(1000) // Reduced delay for better demo experience
+   const url = URL.createObjectURL(file)
    return {
-     url: URL.createObjectURL(file),
+     url,
+     cleanup: () => URL.revokeObjectURL(url), // Add cleanup function
    }
  }
📝 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.

  /**
   * Utility function to create a delayed promise
   * @param time - Delay time in milliseconds
   * @returns Promise that resolves after the specified time
   */
  function sleep(time: number) {
    return new Promise<void>((resolve) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

  /**
   * Simulates file upload with artificial delay
   * @param file - File to be uploaded
   * @returns Promise with upload result containing URL
   */
  async function upload(file: File) {
    await sleep(1000) // Reduced delay for better demo experience
    const url = URL.createObjectURL(file)
    return {
      url,
      cleanup: () => URL.revokeObjectURL(url), // Add cleanup function
    }
  }
src/packages/uploader/demos/taro/demo4.tsx (1)

17-22: ⚠️ Potential issue

Add cleanup and error handling to upload function.

The current implementation might lead to memory leaks due to uncleaned object URLs.

Consider this improvement:

   async function upload(file: File) {
-    await sleep(2000)
-    return {
-      url: URL.createObjectURL(file),
-    }
+    try {
+      await sleep(2000)
+      const url = URL.createObjectURL(file)
+      // Add cleanup when the URL is no longer needed
+      setTimeout(() => URL.revokeObjectURL(url), 0)
+      return { url }
+    } catch (error) {
+      console.error('Upload failed:', error)
+      throw error
+    }
   }
📝 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.

  async function upload(file: File) {
    try {
      await sleep(2000)
      const url = URL.createObjectURL(file)
      // Add cleanup when the URL is no longer needed
      setTimeout(() => URL.revokeObjectURL(url), 0)
      return { url }
    } catch (error) {
      console.error('Upload failed:', error)
      throw error
    }
  }
src/packages/uploader/demos/taro/demo3.tsx (2)

7-10: 🛠️ Refactor suggestion

Consider moving the style object outside the component.

The style object is static and doesn't depend on component state or props. Moving it outside the component would prevent unnecessary recreation on each render.

+const uploaderStyle = {
+  marginInlineEnd: '10px',
+  marginBottom: '10px',
+}

const Demo3 = () => {
  const [list, setList] = useState<FileItem[]>([])
-  const uploaderStyle = {
-    marginInlineEnd: '10px',
-    marginBottom: '10px',
-  }

Committable suggestion was skipped due to low confidence.


18-22: ⚠️ Potential issue

Handle URL.createObjectURL cleanup and add error handling.

The current implementation has two potential issues:

  1. URLs created by URL.createObjectURL should be revoked when no longer needed to prevent memory leaks
  2. The upload function lacks error handling for failed uploads

Consider implementing this improved version:

 async function upload(file: File) {
+  try {
     await sleep(2000)
+    const url = URL.createObjectURL(file)
+    // Add cleanup logic when the URL is no longer needed
+    // You might want to store these URLs in a ref and clean them up when files are removed
     return {
-      url: URL.createObjectURL(file),
+      url,
     }
+  } catch (error) {
+    console.error('Upload failed:', error)
+    throw new Error('Upload failed')
+  }
 }

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demos/h5/demo5.tsx (3)

30-37: 🛠️ Refactor suggestion

Enhance component with loading and error states.

The current implementation could benefit from better user feedback and accessibility:

  1. Add loading state handling
  2. Add error state handling
  3. Improve accessibility

Here's a suggested improvement:

  <Cell style={{ flexWrap: 'wrap' }}>
    <Uploader
      value={list}
      onChange={setList}
      beforeUpload={beforeUpload}
      upload={(file: File) => upload(file)}
+     aria-label="Upload PNG images"
+     onError={(error) => alert(error.message)}
+     loading={isUploading}
    />
  </Cell>

Committable suggestion was skipped due to low confidence.


6-15: ⚠️ Potential issue

Remove debug logs and enhance user feedback in beforeUpload.

The beforeUpload implementation has several areas for improvement:

  1. Remove console.log statements from production code
  2. Add user feedback when files are rejected
  3. Make the allowed file types more maintainable

Here's a suggested improvement:

  const [list, setList] = useState<FileItem[]>([])
+ const ALLOWED_TYPES = ['image/png']
  const beforeUpload = async (files: File[]) => {
-   console.log('bbb')
    const allowedTypes = ['image/png']
    const filteredFiles = Array.from(files).filter((file) =>
-     allowedTypes.includes(file.type)
+     ALLOWED_TYPES.includes(file.type)
    )
-   console.log(filteredFiles)
+   if (filteredFiles.length < files.length) {
+     alert('Only PNG images are allowed')
+   }
    return filteredFiles
  }
📝 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.

  const [list, setList] = useState<FileItem[]>([])
  const ALLOWED_TYPES = ['image/png']
  const beforeUpload = async (files: File[]) => {
    const allowedTypes = ['image/png']
    const filteredFiles = Array.from(files).filter((file) =>
      ALLOWED_TYPES.includes(file.type)
    )
    if (filteredFiles.length < files.length) {
      alert('Only PNG images are allowed')
    }
    return filteredFiles
  }

16-27: ⚠️ Potential issue

Add error handling and cleanup to upload function.

The current implementation has potential memory leaks and lacks error handling:

  1. Object URLs should be revoked when no longer needed
  2. No file size validation
  3. Missing error handling for URL.createObjectURL

Here's a suggested improvement:

+ const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
  async function upload(file: File) {
+   if (file.size > MAX_FILE_SIZE) {
+     throw new Error('File size exceeds 5MB limit');
+   }
    await sleep(2000)
+   try {
+     const url = URL.createObjectURL(file)
      return {
-       url: URL.createObjectURL(file),
+       url,
+       cleanup: () => URL.revokeObjectURL(url),
      }
+   } catch (error) {
+     throw new Error('Failed to process file');
+   }
  }
📝 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.

  const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
  function sleep(time: number) {
    return new Promise<void>((resolve) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }
  async function upload(file: File) {
    if (file.size > MAX_FILE_SIZE) {
      throw new Error('File size exceeds 5MB limit');
    }
    await sleep(2000)
    try {
      const url = URL.createObjectURL(file)
      return {
        url,
        cleanup: () => URL.revokeObjectURL(url),
      }
    } catch (error) {
      throw new Error('Failed to process file');
    }
  }
src/packages/uploader/demos/taro/demo5.tsx (1)

23-28: ⚠️ Potential issue

Add error handling and cleanup for Object URLs.

The current implementation might leak memory as Object URLs aren't being revoked. Also, error handling should be added.

Here's a suggested improvement:

 async function upload(file: File) {
   await sleep(2000)
+  try {
+    const url = URL.createObjectURL(file)
+    // In a real implementation, you would want to revoke the URL after it's no longer needed
+    // URL.revokeObjectURL(url)
     return {
-      url: URL.createObjectURL(file),
+      url,
     }
+  } catch (error) {
+    console.error('Failed to create object URL:', error)
+    throw new Error('Failed to process file')
+  }
 }

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demos/h5/demo9.tsx (5)

31-53: 🛠️ Refactor suggestion

Consider improvements for maintainability and internationalization.

A few suggestions to enhance the code:

  1. Consider extracting inline styles to a styled-component or CSS module
  2. Text content should be internationalized for better maintainability

Example approach:

const messages = {
  upload: '执行上传',
  clear: '手动清空上传'
}

const StyledCell = styled(Cell)`
  display: flex;
  flex-direction: column;
`

const ButtonContainer = styled.div`
  margin-bottom: 10px;
`

const UploadButton = styled(Button)`
  margin-inline-end: 10px;
`

18-23: ⚠️ Potential issue

Add cleanup for object URLs to prevent memory leaks.

The URL.createObjectURL creates a new object URL for each file, which should be revoked when no longer needed to prevent memory leaks.

Consider implementing cleanup:

 async function upload(file: File) {
   await sleep(2000)
+  const objectUrl = URL.createObjectURL(file)
+  // Add cleanup logic when the URL is no longer needed
+  setTimeout(() => URL.revokeObjectURL(objectUrl), 0)
   return {
-    url: URL.createObjectURL(file),
+    url: objectUrl,
   }
 }
📝 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.

  async function upload(file: File) {
    await sleep(2000)
    const objectUrl = URL.createObjectURL(file)
    // Add cleanup logic when the URL is no longer needed
    setTimeout(() => URL.revokeObjectURL(objectUrl), 0)
    return {
      url: objectUrl,
    }
  }

32-39: ⚠️ Potential issue

Convert maxCount to number type.

The maxCount prop is passed as a string but should be a number for better type safety.

 <Uploader
-  maxCount="5"
+  maxCount={5}
   multiple
   autoUpload={false}
   ref={uploadRef}
   upload={(file: File) => upload(file)}
   style={{ marginBottom: 10 }}
 />
📝 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.

      <Uploader
        maxCount={5}
        multiple
        autoUpload={false}
        ref={uploadRef}
        upload={(file: File) => upload(file)}
        style={{ marginBottom: 10 }}
      />

24-29: 🛠️ Refactor suggestion

Add null checks for safer ref handling.

The current implementation uses type assertion which could be unsafe. Consider adding null checks for better type safety.

 const submitUpload = () => {
-  ;(uploadRef.current as uploadRefState).submit()
+  if (uploadRef.current) {
+    uploadRef.current.submit()
+  }
 }

 const clearUpload = () => {
-  ;(uploadRef.current as uploadRefState).clear()
+  if (uploadRef.current) {
+    uploadRef.current.clear()
+  }
 }
📝 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.

  const submitUpload = () => {
    if (uploadRef.current) {
      uploadRef.current.submit()
    }
  }
  const clearUpload = () => {
    if (uploadRef.current) {
      uploadRef.current.clear()
    }
  }

11-17: 🛠️ Refactor suggestion

Consider moving utility functions outside component.

The sleep utility function is recreated on each render. Consider moving it outside the component or using useCallback if component-specific state is needed.

+const sleep = (time: number) => {
+  return new Promise<void>((resolve) => {
+    setTimeout(resolve, time)
+  })
+}

 const Demo9 = () => {
-  function sleep(time: number) {
-    return new Promise<void>((resolve) => {
-      setTimeout(() => {
-        resolve()
-      }, time)
-    })
-  }
📝 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.

const sleep = (time: number) => {
  return new Promise<void>((resolve) => {
    setTimeout(resolve, time)
  })
}

const Demo9 = () => {
src/packages/uploader/demos/taro/demo9.tsx (3)

31-53: 🛠️ Refactor suggestion

Consider these improvements for better maintainability.

  1. The maxCount prop should be a number instead of a string
  2. Consider extracting inline styles to a stylesheet
  3. Button text should be internationalized

Here's how you can improve it:

-      <Uploader
-        maxCount="5"
+      <Uploader
+        maxCount={5}
         multiple
         autoUpload={false}
         ref={uploadRef}
         upload={(file: File) => upload(file)}
-        style={{ marginBottom: 10 }}
+        className="demo-uploader"
       />

Consider creating a separate stylesheet:

.demo-uploader {
  margin-bottom: 10px;
}

And use i18n for button text:

-          执行上传
+          {t('upload.submit')}
-          手动清空上传
+          {t('upload.clear')}

24-29: ⚠️ Potential issue

Implement safer ref handling.

The current type assertions could throw runtime errors if the ref is null.

Consider adding null checks:

 const submitUpload = () => {
-  ;(uploadRef.current as uploadRefState).submit()
+  if (uploadRef.current) {
+    uploadRef.current.submit()
+  }
 }
 const clearUpload = () => {
-  ;(uploadRef.current as uploadRefState).clear()
+  if (uploadRef.current) {
+    uploadRef.current.clear()
+  }
 }
📝 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.

  const submitUpload = () => {
    if (uploadRef.current) {
      uploadRef.current.submit()
    }
  }
  const clearUpload = () => {
    if (uploadRef.current) {
      uploadRef.current.clear()
    }
  }

18-23: ⚠️ Potential issue

Add error handling and cleanup for URL.createObjectURL.

The upload function has two potential issues:

  1. No error handling for failed uploads
  2. URL.createObjectURL creates a memory leak if not revoked

Consider implementing this improved version:

 async function upload(file: File) {
-  await sleep(2000)
-  return {
-    url: URL.createObjectURL(file),
-  }
+  try {
+    await sleep(2000)
+    const objectUrl = URL.createObjectURL(file)
+    // Consider revoking the URL when the upload is cleared or component unmounts
+    return {
+      url: objectUrl,
+      onRemove: () => URL.revokeObjectURL(objectUrl),
+    }
+  } catch (error) {
+    console.error('Upload failed:', error)
+    throw new Error('Upload failed')
+  }
 }
📝 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.

  async function upload(file: File) {
    try {
      await sleep(2000)
      const objectUrl = URL.createObjectURL(file)
      // Consider revoking the URL when the upload is cleared or component unmounts
      return {
        url: objectUrl,
        onRemove: () => URL.revokeObjectURL(objectUrl),
      }
    } catch (error) {
      console.error('Upload failed:', error)
      throw new Error('Upload failed')
    }
  }
src/packages/uploader/demos/h5/demo1.tsx (2)

17-23: 🛠️ Refactor suggestion

Consider moving the sleep utility to a shared utilities file.

The sleep function is a generic utility that could be useful across multiple demos. Consider moving it to a shared utilities file to promote code reuse.

+// src/packages/shared/utils.ts
+export function sleep(time: number): Promise<void> {
+  return new Promise<void>((resolve) => {
+    setTimeout(resolve, time)
+  })
+}

-  function sleep(time: number) {
-    return new Promise<void>((resolve) => {
-      setTimeout(() => {
-        resolve()
-      }, time)
-    })
-  }

Committable suggestion was skipped due to low confidence.


24-32: ⚠️ Potential issue

Address potential memory leak and improve error handling.

  1. The URL.createObjectURL creates a URL that should be revoked when no longer needed to prevent memory leaks.
  2. The error message in uploadFail could be more descriptive.
  3. Consider adding JSDoc comments to document the artificial delays.
+/**
+ * Simulates a successful file upload with a 2-second delay
+ * @param file The file to upload
+ * @returns A promise that resolves with the file URL
+ */
 async function upload(file: File) {
   await sleep(2000)
+  const url = URL.createObjectURL(file)
+  // TODO: Implement cleanup to revoke the URL when it's no longer needed
   return {
-    url: URL.createObjectURL(file),
+    url,
   }
 }

+/**
+ * Simulates a failed file upload with a 2-second delay
+ * @param file The file that failed to upload
+ * @throws Error with detailed message
+ */
 async function uploadFail(file: File): Promise<FileItem> {
   await sleep(2000)
-  throw new Error('Fail to upload')
+  throw new Error(`Failed to upload file: ${file.name}. Please try again.`)
 }
📝 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.

  /**
   * Simulates a successful file upload with a 2-second delay
   * @param file The file to upload
   * @returns A promise that resolves with the file URL
   */
  async function upload(file: File) {
    await sleep(2000)
    const url = URL.createObjectURL(file)
    // TODO: Implement cleanup to revoke the URL when it's no longer needed
    return {
      url,
    }
  }

  /**
   * Simulates a failed file upload with a 2-second delay
   * @param file The file that failed to upload
   * @throws Error with detailed message
   */
  async function uploadFail(file: File): Promise<FileItem> {
    await sleep(2000)
    throw new Error(`Failed to upload file: ${file.name}. Please try again.`)
src/packages/uploader/demos/taro/demo1.tsx (2)

24-31: 🛠️ Refactor suggestion

Improve upload function implementation.

Several improvements can be made to the upload function:

  1. The created Blob is never used
  2. Console.log should be removed from production code
  3. The hardcoded URL makes the Blob creation unnecessary
  async function upload(file: File) {
    await sleep(2000)
-   const blob = new Blob([file], { type: 'image/png' })
-   const url = URL.createObjectURL(blob)
-   console.log(url)
    return {
      url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
    }
  }
📝 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.

  async function upload(file: File) {
    await sleep(2000)
    return {
      url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
    }

40-46: 🛠️ Refactor suggestion

Enhance user feedback and accessibility.

The Uploader component could benefit from additional props to improve user experience:

  1. Add error message display
  2. Show loading states during upload
  3. Include accessibility attributes
  <Uploader
    uploadLabel="商品主图"
    value={list}
    onChange={setList}
    upload={(file: File) => upload(file)}
    style={uploaderStyle}
+   aria-label="Upload product main image"
+   onError={(err) => console.error(err)}
+   loading={false}
  />

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demos/h5/demo2.tsx (1)

46-51: 🛠️ Refactor suggestion

Consider enhancing the demo with more interactive features.

While the current implementation shows various file states, it could be more educational by demonstrating:

  1. Actual file upload handling
  2. Error validation
  3. Size/type restrictions

Consider adding these features:

 <Uploader
   defaultValue={defaultList}
   onDelete={onDelete}
   uploadIcon={<Dongdong />}
   maxCount={6}
+  maxSize={5 * 1024 * 1024}
+  accept="image/*"
+  onOversize={(file) => console.log('File too large:', file)}
+  onUpload={(file) => {
+    // Demo upload simulation
+    return new Promise((resolve) => {
+      setTimeout(() => resolve({ url: URL.createObjectURL(file) }), 1000)
+    })
+  }}
 />
📝 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.

    <Uploader
      defaultValue={defaultList}
      onDelete={onDelete}
      uploadIcon={<Dongdong />}
      maxCount={6}
      maxSize={5 * 1024 * 1024}
      accept="image/*"
      onOversize={(file) => console.log('File too large:', file)}
      onUpload={(file) => {
        // Demo upload simulation
        return new Promise((resolve) => {
          setTimeout(() => resolve({ url: URL.createObjectURL(file) }), 1000)
        })
      }}
    />
src/packages/uploader/demos/taro/demo2.tsx (2)

46-51: 🛠️ Refactor suggestion

Consider showcasing more Uploader features.

While the current demo effectively shows file status handling, consider enhancing it with additional features:

  • File type restrictions (accept prop)
  • File size limits (maxSize prop)
  • Custom validation rules

Example enhancement:

 <Uploader
   defaultValue={defaultList}
   onDelete={onDelete}
   uploadIcon={<Dongdong />}
   maxCount={6}
+  accept="image/*"
+  maxSize={5 * 1024 * 1024}
+  onOversize={(files) => console.log('File too large:', files)}
 />

Committable suggestion was skipped due to low confidence.


7-41: 💡 Codebase verification

Based on the search results, I can now provide a final response:

Consider using local assets from the repository for the demo

The search reveals that:

  1. The specific image URL 360buyimg.com is widely used across multiple demo files
  2. The repository already has a dedicated assets directory at src/sites/assets/images/ with many local images

Recommendations:

  • Store demo images in src/sites/assets/images/ alongside other local assets
  • Create a reusable demo assets constant file to maintain URLs in one place
  • Use relative imports to reference these local assets instead of external URLs

This will:

  • Prevent broken demos if external resources become unavailable
  • Improve load times and reliability
  • Follow the existing pattern of local asset usage seen in other parts of the codebase
🔗 Analysis chain

Consider using local assets for the demo.

The demo currently uses external image URLs which could lead to broken demos if the external resource becomes unavailable.

Let's check if these image URLs are used elsewhere in the codebase:

Consider:

  1. Using local demo assets to prevent external dependencies
  2. Creating a demo assets constant file to maintain URLs in one place
  3. Implementing proper error handling for image loading failures

Let me try a different search approach to verify the usage of these image URLs.

I'm searching for both the URL pattern across all files and checking if there are any local image assets already present in the repository. This will help us:

  1. Verify if these external URLs are used elsewhere
  2. Check if there are existing local assets we could potentially use instead
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the hardcoded image URL usage
rg "360buyimg.com" --type tsx --type ts

Length of output: 67


Script:

#!/bin/bash
# Search for the image URL pattern without file type restrictions
rg "360buyimg\.com"

# Also search for any demo-related image files in the repository
fd -e png -e gif -e jpg -e jpeg -e webp

Length of output: 73275

src/packages/uploader/demos/h5/demo10.tsx (3)

7-40: 🛠️ Refactor suggestion

Consider improving type safety and demo clarity.

A few suggestions to enhance the demo:

  1. Define an enum for file status values to ensure type safety
  2. Use more generic/English file names for better international understanding
  3. Consider using different mock URLs for each file to better demonstrate variety

Here's a suggested improvement:

enum FileStatus {
  SUCCESS = 'success',
  ERROR = 'error',
  UPLOADING = 'uploading'
}

const [list, setList] = useState<FileItem[]>([
  {
    name: 'document1.png',
    url: 'https://example.com/sample1.gif',
    status: FileStatus.SUCCESS,
    message: 'Upload successful',
  },
  // ... other items with different URLs and English text
])

58-70: ⚠️ Potential issue

Enhance component props and accessibility.

A few suggestions for improvement:

  1. maxCount should be a number, not a string
  2. Consider adding error handling feedback
  3. Add accessibility attributes for better user experience

Here's the suggested improvement:

 <Uploader
   upload={(file: File) => upload(file)}
   value={list}
   onChange={setList}
-  maxCount="10"
+  maxCount={10}
   multiple
   previewType="list"
   style={{ marginBottom: 20 }}
+  aria-label="File upload"
+  onError={(error) => console.error('Upload failed:', error)}
 >
-  <Button type="success" size="small">
+  <Button type="success" size="small" aria-label="Upload files">
     上传文件
   </Button>
 </Uploader>
📝 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.

    <Uploader
      upload={(file: File) => upload(file)}
      value={list}
      onChange={setList}
      maxCount={10}
      multiple
      previewType="list"
      style={{ marginBottom: 20 }}
      aria-label="File upload"
      onError={(error) => console.error('Upload failed:', error)}
    >
      <Button type="success" size="small" aria-label="Upload files">
        上传文件
      </Button>
    </Uploader>

41-55: ⚠️ Potential issue

Improve upload simulation reliability and resource management.

Several improvements could be made to the upload simulation:

  1. The 50% failure rate might be too high for demonstration purposes
  2. The error message could be more descriptive
  3. URL.createObjectURL creates a memory leak if not revoked

Here's the suggested fix:

 async function upload(file: File) {
   await sleep(2000)
-  if (Math.random() < 0.5) {
+  if (Math.random() < 0.2) { // 20% failure rate
+    throw new Error(`Failed to upload ${file.name}: Network error`)
+  }
+  const objectUrl = URL.createObjectURL(file)
+  // Add cleanup function to component
   return {
-    url: URL.createObjectURL(file),
+    url: objectUrl,
+    cleanup: () => URL.revokeObjectURL(objectUrl),
   }
-  }
-  throw new Error('Fail to upload')
 }

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demos/taro/demo10.tsx (2)

58-66: 🛠️ Refactor suggestion

Consider type improvements and consistent styling approach.

  1. The maxCount prop should be a number instead of a string
  2. Consider moving inline styles to a styling system for better maintainability
 <Uploader
   upload={(file: File) => upload(file)}
   value={list}
   onChange={setList}
-  maxCount="10"
+  maxCount={10}
   multiple
   previewType="list"
-  style={{ marginBottom: 20 }}
+  className="demo-uploader"
 >

Committable suggestion was skipped due to low confidence.


48-56: ⚠️ Potential issue

Fix potential memory leak with URL.createObjectURL.

The URL.createObjectURL creates a new object URL that persists until the document is unloaded. To prevent memory leaks, you should revoke the URL when it's no longer needed.

 async function upload(file: File) {
   await sleep(2000)
   if (Math.random() < 0.5) {
+    const objectUrl = URL.createObjectURL(file)
+    // Consider revoking the URL when the file is removed or component unmounts
     return {
-      url: URL.createObjectURL(file),
+      url: objectUrl,
     }
   }
-  throw new Error('Fail to upload')
+  throw new Error(`Failed to upload ${file.name}: Simulated random failure`)
 }

Committable suggestion was skipped due to low confidence.

src/packages/uploader/demo.taro.tsx (1)

57-78: 🛠️ Refactor suggestion

Consider using semantic HTML structure.

While the current structure works, using semantic HTML elements would improve accessibility and document outline.

-      <div className="demo bg-w">
+      <section className="demo bg-w">
-        <h2>{translated.basic}</h2>
+        <h2 id="basic">{translated.basic}</h2>
         <Demo1 />
+        <section aria-labelledby="basic">
+          <h3>{translated.uploadStatus}</h3>
           <Demo2 />
+        </section>
         /* ... other demos ... */
-      </div>
+      </section>

This change would:

  • Improve document structure with section elements
  • Add ARIA landmarks for better accessibility
  • Create a clearer content hierarchy

Committable suggestion was skipped due to low confidence.

src/packages/uploader/upload.ts (2)

49-58: ⚠️ Potential issue

Fix duplicate success callback and add proper error handling.

There are several issues in the XHR response handling:

  1. The success callback is incorrectly called twice (lines 49 and 53)
  2. Missing timeout error handling
  3. No cleanup of event listeners

Apply this diff to fix these issues:

-    options.onSuccess?.(xhr.responseText, options)
     xhr.onreadystatechange = () => {
       if (xhr.readyState === 4) {
         if (xhr.status === options.xhrState) {
           options.onSuccess?.(xhr.responseText, options)
         } else {
           options.onFailure?.(xhr.responseText, options)
         }
       }
     }
+    xhr.ontimeout = () => {
+      options.onFailure?.('Upload timeout', options)
+    }
+    xhr.onerror = () => {
+      options.onFailure?.('Network error', options)
+    }
📝 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.

    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        if (xhr.status === options.xhrState) {
          options.onSuccess?.(xhr.responseText, options)
        } else {
          options.onFailure?.(xhr.responseText, options)
        }
      }
    }
    xhr.ontimeout = () => {
      options.onFailure?.('Upload timeout', options)
    }
    xhr.onerror = () => {
      options.onFailure?.('Network error', options)
    }

61-68: 🛠️ Refactor suggestion

Consider improving type safety and hook interface.

The current implementation could benefit from better type safety and a more structured hook interface.

Consider these improvements:

-  headers = {}
+  headers: Record<string, string> = {}

-  beforeXhrUpload?: any
+  beforeXhrUpload?: (xhr: XMLHttpRequest, options: UploadOptions) => boolean | void

   // In the upload method
-  if (options.beforeXhrUpload) {
-    options.beforeXhrUpload(xhr, options)
+  if (options.beforeXhrUpload && options.beforeXhrUpload(xhr, options) !== false) {
+    xhr.send(options.formData)
   } else {
     xhr.send(options.formData)
   }

This change:

  1. Adds proper typing for headers
  2. Improves the beforeXhrUpload hook interface with proper types
  3. Allows the hook to control whether the upload should proceed

Committable suggestion was skipped due to low confidence.

src/packages/uploader/preview.tsx (3)

17-17: 🛠️ Refactor suggestion

Consider using TypeScript enum or constants for status values.

Using string literals for status checks can be error-prone. Consider defining an enum or constants for status values to improve type safety and maintainability.

// Create a new file: src/packages/uploader/constants.ts
export enum UploaderStatus {
  ERROR = 'error',
  SUCCESS = 'success',
  READY = 'ready'
}

Then update the status check:

-if (item.status === 'error') {
+if (item.status === UploaderStatus.ERROR) {

49-62: 🛠️ Refactor suggestion

Extract progress rendering logic into a separate component.

The nested conditional rendering makes the code harder to read and maintain. Consider extracting this logic into a dedicated component.

interface ProgressProps {
  status: string
  message: string
  item: FileItem
}

const ProgressOverlay: React.FC<ProgressProps> = ({ status, message, item }) => {
  if (status === 'ready') {
    return (
      <div className="nut-uploader-preview-progress">
        <div className="nut-uploader-preview-progress-msg">{message}</div>
      </div>
    )
  }
  
  if (status !== 'success') {
    return (
      <div className="nut-uploader-preview-progress">
        {renderIcon(item)}
        <div className="nut-uploader-preview-progress-msg">{message}</div>
      </div>
    )
  }
  
  return null
}

Then use it in the main component:

-{status === 'ready' ? (
-  <div className="nut-uploader-preview-progress">
-    <div className="nut-uploader-preview-progress-msg">
-      {message}
-    </div>
-  </div>
-) : (
-  status !== 'success' && (
-    <div className="nut-uploader-preview-progress">
-      {renderIcon(item)}
-      <div className="nut-uploader-preview-progress-msg">
-        {message}
-      </div>
-    </div>
-  )
-)}
+<ProgressOverlay status={status} message={message} item={item} />

109-113: 🛠️ Refactor suggestion

Improve className handling and component styling.

Two suggestions for improvement:

  1. Validate status before using it in className to prevent invalid CSS classes.
  2. Consider moving the spacing after LinkIcon to CSS.
-className={`nut-uploader-preview-img-file-name ${status}`}
+className={`nut-uploader-preview-img-file-name ${status || ''}`}

-<LinkIcon />
-<span>&nbsp;{name}</span>
+<LinkIcon className="nut-uploader-preview-img-file-icon" />
+<span>{name}</span>

Add to your CSS:

.nut-uploader-preview-img-file-icon {
  margin-right: 0.25em;
}
src/packages/uploader/preview.taro.tsx (2)

8-10: 🛠️ Refactor suggestion

Add proper TypeScript types for component props.

The component is using any type which reduces type safety. Consider creating a proper interface for the props:

interface PreviewProps {
  fileList: FileItem[]
  previewType: 'picture' | 'list'
  deletable?: boolean
  onDeleteItem: (item: FileItem, index: number) => void
  handleItemClick: (item: FileItem, index: number) => void
  previewUrl?: string
  deleteIcon?: React.ReactNode
  children?: React.ReactNode
}

export const Preview: React.FunctionComponent<PreviewProps> = ({...})

Also applies to: 13-20


23-23: 🛠️ Refactor suggestion

Consider using an enum for file status.

Using string literals for status values could lead to typos. Consider defining an enum:

export enum FileStatus {
  Ready = 'ready',
  Success = 'success',
  Error = 'error'
}

// Then use it in the FileItem interface and comparisons:
interface FileItem {
  status: FileStatus
  // ...other properties
}

// In the component:
if (item.status === FileStatus.Error)

Also applies to: 34-41

src/packages/uploader/doc.taro.md (1)

109-109: ⚠️ Potential issue

Fix markdown formatting in URLs.

There are some formatting issues in the documentation links:

  1. Line 109: Remove the extra quotation mark in the capture property link
  2. Line 114: Fix the URL formatting in the accept property description

Apply these changes:

-[选取模式](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#htmlattrdefcapture")
+[选取模式](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#htmlattrdefcapture)
-[详细说明]("https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file#%E9%99%90%E5%88%B6%E5%85%81%E8%AE%B8%E7%9A%84%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B")
+[详细说明](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file#%E9%99%90%E5%88%B6%E5%85%81%E8%AE%B8%E7%9A%84%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B)

Also applies to: 114-114

🧰 Tools
🪛 LanguageTool

[typographical] ~109-~109: Símbolo desemparellado: Parece que falta «)»
Context: ...tring|picture` | | capture | 图片[选取模式](https://developer.mozilla.org/zh-CN/docs...

(UNPAIRED_BRACKETS)

src/packages/uploader/__tests__/uploader.spec.tsx (1)

209-209: ⚠️ Potential issue

Maintain type safety by using FileItem interface.

Using any type reduces type safety and could mask potential type-related issues. This contradicts TypeScript's benefits.

Replace with proper typing:

-  const list: any = {}
+  const list: FileItem = {
+    name: '文件1.png',
+    url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
+    status: 'ready',
+    message: '准备上传',
+    type: 'image',
+    uid: '12'
+  }
📝 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.

  const list: FileItem = {
    name: '文件1.png',
    url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
    status: 'ready',
    message: '准备上传',
    type: 'image',
    uid: '12'
  }
src/packages/uploader/doc.en-US.md (4)

141-145: ⚠️ Potential issue

Fix Methods table formatting.

The table has formatting issues and redundant column separators.

Apply these corrections:

| MethodName | Description | Parameters | ReturnValues |
-| --- | --- | --- | --- | --- | submit | Manual upload mode
+| --- | --- | --- | --- |
| submit | Manual upload mode, performs the upload operation | `-` | `-` |
📝 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.

The Uploader instance can be retrieved by ref and the instance methods called.
| MethodName | Description | Parameters | ReturnValues |
| --- | --- | --- | --- |
| submit | Manual upload mode, performs the upload operation | `-` | `-` |
| clear | Clear the queue of selected files (this method is usually used when uploading in manual mode) | `index` | `-` |

151-151: ⚠️ Potential issue

Fix broken ConfigProvider component link.

The link to the ConfigProvider component is broken.

Update the link to use the correct fragment:

-The component provides the following CSS variables that can be used to customize styles, see [ConfigProvider component](#/zh-CN/component/configprovider).
+The component provides the following CSS variables that can be used to customize styles, see [ConfigProvider component](/zh-CN/component/configprovider).
📝 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.

The component provides the following CSS variables that can be used to customize styles, see [ConfigProvider component](/zh-CN/component/configprovider).
🧰 Tools
🪛 Markdownlint

151-151: null
Link fragments should be valid

(MD051, link-fragments)


129-137: ⚠️ Potential issue

Clean up FileItem interface table.

There are duplicated entries and formatting issues in the table:

Remove duplicated content:

-| uid | Unique identifier of the file | `-` | name | File name.
-| name | File name | `-` | url | Path to file
-| url | file path | `-` | uid | unique identifier for the file | `-` | name | file name | `-` | url | file path | `-` | type | file type
+| uid | Unique identifier of the file | `-` |
+| name | File name | `-` |
+| url | File path | `-` |
+| type | File type | `image` |
📝 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.

| Name | Description | Default Value |
| --- | --- | --- | status | File status value.
| status | File status value, optionally 'ready,uploading,success,error' | `ready` |
| uid | Unique identifier of the file | `-` |
| name | File name | `-` |
| url | File path | `-` |
| type | File type | `image` |
| loadingIcon | Loading Icon | `-` |
| failIcon | failureIcon | `-` |

94-123: ⚠️ Potential issue

Improve props table grammar and clarity.

Several property descriptions need grammatical improvements:

  1. Replace "If or not" with "Whether" for consistency (autoUpload, clearInput)
  2. Improve clarity of the upload property description
  3. Add missing prepositions and fix punctuation

Apply these corrections:

-| autoUpload | If or not the upload will be done immediately after the file is selected, if false, you need to manually execute the ref submit method to upload | `Boolean` | `true` |
+| autoUpload | Whether to upload immediately after file selection. If false, manual execution of the ref submit method is required | `Boolean` | `true` |

-| upload | Upload method, input is the file object to be uploaded, after asynchronous processing, return the upload result | `(file: File) => Promise<FileItem>` | `-` |
+| upload | Upload method that takes a file object as input and returns a Promise with the upload result after processing | `(file: File) => Promise<FileItem>` | `-` |

-| clearInput | If or not you want to clear the `input` content, set it to `true` to support selecting the same file to upload over and over again | `boolean` | `true` |
+| clearInput | Whether to clear the `input` content. When true, allows repeated selection and upload of the same file | `boolean` | `true` |
📝 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.

| --- | --- | --- | --- | autoUpload | Whether to upload the file immediately after selecting it.
| autoUpload | Whether to upload immediately after file selection. If false, manual execution of the ref submit method is required | `Boolean` | `true` | upload | The upload method, the input parameter is the file to be uploaded.
| upload | Upload method that takes a file object as input and returns a Promise with the upload result after processing | `(file: File) => Promise<FileItem>` | `-` |
| name | The name of the `input` tag `name`, the name of the file parameter sent to the backend | `string` | `file` |
| defaultValue | Default list of files already uploaded | `FileItem[]` | `[]` |
| value | List of files that have been uploaded | `FileItem[]` | `-` |
| preview | Whether or not to show the preview image after a successful upload | `boolean` | `true` |
| previewUrl | Default image address when uploading non-image ('image') formats | `string` | `-` |
| deletable | Whether or not to show the delete button | `boolean` | `true` |
| method | The http method for the upload request | `string` | `post` | | previewType
| previewType | The built-in style of the uploaded list, two basic styles are supported picture, list | `string` | `picture` | picture [capture
| capture | Picture [selection mode] (https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#htmlattrdefcapture"), directly bring up the camera | `string` | `false` | maxFileSize
| maxFileSize | You can set the maximum file size (in bytes) for uploading | `number` \| `string` | `Number.MAX_VALUE` |
| maxCount | File upload count limit | `number` \| `string` | `1` |
| fit | Picture fill mode | `contain` \| `cover` \| `fill` \| `none` \| `scale-down` | `cover` |
| clearInput | Whether to clear the `input` content. When true, allows repeated selection and upload of the same file | `boolean` | `true` |
| accept | Allowed file types to be uploaded, [Details] ("https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file#%E9%99%90%E5%88%B6%E5%85%81%E8%AE% B8%E7%9A%84%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B") | `string` | `*` |
| uploadIcon | uploadRegion <a href="#/zh-CN/icon">Icon Name</a> | `React.ReactNode` | `-` |
| deleteIcon | Delete the icon name of the region | `React.ReactNode` | `-` |
| uploadLabel | Text below the image in the upload area | `React.
| multiple | Whether to support file multi-selection |`boolean`|`false`|
| disabled | Whether to disable file uploading |`boolean`|`false`|
| beforeUpload | The beforeUpload function needs to return a`Promise`object |`(file: File[]) => Promise<File[] \| boolean>`|`-`|
| beforeDelete | Callback when deleting a file, does not remove it if the return value is false. Supports returning a`Promise`object, which is not removed when resolve(false) or reject |`(file: FileItem, files: FileItem[]) => boolean`|`-`|
| onOversize | Triggered when file size exceeds limit |`(file: File[]) => void`|`-`|
| onOverCount | Triggered when the number of files exceeds the limit |`(count: number) => void`|`-`|
| onChange | Triggered when the list of uploaded files changes |`(files: FileItem[]) => void`|`-`|
| onDelete | Triggered when clicked to delete a file |`(file: FileItem, files: FileItem[]) => void`|`-`|
| onFileItemClick | Triggered when a file is uploaded successfully |`(file: FileItem, index: number) => void`|`-`|
| onUploadQueueChange | Triggered when the image upload queue changes |`(tasks: FileItem[]) => void`|`-` |
🧰 Tools
🪛 LanguageTool

[grammar] ~95-~95: This is a non-standard phrase. Did you mean “whether or not”?
Context: ...tely after selecting it. | autoUpload | If or not the upload will be done immediately aft...

(IF_OR_NOT)


[grammar] ~95-~95: Possibly, a comma is missing after an introductory clause, the verb inflection is not correct, or a question mark is missing. Did you mean “ref, submit” or “ref submits”?
Context: ...false, you need to manually execute the ref submit method to upload | Boolean | true |...

(IF_DT_NN_VBZ)


[uncategorized] ~95-~95: Possible missing preposition found.
Context: ... upload | Boolean | true | upload | The upload method, the input parameter is t...

(AI_HYDRA_LEO_MISSING_IN)


[style] ~100-~100: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...aded | FileItem[] | - | | preview | Whether or not to show the preview image after a succe...

(WHETHER)


[style] ~102-~102: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...ormats | string | - | | deletable | Whether or not to show the delete button | boolean |...

(WHETHER)


[grammar] ~109-~109: This is a non-standard phrase. Did you mean “whether or not”?
Context: ...scale-down | cover | | clearInput | If or not you want to clear the input content, ...

(IF_OR_NOT)

src/packages/uploader/demos/h5/demo3.tsx (1)

18-22: ⚠️ Potential issue

Potential memory leak due to unrevoked object URLs.

Using URL.createObjectURL(file) creates object URLs that can consume memory if not released. Consider revoking the object URLs when they are no longer needed to prevent memory leaks.

You can modify the code to revoke the object URL after it's used:

 async function upload(file: File) {
   await sleep(2000)
-  return {
-    url: URL.createObjectURL(file),
-  }
+  const url = URL.createObjectURL(file)
+  // Revoke the object URL when it's no longer needed
+  URL.revokeObjectURL(url)
+  return {
+    url: url,
+  }
 }

Alternatively, ensure that URL.revokeObjectURL(url) is called when the file is removed from the list.

Committable suggestion was skipped due to low confidence.

src/packages/uploader/uploader.tsx (2)

190-200: ⚠️ Potential issue

Fix overwriting of _files after beforeUpload

In the fileChange function, after assigning _files from beforeUpload, you overwrite it with filterFiles(new Array<File>().slice.call(files)), which ignores any modifications made by beforeUpload. This means that the filtered files from beforeUpload are not used.

To ensure that the files returned by beforeUpload are correctly processed, modify the code to pass _files to filterFiles:

let _files: File[] = []
if (beforeUpload) {
  _files = await beforeUpload(Array.from(files))
  if (!_files.length) $el.value = ''
} else {
  _files = Array.from(files)
}
-_files = filterFiles(new Array<File>().slice.call(files))
+_files = filterFiles(_files)
📝 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.

  const fileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
    if (disabled) return
    const $el = event.target
    const { files } = $el
    let _files: File[] = []
    if (beforeUpload) {
      _files = await beforeUpload(Array.from(files))
      if (!_files.length) $el.value = ''
    } else {
      _files = Array.from(files)
    }
    _files = filterFiles(_files)


201-227: ⚠️ Potential issue

Ensure fileList is updated for non-image files

Currently, fileList is only updated for image files when preview is true. Non-image files are not added to fileList, which means they won't appear in the upload list.

To fix this, update fileList for all files:

const tasks = _files.map((file) => {
  const info: any = {
    uid: idCountRef.current++,
    status: autoUpload ? 'uploading' : 'ready',
    file,
    message: autoUpload
      ? locale.uploader.uploading
      : locale.uploader.waitingUpload,
    name: file.name,
    type: file.type,
  }
  if (preview && file.type?.includes('image')) {
    const reader = new FileReader()
    reader.onload = (event: ProgressEvent<FileReader>) => {
      const fileItem = {
        ...info,
        url: (event.target as FileReader).result as string,
      }
      fileListRef.current = [...fileListRef.current, fileItem]
      setFileList(fileListRef.current)
    }
    reader.readAsDataURL(file)
  } else {
+   const fileItem = {
+     ...info,
+     url: '',
+   }
+   fileListRef.current = [...fileListRef.current, fileItem]
+   setFileList(fileListRef.current)
  }
  return info
})
📝 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.

    const tasks = _files.map((file) => {
      const info: any = {
        uid: idCountRef.current++,
        status: autoUpload ? 'uploading' : 'ready',
        file,
        message: autoUpload
          ? locale.uploader.uploading
          : locale.uploader.waitingUpload,
        name: file.name,
        type: file.type,
      }
      if (preview && file.type?.includes('image')) {
        const reader = new FileReader()
        reader.onload = (event: ProgressEvent<FileReader>) => {
          const fileItem = {
            ...info,
            url: (event.target as FileReader).result as string,
          }
          fileListRef.current = [...fileListRef.current, fileItem]
          setFileList(fileListRef.current)
        }
        reader.readAsDataURL(file)
      } else {
        const fileItem = {
          ...info,
          url: '',
        }
        fileListRef.current = [...fileListRef.current, fileItem]
        setFileList(fileListRef.current)
      }
      return info
    })
src/packages/uploader/uploader.taro.tsx (2)

377-386: ⚠️ Potential issue

Correct the usage of processed files after beforeUpload in onChangeImage

In the onChangeImage function, after calling beforeUpload, the files variable is assigned the result, but the original _files array is passed to readFile instead of the processed files. This may lead to issues if beforeUpload modifies the file list.

Apply this diff to use the processed files array correctly:

 let files = []
 if (beforeUpload) {
   files = await beforeUpload(new Array<File>().slice.call(_files))
-}
-files = filterFiles(new Array<File>().slice.call(_files))
-readFile(_files)
+  files = filterFiles(files)
+  if (!files.length) return
+  readFile(files)
 } else {
+  files = filterFiles(_files)
   readFile(files)
 }
📝 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.

  const onChangeImage = async (res: Taro.chooseImage.SuccessCallbackResult) => {
    // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
    const { tempFiles } = res
    const _files: Taro.chooseImage.ImageFile[] = filterFiles(tempFiles)
    let files = []
    if (beforeUpload) {
      files = await beforeUpload(new Array<File>().slice.call(_files))
      files = filterFiles(files)
      if (!files.length) return
      readFile(files)
    } else {
      files = filterFiles(_files)
      readFile(files)
    }

245-284: ⚠️ Potential issue

Improve error handling in the uploadAction function

In the uploadAction function, when an upload fails, the error is caught, but then it's re-thrown with throw e. This causes the entire Promise.all to reject, and the error is logged in the .catch block. Re-throwing the error after handling it may not be necessary and could lead to unhandled promise rejections.

Apply this diff to prevent re-throwing the error and handle it gracefully:

         } catch (e) {
           const list = fileListRef.current.map((item) => {
             if (item.uid === currentTask.uid) {
               item.status = 'error'
               item.message = locale.uploader.error
             }
             return item
           })
           setFileList(list)
-          throw e
         }
📝 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.

  const uploadAction = async (tasks: FileItem[]) => {
    const taskIds = tasks.map((task) => task.uid)
    setFileList(
      tasks.map((file: FileItem) => {
        if (taskIds.includes(file.uid)) {
          return {
            ...file,
            status: 'uploading',
            message: locale.uploader.uploading,
          }
        }
        return file
      })
    )
    await Promise.all(
      tasks.map(async (currentTask, index) => {
        try {
          const result = await upload(currentTask.file as File)
          const list = fileListRef.current.map((item) => {
            if (item.uid === currentTask.uid) {
              item.status = 'success'
              item.message = locale.uploader.success
              item.url = result.url
            }
            return item
          })
          setFileList(list)
        } catch (e) {
          const list = fileListRef.current.map((item) => {
            if (item.uid === currentTask.uid) {
              item.status = 'error'
              item.message = locale.uploader.error
            }
            return item
          })
          setFileList(list)
        }
      })
    ).catch((errs) => console.error(errs))

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Outside diff range and nitpick comments (9)
src/packages/uploader/demos/taro/demo4.tsx (1)

24-33: 建议添加无障碍支持

组件实现基本合理,但建议添加以下改进:

  1. 为上传组件添加 aria-label 属性
  2. 考虑添加上传状态的屏幕阅读器提示

建议修改如下:

  <Cell style={{ flexWrap: 'wrap' }}>
    <Uploader
      value={list}
      onChange={setList}
      upload={(file: File) => upload(file)}
      multiple
      maxFileSize={1024 * 50}
      onOversize={onOversize}
+     aria-label="文件上传"
+     role="button"
    />
  </Cell>
src/packages/uploader/demos/taro/demo3.tsx (1)

14-20: 建议优化sleep函数的实现

sleep函数可以添加参数类型约束和默认值,以提高代码的健壮性。

-  function sleep(time: number) {
+  function sleep(time: number = 1000): Promise<void> {
     return new Promise<void>((resolve) => {
       setTimeout(() => {
         resolve()
       }, time)
     })
   }
src/packages/uploader/demos/taro/demo5.tsx (1)

6-14: 建议移除调试代码

代码中的 console.log 语句应该在生产环境中移除。

建议应用以下修改:

  const beforeUpload = async (files: File[]) => {
    const allowedTypes = ['image/png']
    const filteredFiles = Array.from(files).filter((file) =>
      allowedTypes.includes(file.type)
    )
-   console.log(filteredFiles)
    return filteredFiles
  }
src/packages/uploader/demo.taro.tsx (1)

19-21: 建议优化翻译文案的具体性

翻译文案有以下几点可以改进:

  1. "限制上传数量" 建议添加默认限制数量,使用户更清晰了解限制
  2. "自定义上传前的处理" 可以更具体说明可以处理什么,比如文件大小、类型等

建议修改如下:

-      limitedQuantity: '限制上传数量',
+      limitedQuantity: '限制上传数量(默认最多5个)',
-      beforeUpload: '自定义上传前的处理',
+      beforeUpload: '上传前自定义处理(大小、类型等)',

Also applies to: 30-32, 41-42

src/packages/uploader/demos/taro/demo9.tsx (1)

7-40: 建议改进示例数据的真实性

当前的示例数据有以下可以改进的地方:

  1. 文件名可以更贴近真实场景(如:"产品图片.jpg","用户头像.png")
  2. URL 地址都使用了相同的图片
  3. 建议展示更多样的文件类型(如:PDF、DOC等)
src/packages/uploader/uploader.taro.tsx (4)

82-87: 重构:上传处理机制的重大改进

通过将HTTP上传逻辑从组件中分离出来,新的upload方法提供了更灵活的上传实现方式。这种设计允许开发者:

  • 自定义上传逻辑
  • 更好地处理不同平台的上传需求
  • 实现更复杂的上传场景(如分片上传)

建议在文档中提供一些常见上传实现的示例代码,特别是针对不同平台(H5、小程序等)的实现方案。


166-166: 优化:引入上传队列管理机制

新增的上传队列管理提供了更好的上传控制:

  • 支持手动触发上传
  • 提供队列清理机制
  • 实现了自动上传和手动上传的分离

建议添加以下功能增强:

  • 上传队列状态变化的回调
  • 队列暂停/恢复的控制方法
  • 上传进度的批量监控

Also applies to: 171-172, 313-317


Line range hint 279-311: 注意:文件处理逻辑需要优化

当前实现存在以下问题:

  1. idCountRef 计数器可能在组件重新挂载时重置
  2. 文件类型检测依赖文件扩展名,可能不够准确
  3. 状态更新可能存在竞态条件

建议进行如下修改:

- const idCountRef = useRef(0)
+ const idCountRef = useRef(Date.now())
  const readFile = async <T extends TFileType>(files: T[]) => {
+   const currentFileList = [...fileListRef.current]
    const tasks = files.map((file) => {
      // ... existing code ...
    })
-   fileListRef.current = [...fileListRef.current, info]
-   setFileList(fileListRef.current)
+   const newFileList = [...currentFileList, info]
+   fileListRef.current = newFileList
+   setFileList(newFileList)

Line range hint 392-431: 建议:改进上传组件的可访问性和用户体验

上传按钮和预览区域的实现需要考虑以下几点:

  1. 缺少键盘访问支持
  2. 缺少适当的 ARIA 属性
  3. 上传状态的视觉反馈不够明显

建议进行如下改进:

  <View
    className={`nut-uploader-upload ${previewType} ${
      disabled ? 'nut-uploader-upload-disabled' : ''
    }`}
+   role="button"
+   tabIndex={disabled ? -1 : 0}
+   aria-label={locale.uploader.uploadText}
  >
    <View className="nut-uploader-icon">
      {uploadIcon}
-     <span className="nut-uploader-icon-tip">{uploadLabel}</span>
+     <span className="nut-uploader-icon-tip" aria-hidden="true">
+       {uploadLabel}
+     </span>
    </View>
    <Button 
      className="nut-uploader-input" 
      onClick={_chooseImage}
+     aria-hidden="true"
    />
  </View>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2334e78 and 2983242.

📒 Files selected for processing (9)
  • src/packages/uploader/demo.taro.tsx (2 hunks)
  • src/packages/uploader/demos/taro/demo1.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo10.tsx (0 hunks)
  • src/packages/uploader/demos/taro/demo3.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo4.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo5.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo8.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo9.tsx (1 hunks)
  • src/packages/uploader/uploader.taro.tsx (11 hunks)
💤 Files with no reviewable changes (1)
  • src/packages/uploader/demos/taro/demo10.tsx
🧰 Additional context used
📓 Learnings (1)
src/packages/uploader/demos/taro/demo1.tsx (1)
Learnt from: Alex-huxiyang
PR: jdf2e/nutui-react#2416
File: src/packages/uploader/uploader.taro.tsx:230-230
Timestamp: 2024-07-05T02:58:57.992Z
Learning: When changes are made to the `fileList` state in the `src/packages/uploader/uploader.taro.tsx` file, ensure to generate unit tests to cover these changes.
🔇 Additional comments (8)
src/packages/uploader/demos/taro/demo4.tsx (1)

1-6: 代码结构清晰,状态管理符合最佳实践!

使用 useState 管理文件列表状态是一个很好的选择,这样可以确保组件的响应式更新。

src/packages/uploader/demos/taro/demo3.tsx (1)

1-3: 导入声明看起来简洁明了

导入语句组织得当,只引入必要的依赖项。

src/packages/uploader/demos/taro/demo5.tsx (2)

1-3: 导入声明看起来很清晰!

导入声明简洁明了,依赖项引用恰当。


29-36: 组件渲染实现清晰简洁!

组件结构合理,属性传递正确,代码易于理解和维护。

src/packages/uploader/demos/taro/demo1.tsx (1)

10-14: 需要添加文件列表状态管理的单元测试

根据之前的经验,对fileList状态的更改需要相应的单元测试覆盖。建议添加以下测试场景:

  • 初始状态验证
  • 文件列表更新
  • 边界条件处理
src/packages/uploader/demos/taro/demo8.tsx (1)

1-7: 代码结构清晰,类型定义准确!

接口定义简洁明了,很好地定义了上传组件的引用类型。

src/packages/uploader/demo.taro.tsx (1)

53-72: 布局结构优化合理,代码更易维护

代码改动要点:

  1. 从 Taro 特定组件改为标准 HTML 元素,提高了代码的通用性
  2. Demo 组件排序逻辑清晰,从基础用法到进阶特性
  3. 布局结构简化,提高了可维护性
src/packages/uploader/demos/taro/demo9.tsx (1)

1-4: 导入声明看起来很合理!

组件导入和类型声明都很清晰,使用了必要的图标和组件。

src/packages/uploader/demos/taro/demo1.tsx Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
src/packages/uploader/uploader.taro.tsx (2)

Line range hint 280-317: 建议:优化文件处理逻辑

当前实现在文件类型判断和状态管理上有以下可优化点:

  1. 文件类型判断可以抽取为独立函数
  2. 状态更新可以优化以减少重渲染

建议如下优化:

+ const getFileType = (file: TFileType, filepath: string): string => {
+   if (file.fileType) return file.fileType
+   if (file.type) return file.type
+   const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i
+   return (imgReg.test(filepath) || filepath.includes('data:image')) 
+     ? 'image' 
+     : 'unknown'
+ }

  const readFile = async <T extends TFileType>(files: T[]) => {
    const tasks = files.map((file) => {
      const filepath = (file.tempFilePath || file.path) as string
-     let fileType = file.type
-     if (file.fileType) {
-       fileType = file.fileType
-     } else {
-       const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i
-       if (
-         !fileType &&
-         (imgReg.test(filepath) || filepath.includes('data:image'))
-       ) {
-         fileType = 'image'
-       }
-     }
+     const fileType = getFileType(file, filepath)
      // ... rest of the code
    })
  }

Line range hint 386-422: 建议:优化渲染性能

渲染逻辑拆分得很清晰,但建议进行以下优化:

  1. 使用useMemo缓存渲染结果
  2. 避免不必要的重复计算
+ const memoizedListUploader = useMemo(() => {
    return (
      (children || previewType === 'list') && (
        <View className="nut-uploader-slot">
          {/* ... existing code ... */}
        </View>
      )
    )
+ }, [children, previewType, maxCount, fileList.length, locale])

+ const memoizedImageUploader = useMemo(() => {
    return (
      Number(maxCount) > fileList.length &&
      previewType === 'picture' &&
      !children && (
        <View className={`nut-uploader-upload ${previewType} ${
          disabled ? 'nut-uploader-upload-disabled' : ''
        }`}>
          {/* ... existing code ... */}
        </View>
      )
    )
+ }, [maxCount, fileList.length, previewType, children, disabled, uploadIcon, uploadLabel])

  const renderListUploader = () => memoizedListUploader
  const renderImageUploader = () => memoizedImageUploader
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2983242 and 563e918.

📒 Files selected for processing (1)
  • src/packages/uploader/uploader.taro.tsx (11 hunks)
🔇 Additional comments (1)
src/packages/uploader/uploader.taro.tsx (1)

82-87: 接口重构提升了组件的灵活性和可扩展性

通过移除硬编码的上传配置(如url、timeout等),改为提供upload方法,使组件更容易适应不同的上传场景和需求。

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (6)
src/packages/uploader/demos/h5/demo5.tsx (1)

28-35: 建议增加无障碍支持

上传组件缺少适当的 ARIA 属性和标签说明。建议添加无障碍支持以提升用户体验。

 <Cell style={{ flexWrap: 'wrap' }}>
   <Uploader
+    aria-label="上传PNG图片"
+    title="选择文件"
     value={list}
     onChange={setList}
     beforeUpload={beforeUpload}
     upload={(file: File) => upload(file)}
   />
 </Cell>
src/packages/uploader/demos/taro/demo5.tsx (1)

14-20: 建议将工具函数移至共享文件

sleep 函数是一个通用的工具函数,建议将其移动到专门的工具文件中,以便在其他组件中复用。

建议创建一个 utils/async.ts 文件来存放这类异步工具函数。

src/packages/uploader/doc.taro.md (2)

92-92: 建议补充 FileItem 类型说明

upload 方法返回值和 defaultValue/value 属性都使用了 FileItem 类型,建议在属性说明中添加对 FileItem 类型的引用链接,方便用户查阅完整的类型定义。

Also applies to: 94-95


Line range hint 138-143: 建议添加方法使用示例

Methods 部分的说明简洁明了,建议添加一个简单的代码示例来展示如何使用 ref 调用这些方法。

建议添加如下示例:

const uploaderRef = useRef<any>()

// 手动上传
const handleSubmit = () => {
  uploaderRef.current?.submit()
}

// 清空文件队列
const handleClear = () => {
  uploaderRef.current?.clear()
}
🧰 Tools
🪛 LanguageTool

[locale-violation] ~104-~104: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ...-down|cover | | clearInput | 是否需要清空input内容,设为true支持重复选择上传同一个文件 | boolean` | ...

(GL_BARBARISM_REPLACE)


[grammar] ~118-~118: 'album' é un erro. Considere utilizar "álbum"
Context: ...video/wx.chooseMedia.html") | Array | ['album','camera'] | | camera仅支持WEAPP | 仅在 `...

(GL_WIKIPEDIA_COMMON_ERRORS)


[locale-violation] ~121-~121: 'mix' é un xenismo. É preferíbel dicir "mestura"
Context: ...video/wx.chooseMedia.html") | Array | ['image', 'video', 'mix'] | | maxDuration仅支持WEAPP | 拍摄视频最长拍摄...

(GL_BARBARISM_REPLACE)


[locale-violation] ~128-~128: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名称 | 说明 | 默认值 | | --- | --- | --- | | status | 文件状态值,可选'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~128-~128: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件状态值,可选'ready,uploading,success,error' | ready | | uid | 文件的唯一标识 | - | | n...

(UNPAIRED_BRACKETS)

src/packages/uploader/uploader.taro.tsx (2)

Line range hint 286-323: 建议优化文件处理逻辑

当前实现可以考虑以下优化:

  1. 文件类型检测可以更完善,建议添加更多文件类型的支持
  2. 文件状态可以更细化,比如添加 validating 状态
  3. 考虑添加文件大小的格式化显示

建议参考如下改进:

  const readFile = async <T extends TFileType>(files: T[]) => {
    const tasks = files.map((file) => {
      let fileType = file.type
      const filepath = (file.tempFilePath || file.path) as string
+     const formatSize = (size: number) => {
+       if (size < 1024) return size + 'B'
+       if (size < 1024 * 1024) return (size / 1024).toFixed(2) + 'KB'
+       return (size / 1024 / 1024).toFixed(2) + 'MB'
+     }
      if (file.fileType) {
        fileType = file.fileType
      } else {
-       const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i
+       const imgReg = /\.(png|jpeg|jpg|webp|gif|bmp|svg)$/i
+       const videoReg = /\.(mp4|webm|ogg|mov)$/i
        if (
          !fileType &&
          (imgReg.test(filepath) || filepath.includes('data:image'))
        ) {
          fileType = 'image'
        }
+       if (!fileType && videoReg.test(filepath)) {
+         fileType = 'video'
+       }
      }
      const info: any = {
        uid: idCountRef.current++,
-       status: autoUpload ? 'uploading' : 'ready',
+       status: autoUpload ? 'validating' : 'ready',
        file,
        message: autoUpload
-         ? locale.uploader.uploading
+         ? locale.uploader.validating
          : locale.uploader.waitingUpload,
        name: getEnv() === 'WEB' ? file.originalFileObj?.name : filepath,
        path: filepath,
        type: getEnv() === 'WEB' ? file.originalFileObj?.type : fileType,
+       size: formatSize(file.size),
      }

Line range hint 392-444: 建议优化UI渲染和可访问性

当前UI实现可以考虑以下改进:

  1. 添加适当的 ARIA 属性以提升可访问性
  2. 使用更语义化的 HTML 结构
  3. 添加更多的类型安全保护

建议参考如下改进:

  const renderListUploader = () => {
    return (
      (children || previewType === 'list') && (
-       <View className="nut-uploader-slot">
+       <View 
+         className="nut-uploader-slot"
+         role="region"
+         aria-label={locale.uploader.uploadFiles}
+       >
          <>
            {children || (
              <Button 
                size="small" 
                type="primary"
+               aria-label={locale.uploader.uploadFiles}
              >
                {locale.uploader.list}
              </Button>
            )}
            {Number(maxCount) > fileList.length && (
              <Button 
                className="nut-uploader-input" 
                onClick={_chooseImage}
+               aria-label={locale.uploader.selectFiles} 
              />
            )}
          </>
        </View>
      )
    )
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 563e918 and c2cb152.

📒 Files selected for processing (4)
  • src/packages/uploader/demos/h5/demo5.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo5.tsx (1 hunks)
  • src/packages/uploader/doc.taro.md (3 hunks)
  • src/packages/uploader/uploader.taro.tsx (13 hunks)
🧰 Additional context used
🪛 LanguageTool
src/packages/uploader/doc.taro.md

[locale-violation] ~93-~93: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ... => Promise|-| | name |input标签name的名称,发到后台的文件参数名 |string` | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~104-~104: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ...-down|cover | | clearInput | 是否需要清空input内容,设为true支持重复选择上传同一个文件 | boolean` | ...

(GL_BARBARISM_REPLACE)


[grammar] ~118-~118: 'album' é un erro. Considere utilizar "álbum"
Context: ...video/wx.chooseMedia.html") | Array | ['album','camera'] | | camera仅支持WEAPP | 仅在 `...

(GL_WIKIPEDIA_COMMON_ERRORS)


[locale-violation] ~121-~121: 'mix' é un xenismo. É preferíbel dicir "mestura"
Context: ...video/wx.chooseMedia.html") | Array | ['image', 'video', 'mix'] | | maxDuration仅支持WEAPP | 拍摄视频最长拍摄...

(GL_BARBARISM_REPLACE)


[locale-violation] ~128-~128: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名称 | 说明 | 默认值 | | --- | --- | --- | | status | 文件状态值,可选'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~128-~128: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件状态值,可选'ready,uploading,success,error' | ready | | uid | 文件的唯一标识 | - | | n...

(UNPAIRED_BRACKETS)

🔇 Additional comments (8)
src/packages/uploader/demos/h5/demo5.tsx (2)

1-3: 导入声明看起来很清晰!

所有必要的依赖项都已正确导入,没有多余的引用。


6-6: 状态管理实现清晰简洁

使用 useState 管理文件列表,类型定义准确。

src/packages/uploader/demos/taro/demo5.tsx (2)

1-3: 导入声明看起来很清晰!

导入语句简洁明了,只引入了必要的依赖项。


21-25: 此问题在之前的代码审查中已经提出

关于硬编码的延迟时间和图片URL的改进建议仍然有效。

src/packages/uploader/doc.taro.md (2)

21-77: 示例部分结构优化

示例部分的重组更加清晰地展示了组件的各种功能,新增的限制上传数量和大小的示例也很有帮助。


Line range hint 160-169: 主题定制部分完善

CSS 变量定义清晰完整,覆盖了组件的主要样式定制需求。

🧰 Tools
🪛 LanguageTool

[locale-violation] ~157-~157: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...的border圆角 | 4px | | --nutui-uploader-background | 上传图片的背景颜色 | $color-background | | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~157-~157: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...nutui-uploader-background | 上传图片的背景颜色 | $color-background | | --nutui-uploader-background-disab...

(GL_BARBARISM_REPLACE)


[locale-violation] ~158-~158: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...color-background| | \--nutui-uploader-background-disabled | 上传图片禁用状态的背景颜色 |$color-back...

(GL_BARBARISM_REPLACE)


[locale-violation] ~158-~158: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...r-background-disabled | 上传图片禁用状态的背景颜色 | $color-background | | --nutui-uploader-image-icon-tip-f...

(GL_BARBARISM_REPLACE)


[locale-violation] ~161-~161: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ... | | --nutui-uploader-preview-progress-background | 上传区域预览进度的背景颜色 | rgba(0, 0, 0, 0.65)...

(GL_BARBARISM_REPLACE)

src/packages/uploader/uploader.taro.tsx (2)

81-91: 接口设计更加清晰和可控

新的接口设计有以下改进:

  1. 移除了具体的上传配置(如 url、headers 等),改为提供 upload 方法,使组件更加灵活
  2. 添加了 onOverCount 回调,优化了文件数量限制的处理
  3. 新增 onUploadQueueChange 回调,方便跟踪上传队列状态

244-282: 🛠️ Refactor suggestion

建议增强上传过程的错误处理和状态管理

当前实现可以进一步优化:

  1. 添加重试机制,提高上传可靠性
  2. 增加上传进度回调
  3. 完善错误信息展示,包含具体错误信息而不是通用错误提示

建议参考如下改进:

  const uploadAction = async (tasks: FileItem[]) => {
    const taskIds = tasks.map((task) => task.uid)
    const list: FileItem[] = fileListRef.current.map((file: FileItem) => {
      if (taskIds.includes(file.uid)) {
        return {
          ...file,
          status: 'uploading',
          message: locale.uploader.uploading,
        }
      }
      return file
    })
    setFileList(list)
    await Promise.all(
      tasks.map(async (currentTask, index) => {
+       let retryCount = 0
+       const maxRetries = 3
+       while (retryCount < maxRetries) {
          try {
-           const result = await upload(currentTask.file as File)
+           const result = await upload(currentTask.file as File).catch((e) => {
+             throw new Error(`上传失败: ${e.message}`)
+           })
            const list = fileListRef.current.map((item) => {
              if (item.uid === currentTask.uid) {
                item.status = 'success'
                item.message = locale.uploader.success
                item.url = result.url
              }
              return item
            })
            setFileList(list)
+           break
          } catch (e) {
+           retryCount++
+           if (retryCount === maxRetries) {
              const list = fileListRef.current.map((item) => {
                if (item.uid === currentTask.uid) {
                  item.status = 'error'
-                 item.message = locale.uploader.error
+                 item.message = e.message || locale.uploader.error
                }
                return item
              })
              setFileList(list)
+             throw e
            }
+           await new Promise(resolve => setTimeout(resolve, 1000 * retryCount))
          }
+       }
      })
-   ).catch((errs) => console.error(errs))
+   ).catch((errs) => {
+     console.error('上传失败:', errs)
+     props.onError?.(errs)
+   })
  }

Likely invalid or redundant comment.

src/packages/uploader/demos/taro/demo5.tsx Show resolved Hide resolved
@Alex-huxiyang Alex-huxiyang changed the title refactor(uploader): Upoader 3.0 refactor(uploader): Upoader 3.0 重构 & 多端适配 Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
@jdf2e jdf2e deleted a comment from coderabbitai bot Oct 25, 2024
src/packages/uploader/demos/h5/demo1.tsx Outdated Show resolved Hide resolved
src/packages/uploader/index.ts Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
src/packages/uploader/types.ts (1)

1-21: 建议为类型定义添加详细的文档注释

FileItem 接口定义了上传文件的核心数据结构,建议为每个属性添加 JSDoc 注释以提高代码可维护性。例如:

 export type FileItem = {
+  /** 文件上传状态 */
   status?: FileItemStatus
 
+  /** 状态信息或错误消息 */
   message?: string
 
+  /** 文件唯一标识符 */
   uid?: string | number
   // ... 其他属性
 }
src/packages/uploader/uploader.taro.tsx (2)

Line range hint 284-321: 建议优化文件读取逻辑

当前实现存在以下问题:

  1. 文件类型判断逻辑可以提取为独立函数
  2. 状态更新可能导致性能问题
  3. 缺少文件大小和类型的预检查

建议改进:

+const getFileType = (file: TFileType, filepath: string): string => {
+  if (file.fileType) return file.fileType
+  if (file.type) return file.type
+  const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i
+  return (imgReg.test(filepath) || filepath.includes('data:image'))
+    ? 'image'
+    : 'unknown'
+}

 const readFile = async <T extends TFileType>(files: T[]) => {
+  const validFiles = files.filter(validateFile)
   const tasks = files.map((file) => {
-    let fileType = file.type
     const filepath = (file.tempFilePath || file.path) as string
-    if (file.fileType) {
-      fileType = file.fileType
-    } else {
-      const imgReg = /\.(png|jpeg|jpg|webp|gif)$/i
-      if (!fileType && (imgReg.test(filepath) || filepath.includes('data:image'))) {
-        fileType = 'image'
-      }
-    }
+    const fileType = getFileType(file, filepath)

391-425: 建议优化渲染逻辑

建议将样式逻辑抽离为独立的工具函数,提高代码可维护性:

+const getUploaderClasses = (previewType: string, disabled: boolean) => {
+  return classNames('nut-uploader-upload', previewType, {
+    'nut-uploader-upload-disabled': disabled,
+  })
+}

 const renderImageUploader = () => {
   const shouldShow = Number(maxCount) > fileList.length && previewType === 'picture'
   return shouldShow && (
     <View
-      className={`nut-uploader-upload ${previewType} ${
-        disabled ? 'nut-uploader-upload-disabled' : ''
-      }`}
+      className={getUploaderClasses(previewType, disabled)}
     >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6d8ea36 and aafb914.

📒 Files selected for processing (6)
  • src/config.json (1 hunks)
  • src/packages/uploader/index.taro.ts (1 hunks)
  • src/packages/uploader/index.ts (1 hunks)
  • src/packages/uploader/types.ts (1 hunks)
  • src/packages/uploader/uploader.taro.tsx (10 hunks)
  • src/packages/uploader/uploader.tsx (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/packages/uploader/index.ts
  • src/packages/uploader/index.taro.ts
  • src/config.json
🔇 Additional comments (3)
src/packages/uploader/uploader.tsx (2)

190-236: ⚠️ Potential issue

文件处理逻辑需要加强错误处理和状态管理

当前实现存在以下问题:

  1. FileReader 缺少错误处理
  2. 状态更新可能存在竞态条件
  3. 文件处理逻辑较为复杂

建议改进:

 const reader = new FileReader()
+reader.onerror = (error) => {
+  console.error('文件读取失败:', error)
+  info.status = 'error'
+  info.message = locale.uploader.error
+  setFileList([...fileListRef.current])
+}

Likely invalid or redundant comment.


238-278: 🛠️ Refactor suggestion

建议优化上传错误处理机制

当前上传错误处理存在以下问题:

  1. 错误仅打印到控制台
  2. 缺少重试机制
  3. 没有并发控制

建议添加:

  1. 错误重试机制
  2. 上传并发限制
  3. 详细的错误反馈
 ).catch((errs) => {
-  console.error(errs)
+  const failedTasks = tasks.filter(task => {
+    const file = fileListRef.current.find(f => f.uid === task.uid)
+    return file?.status === 'error'
+  })
+  if (failedTasks.length > 0 && retryCount < maxRetries) {
+    setTimeout(() => uploadAction(failedTasks), retryDelay)
+  }
+  onError?.(errs)
 })

Likely invalid or redundant comment.

src/packages/uploader/uploader.taro.tsx (1)

242-280: ⚠️ Potential issue

建议增强错误处理和重试机制

上传处理逻辑存在以下问题:

  1. 错误处理过于简单
  2. 缺少重试机制
  3. 状态更新可能不同步

建议改进:

  1. 添加重试逻辑
  2. 优化错误反馈
  3. 使用 reducer 管理状态

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (5)
src/packages/uploader/demos/taro/demo8.tsx (1)

5-11: 建议将 sleep 函数移至共享工具文件

这个工具函数可能在其他演示文件中也会用到,建议将其提取到共享工具文件中以提高代码复用性。

+// src/packages/shared/utils.ts
+export function sleep(time: number) {
+  return new Promise<void>((resolve) => {
+    setTimeout(() => {
+      resolve()
+    }, time)
+  })
+}
src/packages/uploader/demos/taro/demo10.tsx (2)

6-39: 建议将URL提取为常量

建议将重复使用的图片URL提取为常量,这样可以:

  • 便于统一管理和修改
  • 减少代码重复
  • 提高可维护性
+const DEMO_IMAGE_URL = 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif'

61-61: maxCount 属性应该传入数字类型

当前 maxCount="10" 传入的是字符串类型,虽然在运行时会被自动转换,但建议直接使用数字类型以提高代码质量:

-maxCount="10"
+maxCount={10}
src/packages/uploader/demos/taro/demo9.tsx (2)

5-8: 建议添加接口文档注释

为了提高代码可维护性,建议为 uploadRefState 接口添加 JSDoc 文档注释,说明每个方法的用途和参数。

+/**
+ * 上传组件的引用状态接口
+ * @interface uploadRefState
+ */
 interface uploadRefState {
+  /** 提交上传队列中的文件 */
   submit: () => void
+  /** 清空上传队列 */
   clear: () => void
 }

32-54: 建议提升组件的可访问性和样式管理

当前组件缺少无障碍访问属性,且样式直接写在行内。

建议按照以下方式改进:

 <Cell style={{ display: 'flex', flexDirection: 'column' }}>
   <Uploader
     maxCount="5"
     multiple
     autoUpload={false}
     ref={uploadRef}
     upload={(file: File) => upload(file)}
     style={{ marginBottom: 10 }}
+    accept="image/*"
+    aria-label="文件上传区域"
+    data-testid="demo-uploader"
   />
   <View style={{ display: 'flex' }}>
     <Button
       type="success"
       size="small"
       onClick={submitUpload}
-      style={{ marginRight: '10px' }}
+      className="upload-action-btn"
+      aria-label="开始上传文件"
     >
       执行上传
     </Button>
     <Button 
       type="primary" 
       size="small" 
       onClick={clearUpload}
+      className="upload-clear-btn"
+      aria-label="清空上传列表"
     >
       手动清空上传
     </Button>
   </View>
 </Cell>

建议将样式抽离到单独的样式文件中:

.upload-action-btn {
  margin-right: 10px;
}

.upload-clear-btn {
  /* 可以添加自定义样式 */
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between aafb914 and 55d5b91.

📒 Files selected for processing (4)
  • src/packages/uploader/demo.taro.tsx (2 hunks)
  • src/packages/uploader/demos/taro/demo10.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo8.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo9.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/packages/uploader/demo.taro.tsx
🔇 Additional comments (6)
src/packages/uploader/demos/taro/demo8.tsx (3)

1-3: 导入声明看起来很清晰!

使用 Cell 组件包装 Uploader 是一个很好的布局选择。


19-21: ⚠️ Potential issue

Uploader 组件配置需要完善

当前配置过于简单,建议添加以下重要配置:

  1. 错误处理回调
  2. 文件大小限制
  3. 文件类型限制
  4. 上传状态回调

建议修改如下:

 <Cell>
   <Uploader 
     upload={(file: File) => upload(file)} 
     sourceType={['camera']}
+    maxFileSize={5 * 1024 * 1024}
+    maxCount={5}
+    accept="image/*"
+    onError={(error) => console.error('上传错误:', error)}
+    onChange={(files) => console.log('文件列表变化:', files)}
+    onProgress={(event) => console.log('上传进度:', event.percent)}
   />
 </Cell>

Likely invalid or redundant comment.


12-17: ⚠️ Potential issue

上传函数需要增强错误处理和环境适配

当前实现存在以下问题:

  1. 缺少错误处理机制
  2. 使用硬编码的图片URL可能在不同环境下无法访问

建议修改如下:

 async function upload(file: File) {
+  try {
     await sleep(2000)
+    // 根据环境返回不同的URL
+    const baseUrl = process.env.TARO_ENV === 'harmony' 
+      ? 'harmony-specific-url'
+      : 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif'
     return {
-      url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
+      url: baseUrl,
     }
+  } catch (error) {
+    console.error('上传失败:', error)
+    throw new Error(`上传失败: ${error.message}`)
+  }
 }

Likely invalid or redundant comment.

src/packages/uploader/demos/taro/demo10.tsx (2)

1-3: 导入声明看起来很清晰!

代码使用了具名导入,结构清晰,包含了所有必要的依赖。


8-9: 注意文件名过长可能导致的UI问题

当前示例中的文件名 "文件文件文件文件1文件文件文件文件1文件文件文件文件1.png" 过长,建议:

  1. 在实际应用中添加文件名长度限制
  2. 在UI中使用省略号显示过长的文件名
  3. 为该场景添加UI适配测试用例
src/packages/uploader/demos/taro/demo9.tsx (1)

19-24: 🛠️ Refactor suggestion

建议增强上传函数的健壮性

当前的上传模拟函数过于简单,缺少必要的错误处理和进度跟踪机制。

建议按照以下方式改进:

 async function upload(file: File) {
+  try {
+    // 文件类型检查
+    if (!file.type.startsWith('image/')) {
+      throw new Error('只支持上传图片文件')
+    }
+    
+    // 文件大小检查
+    const maxSize = 5 * 1024 * 1024 // 5MB
+    if (file.size > maxSize) {
+      throw new Error('文件大小不能超过5MB')
+    }
+
     await sleep(2000)
+    // 模拟上传进度
+    const onProgress = (percent: number) => {
+      console.log(`上传进度: ${percent}%`)
+    }
+    
+    // 每500ms更新一次进度
+    for (let i = 0; i <= 100; i += 10) {
+      onProgress(i)
+      await sleep(500)
+    }
+
     return {
       url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
+      name: file.name,
+      size: file.size
     }
+  } catch (error) {
+    console.error('上传失败:', error)
+    throw error
+  }
 }

Likely invalid or redundant comment.

src/packages/uploader/demos/taro/demo10.tsx Show resolved Hide resolved
src/packages/uploader/demos/taro/demo9.tsx Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (17)
src/packages/uploader/doc.en-US.md (2)

1-3: 建议完善组件介绍部分

当前介绍过于简单,建议补充以下内容:

  1. 支持的文件类型
  2. 主要功能特性
  3. 适用场景说明

这些信息将帮助用户更好地理解组件的用途和能力。


142-146: 建议增强方法文档的实用性

建议对方法文档进行以下补充:

  1. 为每个方法添加具体的使用示例代码
  2. 说明方法调用的最佳实践
  3. 补充方法调用的注意事项
  4. 添加与其他属性配合使用的场景说明

这些补充将帮助开发者更好地理解和使用这些方法。

src/packages/uploader/doc.zh-TW.md (5)

21-21: 建议完善示例代码章节的描述

为了提高文档的可读性和理解性,建议在每个示例代码章节前添加简短的描述文字,说明该示例的使用场景和主要功能。例如:

  • "上传状态" 章节可以说明不同状态的含义和使用场景
  • "限制上传数量" 和 "限制上传大小" 可以补充具体的限制范围建议

Also applies to: 29-29, 37-37, 45-45


102-103: 建议说明 value 和 defaultValue 的区别

为了避免使用混淆,建议:

  1. 说明受控和非受控模式的使用场景
  2. 提供两种模式的具体示例代码

135-142: 建议完善 FileItem 接口文档

为提高开发体验,建议:

  1. 为每个 status 值提供详细说明和使用场景
  2. 补充 loadingIcon 和 failIcon 的自定义示例
  3. 说明 percentage 的取值范围和更新时机
🧰 Tools
🪛 LanguageTool

[locale-violation] ~135-~135: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名稱 | 說明 | 默認值 | | --- | --- | --- | | status | 文件狀態值,可選'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~135-~135: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件狀態值,可選'ready,uploading,success,error' | ready | | uid | 文件的唯一標識 | - | | n...

(UNPAIRED_BRACKETS)


146-152: 建议补充方法使用示例

为了更好地说明手动上传模式的使用方法,建议:

  1. 提供完整的 ref 使用示例代码
  2. 说明 submit 方法的调用时机
  3. 补充 clear 方法的使用场景

Line range hint 153-176: 建议添加主题定制的视觉效果展示

为了帮助开发者更好地理解和使用主题定制功能,建议:

  1. 添加不同主题配置的效果对比图
  2. 提供常见场景的主题配置示例
  3. 说明各个变量之间的关联关系
🧰 Tools
🪛 LanguageTool

[locale-violation] ~165-~165: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...的border圓角 | 4px | | --nutui-uploader-background | 上傳圖片的背景顏色 | $color-background | | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~165-~165: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...nutui-uploader-background | 上傳圖片的背景顏色 | $color-background | | --nutui-uploader-background-disab...

(GL_BARBARISM_REPLACE)


[locale-violation] ~166-~166: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...color-background| | \--nutui-uploader-background-disabled | 上傳圖片禁用狀態的背景顏色 |$color-back...

(GL_BARBARISM_REPLACE)


[locale-violation] ~166-~166: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...r-background-disabled | 上傳圖片禁用狀態的背景顏色 | $color-background | | --nutui-uploader-image-icon-tip-f...

(GL_BARBARISM_REPLACE)


[locale-violation] ~169-~169: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ... | | --nutui-uploader-preview-progress-background | 上傳區域預覽進度的背景顏色 | rgba(0, 0, 0, 0.65)...

(GL_BARBARISM_REPLACE)

src/packages/uploader/doc.taro.md (4)

21-77: 建议优化示例文档的结构与说明

示例部分的重组改进了文档的结构,但建议:

  1. 在每个示例开始前添加简短说明,帮助用户理解该示例的使用场景
  2. 为"基础用法-上传列表展示"部分添加与其他示例的区别说明

118-121: 建议优化平台特定属性的文档说明

对于 sourceTypemediaType 等 Taro 特定属性:

  1. 建议添加兼容性表格,明确说明各属性在不同平台(微信、支付宝、H5等)的支持情况
  2. 补充各配置项的实际效果说明
🧰 Tools
🪛 LanguageTool

[grammar] ~118-~118: 'album' é un erro. Considere utilizar "álbum"
Context: ...video/wx.chooseMedia.html") | Array | ['album','camera'] | | camera仅支持WEAPP | 仅在 `...

(GL_WIKIPEDIA_COMMON_ERRORS)


[locale-violation] ~121-~121: 'mix' é un xenismo. É preferíbel dicir "mestura"
Context: ...video/wx.chooseMedia.html") | Array | ['image', 'video', 'mix'] | | maxDuration仅支持WEAPP | 拍摄视频最长拍摄...

(GL_BARBARISM_REPLACE)


Line range hint 139-144: 建议增强 Methods 部分的文档说明

Methods 部分需要补充:

  1. submit 方法的具体使用场景和示例代码
  2. clear 方法的 index 参数说明及其可选值
  3. 补充方法调用的完整示例代码
🧰 Tools
🪛 LanguageTool

[locale-violation] ~104-~104: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ...-down|cover | | clearInput | 是否需要清空input内容,设为true支持重复选择上传同一个文件 | boolean` | ...

(GL_BARBARISM_REPLACE)


[grammar] ~118-~118: 'album' é un erro. Considere utilizar "álbum"
Context: ...video/wx.chooseMedia.html") | Array | ['album','camera'] | | camera仅支持WEAPP | 仅在 `...

(GL_WIKIPEDIA_COMMON_ERRORS)


[locale-violation] ~121-~121: 'mix' é un xenismo. É preferíbel dicir "mestura"
Context: ...video/wx.chooseMedia.html") | Array | ['image', 'video', 'mix'] | | maxDuration仅支持WEAPP | 拍摄视频最长拍摄...

(GL_BARBARISM_REPLACE)


[locale-violation] ~128-~128: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名称 | 说明 | 默认值 | | --- | --- | --- | | status | 文件状态值,可选'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~128-~128: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件状态值,可选'ready,uploading,success,error' | ready | | uid | 文件的唯一标识 | - | | n...

(UNPAIRED_BRACKETS)


Line range hint 161-170: 建议优化主题定制部分的文档

主题定制部分建议添加:

  1. 各样式变量的效果预览图
  2. 常见的自定义主题示例
  3. 在线预览或调试工具的链接
🧰 Tools
🪛 LanguageTool

[locale-violation] ~158-~158: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...的border圆角 | 4px | | --nutui-uploader-background | 上传图片的背景颜色 | $color-background | | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~158-~158: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...nutui-uploader-background | 上传图片的背景颜色 | $color-background | | --nutui-uploader-background-disab...

(GL_BARBARISM_REPLACE)


[locale-violation] ~159-~159: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...color-background| | \--nutui-uploader-background-disabled | 上传图片禁用状态的背景颜色 |$color-back...

(GL_BARBARISM_REPLACE)


[locale-violation] ~159-~159: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ...r-background-disabled | 上传图片禁用状态的背景颜色 | $color-background | | --nutui-uploader-image-icon-tip-f...

(GL_BARBARISM_REPLACE)


[locale-violation] ~162-~162: 'background' é un xenismo. É preferíbel dicir "formación de base"
Context: ... | | --nutui-uploader-preview-progress-background | 上传区域预览进度的背景颜色 | rgba(0, 0, 0, 0.65)...

(GL_BARBARISM_REPLACE)

src/packages/uploader/demos/taro/demo1.tsx (1)

1-14: 建议改进状态管理和常量定义

代码有以下可以改进的地方:

  1. FileItem 的类型定义不完整,建议添加必要的属性类型
  2. 演示用的 URL 应该移到常量文件中

建议按照以下方式重构:

+// src/packages/uploader/demos/constants.ts
+export const DEMO_CONSTANTS = {
+  UPLOADER_DEMO_URL: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif'
+}

+// 完整的 FileItem 类型
+interface DemoFileItem extends FileItem {
+  uid: number;
+  url: string;
+  status?: 'ready' | 'uploading' | 'success' | 'error';
+  message?: string;
+}

-const [list, setList] = useState<FileItem[]>([
+const [list, setList] = useState<DemoFileItem[]>([
   {
     url: demoUrl,
     uid: 133,
+    status: 'success',
   },
 ])
src/packages/uploader/doc.md (2)

135-142: 建议完善 FileItem 文档

为了提高文档的完整性和可用性,建议:

  1. percentage 属性添加类型说明(number)
  2. loadingIconfailIcon 添加示例代码
  3. 补充各个 status 状态的详细说明

需要我帮您补充这部分文档吗?

🧰 Tools
🪛 LanguageTool

[locale-violation] ~135-~135: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名称 | 说明 | 默认值 | | --- | --- | --- | | status | 文件状态值,可选'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~135-~135: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件状态值,可选'ready,uploading,success,error' | ready | | uid | 文件的唯一标识 | - | | n...

(UNPAIRED_BRACKETS)


168-168: 建议添加主题定制的视觉效果展示

建议为新增的 CSS 变量 --nutui-uploader-image-icon-tip-color 添加视觉效果展示,帮助用户更好地理解样式定制的效果。

需要我帮您设计视觉效果展示的示例吗?

src/packages/uploader/demos/taro/demo3.tsx (1)

5-6: 建议将演示URL移至常量配置

建议将演示用的URL移至统一的常量配置文件中管理。

-  const demoUrl =
-    'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif'
+  import { DEMO_IMAGE_URL } from '../constants'
src/packages/uploader/demos/h5/demo1.tsx (2)

6-12: 建议优化初始文件列表的状态处理

初始文件状态设置为 'uploading' 可能会造成用户困惑,建议设置为已完成状态。

 const [list, setList] = useState<FileItem[]>([
   {
     url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
     uid: 133,
-    status: 'uploading',
+    status: 'success',
+    name: 'demo-image.gif'
   },
 ])

27-29: 建议完善上传失败的错误信息

当前上传失败函数的错误信息过于简单。

 async function uploadFail(file: File): Promise<FileItem> {
   await sleep(2000)
-  throw new Error('Fail to upload')
+  throw new Error(`上传失败: ${file.name} (${file.size} bytes)`)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 55d5b91 and 54a7218.

📒 Files selected for processing (11)
  • src/packages/uploader/demos/h5/demo1.tsx (1 hunks)
  • src/packages/uploader/demos/h5/demo3.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo1.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo3.tsx (1 hunks)
  • src/packages/uploader/doc.en-US.md (2 hunks)
  • src/packages/uploader/doc.md (3 hunks)
  • src/packages/uploader/doc.taro.md (3 hunks)
  • src/packages/uploader/doc.zh-TW.md (2 hunks)
  • src/packages/uploader/preview.taro.tsx (5 hunks)
  • src/packages/uploader/preview.tsx (6 hunks)
  • src/packages/uploader/types.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/packages/uploader/types.ts
  • src/packages/uploader/preview.tsx
  • src/packages/uploader/preview.taro.tsx
🧰 Additional context used
📓 Learnings (1)
src/packages/uploader/demos/taro/demo1.tsx (1)
Learnt from: Alex-huxiyang
PR: jdf2e/nutui-react#2416
File: src/packages/uploader/uploader.taro.tsx:230-230
Timestamp: 2024-11-12T04:18:14.418Z
Learning: When changes are made to the `fileList` state in the `src/packages/uploader/uploader.taro.tsx` file, ensure to generate unit tests to cover these changes.
🪛 LanguageTool
src/packages/uploader/doc.en-US.md

[grammar] ~95-~95: This is a non-standard phrase. Did you mean “whether or not”?
Context: ...tely after selecting it. | autoUpload | If or not the upload will be done immediately aft...

(IF_OR_NOT)


[grammar] ~95-~95: Possibly, a comma is missing after an introductory clause, the verb inflection is not correct, or a question mark is missing. Did you mean “ref, submit” or “ref submits”?
Context: ...false, you need to manually execute the ref submit method to upload | boolean | true |...

(IF_DT_NN_VBZ)


[uncategorized] ~95-~95: Possible missing preposition found.
Context: ... upload | boolean | true | upload | The upload method, the input parameter is t...

(AI_HYDRA_LEO_MISSING_IN)


[style] ~100-~100: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...aded | FileItem[] | - | | preview | Whether or not to show the preview image after a succe...

(WHETHER)


[style] ~102-~102: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...ormats | string | - | | deletable | Whether or not to show the delete button | boolean |...

(WHETHER)


[grammar] ~109-~109: This is a non-standard phrase. Did you mean “whether or not”?
Context: ...scale-down | cover | | clearInput | If or not you want to clear the input content, ...

(IF_OR_NOT)

src/packages/uploader/doc.zh-TW.md

[locale-violation] ~101-~101: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ... => Promise|-| | name |input標簽name的名稱,發到後臺的文件參數名 |string` | ...

(GL_BARBARISM_REPLACE)


[typographical] ~109-~109: Símbolo desemparellado: Parece que falta «)»
Context: ...tring|picture` | | capture | 圖片[選取模式](https://developer.mozilla.org/zh-CN/docs...

(UNPAIRED_BRACKETS)


[locale-violation] ~113-~113: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ...-down|cover | | clearInput | 是否需要清空input內容,設為true支持重復選擇上傳同一個文件 | boolean` | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~129-~129: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ... | > 註意:accept、capture 和 multiple 為瀏覽器 input 標簽的原生屬性,移動端各種機型對這些屬性的支持程度有所差異,因此在不同機型和 ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~135-~135: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名稱 | 說明 | 默認值 | | --- | --- | --- | | status | 文件狀態值,可選'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~135-~135: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件狀態值,可選'ready,uploading,success,error' | ready | | uid | 文件的唯一標識 | - | | n...

(UNPAIRED_BRACKETS)

src/packages/uploader/doc.md

[locale-violation] ~101-~101: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ... => Promise|-| | name |input标签name的名称,发到后台的文件参数名 |string` | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~129-~129: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ... | > 注意:accept、capture 和 multiple 为浏览器 input 标签的原生属性,移动端各种机型对这些属性的支持程度有所差异,因此在不同机型和 ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~135-~135: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名称 | 说明 | 默认值 | | --- | --- | --- | | status | 文件状态值,可选'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~135-~135: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件状态值,可选'ready,uploading,success,error' | ready | | uid | 文件的唯一标识 | - | | n...

(UNPAIRED_BRACKETS)

src/packages/uploader/doc.taro.md

[locale-violation] ~93-~93: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ... => Promise|-| | name |input标签name的名称,发到后台的文件参数名 |string` | ...

(GL_BARBARISM_REPLACE)


[locale-violation] ~104-~104: 'input' é un xenismo. É preferíbel dicir "entrada"
Context: ...-down|cover | | clearInput | 是否需要清空input内容,设为true支持重复选择上传同一个文件 | boolean` | ...

(GL_BARBARISM_REPLACE)


[grammar] ~118-~118: 'album' é un erro. Considere utilizar "álbum"
Context: ...video/wx.chooseMedia.html") | Array | ['album','camera'] | | camera仅支持WEAPP | 仅在 `...

(GL_WIKIPEDIA_COMMON_ERRORS)


[locale-violation] ~121-~121: 'mix' é un xenismo. É preferíbel dicir "mestura"
Context: ...video/wx.chooseMedia.html") | Array | ['image', 'video', 'mix'] | | maxDuration仅支持WEAPP | 拍摄视频最长拍摄...

(GL_BARBARISM_REPLACE)


[locale-violation] ~128-~128: 'status' é un xenismo. É preferíbel dicir "estatuto"
Context: ...| 名称 | 说明 | 默认值 | | --- | --- | --- | | status | 文件状态值,可选'ready,uploading,success,erro...

(GL_BARBARISM_REPLACE)


[typographical] ~128-~128: Símbolo desemparellado: Parece que falta «'»
Context: ...| 文件状态值,可选'ready,uploading,success,error' | ready | | uid | 文件的唯一标识 | - | | n...

(UNPAIRED_BRACKETS)

🪛 Markdownlint (0.35.0)
src/packages/uploader/doc.en-US.md

152-152: null
Link fragments should be valid

(MD051, link-fragments)

🔇 Additional comments (7)
src/packages/uploader/doc.en-US.md (2)

94-123: 属性文档需要规范化和完善

存在以下问题:

  1. 多处描述使用了不规范的表达:
    • autoUploadclearInput 等属性使用了 "If or not"
    • 建议统一改为 "是否" 的表达方式
  2. 部分属性描述不完整:
    • upload 方法的返回值类型和示例说明不足
    • onUploadQueueChange 的触发时机描述可以更具体
  3. 类型定义不统一:
    • maxFileSizemaxCount 的类型描述格式不一致
🧰 Tools
🪛 LanguageTool

[grammar] ~95-~95: This is a non-standard phrase. Did you mean “whether or not”?
Context: ...tely after selecting it. | autoUpload | If or not the upload will be done immediately aft...

(IF_OR_NOT)


[grammar] ~95-~95: Possibly, a comma is missing after an introductory clause, the verb inflection is not correct, or a question mark is missing. Did you mean “ref, submit” or “ref submits”?
Context: ...false, you need to manually execute the ref submit method to upload | boolean | true |...

(IF_DT_NN_VBZ)


[uncategorized] ~95-~95: Possible missing preposition found.
Context: ... upload | boolean | true | upload | The upload method, the input parameter is t...

(AI_HYDRA_LEO_MISSING_IN)


[style] ~100-~100: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...aded | FileItem[] | - | | preview | Whether or not to show the preview image after a succe...

(WHETHER)


[style] ~102-~102: Consider shortening this phrase to just ‘whether’, unless you mean ‘regardless of whether’.
Context: ...ormats | string | - | | deletable | Whether or not to show the delete button | boolean |...

(WHETHER)


[grammar] ~109-~109: This is a non-standard phrase. Did you mean “whether or not”?
Context: ...scale-down | cover | | clearInput | If or not you want to clear the input content, ...

(IF_OR_NOT)


150-171: 主题定制部分需要完善

建议进行以下改进:

  1. ConfigProvider 链接失效,需要更新正确的链接
  2. 建议添加常见的自定义主题示例代码
  3. 补充各样式变量之间的关联关系说明
  4. 为关键样式变量添加效果预览图
🧰 Tools
🪛 Markdownlint (0.35.0)

152-152: null
Link fragments should be valid

(MD051, link-fragments)

src/packages/uploader/demos/taro/demo1.tsx (1)

16-29: 🛠️ Refactor suggestion

需要完善上传函数的实现

当前实现存在以下问题:

  1. 上传函数返回值类型不完整
  2. 错误处理机制过于简单
  3. 缺少上传进度回调

建议按照以下方式改进:

+interface UploadProgress {
+  loaded: number;
+  total: number;
+}

+interface UploadError extends Error {
+  code: string;
+  details?: any;
+}

-async function upload(file: File) {
+async function upload(file: File, onProgress?: (progress: UploadProgress) => void): Promise<DemoFileItem> {
   await sleep(2000)
+  // 模拟上传进度
+  onProgress?.({ loaded: 100, total: 100 })
-  return { url: demoUrl }
+  return {
+    url: demoUrl,
+    uid: Date.now(),
+    status: 'success',
+    name: file.name,
+    size: file.size
+  }
 }

-async function uploadFail(file: File): Promise<FileItem> {
+async function uploadFail(file: File): Promise<DemoFileItem> {
   await sleep(2000)
-  throw new Error('Fail to upload')
+  const error: UploadError = new Error('上传失败') as UploadError
+  error.code = 'UPLOAD_FAILED'
+  error.details = { fileName: file.name, fileSize: file.size }
+  throw error
 }

Likely invalid or redundant comment.

src/packages/uploader/doc.md (1)

21-85: 建议更新示例代码

示例代码部分的标题已更新,但需要确保:

  1. 示例代码与新的 API 保持一致
  2. 每个示例都展示了新的 upload 方法的使用方式
  3. 补充 onUploadQueueChange 的使用示例
✅ Verification successful

示例代码已符合新的 API 规范

经过检查,所有示例代码都已经正确实现了:

  1. 每个示例都使用了新的 upload 方法,返回包含 url 的 Promise
  2. 示例展示了多种上传状态和场景,包括成功、失败、上传中等
  3. 通过 valueonChange 属性实现了文件列表的状态管理
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查示例代码是否包含必要的 upload 方法实现
rg -l 'upload.*=.*\(file\).*=>' h5/demo*.tsx

Length of output: 101


Script:

#!/bin/bash
# First, let's find the correct path to the demo files
fd "demo.*\.tsx" --type f

# Then check the content of these demo files for upload implementation
fd "demo.*\.tsx" --type f --exec rg -l "upload.*=.*\(file\).*=>"

# Also search for onUploadQueueChange usage
fd "demo.*\.tsx" --type f --exec rg -l "onUploadQueueChange"

Length of output: 52663


Script:

#!/bin/bash
# 查找 uploader 组件的示例代码
fd "demo.*\.tsx" "src/packages/uploader/demos"

# 检查示例代码中的 upload 方法实现
fd "demo.*\.tsx" "src/packages/uploader/demos" --exec cat {}

Length of output: 22636

src/packages/uploader/demos/h5/demo3.tsx (2)

23-29: 🛠️ Refactor suggestion

建议完善 Uploader 组件配置

当前配置缺少必要的错误处理回调和文件类型限制。

 <Uploader
   value={list}
   onChange={setList}
   upload={(file: File) => upload(file)}
   maxCount={5}
   multiple
+  accept="image/*"
+  onError={(error) => console.error('上传失败:', error)}
+  onProgress={(event) => console.log('上传进度:', event.percent)}
 />

Likely invalid or redundant comment.


13-17: ⚠️ Potential issue

建议增强上传函数的错误处理和资源管理

当前上传函数缺少必要的错误处理和资源清理机制。

 async function upload(file: File) {
+  try {
+    if (!file) {
+      throw new Error('文件不能为空')
+    }
+    
+    const maxSize = 5 * 1024 * 1024 // 5MB
+    if (file.size > maxSize) {
+      throw new Error('文件大小超出限制')
+    }
+    
     await sleep(2000)
+    const url = URL.createObjectURL(file)
+    
+    // 在组件卸载时清理URL对象
+    window.addEventListener('unload', () => URL.revokeObjectURL(url))
+    
     return {
-      url: URL.createObjectURL(file),
+      url,
+      status: 'success' as const,
+      name: file.name
     }
+  } catch (error) {
+    return {
+      status: 'error' as const,
+      message: error instanceof Error ? error.message : '上传失败'
+    }
+  }
 }

Likely invalid or redundant comment.

src/packages/uploader/demos/h5/demo1.tsx (1)

35-45: 🛠️ Refactor suggestion

建议统一上传组件的错误处理

多个上传组件应该有统一的错误处理机制。

 <Uploader
   uploadLabel="商品主图"
   value={list}
   onChange={setList}
   upload={(file: File) => upload(file)}
+  onError={(error) => console.error('上传失败:', error)}
 />
 <Uploader 
   upload={(file: File) => upload(file)} 
+  onError={(error) => console.error('上传失败:', error)}
 />
 <Uploader
   uploadIcon={<Dongdong />}
   upload={(file: File) => uploadFail(file)}
+  onError={(error) => console.error('上传失败:', error)}
 />

Likely invalid or redundant comment.

src/packages/uploader/doc.zh-TW.md Show resolved Hide resolved
src/packages/uploader/doc.taro.md Show resolved Hide resolved
src/packages/uploader/doc.taro.md Show resolved Hide resolved
src/packages/uploader/demos/taro/demo1.tsx Show resolved Hide resolved
src/packages/uploader/doc.md Show resolved Hide resolved
src/packages/uploader/demos/taro/demo3.tsx Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (8)
src/packages/uploader/demos/taro/demo10.tsx (2)

6-41: 建议优化文件名长度和示例数据

  1. 文件名过长可能会导致UI布局问题,建议:
    • 添加文件名长度限制
    • 实现文件名截断显示
  2. 示例数据中所有文件使用相同的URL,建议使用不同的示例图片以更好地展示实际使用场景
 const [list, setList] = useState<FileItem[]>([
   {
-    name: '文件文件文件文件1文件文件文件文件1文件文件文件文件1.png',
+    name: '长文件名示例.png',
     url: 'https://example.com/image1.gif',
     status: 'success',
     message: '上传成功',
   },
   {
     name: '文件2.png',
-    url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
+    url: 'https://example.com/image2.gif',
     status: 'success',
     message: '上传成功',
   },
   // ... 其他文件项类似更新
 ])

59-71: 建议优化组件属性和样式

  1. maxCount属性应该传入数字而不是字符串
  2. 建议使用CSS类替代内联样式,以提高可维护性
 <Uploader
   upload={(file: File) => upload(file)}
   value={list}
   onChange={setList}
-  maxCount="10"
+  maxCount={10}
   multiple
   previewType="list"
-  style={{ marginBottom: 20 }}
+  className="demo-uploader"
 >

同时在样式文件中添加:

.demo-uploader {
  margin-bottom: 20px;
}
src/packages/uploader/demos/h5/demo9.tsx (3)

4-7: 建议为接口添加文档注释

为了提高代码的可维护性,建议为 uploadRefState 接口添加 JSDoc 文档注释,说明每个方法的用途和预期行为。

+/**
+ * Uploader 组件的引用类型接口
+ * @interface uploadRefState
+ */
 interface uploadRefState {
+  /** 触发文件上传操作 */
   submit: () => void
+  /** 清空已选择的文件 */
   clear: () => void
 }

18-22: 建议增强上传模拟的真实性

当前的上传模拟过于简单,建议添加以下功能以提升演示效果:

  1. 错误处理模拟
  2. 上传进度模拟
  3. 文件大小限制模拟
 async function upload(file: File) {
+  if (file.size > 5 * 1024 * 1024) {
+    throw new Error('文件大小超过限制')
+  }
+  const totalSteps = 5
+  for (let i = 1; i <= totalSteps; i++) {
   await sleep(2000)
+    // 模拟上传进度回调
+    console.log(`上传进度: ${(i / totalSteps) * 100}%`)
+  }
   return {
     url: URL.createObjectURL(file),
+    name: file.name,
+    size: file.size
   }
 }

41-46: 建议增加按钮状态处理

建议为按钮添加加载状态和禁用状态的处理,以提供更好的用户体验。

+const [isUploading, setIsUploading] = useState(false)
+
+const submitUpload = async () => {
+  if (!uploadRef.current) return
+  setIsUploading(true)
+  try {
+    await uploadRef.current.submit()
+  } finally {
+    setIsUploading(false)
+  }
+}

-<Button type="success" size="small" onClick={submitUpload}>
+<Button 
+  type="success" 
+  size="small" 
+  onClick={submitUpload}
+  loading={isUploading}
+  disabled={isUploading}
+>
   执行上传
 </Button>
src/packages/uploader/preview.tsx (3)

28-36: 建议使用枚举或常量来管理状态值

当前的状态值使用字符串字面量(如 'success'、'error'),建议改用枚举或常量来提高代码的可维护性和类型安全性。

建议添加以下代码:

export enum UploadStatus {
  SUCCESS = 'success',
  ERROR = 'error',
  READY = 'ready',
  UPLOADING = 'uploading'
}

然后更新相关代码:

- status = 'success',
+ status = UploadStatus.SUCCESS,

50-61: 建议优化条件渲染逻辑

当前的状态判断和进度显示逻辑较为复杂,可以通过提取组件或使用映射来简化代码。

建议将进度显示提取为单独的组件:

const ProgressMessage: React.FC<{ status: string; message: string }> = ({
  status,
  message
}) => (
  <div className="nut-uploader-preview-progress">
    {status !== 'ready' && renderIcon(item)}
    <div className="nut-uploader-preview-progress-msg">
      {message}
    </div>
  </div>
);

Line range hint 110-129: 建议优化状态样式管理

当前状态类名直接拼接到className中,建议使用CSS-in-JS或统一的样式管理方案来处理不同状态的样式。

可以考虑使用以下方案:

  1. 使用 classnames 库管理类名
  2. 将状态样式抽取为独立的样式文件
  3. 使用 CSS Modules 隔离样式

示例代码:

import classNames from 'classnames';

const className = classNames('nut-uploader-preview-img-file-name', {
  'is-error': status === 'error',
  'is-success': status === 'success',
  'is-uploading': status === 'uploading'
});
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 95-95: src/packages/uploader/preview.tsx#L95
Added line #L95 was not covered by tests

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 54a7218 and e232ce7.

📒 Files selected for processing (6)
  • migrate-from-v2.md (1 hunks)
  • src/packages/uploader/demos/h5/demo10.tsx (1 hunks)
  • src/packages/uploader/demos/h5/demo9.tsx (1 hunks)
  • src/packages/uploader/demos/taro/demo10.tsx (1 hunks)
  • src/packages/uploader/preview.taro.tsx (5 hunks)
  • src/packages/uploader/preview.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/packages/uploader/demos/h5/demo10.tsx
  • src/packages/uploader/preview.taro.tsx
🧰 Additional context used
🪛 GitHub Check: codecov/patch
src/packages/uploader/preview.tsx

[warning] 95-95: src/packages/uploader/preview.tsx#L95
Added line #L95 was not covered by tests

🔇 Additional comments (8)
migrate-from-v2.md (4)

528-530: 网络请求相关功能移除说明

组件不再内置网络请求逻辑,移除了所有网络配置相关的属性,包括:

  • 移除了组件内部的ajax相关网络逻辑
  • 移除了urlheadersdataxhrStatewithCredentialstimeout等网络配置属性

这样的改动使组件更加轻量和灵活,用户可以自行实现网络请求逻辑。


531-532: 新增事件处理器

为了提供更好的用户体验,新增了以下事件:

  • onOverCount: 文件数量超过限制时触发
  • onUploadQueueChange: 图片上传队列变化时触发

这些新增的事件可以帮助用户更好地控制上传流程。


533-534: 类型定义和默认值优化

对类型定义和默认值进行了以下优化:

  • 简化了FileItem类型,除url外其他属性变为可选
  • 调整了多选状态下maxCount属性的默认值为Number.MAX_VALUE

这些改动使得类型定义更加灵活,同时提供了更合理的默认值。


535-536: API 更新说明

重要的API更新:

  • 新增了 upload 方法
  • defaultValuevalue 的类型从 FileType 变更为 FileItem

建议用户在升级时注意这些类型变更。

src/packages/uploader/demos/taro/demo10.tsx (2)

1-3: 导入声明看起来不错!

导入声明简洁明了,只引入了必要的依赖。


49-57: ⚠️ Potential issue

需要增强错误处理机制

当前的上传函数实现过于简单,建议进行以下改进:

  1. 定义上传响应的接口类型
  2. 添加更详细的错误信息
  3. 处理更多错误场景(如网络超时、文件大小限制等)
+interface UploadResponse {
+  url: string;
+  name?: string;
+  size?: number;
+}

+class UploadError extends Error {
+  constructor(
+    message: string,
+    public code: string,
+    public details?: any
+  ) {
+    super(message);
+  }
+}

 async function upload(file: File) {
   await sleep(2000)
   if (Math.random() < 0.5) {
-    return {
+    return <UploadResponse>{
       url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
     }
   }
-  throw new Error('Fail to upload')
+  throw new UploadError('上传失败', 'UPLOAD_FAILED', { fileName: file.name })
 }
src/packages/uploader/preview.tsx (2)

4-5: 类型定义改进值得肯定!

any 类型切换到具体的 FileItem 类型定义,这样的改进提高了代码的类型安全性和可维护性。


Line range hint 67-95: 需要补充测试用例

文件名称显示相关的代码缺少测试覆盖,建议添加以下场景的测试:

  1. 图片类型文件的预览
  2. 非图片类型文件的预览
  3. 文件名称的显示逻辑
✅ Verification successful

测试覆盖已经基本完善

经过验证,src/packages/uploader/__tests__/uploader.spec.tsx 中已包含以下测试场景:

  • 图片类型文件的预览测试(通过 previewType="picture" 场景)
  • 非图片类型文件的预览测试(通过 previewType="list" 场景)
  • 文件名称显示及点击逻辑测试(通过 .nut-uploader-preview-img-file-name 相关测试)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否存在相关测试文件
fd -e test.tsx -e spec.tsx preview

Length of output: 93


Script:

#!/bin/bash
# Check content of the test file and look for uploader preview tests
rg -A 5 "preview" src/packages/imagepreview/__test__/imagepreview.spec.tsx

# Search for any uploader related test files
fd -e test.tsx -e spec.tsx uploader

# Search for preview related test cases in the entire codebase
rg -g "*.test.tsx" -g "*.spec.tsx" "preview.*test|describe.*preview" -A 5

Length of output: 1605


Script:

#!/bin/bash
# Check uploader test file content for preview related tests
rg -A 5 "preview" src/packages/uploader/__tests__/uploader.spec.tsx

# Look for specific test cases related to file preview and name display
rg -g "*.spec.tsx" -g "*.test.tsx" "test.*preview.*file|test.*name.*display" src/packages/uploader/__tests__/

Length of output: 1959

src/packages/uploader/demos/h5/demo9.tsx Show resolved Hide resolved
src/packages/uploader/demos/h5/demo9.tsx Show resolved Hide resolved
@oasis-cloud
Copy link
Collaborator

单测提升下覆盖率

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e232ce7 and 3caca30.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • migrate-from-v2.md (1 hunks)
  • src/config.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/config.json
🔇 Additional comments (2)
migrate-from-v2.md (2)

531-533: 事件处理的优化

新的事件系统更加清晰和实用:

  • 新增了文件数量超限和队列变化的回调
  • 简化了 FileItem 类型,提升了使用便利性

534-536: 配置和类型的改进

重要的配置和类型变更:

  • maxCount 在多选状态下的默认值调整为最大值
  • 新增了 upload 方法
  • FileItem 类型的调整使接口更加灵活
✅ Verification successful

Let me check the actual usage and changes in these files to better understand the impact.


Let me try with a different command to check the usage.


Let me try one more search to check the actual usage in the codebase.


Based on the code analysis, I can now provide the final response:

请注意类型和配置的重要变更

根据代码验证,这些变更确实已经实施:

  • maxCount 在多选模式下默认值已设置为 Number.MAX_VALUE
  • 新增了必需的 upload 方法作为组件属性
  • 类型系统从 FileType 迁移到了更具体的 FileItem 类型,提供了更好的类型支持

以下文件需要更新相关使用:

  • src/packages/uploader/uploader.taro.tsx
  • src/packages/uploader/types.ts
  • src/packages/uploader/index.ts
  • src/packages/uploader/index.taro.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查代码库中是否存在旧版本的用法
rg -l 'FileType|defaultValue.*FileType|value.*FileType' 

Length of output: 288


Script:

#!/bin/bash
# Check the actual usage of FileType in the codebase
rg -A 3 'FileType|defaultValue.*FileType|value.*FileType' --type ts --type tsx

Length of output: 108


Script:

#!/bin/bash
# Check FileType usage in TypeScript files
rg -A 3 'FileType|defaultValue.*FileType|value.*FileType' '*.ts' '*.tsx'

# Also check the type definitions
cat src/packages/uploader/types.ts

Length of output: 609


Script:

#!/bin/bash
# Search for FileType usage in all files
rg -A 3 'FileType|defaultValue.*FileType|value.*FileType' src/packages/uploader/

# Check the implementation files
cat src/packages/uploader/uploader.taro.tsx

Length of output: 13839

migrate-from-v2.md Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
src/packages/uploader/__tests__/uploader.spec.tsx (4)

6-8: 导入语句的顺序需要优化

建议按照以下顺序组织导入语句:

  1. 外部依赖
  2. 内部组件
  3. 类型定义
  4. 工具函数
-import { FileItem } from '../types'
-import { Preview } from '../preview'
-import Button from '@/packages/button'
+import * as React from 'react'
+import { render, fireEvent } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import Button from '@/packages/button'
+
+import { Preview } from '../preview'
+import { Uploader } from '../uploader'
+import { FileItem } from '../types'

Line range hint 147-160: 建议增强 beforeDelete 测试用例

当前测试用例仅验证了基本功能,建议添加以下场景的测试:

  1. 异步 beforeDelete 的处理
  2. beforeDelete 抛出异常的情况
  3. 多文件删除的场景

222-245: 按钮交互测试建议补充边界场景

当前测试覆盖了基本的点击事件,建议补充以下场景:

  1. 按钮在禁用状态下的交互
  2. 上传过程中按钮的状态变化
  3. 清空操作后的状态验证

279-279: 预览组件测试需要补充验证

当前的测试用例主要关注点击事件,建议补充:

  1. 不同预览类型的渲染验证
  2. 图片加载失败的处理
  3. 自定义预览内容的渲染

Also applies to: 307-307

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3caca30 and aa0ba95.

📒 Files selected for processing (1)
  • src/packages/uploader/__tests__/uploader.spec.tsx (6 hunks)
🧰 Additional context used
📓 Learnings (1)
src/packages/uploader/__tests__/uploader.spec.tsx (1)
Learnt from: Alex-huxiyang
PR: jdf2e/nutui-react#2416
File: src/packages/uploader/uploader.taro.tsx:230-230
Timestamp: 2024-11-12T04:18:14.418Z
Learning: When changes are made to the `fileList` state in the `src/packages/uploader/uploader.taro.tsx` file, ensure to generate unit tests to cover these changes.
🔇 Additional comments (1)
src/packages/uploader/__tests__/uploader.spec.tsx (1)

202-221: 进度条测试用例完善度高

测试用例完整验证了进度条的渲染和样式,包括:

  1. 进度条元素的存在性检查
  2. 进度值的正确性验证
  3. 样式属性的验证

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
src/packages/uploader/__tests__/uploader.spec.tsx (4)

Line range hint 147-160: 建议使用更具体的变量命名

fileList 作为变量名比较笼统,建议改为更具描述性的名称,如 singleFileListtestFileList。另外,注意到 defaultValue 被替换为 value,这是一个重要的 API 变更。


202-223: 进度条测试用例完善且全面

测试用例很好地覆盖了进度条的渲染、样式和文本显示。建议补充以下场景:

  1. 进度为 0% 的情况
  2. 进度为 100% 的情况
  3. 进度条状态切换的情况

224-247: 按钮交互测试逻辑完整

测试用例完整覆盖了按钮的渲染和点击事件。建议增加:

  1. 按钮禁用状态的测试
  2. 多次点击的处理测试

281-281: 预览组件测试更新合理

URL 属性的添加和点击处理器的更新符合组件的新特性。建议:

  1. 添加预览图片加载失败的测试场景
  2. 测试不同文件类型的预览行为

Also applies to: 309-309

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between aa0ba95 and 18a7aa1.

📒 Files selected for processing (1)
  • src/packages/uploader/__tests__/uploader.spec.tsx (6 hunks)
🧰 Additional context used
📓 Learnings (1)
src/packages/uploader/__tests__/uploader.spec.tsx (1)
Learnt from: Alex-huxiyang
PR: jdf2e/nutui-react#2416
File: src/packages/uploader/uploader.taro.tsx:230-230
Timestamp: 2024-11-12T04:18:14.418Z
Learning: When changes are made to the `fileList` state in the `src/packages/uploader/uploader.taro.tsx` file, ensure to generate unit tests to cover these changes.
🔇 Additional comments (2)
src/packages/uploader/__tests__/uploader.spec.tsx (2)

6-6: 导入语句的更新符合重构要求

导入路径的更改反映了类型定义的重构,同时新增了 Button 组件的导入用于测试新功能。

Also applies to: 8-8


249-249: ⚠️ Potential issue

类型定义需要明确

list 的类型从 FileItem 改为 any 降低了类型安全性,建议:

  1. 保持使用 FileItem 类型
  2. 如果需要特殊处理,创建专门的测试类型
-const list: any = {}
+const list: FileItem = {
+  name: '文件1.png',
+  url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
+  status: 'ready',
+  message: '准备上传',
+  type: 'image',
+  uid: '12',
+}

@jdf2e jdf2e deleted a comment from coderabbitai bot Dec 11, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (3)
src/packages/uploader/__tests__/uploader.spec.tsx (3)

202-223: 进度条渲染测试覆盖了关键场景

测试用例完整验证了上传进度的显示功能,包括:

  • 进度条元素的存在性
  • 进度值的正确渲染
  • 文件名的显示

建议添加边界值测试用例(0% 和 100%)。

 test('should render progress', () => {
   const App = () => {
-    const list: FileItem[] = [
+    const list: FileItem[] = [
+      {
+        name: '文件1.png',
+        status: 'uploading',
+        percentage: 0,
+      },
       {
         name: '文件444.png',
         status: 'uploading',
         percentage: 30,
       },
+      {
+        name: '文件2.png',
+        status: 'uploading',
+        percentage: 100,
+      },
     ]
     return <Uploader deletable value={list} previewType="list" />
   }

342-381: 非图片类型预览测试逻辑完整

测试用例完整覆盖了:

  • 无预览URL的场景
  • 自定义预览URL的场景

建议添加更多文件类型的测试用例(如文档、音频等)。


391-391: 预览组件交互测试需要优化

重复的点击测试代码可以合并,提高测试代码的可维护性。

- fireEvent.click(container.querySelectorAll('.nut-uploader-preview-img-c')[0])
- expect(clickFunc).toBeCalled()
- 
- const { container: container1 } = render(
-   <Preview
-     fileList={list}
-     previewType="picture"
-     deletable
-     onDeleteItem={delFunc}
-     handleItemClick={clickFunc}
-   />
- )
- fireEvent.click(container1.querySelectorAll('.nut-uploader-preview-img-c')[0])
- expect(clickFunc).toBeCalled()

+ // 验证预览图片点击事件
+ fireEvent.click(container.querySelectorAll('.nut-uploader-preview-img-c')[0])
+ expect(clickFunc).toHaveBeenCalledTimes(1)

Also applies to: 419-419

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4376c2e and 020eb24.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • src/config.json (1 hunks)
  • src/packages/uploader/__tests__/uploader.spec.tsx (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/config.json
🔇 Additional comments (4)
src/packages/uploader/__tests__/uploader.spec.tsx (4)

6-8: 导入语句的更新符合重构要求

导入路径的更改反映了组件结构的优化,将类型定义独立管理。


224-294: 文件上传模拟测试设计合理

测试用例全面覆盖了以下场景:

  • 单文件上传
  • 上传失败处理
  • 多文件上传限制
  • 自动上传开关

295-318: 按钮交互测试完整

测试用例验证了上传和清空按钮的渲染与交互。


320-320: ⚠️ Potential issue

需要加强类型安全

使用 any 类型降低了类型安全性。

建议保持使用 FileItem 类型:

-const list: any = {}
+const list: FileItem = {
+  name: '文件1.png',
+  url: 'https://m.360buyimg.com/babel/jfs/t1/164410/22/25162/93384/616eac6cE6c711350/0cac53c1b82e1b05.gif',
+  status: 'ready',
+  message: '准备上传',
+  type: 'image',
+  uid: '12',
+}

@oasis-cloud oasis-cloud merged commit 23561c4 into feat_v3.x Dec 24, 2024
7 checks passed
@oasis-cloud oasis-cloud deleted the hxy/uploader/refactor branch December 24, 2024 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants