UploadComponent.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <template>
  2. <view style="width: 100%;height: 100%;">
  3. <view class="upload-wrap">
  4. <view class="btn-click mgb-16 upload-btn" @click="handleUploadClick()" v-show="isUpload === false">
  5. <!-- <image :src="icons.upload" mode="aspectFill" class="upload-icon" /> -->
  6. <i class="el-icon-upload2"></i>
  7. <text class="upload-text">上传附件</text>
  8. <text class="upload-text1">{{ `只能上传不超过${this.limit}个文件` }}</text>
  9. </view>
  10. <view class="mgb-16 file-wrap" v-for="(item, index) in fileList" :key="index">
  11. <view class="btn-click file-line" @click="handlePreview(item)">
  12. <!-- <view class="btn-click file-line" @click="handleUploadFile(item)"> -->
  13. <view class="file-info">
  14. <i :class="`el-icon-${icons[getFileType(item.name) || 'file']}`"></i>
  15. <text class="file-name">{{ item.name || title[type] }}</text>
  16. </view>
  17. <i :class='`el-icon-${icons.close}`' v-if="isDelete === false"
  18. @click.stop="handleDeleteFile(index)"></i>
  19. </view>
  20. </view>
  21. <view class="mgb-16 file-wrap" v-if="fileList.length === 0">
  22. <view class="file-line">
  23. <text class="file-empty">暂无数据</text>
  24. </view>
  25. </view>
  26. </view>
  27. <xe-upload ref="XeUpload" :options="{ url: uploadUrl }" @callback="handleUploadCallback"></xe-upload>
  28. <u-action-sheet @close="uploadShow = false" cancelText="取消" :actions="uploadList"
  29. @select="handleChangeUploadType" :title="uploadTitle" :show="uploadShow"></u-action-sheet>
  30. <mumu-previewOffce :fileType="prviewFileType" :fileUrl='prviewFileUrl'
  31. v-model='showPreview'></mumu-previewOffce>
  32. <u-popup v-if="videoShow" @close="handleCloseVideo" mode="top" :overlay="true" :show="videoShow"
  33. :closeOnClickOverlay="true">
  34. <view v-if="videoShow" style="width: 100%;height: 100%;">
  35. <video v-if="videoShow" style="width: 100%;" :src="videoUrl" controls preload="auto" autoPlay={true} />
  36. </view>
  37. </u-popup>
  38. </view>
  39. </template>
  40. <script>
  41. import MumuPreviewOffce from '@/uni_modules/mumu-previewOffce/components/mumu-previewOffce/mumu-previewOffce.vue'
  42. import { mapState, mapMutations, mapActions } from 'vuex'
  43. import OSSService from "@/api/sys/OSSService"
  44. export default {
  45. components: {
  46. MumuPreviewOffce
  47. },
  48. computed: mapState({
  49. userInfo: (state) => state.user.userInfo,
  50. }),
  51. created() {
  52. this.ossService = new OSSService()
  53. },
  54. props: {
  55. //上传地址
  56. uploadUrl: {
  57. type: String,
  58. default: ''
  59. },
  60. // 文件列表
  61. fileList: {
  62. type: Array,
  63. default: () => []
  64. },
  65. // 最大上传个数
  66. limit: {
  67. type: Number,
  68. default: 9
  69. },
  70. // 是否可以删除
  71. isDelete: {
  72. type: Boolean,
  73. default: false
  74. },
  75. // 是否可以上传
  76. isUpload: {
  77. type: Boolean,
  78. default: false
  79. },
  80. },
  81. ossService: null,
  82. data() {
  83. return {
  84. uploadType: '',
  85. videoShow: false,
  86. videoUrl: '',
  87. prviewFileType: '',
  88. prviewFileUrl: '',
  89. showPreview: false,
  90. icons: {
  91. close: 'circle-close',
  92. image: 'picture-outline',
  93. video: 'video-camera',
  94. file: 'document',
  95. audio: 'bell',
  96. unknown: 'document'
  97. },
  98. uploadFile: '',
  99. uploadShow: false,
  100. uploadTitle: '附件上传',
  101. uploadList: [
  102. {
  103. name: '视频上传',
  104. },
  105. {
  106. name: '图片上传',
  107. },
  108. {
  109. name: '文件上传',
  110. }
  111. ],
  112. }
  113. },
  114. methods: {
  115. handleCloseVideo() {
  116. this.videoUrl = ""
  117. this.videoShow = false
  118. },
  119. handleDeleteFile(index) {
  120. console.log();
  121. const deletedFile = this.fileList[index]; // 获取被删除的文件
  122. // this.fileList.splice(index, 1); // 删除文件
  123. this.$emit("onRemove", deletedFile, this.fileList, index); // 传递剩余文件列表和被删除的文件
  124. },
  125. // 预览
  126. handlePreview(row) {
  127. const fileType = this.getFileType(row.name);
  128. const flieArr = row.name.split('.');
  129. let suffix = flieArr[flieArr.length - 1];
  130. this.ossService.getTemporaryUrl("/" + row.url).then((data) => {
  131. if (fileType == "image") {
  132. return uni.previewImage({
  133. current: data,
  134. urls: [data],
  135. });
  136. }
  137. if (fileType == "video") {
  138. this.videoUrl = data
  139. this.videoShow = true
  140. return
  141. }
  142. if (fileType == "file") {
  143. this.prviewFileUrl = data
  144. this.prviewFileType = suffix
  145. this.showPreview = true
  146. return
  147. }
  148. uni.showModal({
  149. title: '提示',
  150. content: data,
  151. showCancel: false,
  152. });
  153. })
  154. },
  155. handleUploadClick() {
  156. if (this.fileList.length >= this.limit) {
  157. uni.showModal({
  158. title: '提示',
  159. content: `只能上传不超过${this.limit}个文件`,
  160. showCancel: false,
  161. });
  162. return
  163. }
  164. this.uploadShow = true
  165. this.uploadType = 'type'
  166. },
  167. getFileType(fileName = '') {
  168. const flieArr = fileName.split('.');
  169. let suffix = flieArr[flieArr.length - 1];
  170. if (!suffix) return '';
  171. suffix = suffix.toLocaleLowerCase();
  172. const image = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'];
  173. if (image.includes(suffix)) return 'image';
  174. const video = ['mp4', 'm4v'];
  175. if (video.includes(suffix)) return 'video';
  176. const audio = ['mp3', 'm4a', 'wav', 'aac'];
  177. if (audio.includes(suffix)) return 'audio';
  178. const office = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'plain'];
  179. if (office.includes(suffix)) return 'file';
  180. return 'unknown';
  181. },
  182. handleChangeUploadType(index) {
  183. if (index.name == "视频上传") {
  184. this.$refs.XeUpload.upload('video', {});
  185. }
  186. if (index.name == "图片上传") {
  187. this.$refs.XeUpload.upload('image', {});
  188. }
  189. if (index.name == "文件上传") {
  190. this.$refs.XeUpload.upload('file', {});
  191. }
  192. },
  193. handleUploadCallback(e) {
  194. this.uploadShow = false
  195. const file = e.data[0]
  196. this.fileList.push({
  197. name: file.name,
  198. size: file.size,
  199. url: file.response.url,
  200. lsUrl: file.response.lsUrl,
  201. createBy: this.userInfo,
  202. by: this.userInfo.id,
  203. createTime: this.formatDateNew(new Date())
  204. })
  205. console.log(this.fileList);
  206. this.$emit("onSuccess", file, this.fileList)
  207. },
  208. formatDateNew(date) {
  209. const year = date.getFullYear();
  210. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  211. const day = date.getDate().toString().padStart(2, '0');
  212. const hours = date.getHours().toString().padStart(2, '0');
  213. const minutes = date.getMinutes().toString().padStart(2, '0');
  214. const seconds = date.getSeconds().toString().padStart(2, '0');
  215. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  216. },
  217. }
  218. }
  219. </script>
  220. <style scoped lang="scss">
  221. .btn-click {
  222. transition: all 0.3s;
  223. opacity: 1;
  224. }
  225. .btn-click:active {
  226. opacity: 0.5;
  227. }
  228. .mgb-16 {
  229. margin-bottom: 16rpx;
  230. &:last-child {
  231. margin-bottom: 0;
  232. }
  233. }
  234. .upload-wrap {
  235. width: 100%;
  236. border-radius: 16rpx;
  237. background: white;
  238. .upload-btn {
  239. width: 100%;
  240. height: 176rpx;
  241. border: 2rpx dashed;
  242. color: #409EFF;
  243. border-color: #b3d8ff;
  244. background: #ecf5ff;
  245. border-radius: 16rpx;
  246. display: flex;
  247. align-items: center;
  248. justify-content: center;
  249. flex-direction: column;
  250. .upload-icon {
  251. width: 48rpx;
  252. height: 48rpx;
  253. margin-bottom: 8rpx;
  254. }
  255. .upload-text {
  256. font-size: 26rpx;
  257. line-height: 40rpx;
  258. }
  259. .upload-text1 {
  260. font-size: 20rpx;
  261. line-height: 40rpx;
  262. }
  263. }
  264. .file-wrap {
  265. .file-line {
  266. width: 100%;
  267. border-color: #b3d8ff;
  268. background: #ecf5ff;
  269. border-radius: 8rpx;
  270. padding: 16rpx;
  271. font-size: 26rpx;
  272. color: #409EFF;
  273. line-height: 40rpx;
  274. display: flex;
  275. align-items: center;
  276. justify-content: space-between;
  277. .file-info {
  278. width: 90%;
  279. display: flex;
  280. align-items: center;
  281. .file-name {
  282. max-width: 80%;
  283. padding-left: 16rpx;
  284. overflow: hidden;
  285. text-overflow: ellipsis;
  286. white-space: nowrap;
  287. }
  288. }
  289. .file-icon {
  290. width: 40rpx;
  291. height: 40rpx;
  292. flex-shrink: 0;
  293. }
  294. .file-empty {
  295. color: #999999;
  296. }
  297. }
  298. }
  299. }
  300. </style>