Răsfoiți Sursa

添加文件筛选规则时,补充类型

John 1 an în urmă
părinte
comite
f02c30d616

+ 17 - 17
package.json

@@ -13,25 +13,25 @@
   },
   "dependencies": {
     "@ant-design/icons": "^5.3.7",
-    "@tauri-apps/api": "^1.5.1",
-    "antd": "^5.0.5",
-    "clsx": "^1.2.1",
-    "react": "^18.2.0",
-    "react-dom": "^18.2.0",
-    "react-router": "^6.4.5",
-    "react-router-dom": "^6.4.5"
+    "@tauri-apps/api": "^1.5.6",
+    "antd": "^5.17.4",
+    "clsx": "^2.1.1",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
+    "react-router": "^6.23.1",
+    "react-router-dom": "^6.23.1"
   },
   "devDependencies": {
-    "@rollup/plugin-alias": "^4.0.2",
-    "@tauri-apps/cli": "^1.1.0",
-    "@types/node": "^18.7.10",
-    "@types/react": "^18.0.15",
-    "@types/react-dom": "^18.0.6",
-    "@vitejs/plugin-react": "^2.0.0",
-    "less": "^4.1.3",
-    "prettier": "^2.8.1",
-    "typescript": "^4.6.4",
-    "vite": "^3.0.2"
+    "@rollup/plugin-alias": "^5.1.0",
+    "@tauri-apps/cli": "^1.5.14",
+    "@types/node": "^20.13.0",
+    "@types/react": "^18.3.3",
+    "@types/react-dom": "^18.3.0",
+    "@vitejs/plugin-react": "^4.3.0",
+    "less": "^4.2.0",
+    "prettier": "^3.3.0",
+    "typescript": "^5.4.5",
+    "vite": "^5.2.12"
   },
   "volta": {
     "node": "22.2.0"

Fișier diff suprimat deoarece este prea mare
+ 444 - 341
pnpm-lock.yaml


+ 83 - 7
src/Router.tsx

@@ -1,27 +1,103 @@
 import * as React from "react";
-import { Routes, Route, Outlet, Link } from "react-router-dom";
+import { Routes, Route, Outlet, Link, createBrowserRouter } from "react-router-dom";
 import Layout from "@/components/Layout/Layout";
-import Home from "@/pages/Home/Home";
+// import Home from "@/pages/Home/Home";
 import About from "@/pages/About/About";
 import Finder from "@/pages/Finder/Finder";
 import Setting from "@/pages/Setting/Setting";
 import FileSort from "@/pages/FileSort/FileSort";
 import FileClear from "@/pages/FileClear/FileClear";
+import DuplicateFileIndex from "@/pages/DuplicateFile/Index";
 import DuplicateFile from "@/pages/DuplicateFile/DuplicateFile";
-export default function Router() {
+import DuplicateFileInfo from "@/pages/DuplicateFile/FileInfo";
+/* export default function Router() {
   return (
     <Routes>
       <Route path="/" element={<Layout />}>
-        <Route index element={<DuplicateFile />} />
+        <Route index element={<DuplicateFileIndex />} />
         <Route path={"about"} element={<About />} />
         <Route path={"finder"} element={<Finder />} />
         <Route path={"setting"} element={<Setting />} />
         <Route path={"home"} element={<Home />} />
         <Route path={"file-sort"} element={<FileSort />} />
         <Route path={"file-clear"} element={<FileClear />} />
-        <Route path={"duplicateFile"} element={<DuplicateFile />} />
-        {/*<Route index element={<Home />} />*/}
+        <Route path={"duplicate-file"} element={<DuplicateFileIndex />} >
+          <Route index element={<DuplicateFile />} />
+          <Route path={"info"} element={<DuplicateFileInfo />} />
+        </Route>
       </Route>
     </Routes>
   );
-}
+} */
+
+const router = createBrowserRouter([
+  {
+    path: "/",
+    id: "root",
+    element: <Layout />,
+    /* 
+    // loader: rootLoader,
+    每个路由都可以定义一个“加载器”函数,以便在路由元素呈现之前向路由元素提供数据。
+      loader: async () => {
+        return fakeDb.from("teams").select("*");
+      },
+    */
+    children: [
+      {
+        path: "",
+        element: <DuplicateFileIndex />,
+        children: [
+          {
+            path: "",
+            element: <DuplicateFile />,
+          },
+          {
+            path: "info/:fileId",
+            element: <DuplicateFileInfo />,
+          }
+        ]
+      },
+      {
+        path: "about",
+        element: <About />,
+      },
+      {
+        path: "finder",
+        element: <Finder />,
+      },
+      {
+        path: "setting",
+        element: <Setting />,
+      },
+      {
+        path: "file-sort",
+        element: <FileSort />,
+      },
+      {
+        path: "file-clear",
+        element: <FileClear />,
+      }
+      // {
+      //   path: "duplicate-file",
+      //   element: <DuplicateFileIndex />,
+      //   children: [
+      //     {
+      //       path: "",
+      //       element: <DuplicateFile />,
+      //     },
+      //     {
+      //       path: "info/:fileId",
+      //       element: <DuplicateFileInfo />,
+      //     }
+      //   ]
+      // },
+    ],
+  },
+], {
+  future: {
+    // Normalize `useNavigation()`/`useFetcher()` `formMethod` to uppercase
+    v7_normalizeFormMethod: true,
+  },
+});
+
+export default router

