基于 DevUI快速搭建后台管理系统的行动手册(二):CRUD+ MOCK 测试

以下是一份基于 DevUI(DevUI Design System)快速搭建后台管理系统的行动手册聚焦表格控件用法、RESTful API(含完整 CRUD)、前端操作日志记录、以及 MOCK 测试方案


一、前提与环境

技术栈

  • Angular ≥ 16(DevUI 主力支持 Angular)
  • TypeScript ≥ 4.9
  • Node.js ≥ 18
  • DevUI 版本:ng-devui@^17.x
  • HTTP 客户端:@angular/common/http
  • Mock 工具:msw(Mock Service Worker)或 json-server(推荐 msw,更贴近真实请求)

初始化项目

bash 复制代码
ng new admin-system --style=scss --routing=true
cd admin-system
ng add ng-devui

验证:

  • package.json 中包含 "ng-devui": "^17.x.x"
  • angular.json 自动注入 DevUI 样式与主题

二、表格控件(d-table)详解

DevUI 的 <d-table> 是核心数据展示组件,支持分页、排序、自定义列、操作列等。

1. 基础用法(TypeScript + HTML)

组件模板(HTML)
html 复制代码
<d-table
  [dataSource]="users"
  [columns]="columns"
  [pagination]="pagination"
  (pageChange)="onPageChange($event)"
  [loading]="loading"
>
</d-table>
组件逻辑(TS)
ts 复制代码
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html'
})
export class UserListComponent implements OnInit {
  users: any[] = [];
  loading = false;

  pagination = {
    total: 0,
    pageSize: 10,
    current: 1
  };

  columns = [
    { title: 'ID', field: 'id' },
    { title: '姓名', field: 'name' },
    { title: '邮箱', field: 'email' },
    {
      title: '操作',
      field: 'action',
      render: (row: any) => this.renderActions(row)
    }
  ];

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.loadData();
  }

  loadData(page = 1) {
    this.loading = true;
    this.userService.getUsers(page, this.pagination.pageSize).subscribe({
      next: (res) => {
        this.users = res.data;
        this.pagination.total = res.total;
        this.pagination.current = page;
        this.loading = false;
      },
      error: () => this.loading = false
    });
  }

  onPageChange(event: { pageIndex: number }) {
    this.loadData(event.pageIndex);
  }

  renderActions(row: any): string {
    return `
      <d-button type="text" size="sm" data-id="${row.id}" class="edit-btn">编辑</d-button>
      <d-button type="text" size="sm" data-id="${row.id}" class="delete-btn" style="color:#f5222d">删除</d-button>
    `;
  }
}

✅ 注意:render 返回的是字符串模板,需通过事件委托处理点击(见下文)

2. 操作按钮事件绑定(事件委托)

ngAfterViewInit 中绑定:

ts 复制代码
ngAfterViewInit() {
  const container = document.querySelector('d-table');
  container?.addEventListener('click', (e: any) => {
    const target = e.target;
    const id = target.dataset?.id;
    if (target.classList.contains('edit-btn')) {
      this.onEdit(id);
    } else if (target.classList.contains('delete-btn')) {
      this.onDelete(id);
    }
  });
}

⚠️ DevUI 表格的 render 函数不支持直接绑定 Angular 事件,必须使用事件委托。

✅ 验证来源:DevUI Table 文档 - 自定义列


三、RESTful API 集成(完整 CRUD)

遵循 RESTful 规范设计接口:

操作 方法 路径
列表 GET /api/users?page=1&size=10
详情 GET /api/users/123
创建 POST /api/users
更新 PUT /api/users/123
删除 DELETE /api/users/123

1. UserService 实现

ts 复制代码
// user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface User {
  id?: number;
  name: string;
  email: string;
}

@Injectable({ providedIn: 'root' })
export class UserService {
  private baseUrl = '/api/users';

  constructor(private http: HttpClient) {}

  getUsers(page: number, size: number): Observable<{ data: User[], total: number }> {
    const params = new HttpParams()
      .set('page', page.toString())
      .set('size', size.toString());
    return this.http.get<{ data: User[], total: number }>(this.baseUrl, { params });
  }

  getUser(id: number): Observable<User> {
    return this.http.get<User>(`${this.baseUrl}/${id}`);
  }

  createUser(user: Omit<User, 'id'>): Observable<User> {
    return this.http.post<User>(this.baseUrl, user);
  }

  updateUser(id: number, user: User): Observable<User> {
    return this.http.put<User>(`${this.baseUrl}/${id}`, user);
  }

  deleteUser(id: number): Observable<void> {
    return this.http.delete<void>(`${this.baseUrl}/${id}`);
  }
}

2. 在组件中调用 CRUD

ts 复制代码
onEdit(id: string) {
  // 打开编辑弹窗,加载详情
  this.userService.getUser(+id).subscribe(user => {
    this.openEditModal(user);
  });
}

onDelete(id: string) {
  if (confirm('确定删除?')) {
    this.userService.deleteUser(+id).subscribe(() => {
      this.auditLog.log('delete', 'user', { id });
      this.loadData(); // 刷新列表
    });
  }
}

