🧱 第9B讲:产品管理 (Angular)
发布: (2025年12月5日 GMT+8 13:54)
3 min read
原文: Dev.to
Source: Dev.to
介绍
本模块专注于构建完整的产品管理功能,包括全部的 CRUD 操作以及前端界面与后端 API 的无缝集成。它确保用户能够高效地创建、更新、查看和删除产品,同时在整个系统中保持流畅且响应迅速的体验。
管理员将能够:
- 管理产品
- 与您已经构建的后端 API 进行通信
涵盖的主题
- 授权守卫(Auth Guard)
- 产品的完整 CRUD 页面
- 产品服务(Product Service)
- 产品路由(Product Route)
- 更新应用路由(Update App Routes)
- 更新菜单(Update Menu)
授权守卫
路径: src/app/services/authguard/auth-guard.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { AuthApiService } from '../api/auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuardService {
constructor(
private authService: AuthApiService,
private router: Router
) {}
canActivate(): boolean {
const token = this.authService.getToken();
const refreshToken = this.authService.getRefreshToken();
// If no token and no refresh token, redirect to login
if (!token && !refreshToken) {
this.router.navigate(['/auth/login']);
return false;
}
// If no token but refresh token exists, try to refresh
if (!token && refreshToken) {
this.attemptTokenRefresh(refreshToken);
return false; // Wait for refresh attempt
}
// If token exists, user is authenticated
if (token) {
return true;
}
return false;
}
private attemptTokenRefresh(refreshToken: string): void {
this.authService.refresh({ token: '', refreshToken }).subscribe({
next: () => {
// Token refreshed successfully, reload current route
this.router.navigate([this.router.url]);
},
error: () => {
// Refresh failed, redirect to login
this.authService.logout();
this.router.navigate(['/auth/login']);
}
});
}
}
使用 PrimeNG 的 UI 页面
为产品功能创建以下三个文件:
src/app/features/products/product/product.htmlsrc/app/features/products/product/product.scss(空文件)src/app/features/products/product/product.ts
product.html
<div class="card">
<p-toolbar>
<ng-template pTemplate="left">
<button pButton label="Manage Products" class="p-button-success"></button>
</ng-template>
</p-toolbar>
<p-table #dt [value]="products" [paginator]="true" [rows]="10" responsiveLayout="scroll">
<ng-template pTemplate="header">
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>Stock</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-product>
<tr>
<td>{{ product.id }}</td>
<td>{{ product.name }}</td>
<td>{{ product.description }}</td>
<td>{{ product.price | currency: 'USD' }}</td>
<td>{{ product.stock }}</td>
</tr>
</ng-template>
</p-table>
<p-dialog header="Add Product" [(visible)]="displayDialog" [modal]="true" [responsive]="true">
<div class="p-fluid">
<div class="p-field">
<label for="name">Name</label>
<input id="name" type="text" pInputText [(ngModel)]="product.name" required />
<small class="p-error">Name is required.</small>
</div>
<div class="p-field">
<label for="description">Description</label>
<textarea id="description" pInputTextarea [(ngModel)]="product.description"></textarea>
</div>
<div class="p-field">
<label for="price">Price</label>
<input id="price" type="number" pInputText [(ngModel)]="product.price" />
</div>
<div class="p-field">
<label for="stock">Stock</label>
<input id="stock" type="number" pInputText [(ngModel)]="product.stock" />
</div>
</div>
</p-dialog>
</div>
product.scss
product.ts
import { Component, OnInit, signal, ViewChild } from '@angular/core';
import { ConfirmationService, MessageService } from 'primeng/api';
import { Table, TableModule } from 'primeng/table';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ButtonModule } from 'primeng/button';
import { RippleModule } from 'primeng/ripple';
import { ToastModule } from 'primeng/toast';
import { ToolbarModule } from 'primeng/toolbar';
import { RatingModule } from 'primeng/rating';
import { InputTextModule } from 'primeng/inputtext';
import { TextareaModule } from 'primeng/textarea';
import { SelectModule } from 'primeng/select';
import { Radi