CalculateDuplicateFiles.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. import {
  2. delSelectedFileHistory,
  3. get_all_history,
  4. get_info_by_id,
  5. get_info_by_path,
  6. insertSeletedFileHistory,
  7. updateSelectedFileHistory,
  8. insertSearchFiles,
  9. searchDuplicateFile,
  10. } from "@/services";
  11. import { useEffect, useState } from "react";
  12. import { useNavigate, useParams } from "react-router-dom";
  13. import {
  14. FileInfoType,
  15. insertSearchFilesPasamsType,
  16. stepsStatusType,
  17. } from "@/types/files";
  18. import { message } from "@tauri-apps/api/dialog";
  19. import styles from "./CalculateDuplicateFiles.module.less";
  20. import File from "@/plugins/tauri-plugin-file/file";
  21. import { Button, Col, Row, Steps } from "antd";
  22. import {
  23. LoadingOutlined,
  24. SolutionOutlined,
  25. UserOutlined,
  26. } from "@ant-design/icons";
  27. import { readDir, BaseDirectory } from "@tauri-apps/api/fs";
  28. import { fileTypeList } from "./config";
  29. import get_progress_by_sourceId, {
  30. get_list_by_sourceid,
  31. updateFileHsah,
  32. } from "@/services/file-service";
  33. import { resolve } from "path";
  34. export default function CalculateDuplicateFiles() {
  35. let { fileId } = useParams();
  36. let navigate = useNavigate();
  37. const [fileInfo, setFileInfo] = useState<FileInfoType>({});
  38. const [current, setCurrent] = useState(1);
  39. const [percent, setPercent] = useState(85);
  40. const [stepsStatus, setStepsStatus] = useState<stepsStatusType>({
  41. // 'wait' | 'process' | 'finish' | 'error';
  42. scanDir: "wait",
  43. fileOptions: "wait",
  44. duplicateFiles: "wait",
  45. done: "wait",
  46. });
  47. useEffect(() => {
  48. pageInit();
  49. }, []);
  50. const waittime = (time = 100) => {
  51. return new Promise((resolve) => {
  52. setTimeout(() => {
  53. resolve(0);
  54. }, time);
  55. });
  56. };
  57. async function pageInit() {
  58. if (fileId) {
  59. const [data, errorMsg] = await get_info_by_id(Number.parseInt(fileId));
  60. if (data && typeof data === "object") {
  61. setFileInfo(data);
  62. } else {
  63. await message(errorMsg, { title: "查询失败", type: "error" });
  64. }
  65. }
  66. }
  67. async function getFiles() {
  68. if (fileInfo.path) {
  69. console.log(4545);
  70. setStepsStatus({
  71. ...stepsStatus,
  72. fileOptions: "process",
  73. });
  74. //
  75. // const files = await File.getAllList(fileInfo.path);
  76. // console.log(34, files)
  77. // /Users/honghaitao/Downloads/PDF Expert Installer.app
  78. // const hash = await File.getHash('/Users/honghaitao/Downloads/PDF Expert Installer.app')
  79. // console.log(39, hash)
  80. }
  81. }
  82. async function scanDirAll() {
  83. // const aabb = await get_progress_by_sourceId(`${fileId}`);
  84. // console.log(737373, aabb);
  85. // return
  86. // navigate('/calculate-list/' + fileId)
  87. if (fileInfo.path) {
  88. // 扫描目录文件
  89. setStepsStatus({
  90. ...stepsStatus,
  91. scanDir: "process",
  92. });
  93. setCurrent(1);
  94. setPercent(0);
  95. // 排除指定的文件大小、或者筛选所有体量的文件
  96. const size = []; // 全部为空
  97. // 排除指定的文件类型、或者筛选所有的文件类型
  98. const types = await getTypeValuesByCheckedTypeValues(); // 全部为空
  99. const files = await File.getAllList({
  100. path: fileInfo.path,
  101. types,
  102. });
  103. setPercent(100);
  104. // console.log(636363, files);
  105. // 计算文件属性
  106. if (files.length) {
  107. setStepsStatus({
  108. ...stepsStatus,
  109. scanDir: "finish",
  110. fileOptions: "process",
  111. });
  112. // setCurrent(1)
  113. setPercent(0);
  114. // await files.reduce(async ())
  115. let fileIndex = -1;
  116. let allFilesLength = files.length;
  117. const result = await files.reduce(
  118. async (prevPromise: any, currentFile: any) => {
  119. // 等待上一个 Promise 完成
  120. await prevPromise;
  121. // 获取文件类型和哈希
  122. const fileInfo = await File.getInfo(currentFile);
  123. // const hash = await File.getHash(currentFile);
  124. const hash = "";
  125. fileIndex++;
  126. setPercent(Math.floor((fileIndex / allFilesLength) * 100));
  127. // await waittime(300);
  128. return insertSearchFiles({
  129. // 组装数据
  130. sourceId: `${fileId}`,
  131. path: currentFile,
  132. // type: await File.getType(elm),
  133. name: fileInfo.file_name,
  134. creation_time: fileInfo.creation_time,
  135. modified_time: fileInfo.modified_time,
  136. file_size: fileInfo.file_size,
  137. type: fileInfo.file_type,
  138. hash,
  139. });
  140. },
  141. Promise.resolve(0)
  142. );
  143. setPercent(100);
  144. await waittime(1000);
  145. // 计算文件具体内容
  146. const [allList, allListMsg] = await get_list_by_sourceid(`${fileId}`);
  147. console.log({
  148. allList,
  149. allListMsg,
  150. });
  151. if (allList) {
  152. let fileIndex = -1;
  153. let allFilesLength = allList.length;
  154. setStepsStatus({
  155. ...stepsStatus,
  156. scanDir: "finish",
  157. fileOptions: "finish",
  158. duplicateFiles: "process",
  159. });
  160. setPercent(0);
  161. console.log(173, allFilesLength);
  162. const allListresult = await allList
  163. .filter(
  164. (currentFile: insertSearchFilesPasamsType) => !currentFile.hash
  165. )
  166. .reduce(
  167. async (
  168. prevPromise: any,
  169. currentFile: insertSearchFilesPasamsType
  170. ) => {
  171. // 等待上一个 Promise 完成
  172. await prevPromise;
  173. // 获取文件类型和哈希
  174. // const type = await File.getType(currentFile);
  175. const hash = await File.getHash(currentFile.path);
  176. fileIndex++;
  177. await waittime();
  178. setPercent(Math.floor((fileIndex / allFilesLength) * 100));
  179. return updateFileHsah(currentFile.path, hash, `${fileId}`);
  180. },
  181. Promise.resolve(0)
  182. );
  183. await waittime(1000);
  184. setStepsStatus({
  185. ...stepsStatus,
  186. scanDir: "finish",
  187. fileOptions: "finish",
  188. duplicateFiles: "finish",
  189. });
  190. setPercent(100);
  191. } else {
  192. setStepsStatus({
  193. ...stepsStatus,
  194. scanDir: "finish",
  195. fileOptions: "finish",
  196. duplicateFiles: "finish",
  197. });
  198. setPercent(100);
  199. await waittime(2000);
  200. }
  201. setStepsStatus({
  202. ...stepsStatus,
  203. scanDir: "finish",
  204. fileOptions: "finish",
  205. duplicateFiles: "finish",
  206. done: "process",
  207. });
  208. setPercent(0);
  209. // 分析重复文件
  210. /* const searchDuplicateFileRes = await searchDuplicateFile({
  211. sourceId: fileId || "",
  212. }); */
  213. /*
  214. [
  215. {count: 6, hash: "3ba7bbfc03e3bed23bf066e2e9a6a5389dd33fd8637bc0220d9e6d642ccf5946", ids: "17,21,22,26,27,31", },
  216. {count: 6, hash: "75b7c31709e1529be7bec1c8a40ec98edbda146a09904a5ffad8685da966f90b", ids: "19,23,24,25,29,30", },
  217. {count: 3, hash: "7707b032ff2fea855a1bc22b7be536de13d3ad6d418cc7021893a97cf488e1a3", ids: "20,28,32", }
  218. ]
  219. [
  220. {
  221. count: 6,
  222. hash: "3ba7bbfc03e3bed23bf066e2e9a6a5389dd33fd8637bc0220d9e6d642ccf5946",
  223. paths: "/Users/sysadmin/Pictures/test/欧洲4_副本.jpeg,/Users/s…4.jpeg,/Users/sysadmin/Pictures/test/欧洲4_副本5.jpeg",
  224. ids: "17,21,22,26,27,31",
  225. times: "1718613803964,1718613804035,1718613804041,1718613804070,1718613804080,1718613804112"
  226. },
  227. {
  228. hash: "75b7c31709e1529be7bec1c8a40ec98edbda146a09904a5ffad8685da966f90b",
  229. times: "1718613804012,1718613804051,1718613804057,1718613804063,1718613804094,1718613804104",
  230. paths: "/Users/sysadmin/Pictures/test/欧洲2.jpeg,/Users/sysa…3.jpeg,/Users/sysadmin/Pictures/test/欧洲2_副本2.jpeg",
  231. ids: "19,23,24,25,29,30",
  232. count: 6
  233. }
  234. {
  235. times: "1718613804018,1718613804086,1718613804118",
  236. ids: "20,28,32",
  237. paths: "/Users/sysadmin/Pictures/test/欧洲1_副本2.jpeg,/Users/…洲1.jpeg,/Users/sysadmin/Pictures/test/欧洲1_副本.jpeg",
  238. count: 3,
  239. hash: "7707b032ff2fea855a1bc22b7be536de13d3ad6d418cc7021893a97cf488e1a3"
  240. }
  241. ]
  242. */
  243. /* console.log(747474, searchDuplicateFileRes);
  244. if (searchDuplicateFileRes[0]) {
  245. } */
  246. setStepsStatus({
  247. scanDir: "finish",
  248. fileOptions: "finish",
  249. duplicateFiles: "finish",
  250. done: "finish",
  251. });
  252. setPercent(100);
  253. await waittime(1000);
  254. navigate('/calculate-list/' + fileId)
  255. }
  256. }
  257. }
  258. async function getTypeValuesByCheckedTypeValues() {
  259. let types: any[] = [];
  260. if (!fileInfo.checkedTypeValues?.length || !fileInfo.checkedTypeValues)
  261. return [];
  262. const checkedTypeValues = `${fileInfo.checkedTypeValues}`?.split(",");
  263. fileTypeList.map((elm) => {
  264. if (checkedTypeValues.indexOf(elm.name) > -1) {
  265. types = types.concat(elm.valus);
  266. }
  267. });
  268. return types;
  269. }
  270. return (
  271. <div className={styles.CalculateDuplicateFiles}>
  272. <Row justify="start" align="middle">
  273. <Col>
  274. <div className={styles.pageTitle} onClick={() => getFiles()}>
  275. 路径: {fileInfo.path}
  276. </div>
  277. </Col>
  278. <Col>
  279. <Button type="primary" onClick={() => scanDirAll()}>
  280. 开始
  281. </Button>
  282. </Col>
  283. </Row>
  284. <div className={styles.stepsBox}>
  285. <Steps
  286. current={current}
  287. percent={percent}
  288. labelPlacement="horizontal"
  289. direction="vertical"
  290. items={[
  291. {
  292. title: "扫描目录文件",
  293. status: stepsStatus.scanDir,
  294. },
  295. {
  296. title: "计算文件属性",
  297. status: stepsStatus.fileOptions,
  298. },
  299. {
  300. title: "分析重复文件",
  301. status: stepsStatus.duplicateFiles,
  302. },
  303. {
  304. title: "完成",
  305. status: stepsStatus.done,
  306. },
  307. ]}
  308. />
  309. </div>
  310. </div>
  311. );
  312. }