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

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,52 @@ 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
+ function formatDate(date, dateAdapter, dateFormats) {
95
+ const datePart = dateAdapter.format(date, dateFormats.display.dateInput);
96
+ const hours = date.getHours().toString().padStart(2, '0');
97
+ const minutes = date.getMinutes().toString().padStart(2, '0');
98
+ return `${datePart} ${hours}:${minutes}`;
99
+ }
100
+
101
+ const DEFAULT_TIME_RANGES = [
102
+ { label: '最近5分钟', start: 'offset:-5minutes', end: 'offset:now' },
103
+ { label: '最近15分钟', start: 'offset:-15minutes', end: 'offset:now' },
104
+ { label: '最近30分钟', start: 'offset:-30minutes', end: 'offset:now' },
105
+ { label: '最近1小时', start: 'offset:-1hours', end: 'offset:now' },
106
+ { label: '最近3小时', start: 'offset:-3hours', end: 'offset:now' },
107
+ { label: '最近6小时', start: 'offset:-6hours', end: 'offset:now' },
108
+ { label: '最近12小时', start: 'offset:-12hours', end: 'offset:now' },
109
+ { label: '最近24小时', start: 'offset:-24hours', end: 'offset:now' },
110
+ { label: '最近2天', start: 'offset:-2days', end: 'offset:now' },
111
+ { label: '最近7天', start: 'offset:-7days', end: 'offset:now' },
112
+ { label: '最近30天', start: 'offset:-30days', end: 'offset:now' },
113
+ { label: '最近90天', start: 'offset:-90days', end: 'offset:now' },
114
+ { label: '最近6个月', start: 'offset:-6months', end: 'offset:now' },
115
+ { label: '最近1年', start: 'offset:-1years', end: 'offset:now' },
116
+ { label: '最近2年', start: 'offset:-2years', end: 'offset:now' },
117
+ { label: '最近5年', start: 'offset:-5years', end: 'offset:now' },
118
+ { label: '昨天', start: 'offset:-1days/start', end: 'offset:-1days/end' },
119
+ { label: '前天', start: 'offset:-2days/start', end: 'offset:-2days/end' },
120
+ { label: '上周同一天', start: 'offset:-7days/start', end: 'offset:-7days/end' },
121
+ { label: '今天', start: 'offset:0days/start', end: 'offset:0days/end' },
122
+ { label: '今天至今', start: 'offset:0days/start', end: 'offset:now' },
123
+ { label: '本周至今', start: 'startof:week', end: 'offset:now' },
124
+ { label: '本月至今', start: 'startof:month', end: 'offset:now' },
125
+ { label: '今年至今', start: 'startof:year', end: 'offset:now' }
126
+ ];
127
+ const FUTURE_TIME_RANGES = [
128
+ { label: '未来1天', start: 'offset:now', end: 'offset:+1days' },
129
+ { label: '未来1周', start: 'offset:now', end: 'offset:+1weeks' },
130
+ { label: '未来1月', start: 'offset:now', end: 'offset:+1months' },
131
+ { label: '未来3月', start: 'offset:now', end: 'offset:+3months' }
132
+ ];
133
+
98
134
  class DateSelector {
99
- #cdr;
100
135
  #dialogRef;
101
136
  #data;
102
137
  #selectionModel;
103
138
  #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
139
  constructor() {
111
- this.#cdr = inject(ChangeDetectorRef);
112
140
  this.#dialogRef = inject((MatDialogRef));
113
141
  this.#data = inject(MAT_DIALOG_DATA);
114
142
  this.#selectionModel = inject((MatRangeDateSelectionModel));
@@ -117,7 +145,6 @@ class DateSelector {
117
145
  this._dateFormats = inject(MAT_DATE_FORMATS);
118
146
  this.isMobile = signal(false, ...(ngDevMode ? [{ debugName: "isMobile" }] : []));
119
147
  this.data = this.#data;
120
- this.valueFormat = this.data?.valueFormat ?? 'yyyy-MM-dd HH:mm';
121
148
  this.startDate = model('', ...(ngDevMode ? [{ debugName: "startDate" }] : []));
122
149
  this.endDate = model('', ...(ngDevMode ? [{ debugName: "endDate" }] : []));
123
150
  this.startHour = model(null, ...(ngDevMode ? [{ debugName: "startHour" }] : []));
@@ -129,71 +156,21 @@ class DateSelector {
129
156
  const startStr = this.startDate();
130
157
  if (!startStr)
131
158
  return '';
132
- return this.formatDate(new Date(startStr));
159
+ return formatDate(new Date(startStr), this._dateAdapter, this._dateFormats);
133
160
  }, ...(ngDevMode ? [{ debugName: "displayStart" }] : []));
134
161
  this.displayEnd = computed(() => {
135
162
  const endStr = this.endDate();
136
163
  if (!endStr)
137
164
  return '';
138
- return this.formatDate(new Date(endStr));
165
+ return formatDate(new Date(endStr), this._dateAdapter, this._dateFormats);
139
166
  }, ...(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" }] : []));
167
+ this.timeRanges = [...DEFAULT_TIME_RANGES];
193
168
  this.selectedTimeRange = model(undefined, ...(ngDevMode ? [{ debugName: "selectedTimeRange" }] : []));
194
169
  this.selectedDateRange = null;
195
170
  this.now = new Date();
196
171
  this.selectingStart = true;
172
+ this.hours = Array.from({ length: 24 }, (_, i) => i);
173
+ this.minutes = Array.from({ length: 60 }, (_, i) => i);
197
174
  this.#breakpoints
198
175
  .observe([Breakpoints.Handset, Breakpoints.Tablet])
199
176
  .pipe(takeUntilDestroyed())
@@ -221,17 +198,11 @@ class DateSelector {
221
198
  }
222
199
  }
223
200
  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]);
201
+ this.timeRanges = [...this.timeRanges, ...FUTURE_TIME_RANGES];
231
202
  }
