Skip to content

Commit 5e93cb1

Browse files
feat: company certification
# Conflicts: # packages/service/common/system/timerLock/constants.ts
1 parent 93e5655 commit 5e93cb1

63 files changed

Lines changed: 6590 additions & 146 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/global/common/error/code/team.ts

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EnterpriseAuthErrEnum } from '../../../support/user/team/enterpriseAuth/constant';
12
import { i18nT } from '../../i18n/utils';
23
import type { ErrType } from '../errorCode';
34
/* team: 500000 */
@@ -154,17 +155,76 @@ const teamErr = [
154155
{
155156
statusText: TeamErrEnum.sandboxNotSupport,
156157
message: i18nT('common:code_error.team_error.sandbox_not_support')
158+
},
159+
{
160+
statusText: EnterpriseAuthErrEnum.disabled,
161+
message: i18nT('common:enterprise_auth.error.disabled')
162+
},
163+
{
164+
statusText: EnterpriseAuthErrEnum.serviceNotConfigured,
165+
message: i18nT('common:enterprise_auth.error.service_not_configured')
166+
},
167+
{
168+
statusText: EnterpriseAuthErrEnum.noRemainingTimes,
169+
message: i18nT('common:enterprise_auth.error.no_remaining_times')
170+
},
171+
{
172+
statusText: EnterpriseAuthErrEnum.alreadyVerified,
173+
message: i18nT('common:enterprise_auth.error.already_verified')
174+
},
175+
{
176+
statusText: EnterpriseAuthErrEnum.enterpriseOccupied,
177+
message: i18nT('common:enterprise_auth.error.enterprise_occupied')
178+
},
179+
{
180+
statusText: EnterpriseAuthErrEnum.tooFrequent,
181+
message: i18nT('common:enterprise_auth.error.too_frequent')
182+
},
183+
{
184+
statusText: EnterpriseAuthErrEnum.serviceError,
185+
message: i18nT('common:enterprise_auth.error.service_error')
186+
},
187+
{
188+
statusText: EnterpriseAuthErrEnum.serviceTimeout,
189+
message: i18nT('common:enterprise_auth.error.service_timeout')
190+
},
191+
{
192+
statusText: EnterpriseAuthErrEnum.infoFailed,
193+
message: i18nT('common:enterprise_auth.error.info_failed')
194+
},
195+
{
196+
statusText: EnterpriseAuthErrEnum.taskNotFound,
197+
message: i18nT('common:enterprise_auth.error.task_not_found')
198+
},
199+
{
200+
statusText: EnterpriseAuthErrEnum.taskExpired,
201+
message: i18nT('common:enterprise_auth.error.task_expired')
202+
},
203+
{
204+
statusText: EnterpriseAuthErrEnum.amountError,
205+
message: i18nT('common:enterprise_auth.error.amount_error')
206+
},
207+
{
208+
statusText: EnterpriseAuthErrEnum.amountFailed,
209+
message: i18nT('common:enterprise_auth.error.amount_failed')
210+
},
211+
{
212+
statusText: EnterpriseAuthErrEnum.processing,
213+
message: i18nT('common:enterprise_auth.error.processing')
157214
}
158215
];
159216

160-
export default teamErr.reduce((acc, cur, index) => {
161-
return {
162-
...acc,
163-
[cur.statusText]: {
164-
code: 500000 + index,
165-
statusText: cur.statusText,
166-
message: cur.message,
167-
data: null
168-
}
169-
};
170-
}, {} as ErrType<`${TeamErrEnum}`>);
217+
export default teamErr.reduce(
218+
(acc, cur, index) => {
219+
return {
220+
...acc,
221+
[cur.statusText]: {
222+
code: 500000 + index,
223+
statusText: cur.statusText,
224+
message: cur.message,
225+
data: null
226+
}
227+
};
228+
},
229+
{} as ErrType<`${TeamErrEnum}` | `${EnterpriseAuthErrEnum}`>
230+
);

