背景:A3 需把行业 / 客户 / 客户组 / 客户级字段立为资产根节点;用户确认两级行业树与混搭 UI(行业 B / 客户列表 A / 详情 A / 新建 B / 客户组 B / 字段 A)。 改动: - 新增 ADR-002,行业改为两级树,客户挂末级行业;同步 PRD / 技术架构 / 开发计划。 - 新增 client 模块:industries / customers / customer-groups / customer-fields 接口、真实 PrismaCustomerDirectory、客户状态机与客户转交、客户组数据范围解析、跨客户 404。 - 新增迁移与幂等种子(电商/金融两级行业、2 客户、1 客户组、4 条字段)。 - 前端新增行业/客户/客户组/字段审批页面与路由、导航更名(客户管理 / 行业管理 / 客户组),复用现有 token。 - 补充 shared 契约单测、client 集成用例、A3 浏览器 e2e。 影响面:client 模块与 client 表、shared 契约、web 路由/导航、ScopeContext 数据范围、OpenAPI 与种子;A1 客户转交占位由 client 实现替换。 回滚:回滚本提交;数据库保留新增表或按报告执行 down SQL;CUSTOMER_DIRECTORY 可切回空集实现。 验证:format:check / lint / typecheck / test 全绿(shared 131 / api 90 / web 125,共 346);test:int 5 文件 39 条;A3 e2e 1/1;build 8/8;真实浏览器六页验证通过。
96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
import {
|
|
type CreateIndustryInput,
|
|
createIndustryInputSchema,
|
|
type IndustryDetail,
|
|
type IndustryListQuery,
|
|
industryListQuerySchema,
|
|
type IndustryTreeItem,
|
|
type ListResponse,
|
|
Permission,
|
|
type SetIndustryStatusInput,
|
|
setIndustryStatusInputSchema,
|
|
type UpdateIndustryInput,
|
|
updateIndustryInputSchema,
|
|
} from '@lingxi/shared';
|
|
import {
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
HttpCode,
|
|
Inject,
|
|
Param,
|
|
Patch,
|
|
Post,
|
|
Query,
|
|
} from '@nestjs/common';
|
|
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
|
|
|
import { ZodValidationPipe } from '../../common/pipes/zod-validation.pipe';
|
|
import { Audit, RequirePermissions } from '../../common/security/decorators';
|
|
import { IndustriesService } from './industries.service';
|
|
|
|
@ApiTags('client-industries')
|
|
@ApiBearerAuth()
|
|
@Controller('industries')
|
|
export class IndustriesController {
|
|
constructor(@Inject(IndustriesService) private readonly industries: IndustriesService) {}
|
|
|
|
@Get()
|
|
@RequirePermissions(Permission.CUSTOMER_READ)
|
|
@ApiOperation({ summary: '两级行业树(一级 → 二级)' })
|
|
list(
|
|
@Query(new ZodValidationPipe(industryListQuerySchema)) query: IndustryListQuery,
|
|
): Promise<ListResponse<IndustryTreeItem>> {
|
|
return this.industries.list(query);
|
|
}
|
|
|
|
@Get(':id')
|
|
@RequirePermissions(Permission.CUSTOMER_READ)
|
|
@ApiOperation({ summary: '行业详情与引用(子行业 / 客户 / 资产)' })
|
|
detail(@Param('id') id: string): Promise<IndustryDetail> {
|
|
return this.industries.detail(id);
|
|
}
|
|
|
|
@Post()
|
|
@RequirePermissions(Permission.CUSTOMER_MANAGE)
|
|
@Audit('client.industry.create')
|
|
@ApiOperation({ summary: '新建一级 / 二级行业' })
|
|
create(
|
|
@Body(new ZodValidationPipe(createIndustryInputSchema)) input: CreateIndustryInput,
|
|
): Promise<IndustryDetail> {
|
|
return this.industries.create(input);
|
|
}
|
|
|
|
@Patch(':id')
|
|
@RequirePermissions(Permission.CUSTOMER_MANAGE)
|
|
@Audit('client.industry.update')
|
|
@ApiOperation({ summary: '更新行业名称 / 排序 / 备注(层级与上级不可变)' })
|
|
update(
|
|
@Param('id') id: string,
|
|
@Body(new ZodValidationPipe(updateIndustryInputSchema)) input: UpdateIndustryInput,
|
|
): Promise<IndustryDetail> {
|
|
return this.industries.update(id, input);
|
|
}
|
|
|
|
@Patch(':id/status')
|
|
@RequirePermissions(Permission.CUSTOMER_MANAGE)
|
|
@Audit('client.industry.status')
|
|
@ApiOperation({ summary: '停用 / 启用行业(有启用子行业时禁止停用)' })
|
|
setStatus(
|
|
@Param('id') id: string,
|
|
@Body(new ZodValidationPipe(setIndustryStatusInputSchema)) input: SetIndustryStatusInput,
|
|
): Promise<IndustryDetail> {
|
|
return this.industries.setStatus(id, input);
|
|
}
|
|
|
|
@Delete(':id')
|
|
@HttpCode(204)
|
|
@RequirePermissions(Permission.CUSTOMER_MANAGE)
|
|
@Audit('client.industry.delete')
|
|
@ApiOperation({ summary: '删除行业(仅无子行业 / 客户 / 资产时)' })
|
|
async remove(@Param('id') id: string): Promise<void> {
|
|
await this.industries.remove(id);
|
|
}
|
|
}
|