@solar-angular/platform-browser 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,643 @@
1
+ import { DOCUMENT, DatePipe } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Injectable, InjectionToken } from '@angular/core';
4
+ import { Observable, from, defer, map, shareReplay, firstValueFrom } from 'rxjs';
5
+
6
+ class FileManager {
7
+ constructor() {
8
+ this.document = inject(DOCUMENT);
9
+ }
10
+ /**
11
+ * Opens a file selection dialog.
12
+ * @param options - Options for the file selection.
13
+ * @returns A promise that resolves to an array of selected files.
14
+ * @see https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
15
+ */
16
+ pick(options) {
17
+ const input = this.document.createElement('input');
18
+ input.type = 'file';
19
+ input.accept = options.accept || '';
20
+ input.multiple = !!options.multiple;
21
+ return new Promise((resolve, reject) => {
22
+ input.onchange = () => {
23
+ resolve(Array.from(input.files || []));
24
+ };
25
+ input.onerror = reject;
26
+ input.click();
27
+ });
28
+ }
29
+ async download(url, filename) {
30
+ const response = await fetch(url);
31
+ const blob = await response.blob();
32
+ const anchor = this.document.createElement('a');
33
+ anchor.href = URL.createObjectURL(blob);
34
+ anchor.download = filename ?? new URL(url).pathname.split('/').pop();
35
+ anchor.click();
36
+ return blob;
37
+ }
38
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
39
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileManager, providedIn: 'root' }); }
40
+ }
41
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FileManager, decorators: [{
42
+ type: Injectable,
43
+ args: [{
44
+ providedIn: 'root'
45
+ }]
46
+ }] });
47
+
48
+ class FullscreenService {
49
+ constructor() {
50
+ this.document = inject(DOCUMENT);
51
+ }
52
+ /**
53
+ * 切换全屏
54
+ * @param target
55
+ * @param options
56
+ */
57
+ toggle(target = this.document.documentElement, options) {
58
+ if (this.isFullscreen(target)) {
59
+ return this.document.exitFullscreen();
60
+ }
61
+ return target.requestFullscreen(options);
62
+ }
63
+ /**
64
+ * 元素是否为全屏
65
+ * @param target
66
+ */
67
+ isFullscreen(target = this.document.documentElement) {
68
+ return target === this.document.fullscreenElement;
69
+ }
70
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FullscreenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
71
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FullscreenService, providedIn: 'root' }); }
72
+ }
73
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FullscreenService, decorators: [{
74
+ type: Injectable,
75
+ args: [{
76
+ providedIn: 'root'
77
+ }]
78
+ }] });
79
+
80
+ /**
81
+ * 目前 NG 库 中还不能包含 WebWorker,这里使用 DI 的方式,由 App 提供 WebWorker:
82
+ * ```ts
83
+ * {
84
+ * provide: IMAGE_COMPRESSOR_WEBWORKER_FACTORY,
85
+ * useValue: () => new Worker(new URL('xxx.worker', import.meta.url), { type: 'module' })
86
+ * }
87
+ * ```
88
+ * https://github.com/angular/angular-cli/issues/15059
89
+ */
90
+ const SUN_IMAGE_COMPRESSOR_WORKER_FACTORY = new InjectionToken('ImageCompressorWorkerFactory');
91
+ class ImageCompressor {
92
+ constructor() {
93
+ this.document = inject(DOCUMENT);
94
+ this.workerFactory = inject(SUN_IMAGE_COMPRESSOR_WORKER_FACTORY, { optional: true });
95
+ this.canvas = this.document.createElement('canvas');
96
+ }
97
+ /** 最佳图片格式,优先级:webp -> jpeg -> png */
98
+ get format() {
99
+ return this._format || (this._format = this.isSupportWEBP ? 'webp' : this.isSupportJPEG ? 'jpeg' : 'png');
100
+ }
101
+ /**
102
+ * 是否支持WebP格式
103
+ */
104
+ get isSupportWEBP() {
105
+ try {
106
+ return this.canvas.toDataURL('image/webp').startsWith('data:image/webp');
107
+ }
108
+ catch (e) {
109
+ return false;
110
+ }
111
+ }
112
+ /**
113
+ * 是否支持JPEG格式
114
+ */
115
+ get isSupportJPEG() {
116
+ try {
117
+ return this.canvas.toDataURL('image/jpeg').startsWith('data:image/jpeg');
118
+ }
119
+ catch (e) {
120
+ return false;
121
+ }
122
+ }
123
+ /**
124
+ * 压缩图片
125
+ * @param src 图片URL
126
+ * @param quality 质量
127
+ */
128
+ compress(src, quality = 0.85) {
129
+ const format = this.format;
130
+ const img = new Image();
131
+ img.crossOrigin = 'anonymous';
132
+ return new Observable((observer) => {
133
+ img.onload = () => {
134
+ this.resize(img);
135
+ (('OffscreenCanvas' in window && this.workerFactory) ? this.drawInWorker(img, quality, format) : this.draw(img, quality, format)).subscribe(blob => {
136
+ observer.next(blob);
137
+ observer.complete();
138
+ });
139
+ };
140
+ img.onerror = (error) => {
141
+ observer.error(error);
142
+ observer.complete();
143
+ };
144
+ img.src = src;
145
+ });
146
+ }
147
+ /**
148
+ * 调整图像尺寸
149
+ * @param img
150
+ */
151
+ resize(img) {
152
+ const maxWidth = 1280;
153
+ const maxHeight = 720;
154
+ if (img.width > maxWidth) {
155
+ const divisor = img.width / maxWidth;
156
+ img.width /= divisor;
157
+ img.height /= divisor;
158
+ }
159
+ if (img.height > maxHeight) {
160
+ const divisor = img.height / maxHeight;
161
+ img.width /= divisor;
162
+ img.height /= divisor;
163
+ }
164
+ }
165
+ /**
166
+ * 在主线程中绘制
167
+ * @param img 图像
168
+ * @param quality 质量
169
+ * @param format 格式
170
+ */
171
+ draw(img, quality, format) {
172
+ return new Observable(observer => {
173
+ const canvas = document.createElement('canvas');
174
+ canvas.width = img.width;
175
+ canvas.height = img.height;
176
+ const ctx = canvas.getContext('2d');
177
+ ctx.drawImage(img, 0, 0, img.width, img.height);
178
+ canvas.toBlob(blob => {
179
+ observer.next(blob);
180
+ observer.complete();
181
+ }, 'image/' + format, quality);
182
+ });
183
+ }
184
+ /**
185
+ * 在WebWorker线程中绘制
186
+ * @param img 图像
187
+ * @param quality 质量
188
+ * @param format 格式
189
+ */
190
+ drawInWorker(img, quality, format) {
191
+ const worker = this.workerFactory();
192
+ return new Observable(observer => {
193
+ const complete = () => {
194
+ worker.terminate();
195
+ observer.complete();
196
+ };
197
+ this.createImageBitmap(img).subscribe({
198
+ next: imageBitmap => {
199
+ worker.onmessage = ({ data }) => {
200
+ observer.next(data);
201
+ complete();
202
+ };
203
+ worker.onerror = error => {
204
+ observer.error(error);
205
+ complete();
206
+ };
207
+ worker.postMessage({ quality, format, imageBitmap }, [imageBitmap]);
208
+ },
209
+ error: error => {
210
+ observer.error(error);
211
+ complete();
212
+ }
213
+ });
214
+ });
215
+ }
216
+ /**
217
+ * 创建图像位图
218
+ * @param img 图像源
219
+ */
220
+ createImageBitmap(img) {
221
+ return from(window.createImageBitmap(img, {
222
+ resizeWidth: img.width,
223
+ resizeHeight: img.height
224
+ }).then(bitmap => {
225
+ // 某些情况下,图片宽度与高度会调换,因此这里要做一个判断
226
+ if (bitmap.width !== img.width) {
227
+ return window.createImageBitmap(img, {
228
+ resizeWidth: img.height,
229
+ resizeHeight: img.width
230
+ });
231
+ }
232
+ return bitmap;
233
+ }));
234
+ }
235
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageCompressor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
236
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageCompressor, providedIn: 'root' }); }
237
+ }
238
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageCompressor, decorators: [{
239
+ type: Injectable,
240
+ args: [{
241
+ providedIn: 'root'
242
+ }]
243
+ }] });
244
+
245
+ class ResourceLoader {
246
+ constructor() {
247
+ this.document = inject(DOCUMENT);
248
+ }
249
+ loadScript(url) {
250
+ return new Promise((resolve, reject) => {
251
+ const script = this.document.createElement('script');
252
+ script.type = 'text/javascript';
253
+ script.src = url;
254
+ script.onload = () => resolve();
255
+ script.onerror = () => {
256
+ this.document.head.removeChild(script);
257
+ reject();
258
+ };
259
+ this.document.head.appendChild(script);
260
+ });
261
+ }
262
+ loadStylesheet(url) {
263
+ return new Promise((resolve, reject) => {
264
+ const link = this.document.createElement('link');
265
+ link.rel = 'stylesheet';
266
+ link.type = 'text/css';
267
+ link.href = url;
268
+ link.onload = () => resolve();
269
+ link.onerror = () => {
270
+ this.document.head.removeChild(link);
271
+ reject();
272
+ };
273
+ this.document.head.appendChild(link);
274
+ });
275
+ }
276
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResourceLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
277
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResourceLoader, providedIn: 'root' }); }
278
+ }
279
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ResourceLoader, decorators: [{
280
+ type: Injectable,
281
+ args: [{
282
+ providedIn: 'root'
283
+ }]
284
+ }] });
285
+
286
+ const EXCEL_COL_ALIAS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
287
+ const NUMBER_PATTERN = /[0-9]/g;
288
+ const CHAR_PATTERN = /[a-zA-Z]/g;
289
+ class SpreadsheetService {
290
+ constructor() {
291
+ this.document = inject(DOCUMENT);
292
+ this.resourceLoader = inject(ResourceLoader);
293
+ this.datePipe = new DatePipe('zh-CN');
294
+ // ExcelJS 对象,用时异步自动加载
295
+ this.excel = defer(() => Promise.all([
296
+ this.resourceLoader.loadScript('https://img.omofresh.com/js/aieyes-exceljs-o_1_8_10.min.js'), // 修改过的 https://www.npmjs.com/package/aieyes-exceljs-o
297
+ this.resourceLoader.loadStylesheet('https://img.omofresh.com/css/exceljs.min.css'), // aieyes-exceljs-o 中定义的
298
+ ])).pipe(map(() => ExcelJS), shareReplay(1));
299
+ }
300
+ /**
301
+ * 根据当前的单元格找到下一列的地址
302
+ * 采用倒序进位法,这样就不需要递归了
303
+ */
304
+ nextColOfCell(cell) {
305
+ // 先把字母和数字分开,字母是列,数字是行,倒序排列
306
+ const args = cell.match(CHAR_PATTERN).reverse();
307
+ let needAppend = false;
308
+ for (let i = 0; i < args.length; i++) {
309
+ const arg = args[i];
310
+ if (arg !== 'Z') {
311
+ const idx = EXCEL_COL_ALIAS.indexOf(arg);
312
+ args[i] = EXCEL_COL_ALIAS[idx + 1];
313
+ break;
314
+ }
315
+ else {
316
+ args[i] = 'A';
317
+ if (i === args.length - 1) { // 说明是最后一个了,需要补A
318
+ needAppend = true;
319
+ }
320
+ }
321
+ }
322
+ if (needAppend) {
323
+ args.push('A');
324
+ }
325
+ return args.reverse().join(''); // 最终的结果,反转再合并
326
+ }
327
+ /**
328
+ * 获取单元格的行
329
+ */
330
+ rowOfCell(cell) {
331
+ return cell.match(NUMBER_PATTERN).join('');
332
+ }
333
+ /**
334
+ * 获取单元格的列
335
+ */
336
+ colOfCell(cell) {
337
+ return cell.match(CHAR_PATTERN).join('');
338
+ }
339
+ /**
340
+ * 单元格的列号
341
+ * 当作26进制计算列的编号
342
+ */
343
+ colNumberOfCell(cell) {
344
+ let col = 0;
345
+ cell.match(CHAR_PATTERN).reverse().forEach((c, i) => {
346
+ if (i == 0) {
347
+ // 个位
348
+ col += EXCEL_COL_ALIAS.indexOf(c) + 1;
349
+ }
350
+ else {
351
+ // 十位以上
352
+ col += (EXCEL_COL_ALIAS.indexOf(c) + 1) * i * 26;
353
+ }
354
+ });
355
+ return col;
356
+ }
357
+ async parseDomTable(table, _opts) {
358
+ const excel = await firstValueFrom(this.excel);
359
+ return excel.TableParser.utils.parseDomTable(table, _opts);
360
+ }
361
+ /**
362
+ * 只导出一个table, 内容放在第一个sheet上
363
+ */
364
+ async exportDomTableById(tableId, fileName, _opts) {
365
+ const table = this.document.getElementById(tableId);
366
+ const excel = await firstValueFrom(this.excel);
367
+ const wb = new excel.Workbook();
368
+ const ws = wb.addWorksheet(fileName);
369
+ const re = await this.exportDomTable(wb, ws, table, null, null, _opts);
370
+ await this.saveAsFile(re.wb, fileName);
371
+ }
372
+ /**
373
+ * 导出多个table, 内容放在多个sheet上
374
+ */
375
+ async exportDomTableSheets(tableIds, sheetNames, fileName, _opts) {
376
+ const excel = await firstValueFrom(this.excel);
377
+ let wb = new excel.Workbook();
378
+ for (let index = 0; index < tableIds.length; index++) {
379
+ const table = this.document.getElementById(tableIds[index]);
380
+ const sheetName = sheetNames[index];
381
+ const ws = wb.addWorksheet(sheetName);
382
+ const re = await this.exportDomTable(wb, ws, table, null, null, _opts);
383
+ wb = re.wb;
384
+ }
385
+ await this.saveAsFile(wb, fileName);
386
+ }
387
+ /**
388
+ * 在一页中导出多个table, 每个table默认间隔1列
389
+ */
390
+ async exportDomTableParallel(tableIds, fileName, gap = 1, _opts) {
391
+ const excel = await firstValueFrom(this.excel);
392
+ let wb = new excel.Workbook();
393
+ const ws = wb.addWorksheet(fileName);
394
+ let cursor = 'A'; // 从第一列开始导出,并列几个table
395
+ for (const tableId of tableIds) {
396
+ const table = this.document.getElementById(tableId);
397
+ const re = await this.exportDomTable(wb, ws, table, cursor, null, _opts);
398
+ const lastCol = re.cols[re.cols.length - 1];
399
+ cursor = this.nextColOfCell(lastCol);
400
+ for (let k = 0; k < gap; k++) {
401
+ cursor = this.nextColOfCell(cursor);
402
+ }
403
+ wb = re.wb;
404
+ }
405
+ await this.saveAsFile(wb, fileName);
406
+ }
407
+ /**
408
+ * 在一页中垂直导出多个table
409
+ */
410
+ async exportDomTableVertical(tableIds, fileName, gap = 0, _opts) {
411
+ let rowOffset = 0;
412
+ const excel = await firstValueFrom(this.excel);
413
+ let wb = new excel.Workbook();
414
+ const ws = wb.addWorksheet(fileName);
415
+ for (const tableId of tableIds) {
416
+ const table = this.document.getElementById(tableId);
417
+ const re = await this.exportDomTable(wb, ws, table, null, rowOffset, _opts);
418
+ rowOffset += re.rows.length + gap;
419
+ wb = re.wb;
420
+ }
421
+ await this.saveAsFile(wb, fileName);
422
+ }
423
+ /**
424
+ * 导出dom table
425
+ * colCursor: 标记起始列
426
+ * rowOffset: 偏移的行数
427
+ * @return 返回最后一列的列名
428
+ */
429
+ async exportDomTable(wb, ws, table, colCursor, rowOffset, _opts) {
430
+ if (!_opts) {
431
+ _opts = { cellDates: true, dateNF: 'yyyy/M/d' }; // 默认的日期格式
432
+ }
433
+ else {
434
+ _opts.cellDates = true;
435
+ }
436
+ const ref = await this.parseDomTable(table, _opts);
437
+ let colOffset = 0; // colCursor偏移量,默认为0
438
+ if (colCursor) {
439
+ const c = ws.getColumn(colCursor);
440
+ colOffset = c.number - 1;
441
+ }
442
+ rowOffset = rowOffset || 0; // rowOffset默认为0
443
+ const cellMap = {};
444
+ Object.keys(ref).sort().forEach(cellAlias => {
445
+ if (!cellAlias.startsWith('!')) {
446
+ let rowNum = this.rowOfCell(cellAlias);
447
+ rowNum = String(parseInt(rowNum, 10) + rowOffset);
448
+ const colNum = this.colNumberOfCell(cellAlias);
449
+ const col = ws.getColumn(colOffset + colNum); // 根据偏移量找出所在的列
450
+ const finalCell = col.letter + rowNum;
451
+ cellMap[finalCell] = ref[cellAlias];
452
+ }
453
+ });
454
+ const colSet = new Set();
455
+ Object.keys(cellMap).forEach(k => {
456
+ colSet.add(this.colOfCell(k));
457
+ });
458
+ let cols = Array.from(colSet);
459
+ // 因为excel的列都是连续的,如果导出table存在跨列的话这里面可能却少某一列,所以需要补充缺少的列名保证这一段是连续的
460
+ let cursor = cols[0];
461
+ for (let i = 0; i < ref['!cols'].length - 1; i++) {
462
+ const next = this.nextColOfCell(cursor);
463
+ colSet.add(next);
464
+ cursor = next;
465
+ }
466
+ cols = Array.from(colSet).sort((a, b) => {
467
+ if (a.length === b.length) {
468
+ return a.localeCompare(b);
469
+ }
470
+ else if (a.length > b.length) {
471
+ return 1;
472
+ }
473
+ else if (b.length > a.length) {
474
+ return -1;
475
+ }
476
+ return -1;
477
+ });
478
+ // 赋值
479
+ Object.keys(cellMap).forEach(alias => {
480
+ const cell = ws.getCell(alias);
481
+ const cellConfig = cellMap[alias];
482
+ if (cellConfig.t === 'd') { // 日期格式需格式化后显示,换言之转为了字符串
483
+ cell.value = this.datePipe.transform(cellConfig.v, cellConfig.z);
484
+ }
485
+ else {
486
+ cell.value = cellConfig.v;
487
+ }
488
+ // 默认就有边框的
489
+ if (cellConfig.style.bordered) { // 表示需要加边框
490
+ cell.style.border = {
491
+ top: { style: 'thin' },
492
+ left: { style: 'thin' },
493
+ bottom: { style: 'thin' },
494
+ right: { style: 'thin' }
495
+ };
496
+ }
497
+ // 默认内容垂直居中,左右居中不一定
498
+ cell.style.alignment = {
499
+ horizontal: cellConfig.style.align,
500
+ vertical: 'middle',
501
+ wrapText: true
502
+ };
503
+ // 字体默认为宋体
504
+ cell.style.font = {
505
+ bold: cellConfig.style.bold,
506
+ name: '宋体',
507
+ size: cellConfig.style.pound // 字号
508
+ };
509
+ // 背景色/前景色
510
+ if (cellConfig.style.background) {
511
+ cell.fill = {
512
+ type: 'pattern',
513
+ pattern: 'solid',
514
+ fgColor: { argb: cellConfig.style.background }, // 实际上fgColor是理解上的背景色,而不是前景色,不知道excel怎么定义的
515
+ // bgColor: {argb: 'ffd8e6de'}
516
+ };
517
+ }
518
+ });
519
+ // 设置每行的高度
520
+ ref['!rows'].forEach((rowConfig, rowIndex) => {
521
+ const row = ws.getRow(rowIndex + rowOffset + 1);
522
+ row.height = rowConfig.height;
523
+ });
524
+ // 设置列宽
525
+ ref['!cols'].forEach((colConfig, colIndex) => {
526
+ const colAlias = cols[colIndex];
527
+ const col = ws.getColumn(colAlias);
528
+ if (colConfig.width) {
529
+ col.width = colConfig.width;
530
+ }
531
+ });
532
+ // 合并单元格, 由于不一定有,所以要判断一下
533
+ ref['!merges']?.forEach(mergeParam => {
534
+ const s = mergeParam['s'];
535
+ const e = mergeParam['e'];
536
+ const startCell = ws.getCell(rowOffset + s.r + 1, colOffset + s.c + 1);
537
+ const endCell = ws.getCell(rowOffset + e.r + 1, colOffset + e.c + 1);
538
+ ws.mergeCells([startCell.address, endCell.address]);
539
+ });
540
+ return { wb, cols, rows: ref['!rows'] };
541
+ }
542
+ /**
543
+ * 保存Workbook到磁盘上
544
+ */
545
+ async saveAsFile(wb, fileName) {
546
+ const excelData = await wb.xlsx.writeBuffer();
547
+ const blob = new Blob([excelData], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" /* MediaType.Xlsx */ });
548
+ const anchor = document.createElement('a');
549
+ anchor.href = URL.createObjectURL(blob);
550
+ anchor.download = fileName + '.xlsx';
551
+ anchor.click();
552
+ }
553
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SpreadsheetService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
554
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SpreadsheetService, providedIn: 'root' }); }
555
+ }
556
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SpreadsheetService, decorators: [{
557
+ type: Injectable,
558
+ args: [{
559
+ providedIn: 'root'
560
+ }]
561
+ }] });
562
+
563
+ class LocalStorage {
564
+ constructor() {
565
+ this.storage = inject(DOCUMENT).defaultView.localStorage;
566
+ }
567
+ /**
568
+ * 保存数据
569
+ * @param key 键名
570
+ * @param value 数据
571
+ */
572
+ set(key, value) {
573
+ this.storage.setItem(key, JSON.stringify(value));
574
+ }
575
+ /**
576
+ * 获取数据
577
+ * @param key 键名
578
+ */
579
+ get(key) {
580
+ const data = this.storage.getItem(key);
581
+ return data ? JSON.parse(data) : null;
582
+ }
583
+ /**
584
+ * 移除数据
585
+ * @param key 键名
586
+ */
587
+ remove(key) {
588
+ this.storage.removeItem(key);
589
+ }
590
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorage, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
591
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorage, providedIn: 'root' }); }
592
+ }
593
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LocalStorage, decorators: [{
594
+ type: Injectable,
595
+ args: [{
596
+ providedIn: 'root'
597
+ }]
598
+ }] });
599
+
600
+ class SessionStorage {
601
+ constructor() {
602
+ this.storage = inject(DOCUMENT).defaultView.sessionStorage;
603
+ }
604
+ /**
605
+ * 保存数据
606
+ * @param key 键名
607
+ * @param value 数据
608
+ */
609
+ set(key, value) {
610
+ this.storage.setItem(key, JSON.stringify(value));
611
+ }
612
+ /**
613
+ * 获取数据
614
+ * @param key 键名
615
+ * @param defaults 默认值
616
+ */
617
+ get(key) {
618
+ const data = this.storage.getItem(key);
619
+ return data ? JSON.parse(data) : null;
620
+ }
621
+ /**
622
+ * 移除数据
623
+ * @param key 键名
624
+ */
625
+ remove(key) {
626
+ this.storage.removeItem(key);
627
+ }
628
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SessionStorage, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
629
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SessionStorage, providedIn: 'root' }); }
630
+ }
631
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SessionStorage, decorators: [{
632
+ type: Injectable,
633
+ args: [{
634
+ providedIn: 'root'
635
+ }]
636
+ }] });
637
+
638
+ /**
639
+ * Generated bundle index. Do not edit.
640
+ */
641
+
642
+ export { FileManager, FullscreenService, ImageCompressor, LocalStorage, ResourceLoader, SUN_IMAGE_COMPRESSOR_WORKER_FACTORY, SessionStorage, SpreadsheetService };
643
+ //# sourceMappingURL=solar-angular-platform-browser.mjs.map