UNPKG

book-picker

Version:

<p align="center"> <img width="409" height="331" src="https://raw.githubusercontent.com/ymxk/book-picker/master/book-picker.gif"> </p>

586 lines (574 loc) 18.5 kB
import { EventEmitter, Component, Input, Output, Pipe, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MomentModule } from 'ngx-moment'; import moment from 'moment'; import jspath from 'jspath'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class BookPickerComponent { constructor() { this.name = 'Book Picker'; this.bookeds = new Array(); this.hours = new Array(); this.selected = new EventEmitter(); this.onerror = new EventEmitter(); } /** * @param {?} value * @return {?} */ onSelectedDate(value) { this.selectedDate = value.clone(); this.timeRange = null; } /** * @param {?} value * @return {?} */ onSelectedTime(value) { this.timeRange = value; this.selected.emit(value); } /** * @return {?} */ onErrorTime() { this.onerror.emit(); } } BookPickerComponent.decorators = [ { type: Component, args: [{ selector: 'book-picker', template: "<app-date-picker (selected)=\"onSelectedDate($event)\"></app-date-picker>\n<app-time-picker [nowTime]=\"selectedDate\" [bookeds]=\"bookeds\" [hours]=\"hours\" (selected)=\"onSelectedTime($event)\" (onerror)=\"onErrorTime()\"></app-time-picker>\n<app-book-info [timeRange]=\"timeRange\"></app-book-info>", styles: ["p{font-family:Lato}"] }] } ]; BookPickerComponent.propDecorators = { bookeds: [{ type: Input }], hours: [{ type: Input }], selected: [{ type: Output }], onerror: [{ type: Output }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class HoursOfDay { /** * @param {?} start * @param {?} end */ constructor(start, end) { this.start = start; this.end = end; } } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @enum {string} */ const TimeClass = { BOOKED: 'time-booked', DISABLE: 'time-disable', SELECTED: 'time-selected', NORMAL: '', }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class TimePickerComponent { constructor() { this.timeCells = []; this.nowTime = moment(); this.bookeds = new Array(); this.hours = new Array(); this.selected = new EventEmitter(); this.onerror = new EventEmitter(); } /** * @return {?} */ ngOnInit() { this.initBooksOrHours(); this.getHoursForDays(); } /** * @return {?} */ initBooksOrHours() { if (!this.bookeds) { this.bookeds = new Array(); } if (!this.hours) { this.hours = new Array(); } } /** * @return {?} */ onClear() { this.start = null; this.end = null; } /** * @return {?} */ emitSelected() { this.selected.emit({ start: this.start, end: this.addHalfHour(this.end) }); } /** * @param {?} v * @return {?} */ addHalfHour(v) { return v ? v.clone().add(30, 'm') : null; } /** * @return {?} */ emitError() { this.onerror.emit(); } /** * @param {?} value * @return {?} */ onSelected(value) { if (this.start && this.end && this.start.isSame(value, 'm') && this.end.isSame(value, 'm')) { this.onClear(); this.emitSelected(); return false; } if (this.start && this.end && this.start.isSame(value, 'm')) { this.start = this.end; this.emitSelected(); return false; } if (this.start && this.end && this.end.isSame(value, 'm')) { this.end = this.start; this.emitSelected(); return false; } if (!this.start && !this.end) { /** @type {?} */ let x = this.includesDisable(value.clone(), value.clone()); if (x) { this.emitError(); return false; } this.start = value; this.end = value; this.emitSelected(); return false; } if (value.isBefore(this.start)) { /** @type {?} */ let x = this.includesDisable(value.clone(), this.start.clone()); if (x) { this.emitError(); return false; } this.end = this.start; this.start = value; } if (value.isAfter(this.start)) { /** @type {?} */ let x = this.includesDisable(this.start.clone(), value.clone()); if (x) { this.emitError(); return false; } this.end = value; } this.emitSelected(); } /** * @param {?} start * @param {?} end * @return {?} */ includesDisable(start, end) { /** @type {?} */ let range = []; for (let item = start; item.isBefore(end) || item.isSame(end); item.add(30, 'm')) { range.push(item.clone()); } return range.filter((/** * @param {?} e * @return {?} */ e => { return this.includesBooked(e) || this.includesCloses(e); })).length > 0; } /** * @param {?} v * @return {?} */ includesBooked(v) { return this.bookeds.filter((/** * @param {?} e * @return {?} */ e => { return this.isBetweenDate(v, e.start, e.end); })).length > 0; } /** * @param {?} v * @return {?} */ includesCloses(v) { /** @type {?} */ let ph = this.getOpenHoursOnDated(); if (ph && ph.length == 0) { return true; } return ph.filter((/** * @param {?} e * @return {?} */ e => { return this.isBetweenNotEnd(v, e.opens, e.closes); })).length == 0; } /** * @param {?} v * @param {?} s * @param {?} e * @return {?} */ isBetweenNotEnd(v, s, e) { /** @type {?} */ let vs = this.setHourMinuteIgnorDate(v); /** @type {?} */ let ss = this.setHourMinuteIgnorDate(s); /** @type {?} */ let es = this.setHourMinuteIgnorDate(e); return (vs.isBetween(ss, es, 'm') || vs.isSame(ss, 'm')) ? true : false; } /** * @param {?} v * @param {?} s * @param {?} e * @return {?} */ isBetweenDate(v, s, e) { return v.isBetween(s, e) || v.isSame(s) || v.isSame(e); } /** * @param {?} v * @param {?} s * @param {?} e * @return {?} */ isBetweenM(v, s, e) { return v.isBetween(s, e, 'm') || v.isSame(s, 'm') || v.isSame(e, 'm'); } /** * @param {?} value * @return {?} */ getClassBy(value) { if (this.includesBooked(value)) { return TimeClass.BOOKED; } if (this.includesCloses(value)) { return TimeClass.DISABLE; } if (this.isBetweenM(value, this.start, this.end)) { return TimeClass.SELECTED; } return TimeClass.NORMAL; } /** * @param {?} v * @return {?} */ isSameDay(v) { return moment().isSame(v, 'month') && moment().isSame(v, 'day'); } /** * @return {?} */ getDefaultOpenHours() { return new HoursOfDay(this.nowTime.clone().startOf('day'), this.nowTime.clone().endOf('day')); } /** * @return {?} */ nextHalfHourInNow() { /** @type {?} */ const y = parseFloat(this.nowTime.clone().format('mm')) % 30; return this.addHalfHour(this.nowTime.clone().subtract(y, 'm')); } /** * @param {?} oh * @return {?} */ replaceStartByNow(oh) { /** @type {?} */ let start = this.setHourMinuteIgnorDate(oh.start); if (this.isSameDay(start)) { return new HoursOfDay(this.nextHalfHourInNow(), oh.end); } return oh; } /** * @return {?} */ getHoursForDays() { /** @type {?} */ let oh = this.getOpenHoursOnDated(); if (oh && oh.length > 0) { this.createHours(this.toHoursOfDayFrom(oh)); } else { this.createHours(this.getDefaultOpenHours()); } } /** * @param {?} v * @return {?} */ setHourMinuteIgnorDate(v) { return this.nowTime.clone().hour(v.hour()).minute(v.minute()); } /** * @param {?} oh * @return {?} */ createHours(oh) { /** @type {?} */ let t = this.replaceStartByNow(oh); /** @type {?} */ let start = t.start.clone(); /** @type {?} */ let end = t.end.clone(); this.timeCells = []; for (let item = start; item.isBefore(end); item.add(30, 'm')) { this.timeCells.push(item.clone()); } } /** * @return {?} */ getOpenHoursOnDated() { return this.hours.filter((/** * @param {?} e * @return {?} */ (e) => { return e.weeks.includes(this.nowTime.day()); })); } ; /** * @param {?} ts * @return {?} */ toHoursOfDayFrom(ts) { /** @type {?} */ const opens = jspath.apply(`.opens`, ts); /** @type {?} */ const closes = jspath.apply(`.closes`, ts); return new HoursOfDay(this.setHourMinuteIgnorDate(moment.min(opens)), this.setHourMinuteIgnorDate(moment.max(closes))); } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { for (let propName in changes) { /** @type {?} */ let changedProp = changes[propName]; if (changedProp.isFirstChange()) { this.nowTime = moment(); } else { this.onClear(); this.nowTime = changedProp.currentValue; this.getHoursForDays(); } } } } TimePickerComponent.decorators = [ { type: Component, args: [{ selector: 'app-time-picker', template: "<section class=\"card\">\n\n\t<div *ngFor=\"let c of timeCells\" [ngClass]=\"getClassBy(c)\">\n\t\t<div (click)=\"onSelected(c)\">{{c | amDateFormat: 'HH:mm'}}</div>\n\t</div>\n</section>", styles: ["@charset \"UTF-8\";.card{display:-webkit-flex;display:flex;min-width:100%;min-height:54px;overflow-x:auto;border-top:1px solid #e9e9e9;border-bottom:1px solid #e9e9e9}.card>div{min-width:55px;height:54px;background-color:#fff;text-align:center;border-left:1px solid #e9e9e9}.card>div>div:first-child{font-size:13px;font-family:PingFangSC-Regular;font-weight:400;color:#242424;line-height:54px}.card>div:last-child{border-right:1px solid #e9e9e9}.card::-webkit-scrollbar{display:none}.time-disable div{background:#fbfbfb;color:#c4c4c4!important;line-height:14px!important;padding:20px 0 0 2px}.time-disable ::after{content:\"\\a\u672A\u8425\u4E1A\";white-space:pre-wrap;font-size:10px;color:#c4c4c4}.time-selected div{background:#e5f2ff!important;color:#007aff!important;border-left:0!important}.time-booked div{background:#fbfbfb;color:#c4c4c4!important;line-height:14px!important;padding:20px 0 0 2px}.time-booked ::after{content:\"\\a\u5DF2\u9884\u8BA2\";white-space:pre-wrap;font-size:10px;color:#c4c4c4}"] }] } ]; /** @nocollapse */ TimePickerComponent.ctorParameters = () => []; TimePickerComponent.propDecorators = { nowTime: [{ type: Input }], bookeds: [{ type: Input }], hours: [{ type: Input }], selected: [{ type: Output }], onerror: [{ type: Output }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class DatePickerComponent { constructor() { this.days = []; this.selectedDate = moment(); this.endDayForMonth = moment().add(15, 'd'); this.selected = new EventEmitter(); } /** * @return {?} */ ngOnInit() { this.getDaysForMonth(); } /** * @param {?} value * @return {?} */ onSelected(value) { this.selectedDate = value; this.selected.emit(value); } /** * @param {?} value * @return {?} */ isSameDay(value) { return this.selectedDate.isSame(value, 'day') ? 'date-selected' : ''; } /** * @return {?} */ getDaysForMonth() { for (let item = moment(); item.isBefore(this.endDayForMonth); item.add(1, 'd')) { this.days.push(item.clone()); } } } DatePickerComponent.decorators = [ { type: Component, args: [{ selector: 'app-date-picker', template: "<div class=\"date-title\">{{selectedDate | amDateFormat: 'YYYY'}}</div>\n<section class=\"card\">\n\t<div class=\"card--content\" *ngFor=\"let day of days\" [ngClass]=\"isSameDay(day)\" (click)=\"onSelected(day)\">\n\t\t<div>{{day | weekdays}}</div>\n\t\t<div>{{day | amDateFormat: 'M/D'}}</div>\n\t</div>\n</section>", styles: [".card{display:-webkit-flex;display:flex;min-width:100%;min-height:86px;overflow-x:auto}.card::-webkit-scrollbar{display:none}.card--content{min-width:55px;height:86px;background-color:#fff;text-align:center}.card--content div:first-child{height:18px;font-size:13px;font-family:PingFangSC-Regular;font-weight:400;color:#999;line-height:18px;margin:19px 0 10px}.card--content div:last-child{height:21px;line-height:21px;font-size:15px;font-family:PingFangSC-Medium;font-weight:500;color:#242424}.date-title{width:100%;height:46px;line-height:46px;background:#f8f8f8;font-size:17px;font-family:PingFangSC-Medium;font-weight:1000;color:#242424;text-align:center}.date-selected div{color:#007aff!important}"] }] } ]; /** @nocollapse */ DatePickerComponent.ctorParameters = () => []; DatePickerComponent.propDecorators = { selected: [{ type: Output }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class BookInfoComponent { constructor() { } /** * @return {?} */ ngOnInit() { } } BookInfoComponent.decorators = [ { type: Component, args: [{ selector: 'app-book-info', template: "<div class=\"book-info\" *ngIf=\"timeRange && timeRange.start && timeRange.end\">\n\t<label>\u5171\u8BA1 {{timeRange | booktime}} \u5C0F\u65F6</label>\n <div><i class=\"iconfont icon-clock\"></i> {{timeRange | timetable}} </div>\n</div>", styles: [".book-info{padding:17px 20px}.book-info label{width:90px;background:#f8f8f8;border-radius:2px;font-size:13px;font-family:PingFangSC-Regular;font-weight:400;color:#999;line-height:23px;display:inline-block;text-align:center}.book-info div:last-child{height:24px;line-height:24px;font-size:15px;font-family:PingFangSC-Regular;font-weight:400;color:#242424;margin-top:10px}"] }] } ]; /** @nocollapse */ BookInfoComponent.ctorParameters = () => []; BookInfoComponent.propDecorators = { timeRange: [{ type: Input }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class WeekdaysPipe { constructor() { this.now = moment(); this.weekdays = [ "日", "一", "二", "三", "四", "五", "六" ]; } /** * @param {?} value * @return {?} */ transform(value) { if (!value) { return ''; } return this.now.isSame(value, 'day') ? '今日' : this.weekdays[value.day()]; } } WeekdaysPipe.decorators = [ { type: Pipe, args: [{ name: 'weekdays' },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class TimetablePipe { /** * @param {?} value * @return {?} */ transform(value) { return (value && value.end && value.start) ? this.formatTime(value) : this.defaultFormatTime(); } /** * @param {?} value * @return {?} */ formatTime(value) { return `${value.start.clone().format('M月D日 HH:mm')}~${value.end.clone().format('HH:mm')}`; } /** * @return {?} */ defaultFormatTime() { return `${moment().format('M月D日 HH:mm')}~${moment().format('HH:mm')}`; } } TimetablePipe.decorators = [ { type: Pipe, args: [{ name: 'timetable' },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class BooktimePipe { /** * @param {?} value * @return {?} */ transform(value) { return (value && value.end && value.start) ? `${moment.duration(value.end.diff(value.start)).asHours()}` : '0'; } } BooktimePipe.decorators = [ { type: Pipe, args: [{ name: 'booktime' },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class BookPickerModule { } BookPickerModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule, MomentModule], declarations: [TimePickerComponent, DatePickerComponent, BookInfoComponent, WeekdaysPipe, TimetablePipe, BooktimePipe, BookPickerComponent], exports: [BookPickerComponent] },] } ]; export { BookPickerComponent, BookPickerModule, TimePickerComponent as ɵa, DatePickerComponent as ɵb, BookInfoComponent as ɵc, WeekdaysPipe as ɵd, TimetablePipe as ɵe, BooktimePipe as ɵf }; //# sourceMappingURL=book-picker.js.map