232
203
  }
233
- else {
234
- this.selectTimeRange(this.timeRanges()[5]);
204
+ if (!this.data?.dateTimePicker) {
205
+ this.selectTimeRange(this.timeRanges[5]);
235
206
  }
236
207
  }
237
208
  selectTimeRange(timeRange) {
@@ -252,46 +223,89 @@ class DateSelector {
252
223
  const parseTime = (time) => {
253
224
  if (!time)
254
225
  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();
226
+ // 处理 startof: 前缀 (本周/本月/今年)
227
+ if (time.startsWith('startof:')) {
228
+ const unit = time.replace('startof:', '').trim().toLowerCase();
266
229
  const result = new Date(now);
230
+ result.setHours(0, 0, 0, 0);
267
231
  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
232
  case 'week':
282
- result.setDate(result.getDate() + value * 7);
233
+ // 假设周一为一周的开始
234
+ const day = result.getDay() || 7; // 0是周日,改为7
235
+ if (day !== 1) {
236
+ result.setHours(-24 * (day - 1));
237
+ }
283
238
  break;
284
- case 'months':
285
239
  case 'month':
286
- result.setMonth(result.getMonth() + value);
240
+ result.setDate(1);
287
241
  break;
288
- case 'years':
289
242
  case 'year':
290
- result.setFullYear(result.getFullYear() + value);
243
+ result.setMonth(0, 1);
291
244
  break;
292
245
  }
293
246
  return result;
294
247
  }
248
+ // 处理 offset: 前缀
249
+ if (time.startsWith('offset:')) {
250
+ const offsetStr = time.replace('offset:', '').trim();
251
+ if (offsetStr === 'now')
252
+ return new Date(now);
253
+ // 检查是否有 /start 或 /end 后缀
254
+ let suffix = '';
255
+ let cleanOffset = offsetStr;
256
+ if (offsetStr.endsWith('/start')) {
257
+ suffix = 'start';
258
+ cleanOffset = offsetStr.replace('/start', '');
259
+ }
260
+ else if (offsetStr.endsWith('/end')) {
261
+ suffix = 'end';
262
+ cleanOffset = offsetStr.replace('/end', '');
263
+ }
264
+ const regex = /([+-]?)(\d+)(months?|days?|years?|weeks?|hours?|minutes?)/i;
265
+ const match = regex.exec(cleanOffset);
266
+ // 如果没有匹配到数字偏移量,但有后缀(例如 offset:0days/start),尝试解析
267
+ // 注意:上面的正则也能匹配 0days
268
+ const result = new Date(now);
269
+ if (match) {
270
+ const sign = match[1] === '-' ? -1 : 1;
271
+ const value = parseInt(match[2], 10) * sign;
272
+ const unit = match[3].toLowerCase();
273
+ switch (unit) {
274
+ case 'minutes':
275
+ case 'minute':
276
+ result.setMinutes(result.getMinutes() + value);
277
+ break;
278
+ case 'hours':
279
+ case 'hour':
280
+ result.setHours(result.getHours() + value);
281
+ break;
282
+ case 'days':
283
+ case 'day':
284
+ result.setDate(result.getDate() + value);
285
+ break;
286
+ case 'weeks':
287
+ case 'week':
288
+ result.setDate(result.getDate() + value * 7);
289
+ break;
290
+ case 'months':
291
+ case 'month':
292
+ result.setMonth(result.getMonth() + value);
293
+ break;
294
+ case 'years':
295
+ case 'year':
296
+ result.setFullYear(result.getFullYear() + value);
297
+ break;
298
+ }
299
+ }
300
+ // 应用后缀修正
301
+ if (suffix === 'start') {
302
+ result.setHours(0, 0, 0, 0);
303
+ }
304
+ else if (suffix === 'end') {
305
+ result.setHours(23, 59, 59, 999);
306
+ }
307
+ return result;
308
+ }
295
309
  return new Date(time);
296
310
  };
297
311
  const startDate = timeRange.start ? parseTime(timeRange.start) : null;
@@ -350,33 +364,79 @@ class DateSelector {
350
364
  this.selectedDateRange = range;
351
365
  this.startDate.set(start?.toISOString() ?? '');
352
366
  this.endDate.set(end?.toISOString() ?? '');
367
+ if (start) {
368
+ this.startHour.set(start.getHours());
369
+ this.startMinute.set(start.getMinutes());
370
+ }
371
+ else {
372
+ this.startHour.set(null);
373
+ this.startMinute.set(null);
374
+ }
375
+ if (end) {
376
+ this.endHour.set(end.getHours());
377
+ this.endMinute.set(end.getMinutes());
378
+ }
379
+ else {
380
+ this.endHour.set(null);
381
+ this.endMinute.set(null);
382
+ }
353
383
  }
354
384
  rangeChanged(selectedDate) {
355
385
  if (!selectedDate)
356
386
  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
387
  if (this.selectingStart) {
361
- this.startDate.set(dateWithCurrentTime.toISOString());
388
+ // 正在选择开始日期
389
+ let h = 0, m = 0, s = 0, ms = 0;
390
+ // 尝试保留之前的开始时间
391
+ if (this.selectedDateRange?.start) {
392
+ h = this.selectedDateRange.start.getHours();
393
+ m = this.selectedDateRange.start.getMinutes();
394
+ s = this.selectedDateRange.start.getSeconds();
395
+ }
396
+ const newStart = new Date(selectedDate);
397
+ newStart.setHours(h, m, s, ms);
398
+ this.startDate.set(newStart.toISOString());
362
399
  this.endDate.set('');
363
- this.startHour.set(dateWithCurrentTime.getHours());
364
- this.startMinute.set(dateWithCurrentTime.getMinutes());
400
+ this.startHour.set(newStart.getHours());
401
+ this.startMinute.set(newStart.getMinutes());
365
402
  this.endHour.set(null);
366
403
  this.endMinute.set(null);
367
404
  this.selectedTimeRange.set(undefined);
368
- this.selectedDateRange = new DateRange(dateWithCurrentTime, null);
405
+ this.selectedDateRange = new DateRange(newStart, null);
369
406
  this.#selectionModel.updateSelection(this.selectedDateRange, this);
370
407
  this.selectingStart = false;
371
408
  }
372
409
  else {
410
+ // 正在选择结束日期
373
411
  const start = this.#selectionModel.selection.start;
374
412
  if (!start)
375
413
  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);
414
+ const startDay = new Date(start.getFullYear(), start.getMonth(), start.getDate());
415
+ const selectedDay = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
416
+ let newStart;
417
+ let newEnd;
418
+ if (selectedDay.getTime() < startDay.getTime()) {
419
+ // 用户选了一个比 Start 更早的日期 -> 交换角色
420
+ // 新 Start (selectedDate) 设为 00:00
421
+ newStart = new Date(selectedDate);
422
+ newStart.setHours(0, 0, 0, 0);
423
+ // 新 End (旧 start) 设为 23:59
424
+ newEnd = new Date(start);
425
+ newEnd.setHours(23, 59, 59, 999);
426
+ }
427
+ else {
428
+ // 正常顺序 (selectedDate >= start)
429
+ // Start 保持原样
430
+ newStart = new Date(start);
431
+ // End (selectedDate) 设为 23:59
432
+ newEnd = new Date(selectedDate);
433
+ newEnd.setHours(23, 59, 59, 999);
434
+ // 如果是同一天,确保 Start <= End
435
+ if (newStart.getTime() > newEnd.getTime()) {
436
+ newStart.setHours(0, 0, 0, 0);
437
+ }
438
+ }
439
+ this.updateSelection(newStart, newEnd);
380
440
  this.selectingStart = true;
381
441
  }
382
442
  }
