123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864 |
- import { Component, OnInit, signal, computed, Inject } from '@angular/core';
- import { CommonModule, NgIf, NgFor } from '@angular/common';
- import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
- import { MatButtonModule } from '@angular/material/button';
- import { MatInputModule } from '@angular/material/input';
- import { MatSelectModule } from '@angular/material/select';
- import { MatDatepickerModule } from '@angular/material/datepicker';
- import { MatNativeDateModule } from '@angular/material/core';
- import { MatDialogModule, MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
- import { MatTableModule } from '@angular/material/table';
- import { MatPaginatorModule } from '@angular/material/paginator';
- import { MatCheckboxModule } from '@angular/material/checkbox';
- import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
- import { MatIconModule } from '@angular/material/icon';
- import { MatTooltipModule } from '@angular/material/tooltip';
- import { MatTabsModule } from '@angular/material/tabs';
- import { MatChipsModule } from '@angular/material/chips';
- import { MatMenuModule } from '@angular/material/menu';
- import { MatCardModule } from '@angular/material/card';
- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
- import { Router } from '@angular/router';
- import { Employee, Department, Position, Contract, Certificate, EmployeeStatus } from '../../../models/hr.model';
- // 新增员工对话框组件
- @Component({
- selector: 'app-add-employee-dialog',
- standalone: true,
- imports: [
- CommonModule,
- NgFor,
- FormsModule,
- ReactiveFormsModule,
- MatButtonModule,
- MatInputModule,
- MatSelectModule,
- MatDatepickerModule,
- MatNativeDateModule,
- MatDialogModule,
- MatIconModule
- ],
- template: `
- <h2 mat-dialog-title>{{data.isEdit ? '编辑员工信息' : '新增员工'}}</h2>
- <mat-dialog-content>
- <form [formGroup]="employeeForm" class="employee-form">
- <div class="form-row">
- <mat-form-field appearance="outline">
- <mat-label>姓名</mat-label>
- <input matInput formControlName="name" required>
- <mat-error *ngIf="employeeForm.get('name')?.hasError('required')">姓名不能为空</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline">
- <mat-label>工号</mat-label>
- <input matInput formControlName="employeeId" required>
- <mat-error *ngIf="employeeForm.get('employeeId')?.hasError('required')">工号不能为空</mat-error>
- </mat-form-field>
- </div>
-
- <div class="form-row">
- <mat-form-field appearance="outline">
- <mat-label>部门</mat-label>
- <mat-select formControlName="department" required>
- <mat-option *ngFor="let dept of departments" [value]="dept.name">{{dept.name}}</mat-option>
- </mat-select>
- <mat-error *ngIf="employeeForm.get('department')?.hasError('required')">请选择部门</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline">
- <mat-label>职位</mat-label>
- <mat-select formControlName="position" required>
- <mat-option *ngFor="let pos of positions" [value]="pos.name">{{pos.name}}</mat-option>
- </mat-select>
- <mat-error *ngIf="employeeForm.get('position')?.hasError('required')">请选择职位</mat-error>
- </mat-form-field>
- </div>
-
- <div class="form-row">
- <mat-form-field appearance="outline">
- <mat-label>手机号码</mat-label>
- <input matInput formControlName="phone" required>
- <mat-error *ngIf="employeeForm.get('phone')?.hasError('required')">手机号码不能为空</mat-error>
- <mat-error *ngIf="employeeForm.get('phone')?.hasError('pattern')">请输入有效的手机号码</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline">
- <mat-label>邮箱</mat-label>
- <input matInput formControlName="email" required>
- <mat-error *ngIf="employeeForm.get('email')?.hasError('required')">邮箱不能为空</mat-error>
- <mat-error *ngIf="employeeForm.get('email')?.hasError('email')">请输入有效的邮箱地址</mat-error>
- </mat-form-field>
- </div>
-
- <div class="form-row">
- <mat-form-field appearance="outline">
- <mat-label>性别</mat-label>
- <mat-select formControlName="gender" required>
- <mat-option value="男">男</mat-option>
- <mat-option value="女">女</mat-option>
- </mat-select>
- <mat-error *ngIf="employeeForm.get('gender')?.hasError('required')">请选择性别</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline">
- <mat-label>出生日期</mat-label>
- <input matInput [matDatepicker]="birthDatePicker" formControlName="birthDate">
- <mat-datepicker-toggle matSuffix [for]="birthDatePicker"></mat-datepicker-toggle>
- <mat-datepicker #birthDatePicker></mat-datepicker>
- </mat-form-field>
- </div>
-
- <div class="form-row">
- <mat-form-field appearance="outline">
- <mat-label>入职日期</mat-label>
- <input matInput [matDatepicker]="hireDatePicker" formControlName="hireDate" required>
- <mat-datepicker-toggle matSuffix [for]="hireDatePicker"></mat-datepicker-toggle>
- <mat-datepicker #hireDatePicker></mat-datepicker>
- <mat-error *ngIf="employeeForm.get('hireDate')?.hasError('required')">入职日期不能为空</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline">
- <mat-label>员工状态</mat-label>
- <mat-select formControlName="status" required>
- <mat-option value="在职">在职</mat-option>
- <mat-option value="离职">离职</mat-option>
- <mat-option value="试用期">试用期</mat-option>
- </mat-select>
- <mat-error *ngIf="employeeForm.get('status')?.hasError('required')">请选择员工状态</mat-error>
- </mat-form-field>
- </div>
- </form>
- </mat-dialog-content>
- <mat-dialog-actions align="end">
- <button mat-button mat-dialog-close>取消</button>
- <button mat-raised-button color="primary" [disabled]="employeeForm.invalid" (click)="saveEmployee()">保存</button>
- </mat-dialog-actions>
- `,
- styles: [`
- .employee-form {
- display: flex;
- flex-direction: column;
- gap: 16px;
- padding: 8px;
- }
-
- .form-row {
- display: flex;
- gap: 16px;
-
- mat-form-field {
- flex: 1;
- }
- }
- `]
- })
- export class AddEmployeeDialog implements OnInit {
- employeeForm: FormGroup;
- departments: Department[] = [
- { id: '1', name: '设计部', employeeCount: 0 },
- { id: '2', name: '客服部', employeeCount: 0 },
- { id: '3', name: '技术部', employeeCount: 0 },
- { id: '4', name: '行政部', employeeCount: 0 }
- ];
-
- positions: Position[] = [
- { id: '1', name: '设计师', departmentId: '1', departmentName: '设计部', level: '中级' },
- { id: '2', name: '客服专员', departmentId: '2', departmentName: '客服部', level: '初级' },
- { id: '3', name: '技术组长', departmentId: '3', departmentName: '技术部', level: '高级' },
- { id: '4', name: '前端开发', departmentId: '3', departmentName: '技术部', level: '中级' },
- { id: '5', name: '行政专员', departmentId: '4', departmentName: '行政部', level: '初级' }
- ];
-
- constructor(
- private fb: FormBuilder,
- public dialogRef: MatDialogRef<AddEmployeeDialog>,
- @Inject(MAT_DIALOG_DATA) public data: {employee?: Employee, isEdit: boolean}
- ) {
- this.employeeForm = this.fb.group({
- name: ['', Validators.required],
- employeeId: ['', Validators.required],
- department: ['', Validators.required],
- position: ['', Validators.required],
- phone: ['', [Validators.required, Validators.pattern(/^1[3-9]\d{9}$/)]],
- email: ['', [Validators.required, Validators.email]],
- gender: ['', Validators.required],
- birthDate: [null],
- hireDate: [new Date(), Validators.required],
- status: ['试用期', Validators.required]
- });
-
- if (data.isEdit && data.employee) {
- this.employeeForm.patchValue(data.employee);
- }
- }
-
- ngOnInit() {}
-
- saveEmployee() {
- if (this.employeeForm.valid) {
- const employeeData = this.employeeForm.value;
- this.dialogRef.close(employeeData);
- }
- }
- }
- // 入职流程对话框组件
- @Component({
- selector: 'app-onboarding-dialog',
- standalone: true,
- imports: [
- CommonModule,
- NgFor,
- FormsModule,
- ReactiveFormsModule,
- MatButtonModule,
- MatInputModule,
- MatSelectModule,
- MatDatepickerModule,
- MatNativeDateModule,
- MatDialogModule,
- MatIconModule,
- MatCheckboxModule
- ],
- template: `
- <h2 mat-dialog-title>入职流程</h2>
- <mat-dialog-content>
- <div class="employee-info">
- <h3>员工信息</h3>
- <p><strong>姓名:</strong> {{data.employee.name}}</p>
- <p><strong>部门:</strong> {{data.employee.department}}</p>
- <p><strong>职位:</strong> {{data.employee.position}}</p>
- <p><strong>入职日期:</strong> {{data.employee.hireDate | date:'yyyy-MM-dd'}}</p>
- </div>
-
- <div class="onboarding-tasks">
- <h3>入职任务清单</h3>
- <div class="task-list">
- <div *ngFor="let task of onboardingTasks" class="task-item">
- <mat-checkbox [(ngModel)]="task.completed">{{task.name}}</mat-checkbox>
- <span class="task-assignee">负责人: {{task.assignee}}</span>
- </div>
- </div>
- </div>
- </mat-dialog-content>
- <mat-dialog-actions align="end">
- <button mat-button mat-dialog-close>关闭</button>
- <button mat-raised-button color="primary" (click)="saveOnboarding()">保存进度</button>
- </mat-dialog-actions>
- `,
- styles: [`
- .employee-info {
- margin-bottom: 24px;
- padding: 16px;
- background-color: #f5f5f5;
- border-radius: 4px;
-
- h3 {
- margin-top: 0;
- margin-bottom: 16px;
- color: #1a3a6e;
- }
-
- p {
- margin: 8px 0;
- }
- }
-
- .onboarding-tasks {
- h3 {
- margin-bottom: 16px;
- color: #1a3a6e;
- }
- }
-
- .task-list {
- display: flex;
- flex-direction: column;
- gap: 12px;
- }
-
- .task-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 8px 0;
- border-bottom: 1px solid #e0e0e0;
-
- &:last-child {
- border-bottom: none;
- }
-
- .task-assignee {
- color: #757575;
- font-size: 12px;
- }
- }
- `]
- })
- export class OnboardingDialog {
- onboardingTasks = [
- { name: '签署劳动合同', completed: false, assignee: '人事' },
- { name: '录入系统权限', completed: false, assignee: '技术支持' },
- { name: '领取办公用品', completed: false, assignee: '行政' },
- { name: '参加新员工培训', completed: false, assignee: '培训部' },
- { name: '技术组长审核岗位匹配度', completed: false, assignee: '技术组长' }
- ];
-
- constructor(
- public dialogRef: MatDialogRef<OnboardingDialog>,
- @Inject(MAT_DIALOG_DATA) public data: {employee: Employee}
- ) {}
-
- saveOnboarding() {
- this.dialogRef.close(this.onboardingTasks);
- }
- }
- // 离职流程对话框组件
- @Component({
- selector: 'app-offboarding-dialog',
- standalone: true,
- imports: [
- CommonModule,
- NgFor,
- FormsModule,
- ReactiveFormsModule,
- MatButtonModule,
- MatInputModule,
- MatSelectModule,
- MatDatepickerModule,
- MatNativeDateModule,
- MatDialogModule,
- MatIconModule,
- MatCheckboxModule
- ],
- template: `
- <h2 mat-dialog-title>离职流程</h2>
- <mat-dialog-content>
- <form [formGroup]="offboardingForm" class="offboarding-form">
- <div class="employee-info">
- <h3>员工信息</h3>
- <p><strong>姓名:</strong> {{data.employee.name}}</p>
- <p><strong>部门:</strong> {{data.employee.department}}</p>
- <p><strong>职位:</strong> {{data.employee.position}}</p>
- <p><strong>入职日期:</strong> {{data.employee.hireDate | date:'yyyy-MM-dd'}}</p>
- </div>
-
- <div class="offboarding-details">
- <h3>离职信息</h3>
-
- <mat-form-field appearance="outline" class="full-width">
- <mat-label>离职原因</mat-label>
- <mat-select formControlName="reason" required>
- <mat-option value="个人发展">个人发展</mat-option>
- <mat-option value="薪资问题">薪资问题</mat-option>
- <mat-option value="工作环境">工作环境</mat-option>
- <mat-option value="家庭原因">家庭原因</mat-option>
- <mat-option value="健康原因">健康原因</mat-option>
- <mat-option value="其他">其他</mat-option>
- </mat-select>
- <mat-error *ngIf="offboardingForm.get('reason')?.hasError('required')">请选择离职原因</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline" class="full-width">
- <mat-label>离职日期</mat-label>
- <input matInput [matDatepicker]="resignDatePicker" formControlName="resignDate" required>
- <mat-datepicker-toggle matSuffix [for]="resignDatePicker"></mat-datepicker-toggle>
- <mat-datepicker #resignDatePicker></mat-datepicker>
- <mat-error *ngIf="offboardingForm.get('resignDate')?.hasError('required')">离职日期不能为空</mat-error>
- </mat-form-field>
-
- <mat-form-field appearance="outline" class="full-width">
- <mat-label>工作交接要求</mat-label>
- <textarea matInput formControlName="handoverRequirements" rows="3"></textarea>
- </mat-form-field>
- </div>
-
- <div class="offboarding-tasks">
- <h3>离职任务清单</h3>
- <div class="task-list">
- <div *ngFor="let task of offboardingTasks" class="task-item">
- <mat-checkbox [(ngModel)]="task.completed" [ngModelOptions]="{standalone: true}">
- {{task.name}}
- </mat-checkbox>
- <span class="task-assignee">负责人: {{task.assignee}}</span>
- </div>
- </div>
- </div>
- </form>
- </mat-dialog-content>
- <mat-dialog-actions align="end">
- <button mat-button mat-dialog-close>取消</button>
- <button mat-raised-button color="primary" [disabled]="offboardingForm.invalid" (click)="saveOffboarding()">提交</button>
- </mat-dialog-actions>
- `,
- styles: [`
- .offboarding-form {
- display: flex;
- flex-direction: column;
- gap: 24px;
- }
-
- .employee-info {
- padding: 16px;
- background-color: #f5f5f5;
- border-radius: 4px;
-
- h3 {
- margin-top: 0;
- margin-bottom: 16px;
- color: #1a3a6e;
- }
-
- p {
- margin: 8px 0;
- }
- }
-
- .offboarding-details,
- .offboarding-tasks {
- h3 {
- margin-bottom: 16px;
- color: #1a3a6e;
- }
- }
-
- .full-width {
- width: 100%;
- }
-
- .task-list {
- display: flex;
- flex-direction: column;
- gap: 12px;
- }
-
- .task-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 8px 0;
- border-bottom: 1px solid #e0e0e0;
-
- &:last-child {
- border-bottom: none;
- }
-
- .task-assignee {
- color: #757575;
- font-size: 12px;
- }
- }
- `]
- })
- export class OffboardingDialog implements OnInit {
- offboardingForm: FormGroup;
- offboardingTasks = [
- { name: '项目交接', completed: false, assignee: '技术组长' },
- { name: '客户信息同步', completed: false, assignee: '客服主管' },
- { name: '薪资结算', completed: false, assignee: '财务' },
- { name: '归还办公设备', completed: false, assignee: '行政' },
- { name: '系统权限冻结', completed: false, assignee: '技术支持' }
- ];
-
- constructor(
- private fb: FormBuilder,
- public dialogRef: MatDialogRef<OffboardingDialog>,
- @Inject(MAT_DIALOG_DATA) public data: {employee: Employee}
- ) {
- this.offboardingForm = this.fb.group({
- reason: ['', Validators.required],
- resignDate: [new Date(), Validators.required],
- handoverRequirements: ['']
- });
- }
-
- ngOnInit() {}
-
- saveOffboarding() {
- if (this.offboardingForm.valid) {
- const offboardingData = {
- ...this.offboardingForm.value,
- tasks: this.offboardingTasks
- };
- this.dialogRef.close(offboardingData);
- }
- }
- }
- @Component({
- selector: 'app-employee-records',
- standalone: true,
- imports: [
- CommonModule,
- NgIf,
- NgFor,
- FormsModule,
- ReactiveFormsModule,
- MatButtonModule,
- MatInputModule,
- MatSelectModule,
- MatDatepickerModule,
- MatNativeDateModule,
- MatDialogModule,
- MatTableModule,
- MatPaginatorModule,
- MatCheckboxModule,
- MatSnackBarModule,
- MatIconModule,
- MatTooltipModule,
- MatTabsModule,
- MatChipsModule,
- MatMenuModule,
- MatCardModule,
- MatProgressSpinnerModule
- ],
- templateUrl: './employee-records.html',
- styleUrls: ['./employee-records.scss']
- })
- export class EmployeeRecords implements OnInit {
- // 员工数据
- employees = signal<Employee[]>([
- {
- id: '1',
- name: '张三',
- department: '设计部',
- position: '设计师',
- employeeId: 'DS001',
- phone: '13800138001',
- email: 'zhangsan@example.com',
- gender: '男',
- birthDate: new Date('1990-01-01'),
- hireDate: new Date('2022-01-15'),
- status: '在职',
- idCard: '110105199001011234',
- bankCard: '6222021234567890'
- },
- {
- id: '2',
- name: '李四',
- department: '客服部',
- position: '客服专员',
- employeeId: 'CS001',
- phone: '13800138002',
- email: 'lisi@example.com',
- gender: '女',
- birthDate: new Date('1992-05-20'),
- hireDate: new Date('2022-03-10'),
- status: '在职',
- idCard: '110105199205201256',
- bankCard: '6216619876543210'
- },
- {
- id: '3',
- name: '王五',
- department: '技术部',
- position: '前端开发',
- employeeId: 'FE001',
- phone: '13800138003',
- email: 'wangwu@example.com',
- gender: '男',
- birthDate: new Date('1988-11-15'),
- hireDate: new Date('2023-01-05'),
- status: '试用期',
- idCard: '110105198811151278',
- bankCard: '6225880011223344'
- },
- {
- id: '4',
- name: '赵六',
- department: '设计部',
- position: '高级设计师',
- employeeId: 'DS002',
- phone: '13800138004',
- email: 'zhaoliu@example.com',
- gender: '男',
- birthDate: new Date('1985-07-22'),
- hireDate: new Date('2021-06-18'),
- status: '在职',
- idCard: '110105198507221299',
- bankCard: '6217009988776655'
- },
- {
- id: '5',
- name: '钱七',
- department: '技术部',
- position: '技术组长',
- employeeId: 'TL001',
- phone: '13800138005',
- email: 'qianqi@example.com',
- gender: '男',
- birthDate: new Date('1983-03-30'),
- hireDate: new Date('2020-09-01'),
- status: '在职',
- idCard: '110105198303301233',
- bankCard: '6222035566778899'
- }
- ]);
-
- // 筛选条件
- filterName = signal('');
- filterDepartment = signal('');
- filterPosition = signal('');
- filterStatus = signal('');
-
- // 表格列定义
- displayedColumns = ['select', 'name', 'employeeId', 'department', 'position', 'phone', 'idCard', 'bankCard', 'hireDate', 'status', 'actions'];
-
- // 选中的员工
- selectedEmployees = signal<string[]>([]);
- // 展示敏感信息的行(按员工id)
- sensitiveExpandedIds = signal<string[]>([]);
-
- // 是否有任意行展开敏感信息
- isAnySensitiveExpanded = computed(() => this.sensitiveExpandedIds().length > 0);
- // 部门和职位数据
- departments = [
- { id: '1', name: '设计部', employeeCount: 25 },
- { id: '2', name: '客服部', employeeCount: 18 },
- { id: '3', name: '技术部', employeeCount: 30 },
- { id: '4', name: '行政部', employeeCount: 10 }
- ];
-
- positions = [
- { id: '1', name: '设计师', departmentId: '1', departmentName: '设计部', level: '中级' },
- { id: '2', name: '高级设计师', departmentId: '1', departmentName: '设计部', level: '高级' },
- { id: '3', name: '客服专员', departmentId: '2', departmentName: '客服部', level: '初级' },
- { id: '4', name: '客服主管', departmentId: '2', departmentName: '客服部', level: '高级' },
- { id: '5', name: '前端开发', departmentId: '3', departmentName: '技术部', level: '中级' },
- { id: '6', name: '技术组长', departmentId: '3', departmentName: '技术部', level: '高级' },
- { id: '7', name: '行政专员', departmentId: '4', departmentName: '行政部', level: '初级' }
- ];
-
- // 计算过滤后的员工列表
- filteredEmployees = computed(() => {
- return this.employees().filter(employee => {
- const nameMatch = this.filterName() === '' || employee.name.includes(this.filterName());
- const departmentMatch = this.filterDepartment() === '' || employee.department === this.filterDepartment();
- const positionMatch = this.filterPosition() === '' || employee.position === this.filterPosition();
- const statusMatch = this.filterStatus() === '' || employee.status === this.filterStatus();
-
- return nameMatch && departmentMatch && positionMatch && statusMatch;
- });
- });
-
- constructor(
- private dialog: MatDialog,
- private snackBar: MatSnackBar,
- private router: Router
- ) {}
-
- ngOnInit() {}
- // 掩码与格式化工具
- maskIdCard(id: string): string {
- if (!id) return '';
- if (id.length >= 18) return `${id.slice(0, 6)}********${id.slice(-4)}`;
- if (id.length > 6) return `${id.slice(0, 3)}****${id.slice(-2)}`;
- return id;
- }
- maskBankCard(card: string): string {
- if (!card) return '';
- const compact = card.replace(/\s+/g, '');
- if (compact.length <= 8) return compact;
- const first4 = compact.slice(0, 4);
- const last4 = compact.slice(-4);
- return `${first4} **** **** ${last4}`;
- }
- formatBankCard(card: string): string {
- if (!card) return '';
- return card.replace(/\s+/g, '').replace(/(\d{4})(?=\d)/g, '$1 ').trim();
- }
- isSensitiveExpanded(id: string): boolean {
- return this.sensitiveExpandedIds().includes(id);
- }
- toggleSensitive(id: string) {
- const list = this.sensitiveExpandedIds();
- if (list.includes(id)) {
- this.sensitiveExpandedIds.set(list.filter(x => x !== id));
- } else {
- this.sensitiveExpandedIds.set([...list, id]);
- }
- }
- // 打开新增员工对话框
- openAddEmployeeDialog() {
- const dialogRef = this.dialog.open(AddEmployeeDialog, {
- width: '700px',
- panelClass: 'hr-dialog',
- data: { isEdit: false }
- });
-
- dialogRef.afterClosed().subscribe(result => {
- if (result) {
- const newEmployee: Employee = {
- id: (this.employees().length + 1).toString(),
- ...result
- };
-
- this.employees.update(employees => [...employees, newEmployee]);
- this.showSnackBar('员工添加成功');
- }
- });
- }
-
- // 打开编辑员工对话框
- openEditEmployeeDialog(employee: Employee) {
- const dialogRef = this.dialog.open(AddEmployeeDialog, {
- width: '700px',
- panelClass: 'hr-dialog',
- data: { employee, isEdit: true }
- });
-
- dialogRef.afterClosed().subscribe(result => {
- if (result) {
- this.employees.update(employees =>
- employees.map(emp => emp.id === employee.id ? { ...emp, ...result } : emp)
- );
- this.showSnackBar('员工信息更新成功');
- }
- });
- }
-
- // 打开入职流程对话框
- openOnboardingDialog(employee: Employee) {
- const dialogRef = this.dialog.open(OnboardingDialog, {
- width: '600px',
- panelClass: 'hr-dialog',
- data: { employee }
- });
-
- dialogRef.afterClosed().subscribe(result => {
- if (result) {
- this.showSnackBar('入职流程更新成功');
- }
- });
- }
-
- // 打开离职流程对话框
- openOffboardingDialog(employee: Employee) {
- const dialogRef = this.dialog.open(OffboardingDialog, {
- width: '600px',
- panelClass: 'hr-dialog',
- data: { employee }
- });
-
- dialogRef.afterClosed().subscribe(result => {
- if (result) {
- // 更新员工状态为离职
- this.employees.update(employees =>
- employees.map(emp => emp.id === employee.id ? { ...emp, status: '离职' } : emp)
- );
- this.showSnackBar('离职流程已启动');
- }
- });
- }
-
- // 删除员工
- deleteEmployee(employee: Employee) {
- if (confirm(`确定要删除员工 ${employee.name} 吗?`)) {
- this.employees.update(employees =>
- employees.filter(emp => emp.id !== employee.id)
- );
- this.showSnackBar('员工已删除');
- }
- }
-
- // 批量删除员工
- batchDelete() {
- if (this.selectedEmployees().length === 0) {
- this.showSnackBar('请先选择要删除的员工');
- return;
- }
-
- if (confirm(`确定要删除选中的 ${this.selectedEmployees().length} 名员工吗?`)) {
- this.employees.update(employees =>
- employees.filter(emp => !this.selectedEmployees().includes(emp.id))
- );
- this.selectedEmployees.set([]);
- this.showSnackBar('批量删除成功');
- }
- }
-
- // 导出员工数据
- exportEmployees(type: string) {
- // 实际项目中这里会调用导出服务
- this.showSnackBar(`已导出${type}`);
- }
- // 快捷卡片查看详情
- openQuickAction(type: 'onboarding' | 'offboarding' | 'probation') {
- switch (type) {
- case 'onboarding':
- // 这里可以导航或弹窗,先给出提示
- this.showSnackBar('前往入职流程列表');
- break;
- case 'offboarding':
- this.showSnackBar('前往离职流程列表');
- break;
- case 'probation':
- this.showSnackBar('查看试用期即将到期员工');
- break;
- }
- }
- // 进入员工详情(根据角色跳转至相应详情页)
- goToDetails(employee: Employee) {
- // 目前仅实现设计师角色详情,后续可按职位扩展其它角色
- this.showSnackBar('该角色详情页正在建设中');
- }
-
- // 选择/取消选择单个员工
- toggleSelection(employeeId: string) {
- if (this.isSelected(employeeId)) {
- this.selectedEmployees.update(selected => selected.filter(id => id !== employeeId));
- } else {
- this.selectedEmployees.update(selected => [...selected, employeeId]);
- }
- }
-
- // 选择/取消选择所有员工
- toggleSelectAll(checked: boolean) {
- if (checked) {
- const allIds = this.filteredEmployees().map(emp => emp.id);
- this.selectedEmployees.set(allIds);
- } else {
- this.selectedEmployees.set([]);
- }
- }
-
- // 检查员工是否被选中
- isSelected(employeeId: string): boolean {
- return this.selectedEmployees().includes(employeeId);
- }
-
- // 检查是否所有员工都被选中
- isAllSelected(): boolean {
- return this.filteredEmployees().length > 0 &&
- this.filteredEmployees().every(emp => this.selectedEmployees().includes(emp.id));
- }
-
- // 显示提示消息
- showSnackBar(message: string) {
- this.snackBar.open(message, '关闭', {
- duration: 3000,
- horizontalPosition: 'center',
- verticalPosition: 'bottom',
- panelClass: ['success-snackbar']
- });
- }
-
- // 重置筛选条件
- resetFilters() {
- this.filterName.set('');
- this.filterDepartment.set('');
- this.filterPosition.set('');
- this.filterStatus.set('');
- }
- }
|