Browse Source

重复文件布局调整: 10%

John 1 year ago
parent
commit
ebfdd8ef0b

+ 3 - 1
package.json

@@ -8,9 +8,11 @@
     "start": "tauri dev",
     "build": "tsc && vite build",
     "preview": "vite preview",
-    "tauri": "tauri"
+    "tauri": "tauri",
+    "tauri:build": "tauri build"
   },
   "dependencies": {
+    "@ant-design/icons": "^5.3.7",
     "@tauri-apps/api": "^1.5.1",
     "antd": "^5.0.5",
     "clsx": "^1.2.1",

File diff suppressed because it is too large
+ 336 - 1058
pnpm-lock.yaml


+ 12 - 9
src-tauri/src/common/sqlite/rusqlite_utils.rs

@@ -1,18 +1,21 @@
 use anyhow::{anyhow, Result}; // 引入错误处理库
 use rusqlite::{
-    types::FromSql, // 用于将 SQLite 数据类型转换为 Rust 类型
+    types::FromSql,              // 用于将 SQLite 数据类型转换为 Rust 类型
     types::Value as SqliteValue, // SQLite 的值类型
     types::ValueRef::{Blob, Integer, Null, Real, Text}, // SQLite 值引用类型
-    Connection, Params, Row, ToSql, // 引入 SQLite 连接、参数、行和 ToSql 类型
+    Connection,
+    Params,
+    Row,
+    ToSql, // 引入 SQLite 连接、参数、行和 ToSql 类型
 };
 use serde_json::{Number, Value}; // 引入 JSON 处理库
 use std::{collections::HashMap, sync::Mutex}; // 引入 HashMap 和 Mutex
 
 // 查询单个值
 pub fn query_one_value<P, V>(connection: &Connection, sql: &str, p: P) -> Result<V>
-    where
-        P: Params, // 参数类型
-        V: FromSql, // 从 SQLite 值转换的类型
+where
+    P: Params,  // 参数类型
+    V: FromSql, // 从 SQLite 值转换的类型
 {
     // 准备 SQL 语句
     let mut stmt = connection.prepare(sql)?;
@@ -38,7 +41,7 @@ pub fn rusqlite_row_to_value(row: &Row<'_>, cnt: usize) -> Result<Vec<Value>> {
         let rusqlite_value = row.get_ref_unwrap(i);
         // 将 rusqlite 的值转换为 JSON 值
         let idns_value = match rusqlite_value {
-            Null => Value::Null, // 空值
+            Null => Value::Null,                                  // 空值
             Integer(i64_v) => Value::Number(Number::from(i64_v)), // 整数
             Real(f64_v) => Value::Number(Number::from_f64(f64_v).map_or(Number::from(0i64), |r| r)), // 浮点数
             Text(str_v) => Value::String(String::from_utf8(str_v.to_vec()).unwrap()), // 文本
@@ -61,8 +64,8 @@ pub fn rusqlite_row_to_map(_row: &Row<'_>, names: &Vec<String>) -> Result<HashMa
             Real(f64_v) => Value::Number(Number::from_f64(f64_v).map_or(Number::from(0i64), |r| r)), // 浮点数
             Integer(i64_v) => Value::Number(Number::from(i64_v)), // 整数
             Text(str_v) => Value::String(String::from_utf8(str_v.to_vec()).unwrap()), // 文本
-            Blob(v) => Value::Null, // 二进制数据(这里处理为 Null)
-            _ => Value::Null, // 其他类型处理为 Null
+            Blob(_v) => Value::Null,                              // 二进制数据(这里处理为 Null)
+            _ => Value::Null,                                     // 其他类型处理为 Null
         };
         row.insert(name.to_owned(), v); // 将列名和值添加到 HashMap 中
     }
@@ -85,6 +88,6 @@ pub fn value_to_rusqlite_value(json_value: &Value) -> Result<SqliteValue> {
             }
         }
         Value::String(string_v) => SqliteValue::Text(string_v.clone()), // 字符串
-        _ => SqliteValue::Null, // 其他类型处理为 Null
+        _ => SqliteValue::Null,                                         // 其他类型处理为 Null
     });
 }

