feat: dos header的读取写完了。
This commit is contained in:
@@ -2,17 +2,18 @@ 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";
|
||||
import { Form, Input, 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;
|
||||
name: string; // 字段名称
|
||||
offset: string; // 偏移
|
||||
size: Number; // 字段大小
|
||||
value: string; // 字段值
|
||||
children?: Item[];
|
||||
}
|
||||
|
||||
interface EditableRowProps {
|
||||
@@ -65,7 +66,6 @@ const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
|
||||
const save = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
|
||||
toggleEdit();
|
||||
handleSave({ ...record, ...values });
|
||||
} catch (errInfo) {
|
||||
@@ -82,7 +82,7 @@ const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
|
||||
name={dataIndex}
|
||||
rules={[{ required: true, message: `${title} is required.` }]}
|
||||
>
|
||||
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
|
||||
<Input size="small" ref={inputRef} onPressEnter={save} onBlur={save} />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<div
|
||||
@@ -99,89 +99,72 @@ const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
|
||||
};
|
||||
|
||||
interface DataType {
|
||||
key: React.Key;
|
||||
name: string;
|
||||
age: string;
|
||||
address: string;
|
||||
name: string; // 字段名称
|
||||
offset: string; // 偏移
|
||||
size: string | Number; // 字段大小
|
||||
value: string; // 字段值
|
||||
field_type: string; // 字段类型
|
||||
children?: DataType[];
|
||||
}
|
||||
|
||||
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 App = ({ defaultData = [] }) => {
|
||||
const [dataSource, setDataSource] = useState<DataType[]>(defaultData);
|
||||
useEffect(()=>{
|
||||
setDataSource(defaultData)
|
||||
}, [defaultData])
|
||||
|
||||
const defaultColumns: (ColumnTypes[number] & {
|
||||
editable?: boolean;
|
||||
dataIndex: string;
|
||||
})[] = [
|
||||
{
|
||||
title: "name",
|
||||
title: "字段名称",
|
||||
dataIndex: "name",
|
||||
width: "30%",
|
||||
},
|
||||
{
|
||||
title: "偏移量",
|
||||
dataIndex: "offset",
|
||||
},
|
||||
{
|
||||
title: "字段类型",
|
||||
dataIndex: "field_type",
|
||||
},
|
||||
{
|
||||
title: "字段大小",
|
||||
dataIndex: "size",
|
||||
},
|
||||
{
|
||||
title: "字段值",
|
||||
dataIndex: "value",
|
||||
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 replaceNodeByName = (
|
||||
data: DataType[],
|
||||
name: string,
|
||||
newNode: DataType
|
||||
): DataType[] => {
|
||||
return data.map((item) => {
|
||||
if (item.name === name) {
|
||||
return newNode;
|
||||
}
|
||||
if (item.children) {
|
||||
return {
|
||||
...item,
|
||||
children: replaceNodeByName(item.children, name, newNode),
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
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,
|
||||
});
|
||||
let newData = [...dataSource];
|
||||
newData = replaceNodeByName(newData, row.name, row);
|
||||
setDataSource(newData);
|
||||
};
|
||||
|
||||
@@ -213,18 +196,21 @@ const App: React.FC = () => {
|
||||
components={components}
|
||||
rowClassName={() => "editable-row"}
|
||||
bordered
|
||||
rowKey={(record) => record.name}
|
||||
style={{ width: "100%" }}
|
||||
dataSource={dataSource}
|
||||
columns={columns as ColumnTypes}
|
||||
pagination={false}
|
||||
size="small"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default function DosHeader() {
|
||||
export default function DosHeader({ defaultData }) {
|
||||
console.log("DosHeader defaultData:", defaultData);
|
||||
return (
|
||||
<Flex className={styles.root}>
|
||||
<App />
|
||||
<App defaultData={defaultData} />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,60 +5,11 @@ 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 }) {
|
||||
export default function SiderTree({
|
||||
treeData,
|
||||
defaultSelectedKey,
|
||||
onSelect: onTreeSelect,
|
||||
}) {
|
||||
// 展开的节点
|
||||
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
|
||||
|
||||
@@ -67,7 +18,9 @@ export default function SiderTree({ treeData, defaultSelectedKey }) {
|
||||
|
||||
const onSelect: TreeProps["onSelect"] = (selectedKeys, info) => {
|
||||
console.log("selected", selectedKeys, info);
|
||||
setSelectedKey(selectedKeys[0] as any);
|
||||
let key = info.node.key as string;
|
||||
setSelectedKey(key);
|
||||
onTreeSelect(key);
|
||||
};
|
||||
|
||||
const onExpand: TreeProps["onExpand"] = (_expandedKeys) => {
|
||||
|
||||
@@ -1,16 +1,60 @@
|
||||
import styles from "./MainPage.module.scss";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Layout, Flex, Button } from "antd";
|
||||
import { Layout, Flex, Button, Empty } from "antd";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
const { Content } = Layout;
|
||||
import { SaveOutlined } from "@ant-design/icons";
|
||||
import { SaveOutlined, FolderOpenFilled } from "@ant-design/icons";
|
||||
import SiderTree from "../components/side_tree/SideTree";
|
||||
import DosHeader from "../components/DosHeader/DosHeader";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
|
||||
const SelectNodeMap = {
|
||||
"dos_header": DosHeader,
|
||||
};
|
||||
|
||||
export default function MainPage() {
|
||||
const [treeData, setTreeData] = useState([]);
|
||||
const [filePath, setFilePath] = useState("");
|
||||
const [selectedKey, setSelectedKey] = useState("");
|
||||
const [nodeData, setNodeData] = useState([]);
|
||||
|
||||
const openFile = async () => {
|
||||
const file = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
});
|
||||
console.log("file:", file);
|
||||
if (file) {
|
||||
setFilePath(file);
|
||||
}
|
||||
};
|
||||
|
||||
const changeFile = (filePath: string) => {
|
||||
invoke("command_open_file", { filePath }).then(() => {
|
||||
invoke("command_get_file_pe_node_tree_data").then((res) => {
|
||||
console.log("tree nodes:", res);
|
||||
setTreeData(res as any);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSelect = (newSelectedKey) => {
|
||||
console.log("newSelectedKey", newSelectedKey);
|
||||
// TODO: 获取节点数据
|
||||
newSelectedKey &&
|
||||
invoke(`command_get_pe_data_${newSelectedKey}`).then((resData: any) => {
|
||||
console.log("resData", resData);
|
||||
// 格式化
|
||||
let ary = [];
|
||||
for (let key in resData) {
|
||||
ary.push(resData[key]);
|
||||
}
|
||||
console.log("ary", ary);
|
||||
setNodeData(ary);
|
||||
});
|
||||
setSelectedKey(newSelectedKey);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const unlisten = listen<{ paths: Array<string> }>(
|
||||
@@ -19,12 +63,6 @@ export default function MainPage() {
|
||||
const filePath = event.payload.paths[0];
|
||||
console.log("file path:", filePath);
|
||||
setFilePath(filePath);
|
||||
invoke("command_open_file", { filePath }).then(() => {
|
||||
invoke("command_get_file_pe_node_tree_data").then((res) => {
|
||||
console.log("tree nodes:", res);
|
||||
setTreeData(res as any);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
return () => {
|
||||
@@ -32,22 +70,52 @@ export default function MainPage() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (filePath) {
|
||||
changeFile(filePath);
|
||||
}
|
||||
}, [filePath]);
|
||||
|
||||
console.log("selectedKey", selectedKey);
|
||||
|
||||
return (
|
||||
<Layout className={styles.mainLayout}>
|
||||
<Flex className={styles.header}>
|
||||
<Button
|
||||
style={{
|
||||
marginRight: "10px",
|
||||
}}
|
||||
type="dashed"
|
||||
onClick={openFile}
|
||||
icon={<FolderOpenFilled></FolderOpenFilled>}
|
||||
>
|
||||
打开新文件
|
||||
</Button>
|
||||
<Button type="primary" icon={<SaveOutlined></SaveOutlined>}>
|
||||
保存
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<Flex
|
||||
style={{
|
||||
backgroundColor: "#e5e5e5",
|
||||
paddingBottom: "16px",
|
||||
}}
|
||||
>
|
||||
<Flex className={styles.sider}>
|
||||
<SiderTree
|
||||
treeData={treeData}
|
||||
defaultSelectedKey={treeData[0]?.key || ""}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</Flex>
|
||||
<Content>
|
||||
<DosHeader></DosHeader>
|
||||
{selectedKey && SelectNodeMap[selectedKey] ? (
|
||||
SelectNodeMap[selectedKey]({
|
||||
defaultData: nodeData,
|
||||
})
|
||||
) : (
|
||||
<Empty description={"请选择一个节点"} />
|
||||
)}
|
||||
</Content>
|
||||
</Flex>
|
||||
</Layout>
|
||||
|
||||
Reference in New Issue
Block a user