upload.component.ts 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
  2. import {
  3. ToastController,
  4. IonicModule,
  5. LoadingController,
  6. } from '@ionic/angular';
  7. import * as Parse from 'parse';
  8. import * as qiniu from 'qiniu-js';
  9. @Component({
  10. selector: 'app-upload',
  11. templateUrl: './upload.component.html',
  12. styleUrls: ['./upload.component.scss'],
  13. standalone: true,
  14. imports: [IonicModule],
  15. })
  16. export class UploadComponent implements OnInit {
  17. @Input('files') files: Array<any> = [];
  18. @Input('boxWidth') boxWidth: number = 390; //盒子宽度
  19. @Input('fileWidth') fileWidth: number = 86; //图片高度
  20. @Input('fileHeight') fileHeight: number = 86; //图片宽度
  21. @Input('maxlenght') maxlenght: number = 1; //文件数量限制
  22. @Input('type') type: string = 'image';
  23. @Input('size') size: number = 2048; //上传文件限制大小单位KB
  24. @Input('multiple') multiple: boolean = false; //是否允许选择多张
  25. @Output() onChange: EventEmitter<any> = new EventEmitter<any>();
  26. showBlockNum: number = 4; //每行显示数量
  27. get accept() {
  28. let type;
  29. switch (this.type) {
  30. case 'image':
  31. type = 'image/*';
  32. break;
  33. case 'pdf':
  34. type = 'application/pdf';
  35. break;
  36. case 'audio':
  37. type = 'audio/*';
  38. break;
  39. case 'video':
  40. type = 'video/*';
  41. break;
  42. default:
  43. type = 'file';
  44. break;
  45. }
  46. return type;
  47. }
  48. disabled: boolean = false;
  49. company: string = localStorage.getItem('company') || 'Qje9D4bqol';
  50. config: { uptoken: string; domain: string; bucket: string } = {
  51. uptoken: '',
  52. domain: '',
  53. bucket: '',
  54. };
  55. fileList: Array<{
  56. url: string;
  57. name: string;
  58. type: string;
  59. size?: number;
  60. file?: any;
  61. }> = [];
  62. Previewfilelist: any; //预览图片数组
  63. loading: any;
  64. currentPreviewImg:string = ''
  65. constructor(
  66. public toastController: ToastController,
  67. public loadCtrl: LoadingController
  68. ) {
  69. Parse.Cloud.run('qiniu_uptoken', { company: this.company }).then((data) => {
  70. this.config = {
  71. uptoken: data.uptoken,
  72. domain: data.domain,
  73. bucket: data.bucket,
  74. };
  75. });
  76. }
  77. ngOnInit() {
  78. /* 计算文件布局 */
  79. let n = Math.floor(this.boxWidth / this.fileWidth);
  80. if (n * this.fileWidth + (n - 1) * 10 > this.boxWidth) {
  81. this.showBlockNum = n - 1;
  82. } else {
  83. this.showBlockNum = n;
  84. }
  85. this.fileList = this.files.map((item: any) => {
  86. console.log(item);
  87. return {
  88. url: item?.url,
  89. name: item?.name,
  90. type: 'http',
  91. // status: 'done',
  92. };
  93. });
  94. this.Previewfilelist = this.fileList;
  95. }
  96. onPreview(url:string){
  97. this.currentPreviewImg = url
  98. }
  99. onDelete(index: number) {
  100. console.log(index);
  101. this.fileList.splice(index, 1);
  102. }
  103. async onAdd(e: any) {
  104. let files = e.target.files;
  105. if (this.fileList.length + files.length > this.maxlenght) {
  106. const toast = await this.toastController.create({
  107. message: '超出上传文件数量',
  108. color: 'warning',
  109. duration: 1000,
  110. });
  111. toast.present();
  112. return;
  113. }
  114. for (let index = 0; index < files.length; index++) {
  115. const f = files[index];
  116. this.changeFileReader(f);
  117. }
  118. console.log(this.fileList);
  119. }
  120. //转图片格式
  121. changeFileReader(file: any) {
  122. return new Promise((res) => {
  123. const windowURL = window.URL || window.webkitURL;
  124. const src = windowURL.createObjectURL(file);
  125. let size = file.size / 1024; //KB
  126. this.fileList.push({
  127. url: src,
  128. size: size,
  129. name: file.name || '未知',
  130. type: 'local',
  131. file: file,
  132. });
  133. res(true);
  134. return;
  135. // const reader: any = new FileReader();
  136. // reader.readAsDataURL(file);
  137. // reader.filename = file.name;
  138. // console.log(file);
  139. // let _this = this;
  140. // reader.onload = async function (e: any) {
  141. // let size = e.total / 1024; //KB
  142. // let baseUrl = e.target.result;
  143. // if (size > _this.size) {
  144. // const toast = await _this.toastController.create({
  145. // message: file.name + '文件过大',
  146. // color: 'warning',
  147. // duration: 1000,
  148. // });
  149. // toast.present();
  150. // res(true);
  151. // return;
  152. // }
  153. // _this.fileList.push({
  154. // url: baseUrl,
  155. // size: size,
  156. // name: file.name || '未知',
  157. // type: 'local',
  158. // file: file,
  159. // });
  160. // res(true);
  161. // };
  162. });
  163. }
  164. async onUpload() {
  165. let authLoad = await this.authSpaceCount();
  166. if (!authLoad) {
  167. const toast = await this.toastController.create({
  168. message: '文件存储空间已满,请联系维护人员。',
  169. color: 'warning',
  170. duration: 1000,
  171. });
  172. toast.present();
  173. }
  174. let fs = this.fileList;
  175. this.loading = await this.loadCtrl.create({ message: '上传中' });
  176. this.loading.present();
  177. for (let index = 0; index < fs.length; index++) {
  178. const f = fs[index];
  179. if (f.type == 'local') {
  180. console.log(f);
  181. let url = await this.onQiniuUpFile(f);
  182. await this.saveAttachment({
  183. size: f.size,
  184. url: url,
  185. name: f.name,
  186. type: this.fileList[index].file.type,
  187. });
  188. this.fileList[index].url = url;
  189. this.fileList[index].type = 'http';
  190. delete this.fileList[index].file;
  191. delete this.fileList[index].size;
  192. }
  193. }
  194. this.onChange.emit(this.fileList);
  195. this.loading.dismiss();
  196. }
  197. /* 校验存储空间 */
  198. async authSpaceCount(): Promise<boolean> {
  199. let company = this.company;
  200. let query = new Parse.Query('Company');
  201. query.select('configSpace');
  202. let comObj = await query.get(company);
  203. let limit = comObj.get('configSpace') && comObj.get('configSpace').limit;
  204. // return new Promise((res, rej) => {
  205. let res = await fetch(
  206. `https://server.fmode.cn/api/storage/space?c=${company}`
  207. );
  208. let data = await res.json();
  209. console.log(data);
  210. if (data?.code == 200) {
  211. let spaceMap = data.data;
  212. let _spaceLimit = this.getLimitBytes(limit);
  213. let spaceUsed = spaceMap.totalSize;
  214. console.log('总空间:', _spaceLimit);
  215. console.log('已用空间:', spaceUsed);
  216. if (!_spaceLimit || spaceUsed > _spaceLimit) {
  217. return false;
  218. }
  219. return true;
  220. }
  221. return false;
  222. }
  223. // 单位
  224. getLimitBytes(limit: string) {
  225. let u: number = 1024 * 1024 * 1024;
  226. if (limit) {
  227. let num = Number(limit.slice(0, limit.length - 2));
  228. let unit: string = limit.slice(-2);
  229. switch (unit) {
  230. case 'EB':
  231. u = 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
  232. break;
  233. case 'PB':
  234. u = 1024 * 1024 * 1024 * 1024 * 1024;
  235. break;
  236. case 'TB':
  237. u = 1024 * 1024 * 1024 * 1024;
  238. break;
  239. case 'GB':
  240. u = 1024 * 1024 * 1024;
  241. break;
  242. case 'MB':
  243. u = 1024 * 1024;
  244. break;
  245. case 'KB':
  246. u = 1024;
  247. break;
  248. default:
  249. break;
  250. }
  251. return num * u;
  252. }
  253. return u;
  254. }
  255. onQiniuUpFile(file: any): Promise<string> {
  256. return new Promise((resolve, reject) => {
  257. console.log('进入了上传');
  258. let datepath = this.DateFormat(new Date(), 'hhmmss');
  259. let qiniuFileKey = this.company + '/' + datepath + '/' + file.name;
  260. const putExtra = {
  261. fname: '',
  262. params: {},
  263. mimeType: this.accept,
  264. };
  265. const config = {
  266. useCdnDomain: true, //使用cdn加速
  267. };
  268. const observable = qiniu.upload(
  269. file.file,
  270. qiniuFileKey,
  271. this.config.uptoken,
  272. putExtra,
  273. config
  274. );
  275. observable.subscribe({
  276. next: (result) => {
  277. // 主要用来展示进度
  278. console.log('上传===', result);
  279. },
  280. error: async (err) => {
  281. console.error(err);
  282. const toast = await this.toastController.create({
  283. message: '上传失败',
  284. color: 'warning',
  285. duration: 1000,
  286. });
  287. toast.present();
  288. reject(err);
  289. },
  290. complete: (res) => {
  291. console.log('上传完成');
  292. console.log(res.key);
  293. console.log(`${this.config.domain}${res.key}`);
  294. resolve(`${this.config.domain}${res.key}`);
  295. // this.loading.dismiss();
  296. },
  297. });
  298. });
  299. }
  300. async saveAttachment(
  301. file: { size?: number; url: string; name: string; type: string },
  302. cateId?: string
  303. ) {
  304. let Attachment = Parse.Object.extend('Attachment');
  305. let attachment = new Attachment();
  306. file.size && attachment.set('size', Math.ceil(file.size));
  307. attachment.set('url', file.url);
  308. attachment.set('name', file.name);
  309. attachment.set('mime', file.type);
  310. attachment.set('company', {
  311. __type: 'Pointer',
  312. className: 'Company',
  313. objectId: this.company,
  314. });
  315. cateId &&
  316. attachment.set('category', {
  317. __type: 'Pointer',
  318. className: 'Category',
  319. objectId: cateId,
  320. });
  321. return await attachment.save();
  322. }
  323. DateFormat(date: Date, fmt: string) {
  324. //author: meizz
  325. let o: any = {
  326. 'M+': date.getMonth() + 1, //月份
  327. 'd+': date.getDate(), //日
  328. 'h+': date.getHours(), //小时
  329. 'm+': date.getMinutes(), //分
  330. 's+': date.getSeconds(), //秒
  331. 'q+': Math.floor((date.getMonth() + 3) / 3), //季度
  332. S: date.getMilliseconds(), //毫秒
  333. };
  334. if (/(y+)/.test(fmt))
  335. fmt = fmt.replace(
  336. RegExp.$1,
  337. (date.getFullYear() + '').substr(4 - RegExp.$1.length)
  338. );
  339. for (let k in o)
  340. if (new RegExp('(' + k + ')').test(fmt))
  341. fmt = fmt.replace(
  342. RegExp.$1,
  343. RegExp.$1.length == 1
  344. ? o[k]
  345. : ('00' + o[k]).substr(('' + o[k]).length)
  346. );
  347. return fmt;
  348. }
  349. }