团队模块

This commit is contained in:
‘Liammcl’
2024-12-28 14:28:00 +08:00
parent b3ac241354
commit 4f0e7be806
7 changed files with 121 additions and 15 deletions

View File

@@ -42,12 +42,35 @@ export const useTeams = () => {
}
};
// 创建团队前检查类型是否已存在
const checkTeamTypeExists = async (type) => {
try {
const {data} = await supabaseService.select('teams', {
filter: {
deleted_at: { is: null },
'attributes->>type': { eq: type }
}
});
return data.length > 0;
} catch (error) {
console.error('检查团队类型失败:', error);
throw error;
}
};
// 创建团队
const createTeam = async (values) => {
try {
if (values.type) {
const result = await checkTeamTypeExists(values.type);
if (result) {
throw new Error(`团队类型 "${values.type}" 已存在,请使用其他类型名称`);
}
}
const newTeam = await supabaseService.insert('teams', {
name: values.name,
description: values.description
description: values.description,
attributes: { type: values.type }
});
// 创建团队成员关系

View File

@@ -41,7 +41,12 @@ export const TeamForm = ({ form }) => {
>
<Input placeholder="请输入团队名称" />
</Form.Item>
<Form.Item
name="type"
label="项目归属"
>
<Input placeholder="请输入项目归属" />
</Form.Item>
<Form.Item
name="avatarUrl"
label="团队头像"

View File

@@ -2,7 +2,8 @@ import React, { useState, useEffect } from 'react';
import { Modal,Button, Form, Input, Select, message } from 'antd';
import { MembershipTable } from './MembershipTable';
import { supabaseService } from '@/hooks/supabaseService';
import { supabase } from '@/config/supabase';
import { v4 as uuidv4 } from "uuid";
const { Option } = Select;
export const ExpandedMemberships = ({ teamId }) => {
@@ -69,17 +70,26 @@ export const ExpandedMemberships = ({ teamId }) => {
}
};
const handleAdd = () => {
const handleAdd = (value) => {
handleModalOk(value)
setIsModalVisible(true);
form.resetFields();
};
const handleModalOk = async () => {
const handleModalOk = async (values) => {
try {
const values = await form.validateFields();
const { data: users, error: userError } = await supabase
.from('users')
.select('id, email')
.eq('email', values.email)
.single();
if (userError || users.length===0) {
throw new Error('未找到该用户');
}
await supabaseService.insert('team_membership', {
id:uuidv4(),
team_id: teamId,
user_id: values.user_id,
user_id: users.id,
role: values.role,
is_creator: false
});
@@ -88,7 +98,7 @@ export const ExpandedMemberships = ({ teamId }) => {
message.success('成员已添加');
await loadMemberships();
} catch (error) {
message.error('添加成员失败');
message.error(error.message || '添加成员失败');
console.error('Add failed:', error);
}
};

View File

@@ -1,12 +1,14 @@
import React, { useState } from 'react';
import { Table, Button, Space, Popconfirm, Tag, Form } from 'antd';
import { Table, Button, Space, Popconfirm, Tag, Form, Modal, Input, Select } from 'antd';
import { EditOutlined, DeleteOutlined, SaveOutlined, CloseOutlined, PlusOutlined } from '@ant-design/icons';
import { EditableMembershipCell } from './EditableMembershipCell';
import { roleColors } from '../constants/teamConstants';
import { message } from 'antd';
export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
const [form] = Form.useForm();
const [editingKey, setEditingKey] = useState('');
const [addModalVisible, setAddModalVisible] = useState(false);
const isEditing = (record) => record.id === editingKey;
@@ -38,7 +40,6 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
render: (user) => (
<div className="flex flex-col">
<span className="font-medium">{user?.email}</span>
<span className="text-gray-500 text-sm">{user?.email}</span>
</div>
),
},
@@ -137,16 +138,71 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
};
});
const AddMemberModal = ({ visible, onCancel, onAdd }) => {
const [loading, setLoading] = useState(false);
const handleSubmit = async () => {
try {
setLoading(true);
const values = await form.validateFields();
await onAdd(values);
form.resetFields();
onCancel();
} catch (error) {
message.error('添加失败: ' + error.message);
} finally {
setLoading(false);
}
};
return (
<Modal
title="添加成员"
open={visible}
onCancel={onCancel}
onOk={handleSubmit}
confirmLoading={loading}
>
<Form
form={form}
layout="vertical"
>
<Form.Item
name="email"
label="邮箱"
rules={[
{ required: true, message: '请输入邮箱' },
{ type: 'email', message: '请输入有效的邮箱地址' }
]}
>
<Input placeholder='请输入邮箱' />
</Form.Item>
<Form.Item
name="role"
label="角色"
rules={[{ required: true, message: '请选择角色' }]}
initialValue="MEMBER"
>
<Select>
<Select.Option value="OWNER">管理员</Select.Option>
<Select.Option value="MEMBER">成员</Select.Option>
</Select>
</Form.Item>
</Form>
</Modal>
);
};
return (
<div className="space-y-4">
{/* <Button
<Button
type="primary"
icon={<PlusOutlined />}
onClick={onAdd}
onClick={() => setAddModalVisible(true)}
className="mb-4"
>
添加成员
</Button> */}
</Button>
<Form form={form} component={false}>
<Table
scroll={{ x: true }}
@@ -161,6 +217,12 @@ export const MembershipTable = ({ memberships, onUpdate, onDelete, onAdd }) => {
pagination={false}
/>
</Form>
<AddMemberModal
visible={addModalVisible}
onCancel={() => setAddModalVisible(false)}
onAdd={onAdd}
/>
</div>
);
};

View File

@@ -77,6 +77,12 @@ export const TeamTable = ({ tableLoading,pagination,dataSource, onTableChange,on
</div>
),
},
{
title: '归属',
dataIndex: 'type',
dataIndex: ["attributes", "type"],
key: "type",
},
{
title: '描述',
dataIndex: 'description',

View File

@@ -152,7 +152,7 @@ const TeamManagement = () => {
await loadTeams({ current: 1 });
message.success('创建团队成功');
} catch (error) {
message.error('创建团队失败');
message.error(error.message);
} finally {
setConfirmLoading(false);
}