@@ -392,13 +452,17 @@ class DateSelector {
392
452
  this.endMinute.set(end.getMinutes());
393
453
  }
394
454
  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();
455
+ if (!this.selectedDateRange?.start || !this.selectedDateRange?.end) {
456
+ return;
457
+ }
458
+ const start = new Date(this.selectedDateRange.start);
459
+ const end = new Date(this.selectedDateRange.end);
460
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
461
+ return;
462
+ }
399
463
  const result = {
400
- start: startISO,
401
- end: endISO
464
+ start: start.toISOString(),
465
+ end: end.toISOString()
402
466
  };
403
467
  this.data = { ...this.data, dateTimePicker: result };
404
468
  this.#dialogRef.close(this.data);
@@ -406,12 +470,6 @@ class DateSelector {
406
470
  dismiss() {
407
471
  this.#dialogRef.close(undefined);
408
472
  }
409
- getHours() {
410
- return Array.from({ length: 24 }, (_, i) => i);
411
- }
412
- getMinutes() {
413
- return Array.from({ length: 60 }, (_, i) => i);
414
- }
415
473
  updateStartTime() {
416
474
  if (this.selectedDateRange?.start && this.startHour() !== null && this.startMinute() !== null) {
417
475
  const startDate = new Date(this.selectedDateRange.start);
@@ -438,7 +496,7 @@ class DateSelector {
438
496
  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
497
  DefaultMatCalendarRangeStrategy,
440
498
  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 }); }
499
+ ], 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
500
  }
