123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- <template>
- <div class="title title_grey cl">
- <h2>图片下载中 …</h2>
- </div>
- <div class="progress-box">
- <h3>正在下载图片,请耐心等候 ~</h3>
- <div class="progress">
- <a-progress :percent="Math.round((finishedCount / totalCount) * 100)" />
- </div>
- <p>
- 已下载图片:<b>{{ finishedCount }}</b> / 错误图片:<b>{{ errorCount }}</b>
- / 全部图片:<b>{{ totalCount }}</b>
- </p>
- </div>
- </template>
- <script setup lang="ts">
- import { store } from "@/store";
- import { onMounted, onUnmounted, ref } from "vue";
- import { Modal } from "ant-design-vue";
- import { useRouter } from "vue-router";
- const router = useRouter();
- import { countStudents, getPackages, getStudents } from "@/api/api";
- import { httpApp } from "@/plugins/axiosApp";
- import mustache from "mustache";
- async function getImageDim(
- blob: Blob
- ): Promise<[width: number, height: number]> {
- return new Promise((res) => {
- const img = new Image();
- img.src = URL.createObjectURL(blob);
- img.onload = () => {
- URL.revokeObjectURL(img.src);
- // console.log(img.width);
- res([img.width, img.height]);
- };
- });
- }
- // cache images
- async function cacheImages(urls: string) {
- let allPromiseCount = 0;
- let settledPromiseCount = 0;
- const MAX_CONCURRENT = 6;
- async function sleep() {
- if (allPromiseCount - settledPromiseCount >= MAX_CONCURRENT) {
- console.log("sleep because cache images thread is full");
- await new Promise((res) => setTimeout(res, 300));
- await sleep();
- }
- }
- for (const url of urls) {
- allPromiseCount++;
- await sleep();
- // console.log(url);
- httpApp
- .get(url, {
- responseType: "blob",
- headers: {
- // 怀疑 electron 有问题,这里没生效
- "Cache-Control": "no-cache",
- },
- })
- .then(() => console.debug("downloaded ", url))
- .catch((e) => {
- console.log(e, "cache error");
- })
- .finally(() => {
- settledPromiseCount++;
- });
- }
- }
- const totalCount = ref(0);
- let finishedCount = ref(0);
- let errorCount = ref(0);
- let students = [];
- const config = store.pageInputs["/image-download"];
- // console.log("config::", config);
- onMounted(async () => {
- const storePassedToNodeJs = JSON.parse(JSON.stringify(store));
- const color = storePassedToNodeJs.config.watermark.color;
- const nextColor = storePassedToNodeJs.config.watermark.nextColor;
- // const otherColor = storePassedToNodeJs.config.watermark.otherColor;
- const otherColor = "#ddd";
- try {
- if (config.type === "1") {
- console.log("download start ", Date.now());
- const res = await countStudents(store.env.examId, {
- upload: true,
- withSheetUrl: true,
- withScoreDetail: config.watermark,
- withMarkTrack: config.watermark,
- withGroupScoreTrack: config.watermark && config.trackMode,
- examNumberIn: config.examNumber ?? "",
- subjectCodeIn: config.subjectCode ?? "",
- });
- totalCount.value = res.data;
- let totalImageDownloadTime = 0;
- for (
- let pageNumber = 0;
- pageNumber * 10 < totalCount.value;
- pageNumber++
- ) {
- const resStudents = await getStudents(
- store.env.examId,
- pageNumber + 1,
- 10,
- {
- upload: true,
- withSheetUrl: true,
- withScoreDetail: config.watermark,
- withMarkTrack: config.watermark,
- withGroupScoreTrack: config.watermark && config.trackMode === "1",
- examNumberIn: config.examNumber ?? "",
- subjectCodeIn: config.subjectCode ?? "",
- sliceConfigFix: config.watermark && config.trackMode === "2",
- }
- );
- students = resStudents.data;
- const urls = students.reduce(
- (accumulator, stu) => accumulator.concat(stu.sheetUrls),
- []
- );
- // cacheImages(urls);
- for (const student of students) {
- let allTags = Object.values(student.tags || {})
- .filter((x) => !!x)
- .flat()
- .filter((v: any) => v.userId != 0);
- allTags.forEach((item: any) => {
- if (
- allTags.find((v: any) => {
- return (
- v.groupNumber == item.groupNumber && v.userId != item.userId
- );
- })
- ) {
- item.hide = true;
- } else {
- item.hide = false;
- }
- if (
- allTags.find((v: any) => {
- return (
- v.groupNumber == item.groupNumber &&
- v.userRole &&
- v.userRole !== "MARKER" &&
- (item.userRole === "MARKER" || !item.userRole)
- );
- })
- ) {
- item.forceHide = true;
- }
- });
- // allTags.sort((a: any, b: any) => {
- // return a.userId - b.userId;
- // });
- let colorMap: any = {};
- let headerColorMap: any = {};
- for (let i = 0; i < allTags.length; i++) {
- const tag: any = allTags[i];
- const { groupNumber } = tag;
- if (tag.userRole && tag.userRole !== "MARKER") {
- if (!headerColorMap[groupNumber + ""]) {
- headerColorMap[groupNumber + ""] = {};
- headerColorMap[groupNumber + ""][tag.userId + ""] = "#008000";
- continue;
- } else {
- headerColorMap[groupNumber + ""][tag.userId + ""] = "#008000";
- continue;
- }
- }
- if (!colorMap[groupNumber + ""]) {
- colorMap[groupNumber + ""] = {};
- colorMap[groupNumber + ""][tag.userId + ""] = color;
- } else {
- let targetGroupObjKeys = Object.keys(colorMap[groupNumber + ""]);
- const len = targetGroupObjKeys.length;
- if (len == 1) {
- if (!targetGroupObjKeys.includes(tag.userId + "")) {
- colorMap[groupNumber + ""][tag.userId + ""] = nextColor;
- } else {
- continue;
- }
- } else if (len > 1) {
- if (!targetGroupObjKeys.includes(tag.userId + "")) {
- colorMap[groupNumber + ""][tag.userId + ""] = otherColor;
- } else {
- continue;
- }
- }
- // let c = len === 1 ? nextColor : otherColor;
- // colorMap[groupNumber + ""][tag.userId + ""] = c;
- }
- }
- console.log("allTags:", allTags);
- // console.log("colorMap:", colorMap);
- let resultImgList: any[] = [];
- let sheetUrlsLength = (student.sheetUrls || []).length;
- for (const sheetUrl of student.sheetUrls) {
- if (stopSignal) return;
- try {
- const index = student.sheetUrls.indexOf(sheetUrl);
- student.index = index + 1;
- student.examId = store.env.examId;
- // const filePath = window.electron.join(
- // config.dir,
- // mustache.render(config.template, student)
- // );
- const filePath = [
- config.dir,
- mustache.render(config.template, student),
- ];
- if (config.append && window.electron.existsImage(filePath)) {
- console.log(filePath + " already exists");
- // 执行到这里时,可能图片已经cache了
- urls.splice(urls.indexOf(sheetUrl), 1);
- // console.log(urls);
- continue;
- }
- console.debug("start ", sheetUrl);
- const imageDownloadStartTime = Date.now();
- const imageRes = await httpApp.get(sheetUrl, {
- responseType: "blob",
- headers: {
- "Cache-Control": "no-cache",
- },
- });
- totalImageDownloadTime += Date.now() - imageDownloadStartTime;
- const [width, height] = await getImageDim(imageRes.data);
- const arrayBuffer = await imageRes.data.arrayBuffer();
- // console.log(imageRes.data);
- // console.log(await imageRes.data.arrayBuffer());
- // console.log(new Uint8Array(await imageRes.data.arrayBuffer()));
- let onlyUsePdf = config.pdf == "2";
- console.log("colorMap:", colorMap);
- let fileLocation = await window.electron.addWatermark(
- storePassedToNodeJs,
- arrayBuffer,
- width,
- height,
- filePath,
- student,
- index + 1,
- config.trackMode,
- config.x,
- config.y,
- colorMap,
- headerColorMap,
- onlyUsePdf
- );
- resultImgList.push(fileLocation);
- } catch (error) {
- window.electron.errorLogger(student, sheetUrl, error);
- errorCount.value += 1;
- if (config.failover) {
- throw error;
- } else {
- console.log(student, error);
- continue;
- }
- }
- }
- // 下载完一个学生
- finishedCount.value += 1;
- if (
- resultImgList.length === sheetUrlsLength &&
- (config.pdf == "2" || config.pdf == "3")
- ) {
- let imgName = "";
- if (config.template.lastIndexOf("/") > -1) {
- imgName = config.template.slice(
- config.template.lastIndexOf("/") + 1
- );
- } else {
- imgName = config.template;
- }
- let n = imgName.slice(0, imgName.lastIndexOf("."));
- let pdfName = n
- .match(/{{.*?}}/g)
- ?.map((item: any) => {
- return item.replace("{{", "").replace("}}", "");
- })
- .filter((v) => !!v)
- .map((item: any) => {
- return item === "index" ? "" : student[item];
- })
- .filter((v) => !!v)
- .join("-");
- window.electron.saveToPDF(resultImgList, [
- config.dir,
- `/pdfs/${store.env.examId}/${student.subjectCode}/${pdfName}.pdf`,
- ]);
- }
- }
- }
- console.log(
- "all end at ",
- Date.now(),
- " totalImageDownloadTime: ",
- totalImageDownloadTime
- );
- } else if (config.type === "2") {
- await processPackage();
- }
- const modal = Modal.success({});
- modal.update({
- title: "图片下载完成",
- content: "完成",
- onOk: () => router.back(),
- });
- } catch (error) {
- const modal = Modal.error({});
- console.log(error);
- modal.update({
- title: "图片下载出错",
- content: error.message || error,
- onOk: () => router.back(),
- });
- }
- });
- async function processPackage() {
- const res = await getPackages(store.env.examId, true, true);
- const array = res.data;
- totalCount.value = array.length;
- const urls = array.reduce((accumulator, p) => accumulator.concat(p.urls), []);
- // cacheImages(urls);
- for (let i = 0; i < array.length; i++) {
- const p = array[i];
- p.examId = store.env.examId;
- for (let i = 0; i < p.urls.length; i++) {
- if (stopSignal) return;
- try {
- const index = i + 1;
- p.index = index;
- const filePath = [config.dir, mustache.render(config.template, p)];
- if (config.append && window.electron.existsImage(filePath)) {
- console.log(filePath + " already exists");
- urls.splice(urls.indexOf(p.urls[i]), 1);
- continue;
- }
- const imageRes = await httpApp.get(p.urls[i], {
- responseType: "blob",
- });
- await window.electron.saveImage(
- JSON.parse(JSON.stringify(store)),
- await imageRes.data.arrayBuffer(),
- filePath
- );
- } catch (error) {
- window.electron.errorLogger2(p.urls[i], error);
- errorCount.value += 1;
- if (config.failover) {
- throw error;
- } else {
- console.log(p, error);
- continue;
- }
- }
- }
- finishedCount.value += 1;
- }
- }
- let stopSignal = false;
- onUnmounted(() => (stopSignal = true));
- </script>
|