employee-records.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <div class="employee-records-container hr-page" [class.sensitive-expanded]="isAnySensitiveExpanded()">
  2. <!-- 页面标题和操作栏 -->
  3. <div class="page-header">
  4. <div class="title-section">
  5. <h1>员工档案管理</h1>
  6. <p class="subtitle">管理员工的基本信息、入职流程和离职流程</p>
  7. </div>
  8. <div class="action-buttons">
  9. <button mat-raised-button color="primary" (click)="openAddEmployeeDialog()">
  10. <mat-icon>add</mat-icon> 新增员工
  11. </button>
  12. <button mat-raised-button color="warn" [disabled]="selectedEmployees().length === 0" (click)="batchDelete()">
  13. <mat-icon>delete</mat-icon> 批量删除
  14. </button>
  15. <button mat-button [matMenuTriggerFor]="exportMenu">
  16. <mat-icon>file_download</mat-icon> 导出
  17. </button>
  18. <mat-menu #exportMenu="matMenu" class="hr-menu-panel">
  19. <button mat-menu-item (click)="exportEmployees('员工花名册')">员工花名册</button>
  20. <button mat-menu-item (click)="exportEmployees('部门人员清单')">部门人员清单</button>
  21. </mat-menu>
  22. </div>
  23. </div>
  24. <!-- 筛选条件 -->
  25. <mat-card class="filter-card">
  26. <mat-card-content>
  27. <div class="filter-form">
  28. <mat-form-field appearance="outline">
  29. <mat-label>姓名</mat-label>
  30. <input matInput [ngModel]="filterName()" (ngModelChange)="filterName.set($event)" placeholder="输入员工姓名">
  31. <button *ngIf="filterName()" matSuffix mat-icon-button (click)="filterName.set('')">
  32. <mat-icon>close</mat-icon>
  33. </button>
  34. </mat-form-field>
  35. <mat-form-field appearance="outline">
  36. <mat-label>部门</mat-label>
  37. <mat-select [panelClass]="'hr-select-panel'" [ngModel]="filterDepartment()" (ngModelChange)="filterDepartment.set($event)">
  38. <mat-option value="">全部</mat-option>
  39. <mat-option *ngFor="let dept of departments" [value]="dept.name">{{dept.name}}</mat-option>
  40. </mat-select>
  41. </mat-form-field>
  42. <mat-form-field appearance="outline">
  43. <mat-label>职位</mat-label>
  44. <mat-select [panelClass]="'hr-select-panel'" [ngModel]="filterPosition()" (ngModelChange)="filterPosition.set($event)">
  45. <mat-option value="">全部</mat-option>
  46. <mat-option *ngFor="let pos of positions" [value]="pos.name">{{pos.name}}</mat-option>
  47. </mat-select>
  48. </mat-form-field>
  49. <mat-form-field appearance="outline">
  50. <mat-label>状态</mat-label>
  51. <mat-select [panelClass]="'hr-select-panel'" [ngModel]="filterStatus()" (ngModelChange)="filterStatus.set($event)">
  52. <mat-option value="">全部</mat-option>
  53. <mat-option value="在职">在职</mat-option>
  54. <mat-option value="离职">离职</mat-option>
  55. <mat-option value="试用期">试用期</mat-option>
  56. </mat-select>
  57. </mat-form-field>
  58. <button mat-button color="primary" (click)="resetFilters()">
  59. <mat-icon>refresh</mat-icon> 重置
  60. </button>
  61. </div>
  62. </mat-card-content>
  63. </mat-card>
  64. <!-- 员工列表 -->
  65. <div class="employee-table-container">
  66. <table mat-table [dataSource]="filteredEmployees()" class="employee-table">
  67. <!-- 选择列 -->
  68. <ng-container matColumnDef="select">
  69. <th mat-header-cell *matHeaderCellDef>
  70. <mat-checkbox
  71. [checked]="isAllSelected()"
  72. [indeterminate]="selectedEmployees().length > 0 && !isAllSelected()"
  73. (change)="toggleSelectAll($event.checked)">
  74. </mat-checkbox>
  75. </th>
  76. <td mat-cell *matCellDef="let employee">
  77. <mat-checkbox
  78. [checked]="isSelected(employee.id)"
  79. (change)="toggleSelection(employee.id)">
  80. </mat-checkbox>
  81. </td>
  82. </ng-container>
  83. <!-- 姓名列 -->
  84. <ng-container matColumnDef="name">
  85. <th mat-header-cell *matHeaderCellDef>姓名</th>
  86. <td mat-cell *matCellDef="let employee">{{employee.name}}</td>
  87. </ng-container>
  88. <!-- 工号列 -->
  89. <ng-container matColumnDef="employeeId">
  90. <th mat-header-cell *matHeaderCellDef>工号</th>
  91. <td mat-cell *matCellDef="let employee">{{employee.employeeId}}</td>
  92. </ng-container>
  93. <!-- 部门列 -->
  94. <ng-container matColumnDef="department">
  95. <th mat-header-cell *matHeaderCellDef>部门</th>
  96. <td mat-cell *matCellDef="let employee">{{employee.department}}</td>
  97. </ng-container>
  98. <!-- 职位列 -->
  99. <ng-container matColumnDef="position">
  100. <th mat-header-cell *matHeaderCellDef>职位</th>
  101. <td mat-cell *matCellDef="let employee">{{employee.position}}</td>
  102. </ng-container>
  103. <!-- 手机号列 -->
  104. <ng-container matColumnDef="phone">
  105. <th mat-header-cell *matHeaderCellDef>手机号</th>
  106. <td mat-cell *matCellDef="let employee">{{employee.phone}}</td>
  107. </ng-container>
  108. <!-- 新增:身份证号列,仅在在职员工显示,初始脱敏 -->
  109. <ng-container matColumnDef="idCard">
  110. <th mat-header-cell *matHeaderCellDef>身份证号</th>
  111. <td mat-cell *matCellDef="let employee">
  112. @if (employee.status === '在职') {
  113. <span class="idcard" [class.expanded]="isSensitiveExpanded(employee.id)" [matTooltip]="employee.idCard || ''">
  114. {{ isSensitiveExpanded(employee.id) ? (employee.idCard || '') : maskIdCard(employee.idCard || '') }}
  115. </span>
  116. } @else {
  117. <span class="muted">-</span>
  118. }
  119. </td>
  120. </ng-container>
  121. <!-- 新增:银行卡号列,仅在在职员工显示,初始脱敏 -->
  122. <ng-container matColumnDef="bankCard">
  123. <th mat-header-cell *matHeaderCellDef>银行卡号</th>
  124. <td mat-cell *matCellDef="let employee">
  125. @if (employee.status === '在职') {
  126. <span class="bankcard" [class.expanded]="isSensitiveExpanded(employee.id)" [matTooltip]="formatBankCard(employee.bankCard || '')">
  127. {{ isSensitiveExpanded(employee.id) ? formatBankCard(employee.bankCard || '') : maskBankCard(employee.bankCard || '') }}
  128. </span>
  129. } @else {
  130. <span class="muted">-</span>
  131. }
  132. </td>
  133. </ng-container>
  134. <!-- 入职日期列 -->
  135. <ng-container matColumnDef="hireDate">
  136. <th mat-header-cell *matHeaderCellDef>入职日期</th>
  137. <td mat-cell *matCellDef="let employee">{{employee.hireDate | date:'yyyy-MM-dd'}}</td>
  138. </ng-container>
  139. <!-- 状态列 -->
  140. <ng-container matColumnDef="status">
  141. <th mat-header-cell *matHeaderCellDef>状态</th>
  142. <td mat-cell *matCellDef="let employee">
  143. <span class="status-badge" [ngClass]="{
  144. 'status-active': employee.status === '在职',
  145. 'status-probation': employee.status === '试用期',
  146. 'status-resigned': employee.status === '离职'
  147. }">{{employee.status}}</span>
  148. </td>
  149. </ng-container>
  150. <!-- 操作列:去掉“查看详情”按钮,改为眼睛图标控制敏感信息显示 -->
  151. <ng-container matColumnDef="actions">
  152. <th mat-header-cell *matHeaderCellDef>操作</th>
  153. <td mat-cell *matCellDef="let employee" class="actions-cell">
  154. <button mat-icon-button color="primary" (click)="toggleSensitive(employee.id)" [matTooltip]="isSensitiveExpanded(employee.id) ? '隐藏敏感信息' : '查看敏感信息'">
  155. <mat-icon>{{ isSensitiveExpanded(employee.id) ? 'visibility_off' : 'visibility' }}</mat-icon>
  156. </button>
  157. <button mat-icon-button class="more-actions-btn" [matMenuTriggerFor]="actionMenu" aria-label="操作菜单">
  158. <mat-icon>more_vert</mat-icon>
  159. </button>
  160. <mat-menu #actionMenu="matMenu" panelClass="hr-menu-panel">
  161. <button mat-menu-item (click)="openEditEmployeeDialog(employee)">
  162. <mat-icon>edit</mat-icon>
  163. <span>编辑</span>
  164. </button>
  165. <button mat-menu-item (click)="openOnboardingDialog(employee)" *ngIf="employee.status === '试用期'">
  166. <mat-icon>assignment</mat-icon>
  167. <span>入职流程</span>
  168. </button>
  169. <button mat-menu-item (click)="openOffboardingDialog(employee)" *ngIf="employee.status !== '离职'">
  170. <mat-icon>exit_to_app</mat-icon>
  171. <span>离职流程</span>
  172. </button>
  173. <button mat-menu-item (click)="deleteEmployee(employee)">
  174. <mat-icon>delete</mat-icon>
  175. <span>删除</span>
  176. </button>
  177. </mat-menu>
  178. </td>
  179. </ng-container>
  180. <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  181. <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  182. </table>
  183. <!-- 空状态提示 -->
  184. <div *ngIf="filteredEmployees().length === 0" class="empty-state">
  185. <mat-icon>person_off</mat-icon>
  186. <p>没有找到符合条件的员工记录</p>
  187. <button mat-raised-button color="primary" (click)="resetFilters()">重置筛选条件</button>
  188. </div>
  189. </div>
  190. <!-- 分页器 -->
  191. <mat-paginator [length]="totalLength()"
  192. [pageSize]="pageSize()"
  193. [pageIndex]="pageIndex()"
  194. [pageSizeOptions]="pageSizeOptions"
  195. (page)="onPageChange($event)"
  196. showFirstLastButtons>
  197. </mat-paginator>
  198. <!-- 快捷功能卡片 -->
  199. <div class="quick-actions">
  200. <mat-card class="quick-action-card">
  201. <mat-card-header>
  202. <mat-icon mat-card-avatar>assignment_ind</mat-icon>
  203. <mat-card-title>入职流程</mat-card-title>
  204. <mat-card-subtitle>新员工入职流程管理</mat-card-subtitle>
  205. </mat-card-header>
  206. <mat-card-content>
  207. <p>待处理入职流程: <span class="highlight-count">2</span></p>
  208. </mat-card-content>
  209. <mat-card-actions>
  210. <button mat-button color="primary" (click)="openQuickAction('onboarding')">查看详情</button>
  211. </mat-card-actions>
  212. </mat-card>
  213. <mat-card class="quick-action-card">
  214. <mat-card-header>
  215. <mat-icon mat-card-avatar>exit_to_app</mat-icon>
  216. <mat-card-title>离职流程</mat-card-title>
  217. <mat-card-subtitle>员工离职流程管理</mat-card-subtitle>
  218. </mat-card-header>
  219. <mat-card-content>
  220. <p>待处理离职流程: <span class="highlight-count">1</span></p>
  221. </mat-card-content>
  222. <mat-card-actions>
  223. <button mat-button color="primary" (click)="openQuickAction('offboarding')">查看详情</button>
  224. </mat-card-actions>
  225. </mat-card>
  226. <mat-card class="quick-action-card">
  227. <mat-card-header>
  228. <mat-icon mat-card-avatar>warning</mat-icon>
  229. <mat-card-title>试用期提醒</mat-card-title>
  230. <mat-card-subtitle>试用期即将到期员工</mat-card-subtitle>
  231. </mat-card-header>
  232. <mat-card-content>
  233. <p>即将到期员工: <span class="highlight-count">3</span></p>
  234. </mat-card-content>
  235. <mat-card-actions>
  236. <button mat-button color="primary" (click)="openQuickAction('probation')">查看详情</button>
  237. </mat-card-actions>
  238. </mat-card>
  239. </div>
  240. </div>