重构前端逻辑

This commit is contained in:
dengqichen 2025-11-11 11:19:38 +08:00
parent dc01b87943
commit f75a4b5f7e
6 changed files with 164 additions and 11 deletions

View File

@ -39,12 +39,16 @@ interface PendingApprovalModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
workflowDefinitionKeys?: string[]; // 工作流定义键列表
teamId?: number; // 团队ID用于筛选指定团队的审批任务
environmentId?: number; // 环境ID用于筛选指定环境的审批任务
}
export const PendingApprovalModal: React.FC<PendingApprovalModalProps> = ({
open,
onOpenChange,
workflowDefinitionKeys,
teamId,
environmentId,
}) => {
const { toast } = useToast();
const [loading, setLoading] = useState(false);
@ -61,7 +65,7 @@ export const PendingApprovalModal: React.FC<PendingApprovalModalProps> = ({
const loadApprovalList = async () => {
try {
setLoading(true);
const response = await getMyApprovalTasks(workflowDefinitionKeys);
const response = await getMyApprovalTasks(workflowDefinitionKeys, teamId, environmentId);
if (response) {
setApprovalList(response || []);
}

View File

@ -4,6 +4,8 @@ import type { DeployTeam } from '../types';
interface UsePendingApprovalOptions {
teams: DeployTeam[];
currentTeamId?: number | null; // 当前选中的团队ID
currentEnvId?: number | null; // 当前选中的环境ID
pollingEnabled?: boolean;
pollingInterval?: number; // 轮询间隔默认30秒
}
@ -12,9 +14,12 @@ interface UsePendingApprovalOptions {
* Hook
*
*
*
*/
export function usePendingApproval({
teams,
currentTeamId,
currentEnvId,
pollingEnabled = true,
pollingInterval = 30000 // 默认30秒
}: UsePendingApprovalOptions) {
@ -41,7 +46,12 @@ export function usePendingApproval({
}
try {
const response = await getMyApprovalTasks(workflowDefinitionKeys);
// 传递 teamId 和 environmentId 参数精确筛选
const response = await getMyApprovalTasks(
workflowDefinitionKeys,
currentTeamId || undefined,
currentEnvId || undefined
);
if (response) {
setPendingApprovalCount(response.length || 0);
}
@ -49,7 +59,7 @@ export function usePendingApproval({
// 静默失败,不影响主页面
console.error('Failed to load pending approval count:', error);
}
}, [workflowDefinitionKeys, pollingEnabled]);
}, [workflowDefinitionKeys, currentTeamId, currentEnvId, pollingEnabled]);
// 轮询待审批数量
useEffect(() => {

View File

@ -49,6 +49,8 @@ const Dashboard: React.FC = () => {
const approvalData = usePendingApproval({
teams: deploymentData.teams,
currentTeamId: deploymentData.currentTeamId,
currentEnvId: deploymentData.currentEnvId,
pollingEnabled: !deploymentData.loading
});
@ -60,6 +62,14 @@ const Dashboard: React.FC = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deploymentData.teams.length]);
// 监听团队/环境切换,自动刷新待审批数量
useEffect(() => {
if (deploymentData.currentTeamId && deploymentData.currentEnvId) {
approvalData.loadPendingApprovalCount();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deploymentData.currentTeamId, deploymentData.currentEnvId]);
// 计算当前环境是否应该显示待审批按钮
// 逻辑:当前环境需要审批 且 用户是该环境的审批人
const shouldShowApprovalButton = React.useMemo(() => {
@ -160,6 +170,8 @@ const Dashboard: React.FC = () => {
open={approvalData.approvalModalOpen}
onOpenChange={approvalData.setApprovalModalOpen}
workflowDefinitionKeys={approvalData.workflowDefinitionKeys}
teamId={deploymentData.currentTeamId || undefined}
environmentId={deploymentData.currentEnvId || undefined}
/>
</div>
);

View File

@ -26,11 +26,28 @@ export const getDeployRecordFlowGraph = (deployRecordId: number) =>
/**
*
* @param workflowDefinitionKeys
* @param teamId ID
* @param environmentId ID
*/
export const getMyApprovalTasks = (workflowDefinitionKeys?: string[]) => {
const params = workflowDefinitionKeys && workflowDefinitionKeys.length > 0
? { workflowDefinitionKeys: workflowDefinitionKeys.join(',') }
: {};
export const getMyApprovalTasks = (
workflowDefinitionKeys?: string[],
teamId?: number,
environmentId?: number
) => {
const params: Record<string, any> = {};
if (workflowDefinitionKeys && workflowDefinitionKeys.length > 0) {
params.workflowDefinitionKeys = workflowDefinitionKeys.join(',');
}
if (teamId !== undefined) {
params.teamId = teamId;
}
if (environmentId !== undefined) {
params.environmentId = environmentId;
}
return request.get<PendingApprovalTask[]>(`${DEPLOY_URL}/my-approval-tasks`, { params });
};

View File

@ -32,7 +32,7 @@ import {
createTeamApplication,
updateTeamApplication,
} from '../service';
import { getRepositoryBranches } from '@/pages/Resource/Git/List/service';
import { getRepositoryBranchesList } from '@/pages/Resource/Git/List/service';
import TeamApplicationDialog from './TeamApplicationDialog';
interface TeamApplicationManageDialogProps {
@ -167,12 +167,13 @@ export const TeamApplicationManageDialog: React.FC<
if (!app.repoProjectId || !app.externalSystemId) {
return [];
}
const result = await getRepositoryBranches({
// 使用不分页的列表接口
const result = await getRepositoryBranchesList({
externalSystemId: app.externalSystemId,
repoProjectId: app.repoProjectId,
});
// getRepositoryBranches 返回 Page 类型,需要提取 content
return Array.isArray(result) ? result : (result as any).content || [];
// getRepositoryBranchesList 直接返回数组,不需要提取 content
return Array.isArray(result) ? result : [];
};
const handleLoadJenkinsJobs = async (systemId: number) => {

View File

@ -0,0 +1,109 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { ShieldOff, LogOut, RefreshCw, Mail } from 'lucide-react';
import { logout } from '@/store/userSlice';
/**
*
*
*/
const NoPermission: React.FC = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const handleLogout = () => {
dispatch(logout());
navigate('/login', { replace: true });
};
const handleRefresh = () => {
window.location.reload();
};
return (
<div className="fixed inset-0 flex flex-col items-center justify-center bg-slate-50 p-8 overflow-hidden">
<div className="max-w-2xl text-center">
{/* 图标 */}
<div className="mb-6 flex justify-center">
<div className="rounded-full bg-blue-100 p-6">
<ShieldOff className="h-16 w-16 text-blue-600" />
</div>
</div>
{/* 标题 */}
<div className="mb-6">
<h1 className="text-3xl font-bold text-slate-800">
使Deploy Ease平台
</h1>
<h2 className="mt-3 text-xl font-medium text-slate-600">
</h2>
</div>
{/* 描述 */}
<div className="mb-8 space-y-3 text-slate-600">
<p className="text-base">
访
</p>
<p className="text-base">
使
</p>
</div>
{/* 信息卡片 */}
<div className="mb-8 rounded-lg bg-white border border-slate-200 p-6 text-left">
<h3 className="mb-3 text-sm font-semibold text-slate-800">
</h3>
<ul className="space-y-2 text-sm text-slate-600">
<li className="flex items-start gap-2">
<span className="mt-0.5 text-blue-600"></span>
<span></span>
</li>
<li className="flex items-start gap-2">
<span className="mt-0.5 text-blue-600"></span>
<span></span>
</li>
<li className="flex items-start gap-2">
<span className="mt-0.5 text-blue-600"></span>
<span>"刷新权限"</span>
</li>
</ul>
<div className="mt-4 pt-4 border-t border-slate-100 flex items-center gap-2 text-sm">
<Mail className="h-4 w-4 text-slate-400" />
<span className="text-slate-500">
<span className="font-medium text-slate-700"></span><span className="font-medium text-slate-700"></span>
</span>
</div>
</div>
{/* 操作按钮 */}
<div className="flex justify-center gap-4">
<button
onClick={handleRefresh}
className="inline-flex items-center gap-2 rounded-lg border border-slate-300 bg-white px-6 py-3 text-slate-700 transition-colors hover:bg-slate-50"
>
<RefreshCw className="h-5 w-5" />
</button>
<button
onClick={handleLogout}
className="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-6 py-3 text-white transition-colors hover:bg-blue-700"
>
<LogOut className="h-5 w-5" />
退
</button>
</div>
{/* 提示文本 */}
<p className="mt-6 text-xs text-slate-400">
</p>
</div>
</div>
);
};
export default NoPermission;