专案优化
This commit is contained in:
@@ -11,8 +11,7 @@ import {
|
|||||||
message,
|
message,
|
||||||
Select,
|
Select,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Typography,
|
Typography
|
||||||
Spin
|
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
@@ -259,179 +258,177 @@ export default function ProjectDetail() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gradient-to-b from-gray-50 to-white dark:from-gray-800 dark:to-gray-900/90 min-h-screen p-2">
|
<div className="bg-gradient-to-b from-gray-50 to-white dark:from-gray-800 dark:to-gray-900/90 min-h-screen p-2">
|
||||||
<Spin spinning={loading}>
|
<Card
|
||||||
<Card
|
className="shadow-lg rounded-lg border-0"
|
||||||
className="shadow-lg rounded-lg border-0"
|
title={
|
||||||
title={
|
<div className="flex justify-between items-center py-2">
|
||||||
<div className="flex justify-between items-center py-2">
|
<div className="flex items-center space-x-3">
|
||||||
<div className="flex items-center space-x-3">
|
<Title level={4} className="mb-0 text-gray-800">
|
||||||
<Title level={4} className="mb-0 text-gray-800">
|
{id ? (isEdit ? "编辑专案" : "查看专案") : "新建专案"}
|
||||||
{id ? (isEdit ? "编辑专案" : "查看专案") : "新建专案"}
|
</Title>
|
||||||
</Title>
|
<span className="text-gray-400 text-sm">
|
||||||
<span className="text-gray-400 text-sm">
|
{id
|
||||||
{id
|
? isEdit
|
||||||
? isEdit
|
? "请修改专案信息"
|
||||||
? "请修改专案信息"
|
: "专案详情"
|
||||||
: "专案详情"
|
: "请填写专案信息"}
|
||||||
: "请填写专案信息"}
|
</span>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<Space size="middle">
|
|
||||||
<Button
|
|
||||||
icon={<ArrowLeftOutlined />}
|
|
||||||
onClick={() => navigate("/company/project")}
|
|
||||||
>
|
|
||||||
返回
|
|
||||||
</Button>
|
|
||||||
{!isView && (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<SaveOutlined />}
|
|
||||||
onClick={() => form.submit()}
|
|
||||||
loading={loading}
|
|
||||||
>
|
|
||||||
保存
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
<Space size="middle">
|
||||||
>
|
<Button
|
||||||
<Form
|
icon={<ArrowLeftOutlined />}
|
||||||
form={form}
|
onClick={() => navigate("/company/project")}
|
||||||
onFinish={onFinish}
|
|
||||||
onValuesChange={handleValuesChange}
|
|
||||||
layout="vertical"
|
|
||||||
disabled={isView}
|
|
||||||
initialValues={initialValues}
|
|
||||||
>
|
|
||||||
<Card
|
|
||||||
className="shadow-sm rounded-lg"
|
|
||||||
type="inner"
|
|
||||||
title={
|
|
||||||
<span className="flex items-center space-x-2 text-gray-700">
|
|
||||||
<span className="w-1 h-4 bg-blue-500 rounded-full" />
|
|
||||||
<span>基本信息</span>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
bordered={false}
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-2 gap-8">
|
|
||||||
<Form.Item
|
|
||||||
name="projectName"
|
|
||||||
label={<span className="text-gray-700 font-medium">专案名称</span>}
|
|
||||||
rules={[{ required: true, message: "请输入专案名称" }]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
placeholder="请输入专案名称"
|
|
||||||
className="hover:border-blue-400 focus:border-blue-500"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="customers"
|
|
||||||
label={<span className="text-gray-700 font-medium">客户名称</span>}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
placeholder="请选择客户"
|
|
||||||
className="hover:border-blue-400 focus:border-blue-500"
|
|
||||||
showSearch
|
|
||||||
optionFilterProp="children"
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
options={customers.map((customer) => ({
|
|
||||||
value: customer.id,
|
|
||||||
label: customer.attributes.name,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="timeRange"
|
|
||||||
label={<span className="text-gray-700 font-medium">时间范围</span>}
|
|
||||||
>
|
|
||||||
<DatePicker.RangePicker
|
|
||||||
className="w-full hover:border-blue-400 focus:border-blue-500"
|
|
||||||
format="YYYY-MM-DD"
|
|
||||||
onChange={(dates) => {
|
|
||||||
if (dates) {
|
|
||||||
form.setFieldValue('timeRange', [
|
|
||||||
dayjs(dates[0]),
|
|
||||||
dayjs(dates[1])
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
form.setFieldValue('timeRange', null);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
name="relatedTasks"
|
|
||||||
label={<span className="text-gray-700 font-medium">关联任务</span>}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
placeholder="请选择关联任务"
|
|
||||||
className="hover:border-blue-400 focus:border-blue-500"
|
|
||||||
loading={loadingTasks}
|
|
||||||
showSearch
|
|
||||||
optionFilterProp="children"
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
|
||||||
}
|
|
||||||
options={tasks.map((task) => ({
|
|
||||||
value: task.id,
|
|
||||||
label: task.attributes.taskName,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="description"
|
|
||||||
label={<span className="text-gray-700 font-medium">专案描述</span>}
|
|
||||||
>
|
>
|
||||||
<TextArea
|
返回
|
||||||
rows={4}
|
</Button>
|
||||||
placeholder="请输入专案描述"
|
{!isView && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<SaveOutlined />}
|
||||||
|
onClick={() => form.submit()}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
onFinish={onFinish}
|
||||||
|
onValuesChange={handleValuesChange}
|
||||||
|
layout="vertical"
|
||||||
|
disabled={isView}
|
||||||
|
initialValues={initialValues}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
className="shadow-sm rounded-lg"
|
||||||
|
type="inner"
|
||||||
|
title={
|
||||||
|
<span className="flex items-center space-x-2 text-gray-700">
|
||||||
|
<span className="w-1 h-4 bg-blue-500 rounded-full" />
|
||||||
|
<span>基本信息</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
bordered={false}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-2 gap-8">
|
||||||
|
<Form.Item
|
||||||
|
name="projectName"
|
||||||
|
label={<span className="text-gray-700 font-medium">专案名称</span>}
|
||||||
|
rules={[{ required: true, message: "请输入专案名称" }]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入专案名称"
|
||||||
className="hover:border-blue-400 focus:border-blue-500"
|
className="hover:border-blue-400 focus:border-blue-500"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card
|
<Form.Item
|
||||||
className="shadow-sm rounded-lg mt-6"
|
name="customers"
|
||||||
type="inner"
|
label={<span className="text-gray-700 font-medium">客户名称</span>}
|
||||||
title={
|
>
|
||||||
<span className="flex items-center space-x-2 text-gray-700">
|
<Select
|
||||||
<span className="w-1 h-4 bg-blue-500 rounded-full" />
|
mode="multiple"
|
||||||
<span>专案资源</span>
|
placeholder="请选择客户"
|
||||||
</span>
|
className="hover:border-blue-400 focus:border-blue-500"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="children"
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
||||||
|
}
|
||||||
|
options={customers.map((customer) => ({
|
||||||
|
value: customer.id,
|
||||||
|
label: customer.attributes.name,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="timeRange"
|
||||||
|
label={<span className="text-gray-700 font-medium">时间范围</span>}
|
||||||
|
>
|
||||||
|
<DatePicker.RangePicker
|
||||||
|
className="w-full hover:border-blue-400 focus:border-blue-500"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
onChange={(dates) => {
|
||||||
|
if (dates) {
|
||||||
|
form.setFieldValue('timeRange', [
|
||||||
|
dayjs(dates[0]),
|
||||||
|
dayjs(dates[1])
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
form.setFieldValue('timeRange', null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="relatedTasks"
|
||||||
|
label={<span className="text-gray-700 font-medium">关联任务</span>}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
placeholder="请选择关联任务"
|
||||||
|
className="hover:border-blue-400 focus:border-blue-500"
|
||||||
|
loading={loadingTasks}
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="children"
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
||||||
}
|
}
|
||||||
bordered={false}
|
options={tasks.map((task) => ({
|
||||||
>
|
value: task.id,
|
||||||
<ProjectResourceList
|
label: task.attributes.taskName,
|
||||||
type={TYPE}
|
}))}
|
||||||
form={form}
|
/>
|
||||||
isView={isView}
|
</Form.Item>
|
||||||
formValues={formValues}
|
</div>
|
||||||
onValuesChange={handleValuesChange}
|
|
||||||
/>
|
|
||||||
{/* <TaskList type={TYPE}
|
|
||||||
form={form}
|
|
||||||
isView={isView}
|
|
||||||
formValues={formValues}
|
|
||||||
onValuesChange={handleValuesChange} /> */}
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
</Form>
|
name="description"
|
||||||
</Card>
|
label={<span className="text-gray-700 font-medium">专案描述</span>}
|
||||||
</Spin>
|
>
|
||||||
|
<TextArea
|
||||||
|
rows={4}
|
||||||
|
placeholder="请输入专案描述"
|
||||||
|
className="hover:border-blue-400 focus:border-blue-500"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card
|
||||||
|
className="shadow-sm rounded-lg mt-6"
|
||||||
|
type="inner"
|
||||||
|
title={
|
||||||
|
<span className="flex items-center space-x-2 text-gray-700">
|
||||||
|
<span className="w-1 h-4 bg-blue-500 rounded-full" />
|
||||||
|
<span>专案资源</span>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
bordered={false}
|
||||||
|
>
|
||||||
|
<ProjectResourceList
|
||||||
|
type={TYPE}
|
||||||
|
form={form}
|
||||||
|
isView={isView}
|
||||||
|
formValues={formValues}
|
||||||
|
onValuesChange={handleValuesChange}
|
||||||
|
/>
|
||||||
|
{/* <TaskList type={TYPE}
|
||||||
|
form={form}
|
||||||
|
isView={isView}
|
||||||
|
formValues={formValues}
|
||||||
|
onValuesChange={handleValuesChange} /> */}
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Card, Table, Button, message, Popconfirm, Tag, Space, Select } from 'antd';
|
import { Card, Table, Button, message, Popconfirm, Tag, Space, Select, Tooltip } from 'antd';
|
||||||
import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons';
|
import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, ShareAltOutlined } from '@ant-design/icons';
|
||||||
import { useResources } from "@/hooks/resource/useResource";
|
import { useResources } from "@/hooks/resource/useResource";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { supabase } from "@/config/supabase";
|
import { supabase } from "@/config/supabase";
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { useCopyToClipboard } from 'react-use';
|
||||||
|
|
||||||
const ProjectPage = () => {
|
const ProjectPage = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -19,6 +20,7 @@ const ProjectPage = () => {
|
|||||||
const [tasks, setTasks] = useState([]);
|
const [tasks, setTasks] = useState([]);
|
||||||
const [loadingTasks, setLoadingTasks] = useState(false);
|
const [loadingTasks, setLoadingTasks] = useState(false);
|
||||||
const [selectedTask, setSelectedTask] = useState(null);
|
const [selectedTask, setSelectedTask] = useState(null);
|
||||||
|
const [state, copyToClipboard] = useCopyToClipboard();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
resources: projects,
|
resources: projects,
|
||||||
@@ -164,46 +166,67 @@ const ProjectPage = () => {
|
|||||||
title: "操作",
|
title: "操作",
|
||||||
key: "action",
|
key: "action",
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
render: (_, record) => (
|
render: (_, record) => {
|
||||||
<Space size={0} className="dark:text-gray-300">
|
return (
|
||||||
<Button
|
<Space size={0} className="dark:text-gray-300">
|
||||||
size="small"
|
<Button
|
||||||
type="link"
|
size="small"
|
||||||
icon={<EyeOutlined />}
|
type="link"
|
||||||
onClick={() => navigate(`/company/projectView/${record.id}`)}
|
icon={<EyeOutlined />}
|
||||||
className="dark:text-gray-300 dark:hover:text-blue-400"
|
onClick={() => navigate(`/company/projectView/${record.id}`)}
|
||||||
>
|
className="dark:text-gray-300 dark:hover:text-blue-400"
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
type="link"
|
|
||||||
icon={<EditOutlined />}
|
|
||||||
onClick={() => navigate(`/company/projectInfo/${record.id}?edit=true`)}
|
|
||||||
className="dark:text-gray-300 dark:hover:text-blue-400"
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</Button>
|
|
||||||
<Popconfirm
|
|
||||||
title="确定要删除这个专案吗?"
|
|
||||||
description="删除后将无法恢复!"
|
|
||||||
onConfirm={() => handleDelete(record.id)}
|
|
||||||
okText="确定"
|
|
||||||
cancelText="取消"
|
|
||||||
okButtonProps={{ danger: true }}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
type="link"
|
|
||||||
danger
|
|
||||||
icon={<DeleteOutlined />}
|
|
||||||
className="dark:hover:text-red-400"
|
|
||||||
>
|
>
|
||||||
删除
|
查看
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>
|
<Tooltip title="复制查看链接">
|
||||||
</Space>
|
<Button
|
||||||
),
|
size="small"
|
||||||
|
type="link"
|
||||||
|
icon={<ShareAltOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
const viewUrl = `${window.location.origin}/company/projectView/${record.id}`;
|
||||||
|
copyToClipboard(viewUrl);
|
||||||
|
if (!state.error) {
|
||||||
|
message.success('链接已复制到剪贴板');
|
||||||
|
} else {
|
||||||
|
message.error('复制失败,请手动复制');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="dark:text-gray-300 dark:hover:text-blue-400"
|
||||||
|
>
|
||||||
|
分享
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => navigate(`/company/projectInfo/${record.id}?edit=true`)}
|
||||||
|
className="dark:text-gray-300 dark:hover:text-blue-400"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
<Popconfirm
|
||||||
|
title="确定要删除这个专案吗?"
|
||||||
|
description="删除后将无法恢复!"
|
||||||
|
onConfirm={() => handleDelete(record.id)}
|
||||||
|
okText="确定"
|
||||||
|
cancelText="取消"
|
||||||
|
okButtonProps={{ danger: true }}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
danger
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
className="dark:hover:text-red-400"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { supabase } from "@/config/supabase";
|
import { supabase } from "@/config/supabase";
|
||||||
import { Spin, Tag, Empty, Button, Modal, Form, Input, Collapse, message, Upload,Tabs, Select, Divider } from 'antd';
|
import { Spin, Tag, Empty, Button, Modal, Form, Input, Collapse, message, Upload,Tabs, Select, Divider } from 'antd';
|
||||||
import { PlusOutlined, FolderOpenOutlined, ClockCircleOutlined, InboxOutlined } from '@ant-design/icons';
|
import { PlusOutlined, FolderOpenOutlined, ClockCircleOutlined, InboxOutlined } from '@ant-design/icons';
|
||||||
@@ -8,6 +8,7 @@ import {supabaseService}from '@/hooks/supabaseService'
|
|||||||
const type="project"
|
const type="project"
|
||||||
export default function ProjectInfo() {
|
export default function ProjectInfo() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [projectData, setProjectData] = useState(null);
|
const [projectData, setProjectData] = useState(null);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@@ -496,7 +497,10 @@ export default function ProjectInfo() {
|
|||||||
<Input.TextArea rows={4} placeholder="请输入资源描述" />
|
<Input.TextArea rows={4} placeholder="请输入资源描述" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item className="mb-0 flex justify-end gap-3">
|
<Form.Item >
|
||||||
|
<div className="mb-0 flex justify-end w-full gap-3">
|
||||||
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsModalVisible(false);
|
setIsModalVisible(false);
|
||||||
@@ -508,23 +512,42 @@ export default function ProjectInfo() {
|
|||||||
<Button type="primary" htmlType="submit">
|
<Button type="primary" htmlType="submit">
|
||||||
确定
|
确定
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 加载状态展示
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="min-h-screen bg-gray-50/40 flex items-center justify-center">
|
||||||
<Spin tip="加载中..." />
|
<div className="text-center">
|
||||||
|
<Spin size="large" />
|
||||||
|
<div className="mt-4 text-gray-500">加载项目信息中...</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!projectData) {
|
// 无项目数据状态(包括无 ID 和未找到项目)
|
||||||
|
if (!projectData || !id) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="min-h-screen bg-gray-50/40 flex items-center justify-center">
|
||||||
<Empty description="未找到项目信息" />
|
<Empty
|
||||||
|
description={
|
||||||
|
<div className="text-gray-500">
|
||||||
|
<p className="mb-4">未找到项目信息</p>
|
||||||
|
<Button
|
||||||
|
onClick={() => navigate(-1)}
|
||||||
|
className="bg-blue-50 text-blue-600 hover:bg-blue-100 border-none
|
||||||
|
transition-colors duration-200"
|
||||||
|
>
|
||||||
|
返回上一页
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user