+ 14 - 3
src-tauri/src/self_plugin/tauri_plugin_file/files.rs

@@ -54,11 +54,22 @@ fn read_files_in_directory(directory: &Path, files: &mut Vec<PathBuf>) -> Result
         for entry in entries {
             if let Ok(entry) = entry {
                 let path = entry.path();
-                if path.is_file() && filter_other_directory(path.display().to_string().as_str(), &[".obsidian", ".DS_Store"]) {
+                if path.is_file()
+                    && filter_other_directory(
+                        path.display().to_string().as_str(),
+                        &[".obsidian", ".DS_Store"],
+                    )
+                {
                     // 过滤文件
-                    println!("{}", path.display());
+                    // TODO 后续加上需要过滤的文件
+                    println!("59{}", path.display());
                     files.push(path.clone());
-                } else if path.is_dir() && filter_other_directory(path.display().to_string().as_str(), &["node_modules", ".git", ".obsidian", ".DS_Store"]) {
+                } else if path.is_dir()
+                    && filter_other_directory(
+                        path.display().to_string().as_str(),
+                        &["node_modules", ".git", ".obsidian", ".DS_Store"],
+                    )
+                {
                     // 过滤 目录
                     // println!("{}", path.display());
                     read_files_in_directory(&path, files)?;

+ 2 - 2
src/components/Table/CopyText.tsx

@@ -11,7 +11,7 @@ export function CopyText({
   width?: string | undefined;
   color?: string | undefined;
   ellipsisLine?: number;
-  name: string;
+  name: number|string;
 }) {
   const textRef = useRef<HTMLDivElement>(null);
   const [baseStyle, setBaseStyle] = useState<CSSProperties>({
@@ -47,7 +47,7 @@ export function CopyText({
   }, [ellipsisLine, width, color]);
 
   const content = (
-    <div ref={textRef} style={baseStyle} onClick={() => copyText(name)}>
+    <div ref={textRef} style={baseStyle} onClick={() => copyText(`${name}`)}>
       {name}
     </div>
   );

+ 207 - 0
src/pages/DuplicateFile/DuplicateFile copy

@@ -0,0 +1,207 @@
+import styles from "./DuplicateFile.module.less";
+// import { invoke } from "@tauri-apps/api/tauri";
+import { open } from "@tauri-apps/api/dialog";
+import { Col, Row, Button, message, Table, Select, Space } from "antd";
+import { appDataDir } from "@tauri-apps/api/path";
+import File from "@/plugins/tauri-plugin-file/file";
+import { useEffect, useState } from "react";
+// import { SQLite } from "@/plugins/tauri-plugin-sqlite";
+// import {select_history_init} from '@/databases/index'
+const { Option } = Select;
+import {
+  insertSeletedFileHistory,
+  insertSearchFiles,
+  get_info_by_path,
+  get_all_history,
+  get_list_by_sourceid,
+} from "@/services";
+import { insertSearchFilesPasamsType, historyListType } from "@/types/files";
+import { CopyText } from "@/components/Table/CopyText";
+
+export default function DuplicateFile() {
+  const [usePath, setUsePath] = useState<string>(
+    // "/Users/sysadmin/code/rust_project/tauri-app/diff_source"
+  );
+  const [fileList, setFileList] = useState<insertSearchFilesPasamsType[]>([]);
+  const [historyList, setHistoryList] = useState<historyListType[]>([]);
+
+  const columns = [
+    {
+      title: "ID",
+      dataIndex: "id",
+      key: "id",
+      render: (text: string, record: { id: string }) => (
+        <CopyText width="30px" color="#333" name={record.id}></CopyText>
+      ),
+    },
+    {
+      title: "路径",
+      dataIndex: "name",
+      width: 300,
+      key: "name",
+      render: (text: string, record: { name: string }) => (
+        <CopyText width="300px" ellipsisLine={1} color="#333" name={record.name}></CopyText>
+      ),
+    },
+    {
+      title: "哈希值",
+      dataIndex: "hash",
+      width: 200,
+      key: "hash",
+      render: (text: string, record: { hash: string }) => (
+        <CopyText ellipsisLine={1} name={record.hash}></CopyText>
+      ),
+    },
+    {
+      title: "操作",
+      width: 200,
+      dataIndex: "actions",
+      key: "actions",
+      fixed: "right",
+      render: (text: string, record: { name: string }) => (
+        <Space size="middle">
+          <Button type="link">配置规则</Button>
+          <Button type="link">删除记录</Button>
+        </Space>
+      ),
+    },
+  ];
+  async function sort() {
+    // 打开本地的系统目录,暂时不支持多选
+    const selected = await open({
+      directory: true,
+      multiple: false,
+      defaultPath: await appDataDir(),
+    });
+
+    if (selected && selected.length) {
+      setUsePath(`${selected}`);
+      // 最多记录 100 条用户操作的历史数据
+      const files = await File.getAllList(`${selected}`);
+      console.log(20202020, files);
+    }
+    // await invoke("file_sort", { path: selected });
+    // setFile([...fileStr, await invoke("file_sort", { path: selected })]);
+  }
+
+  // 存储用户的历史选择记录
+  async function opens() {
+    if(!usePath) return
+    const res = await insertSeletedFileHistory(usePath);
+    fileHistoryListInit();
+    if (res) {
+      // return message.error(`${res}`)
+    }
+    const [info, msg] = await get_info_by_path(`${usePath}`);
+    if (!info) {
+      return message.error(msg);
+    }
+    // 最多记录 100 条用户操作的历史数据
+    const files = await File.getAllList(usePath);
+    console.log(101, files);
+    
+
+    if (files.length) {
+      await Promise.allSettled(files.map(async (elm) => await insertSearchFiles({
+        // 组装数据
+        sourceId: (info as any).id,
+        path: elm,
+        type: await File.getType(elm),
+        name: elm,
+        hash: await File.getHash(elm),
+      })))
+      // files.forEach(async (elm) => {
+      //   const [res, msg] = await insertSearchFiles({
+      //     // 组装数据
+      //     sourceId: (info as any).id,
+      //     path: elm,
+      //     type: await File.getType(elm),
+      //     name: elm,
+      //     hash: await File.getHash(elm),
+      //   });
+      //   console.log(67, res, msg);
+      // });
+    }
+    getProcessedQueryData();
+  }
+  useEffect(() => {
+    fileHistoryListInit();
+    
+  }, []);
+
+  useEffect(() => {
+    getProcessedQueryData();
+  }, [usePath])
+
+  // 查询用户历史纪录
+  async function fileHistoryListInit() {
+    const res = await get_all_history();
+    setHistoryList(res);
+  }
+
+  const historyHandleChange = async (value: string) => {
+    console.log(`selected ${value}`);
+    await setFileList([]);
+    await setUsePath(value);
+    
+  };
+
+  // 获取处理好的查询数据数据,根据
+  async function getProcessedQueryData() {
+    console.log(102, usePath);
+    let [info, msg1] = await get_info_by_path(`${usePath}`);
+    console.log(147, info);
+
+    if (!info) return;
+    console.log(104, info);
+
+    const [res, msg2] = await get_list_by_sourceid((info as any).id);
+    console.log(109, res);
+    if (!res) return;
+    setFileList(res);
+
+    // const res = await get_all_history();
+    // setHistoryList(res);
+  }
+
+  return (
+    <div className={styles.DuplicateFileBox}>
+      <Row>
+        <Col>
+          <Button onClick={() => sort()}>选择文件路径</Button>
+        </Col>
+
+        <Col>设置文件路径</Col>
+      </Row>
+      <Row>已选择路径:{usePath}</Row>
+      <Row>
+        <Select style={{ width: "100%" }} onChange={historyHandleChange}>
+          {historyList.length > 0 &&
+            historyList.map((elm, index) => (
+              <Option key={elm.path}>{elm.path}</Option>
+            ))}
+        </Select>
+      </Row>
+      {usePath && (
+        <Row>
+          <Button onClick={() => opens()}>开始</Button>
+        </Row>
+      )}
+      {fileList.length > 0 && (
+        <div>
+          <br />
+          <Row>
+            <Space>
+              <Button type="link">Link Button</Button>
+              <Button type="link">Link Button</Button>
+            </Space>
+          </Row>
+          <br />
+          <Row>
+            <Table rowKey={"id"} dataSource={fileList} columns={columns} />;
+          </Row>
+        </div>
+      )}
+    </div>
+  );
+}

+ 8 - 0
src/pages/DuplicateFile/DuplicateFile.module.less

@@ -1,2 +1,10 @@
 .DuplicateFileBox {
+  padding: 24px;
+  box-sizing: border-box;
+
+  // .searchBox {
+  //   input {
+  //    box-shadow: none;
+  //   }
+  // }
 }

+ 37 - 131
src/pages/DuplicateFile/DuplicateFile.tsx

@@ -1,37 +1,28 @@
 import styles from "./DuplicateFile.module.less";
-// import { invoke } from "@tauri-apps/api/tauri";
-import { open } from "@tauri-apps/api/dialog";
-import { Col, Row, Button, message, Table, Select, Space } from "antd";
-import { appDataDir } from "@tauri-apps/api/path";
-import File from "@/plugins/tauri-plugin-file/file";
+import { Col, Row, Button, message, Table, Select, Space, Modal, Input } from "antd";
 import { useEffect, useState } from "react";
-// import { SQLite } from "@/plugins/tauri-plugin-sqlite";
-// import {select_history_init} from '@/databases/index'
 const { Option } = Select;
-import {
-  insertSeletedFileHistory,
-  insertSearchFiles,
-  get_info_by_path,
-  get_all_history,
-  get_list_by_sourceid,
-} from "@/services";
-import { insertSearchFilesPasamsType, historyListType } from "@/types/files";
+import {  historyListType, insertSearchFilesPasamsType } from "@/types/files";
 import { CopyText } from "@/components/Table/CopyText";
+import { PlusCircleOutlined } from '@ant-design/icons';
+
+const { Search } = Input;
 
 export default function DuplicateFile() {
   const [usePath, setUsePath] = useState<string>(
-    "/Users/sysadmin/code/rust_project/tauri-app/diff_source"
   );
-  const [fileList, setFileList] = useState<insertSearchFilesPasamsType[]>([]);
   const [historyList, setHistoryList] = useState<historyListType[]>([]);
+  const [fileList, setFileList] = useState<insertSearchFilesPasamsType[]>([])
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [fileInfo, setFileInfo] = useState<any>({})
 
   const columns = [
     {
       title: "ID",
       dataIndex: "id",
       key: "id",
-      render: (text: string, record: { id: string }) => (
-        <CopyText width="30px" color="#333" name={record.id}></CopyText>
+      render: (text: string, record: { id: number }) => (
+        <CopyText width="30px" color="#333"  name={record.id}></CopyText>
       ),
     },
     {
@@ -44,20 +35,18 @@ export default function DuplicateFile() {
       ),
     },
     {
-      title: "哈希值",
-      dataIndex: "hash",
-      width: 200,
-      key: "hash",
-      render: (text: string, record: { hash: string }) => (
-        <CopyText ellipsisLine={1} name={record.hash}></CopyText>
+      title: "时间",
+      dataIndex: "name",
+      width: 300,
+      key: "name",
+      render: (text: string, record: { name: string }) => (
+        <CopyText width="300px" ellipsisLine={1} color="#333" name={record.name}></CopyText>
       ),
     },
     {
       title: "操作",
-      width: 200,
       dataIndex: "actions",
       key: "actions",
-      fixed: "right",
       render: (text: string, record: { name: string }) => (
         <Space size="middle">
           <Button type="link">配置规则</Button>
@@ -66,123 +55,40 @@ export default function DuplicateFile() {
       ),
     },
   ];
-  async function sort() {
-    // 打开本地的系统目录,暂时不支持多选
-    const selected = await open({
-      directory: true,
-      multiple: false,
-      defaultPath: await appDataDir(),
-    });
 
-    if (selected && selected.length) {
-      setUsePath(`${selected}`);
-      // 最多记录 100 条用户操作的历史数据
-      const files = await File.getAllList(`${selected}`);
-      console.log(20202020, files);
-    }
-    // await invoke("file_sort", { path: selected });
-    // setFile([...fileStr, await invoke("file_sort", { path: selected })]);
-  }
 
-  // 存储用户的历史选择记录
-  async function opens() {
-    const res = await insertSeletedFileHistory(usePath);
-    fileHistoryListInit();
-    if (res) {
-      // return message.error(`${res}`)
-    }
-    const [info, msg] = await get_info_by_path(`${usePath}`);
-    if (!info) {
-      return message.error(msg);
-    }
-    // 最多记录 100 条用户操作的历史数据
-    const files = await File.getAllList(usePath);
+  function sort()  {
 
-    if (files.length) {
-      files.forEach(async (elm) => {
-        const [res, msg] = await insertSearchFiles({
-          // 组装数据
-          sourceId: (info as any).id,
-          path: elm,
-          type: await File.getType(elm),
-          name: elm,
-          hash: await File.getHash(elm),
-        });
-        // console.log(67, res, msg);
-      });
-    }
-    getProcessedQueryData();
   }
-  useEffect(() => {
-    fileHistoryListInit();
-    getProcessedQueryData();
-  }, []);
-
-  // 查询用户历史纪录
-  async function fileHistoryListInit() {
-    const res = await get_all_history();
-    setHistoryList(res);
-  }
-
-  const historyHandleChange = (value: string) => {
-    // console.log(`selected ${value}`);
-    setUsePath(value);
-  };
 
-  // 获取处理好的查询数据数据,根据
-  async function getProcessedQueryData() {
-    console.log(102, usePath);
-    let [info, msg1] = await get_info_by_path(`${usePath}`);
-    if (!info) return;
-    console.log(104, info);
+  function historyHandleChange() {
 
-    const [res, msg2] = await get_list_by_sourceid((info as any).id);
-    console.log(109, res);
-    if (!res) return;
-    setFileList(res);
-
-    // const res = await get_all_history();
-    // setHistoryList(res);
   }
 
+  function opens() {}
+  function handleOk() {}
+  function handleCancel() {}
+
   return (
     <div className={styles.DuplicateFileBox}>
-      <Row>
-        <Col>
-          <Button onClick={() => sort()}>选择文件路径</Button>
-        </Col>
-
-        <Col>设置文件路径</Col>
+     
+      <Modal title="添加目录" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
+        <Row align="middle">
+          <span>文件路径:</span>
+          <Row justify="space-around" align="middle">
+            <span>{fileInfo.path || ''}</span>
+            <Col><PlusCircleOutlined /></Col>
+          </Row>
+        </Row>
+      </Modal>
+      <Row className={styles.searchBox}>
+        <Col span={8}><Search placeholder="请输入" allowClear /></Col>
+        <Col offset={8} span={8} style={{textAlign: 'right'}}><Button type="primary" onClick={() => setIsModalOpen(true)}>新增</Button></Col>
       </Row>
-      <Row>已选择路径:{usePath}</Row>
+      <br />
       <Row>
-        <Select style={{ width: "100%" }} onChange={historyHandleChange}>
-          {historyList.length > 0 &&
-            historyList.map((elm, index) => (
-              <Option key={index}>{elm.path}</Option>
-            ))}
-        </Select>
+        <Table rowKey={"id"} dataSource={fileList} columns={columns} />
       </Row>
-      {usePath && (
-        <Row>
-          <Button onClick={() => opens()}>开始</Button>
-        </Row>
-      )}
-      {fileList.length > 0 && (
-        <div>
-          <br />
-          <Row>
-            <Space>
-              <Button type="link">Link Button</Button>
-              <Button type="link">Link Button</Button>
-            </Space>
-          </Row>
-          <br />
-          <Row>
-            <Table rowKey={"id"} dataSource={fileList} columns={columns} />;
-          </Row>
-        </div>
-      )}
     </div>
   );
 }

+ 11 - 9
src/services/file-service.ts

@@ -68,12 +68,12 @@ export async function insertSearchFiles({
         ":hash": hash,
       }
     );
-    return [true, ""];
+    return Promise.resolve([true, ""]);
   } catch (err) {
     if (err && `${err}`.indexOf("UNIQUE constraint failed") > -1) {
-      return [false, "当前路径重复"];
+      return Promise.resolve([false, "当前路径重复"]);
     }
-    return [false, err];
+    return Promise.resolve([false, err]);
   }
 }
 
@@ -85,18 +85,20 @@ export async function get_all_history(): Promise<historyListType[]>{
   );
 }
 
-export async function get_list_by_sourceid(sourceid: number):Promise<[insertSearchFilesPasamsType[]|false, string]>{
+export async function get_list_by_sourceid(sourceId: number):Promise<[insertSearchFilesPasamsType[]|false, string]>{
   try {
     await table_init(FILE_DB_PATH, "select_history");
     const DB = await SQLite.open(FILE_DB_PATH);
-    /* const res = await DB.queryWithArgs<Array<insertSearchFilesPasamsType>>(
-      "SELECT * FROM search_files WHERE sourceId = :sourceId",
-      { ":sourceId": sourceid }
-    ); */
     const res = await DB.queryWithArgs<Array<insertSearchFilesPasamsType>>(
+      "SELECT * FROM search_files WHERE sourceId = :sourceId",
+      { ":sourceId": sourceId }
+    );
+    console.log(969696, sourceId);
+    
+    /* const res = await DB.queryWithArgs<Array<insertSearchFilesPasamsType>>(
       "SELECT * FROM search_files WHERE sourceId = :sourceId GROUP BY hash HAVING COUNT(*) > 1",
       { ":sourceId": sourceid }
-    );
+    ); */
     console.log(3434, res);
     
     if(res.length) {

+ 2 - 2
src/style.css

@@ -53,7 +53,7 @@ h1 {
   text-align: center;
 }
 
-input,
+/* input,
 button {
   border-radius: 8px;
   border: 1px solid transparent;
@@ -65,7 +65,7 @@ button {
   background-color: #ffffff;
   transition: border-color 0.25s;
   box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
-}
+} */
 
 button {
   cursor: pointer;

+ 1 - 1
src/types/files.d.ts

@@ -1,5 +1,5 @@
 export type insertSearchFilesPasamsType = {
-    id?: number|string|any,
+    id: number,
     sourceId: number|string|any,
     path: string,
     type: string,

+ 1 - 1
tsconfig.json

@@ -10,7 +10,7 @@
     "strict": true,
     "forceConsistentCasingInFileNames": true,
     "module": "ESNext",
-    "moduleResolution": "bundler",
+    "moduleResolution": "node",
     "resolveJsonModule": true,
     "isolatedModules": true,
     "noEmit": true,

+ 1 - 1
tsconfig.node.json

@@ -2,7 +2,7 @@
   "compilerOptions": {
     "composite": true,
     "module": "ESNext",
-    "moduleResolution": "bundler",
+    "moduleResolution": "node",
     "allowSyntheticDefaultImports": true
   },
   "include": ["vite.config.ts"]

Some files were not shown because too many files changed in this diff