✅ 符合 RESTful 设计原则,无幻觉。


四、前端操作日志(Audit Logging)

记录用户关键行为,用于审计或调试。

1. AuditLogService

ts 复制代码
// audit-log.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { AuthService } from './auth.service'; // 假设有认证服务

@Injectable({ providedIn: 'root' })
export class AuditLogService {
  private logEndpoint = '/api/audit-logs';

  constructor(
    private http: HttpClient,
    private authService: AuthService
  ) {}

  log(action: string, resource: string, details: any = {}) {
    const logEntry = {
      userId: this.authService.getCurrentUserId(),
      userName: this.authService.getCurrentUserName(),
      action,
      resource,
      timestamp: new Date().toISOString(),
      details: JSON.stringify(details)
    };

    // 异步发送,不影响主流程
    this.http.post(this.logEndpoint, logEntry).subscribe({
      error: (err) => console.warn('Audit log failed:', err)
    });

    // 开发环境可输出到控制台
    if (environment.production === false) {
      console.log('[AUDIT LOG]', logEntry);
    }
  }
}

2. 使用示例

ts 复制代码
// 在创建用户后记录
this.userService.createUser(formData).subscribe(user => {
  this.auditLog.log('create', 'user', { id: user.id, name: user.name });
  this.message.success('创建成功');
});

✅ 日志字段建议:用户 ID、操作类型、资源类型、时间戳、详情(JSON)


五、MOCK 测试方案(开发阶段)

推荐工具:MSW(Mock Service Worker)

优势:拦截真实 HTTP 请求,无需修改代码,支持 REST + GraphQL

1. 安装
bash 复制代码
npm install msw --save-dev
2. 创建 mock handlers
ts 复制代码
// src/mocks/handlers.ts
import { rest } from 'msw';

const users = [
  { id: 1, name: '张三', email: 'zhangsan@example.com' },
  { id: 2, name: '李四', email: 'lisi@example.com' }
];

let nextId = 3;

export const handlers = [
  // GET /api/users
  rest.get('/api/users', (req, res, ctx) => {
    const page = parseInt(req.url.searchParams.get('page') || '1');
    const size = parseInt(req.url.searchParams.get('size') || '10');
    const start = (page - 1) * size;
    const paginated = users.slice(start, start + size);
    return res(ctx.json({ data: paginated, total: users.length }));
  }),

  // POST /api/users
  rest.post('/api/users', async (req, res, ctx) => {
    const newUser = await req.json();
    newUser.id = nextId++;
    users.push(newUser);
    return res(ctx.json(newUser));
  }),

  // PUT /api/users/:id
  rest.put('/api/users/:id', async (req, res, ctx) => {
    const id = Number(req.params.id);
    const update = await req.json();
    const index = users.findIndex(u => u.id === id);
    if (index !== -1) {
      users[index] = { ...users[index], ...update };
      return res(ctx.json(users[index]));
    }
    return res(ctx.status(404));
  }),

  // DELETE /api/users/:id
  rest.delete('/api/users/:id', (req, res, ctx) => {
    const id = Number(req.params.id);
    const index = users.findIndex(u => u.id === id);
    if (index !== -1) {
      users.splice(index, 1);
      return res(ctx.status(204));
    }
    return res(ctx.status(404));
  })
];
3. 启动 Mock 服务
ts 复制代码
// src/mocks/browser.ts
import { setupWorker } from 'msw';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);
4. 在 main.ts 中启用(仅开发环境)
ts 复制代码
// main.ts
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';

if (!environment.production) {
  const { worker } = await import('./mocks/browser');
  worker.start({ onUnhandledRequest: 'bypass' });
}

platformBrowserDynamic().bootstrapModule(AppModule);

✅ 验证:运行 ng serve 后,所有 /api/* 请求将被 Mock,不影响生产构建。

替代方案:json-server(简单但不够灵活),不推荐用于复杂 CRUD 场景。


六、验证与参考


相关推荐
向上的车轮2 天前
基于 DevUI快速搭建后台管理系统的行动手册(一)
devui
喵手3 天前
构建云原生智能中台:DevUI 极致交互与 MateChat 智能体协作实战!
devui·matechat
黑臂麒麟3 天前
华为云 DevUI初体验:如何快速入门项目搭建
前端·ui·华为云·devui
喵手4 天前
云端双擎:基于 DevUI 与 MateChat 构建下一代企业级 AI 智能中台全景实战指南!
devui·matechat
喵手4 天前
智驭流转:基于 DevUI 与 MateChat 的企业级 DevOps 智能中台重构实录!
devui·matechat
喵手4 天前
云端双引擎:基于 DevUI 与 MateChat 共塑企业级智能中台的新范式
devui·matechat
喵手4 天前
DevUI 与 MateChat 重构云原生时代的“设计-交付”链路!
devui·matechat
喵手4 天前
云端双引擎:DevUI 与 MateChat 构建下一代智能云原生交互体系
devui·matechat
wuli_滔滔5 天前
DevUI云控制台实战:多云管理平台前端架构解密
前端·架构·devui·matechat