file-row.vue 6.5 KB

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