placeholder.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <script setup lang="tsx">
  2. import { CloudUploadOutlined } from '@ant-design/icons-vue';
  3. import { Button, Flex, Result, theme } from 'ant-design-vue';
  4. import { Attachments, type AttachmentsProps } from 'ant-design-x-vue';
  5. import { computed, type CSSProperties, ref } from 'vue';
  6. defineOptions({ name: 'AXAttachmentPlaceholder' });
  7. const presetFiles: AttachmentsProps['items'] = [
  8. {
  9. uid: '1',
  10. name: 'uploading file.xlsx',
  11. status: 'uploading',
  12. url: 'http://www.baidu.com/xxx.png',
  13. percent: 93,
  14. },
  15. {
  16. uid: '2',
  17. name: 'uploaded file.docx',
  18. status: 'done',
  19. size: 123456,
  20. description: 'Customize description',
  21. url: 'http://www.baidu.com/yyy.png',
  22. },
  23. {
  24. uid: '3',
  25. name: 'upload error with long text file name.zip',
  26. status: 'error',
  27. response: 'Server Error 500', // custom error message to show
  28. url: 'http://www.baidu.com/zzz.png',
  29. },
  30. {
  31. uid: '4',
  32. name: 'image uploading preview.png',
  33. status: 'uploading',
  34. percent: 33,
  35. thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  36. url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  37. },
  38. {
  39. uid: '5',
  40. name: 'image done preview.png',
  41. status: 'done',
  42. size: 123456,
  43. thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  44. url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  45. },
  46. {
  47. uid: '6',
  48. name: 'image error preview.png',
  49. status: 'error',
  50. response: 'Server Error 500', // custom error message to show
  51. thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  52. url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
  53. },
  54. ];
  55. type ExtractFunc<T> = T extends (...args: any) => any ? T : never;
  56. const getPlaceholderFn = (
  57. inlinePlaceholder: ReturnType<ExtractFunc<AttachmentsProps['placeholder']>>,
  58. ) => {
  59. return (type: 'inline' | 'drop') =>
  60. type === 'drop'
  61. ? {
  62. title: 'Drop file here',
  63. }
  64. : inlinePlaceholder;
  65. };
  66. const { token } = theme.useToken();
  67. const items = ref<AttachmentsProps['items']>([]);
  68. const sharedBorderStyle = computed<CSSProperties>(() => ({
  69. borderRadius: token.value.borderRadius,
  70. overflow: 'hidden',
  71. background: token.value.colorBgContainer,
  72. }));
  73. const sharedAttachmentProps = computed<AttachmentsProps>(() => ({
  74. beforeUpload: () => false,
  75. items: items.value,
  76. onChange: ({ fileList }) => {
  77. console.log('onChange:', fileList);
  78. items.value = fileList;
  79. },
  80. }));
  81. defineRender(() => {
  82. return (
  83. <Flex
  84. vertical
  85. gap="middle"
  86. style={{
  87. padding: token.value.padding,
  88. background: token.value.colorBgContainerDisabled,
  89. }}
  90. >
  91. <div style={sharedBorderStyle.value}>
  92. <Attachments
  93. {...sharedAttachmentProps.value}
  94. placeholder={getPlaceholderFn({
  95. icon: <CloudUploadOutlined />,
  96. title: 'Click or Drop files here',
  97. description: 'Support file type: image, video, audio, document, etc.',
  98. })}
  99. />
  100. </div>
  101. <div style={sharedBorderStyle.value}>
  102. <Attachments
  103. {...sharedAttachmentProps.value}
  104. placeholder={getPlaceholderFn(
  105. <Result
  106. title="Custom Placeholder Node"
  107. icon={<CloudUploadOutlined />}
  108. extra={<Button type="primary">Do Upload</Button>}
  109. style={{ padding: 0 }}
  110. />,
  111. )}
  112. />
  113. </div>
  114. <Flex gap="middle">
  115. <Button
  116. style={{ flex: '1 1 50%' }}
  117. disabled={!!items.value.length}
  118. type="primary"
  119. onClick={() => {
  120. items.value = presetFiles
  121. }}
  122. >
  123. Fill Files
  124. </Button>
  125. <Button
  126. style={{ flex: '1 1 50%' }}
  127. disabled={!items.value.length}
  128. onClick={() => {
  129. items.value = []
  130. }}
  131. >
  132. Reset Files
  133. </Button>
  134. </Flex>
  135. </Flex>
  136. )
  137. });
  138. </script>