file-row.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <template>
  2. <div :class="`file-row is-${file.status}`" >
  3. <div class="file-row__item-name">
  4. <el-icon><Paperclip /></el-icon>
  5. <span class="file-row__item-file-name">{{
  6. file.id
  7. ? file[config.optionProps?.label || 'name']
  8. : file.name
  9. }}</span>
  10. </div>
  11. <!-- 进度条仅在当前页面上传的文件中显示-->
  12. <template v-if="file.status === 'ready'">
  13. <el-progress style="width: 100%" :percentage="file.percentage" :stroke-width="2"></el-progress>
  14. <div>
  15. ({{parseFileSize(file.loaded)}}/{{parseFileSize(file.total)}})
  16. <cip-button-text v-if="file.status === 'ready'" type="danger" @click="cancelUpload(file)">取消</cip-button-text>
  17. </div>
  18. </template>
  19. <template v-else>
  20. <div class="handle-button-wrapper">
  21. <cip-button-text :type="isPreview?'visited':undefined" :loading="previewLoading" v-if="previewAble" @click="previewFile">
  22. 预览
  23. </cip-button-text>
  24. <cip-button-text :type="isDownload?'visited':undefined" :loading="downloadLoading" v-if="downloadAble" @click="downloadFile">
  25. 下载
  26. </cip-button-text>
  27. <template v-if="removable">
  28. <cip-button-text @click="remove" :loading="removeLoading">
  29. 删除
  30. </cip-button-text>
  31. </template>
  32. </div>
  33. </template>
  34. </div>
  35. </template>
  36. <script>
  37. import { computed, ref } from 'vue'
  38. import { ElMessageBox, ElProgress, ElIcon } from 'element-plus'
  39. import { Dialog as VanDialog } from 'vant'
  40. import { download } from './upload'
  41. import { getEquipmentType, isEmpty } from '@cip/utils/util'
  42. import { Paperclip } from '@element-plus/icons-vue'
  43. import CipButtonText from '@cip/components/cip-button-text'
  44. export default {
  45. components: { ElProgress, CipButtonText, ElIcon, Paperclip },
  46. props: {
  47. file: {
  48. type: Object,
  49. default: () => { return {} }
  50. },
  51. config: Object,
  52. dependOnValues: Object,
  53. removable: Boolean
  54. },
  55. setup (props, { emit }) {
  56. const isMobile = getEquipmentType() === 'mobile'
  57. const previewLoading = ref(false)
  58. const downloadLoading = ref(false)
  59. const removeLoading = ref(false)
  60. const fileValue = computed(() => {
  61. return props.file
  62. })
  63. // 根据文件大小 显示 B kb mb
  64. const parseFileSize = (size) => {
  65. let unit = 'k'
  66. if (size > 1024) {
  67. size = size / 1024
  68. unit = 'kb'
  69. }
  70. if (size > 1024) {
  71. size = size / 1024
  72. unit = 'mb'
  73. }
  74. return `${Math.floor(size)}${unit}`
  75. }
  76. const cancelUpload = (file) => {
  77. file.abort()
  78. }
  79. const previewAble = computed(() => {
  80. if (typeof props.config.previewAble === 'boolean') return props.config.previewAble
  81. return props.config.previewAble?.(props.dependOnValues, fileValue.value)
  82. })
  83. const isPreview = computed(() => {
  84. return !!props.file.read
  85. })
  86. const isDownload = computed(() => {
  87. return !!props.file.download
  88. })
  89. const previewFile = async () => {
  90. previewLoading.value = true
  91. try {
  92. await props.config.previewFile?.(fileValue.value, props.config)
  93. } finally {
  94. previewLoading.value = false
  95. }
  96. }
  97. const downloadAble = computed(() => {
  98. if (isEmpty(props.config.downloadAble)) return true
  99. if (typeof props.config.downloadAble === 'boolean') return props.config.downloadAble
  100. return props.config.downloadAble(props.dependOnValues, fileValue.value)
  101. })
  102. const downloadFile = async () => {
  103. try {
  104. downloadLoading.value = true
  105. if (isEmpty(props.config.downloadFile)) {
  106. await download(fileValue.value)
  107. } else {
  108. await props.config.downloadFile(fileValue.value, props.config)
  109. }
  110. } finally {
  111. downloadLoading.value = false
  112. }
  113. }
  114. const remove = async () => {
  115. const message = `确认删除《${fileValue.value[props.config.optionProps?.label || 'name']}》`
  116. try {
  117. isMobile
  118. ? await VanDialog.confirm({
  119. title: '警告',
  120. message
  121. })
  122. : await ElMessageBox.confirm(message, '警告', { type: 'warning' })
  123. removeLoading.value = true
  124. if (props.config.deleteFile) {
  125. await props.config.deleteFile?.(fileValue.value, props.config)
  126. }
  127. emit('after-remove', fileValue.value)
  128. } catch (e) {
  129. } finally {
  130. removeLoading.value = false
  131. }
  132. }
  133. return {
  134. removeLoading,
  135. parseFileSize,
  136. cancelUpload,
  137. previewAble,
  138. previewLoading,
  139. previewFile,
  140. downloadAble,
  141. downloadLoading,
  142. downloadFile,
  143. remove,
  144. removeLoading,
  145. isPreview,
  146. isDownload
  147. }
  148. }
  149. }
  150. </script>
  151. <style lang="less">
  152. .file-row{
  153. width: 100%;
  154. font-size: 14px;
  155. //line-height: 1.1em;
  156. line-height: @formItemLineHeight;
  157. padding: 4px 6px;
  158. /*display: flex;*/
  159. /*justify-content: space-between;*/
  160. /*align-items: center;*/
  161. flex-wrap: nowrap;
  162. position: relative;
  163. overflow: hidden;
  164. &:hover{
  165. background: #e6f7ff;
  166. .handle-button-wrapper{
  167. visibility: visible;
  168. top:0;
  169. left: 0;
  170. bottom: 0;
  171. }
  172. }
  173. &__file-name{
  174. display: inline-block;
  175. margin-left: 8px;
  176. text-overflow: ellipsis;
  177. white-space: nowrap;
  178. }
  179. &__process{
  180. display: flex;
  181. align-items: center;
  182. justify-content: space-between;
  183. }
  184. .handle-button-wrapper{
  185. display: flex;
  186. align-items: center;
  187. position: absolute;
  188. left: -100%;
  189. background: rgba(255,255,255,0.8);
  190. visibility: hidden;
  191. opacity: 0.9;
  192. transition: all 0.3s;
  193. padding: 0 8px;
  194. .el-button{
  195. padding: 0 4px;
  196. + .el-button{
  197. margin-left: 4px;
  198. }
  199. }
  200. }
  201. &__button{
  202. cursor: pointer;
  203. flex-shrink: 0;
  204. &+.file-row__button{
  205. margin-left:4px;
  206. }
  207. }
  208. }
  209. </style>