443
501
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: DateSelector, decorators: [{
444
502
  type: Component,
@@ -455,7 +513,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
455
513
  DateTimeInputComponent,
456
514
  MatSidenavModule,
457
515
  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"] }]
516
+ ], 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
517
  }], ctorParameters: () => [], propDecorators: { sidenav: [{
460
518
  type: ViewChild,
461
519
  args: ['sidenav']
@@ -466,73 +524,59 @@ class DatePickerComponent {
466
524
  #dialog;
467
525
  #focusMonitor;
468
526
  #elementRef;
469
- #matFormField;
470
527
  #injector;
471
528
  // 内部值存储:{start: string, end: string} 或 null/undefined
472
529
  #internalValue;
473
530
  #errorStateSignal;
474
- #shouldLabelFloatSignal;
475
531
  #focusedSignal;
476
532
  #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
533
  constructor() {
484
534
  this.#breakpoints = inject(BreakpointObserver);
485
535
  this.#dialog = inject(MatDialog);
486
536
  this.#focusMonitor = inject(FocusMonitor);
487
537
  this.#elementRef = inject(ElementRef);
488
- this.#matFormField = inject(MatFormField, { optional: true });
489
538
  this.#injector = inject(Injector);
490
539
  this._dateAdapter = inject(DateAdapter);
491
540
  this._dateFormats = inject(MAT_DATE_FORMATS);
492
541
  this.destroyRef = inject(DestroyRef);
493
- this.ngControl = null;
542
+ this.ngControl = inject(NgControl, { optional: true, self: true });
494
543
  this.required = false;
495
544
  this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : {}), alias: 'disabled' });
496
545
  this._formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_formDisabled" }] : []));
497
- this.valueFormat = 'yyyy-MM-dd HH:mm';
498
546
  this.placeholder = '';
499
547
  this.future = input(false, ...(ngDevMode ? [{ debugName: "future" }] : []));
500
548
  this.selectedDateRange = model(...(ngDevMode ? [undefined, { debugName: "selectedDateRange" }] : []));
501
- this.toggle = signal(false, ...(ngDevMode ? [{ debugName: "toggle" }] : []));
502
549
  this.selectionChange = output();
503
550
  // 内部值存储:{start: string, end: string} 或 null/undefined
504
551
  this.#internalValue = signal(undefined, ...(ngDevMode ? [{ debugName: "#internalValue" }] : []));
505
552
  // MatFormFieldControl 属性
506
553
  this.stateChanges = new Subject();
507
554
  this.#errorStateSignal = signal(false, ...(ngDevMode ? [{ debugName: "#errorStateSignal" }] : []));
508
- this.#shouldLabelFloatSignal = signal(false, ...(ngDevMode ? [{ debugName: "#shouldLabelFloatSignal" }] : []));
509
555
  this.#focusedSignal = signal(false, ...(ngDevMode ? [{ debugName: "#focusedSignal" }] : []));
510
556
  this.#id = signal(`date-time-picker-${Math.random().toString(36).substr(2, 9)}`, ...(ngDevMode ? [{ debugName: "#id" }] : []));
511
557
  this.displayStart = computed(() => {
512
558
  const range = this.selectedDateRange();
513
559
  if (!range?.start)
514
560
  return '';
515
- return this.formatDate(range.start);
561
+ return formatDate(range.start, this._dateAdapter, this._dateFormats);
516
562
  }, ...(ngDevMode ? [{ debugName: "displayStart" }] : []));
517
563
  this.displayEnd = computed(() => {
518
564
  const range = this.selectedDateRange();
519
565
  if (!range?.end)
520
566
  return '';
521
- return this.formatDate(range.end);
567
+ return formatDate(range.end, this._dateAdapter, this._dateFormats);
522
568
  }, ...(ngDevMode ? [{ debugName: "displayEnd" }] : []));
523
569
  this.ref = effect(() => {
524
- const dateRange = this.selectedDateRange();
570
+ this.selectedDateRange();
525
571
  // 触发 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
- }
572
+ untracked(() => this.stateChanges.next());
535
573
  }, ...(ngDevMode ? [{ debugName: "ref" }] : []));
574
+ if (this.ngControl) {
575
+ this.ngControl.valueAccessor = this;
576
+ this.ngControl.statusChanges?.pipe(takeUntilDestroyed()).subscribe(() => {
577
+ this.stateChanges.next();
578
+ });
579
+ }
536
580
  // 监听 focus 事件
537
581
  this.#focusMonitor
538
582
  .monitor(this.#elementRef, true)
@@ -555,8 +599,7 @@ class DatePickerComponent {
555
599
  const currentValue = this.#internalValue();
556
600
  const data = {
557
601
  dateTimePicker: currentValue ?? undefined,
558
- future: this.future(),
559
- valueFormat: this.valueFormat
602
+ future: this.future()
560
603
  };
561
604
  const dialogRef = this.#dialog.open(DateSelector, {
562
605
  width: isMobile ? '100%' : '850px',
@@ -568,22 +611,21 @@ class DatePickerComponent {
568
611
  panelClass: 'date-time-picker-dialog',
569
612
  injector: this.#injector
570
613
  });
571
- dialogRef
572
- .afterOpened()
573
- .pipe(take(1), takeUntilDestroyed(this.destroyRef), tap(() => this.toggle.update((status) => !status)))
574
- .subscribe();
575
614
  dialogRef
576
615
  .afterClosed()
577
616
  .pipe(take(1), takeUntilDestroyed(this.destroyRef), tap((result) => {
578
- this.toggle.update((status) => !status);
579
617
  if (result && result.dateTimePicker) {
618
+ const start = new Date(result.dateTimePicker.start);
619
+ const end = new Date(result.dateTimePicker.end);
620
+ const startStr = formatDate(start, this._dateAdapter, this._dateFormats);
621
+ const endStr = formatDate(end, this._dateAdapter, this._dateFormats);
580
622
  const rangeValue = {
581
- start: result.dateTimePicker.start,
582
- end: result.dateTimePicker.end
623
+ start: startStr,
624
+ end: endStr
583
625
  };
584
626
  this.#internalValue.set(rangeValue);
585
627
  // 更新显示用的日期范围
586
- this.selectedDateRange.set(new DateRange(new Date(result.dateTimePicker.start), new Date(result.dateTimePicker.end)));
628
+ this.selectedDateRange.set(new DateRange(start, end));
587
629
  // 发出用户手动选择的值
588
630
  this.selectionChange.emit(rangeValue);
589
631
  // 通知表单控件
@@ -635,16 +677,16 @@ class DatePickerComponent {
635
677
  return !this.#internalValue();
636
678
  }
637
679
  get shouldPlaceholderFloat() {
638
- return this.#shouldLabelFloatSignal();
680
+ return this.shouldLabelFloat;
639
681
  }
640
682
  get focused() {
641
683
  return this.#focusedSignal();
642
684
  }
643
685
  get errorState() {
644
- return this.#errorStateSignal();
686
+ return this.#errorStateSignal() || (!!this.ngControl?.invalid && (!!this.ngControl?.touched || !!this.ngControl?.dirty));
645
687
  }
646
688
  get shouldLabelFloat() {
647
- return this.#shouldLabelFloatSignal();
689
+ return this.focused || !this.empty;
648
690
  }
649
691
  get id() {
650
692
  return this.#id();
@@ -680,13 +722,8 @@ class DatePickerComponent {
680
722
  this.stateChanges.next();
681
723
  }
682
724
  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: [
725
+ 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 }, selectedDateRange: { classPropertyName: "selectedDateRange", publicName: "selectedDateRange", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedDateRange: "selectedDateRangeChange", selectionChange: "selectionChange" }, providers: [
684
726
  provideTablerIcons({ IconCalendarDue, IconX }),
685
- {
686
- provide: NG_VALUE_ACCESSOR,
687
- useExisting: forwardRef(() => DatePickerComponent),
688
- multi: true
689
- },
690
727
  {
691
728
  provide: MatFormFieldControl,
692
729
  useExisting: forwardRef(() => DatePickerComponent)
@@ -697,11 +734,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
697
734
  type: Component,
698
735
  args: [{ selector: 'date-time-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TablerIconComponent, MatDatepickerModule, MatDialogModule], providers: [
699
736
  provideTablerIcons({ IconCalendarDue, IconX }),
700
- {
701
- provide: NG_VALUE_ACCESSOR,
702
- useExisting: forwardRef(() => DatePickerComponent),
703
- multi: true
704
- },
705
737
  {
706
738
  provide: MatFormFieldControl,
707
739
  useExisting: forwardRef(() => DatePickerComponent)
@@ -712,152 +744,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
712
744
  args: ['dateRangeButton']
713
745
  }], required: [{
714
746
  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: [{
747
+ }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], placeholder: [{
720
748
  type: Input
721
749
  }], 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
750
 
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
- }
857
-
858
751
  /**
859
752
  * Generated bundle index. Do not edit.
860
753
  */
861
754
 
862
- export { DatePickerComponent, DateSelector, SmartDialogRef, SmartDialogService };
755
+ export { DatePickerComponent, DateSelector };
863
756
  //# sourceMappingURL=luoxiao123-angular-material-date-time-range-picker.mjs.map