import { Component, OnInit, forwardRef, Input, HostBinding, Output, EventEmitter, Injector, SimpleChanges, ElementRef, ViewChild, NgZone, HostListener } from '@angular/core'; import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; import { DateTimeHelperService } from '@farris/ui-common/date'; import { NumberHelperService } from '@farris/ui-common/number'; import { LocaleService } from '@farris/ui-locale'; @Component({ selector: 'farris-text', template: ` {{text && text.length > 0 ? text : control}} `, styles: [], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextComponent), multi: true, }] }) export class TextComponent implements OnInit, ControlValueAccessor { @HostBinding('class.f-component-text') cls = true; @ViewChild('textInner', { read: ElementRef }) textInnerEl: ElementRef; @Output() textChange = new EventEmitter(); /** 是否为密码输入 */ @Input() isPassword = false; // 是否多行文本 @Input() isTextArea = false; // 是否启用自动尺寸 @Input() autoSize = false; // 设置最大高度 @Input() maxHeight: number; // 设置高度 @Input() height = 0; // 控件类型 @Input() type: string; // 是否是日期范围 @Input() dateRange = false; // 需要转化类型格式的表达式 @Input() format: any; // 多语言 @Input() lang: string; // 转换类型用到的数据 @Input() data: any; // 千分位符号 @Input() thousand = ','; // 小数点处符号 @Input() decimal = '.'; // 货币符号及值展现形式 @Input() expression = '%s%v'; @Input() currentLanguage: string; // formControl显示的文本 @Input() showTime: boolean; @Input() textField = 'name'; @Input() valueField = 'value'; @Input() returnFormat = ''; // 从服务器端取值是格式化后的 // 文本方向 @Input() textAlign; // 日期范围模式下input的显示分割符合 @Input() dateRangeDelimiter = '~'; @Input() enumDelimiter = ','; private _tshowType = 0; @Input() set showType(value: number) { this._tshowType = value; // 如果是周 if (value == 4) { this.dateRange = true; } } get showType(): number { return this._tshowType; } /** * 国际化类型 */ @Input() localizationType: string; control: any; // 普通文本 text: any; // 货币符号,默认是RMB currencySymbol = '¥'; // 十进制前面填充的符号 @Input() filledSymbol = '0'; // 普通文本输入值 @Input() set value(value: any) { this.text = this.formatValue(value); this.textChange.emit(this.text); } get value() { return this.text; } @HostListener('mouseenter', ['$event']) changeTitle(ev) { if (!this.isTextArea && !this.isPassword) { this.mouseEnterChangeTitle(); } } // 标签 staticTitle = ""; // 处理中英文情况, 因为多语言暂时不通过这个属性控制 @Input() showTitle = false; //数值格式参数 _option; @Input() set option(value) { this._option = value; } get option() { return this._option; } private localeService: any; beforeWriteValue: (val: any, options: any) => string = null; private controlChange = (val) => { }; private controlTouch = (val) => { }; constructor( private dtHelper: DateTimeHelperService, private numberHelper: NumberHelperService, private injector: Injector, public ngzone: NgZone ) { this.localeService = this.injector.get(LocaleService); } ngOnInit() { } ngOnDestroy(): void { } ngAfterViewInit(): void { if (this.isTextArea) { const clsName = this.textInnerEl.nativeElement.parentElement.className; this.textInnerEl.nativeElement.parentElement.className = clsName + ' f-cmp-text-is-textarea'; } } private mouseEnterChangeTitle() { if (this.textInnerEl.nativeElement.scrollHeight > this.textInnerEl.nativeElement.clientHeight) { this.staticTitle = this.text && this.text.length > 0 ? this.text : this.control; } else { this.staticTitle = ''; } } /** * 处理多语言,待定 */ formatLang(value: any) { return value && value[this.currentLanguage] ? value[this.currentLanguage] : ''; } /** * C货币 * D十进制 * F浮点数 * N数字,带千分位 * P百分比 */ getFormatNumberValue(value: any) { if (!this.format && !this._option) { return value.toString(); } if (this._option && this._option.type && this._option.type == 'number') { if (this._option.formatter) { return this._option.formatter(value); } else { if (this._option.useThousands) { if (this._option.precision != undefined) { this.format = 'n' + this._option.precision; } else { this.format = 'n2'; } } else { if (this._option.precision != undefined) { this.format = 'f' + this._option.precision; } else { this.format = 'f2'; } } } } const firstLetter = this.currencyToUpperCase(this.format.substring(0, 1)); const precision = Number(this.format.substring(1)); let config = {}; let result: any; if (!/C|D|F|N|P/g.test(firstLetter)) { console.warn(`不支持format为 ${this.format} 类型的数字格式化`); return; } if (this.thousand) { Object.assign(config, { thousand: this.thousand }); } if (this.decimal) { Object.assign(config, { decimal: this.decimal }); } if (this.expression) { Object.assign(config, { format: this.expression }); } switch (firstLetter) { case 'C': Object.assign(config, { prefix: this.currencySymbol, precision }); result = this.numberHelper.formatMoney(value, config); break; case 'D': result = this.toDecimal(value, precision); break; case 'F': Object.assign(config, { prefix: '', thousand: '', precision }); result = this.numberHelper.formatMoney(value, config); break; case 'N': Object.assign(config, { prefix: '', precision }); result = this.numberHelper.formatMoney(value, config); break; case 'P': result = this.toPercent(value, precision); break; } return result; } /** * @param value 转换成十进制的数字 * @param precision 十进制数字的长度 */ toDecimal(value: any, precision: any) { if (value.toString().indexOf('.') > -1) { console.warn('十进制转换仅限整型类型'); return; } return (Array(precision).join(this.filledSymbol) + value).slice(-precision); } /** * @param value 转换成百分数的数字 * @param decimal 小数点保留几位 */ toPercent(value: any, precision: any) { return Number(value * 100).toFixed(Number(precision)) + '%'; } /** * 将货币符号首字母转换成大写 */ currencyToUpperCase(value: any) { return value.replace(/[a-z]+/g, (word: any) => { return word.toUpperCase(); }); } /** * 处理年,Y=>y, D=>d */ dateToUpperCase(value: any) { let newFormat: any; if (/Y/g.test(value) === true) { newFormat = value.replace(/Y/g, 'y'); } else { newFormat = value; } if (/D/g.test(newFormat) === true) { newFormat = newFormat.replace(/D/g, 'd'); } return newFormat; } /** * 枚举类型处理 */ getFormatEnumValue(value: any) { if (value == undefined || value === null || value === '') { return ''; } if (this.data && this.data.length) { // 可能存在多选枚举,作为分隔符 // let curVals = ('' + value).split(','); let curVals = ('' + value).split(this.enumDelimiter); let nameResult = []; for (let k = 0; k < curVals.length; k++) { let findObj = this.data.find(item => { return item[this.valueField] == curVals[k]; }); if (findObj) { nameResult.push(findObj[this.textField]); } else { nameResult.push(curVals[k]); } } if (nameResult.length > 0) { // return nameResult.join(','); return nameResult.join(this.enumDelimiter); } return ''; } else { return value; } } /** * boolean值处理 */ getFormatCheckBoxValue(value: boolean) { if (value === true) { return this.localeService.getValue('text.yes'); } else if (value === false || value == null || typeof value === 'undefined') { return this.localeService.getValue('text.no'); } else { return value; } } private timeFormatTo(value: any, fmt: string, hourSystem = 12) { } private makeFormater(fmt: string): string { return fmt; } /* * 日期格式化 */ dateformat(value) { let str; if (!this.format) { this.format = 'YYYY-MM-DD'; } // 当前值是已经格式化后的日期字符串 if (this.returnFormat && this.returnFormat != 'yyyy-MM-dd' && typeof value == 'string') { value = this.getDateFromFormatedString(value, this.returnFormat); } // if (this.format === 'hh:mm:ss' || this.format === 'HH:mm:ss') { // 格式化时间 临时处理 str = value; } else { // if (this.showTime && value instanceof String) { // str = value; // } else { // const formArr = this.format.split(' '); // if (this.showTime && formArr.length < 2) { // formArr.push('HH:mm:ss'); // this.format = formArr.join(' '); // } // // 格式化日期 // str = this.dtHelper.formatTo(value, this.dateToUpperCase(this.format)); // } str = this.dtHelper.formatTo(value, this.dateToUpperCase(this.format)); } return str; } private getDateFromFormatedString(dateString, format) { var result = { year: 0, month: 0, day: 0, hour: 0, minite: 0, second: 0 }; // 当然这里可以默认1970-1-1日 if (dateString) { format.replace(/y+|Y+|M+|d+|D+|h+|H+|m+|s+/g, function (m, a, b, c) {// 这里只做了年月日 加时分秒也是可以的 dateString.substring(a).replace(/\d+/, function (d) { c = parseInt(d, 10) }); if (/y+/i.test(m) && !result.year) result.year = c; if (/M+/.test(m) && !result.month) result.month = c; if (/d+/i.test(m) && !result.day) result.day = c; if (/h+/i.test(m) && !result.hour) result.hour = c; if (/m+/.test(m) && !result.minite) result.minite = c; if (/s+/.test(m) && !result.second) result.second = c; }); } var resultDate = new Date(result.year + '/' + result.month + '/' + result.day + ' ' + result.hour + ':' + result.minite + ':' + result.second); return resultDate; } /** * 格式化处理 */ formatValue(value: any) { let str: any; if (this.currentLanguage) { return this.formatLang(value); } // if (!value) { // return ''; // } if (this.type !== 'boolean' && (value == null || typeof value === 'undefined')) { return ''; } switch (this.type) { case 'string': str = value; break; case 'date': case 'datetime': // console.log(this.format); if (!this.dateRange) { // if (!this.format) { // this.format = 'YYYY-MM-DD'; // } // if (this.format === 'hh:mm:ss') { // // 格式化时间 临时处理 // str = value; // } else { // if (this.showTime) { // str = value; // } else { // // 格式化日期 // str = this.dtHelper.formatTo(value, this.dateToUpperCase(this.format)); // } // } str = this.dateformat(value); // console.log(str); } else { const dateValues = value.split(this.dateRangeDelimiter); let dataStr = []; if (dateValues && dateValues.length) { dateValues.forEach(date => { let val = this.dateformat(date); dataStr.push(val); }); } str = dataStr.join(this.dateRangeDelimiter); } break; // case 'dateTime': // str = this.timeFormatTo(value, this.makeFormater(this.format)); // break; case 'number': str = this.getFormatNumberValue(value); break; case 'enum': str = this.getFormatEnumValue(value); break; case 'boolean': str = this.getFormatCheckBoxValue(value); break; default: break; // throw new Error(`暂不支持 ${this.type} 类型`); } return str; } private setText2Star(value) { if (this.isPassword) { const star = value ? '******' : ''; this.text = star; this.control = star; return true; } return false; } writeValue(value: any): void { // lucas 2021-08-27 if (this.setText2Star(value)) { return; } // xia 2021-03-13 if (this.beforeWriteValue) { const options = { localizationType: this.localizationType, showTime: this.showTime, ref: this }; const text = this.beforeWriteValue(value, options); if (text !== undefined) { this.text = text; return; } } this.control = this.formatValue(value); this.controlChange(value); } registerOnChange(fn: () => {}): void { this.controlChange = fn; } registerOnTouched(fn): void { this.controlTouch = fn; } }