feat: redesign Feishu project console

This commit is contained in:
2026-07-13 16:52:45 +08:00
parent 82f57317df
commit 69837bd50c
34 changed files with 1738 additions and 978 deletions
+32 -2
View File
@@ -165,6 +165,7 @@ export async function renameProjectForActor(
});
await tx.auditEntry.create({
data: {
organizationId: project.organizationId,
projectId: project.id,
actorUserId: actor.userId,
action: "project.renamed",
@@ -243,6 +244,7 @@ export async function bindFeishuChatToProject(
const actor = await requireProjectManager(prisma, project.id, project.organizationId, input.actorFeishuOpenId);
await prisma.$transaction(async (tx) => {
await requireActiveOrganizationTx(tx, project.organizationId);
const defaultRole = await requireDefaultAgentRole(tx, project.organizationId);
const activeProjectBinding = await tx.projectGroupBinding.findFirst({
where: { projectId: project.id, archivedAt: null },
select: { chatId: true },
@@ -258,7 +260,13 @@ export async function bindFeishuChatToProject(
throw new Error(`Feishu chat ${chatId} is already bound to project ${activeChatBinding.projectId}`);
}
await tx.projectGroupBinding.create({
data: { projectId: project.id, chatId, createdByUserId: actor.userId },
data: {
organizationId: project.organizationId,
projectId: project.id,
chatId,
createdByUserId: actor.userId,
selectedAgentRoleId: defaultRole.id,
},
});
await replaceProjectGrant(tx, {
projectId: project.id,
@@ -390,8 +398,15 @@ async function createManagedProject(
createdByUserId: input.actorUserId,
});
if (input.chatId !== undefined) {
const defaultRole = await requireDefaultAgentRole(tx, organization.id);
await tx.projectGroupBinding.create({
data: { projectId: created.id, chatId: input.chatId, createdByUserId: input.actorUserId },
data: {
organizationId: organization.id,
projectId: created.id,
chatId: input.chatId,
createdByUserId: input.actorUserId,
selectedAgentRoleId: defaultRole.id,
},
});
await replaceProjectGrant(tx, {
projectId: created.id,
@@ -566,6 +581,21 @@ async function assertFolderInOrganization(
}
}
async function requireDefaultAgentRole(
tx: Prisma.TransactionClient,
organizationId: string,
): Promise<{ readonly id: string }> {
const roles = await tx.organizationAgentRole.findMany({
where: { organizationId, isDefault: true, disabledAt: null },
select: { id: true },
take: 2,
});
if (roles.length !== 1) {
throw new Error(`organization ${organizationId} must have exactly one active default Agent role`);
}
return roles[0]!;
}
async function requireActiveOrganization(prisma: PrismaClient, organizationId: string): Promise<void> {
const organization = await prisma.organization.findUnique({
where: { id: organizationId },