index.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <template>
  2. <view class="jnpf-file">
  3. <view class="jnpf-file-box" :style="{textAlign:align}">
  4. <view v-if="!detailed &&!disabled " class="jnpf-file-box-line">
  5. <!-- #ifndef APP-HARMONY -->
  6. <CommentLsjUpload :ref="lsjUpload" :childId="childId" :width="width" :height="height" :option="option"
  7. :size="fileSize" :formats="getFormats" :instantly="instantly" @uploadEnd="onuploadEnd"
  8. :lsjUpload="lsjUpload" v-if="!disabled" :currentCount="currentCount">
  9. <view class="icon-ym icon-ym-comment-file" size="mini"></view>
  10. </CommentLsjUpload>
  11. <view class="icon-ym icon-ym-comment-file" size="mini" v-else @click="onCountOver"></view>
  12. <!-- #endif -->
  13. <!-- #ifdef APP-HARMONY -->
  14. <view @click="chooseFile">
  15. <view class="icon-ym icon-ym-comment-file" size="mini"></view>
  16. </view>
  17. <!-- #endif -->
  18. </view>
  19. <view class="icon-ym icon-ym-comment-file" size="mini" v-if="disabled" @click="onCountOver"></view>
  20. <view class="tipText u-p-l-20">
  21. {{tipText}}
  22. </view>
  23. </view>
  24. </view>
  25. </template>
  26. <script>
  27. import CommentLsjUpload from './lsj-upload/lsj-upload.vue'
  28. import {
  29. getDownloadUrl
  30. } from '@/api/common'
  31. import jnpf from '@/utils/jnpf'
  32. const units = {
  33. KB: 1024,
  34. MB: 1024 * 1024,
  35. GB: 1024 * 1024 * 1024,
  36. };
  37. const imgTypeList = ['png', 'jpg', 'jpeg', 'bmp', 'gif']
  38. export default {
  39. components: {
  40. CommentLsjUpload
  41. },
  42. name: 'jnpf-upload-img',
  43. inheritAttrs: false,
  44. props: {
  45. modelValue: {
  46. type: Array,
  47. default: () => ([])
  48. },
  49. limit: {
  50. type: [Number, String],
  51. default: 9
  52. },
  53. fileSize: {
  54. type: Number,
  55. default: 10
  56. },
  57. sizeUnit: {
  58. type: String,
  59. default: 'MB'
  60. },
  61. accept: {
  62. type: String,
  63. default: ''
  64. },
  65. pathType: {
  66. type: String,
  67. default: 'defaultPath'
  68. },
  69. tipText: {
  70. type: String,
  71. default: ''
  72. },
  73. isAccount: {
  74. type: Number,
  75. default: 0
  76. },
  77. folder: {
  78. type: String,
  79. default: ''
  80. },
  81. vModel: {
  82. type: String,
  83. default: ''
  84. },
  85. detailed: {
  86. type: Boolean,
  87. default: false
  88. },
  89. align: {
  90. type: String,
  91. default: 'right'
  92. },
  93. currentCount: {
  94. type: Number,
  95. default: 0
  96. }
  97. },
  98. data() {
  99. return {
  100. percent: '',
  101. fileList: [],
  102. // 上传接口参数
  103. option: {},
  104. params: {
  105. pathType: this.pathType,
  106. isAccount: this.isAccount,
  107. folder: this.folder
  108. },
  109. // 选择文件后是否立即自动上传,true=选择后立即上传
  110. instantly: true,
  111. size: 30,
  112. list: [],
  113. deletable: false,
  114. childId: 'upload' + this.$u.guid(3, false, 2),
  115. lsjUpload: 'lsjUpload' + this.$u.guid(3, false, 2),
  116. width: '48rpx',
  117. height: '48rpx',
  118. disabled: false
  119. }
  120. },
  121. computed: {
  122. baseURL() {
  123. return this.define.baseURL
  124. },
  125. comUploadUrl() {
  126. return this.define.comUploadUrl
  127. },
  128. getFormats() {
  129. let formats = this.accept
  130. formats = formats.replace("image/*", 'png,jpg,jpeg,bmp,gif,webp,psd,svg,tiff')
  131. formats = formats.replace("video/*", 'avi,wmv,mpg,mpeg,mov,rm,ram,swf,flv,mp4,wma,rm,rmvb,flv,mpg,mkv')
  132. formats = formats.replace("audio/*", 'mp3,wav,aif,midi,m4a')
  133. return formats
  134. },
  135. },
  136. created() {
  137. const token = uni.getStorageSync('token')
  138. this.option = {
  139. url: this.baseURL + '/api/file/Uploader/annex',
  140. name: 'file',
  141. header: {
  142. 'Authorization': token,
  143. 'uid': '27682',
  144. 'client': 'app',
  145. 'accountid': 'DP',
  146. },
  147. data: this.params
  148. }
  149. },
  150. watch: {
  151. modelValue: {
  152. handler(val) {
  153. this.fileList = JSON.parse(JSON.stringify(val));
  154. },
  155. immediate: true
  156. }
  157. },
  158. methods: {
  159. // 鸿蒙上传附件
  160. chooseFile() {
  161. if (this.limit === this.fileList.length) return this.toast(`只允许上传${this.limit}个文件`);
  162. uni.chooseFile({
  163. count: 1, //默认100
  164. success: (res) => {
  165. const tempFilePaths = res.tempFilePaths;
  166. const token = uni.getStorageSync('token')
  167. const file = res.tempFiles[0]
  168. // 限制文件大小
  169. if (file.size > units[this.sizeUnit] * Math.abs(this.fileSize)) {
  170. this.toast(`文件大小超过${this.fileSize}${this.sizeUnit}`)
  171. return;
  172. }
  173. uni.uploadFile({
  174. url: this.baseURL + '/api/file/Uploader/annex',
  175. filePath: tempFilePaths[0],
  176. name: 'file',
  177. formData: {
  178. ...this.params,
  179. fileName: file.name
  180. },
  181. header: {
  182. 'Authorization': token,
  183. 'uid': '27682',
  184. 'client': 'app',
  185. 'accountid': 'DP',
  186. },
  187. success: (response) => {
  188. let item = JSON.parse(response.data)
  189. this.fileList.push({
  190. name: res.tempFiles[0].name,
  191. fileId: item.data.name,
  192. url: item.data.url,
  193. fileExtension: item.data.fileExtension,
  194. fileSize: item.data.fileSize
  195. })
  196. this.$emit('update:modelValue', this.fileList)
  197. this.$emit('change', this.fileList)
  198. this.$forceUpdate();
  199. }
  200. });
  201. }
  202. });
  203. },
  204. onCountOver() {
  205. uni.showToast({
  206. title: `最多可以上传${this.limit}个文件`,
  207. icon: 'none'
  208. });
  209. return;
  210. },
  211. // 某文件上传结束回调(成功失败都回调)
  212. onuploadEnd(item) {
  213. if (this.currentCount >= this.limit) {
  214. // this.disabled = true;
  215. return this.$u.toast('最多可以上传' + this.limit + '个文件')
  216. }
  217. if (item['responseText']) {
  218. let response = JSON.parse(item.responseText)
  219. let count = this.fileList.length
  220. if (count >= this.limit) {
  221. // this.disabled = true;
  222. return this.$u.toast('最多可以上传' + this.limit + '个文件')
  223. }
  224. if (response.code != 200) return this.$u.toast(response.msg)
  225. this.fileList.push({
  226. name: item.name,
  227. fileId: response.data.name,
  228. url: response.data.url,
  229. fileExtension: response.data.fileExtension,
  230. fileSize: response.data.fileSize
  231. })
  232. this.$emit('update:modelValue', this.fileList)
  233. this.$emit('change', this.fileList)
  234. }
  235. this.$forceUpdate();
  236. },
  237. downLoad(item) {
  238. if (item.fileExtension && imgTypeList.includes(item.fileExtension)) return this.previewImage(item)
  239. // #ifdef MP
  240. this.previewFile(item)
  241. // #endif
  242. // #ifndef MP
  243. getDownloadUrl('annex', item.fileId).then(res => {
  244. const fileUrl = this.baseURL + res.data.url + '&name=' + item.name;
  245. // #ifdef H5
  246. window.location.href = fileUrl;
  247. // #endif
  248. // #ifdef APP-PLUS
  249. this.downloadFile(res.data.url);
  250. // #endif
  251. })
  252. // #endif
  253. },
  254. // 移除某个文件
  255. delFile(files) {
  256. this.fileList = files
  257. // if(this.fileList.length >= this.limit) {
  258. // this.disabled = true
  259. // }else{
  260. // this.disabled = false
  261. // }
  262. },
  263. previewFile(item) {
  264. let fileTypes = ['doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx']
  265. let url = item.url
  266. let fileType = url.split('.')[1]
  267. if (fileTypes.includes(fileType)) {
  268. uni.downloadFile({
  269. url: this.baseURL + url,
  270. success: (res) => {
  271. var filePath = res.tempFilePath;
  272. uni.openDocument({
  273. filePath: encodeURI(filePath),
  274. showMenu: true,
  275. fileType: fileType,
  276. success: (res) => {
  277. console.log('打开文档成功');
  278. },
  279. fail(err) {
  280. console.log('小程序', err);
  281. }
  282. });
  283. }
  284. });
  285. } else {
  286. this.$u.toast(
  287. '该文件类型无法打开'
  288. )
  289. }
  290. },
  291. previewImage(item) {
  292. if (!item.url) return
  293. const url = jnpf.getAuthImgUrl(item.url)
  294. uni.previewImage({
  295. urls: [url],
  296. current: url,
  297. success: () => {},
  298. fail: () => {
  299. uni.showToast({
  300. title: '预览图片失败',
  301. icon: 'none'
  302. });
  303. }
  304. });
  305. },
  306. downloadFile(url) {
  307. uni.downloadFile({
  308. url: this.baseURL + url,
  309. success: res => {
  310. if (res.statusCode === 200) {
  311. uni.saveFile({
  312. tempFilePath: res.tempFilePath,
  313. success: red => {
  314. uni.showToast({
  315. icon: 'none',
  316. mask: true,
  317. title: '文件已保存:' + red.savedFilePath, //保存路径
  318. duration: 3000,
  319. });
  320. setTimeout(() => {
  321. uni.openDocument({
  322. filePath: red.savedFilePath,
  323. success: ress => {},
  324. fail(err) {}
  325. });
  326. }, 500)
  327. }
  328. });
  329. }
  330. }
  331. });
  332. },
  333. }
  334. }
  335. </script>
  336. <style lang="scss" scoped>
  337. .icon-ym {
  338. font-size: 48rpx;
  339. }
  340. .jnpf-file {
  341. width: 100%;
  342. .jnpf-file-box {
  343. .jnpf-file-box-line {
  344. height: 70rpx;
  345. align-items: center;
  346. display: flex;
  347. }
  348. .tipText {
  349. color: #606266;
  350. word-break: break-all;
  351. line-height: 48rpx;
  352. }
  353. .jnpf-file-item {
  354. justify-content: space-between;
  355. flex-direction: row;
  356. .jnpf-file-item-txt {
  357. width: 230rpx;
  358. flex: auto;
  359. }
  360. .showLeft {
  361. text-align: left;
  362. }
  363. .closeBox {
  364. height: 60rpx;
  365. align-items: flex-end;
  366. justify-content: space-evenly;
  367. flex: 0.2;
  368. .closeTxt {
  369. width: 36rpx;
  370. height: 36rpx;
  371. border-radius: 50%;
  372. background-color: #fa3534;
  373. color: #FFFFFF;
  374. font-size: 20rpx;
  375. align-items: center;
  376. justify-content: center;
  377. line-height: 36rpx;
  378. }
  379. }
  380. }
  381. }
  382. }
  383. </style>