import { Component, input, model, output, signal } from '@angular/core'; import { UiButton } from '../button/button'; /** * 上传头像:圆形头像预览 + 上传/删除(操作按钮复用 ui-button), * 读取本地文件为 dataURL;文件输入为浏览器原生能力,组件内部持有。 */ @Component({ selector: 'ui-upload-avatar', imports: [UiButton], templateUrl: './upload-avatar.html', styleUrl: './upload-avatar.scss', }) export class UiUploadAvatar { /** 头像地址(dataURL 或 URL,双向绑定) */ readonly src = model(''); /** 头像直径(px) */ readonly size = input(80); /** 是否圆形 */ readonly circle = input(true, { transform: (v: unknown) => v === true || v === 'true' }); /** 空态图标 */ readonly icon = input('fa-solid fa-camera'); /** 上传成功(拿到 dataURL)时触发 */ readonly change = output(); /** 校验通过后输出原始 File(供业务方走真实上传链路) */ readonly changeFile = output(); protected readonly uploading = signal(false); protected onPick(e: Event): void { const input = e.currentTarget as HTMLInputElement; const file = input.files?.[0]; input.value = ''; if (!file || !file.type.startsWith('image/')) return; this.uploading.set(true); this.changeFile.emit(file); const reader = new FileReader(); reader.onload = () => { this.uploading.set(false); if (typeof reader.result === 'string') { this.src.set(reader.result); this.change.emit(reader.result); } }; reader.onerror = () => this.uploading.set(false); reader.readAsDataURL(file); } protected remove(): void { this.src.set(''); } }