packages/global/common/system/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export type FastGPTFeConfigsType = {
6060
show_aiproxy?: boolean;
6161
show_coupon?: boolean;
6262
show_discount_coupon?: boolean;
63+
show_enterprise_auth?: boolean;
6364
showWecomConfig?: boolean;
6465

6566
show_dataset_feishu?: boolean;
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import z from 'zod';
2+
import { IntSchema } from '../../../../../common/zod';
3+
import {
4+
EnterpriseAuthAmountMaxErrorTimes,
5+
EnterpriseAuthMaxTimes,
6+
TeamEnterpriseAuthStatusEnum,
7+
TeamEnterpriseAuthTaskStatusEnum
8+
} from '../../../../../support/user/team/enterpriseAuth/constant';
9+
10+
/* ============================================================================
11+
* API: 获取企业认证状态
12+
* Route: GET /api/support/user/team/enterpriseAuth/status
13+
* Method: GET
14+
* Description: 获取当前团队企业认证入口开关、认证状态和可恢复任务信息
15+
* Tags: ['团队管理']
16+
* ============================================================================ */
17+
18+
export const EnterpriseAuthLightTaskSchema = z.object({
19+
taskId: z.string().meta({ description: '认证任务 ID' }),
20+
status: z.enum(TeamEnterpriseAuthTaskStatusEnum).meta({ description: '当前任务状态' }),
21+
amountErrorTimes: z.number().int().meta({
22+
description: '当前任务金额填写错误次数',
23+
example: 0
24+
}),
25+
expireAt: z.date().optional().meta({ description: '金额验证过期时间' })
26+
});
27+
28+
export const GetEnterpriseAuthStatusResponseSchema = z.object({
29+
enabled: z.boolean().meta({ description: '企业认证入口是否开启' }),
30+
status: z.enum(TeamEnterpriseAuthStatusEnum).optional().meta({ description: '团队认证状态' }),
31+
usedTimes: z
32+
.number()
33+
.int()
34+
.optional()
35+
.meta({ description: `已使用认证次数,最多 ${EnterpriseAuthMaxTimes} 次`, example: 0 }),
36+
canManage: z.boolean().optional().meta({ description: '当前成员是否可管理企业认证' }),
37+
verifiedEnterpriseName: z.string().optional().meta({ description: '认证通过企业名称' }),
38+
currentTask: EnterpriseAuthLightTaskSchema.optional().meta({
39+
description: '未完成认证任务;expireAt 仅金额验证阶段存在'
40+
}),
41+
lastErrorCode: z.string().optional().meta({ description: '最近一次失败错误码' }),
42+
lastErrorMessage: z.string().optional().meta({ description: '最近一次失败提示' })
43+
});
44+
export type GetEnterpriseAuthStatusResponseType = z.infer<
45+
typeof GetEnterpriseAuthStatusResponseSchema
46+
>;
47+
48+
/* ============================================================================
49+
* API: 获取当前企业认证任务详情
50+
* Route: GET /api/support/user/team/enterpriseAuth/currentTaskDetail
51+
* Method: GET
52+
* Description: 获取待金额验证任务的完整展示信息,不返回验证金额
53+
* Tags: ['团队管理']
54+
* ============================================================================ */
55+
56+
export const GetEnterpriseAuthCurrentTaskDetailResponseSchema = z.object({
57+
taskId: z.string().meta({ description: '认证任务 ID' }),
58+
status: z.enum(TeamEnterpriseAuthTaskStatusEnum).meta({ description: '当前任务状态' }),
59+
enterpriseName: z.string().meta({ description: '企业名称' }),
60+
unifiedCreditCode: z.string().meta({ description: '统一社会信用代码' }),
61+
legalPersonName: z.string().meta({ description: '法人姓名' }),
62+
bankName: z.string().meta({ description: '开户银行总行名称' }),
63+
bankAccount: z.string().meta({ description: '企业银行账号,仅此接口返回完整值' }),
64+
contactName: z.string().meta({ description: '联系人姓名' }),
65+
contactTitle: z.string().meta({ description: '联系人职位' }),
66+
contactPhone: z.string().meta({ description: '联系人手机号' }),
67+
demand: z.string().meta({ description: '需求描述' }),
68+
amountErrorTimes: z.number().int().meta({ description: '金额错误次数' }),
69+
expireAt: z.date().meta({ description: '金额验证过期时间' })
70+
});
71+
export type GetEnterpriseAuthCurrentTaskDetailResponseType = z.infer<
72+
typeof GetEnterpriseAuthCurrentTaskDetailResponseSchema
73+
>;
74+
75+
/* ============================================================================
76+
* API: 获取企业认证银行列表
77+
* Route: GET /api/support/user/team/enterpriseAuth/banks
78+
* Method: GET
79+
* Description: 从小额汇款服务获取银行编码到总行名称映射
80+
* Tags: ['团队管理']
81+
* ============================================================================ */
82+
83+
export const GetEnterpriseAuthBanksResponseSchema = z.record(z.string(), z.string()).meta({
84+
description: '银行编码到银行名称的映射'
85+
});
86+
export type GetEnterpriseAuthBanksResponseType = z.infer<
87+
typeof GetEnterpriseAuthBanksResponseSchema
88+
>;
89+
90+
const EnterpriseAuthRequiredStringSchema = z.string().trim().min(1);
91+
const BankAccountSchema = EnterpriseAuthRequiredStringSchema.transform((account) =>
92+
account.replace(/\s+/g, '')
93+
)
94+
.pipe(z.string().regex(/^\d{1,64}$/))
95+
.meta({
96+
description: '企业银行账号,仅支持 1-64 位数字,可输入空格分隔',
97+
example: '6222000000000000000'
98+
});
99+
const UnifiedCreditCodeSchema = EnterpriseAuthRequiredStringSchema.transform((code) =>
100+
code.toUpperCase()
101+
)
102+
.pipe(z.string().regex(/^[0-9A-HJ-NPQRTUWXY]{18}$/))
103+
.meta({
104+
description: '统一社会信用代码,18 位大写数字或字母(不包含 I/O/Z/S/V)',
105+
example: '91310000MA1K000000'
106+
});
107+
108+
export const StartEnterpriseAuthBodySchema = z.object({
109+
enterpriseName: EnterpriseAuthRequiredStringSchema.max(100).meta({
110+
description: '企业全称,需与银行开户名一致',
111+
example: '示例科技有限公司'
112+
}),
113+
unifiedCreditCode: UnifiedCreditCodeSchema,
114+
legalPersonName: EnterpriseAuthRequiredStringSchema.max(50).meta({
115+
description: '法人姓名',
116+
example: '张三'
117+
}),
118+
bankAccount: BankAccountSchema,
119+
bankName: EnterpriseAuthRequiredStringSchema.max(80).meta({
120+
description: '开户银行总行名称',
121+
example: '中国工商银行'
122+
}),
123+
contactName: EnterpriseAuthRequiredStringSchema.max(50).meta({
124+
description: '联系人姓名',
125+
example: '李四'
126+
}),
127+
contactTitle: EnterpriseAuthRequiredStringSchema.max(50).meta({
128+
description: '联系人职位',
129+
example: '产品负责人'
130+
}),
131+
contactPhone: EnterpriseAuthRequiredStringSchema.max(30).meta({
132+
description: '联系人手机号',
133+
example: '13800000000'
134+
}),
135+
demand: EnterpriseAuthRequiredStringSchema.max(500).meta({
136+
description: '使用需求描述',
137+
example: '希望了解企业知识库和工作流能力'
138+
})
139+
});
140+
export type StartEnterpriseAuthBodyType = z.infer<typeof StartEnterpriseAuthBodySchema>;
141+
142+
/* ============================================================================
143+
* API: 发起企业认证
144+
* Route: POST /api/support/user/team/enterpriseAuth/start
145+
* Method: POST
146+
* Description: 创建小额汇款认证任务,打款成功后返回待金额验证任务
147+
* Tags: ['团队管理']
148+
* ============================================================================ */
149+
150+
export const StartEnterpriseAuthResponseSchema = z.object({
151+
status: z.enum(TeamEnterpriseAuthStatusEnum).meta({ description: '团队认证状态' }),
152+
currentTask: EnterpriseAuthLightTaskSchema.optional().meta({
153+
description: '未完成认证任务;仅 pending_amount/amount_failed 可进入金额验证页'
154+
}),
155+
usedTimes: z
156+
.number()
157+
.int()
158+
.meta({ description: `已使用认证次数,最多 ${EnterpriseAuthMaxTimes} 次` }),
159+
message: z.string().optional().meta({ description: '流程提示' })
160+
});
161+
export type StartEnterpriseAuthResponseType = z.infer<typeof StartEnterpriseAuthResponseSchema>;
162+
163+
export const VerifyEnterpriseAuthAmountBodySchema = z.object({
164+
taskId: z.string().min(1).meta({ description: '认证任务 ID' }),
165+
amountFen: IntSchema.meta({
166+
description: '用户填写的到账金额,单位为分',
167+
example: 123
168+
})
169+
});
170+
export type VerifyEnterpriseAuthAmountBodyType = z.infer<
171+
typeof VerifyEnterpriseAuthAmountBodySchema
172+
>;
173+
174+
/* ============================================================================
175+
* API: 验证企业认证打款金额
176+
* Route: POST /api/support/user/team/enterpriseAuth/verifyAmount
177+
* Method: POST
178+
* Description: 校验到账金额并在成功后发放企业认证赠送权益
179+
* Tags: ['团队管理']
180+
* ============================================================================ */
181+
182+
export const VerifyEnterpriseAuthAmountResponseSchema = z.object({
183+
status: z.enum(TeamEnterpriseAuthStatusEnum).meta({ description: '团队认证状态' }),
184+
verifiedEnterpriseName: z.string().optional().meta({ description: '认证通过企业名称' }),
185+
grantExpiredAt: z.date().optional().meta({
186+
description: '认证赠送高级版权益到期时间;真实权益以套餐记录 advancedSub.expiredTime 为准'
187+
}),
188+
amountMaxErrorTimes: z.literal(EnterpriseAuthAmountMaxErrorTimes).meta({
189+
description: '金额最大错误次数'
190+
})
191+
});
192+
export type VerifyEnterpriseAuthAmountResponseType = z.infer<
193+
typeof VerifyEnterpriseAuthAmountResponseSchema
194+
>;
195+
196+
/* ============================================================================
197+
* API: 重置企业认证待金额验证任务
198+
* Route: POST /api/support/user/team/enterpriseAuth/reset
199+
* Method: POST
200+
* Description: 用户确认信息有误后取消当前待金额验证任务
201+
* Tags: ['团队管理']
202+
* ============================================================================ */
203+
204+
export const ResetEnterpriseAuthResponseSchema = z.undefined().meta({ description: '操作成功' });
205+
export type ResetEnterpriseAuthResponseType = z.infer<typeof ResetEnterpriseAuthResponseSchema>;

0 commit comments

Comments
 (0)