feat: 添加前后端交互的示例代码

This commit is contained in:
2024-12-08 02:03:27 +08:00
parent 601b373593
commit f8ec30acfc
24 changed files with 1473 additions and 630 deletions

View File

@@ -0,0 +1,8 @@
.root {
margin: 8px;
margin-top: 0;
height: 100%;
background-color: white;
border-radius: 5px;
padding: 16px;
}

View File

@@ -0,0 +1,230 @@
import styles from "./DosHeader.module.scss";
import { Flex } from "antd";
import React, { useContext, useEffect, useRef, useState } from "react";
import type { GetRef, InputRef, TableProps } from "antd";
import { Button, Form, Input, Popconfirm, Table } from "antd";
type FormInstance<T> = GetRef<typeof Form<T>>;
const EditableContext = React.createContext<FormInstance<any> | null>(null);
interface Item {
key: string;
name: string;
age: string;
address: string;
}
interface EditableRowProps {
index: number;
}
const EditableRow: React.FC<EditableRowProps> = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
interface EditableCellProps {
title: React.ReactNode;
editable: boolean;
dataIndex: keyof Item;
record: Item;
handleSave: (record: Item) => void;
}
const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef<InputRef>(null);
const form = useContext(EditableContext)!;
useEffect(() => {
if (editing) {
inputRef.current?.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
const save = async () => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log("Save failed:", errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[{ required: true, message: `${title} is required.` }]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingInlineEnd: 24 }}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
interface DataType {
key: React.Key;
name: string;
age: string;
address: string;
}
type ColumnTypes = Exclude<TableProps<DataType>["columns"], undefined>;
const App: React.FC = () => {
const [dataSource, setDataSource] = useState<DataType[]>([
{
key: "0",
name: "Edward King 0",
age: "32",
address: "London, Park Lane no. 0",
},
{
key: "1",
name: "Edward King 1",
age: "32",
address: "London, Park Lane no. 1",
},
]);
const [count, setCount] = useState(2);
const handleDelete = (key: React.Key) => {
const newData = dataSource.filter((item) => item.key !== key);
setDataSource(newData);
};
const defaultColumns: (ColumnTypes[number] & {
editable?: boolean;
dataIndex: string;
})[] = [
{
title: "name",
dataIndex: "name",
width: "30%",
editable: true,
},
{
title: "age",
dataIndex: "age",
},
{
title: "address",
dataIndex: "address",
},
{
title: "operation",
dataIndex: "operation",
render: (_, record) =>
dataSource.length >= 1 ? (
<Popconfirm
title="Sure to delete?"
onConfirm={() => handleDelete(record.key)}
>
<a>Delete</a>
</Popconfirm>
) : null,
},
];
const handleAdd = () => {
const newData: DataType = {
key: count,
name: `Edward King ${count}`,
age: "32",
address: `London, Park Lane no. ${count}`,
};
setDataSource([...dataSource, newData]);
setCount(count + 1);
};
const handleSave = (row: DataType) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
setDataSource(newData);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const columns = defaultColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record: DataType) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
}),
};
});
return (
<Table<DataType>
components={components}
rowClassName={() => "editable-row"}
bordered
style={{ width: "100%" }}
dataSource={dataSource}
columns={columns as ColumnTypes}
pagination={false}
/>
);
};
export default function DosHeader() {
return (
<Flex className={styles.root}>
<App />
</Flex>
);
}

View File

@@ -0,0 +1,8 @@
.root {
background-color: white;
min-height: 500px;
width: 100%;
margin: 8px;
margin-top: 0;
border-radius: 5px;
}

View File

@@ -0,0 +1,112 @@
import styles from "./SideTree.module.scss";
import { Flex } from "antd";
import { Tree } from "antd";
import { DownOutlined } from "@ant-design/icons";
import type { TreeProps } from "antd";
import { useEffect, useState } from "react";
// const treeData: TreeDataNode[] = [
// {
// title: "文件: Test.exe",
// key: "0-0",
// children: [
// {
// title: "Dos 头部",
// key: "0-0-0",
// },
// {
// title: "Nt 头部",
// key: "0-0-1",
// children: [
// {
// title: "文件头部",
// key: "0-0-1-0",
// },
// {
// title: "可选头部",
// key: "0-0-2-0",
// children: [
// {
// title: "数据目录",
// key: "0-0-1-1",
// },
// ],
// },
// ],
// },
// {
// title: "节 头部",
// key: "0-0-2",
// },
// {
// title: "导入目录",
// key: "0-0-3",
// },
// {
// title: "资源目录",
// key: "0-0-4",
// },
// {
// title: "地址转换",
// key: "0-0-5",
// },
// {
// title: "依赖性分析",
// key: "0-0-6",
// },
// ],
// },
// ];
export default function SiderTree({ treeData, defaultSelectedKey }) {
// 展开的节点
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
// 受控 选择的节点
const [selectedKey, setSelectedKey] = useState<string>(defaultSelectedKey);
const onSelect: TreeProps["onSelect"] = (selectedKeys, info) => {
console.log("selected", selectedKeys, info);
setSelectedKey(selectedKeys[0] as any);
};
const onExpand: TreeProps["onExpand"] = (_expandedKeys) => {
setExpandedKeys(_expandedKeys as any);
};
// 每次 treeData 变化时,更新 expandedKeys
useEffect(() => {
// 递归获取所有的 key
const getKeys = (nodes) => {
const keys = nodes.map((node) => node.key);
nodes.forEach((node) => {
if (node.children) {
keys.push(...getKeys(node.children));
}
});
return keys;
};
setExpandedKeys(getKeys(treeData));
// 设置默认选中的节点
setSelectedKey(defaultSelectedKey);
}, [treeData]);
console.log("selectedKey", selectedKey);
return (
<Flex className={styles.root}>
<Tree
style={{
width: "100%",
height: "100%",
}}
showLine
treeData={treeData}
selectedKeys={[selectedKey]}
switcherIcon={<DownOutlined />}
onSelect={onSelect}
onExpand={onExpand}
expandedKeys={expandedKeys}
/>
</Flex>
);
}