feat:团队列表

This commit is contained in:
1708-huayu 2025-08-06 18:58:51 +08:00
parent cf68c5e915
commit 55ffba0953
9 changed files with 178 additions and 13 deletions

View File

@ -29,6 +29,7 @@ export default function Layout({children}: { children: React.ReactNode }) {
},
},
token: {
controlItemBgHover:"#4096ff",
controlItemBgActiveHover:"#4096ff",
controlItemBgActive:"#4096ff"
}

View File

@ -10,6 +10,7 @@ import {
updateStepItemIndexAPI
} from "@/components/service/StepSort";
import {QuestionCircleOutlined} from "@ant-design/icons";
import {copyToClipboard} from "@/lib/copyToClipboard";
const reorder = (list: TaskStepSortVO[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
@ -42,7 +43,12 @@ const StepSort = (props: { taskId: string, stepList: TaskStepSortVO[] }) => {
const [modalText, setModalText] = useState<TaskStepSortOperateVO>(initModalText);
const items: MenuProps['items'] = [
{
key: "0", label: "上方插入", onClick: () => {
key: "0", label: "复制", onClick: () => {
copyToClipboard(clickTaskSortItem?.stepDesc || "")
// copyToClipboard(clickTaskSortItem?.stepDesc ?? "")
}
},{
key: "1", label: "上方插入", onClick: () => {
setDialogueOpen(true)
setModalText({
id: "",
@ -56,7 +62,7 @@ const StepSort = (props: { taskId: string, stepList: TaskStepSortVO[] }) => {
}
},
{
key: "1", label: "下方插入", onClick: () => {
key: "2", label: "下方插入", onClick: () => {
setDialogueOpen(true)
setModalText({
id: "",
@ -70,13 +76,13 @@ const StepSort = (props: { taskId: string, stepList: TaskStepSortVO[] }) => {
}
},
{
key: "2", label: "修改步骤", onClick: () => {
key: "3", label: "修改步骤", onClick: () => {
setDialogueOpen(true)
setModalText(clickTaskSortItem!)
}
},
{
key: "3", label:
key: "4", label:
<Popconfirm
title="删除步骤"
description="确认要删除步骤?"

View File

@ -0,0 +1,102 @@
import React, {Fragment, useEffect, useRef, useState} from "react";
import {Button, Modal, TablePaginationConfig} from "antd";
import {ActionType, ProColumns, ProTable} from "@ant-design/pro-components";
import {Params} from "next/dist/shared/lib/router/utils/route-matcher";
import {TeamMemberVO} from "@/components/type/Share.d";
import type {FilterValue, SorterResult, TableCurrentDataSource} from "antd/es/table/interface";
import {listTeamMemberAPI} from "@/components/service/Share";
const TeamMember = (props: { taskId: string }) => {
const [open, setOpen] = useState(false);
const onClose = () => {
setOpen(false);
};
const ref = useRef<ActionType>();
const [userList, setUserList] = React.useState<TeamMemberVO[]>([]);
const [totalUserList, setTotalUserList] = React.useState<TeamMemberVO[]>([]);
const [totalElement, setTotalElement] = React.useState(0);
const [loading, setLoading] = React.useState(false);
useEffect(() => {
if (open){
setLoading(true);
listTeamMemberAPI(props.taskId).then((res)=>{
if (res.data.status.success){
setUserList(res.data.data.splice(0,10))
setTotalUserList(res.data.data)
setTotalElement(res.data.data.length)
setTimeout(()=>{ref.current?.reload()},100)
}
setLoading(false)
})
}
},[open])
const columns: ProColumns<TeamMemberVO>[] = [
{
title: 'ID',
key: 'username',
dataIndex: 'username',
width: 150,
},
{
title: '昵称',
key: 'nickname',
dataIndex: 'nickname',
width: 150,
},
{
title: '操作',
key: 'operate',
width: 120,
valueType: 'option',
render: () => [<Button key="1"></Button>],
},
];
return (
<Fragment>
<Button type="primary" onClick={() => setOpen(!open)}>
</Button>
<Modal
title="团队成员"
closable={{'aria-label': 'Custom Close Button'}}
open={open}
destroyOnClose={true}
footer={null}
onCancel={onClose}
>
<ProTable<TeamMemberVO, Params>
actionRef={ref}
search={false}
toolBarRender={false}
loading={loading}
columns={columns}
dataSource={userList}
// request={(params, sorter, filter) => {
// // 表单搜索项会从 params 传入,传递给后端接口。
// console.log(params, sorter, filter);
// return Promise.resolve({
// data: userList,
// success: true,
// });
// }}
/* Pagination */
pagination={{
defaultPageSize:10,
defaultCurrent:1,
total: totalElement,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `总共 ${total}`
}}
onChange={(pagination: TablePaginationConfig, filters: Record<string, FilterValue | null>,
sorter: SorterResult<TeamMemberVO> | SorterResult<TeamMemberVO>[], extra:
TableCurrentDataSource<TeamMemberVO>) => {
setUserList(totalUserList.splice((pagination.current??1-1)*(pagination.pageSize??10),pagination.pageSize))
}}
/>
</Modal>
</Fragment>)
}
export default TeamMember;

View File

@ -1,9 +1,12 @@
import {AxiosResponse} from "axios";
import {ResponseVO} from "@/lib/definitions";
import {httpReq} from "@/utils/axiosReq";
import {ShareVO} from "@/components/type/Share.d";
import {ShareVO, TeamMemberVO} from "@/components/type/Share.d";
export const addTaskPassAPI= (data:ShareVO):Promise<AxiosResponse<ResponseVO<ShareVO>>> =>{
return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + "/task/pass",
data)
}
export const listTeamMemberAPI = (taskId:string):Promise<AxiosResponse<ResponseVO<TeamMemberVO[]>>> =>{
return httpReq.get(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + `/task/team/member/list?taskId=${taskId}`)
}

View File

@ -1 +1,12 @@
export interface ShareVO { taskId: string, pass: string, joinCheck: string ,id?:string}
export interface TeamMemberVO {
id:string,
userId:string,
username:string,
nickname:string,
userState:string,
userRole:string,
taskId:string,
fId:string,
}

View File

@ -47,9 +47,10 @@ class OperationButton extends React.Component<OperationButtonProps, OperationMod
render() {
const handleCancel = () => {
this.setState({...this.state, openModal: false})
if (this.state.operationId !== OPERATION_BUTTON_TYPE.DETAIL) {
this.props.refreshDate?.()
}
}
const closeAndReloadData = () => {
this.setState({...this.state, openModal: false})
this.props.refreshDate?.()
}
const onClick: MenuProps['onClick'] = ({key}) => {
console.log(key)
@ -156,6 +157,7 @@ class OperationButton extends React.Component<OperationButtonProps, OperationMod
key: OPERATION_BUTTON_TYPE.UPDATE_PRIORITY,
label: <a onClick={(e) => {
this.setState({updatePriority: true})
console.log("修改优先级",this.state.priority)
}}></a>,
},
{
@ -213,7 +215,8 @@ class OperationButton extends React.Component<OperationButtonProps, OperationMod
this.state.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD ? '添加支线任务' :
this.state.operationId === OPERATION_BUTTON_TYPE.UPDATE ? '修改任务' : '未知操作'}
open={this.state.openModal}
reloadData={handleCancel}/>}
closeOpen={handleCancel}
reloadData={closeAndReloadData}/>}
</Fragment>
}
}

View File

@ -25,6 +25,7 @@ import ClickRecord from "@/components/ClickRecord";
import onceConsumeList from "@/components/constant/onceConsumeList.json"
import {onceConsumerRead} from "@/utils/codeToReadName";
import style from "@/ui/task/project/DetailModelForm.module.css"
import TeamMember from "@/components/TeamMember";
export type DetailModelFormProps = {
// 当前内容id
itemId?: string,
@ -51,9 +52,10 @@ export type DetailModelFormProps = {
export type PidSelectTree = { label: string; value: string; pid: string; children?: PidSelectTree[] }
export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
console.log("DetailModelForm:props:", props)
const [form] = Form.useForm<DataType>();
const [requestTask, setRequestTask] = useState<DataType>()
console.log("DetailModelForm:props:", props,requestTask)
const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL)
// 团队第一层 pid必须为0
const [taskType, setTaskType] = useState('0')
@ -87,6 +89,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
console.log("form.setFieldsValue(task.data)" + JSON.stringify(task.data))
} else {
message.error(task.status.message);
setRequestTask(undefined)
form.resetFields()
props.reloadData?.()
}
}).finally(() => {
@ -141,6 +145,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
destroyOnClose: true,
maskClosable: false,
onCancel: () => {
setRequestTask(undefined)
form.resetFields()
props.reloadData?.();
},
}}
@ -170,6 +176,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
console.log('response', response)
if (response.status.success) {
message.success("删除任务成功:" + response.data)
setRequestTask(undefined)
form.resetFields()
props.reloadData?.()
}
}));
@ -191,6 +199,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
} else {
if (editFormDisable && taskType == '1') {
result.push(<ShareOption taskId={props.itemId!}/>)
result.push(<TeamMember taskId={props.itemId!}/> )
}
result.push(<Button type="primary" key="close"
onClick={() => props.closeOpen?.()}></Button>)
@ -269,6 +278,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
// 树任务重新刷新
// 四象限任务重新刷新
// 如果可以直接更新列表而不请求。。。。。。
setRequestTask(undefined)
form.resetFields()
props.reloadData?.()
result = true
} else {
@ -289,6 +300,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
// 如果可以直接更新列表而不请求。。。。。。
console.log('props.reloadData?.()', props.reloadData)
result = (taskType != '1')
setRequestTask(undefined)
form.resetFields()
props.reloadData?.()
} else {
message.error(response.data.status.message)

View File

@ -12,3 +12,23 @@
.ant-form-item .ant-form-item-label{
overflow: visible;
}
.text-ellipsis {
/* 单行省略 */
/*width: 100%;*/
/*box-sizing: border-box;*/
/*white-space: nowrap;*/
/*overflow: hidden;*/
/*text-overflow: ellipsis;*/
width: 100%;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.5em; /* 根据实际字体大小调整 */
max-height: 3em; /* 2行 x 1.5em */
word-break: break-word; /* 允许长单词换行 */
}

View File

@ -5,11 +5,11 @@ import {
} from '@ant-design/icons';
import type {ActionType, FormInstance, ProColumns, ProFormInstance} from '@ant-design/pro-components';
import {ProTable, TableDropdown} from '@ant-design/pro-components';
import {Button, DatePicker, Dropdown, Space, Switch, Tag, Tooltip} from 'antd';
import { DatePicker, Dropdown, Space, Switch, Tag, Tooltip} from 'antd';
import React, {Fragment, useContext, useEffect, useRef} from 'react';
import {DataType} from "@/lib/definitions";
import {
getTaskTreeResult, getTaskTreeResultAPI,
getTaskTreeResultAPI,
OPERATION_BUTTON_TYPE,
taskPriorityList,
taskStateList,
@ -63,6 +63,11 @@ const TreeTablePro: React.FC = (props:{joinId?:string}) => {
key: 'description',
title: '任务描述',
dataIndex: 'description',
render: (_, record) => {
return <Tooltip placement="topLeft" title={record.description}>
<div className='text-ellipsis'>{record.description}</div>
</Tooltip>
}
},
{
key: 'priority',
@ -152,6 +157,7 @@ const TreeTablePro: React.FC = (props:{joinId?:string}) => {
title: '操作',
valueType: 'option',
render: (_, record) => <OperationButton itemId={record.id} itemName={record.name} pid={record.pid} pPid={record.pPid}
priority={record.priority}
refreshDate={() => {
actionRef.current?.reload(false);
}}/>,