فهرست منبع

1.3.1迭代开发

刘洋 2 سال پیش
والد
کامیت
c377e47e99
6فایلهای تغییر یافته به همراه129 افزوده شده و 15 حذف شده
  1. 4 2
      config.json
  2. 21 0
      src/api/api.ts
  3. 35 0
      src/features/Image/Image.vue
  4. 27 10
      src/features/ImageDownload/ImageDownload.vue
  5. 38 3
      src/lib/watermark.ts
  6. 4 0
      src/types/index.ts

+ 4 - 2
config.json

@@ -13,12 +13,14 @@
     "watermark": {
     "watermark": {
         "fontFile": "font/simsun.ttf",
         "fontFile": "font/simsun.ttf",
         "fontSize": 30,
         "fontSize": 30,
-        "color": "#ff0000"
+        "color": "#ff0000",
+        "nextColor": "#0000ff",
+        "otherColor": "#008000"
     },
     },
     "logger": {
     "logger": {
         "level": "info"
         "level": "info"
     },
     },
-    "imagemagickDev": "/usr/local/bin/",
+    "imagemagickDev": "C:\\ImageMagick-7.1.0-Q16\\",
     "openDevTools": false,
     "openDevTools": false,
     "servers": [
     "servers": [
         {
         {

+ 21 - 0
src/api/api.ts

@@ -36,6 +36,27 @@ export function getStudents(
   return httpApp.post("/api/exam/students", new URLSearchParams(form));
   return httpApp.post("/api/exam/students", new URLSearchParams(form));
 }
 }
 
 
+export function getStudentsWithSlice(
+  examId: number,
+  pageNumber: number,
+  pageSize: number,
+  params: any
+) {
+  const form = {
+    examId: examId,
+    pageNumber: pageNumber,
+    pageSize: pageSize,
+  };
+  if (params != undefined) {
+    for (const key in params) {
+      if (params[key] && params[key] != "") {
+        form[key] = params[key];
+      }
+    }
+  }
+  return httpApp.post("/api/exam/students/slice", new URLSearchParams(form));
+}
+
 export function countStudents(examId: number, params) {
 export function countStudents(examId: number, params) {
   params = params || {};
   params = params || {};
   params.examId = examId;
   params.examId = examId;

+ 35 - 0
src/features/Image/Image.vue

@@ -65,6 +65,27 @@
         </td>
         </td>
       </tr>
       </tr>
       <template v-if="type === '1'">
       <template v-if="type === '1'">
+        <tr id="number-of-files">
+          <th>文件分批存放:</th>
+          <td>
+            <div class="input-radio">
+              <a-radio-group name="radioGroup" v-model:value="fileNumberSplit">
+                <a-radio :value="true">是</a-radio>
+                <a-radio :value="false">否</a-radio>
+              </a-radio-group>
+            </div>
+          </td>
+        </tr>
+        <tr v-if="fileNumberSplit">
+          <th></th>
+          <td style="padding-top: 0">
+            <div class="number-limit">
+              每个子文件夹存放&nbsp;
+              <a-input-number v-model:value="fileNumberLimits" :min="1" />
+              &nbsp;张图片
+            </div>
+          </td>
+        </tr>
         <tr id="watermark-select">
         <tr id="watermark-select">
           <th>添加分数水印:</th>
           <th>添加分数水印:</th>
           <td>
           <td>
@@ -188,6 +209,8 @@ let template = ref("");
 let dir = ref("");
 let dir = ref("");
 let append = ref(false);
 let append = ref(false);
 let failover = ref(true);
 let failover = ref(true);
+let fileNumberSplit = ref(false);
+let fileNumberLimits = ref(null);
 let watermark = ref(true);
 let watermark = ref(true);
 let trackMode = ref("");
 let trackMode = ref("");
 let examNumber = ref("");
 let examNumber = ref("");
@@ -202,6 +225,8 @@ if (config) {
   dir.value = config.dir;
   dir.value = config.dir;
   append.value = config.append;
   append.value = config.append;
   failover.value = config.failover;
   failover.value = config.failover;
+  fileNumberSplit.value = config.fileNumberSplit;
+  fileNumberLimits.value = config.fileNumberLimits;
   watermark.value = config.watermark;
   watermark.value = config.watermark;
   trackMode.value = config.trackMode;
   trackMode.value = config.trackMode;
   examNumber.value = config.examNumber || "";
   examNumber.value = config.examNumber || "";
@@ -248,6 +273,10 @@ const start = (e: MouseEvent) => {
     message.info("请填写图片转存规则");
     message.info("请填写图片转存规则");
     return false;
     return false;
   }
   }
+  if (fileNumberSplit.value && !fileNumberLimits.value) {
+    message.info("请填写每个文件夹存放的图片数量");
+    return false;
+  }
   if (type.value === "1") {
   if (type.value === "1") {
     if (!x.value) {
     if (!x.value) {
       message.info("请填写水印起始位置(横向)");
       message.info("请填写水印起始位置(横向)");
@@ -269,6 +298,8 @@ const start = (e: MouseEvent) => {
     dir: dir.value.trim(),
     dir: dir.value.trim(),
     append: append.value,
     append: append.value,
     failover: failover.value,
     failover: failover.value,
+    fileNumberSplit: fileNumberSplit.value,
+    fileNumberLimits: fileNumberLimits.value,
     watermark: watermark.value,
     watermark: watermark.value,
     trackMode: trackMode.value,
     trackMode: trackMode.value,
     examNumber: examNumber.value.trim(),
     examNumber: examNumber.value.trim(),
@@ -385,4 +416,8 @@ const mouseUpHandler = () => {
 .water-mark {
 .water-mark {
   position: absolute;
   position: absolute;
 }
 }
+.number-limit {
+  display: flex;
+  align-items: center;
+}
 </style>
 </style>

+ 27 - 10
src/features/ImageDownload/ImageDownload.vue

@@ -20,9 +20,10 @@ import { onMounted, onUnmounted, ref } from "vue";
 import { Modal } from "ant-design-vue";
 import { Modal } from "ant-design-vue";
 import { useRouter } from "vue-router";
 import { useRouter } from "vue-router";
 const router = useRouter();
 const router = useRouter();
-import { getStudents, countStudents, getPackages } from "@/api/api";
+import { countStudents, getPackages, getStudentsWithSlice } from "@/api/api";
 import { httpApp } from "@/plugins/axiosApp";
 import { httpApp } from "@/plugins/axiosApp";
 import mustache from "mustache";
 import mustache from "mustache";
+const path = require("path");
 
 
 async function getImageDim(
 async function getImageDim(
   blob: Blob
   blob: Blob
@@ -79,6 +80,7 @@ let errorCount = ref(0);
 let students = [];
 let students = [];
 
 
 const config = store.pageInputs["/image-download"];
 const config = store.pageInputs["/image-download"];
+console.log("config::", config);
 onMounted(async () => {
 onMounted(async () => {
   const storePassedToNodeJs = JSON.parse(JSON.stringify(store));
   const storePassedToNodeJs = JSON.parse(JSON.stringify(store));
   try {
   try {
@@ -95,19 +97,19 @@ onMounted(async () => {
       });
       });
       totalCount.value = res.data;
       totalCount.value = res.data;
       let totalImageDownloadTime = 0;
       let totalImageDownloadTime = 0;
-
+      let curFileIndex = 0;
       for (
       for (
         let pageNumber = 0;
         let pageNumber = 0;
         pageNumber * 10 < totalCount.value;
         pageNumber * 10 < totalCount.value;
         pageNumber++
         pageNumber++
       ) {
       ) {
-        const resStudents = await getStudents(
+        const resStudents = await getStudentsWithSlice(
           store.env.examId,
           store.env.examId,
           pageNumber + 1,
           pageNumber + 1,
           10,
           10,
           {
           {
             upload: true,
             upload: true,
-            withSheetUrl: true,
+            withSliceUrl: true,
             withScoreDetail: config.watermark,
             withScoreDetail: config.watermark,
             withMarkTrack: config.watermark,
             withMarkTrack: config.watermark,
             withGroupScoreTrack: config.watermark && config.trackMode === "1",
             withGroupScoreTrack: config.watermark && config.trackMode === "1",
@@ -118,16 +120,16 @@ onMounted(async () => {
         students = resStudents.data;
         students = resStudents.data;
 
 
         const urls = students.reduce(
         const urls = students.reduce(
-          (accumulator, stu) => accumulator.concat(stu.sheetUrls),
+          (accumulator, stu) => accumulator.concat(stu.sliceUrls),
           []
           []
         );
         );
         cacheImages(urls);
         cacheImages(urls);
 
 
         for (const student of students) {
         for (const student of students) {
-          for (const sheetUrl of student.sheetUrls) {
+          for (const sheetUrl of student.sliceUrls) {
             if (stopSignal) return;
             if (stopSignal) return;
             try {
             try {
-              const index = student.sheetUrls.indexOf(sheetUrl);
+              const index = student.sliceUrls.indexOf(sheetUrl);
               student.index = index + 1;
               student.index = index + 1;
               student.examId = store.env.examId;
               student.examId = store.env.examId;
               // const filePath = window.electron.join(
               // const filePath = window.electron.join(
@@ -145,7 +147,7 @@ onMounted(async () => {
                 // console.log(urls);
                 // console.log(urls);
                 continue;
                 continue;
               }
               }
-
+              // console.log("filePath3:", filePath);
               console.debug("start ", sheetUrl);
               console.debug("start ", sheetUrl);
               const imageDownloadStartTime = Date.now();
               const imageDownloadStartTime = Date.now();
               const imageRes = await httpApp.get(sheetUrl, {
               const imageRes = await httpApp.get(sheetUrl, {
@@ -162,7 +164,20 @@ onMounted(async () => {
               // console.log(imageRes.data);
               // console.log(imageRes.data);
               // console.log(await imageRes.data.arrayBuffer());
               // console.log(await imageRes.data.arrayBuffer());
               // console.log(new Uint8Array(await imageRes.data.arrayBuffer()));
               // console.log(new Uint8Array(await imageRes.data.arrayBuffer()));
-
+              console.log("curFileIndex:", curFileIndex);
+              let folderName = "";
+              if (config.fileNumberSplit) {
+                folderName = `/${
+                  Math.floor(curFileIndex / config.fileNumberLimits) *
+                    config.fileNumberLimits +
+                  1
+                }~${
+                  Math.floor(curFileIndex / config.fileNumberLimits) *
+                    config.fileNumberLimits +
+                  config.fileNumberLimits
+                }`;
+                console.log("folderName:", folderName);
+              }
               await window.electron.addWatermark(
               await window.electron.addWatermark(
                 storePassedToNodeJs,
                 storePassedToNodeJs,
                 arrayBuffer,
                 arrayBuffer,
@@ -173,8 +188,10 @@ onMounted(async () => {
                 index + 1,
                 index + 1,
                 config.trackMode,
                 config.trackMode,
                 config.x,
                 config.x,
-                config.y
+                config.y,
+                folderName
               );
               );
+              curFileIndex++;
             } catch (error) {
             } catch (error) {
               errorCount.value += 1;
               errorCount.value += 1;
               if (config.failover) {
               if (config.failover) {

+ 38 - 3
src/lib/watermark.ts

@@ -17,8 +17,15 @@ export async function addWatermark(
   index: number,
   index: number,
   trackMode: string,
   trackMode: string,
   x = 0.01,
   x = 0.01,
-  y = 0.03
+  y = 0.03,
+  folderName = ""
 ): Promise<boolean> {
 ): Promise<boolean> {
+  if (folderName) {
+    const lastIndex: number = filePath[1].lastIndexOf("/");
+    const preStr: any = filePath[1].slice(0, lastIndex);
+    const nextStr: any = filePath[1].slice(lastIndex);
+    filePath[1] = preStr + folderName + nextStr;
+  }
   const file = path.join(...filePath);
   const file = path.join(...filePath);
   if (
   if (
     index !== 1 &&
     index !== 1 &&
@@ -50,6 +57,8 @@ export async function addWatermark(
   }
   }
   const fontFile = store.config.watermark.fontFile;
   const fontFile = store.config.watermark.fontFile;
   const color = store.config.watermark.color;
   const color = store.config.watermark.color;
+  const nextColor = store.config.watermark.nextColor;
+  const otherColor = store.config.watermark.otherColor;
   const image = Buffer.from(imageData);
   const image = Buffer.from(imageData);
   // const size = sizeOf(image);
   // const size = sizeOf(image);
   // console.log(size);
   // console.log(size);
@@ -238,12 +247,38 @@ export async function addWatermark(
   if (student.tags != undefined && student.tags[index] != undefined) {
   if (student.tags != undefined && student.tags[index] != undefined) {
     const fontSize = 60;
     const fontSize = 60;
     const height = fontSize + 10;
     const height = fontSize + 10;
-    imgData.font(fontFile, fontSize).fill(color);
+    // imgData.font(fontFile, fontSize).fill(color);
     const tags = student.tags[index];
     const tags = student.tags[index];
+
+    let userIds: any = tags.map((item: any) => item.userId || 0);
+    userIds = Array.from(new Set(userIds));
+    userIds.sort();
+    const colorMap: any = {
+      "0": color,
+    };
+    let startIndex = 1;
+    if (!userIds.includes(0)) {
+      startIndex = 0;
+    }
+
+    for (let i = 0; i < userIds.length; i++) {
+      const uId: string | number = userIds[i];
+      if (i == startIndex) {
+        colorMap[uId + ""] = color;
+      } else if (i == startIndex + 1) {
+        colorMap[uId + ""] = nextColor;
+      } else if (i > startIndex + 1) {
+        colorMap[uId + ""] = otherColor;
+      }
+    }
+
     for (let i = 0; i < tags.length; i++) {
     for (let i = 0; i < tags.length; i++) {
       const tag = tags[i];
       const tag = tags[i];
       if (tag.content != undefined) {
       if (tag.content != undefined) {
         let top = tag.top;
         let top = tag.top;
+        imgData
+          .font(fontFile, fontSize)
+          .fill(colorMap[tag.userId + ""] || color);
         for (let j = 0; j < tag.content.length; j++) {
         for (let j = 0; j < tag.content.length; j++) {
           imgData.drawText(tag.left, top, tag.content[j]);
           imgData.drawText(tag.left, top, tag.content[j]);
           top += height;
           top += height;
@@ -272,7 +307,7 @@ export async function saveImage(
   filePath: string[]
   filePath: string[]
 ): Promise<boolean> {
 ): Promise<boolean> {
   const file = path.join(...filePath);
   const file = path.join(...filePath);
-
+  console.log("saveImage file:", file);
   if (store.pageInputs["/image-download"].append && fs.existsSync(file)) {
   if (store.pageInputs["/image-download"].append && fs.existsSync(file)) {
     console.log(file + " already exists");
     console.log(file + " already exists");
     return true;
     return true;

+ 4 - 0
src/types/index.ts

@@ -39,6 +39,8 @@ export interface Store {
       dir: string;
       dir: string;
       append: boolean;
       append: boolean;
       failover: boolean;
       failover: boolean;
+      fileNumberSplit: boolean;
+      fileNumberLimits: any;
       watermark: boolean;
       watermark: boolean;
       trackMode: string;
       trackMode: string;
       examNumber?: string;
       examNumber?: string;
@@ -75,6 +77,8 @@ export interface Watermark {
   fontFile: string;
   fontFile: string;
   fontSize: number;
   fontSize: number;
   color: string;
   color: string;
+  nextColor: string;
+  otherColor: string;
 }
 }
 
 
 export interface Student {
 export interface Student {