backup
This commit is contained in:
parent
a2db003a01
commit
c5abcf2166
|
@ -1,4 +1,4 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
# See https://help.github.com/articles/ignoring-files/ four more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
|
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
|
@ -9,16 +9,25 @@
|
|||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"antd": "^5.16.1",
|
||||
"axios": "^1.6.8",
|
||||
"next": "14.1.3",
|
||||
"postcss": "8.4.31",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"next": "14.1.3"
|
||||
"tailwindcss": "3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@vercel/style-guide": "^5.0.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.1.3"
|
||||
"eslint-config-next": "14.1.3",
|
||||
"prettier": "3.0.3",
|
||||
"prettier-plugin-tailwindcss": "0.5.4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export default function Page() {
|
||||
return <p>Customer Page</p>;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function Page() {
|
||||
return <p>Invoice Page</p>;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import SideNav from '@/app/ui/dashboard/sidenav';
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
|
||||
<div className="w-full flex-none md:w-64">
|
||||
<SideNav />
|
||||
</div>
|
||||
<div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function Loading() {
|
||||
return <div>Loading...</div>;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function Page() {
|
||||
return <p>Dashboard Page</p>;
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
:root {
|
||||
--max-width: 1100px;
|
||||
--border-radius: 12px;
|
||||
--font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
|
||||
"Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
|
||||
"Fira Mono", "Droid Sans Mono", "Courier New", monospace;
|
||||
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
|
||||
--primary-glow: conic-gradient(
|
||||
from 180deg at 50% 50%,
|
||||
#16abff33 0deg,
|
||||
#0885ff33 55deg,
|
||||
#54d6ff33 120deg,
|
||||
#0071ff33 160deg,
|
||||
transparent 360deg
|
||||
);
|
||||
--secondary-glow: radial-gradient(
|
||||
rgba(255, 255, 255, 1),
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
|
||||
--tile-start-rgb: 239, 245, 249;
|
||||
--tile-end-rgb: 228, 232, 233;
|
||||
--tile-border: conic-gradient(
|
||||
#00000080,
|
||||
#00000040,
|
||||
#00000030,
|
||||
#00000020,
|
||||
#00000010,
|
||||
#00000010,
|
||||
#00000080
|
||||
);
|
||||
|
||||
--callout-rgb: 238, 240, 241;
|
||||
--callout-border-rgb: 172, 175, 176;
|
||||
--card-rgb: 180, 185, 188;
|
||||
--card-border-rgb: 131, 134, 135;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
|
||||
--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
|
||||
--secondary-glow: linear-gradient(
|
||||
to bottom right,
|
||||
rgba(1, 65, 255, 0),
|
||||
rgba(1, 65, 255, 0),
|
||||
rgba(1, 65, 255, 0.3)
|
||||
);
|
||||
|
||||
--tile-start-rgb: 2, 13, 46;
|
||||
--tile-end-rgb: 2, 5, 19;
|
||||
--tile-border: conic-gradient(
|
||||
#ffffff80,
|
||||
#ffffff40,
|
||||
#ffffff30,
|
||||
#ffffff20,
|
||||
#ffffff10,
|
||||
#ffffff10,
|
||||
#ffffff80
|
||||
);
|
||||
|
||||
--callout-rgb: 20, 20, 20;
|
||||
--callout-border-rgb: 108, 108, 108;
|
||||
--card-rgb: 100, 100, 100;
|
||||
--card-border-rgb: 200, 200, 200;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
rgb(var(--background-end-rgb))
|
||||
)
|
||||
rgb(var(--background-start-rgb));
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
import "@/app/ui/globals.css";
|
||||
// import { inter } from '@/app/ui/fonts';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
|
@ -15,8 +14,8 @@ export default function RootLayout({
|
|||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
<html>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import React from "react";
|
||||
|
||||
export type Invoice = {
|
||||
id: string;
|
||||
customer_id: string;
|
||||
amount: number;
|
||||
date: string;
|
||||
// In TypeScript, this is called a string union type.
|
||||
// It means that the "status" property can only be one of the two strings: 'pending' or 'paid'.
|
||||
status: 'pending' | 'paid';
|
||||
};
|
||||
type Status={
|
||||
success:boolean;
|
||||
code:number ;
|
||||
message: string;
|
||||
}
|
||||
export type ResultPage<T> = {
|
||||
content:T[];
|
||||
totalPages:number;
|
||||
totalElements:number;
|
||||
|
||||
}
|
||||
export type ResponseVO<T>={
|
||||
data:T;
|
||||
timeStamp:number;
|
||||
status:Status;
|
||||
}
|
||||
|
||||
export type DataType ={
|
||||
key: React.ReactNode;
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
description: string;
|
||||
state: number;
|
||||
priority: number;
|
||||
type:number;
|
||||
action?:React.ReactNode;
|
||||
children: DataType[];
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
const invoices = [
|
||||
{
|
||||
customer_id: customers[0].id,
|
||||
amount: 15795,
|
||||
status: 'pending',
|
||||
date: '2022-12-06',
|
||||
},
|
||||
{
|
||||
customer_id: customers[1].id,
|
||||
amount: 20348,
|
||||
status: 'pending',
|
||||
date: '2022-11-14',
|
||||
},
|
||||
];
|
|
@ -0,0 +1,21 @@
|
|||
import {unstable_noStore as noStore} from 'next/cache';
|
||||
import axios, {AxiosResponse} from "axios";
|
||||
import {DataType, ResponseVO, ResultPage} from "@/app/lib/definitions";
|
||||
|
||||
export async function taskTreeResult():Promise<ResponseVO<ResultPage<DataType>>> {
|
||||
noStore();
|
||||
try {
|
||||
// 使用 Axios 发送 POST 请求获取数据
|
||||
const response: AxiosResponse<ResponseVO<ResultPage<DataType>>> = await axios.post('http://localhost:8090/task/tree', {
|
||||
pageSize: 10,
|
||||
pageNumber: 1
|
||||
});
|
||||
// 从响应中提取数据并返回
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// 处理错误
|
||||
console.error('Error fetching data:', error);
|
||||
// 返回一个默认值或者抛出错误
|
||||
throw new Error('Failed to fetch data');
|
||||
}
|
||||
}
|
135
src/app/page.tsx
135
src/app/page.tsx
|
@ -1,95 +1,52 @@
|
|||
import Image from "next/image";
|
||||
import styles from "./page.module.css";
|
||||
import AcmeLogo from '@/app/ui/acme-logo';
|
||||
import { ArrowRightIcon } from '@heroicons/react/24/outline';
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<div className={styles.description}>
|
||||
<p>
|
||||
Get started by editing
|
||||
<code className={styles.code}>src/app/page.tsx</code>
|
||||
</p>
|
||||
<div>
|
||||
<a
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{" "}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className={styles.vercelLogo}
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
<main className="flex min-h-screen flex-col p-6">
|
||||
<div className="flex h-20 shrink-0 items-end rounded-lg bg-blue-500 p-4 md:h-52">
|
||||
<AcmeLogo/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.center}>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.grid}>
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Docs <span>-></span>
|
||||
</h2>
|
||||
<p>Find in-depth information about Next.js features and API.</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Learn <span>-></span>
|
||||
</h2>
|
||||
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Templates <span>-></span>
|
||||
</h2>
|
||||
<p>Explore starter templates for Next.js.</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Deploy <span>-></span>
|
||||
</h2>
|
||||
<p>
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<div className="mt-4 flex grow flex-col gap-4 md:flex-row">
|
||||
<div className="flex flex-col justify-center gap-6 rounded-lg bg-gray-50 px-6 py-10 md:w-2/5 md:px-20">
|
||||
<p
|
||||
className={`text-xl text-gray-800 md:text-3xl md:leading-normal`}
|
||||
>
|
||||
<strong>Welcome to Acme.</strong> This is the example for the{' '}
|
||||
<a href="https://nextjs.org/learn/" className="text-blue-500">
|
||||
Next.js Learn Course
|
||||
</a>
|
||||
, brought to you by Vercel.
|
||||
</p>
|
||||
<Link
|
||||
href="/login"
|
||||
className="flex items-center gap-5 self-start rounded-lg bg-blue-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-blue-400 md:text-base"
|
||||
>
|
||||
<span>Log in</span>
|
||||
{/*<ArrowRightIcon className="w-5 md:w-6"/>*/}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
|
||||
{/* Add Hero Images Here */}
|
||||
<Image
|
||||
src="/hero-desktop.png"
|
||||
width={1000}
|
||||
height={760}
|
||||
alt="Screenshots of the dashboard project showing desktop version"
|
||||
className="hidden md:block"
|
||||
/>
|
||||
<Image
|
||||
src="/hero-mobile.png"
|
||||
width={560}
|
||||
height={620}
|
||||
alt="Screenshot of the dashboard project showing mobile version"
|
||||
className="block md:hidden"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import SideNav from '@/app/ui/dashboard/sidenav';
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
|
||||
<div className="w-full flex-none md:w-64">
|
||||
<SideNav />
|
||||
</div>
|
||||
<div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function Page() {
|
||||
return <p>Dashboard Page</p>;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import SideNav from '@/app/ui/dashboard/sidenav';
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div>{children}</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function Loading() {
|
||||
return <div>Loading...</div>;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default function Loading() {
|
||||
return <div>Loading...</div>;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import TreeTable from "@/app/ui/task/project/TreeTable";
|
||||
import {DetailForm} from "@/app/ui/task/project/DetailForm";
|
||||
|
||||
const Page: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<TreeTable/>
|
||||
<DetailForm itemId={12} operationId={"1"}></DetailForm>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
|
@ -0,0 +1,13 @@
|
|||
import { GlobeAltIcon } from '@heroicons/react/24/outline';
|
||||
// import { lusitana } from '@/app/ui/fonts';
|
||||
|
||||
export default function AcmeLogo() {
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-row items-center leading-none text-white`}
|
||||
>
|
||||
{/*<GlobeAltIcon className="h-12 w-12 rotate-[15deg]" />*/}
|
||||
<p className="text-[44px]">Acme</p>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import {
|
||||
UserGroupIcon,
|
||||
HomeIcon,
|
||||
DocumentDuplicateIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
|
||||
// Map of links to display in the side navigation.
|
||||
// Depending on the size of the application, this would be stored in a database.
|
||||
const links = [
|
||||
{ name: 'Home', href: '/dashboard', icon: HomeIcon },
|
||||
{
|
||||
name: 'Invoices',
|
||||
href: '/dashboard/invoices',
|
||||
icon: DocumentDuplicateIcon,
|
||||
},
|
||||
{ name: 'Customers', href: '/dashboard/customers', icon: UserGroupIcon },
|
||||
];
|
||||
|
||||
export default function NavLinks() {
|
||||
return (
|
||||
<>
|
||||
{links.map((link) => {
|
||||
const LinkIcon = link.icon;
|
||||
return (
|
||||
<a
|
||||
key={link.name}
|
||||
href={link.href}
|
||||
className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
|
||||
>
|
||||
{/*<LinkIcon className="w-6" />*/}
|
||||
<p className="hidden md:block">{link.name}</p>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import Link from 'next/link';
|
||||
import NavLinks from '@/app/ui/dashboard/nav-links';
|
||||
import AcmeLogo from '@/app/ui/acme-logo';
|
||||
import { PowerIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
export default function SideNav() {
|
||||
return (
|
||||
<div className="flex h-full flex-col px-3 py-4 md:px-2">
|
||||
<Link
|
||||
className="mb-2 flex h-20 items-end justify-start rounded-md bg-blue-600 p-4 md:h-40"
|
||||
href="/public"
|
||||
>
|
||||
<div className="w-32 text-white md:w-40">
|
||||
<AcmeLogo />
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex grow flex-row justify-between space-x-2 md:flex-col md:space-x-0 md:space-y-2">
|
||||
<NavLinks />
|
||||
<div className="hidden h-auto w-full grow rounded-md bg-gray-50 md:block"></div>
|
||||
<form>
|
||||
<button className="flex h-[48px] w-full grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3">
|
||||
<PowerIcon className="w-6" />
|
||||
<div className="hidden md:block">Sign Out</div>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// import { Inter,Lusitana } from 'next/font/google';
|
||||
//
|
||||
// export const inter = Inter({ subsets: ['latin'] });
|
||||
// export const lusitana = Lusitana({
|
||||
// weight: ['400', '700'],
|
||||
// subsets: ['latin'],
|
||||
// });
|
|
@ -0,0 +1,18 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
input[type='number'] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
input[type='number']::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type='number']::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
'use client'
|
||||
import React, { useState } from 'react';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Cascader,
|
||||
Checkbox,
|
||||
ColorPicker,
|
||||
DatePicker,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Radio,
|
||||
Select,
|
||||
Slider,
|
||||
Switch,
|
||||
TreeSelect,
|
||||
Upload,
|
||||
} from 'antd';
|
||||
export interface DetailFormProps {
|
||||
itemId: number,
|
||||
operationId: string,
|
||||
}
|
||||
|
||||
export const DetailForm: React.FC<DetailFormProps> = (props) => {
|
||||
|
||||
|
||||
const [componentDisabled, setComponentDisabled] =
|
||||
useState<boolean>(props.operationId==='1');
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
const { TextArea } = Input;
|
||||
|
||||
const normFile = (e: any) => {
|
||||
if (Array.isArray(e)) {
|
||||
return e;
|
||||
}
|
||||
return e?.fileList;
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
checked={componentDisabled}
|
||||
onChange={(e) => setComponentDisabled(e.target.checked)}
|
||||
>
|
||||
Form disabled
|
||||
</Checkbox>
|
||||
<Form
|
||||
labelCol={{span: 4}}
|
||||
wrapperCol={{span: 14}}
|
||||
layout="horizontal"
|
||||
disabled={componentDisabled}
|
||||
style={{maxWidth: 600}}
|
||||
>
|
||||
<Form.Item label="Checkbox" name="disabled" valuePropName="checked">
|
||||
<Checkbox>Checkbox</Checkbox>
|
||||
</Form.Item>
|
||||
<Form.Item label="Radio">
|
||||
<Radio.Group>
|
||||
<Radio value="apple"> Apple </Radio>
|
||||
<Radio value="pear"> Pear </Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item label="Input">
|
||||
<Input/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Select">
|
||||
<Select>
|
||||
<Select.Option value="demo">Demo</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label="TreeSelect">
|
||||
<TreeSelect
|
||||
treeData={[
|
||||
{title: 'Light', value: 'light', children: [{title: 'Bamboo', value: 'bamboo'}]},
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Cascader">
|
||||
<Cascader
|
||||
options={[
|
||||
{
|
||||
value: 'zhejiang',
|
||||
label: 'Zhejiang',
|
||||
children: [
|
||||
{
|
||||
value: 'hangzhou',
|
||||
label: 'Hangzhou',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="DatePicker">
|
||||
<DatePicker/>
|
||||
</Form.Item>
|
||||
<Form.Item label="RangePicker">
|
||||
<RangePicker/>
|
||||
</Form.Item>
|
||||
<Form.Item label="InputNumber">
|
||||
<InputNumber/>
|
||||
</Form.Item>
|
||||
<Form.Item label="TextArea">
|
||||
<TextArea rows={4}/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Switch" valuePropName="checked">
|
||||
<Switch/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Upload" valuePropName="fileList" getValueFromEvent={normFile}>
|
||||
<Upload action="/upload.do" listType="picture-card">
|
||||
<button style={{border: 0, background: 'none'}} type="button">
|
||||
<PlusOutlined/>
|
||||
<div style={{marginTop: 8}}>Upload</div>
|
||||
</button>
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
<Form.Item label="Button">
|
||||
<Button>Button</Button>
|
||||
</Form.Item>
|
||||
<Form.Item label="Slider">
|
||||
<Slider/>
|
||||
</Form.Item>
|
||||
<Form.Item label="ColorPicker">
|
||||
<ColorPicker/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
import React, {Fragment} from "react";
|
||||
import {Button, Dropdown, MenuProps, Modal, Popconfirm, Space} from "antd";
|
||||
import {DownOutlined, QuestionCircleOutlined} from "@ant-design/icons";
|
||||
import {DetailForm} from "@/app/ui/task/project/DetailForm";
|
||||
|
||||
export interface OperationButtonProps {
|
||||
itemId: number
|
||||
}
|
||||
interface OperationModelProps {
|
||||
operationId: string,
|
||||
openModal:boolean
|
||||
}
|
||||
class OperationButton extends React.Component<OperationButtonProps,OperationModelProps> {
|
||||
|
||||
constructor(props: OperationButtonProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
operationId: '',
|
||||
openModal:false
|
||||
};
|
||||
}
|
||||
render() {
|
||||
const handleCancel =()=>{
|
||||
this.setState({...this.state,openModal:false})
|
||||
}
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: <a onClick={(e) => {
|
||||
this.setState({...this.state,openModal:true})
|
||||
}}>详情</a>,
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: <a onClick={(e) => {
|
||||
this.setState({...this.state,openModal:true})
|
||||
}}>添加下级</a>,
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: <a onClick={(e) => {
|
||||
this.setState({...this.state,openModal:true})
|
||||
}}>修改</a>,
|
||||
}
|
||||
,
|
||||
{
|
||||
key: '4',
|
||||
label: <Popconfirm
|
||||
title="删除任务"
|
||||
description="确认要删除任务?"
|
||||
icon={<QuestionCircleOutlined style={{color: 'red'}}/>}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>删除</Popconfirm>,
|
||||
}
|
||||
,
|
||||
{
|
||||
key: '5',
|
||||
label: <Popconfirm
|
||||
title="完成任务"
|
||||
description="确认要完成任务?"
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
>完成</Popconfirm>,
|
||||
}
|
||||
];
|
||||
return <Fragment>
|
||||
<Dropdown menu={{items}}>
|
||||
<a onClick={(e) => {
|
||||
e.preventDefault()
|
||||
}}>
|
||||
<Space>
|
||||
操作<DownOutlined/>
|
||||
</Space>
|
||||
</a>
|
||||
</Dropdown>
|
||||
<Modal
|
||||
open={this.state.openModal}
|
||||
title="Title"
|
||||
// open={open}
|
||||
// onOk={handleOk}
|
||||
onCancel={handleCancel}
|
||||
// footer={[
|
||||
// <Button key="back" onClick={handleCancel}>
|
||||
// Return
|
||||
// </Button>,
|
||||
// <Button key="submit" type="primary" loading={loading} onClick={handleOk}>
|
||||
// Submit
|
||||
// </Button>,
|
||||
// <Button
|
||||
// key="link"
|
||||
// href="https://google.com"
|
||||
// type="primary"
|
||||
// loading={loading}
|
||||
// onClick={handleOk}
|
||||
// >
|
||||
// Search on Google
|
||||
// </Button>,
|
||||
// ]}
|
||||
>
|
||||
<DetailForm itemId={this.props.itemId} operationId={'1'}/>
|
||||
</Modal>
|
||||
</Fragment>
|
||||
}
|
||||
}
|
||||
|
||||
export default OperationButton;
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
'use client'
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Button, ColorPicker, Dropdown, MenuProps, Space, Switch, Table} from 'antd';
|
||||
import type { TableColumnsType, TableProps } from 'antd';
|
||||
import { taskTreeResult} from "@/app/lib/task/project/data";
|
||||
import {DataType, ResponseVO, ResultPage} from "@/app/lib/definitions";
|
||||
import {DownOutlined} from "@ant-design/icons";
|
||||
import OperationButton from "@/app/ui/task/project/OperationButton";
|
||||
|
||||
type TableRowSelection<T> = TableProps<T>['rowSelection'];
|
||||
|
||||
|
||||
const columns: TableColumnsType<DataType> = [
|
||||
{
|
||||
title: '任务编码',
|
||||
dataIndex: 'code',
|
||||
key: 'code',
|
||||
width: '10%',
|
||||
},
|
||||
{
|
||||
title: '任务名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '任务描述',
|
||||
dataIndex: 'description',
|
||||
width: '30%',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '任务状态',
|
||||
dataIndex: 'state',
|
||||
width: '10%',
|
||||
key: 'state',
|
||||
},
|
||||
{
|
||||
title: '优先级',
|
||||
dataIndex: 'priority',
|
||||
width: '10%',
|
||||
key: 'priority',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: '10%',
|
||||
key: 'action',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
// rowSelection objects indicates the need for row selection
|
||||
const rowSelection: TableRowSelection<DataType> = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||
},
|
||||
onSelect: (record, selected, selectedRows) => {
|
||||
console.log(record, selected, selectedRows);
|
||||
},
|
||||
onSelectAll: (selected, selectedRows, changeRows) => {
|
||||
console.log(selected, selectedRows, changeRows);
|
||||
},
|
||||
};
|
||||
function recursionActionChild(children:DataType[]){
|
||||
if (children.length===0){
|
||||
return;
|
||||
}
|
||||
children.forEach(item=>{
|
||||
item.key=item.id;
|
||||
item.action=(<OperationButton itemId={item.id}></OperationButton>)
|
||||
recursionActionChild(item.children)
|
||||
})
|
||||
}
|
||||
const TreeTable: React.FC = () => {
|
||||
// const [checkStrictly, setCheckStrictly] = useState(false);
|
||||
const [data, setData] = useState<DataType[]>([]);
|
||||
const [pageNumber, setPageNumber] = useState<number>(1);
|
||||
const [pageSize, setPageSize] = useState<number>(10);
|
||||
useEffect(() => {
|
||||
console.log("useEffect::taskTreeResult")
|
||||
taskTreeResult().then((result:ResponseVO<ResultPage<DataType>>)=>{
|
||||
if (result.status.success){
|
||||
recursionActionChild(result.data.content);
|
||||
setData(result.data.content)
|
||||
}
|
||||
})
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{/*<Space align="center" style={{ marginBottom: 16 }}>*/}
|
||||
{/* CheckStrictly: <Switch checked={checkStrictly} onChange={setCheckStrictly} />*/}
|
||||
{/*</Space>*/}
|
||||
<Button type="primary">添加主线任务</Button>
|
||||
<ColorPicker defaultValue="#1677ff" showText/>
|
||||
<Table
|
||||
columns={columns}
|
||||
// rowSelection={{ ...rowSelection, checkStrictly}}
|
||||
dataSource={data}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TreeTable;
|
Loading…
Reference in New Issue