+ 0 - 1
src/components/Layout/Layout.tsx

@@ -45,7 +45,6 @@ export default function Layout() {
         unListen.push(ulf);
       })
       .catch(() => {});
-
     return () => {
       for (const ulf of unListen) ulf();
     };

+ 6 - 2
src/components/Menu/Menu.tsx

@@ -1,16 +1,20 @@
 import styles from "./Menu.module.less";
 import clsx from "clsx";
 import { useEffect, useState } from "react";
-import { useNavigate } from "react-router-dom";
+
+import { useParams, useLocation, useNavigate } from "react-router-dom";
 
 export default function Menu() {
   let navigate = useNavigate();
+  const location = useLocation();
   const [active, setActive] = useState<string>("");
   useEffect(() => {
     initMenu();
   }, []);
 
   async function initMenu() {
+    console.log(141414, location);
+    
     // const config = LogicalSize;
     // console.log({ LogicalSize: new LogicalSize() });
     // console.log(window);
@@ -30,7 +34,7 @@ export default function Menu() {
         },
         {
           label: "重复文件",
-          path: "/duplicateFile",
+          path: "/",
         },
       ],
     },

+ 33 - 1
src/config/file.ts

@@ -1 +1,33 @@
-export const FILE_DB_PATH = 'files.db'
+export const FILE_DB_PATH = 'files.db'
+
+
+
+// 所有的音频类型
+export const File_AUDIO_TYPE = [
+  'mp3', 'wav', 'aac', 'ogg', 'flac', 'alac', 'wma', 'm4a'
+];
+
+// 所有的视频类型
+export const File_VIDEO_TYPE = [
+  'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'm4v'
+];
+
+// 所有的文档类型
+export const File_DOCUMENT_TYPE = [
+  'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf', 'odt'
+];
+
+// 所有的图片类型
+export const File_IMAGE_TYPE = [
+  'jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'svg', 'webp', 'heif', 'ico'
+];
+
+// 所有的应用程序类型
+export const File_APPLICATION_TYPE = [
+  'exe', 'dmg', 'pkg', 'app', 'apk', 'bat', 'sh'
+];
+
+// 所有的压缩包类型
+export const File_COMPRESSED_TYPE = [
+  'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'arj', 'iso'
+];

+ 2 - 4
src/main.tsx

@@ -1,13 +1,11 @@
 import React from "react";
 import ReactDOM from "react-dom/client";
-import { BrowserRouter } from "react-router-dom";
+import { BrowserRouter, RouterProvider } from "react-router-dom";
 import Router from "./Router";
 import "./style.css";
 
 ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
   <React.StrictMode>
-    <BrowserRouter>
-      <Router />
-    </BrowserRouter>
+    <RouterProvider router={Router} />
   </React.StrictMode>
 );

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

@@ -7,4 +7,21 @@
   //    box-shadow: none;
   //   }
   // }
+  .iconEvent{
+    cursor: pointer;
+    color: var(--color-6);
+  }
 }
+
+// CSS Module样式
+.iconHover{
+  margin-left: 5px;
+  &:hover {
+    color: var(--color-6); /* 悬停时的颜色 */
+  }
+}
+.filePath {
+  color: var(--color-6); /* 悬停时的颜色 */ 
+  font-size: 14px;
+  margin-left: 12px;
+}

+ 159 - 7
src/pages/DuplicateFile/DuplicateFile.tsx

@@ -1,12 +1,17 @@
 import styles from "./DuplicateFile.module.less";
-import { Col, Row, Button, message, Table, Select, Space, Modal, Input } from "antd";
+import { Col, Row, Button, message, Table, Select, Space, Modal, Input, Checkbox, GetProp } from "antd";
 import { useEffect, useState } from "react";
 const { Option } = Select;
+import { open } from "@tauri-apps/api/dialog";
+import File from "@/plugins/tauri-plugin-file/file";
 import {  historyListType, insertSearchFilesPasamsType } from "@/types/files";
 import { CopyText } from "@/components/Table/CopyText";
