fix(frontend): 深度健康检查 - 清理死代码和修复合并冲突
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
Deploy / Deploy Staging (push) Has been cancelled
Deploy / Build Production Runtime Images (push) Has been cancelled
Deploy / Deploy Production (push) Has been cancelled
Deploy / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
Tests / lint (pull_request) Failing after 1924h56m40s
Tests / test (pull_request) Failing after 1924h56m42s

- 删除未使用的API模块: projects.ts, generation.ts, subscription.ts, projectTitles.ts
- 删除未使用的业务组件: InviteMemberModal.tsx, MemberList.tsx, PermissionMatrix.tsx
- 删除未引用的布局组件: Sidebar.tsx
- 删除未引用的状态管理: uiStore.ts
- 修复 business.css 中残留的git合并冲突标记
- 移除 business.css 中重复的注释行

所有删除的文件均经过引用检查,确认无任何页面/组件/hook引用
This commit is contained in:
CI Test
2026-06-28 10:34:00 +08:00
parent 9c287145a1
commit 5c46fe648d
10 changed files with 0 additions and 654 deletions
@@ -1,80 +0,0 @@
/**
* 邀请成员弹窗
*/
import React from 'react';
import { Modal, Form, Input, Select, message } from 'antd';
import { useInviteMember } from '@/hooks/useWorkspace';
interface InviteMemberModalProps {
workspaceId: string;
open: boolean;
onClose: () => void;
}
const InviteMemberModal: React.FC<InviteMemberModalProps> = ({
workspaceId,
open,
onClose,
}) => {
const [form] = Form.useForm();
const inviteMutation = useInviteMember(workspaceId);
const handleOk = async () => {
try {
const values = await form.validateFields();
await inviteMutation.mutateAsync(values);
message.success('邀请已发送!');
form.resetFields();
onClose();
} catch (error) {
// 验证失败或请求失败
}
};
const handleCancel = () => {
form.resetFields();
onClose();
};
return (
<Modal
title="邀请成员"
open={open}
onOk={handleOk}
onCancel={handleCancel}
confirmLoading={inviteMutation.isPending}
okText="发送邀请"
cancelText="取消"
>
<Form form={form} layout="vertical">
<Form.Item
name="email"
label="邮箱地址"
rules={[
{ required: true, message: '请输入邮箱地址' },
{ type: 'email', message: '请输入有效的邮箱地址' },
]}
>
<Input placeholder="member@example.com" />
</Form.Item>
<Form.Item
name="role"
label="角色"
initialValue="member"
rules={[{ required: true, message: '请选择角色' }]}
>
<Select
options={[
{ value: 'admin', label: '管理员 - 可以管理成员和项目' },
{ value: 'member', label: '成员 - 可以创建和管理项目' },
{ value: 'viewer', label: '访客 - 只读权限' },
]}
/>
</Form.Item>
</Form>
</Modal>
);
};
export default InviteMemberModal;
@@ -1,129 +0,0 @@
/**
* 成员列表组件
*/
import React from 'react';
import { Table, Button, Tag, Space, Popconfirm, message, Select } from 'antd';
import { DeleteOutlined } from '@ant-design/icons';
import { useWorkspaceMembers } from '@/hooks/useWorkspace';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { removeMember, updateMemberRole } from '@/api/workspace';
interface MemberListProps {
workspaceId: string;
}
const MemberList: React.FC<MemberListProps> = ({ workspaceId }) => {
const { data: members, isLoading } = useWorkspaceMembers(workspaceId);
const queryClient = useQueryClient();
const removeMutation = useMutation({
mutationFn: (memberId: string) => removeMember(workspaceId, memberId),
onSuccess: () => {
message.success('成员已移除');
queryClient.invalidateQueries({ queryKey: ['workspaceMembers', workspaceId] });
},
});
const updateRoleMutation = useMutation({
mutationFn: ({ memberId, role }: { memberId: string; role: string }) =>
updateMemberRole(workspaceId, memberId, role as any),
onSuccess: () => {
message.success('角色已更新');
queryClient.invalidateQueries({ queryKey: ['workspaceMembers', workspaceId] });
},
});
const getRoleTag = (role: string) => {
const roleConfig: Record<string, { color: string; text: string }> = {
owner: { color: 'gold', text: '拥有者' },
admin: { color: 'blue', text: '管理员' },
member: { color: 'green', text: '成员' },
viewer: { color: 'default', text: '访客' },
};
const config = roleConfig[role] || roleConfig.member;
return <Tag color={config.color}>{config.text}</Tag>;
};
const columns = [
{
title: '用户名',
dataIndex: 'username',
key: 'username',
},
{
title: '邮箱',
dataIndex: 'email',
key: 'email',
},
{
title: '角色',
dataIndex: 'role',
key: 'role',
render: (role: string, record: any) => {
if (role === 'owner') {
return getRoleTag(role);
}
return (
<Select
value={role}
style={{ width: 120 }}
onChange={(newRole) =>
updateRoleMutation.mutate({ memberId: record.id, role: newRole })
}
options={[
{ value: 'admin', label: '管理员' },
{ value: 'member', label: '成员' },
{ value: 'viewer', label: '访客' },
]}
/>
);
},
},
{
title: '加入时间',
dataIndex: 'joined_at',
key: 'joined_at',
render: (date: string) => new Date(date).toLocaleDateString(),
},
{
title: '操作',
key: 'action',
render: (_: any, record: any) => {
if (record.role === 'owner') {
return <span style={{ color: '#999' }}>-</span>;
}
return (
<Space>
<Popconfirm
title="确定移除该成员?"
onConfirm={() => removeMutation.mutate(record.id)}
okText="确定"
cancelText="取消"
>
<Button
type="text"
danger
icon={<DeleteOutlined />}
loading={removeMutation.isPending}
>
移除
</Button>
</Popconfirm>
</Space>
);
},
},
];
return (
<Table
columns={columns}
dataSource={members}
loading={isLoading}
rowKey="id"
pagination={{ pageSize: 10 }}
/>
);
};
export default MemberList;
@@ -1,100 +0,0 @@
/**
* 权限矩阵展示组件 - V21 UI
*/
import React from 'react';
import { Card, Table } from 'antd';
import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
import './business.css';
const PermissionMatrix: React.FC = () => {
const permissions = [
{ action: '查看工作空间', owner: true, admin: true, member: true, viewer: true },
{ action: '创建项目', owner: true, admin: true, member: true, viewer: false },
{ action: '编辑项目', owner: true, admin: true, member: true, viewer: false },
{ action: '删除项目', owner: true, admin: true, member: false, viewer: false },
{ action: '邀请成员', owner: true, admin: true, member: false, viewer: false },
{ action: '移除成员', owner: true, admin: true, member: false, viewer: false },
{ action: '修改成员角色', owner: true, admin: true, member: false, viewer: false },
{ action: '升级订阅', owner: true, admin: false, member: false, viewer: false },
{ action: '删除工作空间', owner: true, admin: false, member: false, viewer: false },
];
const columns = [
{
title: '操作',
dataIndex: 'action',
key: 'action',
fixed: 'left' as const,
width: 160,
render: (text: string) => <span style={{ fontWeight: 500 }}>{text}</span>,
},
{
title: '拥有者',
dataIndex: 'owner',
key: 'owner',
align: 'center' as const,
width: 100,
render: (value: boolean) =>
value ? (
<CheckOutlined style={{ color: '#16a34a', fontSize: '18px' }} />
) : (
<CloseOutlined style={{ color: '#dc2626', fontSize: '16px' }} />
),
},
{
title: '管理员',
dataIndex: 'admin',
key: 'admin',
align: 'center' as const,
width: 100,
render: (value: boolean) =>
value ? (
<CheckOutlined style={{ color: '#16a34a', fontSize: '18px' }} />
) : (
<CloseOutlined style={{ color: '#dc2626', fontSize: '16px' }} />
),
},
{
title: '成员',
dataIndex: 'member',
key: 'member',
align: 'center' as const,
width: 100,
render: (value: boolean) =>
value ? (
<CheckOutlined style={{ color: '#16a34a', fontSize: '18px' }} />
) : (
<CloseOutlined style={{ color: '#dc2626', fontSize: '16px' }} />
),
},
{
title: '访客',
dataIndex: 'viewer',
key: 'viewer',
align: 'center' as const,
width: 100,
render: (value: boolean) =>
value ? (
<CheckOutlined style={{ color: '#16a34a', fontSize: '18px' }} />
) : (
<CloseOutlined style={{ color: '#dc2626', fontSize: '16px' }} />
),
},
];
return (
<Card title="权限说明" className="xx-card">
<div className="xx-table-wrapper">
<Table
columns={columns}
dataSource={permissions}
pagination={false}
rowKey="action"
size="middle"
/>
</div>
</Card>
);
};
export default PermissionMatrix;
@@ -89,7 +89,6 @@
overflow: hidden;
}
<<<<<<< HEAD
/* 表格包装器 */
.xx-table-wrapper {
border-radius: 16px;
@@ -223,7 +222,6 @@
box-shadow: 0 8px 24px rgba(79,70,229,0.1);
}
<<<<<<< HEAD
/* ==================== 进度条 ==================== */
.xx-progress {
margin-top: 12px;
@@ -231,7 +229,6 @@
/* ==================== Ant Design 覆盖样式 ==================== */
/* Table overrides */
/* ==================== Ant Design 覆盖样式 ==================== */
.ant-table-wrapper .ant-table-thead > tr > th {
background: #f8fafc !important;
font-weight: 700 !important;
@@ -249,7 +246,6 @@
background: #fafbfc !important;
}
<<<<<<< HEAD
/* Card overrides */
.ant-card {
border-radius: 22px !important;
@@ -272,7 +268,6 @@
padding: 20px 24px !important;
}
<<<<<<< HEAD
/* Modal overrides */
.ant-modal-content {
border-radius: 22px !important;
@@ -298,7 +293,6 @@
padding: 16px 24px !important;
}
<<<<<<< HEAD
/* Button overrides */
.ant-btn-primary {
background: linear-gradient(135deg, #6366f1, #4f46e5) !important;
@@ -316,7 +310,6 @@
transform: translateY(-1px);
}
<<<<<<< HEAD
/* Tag overrides */
.ant-tag {
border-radius: 10px !important;
@@ -324,7 +317,6 @@
font-weight: 500 !important;
}
<<<<<<< HEAD
/* Select overrides */
.ant-select-selector {
border-radius: 14px !important;
@@ -340,7 +332,6 @@
box-shadow: 0 0 0 3px rgba(79,70,229,0.1) !important;
}
<<<<<<< HEAD
/* Input overrides */
.ant-input {
border-radius: 14px !important;
@@ -357,7 +348,6 @@
box-shadow: 0 0 0 3px rgba(79,70,229,0.1) !important;
}
<<<<<<< HEAD
/* Progress overrides */
.ant-progress-inner {
background: #f1f5f9 !important;
-107
View File
@@ -1,107 +0,0 @@
/**
* 侧边栏导航
*/
import React from 'react';
import { Layout, Menu } from 'antd';
import {
HomeOutlined,
AppstoreOutlined,
TeamOutlined,
CrownOutlined,
UserOutlined,
DashboardOutlined,
} from '@ant-design/icons';
import { useNavigate, useLocation } from 'react-router-dom';
import type { MenuProps } from 'antd';
const { Sider } = Layout;
interface SidebarProps {
collapsed: boolean;
}
const Sidebar: React.FC<SidebarProps> = ({ collapsed }) => {
const navigate = useNavigate();
const location = useLocation();
const menuItems: MenuProps['items'] = [
{
key: '/',
icon: <HomeOutlined />,
label: '首页',
onClick: () => navigate('/'),
},
{
key: '/projects',
icon: <AppstoreOutlined />,
label: '项目',
disabled: true,
},
{
key: '/members',
icon: <TeamOutlined />,
label: '成员管理',
disabled: true,
},
{
key: '/subscription',
icon: <CrownOutlined />,
label: '订阅管理',
onClick: () => navigate('/subscription'),
},
{
key: '/admin',
icon: <DashboardOutlined />,
label: 'Admin(暂未开放)',
disabled: true,
},
{
key: '/profile',
icon: <UserOutlined />,
label: '个人中心',
onClick: () => navigate('/profile'),
},
];
// 根据当前路径选中菜单项
const selectedKey = '/' + location.pathname.split('/')[1];
return (
<Sider
collapsible
collapsed={collapsed}
trigger={null}
width={200}
style={{
overflow: 'auto',
height: '100vh',
position: 'sticky',
left: 0,
top: 0,
bottom: 0,
}}
>
<div
style={{
height: 64,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#fff',
fontSize: '18px',
fontWeight: 'bold',
}}
>
{collapsed ? '🦐' : '小虾 SaaS'}
</div>
<Menu
theme="dark"
mode="inline"
selectedKeys={[selectedKey]}
items={menuItems}
/>
</Sider>
);
};
export default Sidebar;