303 lines
11 KiB
TypeScript
303 lines
11 KiB
TypeScript
import type { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
import { AppShell } from './AppShell';
|
|
import { UserProjectRightsModal } from '../user/UserProjectRightsModal';
|
|
import { UserSettingsModal } from '../user/UserSettingsModal';
|
|
import { DocVisibilityModal } from '../doc/DocVisibilityModal';
|
|
import { CreateProjectModal, type CreateProjectConfirmData } from '../project/CreateProjectModal';
|
|
import { ProjectMembersModal } from '../project/ProjectMembersModal';
|
|
import { ProjectSettingsModal } from '../project/ProjectSettingsModal';
|
|
import { FirstLoginPasswordModal } from '../auth/FirstLoginPasswordModal';
|
|
import { authClient } from '../../api/auth';
|
|
import type { LoginResult } from '../../types/auth';
|
|
import type { DocPermissionRole, UserProfile, UserRole } from '../../types/docgov';
|
|
import type { DocVisibilityRule, RoleDefinition } from '../../types/rbac';
|
|
import type { CreateProjectSubmitPhase } from '../../lib/createProjectSubmitGuard';
|
|
import type {
|
|
DeliverableCategory,
|
|
DeliverableItem,
|
|
ProjectInfo,
|
|
ProjectMember,
|
|
ProjectMemberRole,
|
|
ProjectSession,
|
|
} from '../../types/workbench';
|
|
|
|
export type WorkbenchWorkflowState = {
|
|
activeKey: string;
|
|
version: number;
|
|
creatorId: number;
|
|
lifecycleStatus: string;
|
|
};
|
|
|
|
export interface WorkbenchViewProps {
|
|
visibleSessions: ProjectSession[];
|
|
activeSessionId: string;
|
|
sessions: ProjectSession[];
|
|
deliverables: DeliverableItem[];
|
|
currentProjectId: number;
|
|
setActiveSessionId: (id: string) => void;
|
|
setActiveDocId: (id: string) => void;
|
|
setActiveCategory: (category: DeliverableCategory) => void;
|
|
setCreateProjectModalOpen: (open: boolean) => void;
|
|
canCreateProject: boolean;
|
|
currentUser: UserProfile;
|
|
currentDocRole: UserRole;
|
|
setRightsModalOpen: Dispatch<SetStateAction<boolean>>;
|
|
setUserSettingsOpen: Dispatch<SetStateAction<boolean>>;
|
|
setView: (view: 'workbench' | 'admin' | 'subagents') => void;
|
|
setProjectMembersModalOpen: Dispatch<SetStateAction<boolean>>;
|
|
currentWfState: WorkbenchWorkflowState;
|
|
workflowGovernanceEnabled: boolean;
|
|
setProjectSettingsOpen: Dispatch<SetStateAction<boolean>>;
|
|
setProjectWorkflowsState: Dispatch<SetStateAction<Record<number, WorkbenchWorkflowState>>>;
|
|
workflowBanner: ReactNode;
|
|
chatContent: ReactNode;
|
|
docContent: ReactNode;
|
|
rightsModalOpen: boolean;
|
|
visibleDeliverables: DeliverableItem[];
|
|
activeDocId: string;
|
|
canAssignLead: boolean;
|
|
handleSelectDoc: (id: string) => void;
|
|
handleRoleChangeForDoc: (docId: string, role: DocPermissionRole) => void | Promise<void>;
|
|
session: LoginResult | null;
|
|
setSession: Dispatch<SetStateAction<LoginResult | null>>;
|
|
handleLogout: () => void;
|
|
userSettingsOpen: boolean;
|
|
roles: RoleDefinition[];
|
|
setAllUsers: Dispatch<SetStateAction<UserProfile[]>>;
|
|
setCurrentUser: Dispatch<SetStateAction<UserProfile>>;
|
|
docVisibilityModalOpen: boolean;
|
|
setDocVisibilityModalOpen: Dispatch<SetStateAction<boolean>>;
|
|
targetDocForVisibility: DeliverableItem | null;
|
|
handleSaveDocVisibilityRule: (docId: string, rule: DocVisibilityRule | undefined) => void;
|
|
createProjectModalOpen: boolean;
|
|
createProjectSubmitting: boolean;
|
|
setCreateProjectError: Dispatch<SetStateAction<string | null>>;
|
|
handleCreateProjectConfirm: (data: CreateProjectConfirmData) => void | Promise<void>;
|
|
createProjectError: string | null;
|
|
createProjectSubmitPhase: CreateProjectSubmitPhase | null;
|
|
allUsers: UserProfile[];
|
|
projectMembersModalOpen: boolean;
|
|
currentProject: ProjectInfo | undefined;
|
|
canManageProjectMembers: boolean;
|
|
projectMembersError: string | null;
|
|
handleAddProjectMember: (member: Omit<ProjectMember, 'joinedAt' | 'status'>) => void | Promise<void>;
|
|
handleUpdateProjectMemberRole: (userId: number, role: ProjectMemberRole) => void | Promise<void>;
|
|
handleRemoveProjectMember: (userId: number) => void | Promise<void>;
|
|
handleRestoreProjectMember: (userId: number) => void | Promise<void>;
|
|
projectSettingsOpen: boolean;
|
|
currentActiveSession: ProjectSession | undefined;
|
|
}
|
|
|
|
export function WorkbenchView({
|
|
visibleSessions,
|
|
activeSessionId,
|
|
sessions,
|
|
deliverables,
|
|
currentProjectId,
|
|
setActiveSessionId,
|
|
setActiveDocId,
|
|
setActiveCategory,
|
|
setCreateProjectModalOpen,
|
|
canCreateProject,
|
|
currentUser,
|
|
currentDocRole,
|
|
setRightsModalOpen,
|
|
setUserSettingsOpen,
|
|
setView,
|
|
setProjectMembersModalOpen,
|
|
currentWfState,
|
|
workflowGovernanceEnabled,
|
|
setProjectSettingsOpen,
|
|
setProjectWorkflowsState,
|
|
workflowBanner,
|
|
chatContent,
|
|
docContent,
|
|
rightsModalOpen,
|
|
visibleDeliverables,
|
|
activeDocId,
|
|
canAssignLead,
|
|
handleSelectDoc,
|
|
handleRoleChangeForDoc,
|
|
session,
|
|
setSession,
|
|
handleLogout,
|
|
userSettingsOpen,
|
|
roles,
|
|
setAllUsers,
|
|
setCurrentUser,
|
|
docVisibilityModalOpen,
|
|
setDocVisibilityModalOpen,
|
|
targetDocForVisibility,
|
|
handleSaveDocVisibilityRule,
|
|
createProjectModalOpen,
|
|
createProjectSubmitting,
|
|
setCreateProjectError,
|
|
handleCreateProjectConfirm,
|
|
createProjectError,
|
|
createProjectSubmitPhase,
|
|
allUsers,
|
|
projectMembersModalOpen,
|
|
currentProject,
|
|
canManageProjectMembers,
|
|
projectMembersError,
|
|
handleAddProjectMember,
|
|
handleUpdateProjectMemberRole,
|
|
handleRemoveProjectMember,
|
|
handleRestoreProjectMember,
|
|
projectSettingsOpen,
|
|
currentActiveSession,
|
|
}: WorkbenchViewProps) {
|
|
return (
|
|
<>
|
|
<AppShell
|
|
sessions={visibleSessions}
|
|
activeSessionId={activeSessionId}
|
|
onSelectSession={(sessId) => {
|
|
if (window.location.hash) {
|
|
history.replaceState(null, '', window.location.pathname + window.location.search);
|
|
}
|
|
setActiveSessionId(sessId);
|
|
const targetSess = sessions.find((s) => s.sessionId === sessId);
|
|
if (targetSess && targetSess.projectId !== currentProjectId) {
|
|
const targetProjDocs = deliverables.filter((d) => d.projectId === targetSess.projectId);
|
|
if (targetProjDocs.length > 0) {
|
|
setActiveDocId(targetProjDocs[0].docId);
|
|
setActiveCategory(targetProjDocs[0].category);
|
|
}
|
|
}
|
|
}}
|
|
onNewSession={() => setCreateProjectModalOpen(true)}
|
|
canCreateProject={canCreateProject}
|
|
currentUser={currentUser}
|
|
currentRole={currentDocRole}
|
|
currentUserName={currentUser.name}
|
|
onChangeRole={(_, __) => {}}
|
|
onOpenRightsModal={() => setRightsModalOpen(true)}
|
|
onOpenUserSettings={() => setUserSettingsOpen(true)}
|
|
onOpenAdminSettings={() => setView('admin')}
|
|
onOpenProjectMembers={() => setProjectMembersModalOpen(true)}
|
|
activeWorkflowKey={currentWfState.activeKey}
|
|
workflowVersion={currentWfState.version}
|
|
lifecycleStatus={currentWfState.lifecycleStatus}
|
|
isCreator={currentWfState.creatorId === currentUser.id}
|
|
governanceEnabled={workflowGovernanceEnabled}
|
|
onOpenProjectSettings={() => setProjectSettingsOpen(true)}
|
|
onWorkflowChanged={(newKey, newVer) => {
|
|
setProjectWorkflowsState((prev) => ({
|
|
...prev,
|
|
[currentProjectId]: {
|
|
...currentWfState,
|
|
activeKey: newKey,
|
|
version: newVer,
|
|
lifecycleStatus: 'active',
|
|
},
|
|
}));
|
|
}}
|
|
workflowBanner={workflowBanner}
|
|
chatContent={chatContent}
|
|
docContent={docContent}
|
|
/>
|
|
<UserProjectRightsModal
|
|
isOpen={rightsModalOpen}
|
|
onClose={() => setRightsModalOpen(false)}
|
|
currentUser={currentUser}
|
|
currentProjectTitle={sessions.find((s) => s.sessionId === activeSessionId)?.title || '当前项目'}
|
|
deliverables={visibleDeliverables}
|
|
activeDocId={activeDocId}
|
|
canAssignLead={canAssignLead}
|
|
onSelectDoc={handleSelectDoc}
|
|
onRoleChangeForDoc={handleRoleChangeForDoc}
|
|
/>
|
|
<FirstLoginPasswordModal
|
|
isOpen={!!session?.mustChangePassword}
|
|
user={currentUser}
|
|
onPasswordChanged={() => {
|
|
if (!session) return;
|
|
const updated = {
|
|
...session,
|
|
mustChangePassword: false,
|
|
user: { ...session.user, mustChangePassword: false },
|
|
};
|
|
setSession(updated);
|
|
authClient.saveSession(updated);
|
|
}}
|
|
onLogout={handleLogout}
|
|
/>
|
|
<UserSettingsModal
|
|
isOpen={userSettingsOpen}
|
|
onClose={() => setUserSettingsOpen(false)}
|
|
currentUser={currentUser}
|
|
roles={roles}
|
|
onUpdateProfile={(updatedProfile) => {
|
|
setAllUsers((prev) =>
|
|
prev.map((u) => (u.id === currentUser.id ? { ...u, ...updatedProfile } : u))
|
|
);
|
|
setCurrentUser((prev) => ({ ...prev, ...updatedProfile }));
|
|
}}
|
|
onLogout={handleLogout}
|
|
/>
|
|
<DocVisibilityModal
|
|
isOpen={docVisibilityModalOpen}
|
|
onClose={() => setDocVisibilityModalOpen(false)}
|
|
doc={targetDocForVisibility}
|
|
roles={roles}
|
|
currentUserName={currentUser.name}
|
|
onSaveRule={handleSaveDocVisibilityRule}
|
|
/>
|
|
<CreateProjectModal
|
|
isOpen={createProjectModalOpen}
|
|
onClose={() => {
|
|
if (createProjectSubmitting) return;
|
|
setCreateProjectModalOpen(false);
|
|
setCreateProjectError(null);
|
|
}}
|
|
onSubmit={handleCreateProjectConfirm}
|
|
submitError={createProjectError}
|
|
submitting={createProjectSubmitting}
|
|
submitPhase={createProjectSubmitPhase}
|
|
currentUser={currentUser}
|
|
availableUsers={allUsers}
|
|
/>
|
|
<ProjectMembersModal
|
|
isOpen={projectMembersModalOpen}
|
|
onClose={() => setProjectMembersModalOpen(false)}
|
|
project={currentProject}
|
|
currentUser={currentUser}
|
|
availableUsers={allUsers}
|
|
canManage={canManageProjectMembers}
|
|
membersError={projectMembersError}
|
|
onAddMember={handleAddProjectMember}
|
|
onUpdateMemberRole={handleUpdateProjectMemberRole}
|
|
onRemoveMember={handleRemoveProjectMember}
|
|
onRestoreMember={handleRestoreProjectMember}
|
|
/>
|
|
<ProjectSettingsModal
|
|
open={projectSettingsOpen}
|
|
projectId={currentProjectId}
|
|
projectName={currentActiveSession?.title || '当前项目'}
|
|
canAssignLead={canAssignLead}
|
|
members={(currentProject?.members || [])
|
|
.filter((m) => m.status === 'active')
|
|
.map((m) => ({
|
|
userId: m.userId,
|
|
name:
|
|
allUsers.find((u) => u.id === m.userId)?.name ||
|
|
m.userName ||
|
|
`用户 ${m.userId}`,
|
|
}))}
|
|
onClose={() => setProjectSettingsOpen(false)}
|
|
onActivated={(activeKey) => {
|
|
setProjectWorkflowsState((prev) => ({
|
|
...prev,
|
|
[currentProjectId]: {
|
|
...currentWfState,
|
|
activeKey,
|
|
lifecycleStatus: 'active',
|
|
},
|
|
}));
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|