@luoxiao123/angular-material-date-time-range-picker 21.1.1 → 21.1.3

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, model, output, ChangeDetectionStrategy, Component, input, computed, ChangeDetectorRef, signal, ViewChild, ElementRef, Injector, DestroyRef, effect, untracked, forwardRef, Input, Injectable } from '@angular/core';
2
+ import { model, output, ChangeDetectionStrategy, Component, input, computed, inject, signal, ViewChild, ElementRef, Injector, DestroyRef, effect, untracked, forwardRef, Input } from '@angular/core';
3
3
  import { Subject, take, tap } from 'rxjs';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import * as i1 from '@angular/material/datepicker';
@@ -8,8 +8,8 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
8
8
  import { TablerIconComponent, provideTablerIcons } from '@luoxiao123/angular-tabler-icons';
9
9
  import { IconLayoutSidebarLeftCollapse, IconClock, IconX, IconCalendarDue, IconInfoCircle } from '@luoxiao123/angular-tabler-icons/icons';
10
10
  import * as i2 from '@angular/forms';
11
- import { FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
12
- import { MatFormField, MatFormFieldControl } from '@angular/material/form-field';
11
+ import { FormsModule, ReactiveFormsModule, NgControl } from '@angular/forms';
12
+ import { MatFormFieldControl } from '@angular/material/form-field';
13
13
  import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
14
14
  import { FocusMonitor } from '@angular/cdk/a11y';
15
15
  import * as i3$1 from '@angular/common';
@@ -20,12 +20,9 @@ import * as i2$1 from '@angular/material/sidenav';
20
20
  import { MatSidenavModule } from '@angular/material/sidenav';
21
21
  import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
22
22
  import * as i1$1 from '@angular/cdk/bidi';
23
- import { MatBottomSheet } from '@angular/material/bottom-sheet';
24
23
 
25
24
  class Container {
26
25
  constructor() {
27
- this.#breakpoints = inject(BreakpointObserver);
28
- this.isMobile = this.#breakpoints.isMatched([Breakpoints.Handset, Breakpoints.Tablet]);
29
26
  this.hasHeader = model(true, ...(ngDevMode ? [{ debugName: "hasHeader" }] : []));
30
27
  this.hasFooter = model(true, ...(ngDevMode ? [{ debugName: "hasFooter" }] : []));
31
28
  this.headerTitle = model('', ...(ngDevMode ? [{ debugName: "headerTitle" }] : []));
@@ -48,7 +45,6 @@ class Container {
48
45
  this.submit = output();
49
46
  this.secondaryButton = output();
50
47
  }
51
- #breakpoints;
52
48
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: Container, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
53
49
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: Container, isStandalone: true, selector: "date-time-picker-container", inputs: { hasHeader: { classPropertyName: "hasHeader", publicName: "hasHeader", isSignal: true, isRequired: false, transformFunction: null }, hasFooter: { classPropertyName: "hasFooter", publicName: "hasFooter", isSignal: true, isRequired: false, transformFunction: null }, headerTitle: { classPropertyName: "headerTitle", publicName: "headerTitle", isSignal: true, isRequired: false, transformFunction: null }, headerExtraContent: { classPropertyName: "headerExtraContent", publicName: "headerExtraContent", isSignal: true, isRequired: false, transformFunction: null }, footerExtraContent: { classPropertyName: "footerExtraContent", publicName: "footerExtraContent", isSignal: true, isRequired: false, transformFunction: null }, hasDismiss: { classPropertyName: "hasDismiss", publicName: "hasDismiss", isSignal: true, isRequired: false, transformFunction: null }, hasSubmit: { classPropertyName: "hasSubmit", publicName: "hasSubmit", isSignal: true, isRequired: false, transformFunction: null }, submitTitle: { classPropertyName: "submitTitle", publicName: "submitTitle", isSignal: true, isRequired: false, transformFunction: null }, submitBg: { classPropertyName: "submitBg", publicName: "submitBg", isSignal: true, isRequired: false, transformFunction: null }, submitColor: { classPropertyName: "submitColor", publicName: "submitColor", isSignal: true, isRequired: false, transformFunction: null }, submitTitleColor: { classPropertyName: "submitTitleColor", publicName: "submitTitleColor", isSignal: true, isRequired: false, transformFunction: null }, disabledSubmit: { classPropertyName: "disabledSubmit", publicName: "disabledSubmit", isSignal: true, isRequired: false, transformFunction: null }, hasSecondaryButton: { classPropertyName: "hasSecondaryButton", publicName: "hasSecondaryButton", isSignal: true, isRequired: false, transformFunction: null }, secondaryButtonTitle: { classPropertyName: "secondaryButtonTitle", publicName: "secondaryButtonTitle", isSignal: true, isRequired: false, transformFunction: null }, secondaryButtonBg: { classPropertyName: "secondaryButtonBg", publicName: "secondaryButtonBg", isSignal: true, isRequired: false, transformFunction: null }, secondaryButtonColor: { classPropertyName: "secondaryButtonColor", publicName: "secondaryButtonColor", isSignal: true, isRequired: false, transformFunction: null }, secondaryButtonTitleColor: { classPropertyName: "secondaryButtonTitleColor", publicName: "secondaryButtonTitleColor", isSignal: true, isRequired: false, transformFunction: null }, disabledSecondaryButton: { classPropertyName: "disabledSecondaryButton", publicName: "disabledSecondaryButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hasHeader: "hasHeaderChange", hasFooter: "hasFooterChange", headerTitle: "headerTitleChange", headerExtraContent: "headerExtraContentChange", footerExtraContent: "footerExtraContentChange", hasDismiss: "hasDismissChange", hasSubmit: "hasSubmitChange", submitTitle: "submitTitleChange", submitBg: "submitBgChange", submitColor: "submitColorChange", submitTitleColor: "submitTitleColorChange", disabledSubmit: "disabledSubmitChange", hasSecondaryButton: "hasSecondaryButtonChange", secondaryButtonTitle: "secondaryButtonTitleChange", secondaryButtonBg: "secondaryButtonBgChange", secondaryButtonColor: "secondaryButtonColorChange", secondaryButtonTitleColor: "secondaryButtonTitleColorChange", disabledSecondaryButton: "disabledSecondaryButtonChange", dismiss: "dismiss", submit: "submit", secondaryButton: "secondaryButton" }, providers: [provideTablerIcons({ IconInfoCircle, IconCalendarDue, IconX, IconClock, IconLayoutSidebarLeftCollapse })], ngImport: i0, template: "<aside class=\"container-wrapper\">\r\n @if (hasHeader()) {\r\n <header class=\"container-header\">\r\n <div class=\"container-header-start\">\r\n <i-tabler name=\"clock\" strokeWidth=\"2px\" size=\"18px\" class=\"container-header-icon\" />\r\n\r\n @if (headerTitle()) {\r\n <h2 class=\"container-header-title\">{{ headerTitle() }}</h2>\r\n }\r\n </div>\r\n\r\n @if (headerExtraContent()) {\r\n <div class=\"container-header-extra\">\r\n <ng-container *ngTemplateOutlet=\"headerExtraContent() ?? null\"></ng-container>\r\n </div>\r\n }\r\n\r\n <button (click)=\"dismiss.emit()\" type=\"button\" class=\"container-header-close\" [attr.aria-label]=\"'\u5173\u95ED'\" tabindex=\"0\">\r\n <i-tabler name=\"x\" strokeWidth=\"2.5px\" size=\"18px\" class=\"container-header-close-icon\" />\r\n </button>\r\n </header>\r\n }\r\n\r\n <main class=\"container-main\">\r\n <ng-content />\r\n </main>\r\n\r\n @if (hasFooter()) {\r\n <footer class=\"container-footer\">\r\n @if (footerExtraContent()) {\r\n <div class=\"container-footer-extra\">\r\n <ng-container *ngTemplateOutlet=\"footerExtraContent() ?? null\"></ng-container>\r\n </div>\r\n }\r\n\r\n <div class=\"container-footer-actions\">\r\n @if (hasDismiss()) {\r\n <button mat-stroked-button color=\"primary\" (click)=\"dismiss.emit()\" type=\"button\"> \u53D6\u6D88 </button>\r\n }\r\n\r\n @if (hasSecondaryButton()) {\r\n <button mat-stroked-button color=\"primary\" (click)=\"secondaryButton.emit()\" type=\"button\" [disabled]=\"disabledSecondaryButton()\">\r\n {{ secondaryButtonTitle() }}\r\n </button>\r\n }\r\n\r\n @if (hasSubmit()) {\r\n <button mat-raised-button color=\"primary\" (click)=\"submit.emit()\" type=\"button\" [disabled]=\"disabledSubmit()\">\r\n {{ submitTitle() }}\r\n </button>\r\n }\r\n </div>\r\n </footer>\r\n }\r\n</aside>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;height:100%}.container-wrapper{width:100%;height:100%;display:flex;flex-direction:column;justify-content:space-between;overflow:hidden}.container-header{width:100%;padding:12px 16px;display:flex;gap:12px;justify-content:space-between;align-items:center;background-color:var(--mat-sys-surface-container-low, #fafafa);border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));-webkit-user-select:none;user-select:none;flex-shrink:0;box-sizing:border-box}.container-header-start{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.container-header-icon{color:var(--mat-sys-primary, #1976d2);flex-shrink:0}.container-header-title{font-size:.9375rem;font-weight:500;line-height:1.35;color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.container-header-extra{display:flex;align-items:center;gap:8px;flex:1;padding:0 4px;font-size:.75rem}.container-header-close{width:32px;height:32px;padding:0;display:flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:4px;cursor:pointer;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));transition:background-color .2s ease;flex-shrink:0}.container-header-close:hover{background-color:var(--mat-sys-surface-container-highest, rgba(0, 0, 0, .08))}.container-header-close:focus-visible{outline:2px solid var(--mat-sys-primary, #1976d2);outline-offset:2px}.container-header-close-icon{display:flex;align-items:center;justify-content:center}.container-main{flex:1;width:100%;display:flex;overflow-y:auto;overflow-x:hidden;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12))}.container-footer{width:100%;padding:12px 16px;display:flex;gap:12px;justify-content:flex-end;align-items:center;background-color:var(--mat-sys-surface-container-low, #fafafa);border-top:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));-webkit-user-select:none;user-select:none;flex-shrink:0;box-sizing:border-box}.container-footer-extra{display:flex;align-items:center;gap:8px;margin-right:auto;font-size:.75rem;padding:0 4px}.container-footer-actions{display:flex;gap:8px;align-items:center;flex-shrink:0}\n", ":host{height:100%}\n"], dependencies: [{ kind: "component", type: TablerIconComponent, selector: "i-tabler, tabler-icon", inputs: ["name"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
54
50
  }
@@ -95,20 +91,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
95
91
  args: [{ selector: 'date-time-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatDatepickerModule, FormsModule, TablerIconComponent, CommonModule], template: "<div class=\"date-time-input-wrapper\">\r\n <label class=\"date-time-input-label\">{{ label() }}</label>\r\n\r\n <div class=\"date-time-input-container\">\r\n <!-- \u65E5\u671F\u90E8\u5206 -->\r\n <div class=\"date-time-input-date\">\r\n <input\r\n type=\"text\"\r\n matInput\r\n [ngModel]=\"dateObj()\"\r\n (ngModelChange)=\"onDateChange($event)\"\r\n [matDatepicker]=\"datePicker\"\r\n (click)=\"datePicker.open()\"\r\n (focus)=\"datePicker.open()\"\r\n placeholder=\"\u9009\u62E9\u65E5\u671F\"\r\n class=\"date-time-input-field\"\r\n />\r\n <mat-datepicker #datePicker></mat-datepicker>\r\n\r\n <button type=\"button\" class=\"date-time-input-icon-btn\" tabindex=\"-1\" aria-hidden=\"true\">\r\n <i-tabler name=\"calendar-due\" strokeWidth=\"2px\" size=\"16px\" />\r\n </button>\r\n </div>\r\n\r\n <!-- \u5206\u9694\u7B26 -->\r\n <div class=\"date-time-input-divider\"></div>\r\n\r\n <!-- \u65F6\u95F4\u90E8\u5206 -->\r\n <div class=\"date-time-input-time\">\r\n <!-- \u5C0F\u65F6 -->\r\n <select class=\"date-time-input-select date-time-input-select-hour\" [ngModel]=\"hourValue()\" (ngModelChange)=\"onHourChange($event)\" [attr.aria-label]=\"'\u5C0F\u65F6'\">\r\n <option [ngValue]=\"null\" disabled>--</option>\r\n @for (hour of hours(); track hour) {\r\n <option [ngValue]=\"hour\">{{ hour | number: '2.0-0' }}</option>\r\n }\r\n </select>\r\n\r\n <!-- \u5206\u9694\u7B26 -->\r\n <span class=\"date-time-input-separator\">:</span>\r\n\r\n <!-- \u5206\u949F -->\r\n <select class=\"date-time-input-select date-time-input-select-minute\" [ngModel]=\"minuteValue()\" (ngModelChange)=\"onMinuteChange($event)\" [attr.aria-label]=\"'\u5206\u949F'\">\r\n <option [ngValue]=\"null\" disabled>--</option>\r\n @for (minute of minutes(); track minute) {\r\n <option [ngValue]=\"minute\">{{ minute | number: '2.0-0' }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{display:block}:host .date-time-input-wrapper{display:flex;flex-direction:column;gap:8px;padding:12px 16px}@media(max-width:767px){:host .date-time-input-wrapper{padding-bottom:0}}:host .date-time-input-label{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}:host .date-time-input-container{display:flex;align-items:center;width:100%;max-width:100%;border:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));border-radius:4px;overflow:hidden;background-color:var(--mat-sys-surface-container-low, rgba(0, 0, 0, .02));transition:border-color .2s ease;box-sizing:border-box}:host .date-time-input-container:hover{border-color:var(--mat-divider-color, rgba(0, 0, 0, .24))}:host .date-time-input-container:focus-within{border-color:var(--mat-sys-primary, #1976d2);background-color:var(--mat-sys-surface, #fff)}:host .date-time-input-date{flex:1;display:flex;align-items:center;position:relative;padding:0 8px;min-width:0;overflow:hidden}:host .date-time-input-field{flex:1;height:36px;padding:0;border:none;background:transparent;color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));font-size:.875rem;min-width:0;overflow:hidden;text-overflow:ellipsis}:host .date-time-input-field::placeholder{color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .4))}:host .date-time-input-field:focus{outline:none}:host .date-time-input-icon-btn{position:absolute;right:0;width:24px;height:24px;padding:0;display:flex;align-items:center;justify-content:center;background:transparent;border:none;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));pointer-events:none}:host .date-time-input-divider{width:1px;height:20px;background-color:var(--mat-divider-color, rgba(0, 0, 0, .12))}:host .date-time-input-time{flex:1;display:flex;min-width:0;align-items:center;gap:2px;padding:0 8px}:host .date-time-input-select{flex:1;height:36px;border:none;background:transparent;color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));font-size:.875rem;font-weight:500;padding:0 2px;cursor:pointer;text-align:center}:host .date-time-input-select:focus{outline:none}:host .date-time-input-separator{color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));font-weight:500;padding:0 2px;-webkit-user-select:none;user-select:none}\n"] }]
96
92
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], dateValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateValue", required: false }] }], hourValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourValue", required: false }] }], minuteValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteValue", required: false }] }], hours: [{ type: i0.Input, args: [{ isSignal: true, alias: "hours", required: false }] }], minutes: [{ type: i0.Input, args: [{ isSignal: true, alias: "minutes", required: false }] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], hourChange: [{ type: i0.Output, args: ["hourChange"] }], minuteChange: [{ type: i0.Output, args: ["minuteChange"] }], timeChange: [{ type: i0.Output, args: ["timeChange"] }] } });
97
93
 
94
+ /**
95
+ * 格式化日期对象为字符串
96
+ *
97
+ * 将给定的 Date 对象格式化为包含日期和时间的字符串。
98
+ * 日期部分使用提供的 DateAdapter 和 MatDateFormats 进行格式化。
99
+ * 时间部分格式化为 HH:mm (24小时制)。
100
+ *
101
+ * @param date - 要格式化的 Date 对象
102
+ * @param dateAdapter - Angular Material 的 DateAdapter,用于处理日期部分的格式化
103
+ * @param dateFormats - Angular Material 的 MatDateFormats,包含日期格式配置
104
+ * @returns 格式化后的日期时间字符串,例如 "2024-01-24 14:30"
105
+ */
106
+ function formatDate(date, dateAdapter, dateFormats) {
107
+ const datePart = dateAdapter.format(date, dateFormats.display.dateInput);
108
+ const hours = date.getHours().toString().padStart(2, '0');
109
+ const minutes = date.getMinutes().toString().padStart(2, '0');
110
+ return `${datePart} ${hours}:${minutes}`;
111
+ }
112
+
113
+ const DEFAULT_TIME_RANGES = [
114
+ { label: '最近5分钟', start: 'offset:-5minutes', end: 'offset:now' },
115
+ { label: '最近15分钟', start: 'offset:-15minutes', end: 'offset:now' },
116
+ { label: '最近30分钟', start: 'offset:-30minutes', end: 'offset:now' },
117
+ { label: '最近1小时', start: 'offset:-1hours', end: 'offset:now' },
118
+ { label: '最近3小时', start: 'offset:-3hours', end: 'offset:now' },
119
+ { label: '最近6小时', start: 'offset:-6hours', end: 'offset:now' },
120
+ { label: '最近12小时', start: 'offset:-12hours', end: 'offset:now' },
121
+ { label: '最近24小时', start: 'offset:-24hours', end: 'offset:now' },
122
+ { label: '最近2天', start: 'offset:-2days', end: 'offset:now' },
123
+ { label: '最近7天', start: 'offset:-7days', end: 'offset:now' },
124
+ { label: '最近30天', start: 'offset:-30days', end: 'offset:now' },
125
+ { label: '最近90天', start: 'offset:-90days', end: 'offset:now' },
126
+ { label: '最近6个月', start: 'offset:-6months', end: 'offset:now' },
127
+ { label: '最近1年', start: 'offset:-1years', end: 'offset:now' },
128
+ { label: '最近2年', start: 'offset:-2years', end: 'offset:now' },
129
+ { label: '最近5年', start: 'offset:-5years', end: 'offset:now' },
130
+ { label: '昨天', start: 'offset:-1days/start', end: 'offset:-1days/end' },
131
+ { label: '前天', start: 'offset:-2days/start', end: 'offset:-2days/end' },
132
+ { label: '上周同一天', start: 'offset:-7days/start', end: 'offset:-7days/end' },
133
+ { label: '今天', start: 'offset:0days/start', end: 'offset:0days/end' },
134
+ { label: '今天至今', start: 'offset:0days/start', end: 'offset:now' },
135
+ { label: '本周至今', start: 'startof:week', end: 'offset:now' },
136
+ { label: '本月至今', start: 'startof:month', end: 'offset:now' },
137
+ { label: '今年至今', start: 'startof:year', end: 'offset:now' }
138
+ ];
139
+ const FUTURE_TIME_RANGES = [
140
+ { label: '未来1天', start: 'offset:now', end: 'offset:+1days' },
141
+ { label: '未来1周', start: 'offset:now', end: 'offset:+1weeks' },
142
+ { label: '未来1月', start: 'offset:now', end: 'offset:+1months' },
143
+ { label: '未来3月', start: 'offset:now', end: 'offset:+3months' }
144
+ ];
145
+
98
146
  class DateSelector {
99
- #cdr;
100
147
  #dialogRef;
101
148
  #data;
102
149
  #selectionModel;
103
150
  #breakpoints;
104
- formatDate(date) {
105
- const datePart = this._dateAdapter.format(date, this._dateFormats.display.dateInput);
106
- const hours = date.getHours().toString().padStart(2, '0');
107
- const minutes = date.getMinutes().toString().padStart(2, '0');
108
- return `${datePart} ${hours}:${minutes}`;
109
- }
110
151
  constructor() {
111
- this.#cdr = inject(ChangeDetectorRef);
112
152
  this.#dialogRef = inject((MatDialogRef));
113
153
  this.#data = inject(MAT_DIALOG_DATA);
114
154
  this.#selectionModel = inject((MatRangeDateSelectionModel));
@@ -117,7 +157,6 @@ class DateSelector {
117
157
  this._dateFormats = inject(MAT_DATE_FORMATS);
118
158
  this.isMobile = signal(false, ...(ngDevMode ? [{ debugName: "isMobile" }] : []));
119
159
  this.data = this.#data;
120
- this.valueFormat = this.data?.valueFormat ?? 'yyyy-MM-dd HH:mm';
121
160
  this.startDate = model('', ...(ngDevMode ? [{ debugName: "startDate" }] : []));
122
161
  this.endDate = model('', ...(ngDevMode ? [{ debugName: "endDate" }] : []));
123
162
  this.startHour = model(null, ...(ngDevMode ? [{ debugName: "startHour" }] : []));
@@ -129,71 +168,21 @@ class DateSelector {
129
168
  const startStr = this.startDate();
130
169
  if (!startStr)
131
170
  return '';
132
- return this.formatDate(new Date(startStr));
171
+ return formatDate(new Date(startStr), this._dateAdapter, this._dateFormats);
133
172
  }, ...(ngDevMode ? [{ debugName: "displayStart" }] : []));
134
173
  this.displayEnd = computed(() => {
135
174
  const endStr = this.endDate();
136
175
  if (!endStr)
137
176
  return '';
138
- return this.formatDate(new Date(endStr));
177
+ return formatDate(new Date(endStr), this._dateAdapter, this._dateFormats);
139
178
  }, ...(ngDevMode ? [{ debugName: "displayEnd" }] : []));
140
- this.relativeDurations = [
141
- ['最近5分钟', '-5minutes'],
142
- ['最近15分钟', '-15minutes'],
143
- ['最近30分钟', '-30minutes'],
144
- ['最近1小时', '-1hours'],
145
- ['最近3小时', '-3hours'],
146
- ['最近6小时', '-6hours'],
147
- ['最近12小时', '-12hours'],
148
- ['最近24小时', '-24hours'],
149
- ['最近2天', '-2days'],
150
- ['最近7天', '-7days'],
151
- ['最近30天', '-30days'],
152
- ['最近90天', '-90days'],
153
- ['最近6个月', '-6months'],
154
- ['最近1年', '-1years'],
155
- ['最近2年', '-2years'],
156
- ['最近5年', '-5years'],
157
- ['上周', '-1weeks'],
158
- ['上个月', '-1months'],
159
- ['去年', '-1years']
160
- ];
161
- this.fixedDays = [
162
- ['昨天', '-1days/day'],
163
- ['前天', '-2days/day'],
164
- ['上周同一天', '-7days/day'],
165
- ['上周', '-1weeks/week'],
166
- ['上个月', '-1months/month'],
167
- ['去年', '-1years/year']
168
- ];
169
- this.currentPeriods = [
170
- ['今天', 'today', 'today'],
171
- ['今天至今', 'today', 'now'],
172
- ['本周至今', 'thisweek', 'now'],
173
- ['本月至今', 'thismonth', 'now'],
174
- ['今年至今', 'thisyear', 'now']
175
- ];
176
- this.timeRanges = signal([
177
- ...this.relativeDurations.map(([label, offset]) => ({
178
- label,
179
- start: `offset:${offset}`,
180
- end: 'offset:now'
181
- })),
182
- ...this.fixedDays.map(([label, point]) => ({
183
- label,
184
- start: `offset:${point}`,
185
- end: `offset:${point}`
186
- })),
187
- ...this.currentPeriods.map(([label, start, end]) => ({
188
- label,
189
- start: `offset:${start}`,
190
- end: `offset:${end}`
191
- }))
192
- ], ...(ngDevMode ? [{ debugName: "timeRanges" }] : []));
179
+ this.timeRanges = [...DEFAULT_TIME_RANGES];
193
180
  this.selectedTimeRange = model(undefined, ...(ngDevMode ? [{ debugName: "selectedTimeRange" }] : []));
194
181
  this.selectedDateRange = null;
195
182
  this.now = new Date();
196
183
  this.selectingStart = true;
184
+ this.hours = Array.from({ length: 24 }, (_, i) => i);
185
+ this.minutes = Array.from({ length: 60 }, (_, i) => i);
197
186
  this.#breakpoints
198
187
  .observe([Breakpoints.Handset, Breakpoints.Tablet])
199
188
  .pipe(takeUntilDestroyed())
@@ -212,8 +201,8 @@ class DateSelector {
212
201
  this.selectedDateRange = new DateRange(start, end);
213
202
  this.#selectionModel.updateSelection(this.selectedDateRange, this);
214
203
  // 初始化时间值
215
- this.startDate.set(picker.start);
216
- this.endDate.set(picker.end);
204
+ this.startDate.set(!isNaN(start.getTime()) ? start.toISOString() : String(picker.start));
205
+ this.endDate.set(!isNaN(end.getTime()) ? end.toISOString() : String(picker.end));
217
206
  this.startHour.set(start.getHours());
218
207
  this.startMinute.set(start.getMinutes());
219
208
  this.endHour.set(end.getHours());
@@ -221,17 +210,11 @@ class DateSelector {
221
210
  }
222
211
  }
223
212
  if (this.future()) {
224
- const futureOffsets = [
225
- { label: '未来1天', start: 'offset:now', end: 'offset:+1days' },
226
- { label: '未来1周', start: 'offset:now', end: 'offset:+1weeks' },
227
- { label: '未来1月', start: 'offset:now', end: 'offset:+1months' },
228
- { label: '未来3月', start: 'offset:now', end: 'offset:+3months' }
229
- ];
230
- this.timeRanges.update(ranges => [...ranges, ...futureOffsets]);
213
+ this.timeRanges = [...this.timeRanges, ...FUTURE_TIME_RANGES];
231
214
  }
232
215
  }
233
- else {
234
- this.selectTimeRange(this.timeRanges()[5]);
216
+ if (!this.data?.dateTimePicker) {
217
+ this.selectTimeRange(this.timeRanges[5]);
235
218
  }
236
219
  }
237
220
  selectTimeRange(timeRange) {
@@ -252,46 +235,89 @@ class DateSelector {
252
235
  const parseTime = (time) => {
253
236
  if (!time)
254
237
  return new Date(now);
255
- if (time.startsWith('offset:')) {
256
- const offset = time.replace('offset:', '').trim();
257
- if (offset === 'now')
258
- return new Date(now);
259
- const regex = /([+-]?)(\d+)(months?|days?|years?|weeks?|hours?|minutes?)/i;
260
- const match = regex.exec(offset);
261
- if (!match)
262
- return new Date(now);
263
- const sign = match[1] === '-' ? -1 : 1;
264
- const value = parseInt(match[2], 10) * sign;
265
- const unit = match[3].toLowerCase();
238
+ // 处理 startof: 前缀 (本周/本月/今年)
239
+ if (time.startsWith('startof:')) {
240
+ const unit = time.replace('startof:', '').trim().toLowerCase();
266
241
  const result = new Date(now);
242
+ result.setHours(0, 0, 0, 0);
267
243
  switch (unit) {
268
- case 'minutes':
269
- case 'minute':
270
- result.setMinutes(result.getMinutes() + value);
271
- break;
272
- case 'hours':
273
- case 'hour':
274
- result.setHours(result.getHours() + value);
275
- break;
276
- case 'days':
277
- case 'day':
278
- result.setDate(result.getDate() + value);
279
- break;
280
- case 'weeks':
281
244
  case 'week':
282
- result.setDate(result.getDate() + value * 7);
245
+ // 假设周一为一周的开始
246
+ const day = result.getDay() || 7; // 0是周日,改为7
247
+ if (day !== 1) {
248
+ result.setHours(-24 * (day - 1));
249
+ }
283
250
  break;
284
- case 'months':
285
251
  case 'month':
286
- result.setMonth(result.getMonth() + value);
252
+ result.setDate(1);
287
253
  break;
288
- case 'years':
289
254
  case 'year':
290
- result.setFullYear(result.getFullYear() + value);
255
+ result.setMonth(0, 1);
291
256
  break;
292
257
  }
293
258
  return result;
294
259
  }
260
+ // 处理 offset: 前缀
261
+ if (time.startsWith('offset:')) {
262
+ const offsetStr = time.replace('offset:', '').trim();
263
+ if (offsetStr === 'now')
264
+ return new Date(now);
265
+ // 检查是否有 /start 或 /end 后缀
266
+ let suffix = '';
267
+ let cleanOffset = offsetStr;
268
+ if (offsetStr.endsWith('/start')) {
269
+ suffix = 'start';
270
+ cleanOffset = offsetStr.replace('/start', '');
271
+ }
272
+ else if (offsetStr.endsWith('/end')) {
273
+ suffix = 'end';
274
+ cleanOffset = offsetStr.replace('/end', '');
275
+ }
276
+ const regex = /([+-]?)(\d+)(months?|days?|years?|weeks?|hours?|minutes?)/i;
277
+ const match = regex.exec(cleanOffset);
278
+ // 如果没有匹配到数字偏移量,但有后缀(例如 offset:0days/start),尝试解析
279
+ // 注意:上面的正则也能匹配 0days
280
+ const result = new Date(now);
281
+ if (match) {
282
+ const sign = match[1] === '-' ? -1 : 1;
283
+ const value = parseInt(match[2], 10) * sign;
284
+ const unit = match[3].toLowerCase();
285
+ switch (unit) {
286
+ case 'minutes':
287
+ case 'minute':
288
+ result.setMinutes(result.getMinutes() + value);
289
+ break;
290
+ case 'hours':
291
+ case 'hour':
292
+ result.setHours(result.getHours() + value);
293
+ break;
294
+ case 'days':
295
+ case 'day':
296
+ result.setDate(result.getDate() + value);
297
+ break;
298
+ case 'weeks':
299
+ case 'week':
300
+ result.setDate(result.getDate() + value * 7);
301
+ break;
302
+ case 'months':
303
+ case 'month':
304
+ result.setMonth(result.getMonth() + value);
305
+ break;
306
+ case 'years':
307
+ case 'year':
308
+ result.setFullYear(result.getFullYear() + value);
309
+ break;
310
+ }
311
+ }
312
+ // 应用后缀修正
313
+ if (suffix === 'start') {
314
+ result.setHours(0, 0, 0, 0);
315
+ }
316
+ else if (suffix === 'end') {
317
+ result.setHours(23, 59, 59, 999);
318
+ }
319
+ return result;
320
+ }
295
321
  return new Date(time);
296
322
  };
297
323
  const startDate = timeRange.start ? parseTime(timeRange.start) : null;
@@ -350,33 +376,79 @@ class DateSelector {
350
376
  this.selectedDateRange = range;
351
377
  this.startDate.set(start?.toISOString() ?? '');
352
378
  this.endDate.set(end?.toISOString() ?? '');
379
+ if (start) {
380
+ this.startHour.set(start.getHours());
381
+ this.startMinute.set(start.getMinutes());
382
+ }
383
+ else {
384
+ this.startHour.set(null);
385
+ this.startMinute.set(null);
386
+ }
387
+ if (end) {
388
+ this.endHour.set(end.getHours());
389
+ this.endMinute.set(end.getMinutes());
390
+ }
391
+ else {
392
+ this.endHour.set(null);
393
+ this.endMinute.set(null);
394
+ }
353
395
  }
354
396
  rangeChanged(selectedDate) {
355
397
  if (!selectedDate)
356
398
  return;
357
- // 创建一个新日期对象,保留日期部分,但使用当前时间作为时间部分
358
- const now = new Date();
359
- const dateWithCurrentTime = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate(), now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds());
360
399
  if (this.selectingStart) {
361
- this.startDate.set(dateWithCurrentTime.toISOString());
400
+ // 正在选择开始日期
401
+ let h = 0, m = 0, s = 0, ms = 0;
402
+ // 尝试保留之前的开始时间
403
+ if (this.selectedDateRange?.start) {
404
+ h = this.selectedDateRange.start.getHours();
405
+ m = this.selectedDateRange.start.getMinutes();
406
+ s = this.selectedDateRange.start.getSeconds();
407
+ }
408
+ const newStart = new Date(selectedDate);
409
+ newStart.setHours(h, m, s, ms);
410
+ this.startDate.set(newStart.toISOString());
362
411
  this.endDate.set('');
363
- this.startHour.set(dateWithCurrentTime.getHours());
364
- this.startMinute.set(dateWithCurrentTime.getMinutes());
412
+ this.startHour.set(newStart.getHours());
413
+ this.startMinute.set(newStart.getMinutes());
365
414
  this.endHour.set(null);
366
415
  this.endMinute.set(null);
367
416
  this.selectedTimeRange.set(undefined);
368
- this.selectedDateRange = new DateRange(dateWithCurrentTime, null);
417
+ this.selectedDateRange = new DateRange(newStart, null);
369
418
  this.#selectionModel.updateSelection(this.selectedDateRange, this);
370
419
  this.selectingStart = false;
371
420
  }
372
421
  else {
422
+ // 正在选择结束日期
373
423
  const start = this.#selectionModel.selection.start;
374
424
  if (!start)
375
425
  return;
376
- const range = start.toDateString() === selectedDate.toDateString()
377
- ? new DateRange(start, start)
378
- : new DateRange(start < dateWithCurrentTime ? start : dateWithCurrentTime, start < dateWithCurrentTime ? dateWithCurrentTime : start);
379
- this.updateSelection(range.start, range.end);
426
+ const startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate());
427
+ const selectedDay = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
428
+ let newStart;
429
+ let newEnd;
430
+ if (selectedDay.getTime() < startDay.getTime()) {
431
+ // 用户选了一个比 Start 更早的日期 -> 交换角色
432
+ // 新 Start (selectedDate) 设为 00:00
433
+ newStart = new Date(selectedDate);
434
+ newStart.setHours(0, 0, 0, 0);
435
+ // 新 End (旧 start) 设为 23:59
436
+ newEnd = new Date(start);
437
+ newEnd.setHours(23, 59, 59, 999);
438
+ }
439
+ else {
440
+ // 正常顺序 (selectedDate >= start)
441
+ // Start 保持原样
442
+ newStart = new Date(start);
443
+ // End (selectedDate) 设为 23:59
444
+ newEnd = new Date(selectedDate);
445
+ newEnd.setHours(23, 59, 59, 999);
446
+ // 如果是同一天,确保 Start <= End
447
+ if (newStart.getTime() > newEnd.getTime()) {
448
+ newStart.setHours(0, 0, 0, 0);
449
+ }
450
+ }
451
+ this.updateSelection(newStart, newEnd);
380
452
  this.selectingStart = true;
381
453
  }
382
454
  }
@@ -392,13 +464,17 @@ class DateSelector {
392
464
  this.endMinute.set(end.getMinutes());
393
465
  }
394
466
  submit() {
395
- const start = new Date(this.selectedDateRange?.start ?? '');
396
- const end = new Date(this.selectedDateRange?.end ?? '');
397
- const startISO = start.toISOString();
398
- const endISO = end.toISOString();
467
+ if (!this.selectedDateRange?.start || !this.selectedDateRange?.end) {
468
+ return;
469
+ }
470
+ const start = new Date(this.selectedDateRange.start);
471
+ const end = new Date(this.selectedDateRange.end);
472
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
473
+ return;
474
+ }
399
475
  const result = {
400
- start: startISO,
401
- end: endISO
476
+ start: start.toISOString(),
477
+ end: end.toISOString()
402
478
  };
403
479
  this.data = { ...this.data, dateTimePicker: result };
404
480
  this.#dialogRef.close(this.data);
@@ -406,12 +482,6 @@ class DateSelector {
406
482
  dismiss() {
407
483
  this.#dialogRef.close(undefined);
408
484
  }
409
- getHours() {
410
- return Array.from({ length: 24 }, (_, i) => i);
411
- }
412
- getMinutes() {
413
- return Array.from({ length: 60 }, (_, i) => i);
414
- }
415
485
  updateStartTime() {
416
486
  if (this.selectedDateRange?.start && this.startHour() !== null && this.startMinute() !== null) {
417
487
  const startDate = new Date(this.selectedDateRange.start);
@@ -438,7 +508,7 @@ class DateSelector {
438
508
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DateSelector, isStandalone: true, selector: "date-time-picker-selector", inputs: { startDate: { classPropertyName: "startDate", publicName: "startDate", isSignal: true, isRequired: false, transformFunction: null }, endDate: { classPropertyName: "endDate", publicName: "endDate", isSignal: true, isRequired: false, transformFunction: null }, startHour: { classPropertyName: "startHour", publicName: "startHour", isSignal: true, isRequired: false, transformFunction: null }, startMinute: { classPropertyName: "startMinute", publicName: "startMinute", isSignal: true, isRequired: false, transformFunction: null }, endHour: { classPropertyName: "endHour", publicName: "endHour", isSignal: true, isRequired: false, transformFunction: null }, endMinute: { classPropertyName: "endMinute", publicName: "endMinute", isSignal: true, isRequired: false, transformFunction: null }, future: { classPropertyName: "future", publicName: "future", isSignal: true, isRequired: false, transformFunction: null }, selectedTimeRange: { classPropertyName: "selectedTimeRange", publicName: "selectedTimeRange", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { startDate: "startDateChange", endDate: "endDateChange", startHour: "startHourChange", startMinute: "startMinuteChange", endHour: "endHourChange", endMinute: "endMinuteChange", future: "futureChange", selectedTimeRange: "selectedTimeRangeChange" }, providers: [
439
509
  DefaultMatCalendarRangeStrategy,
440
510
  MatRangeDateSelectionModel
441
- ], viewQueries: [{ propertyName: "sidenav", first: true, predicate: ["sidenav"], descendants: true }], ngImport: i0, template: "<date-time-picker-container\r\n headerTitle=\"\u65E5\u671F\u65F6\u95F4\u9009\u62E9\u5668\"\r\n submitTitle=\"\u5E94\u7528\"\r\n [disabledSubmit]=\"!selectedDateRange\"\r\n [footerExtraContent]=\"footerExtraContent\"\r\n (submit)=\"submit()\"\r\n (dismiss)=\"dismiss()\"\r\n>\r\n <mat-sidenav-container class=\"date-selector-sidenav-container\">\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F -->\r\n <mat-sidenav\r\n #sidenav\r\n [mode]=\"isMobile() ? 'over' : 'side'\"\r\n [opened]=\"!isMobile()\"\r\n class=\"date-selector-sidebar\"\r\n dir=\"rtl\"\r\n >\r\n <div class=\"date-selector-sidebar-inner\" dir=\"ltr\">\r\n <div class=\"date-selector-sidebar-header\">\r\n <span class=\"date-selector-sidebar-title\">\u5FEB\u6377\u9009\u62E9</span>\r\n @if (isMobile()) {\r\n <button mat-icon-button (click)=\"sidenav.close()\">\r\n <i-tabler name=\"layout-sidebar-left-collapse\" />\r\n </button>\r\n }\r\n </div>\r\n <ul class=\"date-selector-sidebar-list\">\r\n @for (timeRangeItem of timeRanges(); track timeRangeItem) {\r\n <li class=\"date-selector-sidebar-item\">\r\n <button\r\n type=\"button\"\r\n (click)=\"selectTimeRange(timeRangeItem); isMobile() && sidenav.close()\"\r\n [class.selected]=\"selectedTimeRange() && selectedTimeRange()?.start === timeRangeItem.start && selectedTimeRange()?.end === timeRangeItem.end\"\r\n class=\"date-selector-sidebar-btn\"\r\n >\r\n <span class=\"date-selector-sidebar-text\">{{ timeRangeItem.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n </mat-sidenav>\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F\u7ED3\u675F -->\r\n\r\n <mat-sidenav-content>\r\n @if (isMobile()) {\r\n <div class=\"date-selector-mobile-toolbar\">\r\n <button mat-button (click)=\"sidenav.open()\">\r\n <span>\u5FEB\u6377\u9009\u62E9</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- \u4E3B\u8981\u5185\u5BB9\u533A\u57DF -->\r\n <div class=\"date-selector-main\">\r\n <div class=\"date-selector-content\">\r\n <!-- \u65E5\u5386\u5BB9\u5668 -->\r\n <section class=\"date-selector-calendar-section\">\r\n <div class=\"date-selector-calendar-wrapper\">\r\n <mat-calendar [maxDate]=\"!future() ? now : undefined\" [(selected)]=\"selectedDateRange\" (selectedChange)=\"rangeChanged($event)\" class=\"date-selector-calendar\" />\r\n </div>\r\n </section>\r\n <!-- \u65E5\u5386\u5BB9\u5668\u7ED3\u675F -->\r\n\r\n <!-- \u65F6\u95F4\u8BBE\u7F6E\u5BB9\u5668 -->\r\n <section class=\"date-selector-time-section\">\r\n <!-- \u5F00\u59CB\u548C\u7ED3\u675F\u8F93\u5165\u65E5\u671F -->\r\n <div class=\"date-selector-inputs\">\r\n <!-- \u4ECE\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u5F00\u59CB\u65E5\u671F\"\r\n [dateValue]=\"startDate()\"\r\n [hourValue]=\"startHour()\"\r\n (hourChange)=\"startHour.set($event)\"\r\n [minuteValue]=\"startMinute()\"\r\n (minuteChange)=\"startMinute.set($event)\"\r\n [hours]=\"getHours()\"\r\n [minutes]=\"getMinutes()\"\r\n (dateChange)=\"changeDatePart('start', $event)\"\r\n (timeChange)=\"updateStartTime()\"\r\n />\r\n\r\n <!-- \u7ED3\u675F\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u7ED3\u675F\u65E5\u671F\"\r\n [dateValue]=\"endDate()\"\r\n [hourValue]=\"endHour()\"\r\n (hourChange)=\"endHour.set($event)\"\r\n [minuteValue]=\"endMinute()\"\r\n (minuteChange)=\"endMinute.set($event)\"\r\n [hours]=\"getHours()\"\r\n [minutes]=\"getMinutes()\"\r\n (dateChange)=\"changeDatePart('end', $event)\"\r\n (timeChange)=\"updateEndTime()\"\r\n />\r\n </div>\r\n\r\n <div class=\"date-selector-hint-wrapper\">\r\n <div class=\"date-selector-hint\">\r\n <i-tabler name=\"info-circle\" strokeWidth=\"2px\" class=\"date-selector-hint-icon\"></i-tabler>\r\n <span class=\"date-selector-hint-text\">\u5982\u679C\u8981\u9009\u62E9\u4E00\u5929\uFF0C\u8BF7\u53CC\u51FB\u8BE5\u5929\u3002</span>\r\n </div>\r\n </div>\r\n\r\n </section>\r\n </div>\r\n </div>\r\n </mat-sidenav-content>\r\n </mat-sidenav-container>\r\n</date-time-picker-container>\r\n\r\n<ng-template #footerExtraContent>\r\n <div class=\"date-selector-footer-range\">\r\n <span class=\"date-selector-footer-label\">\u8303\u56F4\uFF1A</span>\r\n\r\n @if (startDate()) {\r\n <div class=\"date-selector-footer-value\">\r\n @if (startDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayStart() }}</span>\r\n }\r\n\r\n @if (startDate() && endDate()) {\r\n <span class=\"date-selector-footer-separator\">-</span>\r\n }\r\n\r\n @if (endDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayEnd() }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.date-selector-sidebar{width:12rem;height:100%;background-color:var(--mat-sys-surface-container, #fafafa);border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;flex-direction:column}.date-selector-sidebar-inner{width:100%;height:100%;display:flex;flex-direction:column;padding:0}.date-selector-sidebar-header{padding:12px 16px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));background-color:var(--mat-sys-surface, #fff);position:sticky;top:0;z-index:1;display:flex;justify-content:space-between;align-items:center}.date-selector-sidebar-title{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-sidebar-list{list-style:none;margin:0;padding:4px 0;flex:1;overflow-y:auto;overflow-x:hidden}.date-selector-sidebar-item{margin:0;padding:0}.date-selector-sidebar-btn{width:100%;padding:8px 12px;background:transparent;border:none;cursor:pointer;font-size:.8125rem;font-weight:500;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));text-align:left;transition:all .2s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.date-selector-sidebar-btn:hover{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));color:var(--mat-sys-primary, #1976d2);padding-left:16px}.date-selector-sidebar-btn.selected{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .16));color:var(--mat-sys-primary, #1976d2);font-weight:600;padding-left:16px}.date-selector-sidebar-btn:focus-visible{outline:2px solid var(--mat-sys-primary, #1976d2);outline-offset:-2px}.date-selector-sidebar-text{display:block}.date-selector-main{width:100%;height:100%;display:flex;background-color:var(--mat-sys-surface, #fff)}@media(max-width:767px){.date-selector-main{height:auto;flex:1}}.date-selector-content{width:100%;height:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-content{flex-direction:row}}.date-selector-calendar-section{width:100%;display:flex;align-items:center;justify-content:center;padding:16px;border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));box-sizing:border-box}@media(min-width:768px){.date-selector-calendar-section{width:50%}}@media(max-width:767px){.date-selector-calendar-section{border-right:none;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));padding-top:0;padding-bottom:0}}.date-selector-calendar-wrapper{width:100%;display:flex;flex-direction:column;gap:16px}.date-selector-calendar{width:100%}.date-selector-hint{display:flex;align-items:flex-start;gap:8px;padding:12px 16px;background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));border:1px solid var(--mat-outline-variant, rgba(25, 118, 210, .16));border-radius:4px;align-items:center}.date-selector-hint-icon{flex-shrink:0;color:var(--mat-sys-primary, #1976d2);margin-top:2px}.date-selector-hint-text{font-size:.75rem;line-height:1.25;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-hint-wrapper{padding:12px 16px}.date-selector-time-section{width:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-time-section{width:50%}}.date-selector-inputs{display:flex;flex-direction:column;padding:0}.date-selector-footer-range{display:flex;align-items:center;gap:8px;font-size:.75rem;margin-right:auto;padding:0 8px}.date-selector-footer-label{font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-label{display:block}}.date-selector-footer-value{display:flex;flex-direction:column;gap:0;font-weight:600}@media(min-width:768px){.date-selector-footer-value{flex-direction:row;gap:8px;align-items:center}}.date-selector-footer-date{color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));white-space:nowrap}.date-selector-footer-separator{color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-separator{display:block}}.date-selector-sidenav-container{width:100%;height:100%;background-color:transparent}.date-selector-mobile-toolbar{padding:8px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;align-items:center}\n", ":host{display:block;height:100%}\n"], dependencies: [{ kind: "component", type: MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "component", type: TablerIconComponent, selector: "i-tabler, tabler-icon", inputs: ["name"] }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "directive", type: i1$1.Dir, selector: "[dir]", inputs: ["dir"], outputs: ["dirChange"], exportAs: ["dir"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: Container, selector: "date-time-picker-container", inputs: ["hasHeader", "hasFooter", "headerTitle", "headerExtraContent", "footerExtraContent", "hasDismiss", "hasSubmit", "submitTitle", "submitBg", "submitColor", "submitTitleColor", "disabledSubmit", "hasSecondaryButton", "secondaryButtonTitle", "secondaryButtonBg", "secondaryButtonColor", "secondaryButtonTitleColor", "disabledSecondaryButton"], outputs: ["hasHeaderChange", "hasFooterChange", "headerTitleChange", "headerExtraContentChange", "footerExtraContentChange", "hasDismissChange", "hasSubmitChange", "submitTitleChange", "submitBgChange", "submitColorChange", "submitTitleColorChange", "disabledSubmitChange", "hasSecondaryButtonChange", "secondaryButtonTitleChange", "secondaryButtonBgChange", "secondaryButtonColorChange", "secondaryButtonTitleColorChange", "disabledSecondaryButtonChange", "dismiss", "submit", "secondaryButton"] }, { kind: "component", type: DateTimeInputComponent, selector: "date-time-input", inputs: ["label", "dateValue", "hourValue", "minuteValue", "hours", "minutes"], outputs: ["dateChange", "hourChange", "minuteChange", "timeChange"] }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i2$1.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i2$1.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i2$1.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
511
+ ], viewQueries: [{ propertyName: "sidenav", first: true, predicate: ["sidenav"], descendants: true }], ngImport: i0, template: "<date-time-picker-container\r\n headerTitle=\"\u65E5\u671F\u65F6\u95F4\u9009\u62E9\u5668\"\r\n submitTitle=\"\u5E94\u7528\"\r\n [disabledSubmit]=\"!selectedDateRange\"\r\n [footerExtraContent]=\"footerExtraContent\"\r\n (submit)=\"submit()\"\r\n (dismiss)=\"dismiss()\"\r\n>\r\n <mat-sidenav-container class=\"date-selector-sidenav-container\">\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F -->\r\n <mat-sidenav #sidenav [mode]=\"isMobile() ? 'over' : 'side'\" [opened]=\"!isMobile()\" class=\"date-selector-sidebar\" dir=\"rtl\">\r\n <div class=\"date-selector-sidebar-inner\" dir=\"ltr\">\r\n <div class=\"date-selector-sidebar-header\">\r\n <span class=\"date-selector-sidebar-title\">\u5FEB\u6377\u9009\u62E9</span>\r\n @if (isMobile()) {\r\n <button mat-icon-button (click)=\"sidenav.close()\">\r\n <i-tabler name=\"layout-sidebar-left-collapse\" />\r\n </button>\r\n }\r\n </div>\r\n <ul class=\"date-selector-sidebar-list\">\r\n @for (timeRangeItem of timeRanges; track timeRangeItem) {\r\n <li class=\"date-selector-sidebar-item\">\r\n <button\r\n type=\"button\"\r\n (click)=\"selectTimeRange(timeRangeItem); isMobile() && sidenav.close()\"\r\n [class.selected]=\"selectedTimeRange() && selectedTimeRange()?.start === timeRangeItem.start && selectedTimeRange()?.end === timeRangeItem.end\"\r\n class=\"date-selector-sidebar-btn\"\r\n >\r\n <span class=\"date-selector-sidebar-text\">{{ timeRangeItem.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n </mat-sidenav>\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F\u7ED3\u675F -->\r\n\r\n <mat-sidenav-content>\r\n @if (isMobile()) {\r\n <div class=\"date-selector-mobile-toolbar\">\r\n <button mat-button (click)=\"sidenav.open()\">\r\n <span>\u5FEB\u6377\u9009\u62E9</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- \u4E3B\u8981\u5185\u5BB9\u533A\u57DF -->\r\n <div class=\"date-selector-main\">\r\n <div class=\"date-selector-content\">\r\n <!-- \u65E5\u5386\u5BB9\u5668 -->\r\n <section class=\"date-selector-calendar-section\">\r\n <div class=\"date-selector-calendar-wrapper\">\r\n <mat-calendar [maxDate]=\"!future() ? now : undefined\" [(selected)]=\"selectedDateRange\" (selectedChange)=\"rangeChanged($event)\" class=\"date-selector-calendar\" />\r\n </div>\r\n </section>\r\n <!-- \u65E5\u5386\u5BB9\u5668\u7ED3\u675F -->\r\n\r\n <!-- \u65F6\u95F4\u8BBE\u7F6E\u5BB9\u5668 -->\r\n <section class=\"date-selector-time-section\">\r\n <!-- \u5F00\u59CB\u548C\u7ED3\u675F\u8F93\u5165\u65E5\u671F -->\r\n <div class=\"date-selector-inputs\">\r\n <!-- \u4ECE\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u5F00\u59CB\u65E5\u671F\"\r\n [dateValue]=\"startDate()\"\r\n [hourValue]=\"startHour()\"\r\n (hourChange)=\"startHour.set($event)\"\r\n [minuteValue]=\"startMinute()\"\r\n (minuteChange)=\"startMinute.set($event)\"\r\n [hours]=\"hours\"\r\n [minutes]=\"minutes\"\r\n (dateChange)=\"changeDatePart('start', $event)\"\r\n (timeChange)=\"updateStartTime()\"\r\n />\r\n\r\n <!-- \u7ED3\u675F\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u7ED3\u675F\u65E5\u671F\"\r\n [dateValue]=\"endDate()\"\r\n [hourValue]=\"endHour()\"\r\n (hourChange)=\"endHour.set($event)\"\r\n [minuteValue]=\"endMinute()\"\r\n (minuteChange)=\"endMinute.set($event)\"\r\n [hours]=\"hours\"\r\n [minutes]=\"minutes\"\r\n (dateChange)=\"changeDatePart('end', $event)\"\r\n (timeChange)=\"updateEndTime()\"\r\n />\r\n </div>\r\n\r\n <div class=\"date-selector-hint-wrapper\">\r\n <div class=\"date-selector-hint\">\r\n <i-tabler name=\"info-circle\" strokeWidth=\"2px\" class=\"date-selector-hint-icon\"></i-tabler>\r\n <span class=\"date-selector-hint-text\">\u5982\u679C\u8981\u9009\u62E9\u4E00\u5929\uFF0C\u8BF7\u53CC\u51FB\u8BE5\u5929\u3002</span>\r\n </div>\r\n </div>\r\n </section>\r\n </div>\r\n </div>\r\n </mat-sidenav-content>\r\n </mat-sidenav-container>\r\n</date-time-picker-container>\r\n\r\n<ng-template #footerExtraContent>\r\n <div class=\"date-selector-footer-range\">\r\n <span class=\"date-selector-footer-label\">\u8303\u56F4\uFF1A</span>\r\n\r\n @if (startDate()) {\r\n <div class=\"date-selector-footer-value\">\r\n @if (startDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayStart() }}</span>\r\n }\r\n\r\n @if (startDate() && endDate()) {\r\n <span class=\"date-selector-footer-separator\">-</span>\r\n }\r\n\r\n @if (endDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayEnd() }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.date-selector-sidebar{width:12rem;height:100%;background-color:var(--mat-sys-surface-container, #fafafa);border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;flex-direction:column}.date-selector-sidebar-inner{width:100%;height:100%;display:flex;flex-direction:column;padding:0}.date-selector-sidebar-header{padding:12px 16px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));background-color:var(--mat-sys-surface, #fff);position:sticky;top:0;z-index:1;display:flex;justify-content:space-between;align-items:center}.date-selector-sidebar-title{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-sidebar-list{list-style:none;margin:0;padding:4px 0;flex:1;overflow-y:auto;overflow-x:hidden}.date-selector-sidebar-item{margin:0;padding:0}.date-selector-sidebar-btn{width:100%;padding:8px 12px;background:transparent;border:none;cursor:pointer;font-size:.8125rem;font-weight:500;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));text-align:left;transition:all .2s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.date-selector-sidebar-btn:hover{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));color:var(--mat-sys-primary, #1976d2);padding-left:16px}.date-selector-sidebar-btn.selected{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .16));color:var(--mat-sys-primary, #1976d2);font-weight:600;padding-left:16px}.date-selector-sidebar-btn:focus-visible{outline:2px solid var(--mat-sys-primary, #1976d2);outline-offset:-2px}.date-selector-sidebar-text{display:block}.date-selector-main{width:100%;height:100%;display:flex;background-color:var(--mat-sys-surface, #fff)}@media(max-width:767px){.date-selector-main{height:auto;flex:1}}.date-selector-content{width:100%;height:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-content{flex-direction:row}}.date-selector-calendar-section{width:100%;display:flex;align-items:center;justify-content:center;padding:16px;border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));box-sizing:border-box}@media(min-width:768px){.date-selector-calendar-section{width:50%}}@media(max-width:767px){.date-selector-calendar-section{border-right:none;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));padding-top:0;padding-bottom:0}}.date-selector-calendar-wrapper{width:100%;display:flex;flex-direction:column;gap:16px}.date-selector-calendar{width:100%}.date-selector-hint{display:flex;align-items:flex-start;gap:8px;padding:12px 16px;background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));border:1px solid var(--mat-outline-variant, rgba(25, 118, 210, .16));border-radius:4px;align-items:center}.date-selector-hint-icon{flex-shrink:0;color:var(--mat-sys-primary, #1976d2);margin-top:2px}.date-selector-hint-text{font-size:.75rem;line-height:1.25;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-hint-wrapper{padding:12px 16px}.date-selector-time-section{width:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-time-section{width:50%}}.date-selector-inputs{display:flex;flex-direction:column;padding:0}.date-selector-footer-range{display:flex;align-items:center;gap:8px;font-size:.75rem;margin-right:auto;padding:0 8px}.date-selector-footer-label{font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-label{display:block}}.date-selector-footer-value{display:flex;flex-direction:column;gap:0;font-weight:600}@media(min-width:768px){.date-selector-footer-value{flex-direction:row;gap:8px;align-items:center}}.date-selector-footer-date{color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));white-space:nowrap}.date-selector-footer-separator{color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-separator{display:block}}.date-selector-sidenav-container{width:100%;height:100%;background-color:transparent}.date-selector-mobile-toolbar{padding:8px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;align-items:center}\n", ":host{display:block;height:100%}\n"], dependencies: [{ kind: "component", type: MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "component", type: TablerIconComponent, selector: "i-tabler, tabler-icon", inputs: ["name"] }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "directive", type: i1$1.Dir, selector: "[dir]", inputs: ["dir"], outputs: ["dirChange"], exportAs: ["dir"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: Container, selector: "date-time-picker-container", inputs: ["hasHeader", "hasFooter", "headerTitle", "headerExtraContent", "footerExtraContent", "hasDismiss", "hasSubmit", "submitTitle", "submitBg", "submitColor", "submitTitleColor", "disabledSubmit", "hasSecondaryButton", "secondaryButtonTitle", "secondaryButtonBg", "secondaryButtonColor", "secondaryButtonTitleColor", "disabledSecondaryButton"], outputs: ["hasHeaderChange", "hasFooterChange", "headerTitleChange", "headerExtraContentChange", "footerExtraContentChange", "hasDismissChange", "hasSubmitChange", "submitTitleChange", "submitBgChange", "submitColorChange", "submitTitleColorChange", "disabledSubmitChange", "hasSecondaryButtonChange", "secondaryButtonTitleChange", "secondaryButtonBgChange", "secondaryButtonColorChange", "secondaryButtonTitleColorChange", "disabledSecondaryButtonChange", "dismiss", "submit", "secondaryButton"] }, { kind: "component", type: DateTimeInputComponent, selector: "date-time-input", inputs: ["label", "dateValue", "hourValue", "minuteValue", "hours", "minutes"], outputs: ["dateChange", "hourChange", "minuteChange", "timeChange"] }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i2$1.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i2$1.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i2$1.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
442
512
  }
443
513
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DateSelector, decorators: [{
444
514
  type: Component,
@@ -455,7 +525,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
455
525
  DateTimeInputComponent,
456
526
  MatSidenavModule,
457
527
  MatButtonModule
458
- ], template: "<date-time-picker-container\r\n headerTitle=\"\u65E5\u671F\u65F6\u95F4\u9009\u62E9\u5668\"\r\n submitTitle=\"\u5E94\u7528\"\r\n [disabledSubmit]=\"!selectedDateRange\"\r\n [footerExtraContent]=\"footerExtraContent\"\r\n (submit)=\"submit()\"\r\n (dismiss)=\"dismiss()\"\r\n>\r\n <mat-sidenav-container class=\"date-selector-sidenav-container\">\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F -->\r\n <mat-sidenav\r\n #sidenav\r\n [mode]=\"isMobile() ? 'over' : 'side'\"\r\n [opened]=\"!isMobile()\"\r\n class=\"date-selector-sidebar\"\r\n dir=\"rtl\"\r\n >\r\n <div class=\"date-selector-sidebar-inner\" dir=\"ltr\">\r\n <div class=\"date-selector-sidebar-header\">\r\n <span class=\"date-selector-sidebar-title\">\u5FEB\u6377\u9009\u62E9</span>\r\n @if (isMobile()) {\r\n <button mat-icon-button (click)=\"sidenav.close()\">\r\n <i-tabler name=\"layout-sidebar-left-collapse\" />\r\n </button>\r\n }\r\n </div>\r\n <ul class=\"date-selector-sidebar-list\">\r\n @for (timeRangeItem of timeRanges(); track timeRangeItem) {\r\n <li class=\"date-selector-sidebar-item\">\r\n <button\r\n type=\"button\"\r\n (click)=\"selectTimeRange(timeRangeItem); isMobile() && sidenav.close()\"\r\n [class.selected]=\"selectedTimeRange() && selectedTimeRange()?.start === timeRangeItem.start && selectedTimeRange()?.end === timeRangeItem.end\"\r\n class=\"date-selector-sidebar-btn\"\r\n >\r\n <span class=\"date-selector-sidebar-text\">{{ timeRangeItem.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n </mat-sidenav>\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F\u7ED3\u675F -->\r\n\r\n <mat-sidenav-content>\r\n @if (isMobile()) {\r\n <div class=\"date-selector-mobile-toolbar\">\r\n <button mat-button (click)=\"sidenav.open()\">\r\n <span>\u5FEB\u6377\u9009\u62E9</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- \u4E3B\u8981\u5185\u5BB9\u533A\u57DF -->\r\n <div class=\"date-selector-main\">\r\n <div class=\"date-selector-content\">\r\n <!-- \u65E5\u5386\u5BB9\u5668 -->\r\n <section class=\"date-selector-calendar-section\">\r\n <div class=\"date-selector-calendar-wrapper\">\r\n <mat-calendar [maxDate]=\"!future() ? now : undefined\" [(selected)]=\"selectedDateRange\" (selectedChange)=\"rangeChanged($event)\" class=\"date-selector-calendar\" />\r\n </div>\r\n </section>\r\n <!-- \u65E5\u5386\u5BB9\u5668\u7ED3\u675F -->\r\n\r\n <!-- \u65F6\u95F4\u8BBE\u7F6E\u5BB9\u5668 -->\r\n <section class=\"date-selector-time-section\">\r\n <!-- \u5F00\u59CB\u548C\u7ED3\u675F\u8F93\u5165\u65E5\u671F -->\r\n <div class=\"date-selector-inputs\">\r\n <!-- \u4ECE\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u5F00\u59CB\u65E5\u671F\"\r\n [dateValue]=\"startDate()\"\r\n [hourValue]=\"startHour()\"\r\n (hourChange)=\"startHour.set($event)\"\r\n [minuteValue]=\"startMinute()\"\r\n (minuteChange)=\"startMinute.set($event)\"\r\n [hours]=\"getHours()\"\r\n [minutes]=\"getMinutes()\"\r\n (dateChange)=\"changeDatePart('start', $event)\"\r\n (timeChange)=\"updateStartTime()\"\r\n />\r\n\r\n <!-- \u7ED3\u675F\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u7ED3\u675F\u65E5\u671F\"\r\n [dateValue]=\"endDate()\"\r\n [hourValue]=\"endHour()\"\r\n (hourChange)=\"endHour.set($event)\"\r\n [minuteValue]=\"endMinute()\"\r\n (minuteChange)=\"endMinute.set($event)\"\r\n [hours]=\"getHours()\"\r\n [minutes]=\"getMinutes()\"\r\n (dateChange)=\"changeDatePart('end', $event)\"\r\n (timeChange)=\"updateEndTime()\"\r\n />\r\n </div>\r\n\r\n <div class=\"date-selector-hint-wrapper\">\r\n <div class=\"date-selector-hint\">\r\n <i-tabler name=\"info-circle\" strokeWidth=\"2px\" class=\"date-selector-hint-icon\"></i-tabler>\r\n <span class=\"date-selector-hint-text\">\u5982\u679C\u8981\u9009\u62E9\u4E00\u5929\uFF0C\u8BF7\u53CC\u51FB\u8BE5\u5929\u3002</span>\r\n </div>\r\n </div>\r\n\r\n </section>\r\n </div>\r\n </div>\r\n </mat-sidenav-content>\r\n </mat-sidenav-container>\r\n</date-time-picker-container>\r\n\r\n<ng-template #footerExtraContent>\r\n <div class=\"date-selector-footer-range\">\r\n <span class=\"date-selector-footer-label\">\u8303\u56F4\uFF1A</span>\r\n\r\n @if (startDate()) {\r\n <div class=\"date-selector-footer-value\">\r\n @if (startDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayStart() }}</span>\r\n }\r\n\r\n @if (startDate() && endDate()) {\r\n <span class=\"date-selector-footer-separator\">-</span>\r\n }\r\n\r\n @if (endDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayEnd() }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.date-selector-sidebar{width:12rem;height:100%;background-color:var(--mat-sys-surface-container, #fafafa);border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;flex-direction:column}.date-selector-sidebar-inner{width:100%;height:100%;display:flex;flex-direction:column;padding:0}.date-selector-sidebar-header{padding:12px 16px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));background-color:var(--mat-sys-surface, #fff);position:sticky;top:0;z-index:1;display:flex;justify-content:space-between;align-items:center}.date-selector-sidebar-title{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-sidebar-list{list-style:none;margin:0;padding:4px 0;flex:1;overflow-y:auto;overflow-x:hidden}.date-selector-sidebar-item{margin:0;padding:0}.date-selector-sidebar-btn{width:100%;padding:8px 12px;background:transparent;border:none;cursor:pointer;font-size:.8125rem;font-weight:500;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));text-align:left;transition:all .2s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.date-selector-sidebar-btn:hover{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));color:var(--mat-sys-primary, #1976d2);padding-left:16px}.date-selector-sidebar-btn.selected{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .16));color:var(--mat-sys-primary, #1976d2);font-weight:600;padding-left:16px}.date-selector-sidebar-btn:focus-visible{outline:2px solid var(--mat-sys-primary, #1976d2);outline-offset:-2px}.date-selector-sidebar-text{display:block}.date-selector-main{width:100%;height:100%;display:flex;background-color:var(--mat-sys-surface, #fff)}@media(max-width:767px){.date-selector-main{height:auto;flex:1}}.date-selector-content{width:100%;height:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-content{flex-direction:row}}.date-selector-calendar-section{width:100%;display:flex;align-items:center;justify-content:center;padding:16px;border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));box-sizing:border-box}@media(min-width:768px){.date-selector-calendar-section{width:50%}}@media(max-width:767px){.date-selector-calendar-section{border-right:none;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));padding-top:0;padding-bottom:0}}.date-selector-calendar-wrapper{width:100%;display:flex;flex-direction:column;gap:16px}.date-selector-calendar{width:100%}.date-selector-hint{display:flex;align-items:flex-start;gap:8px;padding:12px 16px;background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));border:1px solid var(--mat-outline-variant, rgba(25, 118, 210, .16));border-radius:4px;align-items:center}.date-selector-hint-icon{flex-shrink:0;color:var(--mat-sys-primary, #1976d2);margin-top:2px}.date-selector-hint-text{font-size:.75rem;line-height:1.25;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-hint-wrapper{padding:12px 16px}.date-selector-time-section{width:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-time-section{width:50%}}.date-selector-inputs{display:flex;flex-direction:column;padding:0}.date-selector-footer-range{display:flex;align-items:center;gap:8px;font-size:.75rem;margin-right:auto;padding:0 8px}.date-selector-footer-label{font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-label{display:block}}.date-selector-footer-value{display:flex;flex-direction:column;gap:0;font-weight:600}@media(min-width:768px){.date-selector-footer-value{flex-direction:row;gap:8px;align-items:center}}.date-selector-footer-date{color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));white-space:nowrap}.date-selector-footer-separator{color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-separator{display:block}}.date-selector-sidenav-container{width:100%;height:100%;background-color:transparent}.date-selector-mobile-toolbar{padding:8px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;align-items:center}\n", ":host{display:block;height:100%}\n"] }]
528
+ ], template: "<date-time-picker-container\r\n headerTitle=\"\u65E5\u671F\u65F6\u95F4\u9009\u62E9\u5668\"\r\n submitTitle=\"\u5E94\u7528\"\r\n [disabledSubmit]=\"!selectedDateRange\"\r\n [footerExtraContent]=\"footerExtraContent\"\r\n (submit)=\"submit()\"\r\n (dismiss)=\"dismiss()\"\r\n>\r\n <mat-sidenav-container class=\"date-selector-sidenav-container\">\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F -->\r\n <mat-sidenav #sidenav [mode]=\"isMobile() ? 'over' : 'side'\" [opened]=\"!isMobile()\" class=\"date-selector-sidebar\" dir=\"rtl\">\r\n <div class=\"date-selector-sidebar-inner\" dir=\"ltr\">\r\n <div class=\"date-selector-sidebar-header\">\r\n <span class=\"date-selector-sidebar-title\">\u5FEB\u6377\u9009\u62E9</span>\r\n @if (isMobile()) {\r\n <button mat-icon-button (click)=\"sidenav.close()\">\r\n <i-tabler name=\"layout-sidebar-left-collapse\" />\r\n </button>\r\n }\r\n </div>\r\n <ul class=\"date-selector-sidebar-list\">\r\n @for (timeRangeItem of timeRanges; track timeRangeItem) {\r\n <li class=\"date-selector-sidebar-item\">\r\n <button\r\n type=\"button\"\r\n (click)=\"selectTimeRange(timeRangeItem); isMobile() && sidenav.close()\"\r\n [class.selected]=\"selectedTimeRange() && selectedTimeRange()?.start === timeRangeItem.start && selectedTimeRange()?.end === timeRangeItem.end\"\r\n class=\"date-selector-sidebar-btn\"\r\n >\r\n <span class=\"date-selector-sidebar-text\">{{ timeRangeItem.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n </div>\r\n </mat-sidenav>\r\n <!-- \u5DE6\u4FA7\u5FEB\u6377\u9009\u62E9\u9762\u677F\u7ED3\u675F -->\r\n\r\n <mat-sidenav-content>\r\n @if (isMobile()) {\r\n <div class=\"date-selector-mobile-toolbar\">\r\n <button mat-button (click)=\"sidenav.open()\">\r\n <span>\u5FEB\u6377\u9009\u62E9</span>\r\n </button>\r\n </div>\r\n }\r\n\r\n <!-- \u4E3B\u8981\u5185\u5BB9\u533A\u57DF -->\r\n <div class=\"date-selector-main\">\r\n <div class=\"date-selector-content\">\r\n <!-- \u65E5\u5386\u5BB9\u5668 -->\r\n <section class=\"date-selector-calendar-section\">\r\n <div class=\"date-selector-calendar-wrapper\">\r\n <mat-calendar [maxDate]=\"!future() ? now : undefined\" [(selected)]=\"selectedDateRange\" (selectedChange)=\"rangeChanged($event)\" class=\"date-selector-calendar\" />\r\n </div>\r\n </section>\r\n <!-- \u65E5\u5386\u5BB9\u5668\u7ED3\u675F -->\r\n\r\n <!-- \u65F6\u95F4\u8BBE\u7F6E\u5BB9\u5668 -->\r\n <section class=\"date-selector-time-section\">\r\n <!-- \u5F00\u59CB\u548C\u7ED3\u675F\u8F93\u5165\u65E5\u671F -->\r\n <div class=\"date-selector-inputs\">\r\n <!-- \u4ECE\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u5F00\u59CB\u65E5\u671F\"\r\n [dateValue]=\"startDate()\"\r\n [hourValue]=\"startHour()\"\r\n (hourChange)=\"startHour.set($event)\"\r\n [minuteValue]=\"startMinute()\"\r\n (minuteChange)=\"startMinute.set($event)\"\r\n [hours]=\"hours\"\r\n [minutes]=\"minutes\"\r\n (dateChange)=\"changeDatePart('start', $event)\"\r\n (timeChange)=\"updateStartTime()\"\r\n />\r\n\r\n <!-- \u7ED3\u675F\u65E5\u671F -->\r\n <date-time-input\r\n label=\"\u7ED3\u675F\u65E5\u671F\"\r\n [dateValue]=\"endDate()\"\r\n [hourValue]=\"endHour()\"\r\n (hourChange)=\"endHour.set($event)\"\r\n [minuteValue]=\"endMinute()\"\r\n (minuteChange)=\"endMinute.set($event)\"\r\n [hours]=\"hours\"\r\n [minutes]=\"minutes\"\r\n (dateChange)=\"changeDatePart('end', $event)\"\r\n (timeChange)=\"updateEndTime()\"\r\n />\r\n </div>\r\n\r\n <div class=\"date-selector-hint-wrapper\">\r\n <div class=\"date-selector-hint\">\r\n <i-tabler name=\"info-circle\" strokeWidth=\"2px\" class=\"date-selector-hint-icon\"></i-tabler>\r\n <span class=\"date-selector-hint-text\">\u5982\u679C\u8981\u9009\u62E9\u4E00\u5929\uFF0C\u8BF7\u53CC\u51FB\u8BE5\u5929\u3002</span>\r\n </div>\r\n </div>\r\n </section>\r\n </div>\r\n </div>\r\n </mat-sidenav-content>\r\n </mat-sidenav-container>\r\n</date-time-picker-container>\r\n\r\n<ng-template #footerExtraContent>\r\n <div class=\"date-selector-footer-range\">\r\n <span class=\"date-selector-footer-label\">\u8303\u56F4\uFF1A</span>\r\n\r\n @if (startDate()) {\r\n <div class=\"date-selector-footer-value\">\r\n @if (startDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayStart() }}</span>\r\n }\r\n\r\n @if (startDate() && endDate()) {\r\n <span class=\"date-selector-footer-separator\">-</span>\r\n }\r\n\r\n @if (endDate()) {\r\n <span class=\"date-selector-footer-date\">{{ displayEnd() }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.date-selector-sidebar{width:12rem;height:100%;background-color:var(--mat-sys-surface-container, #fafafa);border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;flex-direction:column}.date-selector-sidebar-inner{width:100%;height:100%;display:flex;flex-direction:column;padding:0}.date-selector-sidebar-header{padding:12px 16px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));background-color:var(--mat-sys-surface, #fff);position:sticky;top:0;z-index:1;display:flex;justify-content:space-between;align-items:center}.date-selector-sidebar-title{font-size:.75rem;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-sidebar-list{list-style:none;margin:0;padding:4px 0;flex:1;overflow-y:auto;overflow-x:hidden}.date-selector-sidebar-item{margin:0;padding:0}.date-selector-sidebar-btn{width:100%;padding:8px 12px;background:transparent;border:none;cursor:pointer;font-size:.8125rem;font-weight:500;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));text-align:left;transition:all .2s ease;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.date-selector-sidebar-btn:hover{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));color:var(--mat-sys-primary, #1976d2);padding-left:16px}.date-selector-sidebar-btn.selected{background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .16));color:var(--mat-sys-primary, #1976d2);font-weight:600;padding-left:16px}.date-selector-sidebar-btn:focus-visible{outline:2px solid var(--mat-sys-primary, #1976d2);outline-offset:-2px}.date-selector-sidebar-text{display:block}.date-selector-main{width:100%;height:100%;display:flex;background-color:var(--mat-sys-surface, #fff)}@media(max-width:767px){.date-selector-main{height:auto;flex:1}}.date-selector-content{width:100%;height:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-content{flex-direction:row}}.date-selector-calendar-section{width:100%;display:flex;align-items:center;justify-content:center;padding:16px;border-right:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));box-sizing:border-box}@media(min-width:768px){.date-selector-calendar-section{width:50%}}@media(max-width:767px){.date-selector-calendar-section{border-right:none;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));padding-top:0;padding-bottom:0}}.date-selector-calendar-wrapper{width:100%;display:flex;flex-direction:column;gap:16px}.date-selector-calendar{width:100%}.date-selector-hint{display:flex;align-items:flex-start;gap:8px;padding:12px 16px;background-color:var(--mat-sys-primary-container, rgba(25, 118, 210, .08));border:1px solid var(--mat-outline-variant, rgba(25, 118, 210, .16));border-radius:4px;align-items:center}.date-selector-hint-icon{flex-shrink:0;color:var(--mat-sys-primary, #1976d2);margin-top:2px}.date-selector-hint-text{font-size:.75rem;line-height:1.25;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6))}.date-selector-hint-wrapper{padding:12px 16px}.date-selector-time-section{width:100%;display:flex;flex-direction:column}@media(min-width:768px){.date-selector-time-section{width:50%}}.date-selector-inputs{display:flex;flex-direction:column;padding:0}.date-selector-footer-range{display:flex;align-items:center;gap:8px;font-size:.75rem;margin-right:auto;padding:0 8px}.date-selector-footer-label{font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-label{display:block}}.date-selector-footer-value{display:flex;flex-direction:column;gap:0;font-weight:600}@media(min-width:768px){.date-selector-footer-value{flex-direction:row;gap:8px;align-items:center}}.date-selector-footer-date{color:var(--mat-sys-on-surface, rgba(0, 0, 0, .87));white-space:nowrap}.date-selector-footer-separator{color:var(--mat-sys-on-surface-variant, rgba(0, 0, 0, .6));display:none}@media(min-width:768px){.date-selector-footer-separator{display:block}}.date-selector-sidenav-container{width:100%;height:100%;background-color:transparent}.date-selector-mobile-toolbar{padding:8px;border-bottom:1px solid var(--mat-divider-color, rgba(0, 0, 0, .12));display:flex;align-items:center}\n", ":host{display:block;height:100%}\n"] }]
459
529
  }], ctorParameters: () => [], propDecorators: { sidenav: [{
460
530
  type: ViewChild,
461
531
  args: ['sidenav']
@@ -466,73 +536,60 @@ class DatePickerComponent {
466
536
  #dialog;
467
537
  #focusMonitor;
468
538
  #elementRef;
469
- #matFormField;
470
539
  #injector;
471
540
  // 内部值存储:{start: string, end: string} 或 null/undefined
472
541
  #internalValue;
473
542
  #errorStateSignal;
474
- #shouldLabelFloatSignal;
475
543
  #focusedSignal;
476
544
  #id;
477
- formatDate(date) {
478
- const datePart = this._dateAdapter.format(date, this._dateFormats.display.dateInput);
479
- const hours = date.getHours().toString().padStart(2, '0');
480
- const minutes = date.getMinutes().toString().padStart(2, '0');
481
- return `${datePart} ${hours}:${minutes}`;
482
- }
483
545
  constructor() {
484
546
  this.#breakpoints = inject(BreakpointObserver);
485
547
  this.#dialog = inject(MatDialog);
486
548
  this.#focusMonitor = inject(FocusMonitor);
487
549
  this.#elementRef = inject(ElementRef);
488
- this.#matFormField = inject(MatFormField, { optional: true });
489
550
  this.#injector = inject(Injector);
490
551
  this._dateAdapter = inject(DateAdapter);
491
552
  this._dateFormats = inject(MAT_DATE_FORMATS);
492
553
  this.destroyRef = inject(DestroyRef);
493
- this.ngControl = null;
554
+ this.ngControl = inject(NgControl, { optional: true, self: true });
494
555
  this.required = false;
495
556
  this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : {}), alias: 'disabled' });
496
557
  this._formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_formDisabled" }] : []));
497
- this.valueFormat = 'yyyy-MM-dd HH:mm';
498
558
  this.placeholder = '';
499
559
  this.future = input(false, ...(ngDevMode ? [{ debugName: "future" }] : []));
560
+ this.isTimestamp = input(false, ...(ngDevMode ? [{ debugName: "isTimestamp" }] : []));
500
561
  this.selectedDateRange = model(...(ngDevMode ? [undefined, { debugName: "selectedDateRange" }] : []));
501
- this.toggle = signal(false, ...(ngDevMode ? [{ debugName: "toggle" }] : []));
502
562
  this.selectionChange = output();
503
563
  // 内部值存储:{start: string, end: string} 或 null/undefined
504
564
  this.#internalValue = signal(undefined, ...(ngDevMode ? [{ debugName: "#internalValue" }] : []));
505
565
  // MatFormFieldControl 属性
506
566
  this.stateChanges = new Subject();
507
567
  this.#errorStateSignal = signal(false, ...(ngDevMode ? [{ debugName: "#errorStateSignal" }] : []));
508
- this.#shouldLabelFloatSignal = signal(false, ...(ngDevMode ? [{ debugName: "#shouldLabelFloatSignal" }] : []));
509
568
  this.#focusedSignal = signal(false, ...(ngDevMode ? [{ debugName: "#focusedSignal" }] : []));
510
569
  this.#id = signal(`date-time-picker-${Math.random().toString(36).substr(2, 9)}`, ...(ngDevMode ? [{ debugName: "#id" }] : []));
511
570
  this.displayStart = computed(() => {
512
571
  const range = this.selectedDateRange();
513
572
  if (!range?.start)
514
573
  return '';
515
- return this.formatDate(range.start);
574
+ return formatDate(range.start, this._dateAdapter, this._dateFormats);
516
575
  }, ...(ngDevMode ? [{ debugName: "displayStart" }] : []));
517
576
  this.displayEnd = computed(() => {
518
577
  const range = this.selectedDateRange();
519
578
  if (!range?.end)
520
579
  return '';
521
- return this.formatDate(range.end);
580
+ return formatDate(range.end, this._dateAdapter, this._dateFormats);
522
581
  }, ...(ngDevMode ? [{ debugName: "displayEnd" }] : []));
523
582
  this.ref = effect(() => {
524
- const dateRange = this.selectedDateRange();
583
+ this.selectedDateRange();
525
584
  // 触发 MatFormField 更新
526
- this.stateChanges.next();
527
- this.#shouldLabelFloatSignal.set(!!dateRange);
528
- // 通知 ControlValueAccessor(当通过 model 更新时)
529
- if (dateRange && this.onChange) {
530
- const value = this.#internalValue();
531
- if (value) {
532
- this.onChange(value);
533
- }
534
- }
585
+ untracked(() => this.stateChanges.next());
535
586
  }, ...(ngDevMode ? [{ debugName: "ref" }] : []));
587
+ if (this.ngControl) {
588
+ this.ngControl.valueAccessor = this;
589
+ this.ngControl.statusChanges?.pipe(takeUntilDestroyed()).subscribe(() => {
590
+ this.stateChanges.next();
591
+ });
592
+ }
536
593
  // 监听 focus 事件
537
594
  this.#focusMonitor
538
595
  .monitor(this.#elementRef, true)
@@ -555,8 +612,7 @@ class DatePickerComponent {
555
612
  const currentValue = this.#internalValue();
556
613
  const data = {
557
614
  dateTimePicker: currentValue ?? undefined,
558
- future: this.future(),
559
- valueFormat: this.valueFormat
615
+ future: this.future()
560
616
  };
561
617
  const dialogRef = this.#dialog.open(DateSelector, {
562
618
  width: isMobile ? '100%' : '850px',
@@ -568,22 +624,31 @@ class DatePickerComponent {
568
624
  panelClass: 'date-time-picker-dialog',
569
625
  injector: this.#injector
570
626
  });
571
- dialogRef
572
- .afterOpened()
573
- .pipe(take(1), takeUntilDestroyed(this.destroyRef), tap(() => this.toggle.update((status) => !status)))
574
- .subscribe();
575
627
  dialogRef
576
628
  .afterClosed()
577
629
  .pipe(take(1), takeUntilDestroyed(this.destroyRef), tap((result) => {
578
- this.toggle.update((status) => !status);
579
630
  if (result && result.dateTimePicker) {
631
+ const start = new Date(result.dateTimePicker.start);
632
+ const end = new Date(result.dateTimePicker.end);
633
+ let startVal;
634
+ let endVal;
635
+ if (this.isTimestamp()) {
636
+ start.setSeconds(0, 0);
637
+ end.setSeconds(0, 0);
638
+ startVal = start.getTime();
639
+ endVal = end.getTime();
640
+ }
641
+ else {
642
+ startVal = formatDate(start, this._dateAdapter, this._dateFormats);
643
+ endVal = formatDate(end, this._dateAdapter, this._dateFormats);
644
+ }
580
645
  const rangeValue = {
581
- start: result.dateTimePicker.start,
582
- end: result.dateTimePicker.end
646
+ start: startVal,
647
+ end: endVal
583
648
  };
584
649
  this.#internalValue.set(rangeValue);
585
650
  // 更新显示用的日期范围
586
- this.selectedDateRange.set(new DateRange(new Date(result.dateTimePicker.start), new Date(result.dateTimePicker.end)));
651
+ this.selectedDateRange.set(new DateRange(start, end));
587
652
  // 发出用户手动选择的值
588
653
  this.selectionChange.emit(rangeValue);
589
654
  // 通知表单控件
@@ -635,16 +700,16 @@ class DatePickerComponent {
635
700
  return !this.#internalValue();
636
701
  }
637
702
  get shouldPlaceholderFloat() {
638
- return this.#shouldLabelFloatSignal();
703
+ return this.shouldLabelFloat;
639
704
  }
640
705
  get focused() {
641
706
  return this.#focusedSignal();
642
707
  }
643
708
  get errorState() {
644
- return this.#errorStateSignal();
709
+ return this.#errorStateSignal() || (!!this.ngControl?.invalid && (!!this.ngControl?.touched || !!this.ngControl?.dirty));
645
710
  }
646
711
  get shouldLabelFloat() {
647
- return this.#shouldLabelFloatSignal();
712
+ return this.focused || !this.empty;
648
713
  }
649
714
  get id() {
650
715
  return this.#id();
@@ -680,13 +745,8 @@ class DatePickerComponent {
680
745
  this.stateChanges.next();
681
746
  }
682
747
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
683
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DatePickerComponent, isStandalone: true, selector: "date-time-picker", inputs: { required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: false, isRequired: false, transformFunction: null }, dateTimePicker: { classPropertyName: "dateTimePicker", publicName: "dateTimePicker", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, future: { classPropertyName: "future", publicName: "future", isSignal: true, isRequired: false, transformFunction: null }, selectedDateRange: { classPropertyName: "selectedDateRange", publicName: "selectedDateRange", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedDateRange: "selectedDateRangeChange", selectionChange: "selectionChange" }, providers: [
748
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: DatePickerComponent, isStandalone: true, selector: "date-time-picker", inputs: { required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, future: { classPropertyName: "future", publicName: "future", isSignal: true, isRequired: false, transformFunction: null }, isTimestamp: { classPropertyName: "isTimestamp", publicName: "isTimestamp", isSignal: true, isRequired: false, transformFunction: null }, selectedDateRange: { classPropertyName: "selectedDateRange", publicName: "selectedDateRange", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedDateRange: "selectedDateRangeChange", selectionChange: "selectionChange" }, providers: [
684
749
  provideTablerIcons({ IconCalendarDue, IconX }),
685
- {
686
- provide: NG_VALUE_ACCESSOR,
687
- useExisting: forwardRef(() => DatePickerComponent),
688
- multi: true
689
- },
690
750
  {
691
751
  provide: MatFormFieldControl,
692
752
  useExisting: forwardRef(() => DatePickerComponent)
@@ -697,11 +757,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
697
757
  type: Component,
698
758
  args: [{ selector: 'date-time-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TablerIconComponent, MatDatepickerModule, MatDialogModule], providers: [
699
759
  provideTablerIcons({ IconCalendarDue, IconX }),
700
- {
701
- provide: NG_VALUE_ACCESSOR,
702
- useExisting: forwardRef(() => DatePickerComponent),
703
- multi: true
704
- },
705
760
  {
706
761
  provide: MatFormFieldControl,
707
762
  useExisting: forwardRef(() => DatePickerComponent)
@@ -712,152 +767,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
712
767
  args: ['dateRangeButton']
713
768
  }], required: [{
714
769
  type: Input
715
- }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valueFormat: [{
716
- type: Input
717
- }], dateTimePicker: [{
718
- type: Input
719
- }], placeholder: [{
770
+ }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], placeholder: [{
720
771
  type: Input
721
- }], future: [{ type: i0.Input, args: [{ isSignal: true, alias: "future", required: false }] }], selectedDateRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDateRange", required: false }] }, { type: i0.Output, args: ["selectedDateRangeChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
722
-
723
- class SmartDialogService {
724
- constructor() {
725
- this.#dialog = inject(MatDialog);
726
- this.#bottomSheet = inject(MatBottomSheet);
727
- this.#breakpoints = inject(BreakpointObserver);
728
- this.ref = null;
729
- this.data = null;
730
- }
731
- #dialog;
732
- #bottomSheet;
733
- #breakpoints;
734
- open(component, config = {}) {
735
- const isMobile = this.#breakpoints.isMatched([
736
- Breakpoints.Handset,
737
- Breakpoints.Tablet
738
- ]);
739
- const smartRef = new SmartDialogRef({});
740
- this.data = config.data;
741
- if (isMobile) {
742
- this.ref = this.#bottomSheet.open(component, {
743
- ariaLabel: 'Bottomsheet',
744
- ariaModal: true,
745
- autoFocus: false,
746
- data: config.data,
747
- panelClass: config.panelClass,
748
- disableClose: config.disableClose
749
- });
750
- Promise.resolve().then(() => {
751
- const hostElement = this.ref?.containerInstance?._elementRef?.nativeElement;
752
- const container = hostElement?.closest('.mat-bottom-sheet-container');
753
- if (container) {
754
- if (config.width)
755
- container.style.width = config.width;
756
- if (config.height)
757
- container.style.height = config.height;
758
- if (config.maxWidth)
759
- container.style.maxWidth = config.maxWidth;
760
- container.style.minWidth = 'unset';
761
- container.style.maxHeight = 'unset';
762
- container.style.borderTopLeftRadius = '1rem';
763
- container.style.borderTopRightRadius = '1rem';
764
- }
765
- if (hostElement) {
766
- if (config.width)
767
- hostElement.style.width = config.width;
768
- if (config.maxWidth)
769
- hostElement.style.maxWidth = config.maxWidth;
770
- if (config.height)
771
- hostElement.style.height = config.height;
772
- }
773
- });
774
- smartRef.ref = this.ref;
775
- }
776
- else {
777
- this.ref = this.#dialog.open(component, {
778
- data: config.data,
779
- ariaLabel: 'Dialog',
780
- ariaModal: true,
781
- autoFocus: false,
782
- panelClass: config.panelClass,
783
- disableClose: config.disableClose,
784
- width: config.width,
785
- height: config.height,
786
- maxWidth: config.maxWidth,
787
- });
788
- const hostElement = this.ref._containerInstance?._elementRef?.nativeElement;
789
- const container = hostElement?.closest('.mat-mdc-dialog-panel');
790
- if (container) {
791
- if (config.width)
792
- container.style.width = config.width;
793
- if (config.height)
794
- container.style.height = config.height;
795
- if (config.maxWidth) {
796
- container.style.maxWidth = config.maxWidth;
797
- }
798
- else {
799
- container.style.maxWidth = 'unset';
800
- }
801
- container.style.minWidth = 'unset';
802
- container.style.maxHeight = 'unset';
803
- }
804
- smartRef.ref = this.ref;
805
- }
806
- return smartRef;
807
- }
808
- getData() {
809
- return this.data;
810
- }
811
- close(result) {
812
- if (!this.ref)
813
- return;
814
- if ('close' in this.ref) {
815
- this.ref.close(result);
816
- }
817
- else {
818
- this.ref.dismiss(result);
819
- }
820
- this.clear();
821
- }
822
- clear() {
823
- this.ref = null;
824
- this.data = null;
825
- }
826
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SmartDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
827
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SmartDialogService, providedIn: 'root' }); }
828
- }
829
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SmartDialogService, decorators: [{
830
- type: Injectable,
831
- args: [{ providedIn: 'root' }]
832
- }] });
833
- class SmartDialogRef {
834
- constructor(ref) {
835
- this.ref = ref;
836
- }
837
- close(result) {
838
- if ('close' in this.ref) {
839
- this.ref.close(result);
840
- }
841
- else {
842
- this.ref.dismiss(result);
843
- }
844
- }
845
- afterOpened() {
846
- return this.ref.afterOpened();
847
- }
848
- afterClosed() {
849
- if ('afterClosed' in this.ref) {
850
- return this.ref.afterClosed();
851
- }
852
- else {
853
- return this.ref.afterDismissed();
854
- }
855
- }
856
- }
772
+ }], future: [{ type: i0.Input, args: [{ isSignal: true, alias: "future", required: false }] }], isTimestamp: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTimestamp", required: false }] }], selectedDateRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedDateRange", required: false }] }, { type: i0.Output, args: ["selectedDateRangeChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
857
773
 
858
774
  /**
859
775
  * Generated bundle index. Do not edit.
860
776
  */
861
777
 
862
- export { DatePickerComponent, DateSelector, SmartDialogRef, SmartDialogService };
778
+ export { DatePickerComponent, DateSelector, formatDate };
863
779
  //# sourceMappingURL=luoxiao123-angular-material-date-time-range-picker.mjs.map