operations-user-detail.component.html 4.6 KB

123456789101112131415161718
  1. <header class="page-header"><div><a routerLink="/admin/users"><lucide-icon [img]="icons.ArrowLeft" [size]="17" />返回用户列表</a><p>USER PROFILE</p><h1>{{ user()?.displayName || '用户详情' }}</h1><span>只展示运营需要的资料、关系、课时和账号状态</span></div><button type="button" (click)="load()" [disabled]="loading()"><lucide-icon [img]="icons.RefreshCw" [size]="17" />刷新</button></header>
  2. @if (loading() && !user()) { <div class="state"><lucide-icon class="spin" [img]="icons.LoaderCircle" [size]="28" />正在加载用户资料…</div> }
  3. @else if (error() && !user()) { <div class="state error" role="alert">{{ error() }}</div> }
  4. @else {
  5. @if (user(); as detail) {
  6. <section class="profile-summary"><div class="avatar"><lucide-icon [img]="icons.UserRound" [size]="28" /></div><div><h2>{{ detail.displayName }}</h2><p>用户 ID {{ detail.userId || '—' }} · {{ detail.username }}</p></div><span class="status" [class.disabled]="detail.status === 'disabled'">{{ detail.statusLabel }}</span></section>
  7. @if (message()) { <p class="notice" role="status">{{ message() }}</p> } @if (error()) { <p class="notice error" role="alert">{{ error() }}</p> }
  8. <div class="detail-grid">
  9. <section class="panel"><header><h2>基本资料</h2><span>身份与联系信息</span></header><dl><div><dt>显示名称</dt><dd>{{ detail.displayName }}</dd></div><div><dt>手机号</dt><dd>{{ revealMobile() ? detail.mobile : detail.mobileMasked }} @if (!revealMobile() && detail.permissions.canRevealMobile) { <button class="text-button" type="button" (click)="reveal()"><lucide-icon [img]="icons.Eye" [size]="15" />查看完整号码</button> }</dd></div><div><dt>邮箱</dt><dd>{{ detail.email || '—' }}</dd></div><div><dt>注册时间</dt><dd>{{ detail.registeredAt | date:'yyyy-MM-dd HH:mm' }}</dd></div><div><dt>最后登录</dt><dd>{{ detail.lastLoginAt ? (detail.lastLoginAt | date:'yyyy-MM-dd HH:mm') : '—' }}</dd></div><div><dt>登录次数</dt><dd>{{ detail.loginCount }}</dd></div></dl></section>
  10. <section class="panel"><header><h2>课程与余额</h2><span>当前可用额度</span></header><div class="balance-grid"><article><strong>{{ detail.periods30 }}</strong><span>30 分钟课时</span></article><article><strong>{{ detail.periods60 }}</strong><span>60 分钟课时</span></article><article><strong>{{ detail.trialPeriods }}</strong><span>体验/扩展课时</span></article><article><strong>{{ detail.balances.userPoint }}</strong><span>用户积分</span></article></div></section>
  11. <section class="panel"><header><h2>组织关系</h2><span>用户组与所属代理</span></header><dl><div><dt>当前用户组</dt><dd>{{ detail.groupName || ('用户组 ' + detail.groupId) }}</dd></div><div><dt>所属代理</dt><dd>{{ detail.parentDisplayName || '未绑定' }}</dd></div></dl>@if (detail.permissions.canManage) { <div class="inline-form"><label>用户组 ID<input type="number" min="0" [ngModel]="groupId()" (ngModelChange)="groupId.set($event)" /></label><button type="button" (click)="changeGroup()" [disabled]="saving()">更新用户组</button><label>上级代理用户 ID<input type="number" min="0" [ngModel]="parentUserId()" (ngModelChange)="parentUserId.set($event)" /></label><button type="button" (click)="saveRelation()" [disabled]="saving()">保存代理关系</button></div> }</section>
  12. <section class="panel risk"><header><h2>账号与高风险操作</h2><span>所有操作都会写入审计日志</span></header>@if (detail.permissions.canManage) { <div class="risk-actions"><button type="button" (click)="changeStatus()" [disabled]="saving()"><lucide-icon [img]="icons.ShieldAlert" [size]="17" />{{ detail.status === 'disabled' ? '恢复账号' : '停用账号' }}</button></div> } @if (detail.permissions.canAdjustBalance) { <div class="balance-form"><label>调整项目<select [ngModel]="balanceType()" (ngModelChange)="balanceType.set($event)"><option [ngValue]="1">30 分钟课时</option><option [ngValue]="2">60 分钟课时</option><option [ngValue]="3">经验</option><option [ngValue]="4">积分</option></select></label><label>方向<select [ngModel]="balanceDirection()" (ngModelChange)="balanceDirection.set($event)"><option value="add">增加</option><option value="deduct">扣减</option></select></label><label>数量<input type="number" min="0.01" step="0.01" [ngModel]="balanceAmount()" (ngModelChange)="balanceAmount.set($event)" /></label><button type="button" (click)="adjustBalance()" [disabled]="saving()">确认调整</button></div> }<label class="reason">操作原因<textarea [ngModel]="reason()" (ngModelChange)="reason.set($event)" placeholder="必填:说明本次修改的业务原因"></textarea></label></section>
  13. </div>
  14. }
  15. }