upload-file.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <template>
  2. <view class="uni-file-picker__files">
  3. <view v-if="!readonly" class="files-button" @click="choose">
  4. <slot></slot>
  5. </view>
  6. <!-- :class="{'is-text-box':showType === 'list'}" -->
  7. <view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle">
  8. <!-- ,'is-list-card':showType === 'list-card' -->
  9. <view
  10. class="uni-file-picker__lists-box"
  11. v-for="(item, index) in list"
  12. :key="index"
  13. :class="{
  14. 'files-border': index !== 0 && styles.dividline,
  15. }"
  16. :style="index !== 0 && styles.dividline && borderLineStyle"
  17. >
  18. <view class="uni-file-picker__item">
  19. <!-- :class="{'is-text-image':showType === 'list'}" -->
  20. <!-- <view class="files__image is-text-image">
  21. <image class="header-image" :src="item.logo" mode="aspectFit"></image>
  22. </view> -->
  23. <view class="files__name">{{ item.name }}</view>
  24. <view v-if="delIcon && !readonly" class="icon-del-box icon-files" @click="delFile(index)">
  25. <view class="icon-del icon-files"></view>
  26. <view class="icon-del rotate"></view>
  27. </view>
  28. </view>
  29. <view
  30. v-if="(item.progress && item.progress !== 100) || item.progress === 0"
  31. class="file-picker__progress"
  32. >
  33. <progress
  34. class="file-picker__progress-item"
  35. :percent="item.progress === -1 ? 0 : item.progress"
  36. stroke-width="4"
  37. :backgroundColor="item.errMsg ? '#ff5a5f' : '#EBEBEB'"
  38. />
  39. </view>
  40. <view
  41. v-if="item.status === 'error'"
  42. class="file-picker__mask"
  43. @click.stop="uploadFiles(item, index)"
  44. >
  45. 点击重试
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </template>
  51. <script>
  52. export default {
  53. name: 'uploadFile',
  54. emits: ['uploadFiles', 'choose', 'delFile'],
  55. props: {
  56. filesList: {
  57. type: Array,
  58. default() {
  59. return [];
  60. },
  61. },
  62. delIcon: {
  63. type: Boolean,
  64. default: true,
  65. },
  66. limit: {
  67. type: [Number, String],
  68. default: 9,
  69. },
  70. showType: {
  71. type: String,
  72. default: '',
  73. },
  74. listStyles: {
  75. type: Object,
  76. default() {
  77. return {
  78. // 是否显示边框
  79. border: true,
  80. // 是否显示分隔线
  81. dividline: true,
  82. // 线条样式
  83. borderStyle: {},
  84. };
  85. },
  86. },
  87. readonly: {
  88. type: Boolean,
  89. default: false,
  90. },
  91. },
  92. computed: {
  93. list() {
  94. let files = [];
  95. this.filesList.forEach((v) => {
  96. files.push(v);
  97. });
  98. return files;
  99. },
  100. styles() {
  101. let styles = {
  102. border: true,
  103. dividline: true,
  104. 'border-style': {},
  105. };
  106. return Object.assign(styles, this.listStyles);
  107. },
  108. borderStyle() {
  109. let { borderStyle, border } = this.styles;
  110. let obj = {};
  111. if (!border) {
  112. obj.border = 'none';
  113. } else {
  114. let width = (borderStyle && borderStyle.width) || 1;
  115. width = this.value2px(width);
  116. let radius = (borderStyle && borderStyle.radius) || 5;
  117. radius = this.value2px(radius);
  118. obj = {
  119. 'border-width': width,
  120. 'border-style': (borderStyle && borderStyle.style) || 'solid',
  121. 'border-color': (borderStyle && borderStyle.color) || '#eee',
  122. 'border-radius': radius,
  123. };
  124. }
  125. let classles = '';
  126. for (let i in obj) {
  127. classles += `${i}:${obj[i]};`;
  128. }
  129. return classles;
  130. },
  131. borderLineStyle() {
  132. let obj = {};
  133. let { borderStyle } = this.styles;
  134. if (borderStyle && borderStyle.color) {
  135. obj['border-color'] = borderStyle.color;
  136. }
  137. if (borderStyle && borderStyle.width) {
  138. let width = (borderStyle && borderStyle.width) || 1;
  139. let style = (borderStyle && borderStyle.style) || 0;
  140. if (typeof width === 'number') {
  141. width += 'px';
  142. } else {
  143. width = width.indexOf('px') ? width : width + 'px';
  144. }
  145. obj['border-width'] = width;
  146. if (typeof style === 'number') {
  147. style += 'px';
  148. } else {
  149. style = style.indexOf('px') ? style : style + 'px';
  150. }
  151. obj['border-top-style'] = style;
  152. }
  153. let classles = '';
  154. for (let i in obj) {
  155. classles += `${i}:${obj[i]};`;
  156. }
  157. return classles;
  158. },
  159. },
  160. methods: {
  161. uploadFiles(item, index) {
  162. this.$emit('uploadFiles', {
  163. item,
  164. index,
  165. });
  166. },
  167. choose() {
  168. this.$emit('choose');
  169. },
  170. delFile(index) {
  171. this.$emit('delFile', index);
  172. },
  173. value2px(value) {
  174. if (typeof value === 'number') {
  175. value += 'px';
  176. } else {
  177. value = value.indexOf('px') !== -1 ? value : value + 'px';
  178. }
  179. return value;
  180. },
  181. },
  182. };
  183. </script>
  184. <style lang="scss">
  185. .uni-file-picker__files {
  186. /* #ifndef APP-NVUE */
  187. display: flex;
  188. /* #endif */
  189. flex-direction: column;
  190. justify-content: flex-start;
  191. }
  192. .files-button {
  193. // border: 1px red solid;
  194. }
  195. .uni-file-picker__lists {
  196. position: relative;
  197. margin-top: 5px;
  198. overflow: hidden;
  199. }
  200. .file-picker__mask {
  201. /* #ifndef APP-NVUE */
  202. display: flex;
  203. /* #endif */
  204. justify-content: center;
  205. align-items: center;
  206. position: absolute;
  207. right: 0;
  208. top: 0;
  209. bottom: 0;
  210. left: 0;
  211. color: #fff;
  212. font-size: 14px;
  213. background-color: rgba(0, 0, 0, 0.4);
  214. }
  215. .uni-file-picker__lists-box {
  216. position: relative;
  217. }
  218. .uni-file-picker__item {
  219. /* #ifndef APP-NVUE */
  220. display: flex;
  221. /* #endif */
  222. align-items: center;
  223. padding: 8px 10px;
  224. padding-right: 5px;
  225. padding-left: 10px;
  226. }
  227. .files-border {
  228. border-top: 1px #eee solid;
  229. }
  230. .files__name {
  231. flex: 1;
  232. font-size: 14px;
  233. color: #666;
  234. margin-right: 25px;
  235. /* #ifndef APP-NVUE */
  236. word-break: break-all;
  237. word-wrap: break-word;
  238. /* #endif */
  239. }
  240. .icon-files {
  241. /* #ifndef APP-NVUE */
  242. position: static;
  243. background-color: initial;
  244. /* #endif */
  245. }
  246. // .icon-files .icon-del {
  247. // background-color: #333;
  248. // width: 12px;
  249. // height: 1px;
  250. // }
  251. .is-list-card {
  252. border: 1px #eee solid;
  253. margin-bottom: 5px;
  254. border-radius: 5px;
  255. box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1);
  256. padding: 5px;
  257. }
  258. .files__image {
  259. width: 40px;
  260. height: 40px;
  261. margin-right: 10px;
  262. }
  263. .header-image {
  264. width: 100%;
  265. height: 100%;
  266. }
  267. .is-text-box {
  268. border: 1px #eee solid;
  269. border-radius: 5px;
  270. }
  271. .is-text-image {
  272. width: 25px;
  273. height: 25px;
  274. margin-left: 5px;
  275. }
  276. .rotate {
  277. position: absolute;
  278. transform: rotate(90deg);
  279. }
  280. .icon-del-box {
  281. /* #ifndef APP-NVUE */
  282. display: flex;
  283. margin: auto 0;
  284. /* #endif */
  285. align-items: center;
  286. justify-content: center;
  287. position: absolute;
  288. top: 0px;
  289. bottom: 0;
  290. right: 5px;
  291. height: 26px;
  292. width: 26px;
  293. // border-radius: 50%;
  294. // background-color: rgba(0, 0, 0, 0.5);
  295. z-index: 2;
  296. transform: rotate(-45deg);
  297. }
  298. .icon-del {
  299. width: 15px;
  300. height: 1px;
  301. background-color: #333;
  302. // border-radius: 1px;
  303. }
  304. /* #ifdef H5 */
  305. @media all and (min-width: 768px) {
  306. .uni-file-picker__files {
  307. max-width: 375px;
  308. }
  309. }
  310. /* #endif */
  311. </style>