-import { PlusCircleOutlined } from '@ant-design/icons';
+import { PlusCircleOutlined, RedoOutlined } from '@ant-design/icons';
+import { appDataDir } from "@tauri-apps/api/path";
+import { File_APPLICATION_TYPE, File_AUDIO_TYPE, File_COMPRESSED_TYPE, File_DOCUMENT_TYPE, File_IMAGE_TYPE, File_VIDEO_TYPE } from "@/config";
 
 const { Search } = Input;
+const { TextArea } = Input;
 
 export default function DuplicateFile() {
   const [usePath, setUsePath] = useState<string>(
@@ -55,10 +60,53 @@ export default function DuplicateFile() {
       ),
     },
   ];
+  const fileTypeList = [
+    {
+      name: '音频',
+      valus: File_AUDIO_TYPE
+    },
+    {
+      name: '视频',
+      valus: File_VIDEO_TYPE
+    },
+    {
+      name: '文档',
+      valus: File_DOCUMENT_TYPE
+    },
+    {
+      name: '图片',
+      valus: File_IMAGE_TYPE
+    },
+    {
+      name: '应用程序',
+      valus: File_APPLICATION_TYPE
+    },
+    {
+      name: '压缩包',
+      valus: File_COMPRESSED_TYPE
+    }
+  ]
 
 
-  function sort()  {
+  async function getDir()  {
+    // 打开本地的系统目录,暂时不支持多选
+    const selected = await open({
+      directory: true,
+      multiple: false,
+      defaultPath: await appDataDir(),
+    });
 
+    if (selected && selected.length) {
+      setFileInfo({
+        ...fileInfo,
+        path: selected
+      })
+      // setUsePath(`${selected}`);
+      // 最多记录 100 条用户操作的历史数据
+      // const files = await File.getAllList(`${selected}`);
+    }
+    // await invoke("file_sort", { path: selected });
+    // setFile([...fileStr, await invoke("file_sort", { path: selected })]);
   }
 
   function historyHandleChange() {
@@ -67,17 +115,121 @@ export default function DuplicateFile() {
 
   function opens() {}
   function handleOk() {}
-  function handleCancel() {}
+  function handleCancel() {
+    setFileInfo({});
+    setIsModalOpen(false);
+  }
+
+  const onTypesChange: GetProp<typeof Checkbox.Group, 'onChange'> = (checkedValues) => {
+    console.log('checked = ', checkedValues);
+    setFileInfo({
+      ...fileInfo,
+      checkedTypeValues: checkedValues
+    })
+  };
+
+
+  const onAddTypeChange = (types: string) => {
+    setFileInfo({
+      ...fileInfo,
+      addType: types
+    })
+  };
+  const onPassTypeChange = (types: string) => {
+    setFileInfo({
+      ...fileInfo,
+      passType: types
+    })
+  };
+
+  const checkboxAll = () => {
+    const otherTypes = ['其他所有带扩展名的类型', '其他所有无扩展名的类型', '指定', '排除'];
+    const checkedValues = fileTypeList.map(typeInfo => typeInfo.name)
+    setFileInfo({
+      ...fileInfo,
+      checkboxAll: !fileInfo.checkboxAll,
+      checkedTypeValues: fileInfo.checkboxAll ? []: [...checkedValues, ...otherTypes]
+    })
+  }
 
   return (
     <div className={styles.DuplicateFileBox}>
-     
       <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>
+            <span className={styles.filePath}>{fileInfo.path || ''}</span>
+            <Col>
+             {
+              fileInfo.path ?  <RedoOutlined className={styles.iconHover} onClick={() => getDir()}/> : <PlusCircleOutlined className={styles.iconHover} onClick={() => getDir()}/>
+             }
+            </Col>
+          </Row>
+        </Row>
+        <Row align="top">
+          <span>文件类型:</span>
+          <Row style={{
+            flex: 1,
+            padding: '2px 12px'
+          }}>
+            <Row style={{flex: 1}}><Checkbox onChange={() => checkboxAll() } value={'全选/不选'}>全选/不选</Checkbox></Row>
+             <Checkbox.Group onChange={onTypesChange} value={fileInfo.checkedTypeValues}>
+              {
+                fileTypeList.map((typeInfo) => (
+                  <Col span={7} >
+                    <Checkbox value={typeInfo.name}>{typeInfo.name}</Checkbox>
+                  </Col>
+                ))
+              }
+              <Col span={24} >
+                <Checkbox value={'其他所有带扩展名的类型'}>其他所有带扩展名的类型</Checkbox>
+              </Col>
+              <Col span={24} >
+                <Checkbox value={'其他所有无扩展名的类型'}>其他所有无扩展名的类型</Checkbox>
+              </Col>
+              <Col span={24}>
+                <Row style={{flex: 1, marginTop: '8px'}}>
+                  <Col span={4}>
+                    <Checkbox value={'指定'}>指定</Checkbox>
+                  </Col>
+                  <Col span={20}>
+                    <TextArea
+                      value={fileInfo.addType}
+                      onChange={(e) => onAddTypeChange(e.target.value)}
+                      placeholder="格式:.扩展名1.扩展名2…"
+                      autoSize={{ minRows: 3, maxRows: 5 }}
+                    />
+                  </Col>
+                </Row>
+              </Col>
+              <Col span={24}>
+                <Row style={{flex: 1, marginTop: '8px'}}>
+                  <Col span={4}>
+                    <Checkbox value={'排除'}>排除</Checkbox>
+                  </Col>
+                  <Col span={20}>
+                    <TextArea
+                      value={fileInfo.passType}
+                      onChange={(e) => onPassTypeChange(e.target.value)}
+                      placeholder="格式:.扩展名1.扩展名2…"
+                      autoSize={{ minRows: 3, maxRows: 5 }}
+                    />
+                  </Col>
+                </Row>
+              </Col>
+             </Checkbox.Group>
+            
+          </Row>
+        </Row>
+        <Row align="middle">
+          <span>文件大小:</span>
+          <Row justify="space-around" align="middle">
+            <span className={styles.filePath}>{fileInfo.path || ''}</span>
+            <Col>
+             {
+              fileInfo.path ?  <RedoOutlined className={styles.iconHover} onClick={() => getDir()}/> : <PlusCircleOutlined className={styles.iconHover} onClick={() => getDir()}/>
+             }
+            </Col>
           </Row>
         </Row>
       </Modal>

+ 0 - 0
src/pages/DuplicateFile/DuplicateFile copy → src/pages/DuplicateFile/DuplicateFileCopy


+ 3 - 0
src/pages/DuplicateFile/FileInfo.tsx

@@ -0,0 +1,3 @@
+export default function About() {
+  return <div>About1</div>;
+}

+ 8 - 0
src/pages/DuplicateFile/Index.tsx

@@ -0,0 +1,8 @@
+import { Outlet } from "react-router-dom";
+
+export default function DuplicateFile() {
+
+  return (
+    <Outlet />
+  );
+}

+ 11 - 106
src/style.css

@@ -1,107 +1,12 @@
 :root {
-  font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
-  font-size: 16px;
-  line-height: 24px;
-  font-weight: 400;
-
-  color: #0f0f0f;
-  background-color: #fafafa;
-
-  font-synthesis: none;
-  text-rendering: optimizeLegibility;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  -webkit-text-size-adjust: 100%;
-}
-
-.container {
-  margin: 0;
-  padding-top: 10vh;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  text-align: center;
-}
-
-.logo {
-  height: 6em;
-  padding: 1.5em;
-  will-change: filter;
-  transition: 0.75s;
-}
-
-.logo.tauri:hover {
-  filter: drop-shadow(0 0 2em #24c8db);
-}
-
-.row {
-  display: flex;
-  justify-content: center;
-}
-
-a {
-  font-weight: 500;
-  color: #646cff;
-  text-decoration: inherit;
-}
-
-a:hover {
-  color: #535bf2;
-}
-
-h1 {
-  text-align: center;
-}
-
-/* input,
-button {
-  border-radius: 8px;
-  border: 1px solid transparent;
-  padding: 0.6em 1.2em;
-  font-size: 1em;
-  font-weight: 500;
-  font-family: inherit;
-  color: #0f0f0f;
-  background-color: #ffffff;
-  transition: border-color 0.25s;
-  box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
-} */
-
-button {
-  cursor: pointer;
-}
-
-button:hover {
-  border-color: #396cd8;
-}
-
-input,
-button {
-  outline: none;
-}
-
-#greet-input {
-  margin-right: 5px;
-}
-
-@media (prefers-color-scheme: dark) {
-  :root {
-    color: #f6f6f6;
-    background-color: #2f2f2f;
-  }
-
-  a:hover {
-    color: #24c8db;
-  }
-
-  input,
-  button {
-    color: #ffffff;
-    background-color: #0f0f0f98;
-  }
-}
-
-body {
-  padding: 0;
-  margin: 0;
-}
+  --color-1: #f0f5ff;
+  --color-2: #d6e4ff;
+  --color-3: #adc6ff;
+  --color-4: #85a5ff;
+  --color-5: #597ef7;
+  --color-6: #2f54eb;
+  --color-7: #1d39c4;
+  --color-8: #10239e;
+  --color-9: #061178;
+  --color-10: #030852;
+}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff