import { StudentCheckItem, AllCheckFilter } from "./types"; import { useAppStore } from "@/store"; import { randomCode } from "@/utils/tool"; import axios from "axios"; import Papa from "papaparse"; const appStore = useAppStore(); export const allCheckList = async ( params: AllCheckFilter ): Promise => { // if (!params.isCheck && !params.imageName) { // return Promise.resolve([]); // } const fname = params.isCheck ? `check-${params.menuKey}` : "success"; const url = `${appStore.serverUrl}/${fname}.csv?${randomCode()}`; let students: StudentCheckItem[] = await fetchAndParseData(url).catch( () => [] ); if (params.imageName) { students = students.filter((item) => item.imageName === params.imageName); } // console.log(students); const cacheList = await fetchCacheList(); const data = (students || []).map((item) => { return { ...item, checked: cacheList.includes(item.imageName), }; }); // console.log(data); return Promise.resolve(data); }; export const getExamNumberInfo = async ( imageName: string ): Promise => { const url = `${appStore.serverUrl}/cache/${imageName}.csv?${randomCode()}`; const students = await fetchAndParseData(url).catch(() => []); if (!students || students.length === 0) { return Promise.resolve(null); } const item = students[0]; const questions = (item.smda ? item.smda.split("|") : []).map((item) => item.trim().replace(/[\.\?]/g, "#") ); return Promise.resolve({ ...students[0], questions }); }; export const fetchCacheList = async () => { try { const res = await axios.get(`${appStore.serverUrl}/cache/`); const parser = new DOMParser(); const doc = parser.parseFromString(res.data, "text/html"); const links = Array.from(doc.querySelectorAll("a")) .map((a) => a.getAttribute("href")) .filter((href) => href && /\/cache\/.*\.csv$/.test(href)) .map((href) => { // Extract filename without extension const parts = href.split("/"); const filenameWithExtension = parts[parts.length - 1]; return filenameWithExtension.replace(".csv", ""); }); // console.log("缓存文件列表:", links); return links; // Return the extracted list } catch (err) { return []; console.error("获取失败:", err); } }; export const saveCheck = async (data: string[][], filename): Promise => { const url = `${appStore.serverUrl}/upload?path=/cache`; return uploadCsvData(url, data, filename); }; /** * 请求给定远程地址,获取文件流数据(CSV 或 JSON),并解析其内容。 * @param remoteUrl 远程文件地址 * @returns 解析后的数据 */ export const fetchAndParseData = async (remoteUrl: string): Promise => { try { const response = await axios.get(remoteUrl, { responseType: "text", // Fetch as text to handle both JSON and CSV }); const contentType = response.headers["content-type"]; let data; if (contentType && contentType.includes("application/json")) { // Try parsing as JSON try { data = JSON.parse(response.data); } catch (error) { console.error("Error parsing JSON:", error); throw new Error("Failed to parse JSON data"); } } else if (contentType && contentType.includes("text/csv")) { // Try parsing as CSV return new Promise((resolve, reject) => { Papa.parse(response.data, { header: true, // Assume header row skipEmptyLines: true, complete: (results) => { resolve(results.data); }, error: (error: any) => { console.error("Error parsing CSV:", error); reject(new Error("Failed to parse CSV data")); }, }); }); } else { // Attempt to guess format or throw error try { // Try JSON first data = JSON.parse(response.data); } catch (jsonError) { // If JSON fails, try CSV return new Promise((resolve, reject) => { Papa.parse(response.data, { header: true, skipEmptyLines: true, complete: (results) => { if (results.errors.length > 0) { console.error("CSV parsing errors:", results.errors); // If CSV parsing also has issues, reject reject( new Error( "Failed to parse data: Unknown format or invalid content" ) ); } else { resolve(results.data); } }, error: (csvError: any) => { console.error("Error parsing CSV:", csvError); reject( new Error( "Failed to parse data: Could not determine format or invalid content" ) ); }, }); }); } } return data; } catch (error) { console.error("Error fetching or parsing data:", error); throw new Error("Failed to fetch or parse data from the remote URL"); } }; /** * 构建 CSV 文件内容并上传到指定 URL。 * 注意:渲染进程中上传成功后,会触发一个重定向,想要不处理重定向只能在主进程中处理上传 * @param uploadUrl 上传的目标 URL * @param data 要转换为 CSV 并上传的数据数组 * @param filename 上传的文件名 * @returns 上传结果 */ export const uploadCsvData = async ( uploadUrl: string, data: string[][], filename: string = "upload.csv" ): Promise => { try { // Convert data array to CSV string const csvString = Papa.unparse(data); // Send data to main process for upload // Assuming 'window.electron.ipcRenderer.invoke' is available for IPC // The channel name 'upload-csv' is an example; it should match the handler in the main process. const result = await window.electronApi.uploadCsvData({ uploadUrl, csvString, filename, }); if (!result.error) return result.data; throw new Error(result.message || "Failed to send CSV data for upload"); } catch (error) { console.error("Error preparing or sending CSV data for upload:", error); // It's good practice to re-throw or handle the error appropriately // For instance, if the error is already an Error object with a message, just re-throw it if (error instanceof Error) { throw error; } throw new Error("Failed to prepare or send CSV data for upload"); } };