In Progress
As a 潜在客户(包括游客), I want 查看详细的信息化项目全过程咨询服务介绍并能够提交我的项目需求和联系方式(无需登录), so that 我能够了解公司提供的项目前期咨询、项目建议书编制、可行性研究、初步设计、深化审计、造价咨询和竣工资料等全流程服务能力,并能方便地获取专业咨询。
src/client/home/pages/DesignPlanningPage.tsxsrc/client/components/ui/ (使用shadcn/ui组件)src/client/home/routes.tsxsrc/server/modules/consultation/ (新建目录)src/server/api/consultation-requests/ (新建目录)当前页面包含以下主要部分:
// 客户需求实体字段设计(支持游客提交)
@Entity('consultation_requests')
export class ConsultationRequest {
@PrimaryGeneratedColumn({ unsigned: true })
id!: number;
@Column({ name: 'customer_name', type: 'varchar', length: 255 })
customerName!: string;
@Column({ name: 'company_name', type: 'varchar', length: 255, nullable: true })
companyName!: string | null;
@Column({ name: 'phone', type: 'varchar', length: 20 })
phone!: string;
@Column({ name: 'email', type: 'varchar', length: 255, nullable: true })
email!: string | null;
@Column({ name: 'project_type', type: 'varchar', length: 100 })
projectType!: string;
@Column({ name: 'project_description', type: 'text' })
projectDescription!: string;
@Column({ name: 'budget_range', type: 'varchar', length: 100, nullable: true })
budgetRange!: string | null;
@Column({ name: 'timeline', type: 'varchar', length: 100, nullable: true })
timeline!: string | null;
@Column({ name: 'status', type: 'varchar', length: 20, default: 'pending' })
status!: string;
@Column({ name: 'is_guest', type: 'tinyint', default: 0, comment: '是否为游客提交' })
isGuest!: number;
@Column({ name: 'ip_address', type: 'varchar', length: 45, nullable: true, comment: '提交IP地址' })
ipAddress!: string | null;
@Column({ name: 'user_agent', type: 'text', nullable: true, comment: '用户代理信息' })
userAgent!: string | null;
@CreateDateColumn({ name: 'created_at' })
createdAt!: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt!: Date;
}
// 客户需求提交DTO Schema(支持游客提交)
export const CreateConsultationRequestDto = z.object({
customerName: z.string().min(2, '姓名至少2个字符').max(255).openapi({
description: '客户姓名',
example: '张三'
}),
companyName: z.string().max(255).optional().openapi({
description: '公司名称',
example: 'ABC科技有限公司'
}),
phone: z.string().regex(/^1[3-9]\d{9}$/, '请输入正确的手机号').openapi({
description: '手机号',
example: '13800138000'
}),
email: z.string().email('请输入正确的邮箱地址').optional().openapi({
description: '邮箱地址',
example: 'zhangsan@example.com'
}),
projectType: z.string().min(1, '请选择项目类型').max(100).openapi({
description: '项目类型',
example: '企业ERP系统'
}),
projectDescription: z.string().min(10, '项目描述至少10个字符').max(2000).openapi({
description: '项目描述',
example: '我们需要开发一个企业ERP系统,包含财务、采购、销售等模块'
}),
budgetRange: z.string().max(100).optional().openapi({
description: '预算范围',
example: '10-50万'
}),
timeline: z.string().max(100).optional().openapi({
description: '项目时间要求',
example: '3-6个月'
}),
isGuest: z.boolean().default(true).openapi({
description: '是否为游客提交',
example: true
}),
captchaToken: z.string().optional().openapi({
description: '机器人验证token',
example: 'captcha_token_123'
})
});
src/client/home/pages/目录@/client/components/ui/src/server/modules/consultation/目录src/server/api/consultation-requests/目录// 公开客户需求提交API路由(无需认证)
const routeDef = createRoute({
method: 'post',
path: '/api/v1/public/consultation-requests',
// 注意:不使用authMiddleware,支持游客提交
request: {
body: {
content: {
'application/json': { schema: CreateConsultationRequestDto }
}
}
},
responses: {
200: {
description: '成功提交客户需求',
content: { 'application/json': { schema: ConsultationRequestSchema } }
},
400: {
description: '请求参数错误',
content: { 'application/json': { schema: ErrorSchema } }
},
500: {
description: '服务器错误',
content: { 'application/json': { schema: ErrorSchema } }
}
}
});
// 反垃圾邮件验证服务
export class SpamProtectionService {
async validateSubmission(requestData: CreateConsultationRequestDto, ipAddress: string): Promise<boolean> {
// 1. IP频率限制:同一IP24小时内最多提交5次
const recentSubmissions = await this.getRecentSubmissionsByIP(ipAddress);
if (recentSubmissions >= 5) {
throw new Error('提交频率过高,请稍后再试');
}
// 2. 内容重复检测:检查相似的项目描述
const similarRequests = await this.findSimilarRequests(requestData.projectDescription);
if (similarRequests.length > 0) {
throw new Error('检测到重复提交,请修改项目描述');
}
// 3. 机器人验证:验证captcha token
if (requestData.captchaToken) {
const isValid = await this.validateCaptcha(requestData.captchaToken);
if (!isValid) {
throw new Error('机器人验证失败');
}
}
return true;
}
// 支持多种验证方式:reCAPTCHA、hCaptcha、自定义验证等
private async validateCaptcha(token: string): Promise<boolean> {
// 实现具体的验证逻辑
return true;
}
}
src/client/home/pages/__tests__/DesignPlanningPage.test.tsx (前端页面测试)src/server/modules/consultation/__tests__/consultation-request.service.test.ts (后端服务测试)src/server/api/consultation-requests/__tests__/ (API路由测试)| Date | Version | Description | Author |
|---|---|---|---|
| 2025-09-25 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
| 2025-09-25 | 1.1 | 添加客户需求提交功能需求 | Bob (Scrum Master) |
| 2025-09-25 | 1.2 | 扩展支持游客提交需求功能 | Bob (Scrum Master) |
此部分由开发代理在实施过程中填写
Claude Code (d8d-model)
src/client/home/pages/DesignPlanningPage.tsx - 主要修改文件(已实现UI更新)src/client/components/ConsultationRequestForm.tsx - 客户需求表单组件(已实现)src/server/modules/consultation/consultation-request.entity.ts - 客户需求实体(已实现)src/server/modules/consultation/consultation-request.schema.ts - 客户需求Schema(已实现)src/server/modules/consultation/consultation-request.service.ts - 客户需求服务(已实现)src/server/modules/consultation/spam-protection.service.ts - 反垃圾邮件验证服务(已实现)src/server/api/consultation-requests/ - 客户需求API路由(已实现)src/server/api/public/consultation-requests/ - 公开客户需求API路由(已实现)src/client/api.ts - 添加了客户需求客户端API(已更新)src/server/api.ts - 注册了客户需求API路由(已更新)src/server/data-source.ts - 注册了客户需求实体(已更新)此部分由QA代理在质量检查后填写