Browse Source

Merge branch 'beta'

SanHQin 1 day ago
parent
commit
25b376317a
32 changed files with 961 additions and 59 deletions
  1. 1 1
      dist/index.html
  2. 0 0
      dist/static/css/app.adc867baa722f56bff768b5f11ea09c4.css
  3. 0 0
      dist/static/css/app.adc867baa722f56bff768b5f11ea09c4.css.map
  4. 0 0
      dist/static/css/workPage.48dddfde3fdf305b6255d571fb2e352b.css
  5. 0 0
      dist/static/css/workPage.48dddfde3fdf305b6255d571fb2e352b.css.map
  6. 0 0
      dist/static/css/workPage.d00f7b2a64686852e2ce6c88c161e264.css.map
  7. 0 0
      dist/static/js/app.4af0c5ead94b65b33825.js
  8. 0 0
      dist/static/js/app.4af0c5ead94b65b33825.js.map
  9. 0 0
      dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map
  10. 0 0
      dist/static/js/vendor.714ff2bfc93f2f096b79.js.map
  11. 0 0
      dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map
  12. 0 0
      dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js
  13. 0 0
      dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js.map
  14. 0 0
      dist/static/js/workPage-vendor.e1fc95e471d70a1519e8.js
  15. 0 0
      dist/static/js/workPage-vendor.e1fc95e471d70a1519e8.js.map
  16. 0 0
      dist/static/js/workPage.1a268ecca54a9e133aa1.js
  17. 0 0
      dist/static/js/workPage.1a268ecca54a9e133aa1.js.map
  18. 0 0
      dist/static/js/workPage.db384ded4a6602a94be8.js
  19. 0 0
      dist/static/js/workPage.db384ded4a6602a94be8.js.map
  20. 1 1
      dist/workPage.html
  21. 70 3
      src/components/pages/pptEasy/addCourse3.vue
  22. 94 28
      src/components/pages/studentManageNew/component/addstu.vue
  23. 6 2
      src/components/pages/workPage/components/choiceQuestion.vue
  24. 264 0
      src/components/pages/workPage/components/photo.vue
  25. 17 12
      src/components/pages/workPage/components/questionsAndAnswers.vue
  26. 449 0
      src/components/pages/workPage/components/setPhoto.vue
  27. 1 1
      src/components/pages/workPage/components/setVoteQuestion.vue
  28. 24 4
      src/components/pages/workPage/index_new.vue
  29. 7 1
      src/components/pages/workPage/setIndex.vue
  30. 9 2
      src/lang/cn.json
  31. 9 2
      src/lang/en.json
  32. 9 2
      src/lang/hk.json

+ 1 - 1
dist/index.html

@@ -37,7 +37,7 @@
       width: 100%;
       background: #e6eaf0;
       font-family: '黑体';
-    }</style><link href=./static/css/app.c69f4aee1d5ad4d3aa47aeb3820a212f.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.23ea04dc469b57e2b4f8.js></script><script type=text/javascript src=./static/js/vendor.714ff2bfc93f2f096b79.js></script><script type=text/javascript src=./static/js/app.c2ca1b1226c6bcdc4721.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.adc867baa722f56bff768b5f11ea09c4.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.23ea04dc469b57e2b4f8.js></script><script type=text/javascript src=./static/js/vendor.714ff2bfc93f2f096b79.js></script><script type=text/javascript src=./static/js/app.4af0c5ead94b65b33825.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.adc867baa722f56bff768b5f11ea09c4.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.adc867baa722f56bff768b5f11ea09c4.css.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/workPage.48dddfde3fdf305b6255d571fb2e352b.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/workPage.48dddfde3fdf305b6255d571fb2e352b.css.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/workPage.d00f7b2a64686852e2ce6c88c161e264.css.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.4af0c5ead94b65b33825.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.4af0c5ead94b65b33825.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/vendor.714ff2bfc93f2f096b79.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage-vendor.7b2c55096449c94cc8fd.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage-vendor.e1fc95e471d70a1519e8.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage-vendor.e1fc95e471d70a1519e8.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage.1a268ecca54a9e133aa1.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage.1a268ecca54a9e133aa1.js.map


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage.db384ded4a6602a94be8.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/workPage.db384ded4a6602a94be8.js.map


+ 1 - 1
dist/workPage.html

@@ -1,4 +1,4 @@
-<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>工作页面 - CocoFlow</title><link rel=icon href=../static/logo.ico><link href=./static/css/workPage.d00f7b2a64686852e2ce6c88c161e264.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script type=text/javascript src=./static/js/workPage-manifest.2ece51fa34be51c8610a.js></script><script type=text/javascript src=./static/js/workPage-vendor.7b2c55096449c94cc8fd.js></script><script type=text/javascript src=./static/js/workPage.1a268ecca54a9e133aa1.js></script></body></html><script>function stopSafari() {
+<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>工作页面 - CocoFlow</title><link rel=icon href=../static/logo.ico><link href=./static/css/workPage.48dddfde3fdf305b6255d571fb2e352b.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script type=text/javascript src=./static/js/workPage-manifest.2ece51fa34be51c8610a.js></script><script type=text/javascript src=./static/js/workPage-vendor.e1fc95e471d70a1519e8.js></script><script type=text/javascript src=./static/js/workPage.db384ded4a6602a94be8.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {

+ 70 - 3
src/components/pages/pptEasy/addCourse3.vue

@@ -865,6 +865,16 @@
                   </div>
                 </div>
               </div>
+              <div class="form-row">
+                <div class="form-item aiAssistant-item">
+                  <div class="aiAssistant_box">
+                      <label class="aiAssistant_box_title">{{ lang.ssAIAssistant }}</label>
+                      <div class="ai-switch-wrapper">
+                        <el-switch v-model="aiAssistant" active-color="#FF8C00" inactive-color="#DCDFE6"></el-switch>
+                      </div>
+                  </div>
+                </div>
+              </div>
               <div class="publish-modal-footer">
                 <button class="btn-cancel" @click="dialogVisiblePublish = false">{{ lang.ssCancel }}</button>
                 <button class="btn-publish" @click="confirmPublish">
@@ -1034,7 +1044,7 @@ export default {
       courseName: "",
       isTeacherSee: false,
       visibility: "students",
-      aiAssistant: true,
+      aiAssistant: false,
       classOptions: [],
       publishing: false,
       editingCourseName: false,
@@ -1949,7 +1959,7 @@ export default {
 
       console.log(_url)
       this.pptCourseJson.pptData = _url;
-
+      this.pptCourseJson.aiAssistant = this.aiAssistant;
 
 
       this.inputShow = true;
@@ -2068,6 +2078,7 @@ export default {
       this.uploadFile2(pptJsonFile2, this.cid);
 
       this.pptCourseJson.pptData = _url;
+      this.pptCourseJson.aiAssistant = this.aiAssistant;
 
       let params = [
         {
@@ -2214,7 +2225,7 @@ export default {
           .then(res => {
             this.loading = true;
             this.pptCourseJson = JSON.parse(res.data[0][0].chapters);
-
+            this.aiAssistant = this.pptCourseJson.aiAssistant ? this.pptCourseJson.aiAssistant : false
 
             this.$forceUpdate();
             this.courseName = res.data[0][0].title;
@@ -2663,6 +2674,9 @@ export default {
         this.answerQ = "";
         this.addAnswer();
         // this.dialogVisible8 = true;
+      }else if (tool == 79){
+        this.answerQ = "";
+        this.addPhoto();
       } else if (tool == 72) {
         this.$refs.appDialog.openG(
           [],
@@ -3271,6 +3285,37 @@ export default {
         this.editId = null;
       });
     },
+    addPhoto() {
+      // if (this.answerQ == "") {
+      //   this.$message.error(this.lang.ssEnterQuesL);
+      //   return;
+      // }
+      let _data = { id: new Date().getTime(), tool: 79, title: this.lang.ssPhoto, brief: this.lang.ssPhotoTool, json: { answerQ: this.answerQ, fileList: [] }, url: "" }
+      if (this.editId) {
+        let oldData = this.pptCourseJson.toolsList.find(i => i.id === this.editId);
+        _data.id = oldData.id;
+        _data.title = oldData.title;
+        _data.brief = oldData.brief;
+        this.pptCourseJson.toolsList.splice(this.pptCourseJson.toolsList.findIndex(i => i.id === this.editId), 1, _data);
+      } else {
+        this.pptCourseJson.toolsList.push(_data);
+      }
+
+      this.dialogVisible8 = false;
+      this.getWorkPageId(_data.id, 79, { answerQ: this.answerQ, fileList: [] }).then(res => {
+        let baseUrl = this.setUrl()
+        let url = `${baseUrl}/pbl-teacher-table/dist/workPage.html#/setWorkPage?id=${res}&type=${_data.tool}`;
+        this.pptCourseJson.toolsList.find(i => i.id === _data.id).url = url;
+        this.setPPtToolList();
+        _data.url = url
+        if (!this.editId) {
+          this.addContent(_data)
+        } else {
+          this.addContent(_data, 2)
+        }
+        this.editId = null;
+      });
+    },
     async getWorkPageId(id, tool, json) {
       let params = [{
         userid: this.userid,
@@ -3366,6 +3411,9 @@ export default {
       } else if (tool == 15) {
         this.answerQ = "";
         this.addAnswer();
+      } else if (tool == 79) {
+        this.answerQ = "";
+        this.addPhoto();
       }
     },
     clearLine() {
@@ -5552,4 +5600,23 @@ export default {
 .web-search-footer .btn-confirm:hover {
   background-color: #e67300;
 }
+
+.aiAssistant-item {
+  border: 1px solid #ececef;
+  border-radius: 5px;
+}
+
+.aiAssistant_box{
+  display: flex;
+  align-items: center;
+  background: #fafbfd;
+  padding: 14px 10px;
+  border-radius: 5px;
+  justify-content: space-between;
+  box-sizing: border-box;
+}
+
+.aiAssistant_box_title{}
+
+.ai-switch-wrapper{}
 </style>

+ 94 - 28
src/components/pages/studentManageNew/component/addstu.vue

@@ -168,11 +168,12 @@
               <span class="download-template" @click="downloadTemplate"
                 >{{ lang.ssDownloadTemp }}</span
               >
+              <span style="margin-left: 10px;font-weight: 600;">{{ lang.ssAccColOptional }}</span>
             </div>
-            <div v-if="boxType == 0" style="margin-top: 10px">
+            <div v-if="boxType == 0" style="margin-top: 10px;font-weight: 600;">
               {{ lang.ssUploadNote }}
             </div>
-            <div v-else style="margin-top: 10px">
+            <div v-else style="margin-top: 10px;font-weight: 600;">
               {{ lang.ssSyncImportClassInfo }}
             </div>
             <!-- <div style="margin-top: 10px">
@@ -401,10 +402,10 @@ export default {
           export_json_to_excel,
         } = require("../../../../common/Export2Excel");
         // 增加 colWidths 参数以调整列宽,例如调整为 [20, 35, 20]
-        let tHeader = [this.lang.StudentName];
+        let tHeader = [this.lang.StudentName, this.lang.ssStuAccHd];
             
         if (this.boxType == 2) {
-           tHeader = [this.lang.StudentName,this.lang.Class];
+           tHeader = [this.lang.StudentName, this.lang.Class, this.lang.ssStuAccHd];
         }
         const data = [];
         const colWidths = [35]; // 设置每一列的宽度
@@ -455,7 +456,7 @@ export default {
           }
           outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); //outdata就是你想要的东西
           let da = [...outdata];
-          // console.log(da, "da");
+          console.log(da, "da");
           let arr = [];
           da.map((v) => {
             let obj = {};
@@ -471,9 +472,20 @@ export default {
                 _this.org &&
                 _this.schoolChar
               ) {
+                if (Number(v[_this.lang.ssStuAccHd])) {
+                  obj.account = v[_this.lang.ssStuAccHd] + '@' + _this.schoolChar + '.' + _this.userSuffix;
+                } else {
+                  obj.account = '';
+                }
+
                 obj.mail =
                   uuidv4() + "@" + _this.schoolChar + "." + _this.userSuffix;
               } else {
+                if (Number(v[_this.lang.ssStuAccHd])) {
+                  obj.account = v[_this.lang.ssStuAccHd] + + _this.userSuffix;
+                } else {
+                  obj.account = '';
+                }
                 obj.mail = uuidv4() + "@" + _this.userSuffix;
               }
               obj.class = _this.boxType == 2 ? v[_this.lang.Class] : _this.classInfo.id;
@@ -611,19 +623,45 @@ export default {
       console.log(box, "box");
       this.uploadfileLoading = true;
       this.impbox = box;
+      let data1 = box.filter(e => !e.account);
+      let data2 = box.filter(e => e.account);
+
+      data2.forEach((e) => {
+        e.mail = e.account;
+      });
+
       const batchSize = 50;
-      if (box.length > batchSize) {
-        // 计算总批次数
-        const totalBatches = Math.ceil(box.length / batchSize);
-        for (let i = 0; i < totalBatches; i++) {
-          const batch = box.slice(i * batchSize, (i + 1) * batchSize);
-          await this.uploadBatch(batch); // 假设 uploadBatch 返回 Promise
-          console.log(`第 ${i + 1} 批上传完成`, batch);
+      if (data1.length > 0) {
+        if (data1.length > batchSize) {
+          // 计算总批次数
+          const totalBatches = Math.ceil(data1.length / batchSize);
+          for (let i = 0; i < totalBatches; i++) {
+            const batch = data1.slice(i * batchSize, (i + 1) * batchSize);
+            await this.uploadBatch(batch); // 假设 uploadBatch 返回 Promise
+            console.log(`普通上传第 ${i + 1} 批上传完成`, batch);
+          }
+        } else {
+          // 长度不超过 10,直接上传整个数组
+          await this.uploadBatch(data1);
         }
-      } else {
-        // 长度不超过 10,直接上传整个数组
-        await this.uploadBatch(box);
       }
+
+      if (data2.length > 0) {
+        if (data2.length > batchSize) {
+          // 计算总批次数
+          const totalBatches = Math.ceil(data2.length / batchSize);
+          for (let i = 0; i < totalBatches; i++) {
+            const batch = data2.slice(i * batchSize, (i + 1) * batchSize);
+            await this.uploadBatchAccount (batch); // 假设 uploadBatch 返回 Promise
+            console.log(`自定义账号上传第 ${i + 1} 批上传完成`, batch);
+          }
+        } else {
+          // 长度不超过 10,直接上传整个数组
+          await this.uploadBatchAccount (data2);
+        }
+      }
+
+
       this.$message({
         message: this.lang.ssAddOk,
         type: "success",
@@ -671,21 +709,49 @@ export default {
             }
             if (z == 2) {
               console.log("添加成功");
-              // this.$message({
-              //   message: this.lang.ssAddOk,
-              //   type: "success",
-              // });
-              // this.deltypy = 0;
-              // this.popBoxdia= true;
-              // // this.addStuVisible = false;
-              // console.log('this.selectedStuData',this.selectedStuData);
-              
-              // // this.selectedStuData = [];
-              // this.$emit("getCascaderData");
-              // this.addOp3('1', "", { type: "student_add" }, "success")
             }
             resolve(res);
-            // this.uploadfileLoading = false;
+          })
+          .catch((err) => {
+            console.error(err);
+            this.addOp3('1', "", { type: "student_add" }, err)
+            reject(err);
+          });
+        });
+    },
+    async uploadBatchAccount(box){
+      return new Promise((resolve, reject) => {
+        let z = 2;
+        let newArr = JSON.stringify(box);
+        let params = [
+          {
+            arr: newArr,
+            userpassword: "Coco1234",
+            oid: this.oid,
+          },
+        ];
+      console.log(params, "batchRegistrationMoreAcc");
+      // batchRegistrationMoreCopy
+        this.ajax
+          .post(this.$store.state.api + "batchRegistrationMoreAcc", params)
+          .then((res) => {
+            console.log(res, "res");
+            if (res.data.type == 1) {
+              this.$message.error(this.lang.stunumberregistered);
+              z = 1;
+            }
+            if (res.data.type == 2) {
+              this.$message.error(this.lang.stuaccregistered);
+              z = 1;
+            }
+            if (res.data.type == 3) {
+              this.$message.error(this.lang.studuplicateIDs);
+              z = 1;
+            }
+            if (z == 2) {
+              console.log("添加成功");
+            }
+            resolve(res);
           })
           .catch((err) => {
             console.error(err);

+ 6 - 2
src/components/pages/workPage/components/choiceQuestion.vue

@@ -307,13 +307,15 @@ export default {
   font-size: 1rem;
   color: #000;
   user-select: none;
+  border: solid 4px rgba(252, 207, 0, 0);
   /* 不可选中 */
   /* box-sizing: border-box;
   padding: 20px 40px; */
 }
 
 .cq_ca_t1_item_active {
-  box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
+  /* box-shadow: 4px 4px 14px 4px rgba(252, 207, 0, 1); */
+  border: solid 4px rgba(252, 207, 0, 1);
 }
 
 .cq_ca_t1_item>div {
@@ -380,6 +382,7 @@ export default {
   user-select: none;
   overflow: auto;
   overflow-y: hidden;
+  border: solid 4px rgba(252, 207, 0, 0);
 }
 
 .cq_ca_t2_item>div {
@@ -402,7 +405,8 @@ export default {
 
 
 .cq_ca_t2_item_active {
-  box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5);
+  /* box-shadow: 4px 4px 14px 0px rgba(252, 207, 0, 0.5); */
+  border: solid 4px rgba(252, 207, 0, 1);
 }
 
 .cq_ca_t2_item>div {

+ 264 - 0
src/components/pages/workPage/components/photo.vue

@@ -0,0 +1,264 @@
+<template>
+  <div class="questionsAndAnswers">
+    <div class="qaa_title">{{ work.answerQ }}</div>
+    <div class="qaa_img" v-if="work.imageList && work.imageList.length > 0">
+      <div v-for="(item, index) in work.imageList" :key="index">
+        <img :src="item.url" alt="" @click="$hevueImgPreview(item.url)">
+      </div>
+    </div>
+    <div class="qaa_type">{{ lang.ssPhoto }}</div>
+    <!-- 图片列表 -->
+    <div class="imageList" v-if="work.fileList && work.fileList.length > 0">
+      <div v-for="(image, imageIndex) in work.fileList" :key="imageIndex" class="image-item">
+        <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]" fit="cover"></el-image>
+        <svg class="delete-icon" @click="delImage(imageIndex)" t="1774237005199" viewBox="0 0 1024 1024" width="20" height="20">
+          <path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024zM305.956571 370.395429L447.488 512 305.956571 653.604571a45.568 45.568 0 1 0 64.438858 64.438858L512 576.512l141.604571 141.531429a45.568 45.568 0 0 0 64.438858-64.438858L576.512 512l141.531429-141.604571a45.568 45.568 0 1 0-64.438858-64.438858L512 447.488 370.395429 305.956571a45.568 45.568 0 0 0-64.438858 64.438858z" fill="#FF2525" p-id="4716"></path>
+        </svg>
+        <span class="delete-text">{{ lang.ssDeleteImage }}</span>
+      </div>
+    </div>
+
+    <!-- 操作按钮区域 -->
+    <div class="upload-area">
+      <!-- 拍照按钮 -->
+      <!-- <button class="photo-btn" @click="takePhoto" v-if="isMobile">
+        <span class="plus-icon">+</span>
+        <span>{{ lang.ssTakePhoto }}</span>
+      </button> -->
+      
+      <button class="photo-btn" @click="uploadImage">
+        <span class="plus-icon">+</span>
+        <span>{{ lang.ssTakePhoto }}</span>
+      </button>
+      <!-- 上传图片按钮 -->
+      <!-- <span class="upload-btn" @click="uploadImage">{{ lang.ssContinueAddImage }}</span> -->
+    </div>
+  </div>
+</template>
+
+<script>
+import { uploadOneFile } from '@/components/tools/uploadFile'
+export default {
+  props: {
+    workData: {
+      type: Object,
+      default: () => {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      work: {
+        fileList: []
+      },
+      recordObj: {},
+      isMobile: false
+    };
+  },
+  computed: {
+
+  },
+  watch: {
+    work: {
+      deep: true,
+      handler(newValue) {
+        if (JSON.stringify(newValue) != JSON.stringify(this.workData.json)) {
+          this.changeWorkData(newValue);
+        }
+      }
+    },
+    workData: {
+      handler: function (newValue, oldValue) {
+        let _data = JSON.parse(JSON.stringify(this.workData.json));
+        if (JSON.stringify(newValue) != JSON.stringify(oldValue) || JSON.stringify(this.work) != JSON.stringify(_data)) {
+          let _data = JSON.parse(JSON.stringify(this.workData.json));
+          if (!_data.fileList) {
+            _data.fileList = [];
+          }
+          this.work = _data;
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    // 更新作业
+    changeWorkData(newValue) {
+      this.$emit("changeWorkData", JSON.stringify(newValue));
+    },
+    // 拍照功能
+    takePhoto() {
+      const input = document.createElement('input');
+      input.type = 'file';
+      input.accept = 'image/*';
+      input.capture = 'environment'; // 使用后置摄像头
+      input.click();
+      input.onchange = (e) => {
+        if (e.target.files[0]) {
+          uploadOneFile(e.target.files[0]).then(res => {
+            res.src = res.url;
+            this.work.fileList = [...this.work.fileList, res];
+            this.changeWorkData(this.work);
+          });
+        }
+      };
+    },
+    // 上传图片功能
+    uploadImage() {
+      const input = document.createElement('input');
+      input.type = 'file';
+      input.accept = 'image/*';
+      input.click();
+      input.onchange = (e) => {
+        if (e.target.files[0]) {
+          uploadOneFile(e.target.files[0]).then(res => {
+            res.src = res.url;
+            this.work.fileList = [...this.work.fileList, res];
+            this.changeWorkData(this.work);
+          });
+        }
+      };
+    },
+    // 删除图片
+    delImage(index) {
+      this.work.fileList.splice(index, 1);
+      this.changeWorkData(this.work);
+    },
+    checkMobile() {
+      const ua = navigator.userAgent;
+      const isMobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|Android/i.test(ua);
+      const isTablet = /iPad|Android(?!.*Mobile)/i.test(ua);
+      this.isMobile = isMobileDevice || isTablet;
+    }
+  },
+  mounted() {
+    this.checkMobile();
+  },
+  beforeUnmount() {
+  }
+};
+</script>
+
+<style scoped>
+.questionsAndAnswers {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  box-sizing: border-box;
+  padding: 70px 10%;
+  overflow: auto;
+}
+
+.qaa_title {
+  font-size: 2rem;
+  font-weight: bold;
+  text-align: center;
+  width: 100%;
+}
+
+
+.qaa_img {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.qaa_img>div {
+  max-width: 200px;
+  height: auto;
+  margin: 10px;
+}
+
+.qaa_img>div>img {
+  width: 100%;
+  height: auto;
+  object-fit: cover;
+  cursor: pointer;
+}
+
+.qaa_type {
+  margin: 20px 0 40px 0;
+  font-size: 1rem;
+  color: #808080;
+}
+
+.imageList {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  margin-bottom: 30px;
+  justify-content: center;
+}
+
+.image-item {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.delete-icon {
+  position: absolute;
+  top: -10px;
+  right: -10px;
+  cursor: pointer;
+}
+
+.delete-text {
+  margin-top: 8px;
+  color: #FF2525;
+  font-size: .9rem;  
+}
+
+.upload-area {
+  display: flex;
+  align-items: center;
+  gap: 40px;
+}
+
+.photo-btn {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  padding: 12px 32px;
+  border: 2px solid #FF9500;
+  border-radius: 8px;
+  background-color: #fff;
+  color: #FF9500;
+  font-size: 1rem;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.photo-btn:hover {
+  background-color: #fff8f0;
+}
+
+.photo-btn + .photo-btn {
+  margin-left: 20px;
+}
+
+.plus-icon {
+  font-size: 1.2rem;
+  font-weight: bold;
+}
+
+.upload-btn {
+  color: #67C23A;
+  font-size: 1rem;
+  cursor: pointer;
+  transition: color 0.3s;
+}
+
+.upload-btn:hover {
+  color: #85CE61;
+}
+</style>

File diff suppressed because it is too large
+ 17 - 12
src/components/pages/workPage/components/questionsAndAnswers.vue


+ 449 - 0
src/components/pages/workPage/components/setPhoto.vue

@@ -0,0 +1,449 @@
+<template>
+  <div class="setChoiceQuestion">
+    <div class="testItem">
+      <div class="ti_header">
+        <span>{{ lang.ssPhotoTip }}</span>
+      </div>
+
+      <div class="ti_title">
+        <el-input class="ti_t_input" type="textarea" v-model="jsonData.answerQ" @input="setTestTitle"></el-input>
+        <div class="uploadImage" @click="uploadImage()">
+          <svg viewBox="0 0 1024 1024" version="1.1" p-id="15953" width="200" height="200">
+            <path
+              d="M368 480c-62.4 0-112-49.6-112-112s49.6-112 112-112 112 49.6 112 112-49.6 112-112 112z m0-160c-27.2 0-48 20.8-48 48s20.8 48 48 48 48-20.8 48-48-20.8-48-48-48z m464 608H192c-52.8 0-96-43.2-96-96V192c0-52.8 43.2-96 96-96h640c52.8 0 96 43.2 96 96v640c0 52.8-43.2 96-96 96zM192 160c-17.6 0-32 14.4-32 32v640c0 17.6 14.4 32 32 32h640c17.6 0 32-14.4 32-32V192c0-17.6-14.4-32-32-32H192z m259.2 556.8c-25.6 0-51.2-11.2-70.4-30.4l-38.4-40c-12.8-12.8-33.6-12.8-46.4 0l-49.6 52.8c-12.8 12.8-32 12.8-44.8 1.6s-12.8-32-1.6-44.8l49.6-52.8c17.6-19.2 43.2-30.4 68.8-30.4s51.2 11.2 70.4 30.4l38.4 40c12.8 12.8 33.6 12.8 46.4 0l160-168c17.6-19.2 43.2-30.4 70.4-30.4s51.2 11.2 70.4 30.4L920 628.8c12.8 12.8 11.2 33.6-1.6 44.8-12.8 12.8-33.6 11.2-44.8-1.6L728 518.4c-12.8-12.8-33.6-12.8-46.4 0L521.6 688c-19.2 17.6-44.8 28.8-70.4 28.8z"
+              fill="#333333" p-id="15954"></path>
+          </svg>
+        </div>
+      </div>
+      <!-- 图片 -->
+      <div class="imageList">
+        <div v-for="(image, imageIndex) in jsonData.imageList" :key="imageIndex">
+          <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]"
+            fit="cover"></el-image>
+            <svg @click="delImage(imageIndex)" t="1774237005199" viewBox="0 0 1024 1024" width="200" height="200"><path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024zM305.956571 370.395429L447.488 512 305.956571 653.604571a45.568 45.568 0 1 0 64.438858 64.438858L512 576.512l141.604571 141.531429a45.568 45.568 0 0 0 64.438858-64.438858L576.512 512l141.531429-141.604571a45.568 45.568 0 1 0-64.438858-64.438858L512 447.488 370.395429 305.956571a45.568 45.568 0 0 0-64.438858 64.438858z" fill="#FF2525" p-id="4716"></path></svg>
+        </div>
+      </div>
+
+
+      <!-- 解释说明 -->
+      <div class="explanation" v-show="false">
+        <div class="e_header">
+          <span>{{ lang.ssEvaluationStandard }}</span>
+          <!-- <div v-show="false">
+            <svg t="1774233113566" viewBox="0 0 1027 1024" width="200" height="200">
+              <path
+                d="M511.979521 544.586217a54.525819 54.525819 0 0 1-23.359066-5.247791L31.038758 321.427143a54.397824 54.397824 0 0 1 0-98.236071L488.620455 5.279789c14.719411-7.039718 31.99872-7.039718 46.718131 0l457.581697 217.911283a54.397824 54.397824 0 0 1 0 98.236071l-457.581697 217.911283A54.525819 54.525819 0 0 1 511.979521 544.586217zM180.984761 272.341106L511.979521 429.966801l331.058757-157.625695L511.979521 114.587417 180.984761 272.341106z m354.417823 746.402144l457.517699-217.911283a54.397824 54.397824 0 1 0-46.718131-98.236071L511.979521 909.371625l-434.158634-206.775729a54.397824 54.397824 0 0 0-46.718131 98.236071l457.581697 217.911283a54.525819 54.525819 0 0 0 46.718131 0z m0-239.73441l457.517699-217.847286a54.397824 54.397824 0 1 0-46.718131-98.300068L511.979521 669.573217l-434.158634-206.711731a54.397824 54.397824 0 0 0-46.718131 98.300068l457.581697 217.847286a54.525819 54.525819 0 0 0 46.718131 0z"
+                p-id="9073"></path>
+            </svg>
+            <span>AI生成</span>
+          </div> -->
+        </div>
+        <el-input type="textarea" rows="3" resize="none" v-model="jsonData.evaluationCriteria" :placeholder="lang.ssEnterEvaluationStandard"
+          @input="setTestJson()"></el-input>
+      </div>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import { uploadOneFile } from '@/components/tools/uploadFile'
+export default {
+  emits: ['setTestJson', 'save'],
+  props: {
+    workData: {
+      type: Object,
+      default: () => { }
+    }
+  },
+  data() {
+    return {
+      jsonData: {}
+    }
+  },
+  watch: {
+    workData: {
+      handler(newVal, oldVal) {
+        if (newVal.type == 15) {
+          if (JSON.stringify(newVal.json) != JSON.stringify(this.jsonData)) {
+            let _data = JSON.parse(JSON.stringify(newVal.json))
+
+            if(!_data.imageList){
+              _data.imageList = [];
+            }
+            if(!_data.evaluationCriteria){
+              _data.evaluationCriteria = '';
+            }
+
+            this.jsonData = _data;
+          }
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    // 更新题目
+    setTestJson() {
+      // console.log(this.jsonData)
+      // this.jsonData.testCount = this.jsonData.testJson.length;
+      this.$emit('setTestJson', this.jsonData);
+    },
+    //修改标题
+    setTestTitle( title) {
+      console.log('修改标题', title)
+      this.jsonData.answerQ = title;
+      // let test = this.jsonData..find(item => item.id == id);
+      // if (test) {
+      //   test.teststitle = title;
+      // }
+      this.setTestJson();
+    },
+    // 上传图片
+    uploadImage(id) {
+      const input = document.createElement('input');
+      input.type = 'file';
+      input.accept = 'image/*';
+      input.click();
+      input.onchange = (e) => {
+        if (e.target.files[0]) {
+          uploadOneFile(e.target.files[0]).then(res => {
+            res.src = res.url
+            this.jsonData.imageList = [res];
+            this.$forceUpdate();
+            // this.jsonData.testJson.find(item => item.id == id).timuList = [res];
+            this.setTestJson();
+          })
+        }
+      }
+    },
+    // 删除图片
+    delImage(index) {
+      this.jsonData.imageList.splice(index, 1);
+      // let test = this.jsonData.testJson.find(item => item.id == id);
+      // if (test) {
+      //   test.timuList.splice(index, 1);
+      // }
+      this.setTestJson();
+    },
+  },
+}
+</script>
+
+<style scoped>
+.setChoiceQuestion {
+  width: 100%;
+  height: auto;
+  background: #fff;
+  display: flex;
+  flex-direction: column;
+  overflow: auto;
+  padding: 4rem;
+  box-sizing: border-box;
+  gap: 2rem;
+}
+
+.addTest {
+  border-radius: 5px;
+  border: 1px dashed #d1d5db;
+  padding: .5rem 1rem;
+  height: fit-content;
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  cursor: pointer;
+}
+
+.addTest>svg {
+  width: .7rem;
+  height: .7rem;
+  fill: #6E7583;
+}
+
+.addTest>span {
+  font-weight: bold;
+  font-size: .9rem;
+  color: #6b7280;
+}
+
+.testItem {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+  flex-direction: column;
+}
+
+.ti_header {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+
+}
+
+.ti_header>span {
+  font-size: 1rem;
+  font-weight: 600;
+  color: #ff9300;
+}
+
+.ti_h_edit {
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+}
+
+.ti_h_edit>span {
+  width: 1.5rem;
+  height: 1.5rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #F9FAFB;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.ti_h_edit>span>svg {
+  width: 1rem;
+  height: 1rem;
+  fill: #6B7280;
+}
+
+.ti_title {
+  width: 100%;
+  height: fit-content;
+  padding-bottom: 2rem;
+  min-height: 4rem;
+  background: #FAFBFC;
+  border-radius: 8px;
+  border: 1px solid #E5E7EB;
+  position: relative;
+}
+
+.ti_t_input {
+  width: 100%;
+  height: 100%;
+  padding: 1rem;
+  box-sizing: border-box;
+  border: none;
+  outline: none;
+  background: none;
+  font-size: 1.2rem;
+  resize: none;
+  /* max-height: 10rem; */
+  overflow: auto;
+  /* padding-right: 2rem; */
+}
+
+.ti_t_input /deep/ .el-textarea__inner {
+  padding: 0;
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  border: none;
+  outline: none;
+  background: none;
+  font-size: 1.2rem;
+  resize: none;
+  /* max-height: 10rem; */
+  overflow: auto;
+}
+
+.uploadImage {
+  position: absolute;
+  bottom: 0.5rem;
+  right: 0.5rem;
+  background: #fff;
+  border-radius: .5rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border: 1px solid #E5E7EB;
+  cursor: pointer;
+  padding: .5rem;
+}
+
+.uploadImage>svg {
+  width: 1rem;
+  height: 1rem;
+}
+
+.checkList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  padding-left: 4rem;
+}
+
+.checkItem {
+  width: 100%;
+  height: auto;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  gap: .5rem;
+
+}
+
+.check {
+  width: 1.1rem;
+  height: 1.1rem;
+  border: solid 1px #D1D5DB;
+  border-radius: .25rem;
+  cursor: pointer;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.checked {
+  background: #FF9300;
+}
+
+.checked>svg {
+  width: .7rem;
+  height: .7rem;
+  fill: #fff;
+}
+
+.checkItem>.el-input {
+  width: calc(100% - 10rem);
+}
+
+.addCheck {
+  border-radius: 5px;
+  border: 1px dashed #d1d5db;
+  padding: .3rem .8rem;
+  height: fit-content;
+  width: fit-content;
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  cursor: pointer;
+  margin-left: 2.2rem;
+}
+
+.addCheck>svg {
+  width: .5rem;
+  height: .5rem;
+  fill: #6E7583;
+}
+
+.addCheck>span {
+  font-weight: bold;
+  font-size: .8rem;
+  color: #6b7280;
+}
+
+.btn {
+  display: flex;
+  align-items: center;
+  gap: .25em;
+}
+
+.btn>div {
+  width: 1.5rem;
+  height: 1.5rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #F9FAFB;
+  border-radius: .4px;
+  cursor: pointer;
+}
+
+.btn>div>svg {
+  width: 1rem;
+  height: 1rem;
+  fill: #6B7280;
+}
+
+.explanation {
+  width: 100%;
+  height: auto;
+  padding: 1rem;
+  background: #FAFBFC;
+  border-radius: 5px;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  border-radius: .8rem;
+}
+
+.e_header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.e_header>span {
+  color: #6b7280;
+  font-size: .8rem;
+  font-weight: 500;
+}
+
+.e_header>div {
+  display: flex;
+  align-items: center;
+  gap: .5rem;
+  background: #ff9300;
+  color: #fff;
+  padding: .3rem .8rem;
+  font-size: .8rem;
+  font-weight: 500;
+  border-radius: .5rem;
+  cursor: pointer;
+}
+
+.e_header>div>svg {
+  width: .8rem;
+  height: .8rem;
+  fill: #fff;
+}
+
+.imageList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 1rem;
+}
+.imageList>div{
+  width: 100px;
+  height: 100px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  /* overflow: hidden; */
+  border-radius: .5rem;
+  position: relative;
+
+}
+
+.imageList>div:hover>svg{
+  display: flex;
+}
+
+.imageList>div>svg{
+  width: 1rem;
+  height: 1rem;
+  position: absolute;
+  top: -.3rem;
+  right: -.3rem;
+  font-weight: 500;
+  border-radius: .5rem;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  display: none;
+}
+
+</style>

+ 1 - 1
src/components/pages/workPage/components/setVoteQuestion.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="setChoiceQuestion">
     <div class="head_title">{{ lang.ssVoteTopic }}</div>
-    <div class="testItem" v-for="(item, index) in jsonData.testJson" :key="item.id">
+    <div class="testItem" v-for="(item) in jsonData.testJson" :key="item.id">
       <div class="ti_title">
         <el-input class="ti_t_input" type="textarea" v-model="item.teststitle" :rows="3" :autosize="{ minRows: 3, maxRows: 6 }" resize="none" :placeholder="lang.ssEnterTextTitle" @input="setTestTitle(item.id)"></el-input>
         <div class="uploadImage" @click="uploadImage(item.id)">

+ 24 - 4
src/components/pages/workPage/index_new.vue

@@ -6,6 +6,8 @@
       @changeWorkData="changeWorkData" />
     <voteQuestion ref="voteQuestionRef" v-if="workData.type === '78'" :workData="workData"
       @changeWorkData="changeWorkData" />
+    <photo ref="photoRef" v-if="workData.type === '79'" :workData="workData"
+      @changeWorkData="changeWorkData" />
   </div>
 </template>
 
@@ -15,11 +17,13 @@ import "katex/dist/katex.min.css";
 import questionsAndAnswers from "./components/questionsAndAnswers.vue";
 import choiceQuestion from "./components/choiceQuestion.vue";
 import voteQuestion from "./components/voteQuestion.vue";
+import photo from "./components/photo.vue";
 export default {
   components: {
     questionsAndAnswers,
     choiceQuestion,
-    voteQuestion
+    voteQuestion,
+    photo
   },
   data() {
     return {
@@ -122,10 +126,13 @@ export default {
                   item.userAnswer = "";
                 }
               });
+            }else if(_data.type == 79){
+              _data.json.fileList = [];
             }
 
             this.workData = _data;
             this.studentWorkToWorkData();
+            this.getSubmitWork();
           }
         });
     },
@@ -260,9 +267,21 @@ export default {
             content: encodeURIComponent(JSON.stringify(this.workData.json)),
             type: "22"
           });
+        } else if (this.workData.type == "79") {
+          //照片题
+          params.push({
+            uid: this.userid,
+            cid: this.courseid,
+            stage: 0,
+            task: task,
+            tool: 0,
+            atool: "79",
+            content: encodeURIComponent(JSON.stringify(this.workData.json)),
+            type: "23"
+          });
         }
         if (
-          ["3", "8", "22"].includes(params[0].type) &&
+          ["3", "8", "22", "23"].includes(params[0].type) &&
           params[0].uid &&
           params[0].cid
         ) {
@@ -329,7 +348,7 @@ export default {
             this.loading = false;
             if (_data.length) {
               _data = _data[0];
-              if (["15", "45", "78"].includes(_data.atool)) {
+              if (["15", "45", "78", "79"].includes(_data.atool)) {
                 let _work = JSON.parse(decodeURIComponent(_data.content));
                 this.studentWork = _work;
                 this.studentWorkToWorkData();
@@ -378,6 +397,8 @@ export default {
                 _work.testJson[index].userAnswer;
             }
           });
+        }else if(this.workData.type == "79"){
+          this.workData.json.fileList = _work.fileList;
         }
         this.$forceUpdate();
       }
@@ -393,7 +414,6 @@ export default {
   },
   mounted() {
     this.getWorkData();
-    this.getSubmitWork();
     window.submitWork = this.submitWork;
   }
 };

+ 7 - 1
src/components/pages/workPage/setIndex.vue

@@ -4,6 +4,7 @@
     <setChoiceQuestion :workData="workData" v-if="workData.type == 45" @setTestJson="setTestJson" @save="saveTest"/>
     <setQuestionsAndAnswers :workData="workData" v-if="workData.type == 15" @setTestJson="setTestJson" @save="saveTest"/>
     <setVoteQuestion :workData="workData" v-if="workData.type == 78" @setTestJson="setTestJson" @save="saveTest"/>
+    <setPhoto :workData="workData" v-if="workData.type == 79" @setTestJson="setTestJson" @save="saveTest"/>
   </div>
 </template>
 
@@ -11,6 +12,7 @@
 import setChoiceQuestion from './components/setChoiceQuestion.vue'
 import setQuestionsAndAnswers from './components/setQuestionsAndAnswers.vue'
 import setVoteQuestion from './components/setVoteQuestion.vue'
+import setPhoto from './components/setPhoto.vue'
 
 function debounce(func, wait) {
   let timeout;
@@ -26,7 +28,8 @@ export default {
   components: {
     setChoiceQuestion,
     setQuestionsAndAnswers,
-    setVoteQuestion
+    setVoteQuestion,
+    setPhoto
   },
   data() {
     return {
@@ -78,6 +81,9 @@ export default {
                 //   item.userAnswer = "";
                 // }
               });
+            }else if (_data.type == 79) {
+              _data.json.answer = "";
+              _data.json.fileList = [];
             }
             this.type = _data.type;
 

+ 9 - 2
src/lang/cn.json

@@ -1055,6 +1055,7 @@
   "ssOnlyStudentsDesc":"仅对发布的班级学生可见,其他人无法访问",
   "ssOrganizationVisible":"组织可见",
   "ssOrganizationDesc":"学校内所有教师均可查看",
+  "ssAIAssistant":"AI助手",
   "ssCourseCover":"课程封面",
   "ssHoverToSelectUpload":"悬浮选择上传方式",
   "ssUploadFromLocal":"自本地上传",
@@ -1883,6 +1884,9 @@
   "ssCourseDesign":"课程设计",
   "ssInterVideo":"交互视频",
   "ssPhoto":"拍照",
+  "ssPhotoTip":"拍照指引",
+  "ssTakePhoto":"拍照上传",
+  "ssFileUpload":"文件上传",
   "ssAIAgent":"AI智能体",
   "ssPPT":"PPT",
   "ssModify":"修 改",
@@ -1928,6 +1932,7 @@
   "ssBilibiliVideo":"Bilibili视频",
   "ssQAQuestion":"问答题",
   "ssQAQuestionTool":"问答题工具",
+  "ssPhotoTool":"拍照工具",
   "ssBilibiliVideoSearch":"Bilibili视频检索",
   "ssBiliLoading":"正在检索中,请稍等...",
   "ssBiliSearchKey":"搜索视频关键字(如需搜索多个可,隔开)",
@@ -2011,7 +2016,8 @@
   "ssUploadTip":"支持格式:.xlsx,.xls,大小不超过10MB",
   "ssUploadTempLbl":"上传模板:",
   "ssDownloadTemp":"下载模板",
-  "ssUploadNote":"提示:请按照模板格式填写学生信息并导入。",
+  "ssUploadNote":"提示:请按照模板填写学生信息。",
+  "ssAccColOptional":"账户列非必填:手动输入则以输入为准,未输入则由系统自动生成。",
   "ssGetSuffixReUp":"正在获取后缀,请重新上传",
   "ssGetSuffixReAdd":"正在获取后缀,请重新添加",
   "ssCheckStuNameCol":"请检查上传文件学生姓名列是否填写正确",
@@ -2036,6 +2042,7 @@
   "ssPPtUpProgress":"上传进度(*)",
   "ssBilibiliVideoSearchKeyword":"请输入关键词",
   "ssEditGrade":"编辑年级",
+  "ssStuAccHd":"账户",
   "ssConfirmDeleteClassStudentone":"确认移除*学生?",
   "ssExplanationTip":"解释说明",
   "ssAIGenerate":"AI生成",
@@ -2047,7 +2054,7 @@
   "ssSelectCourseType":"请选择课程类型",
   "ssSelectedCourse":"已选择 * 个课程",
   "ssSelectedApp":"已选择 * 个应用",
-  "ssSyncImportClassInfo":"提示: 如需同步导入班级信息,请于此处下载导入模板,并于【班级】列准确输入年级+班级名称作为学生班级(兴趣班不支持导入学生)。",
+  "ssSyncImportClassInfo":"提示:如需同步导入班级信息,请于模板中的班级列,输入当前年级+班级名称作为学生班级(如六年级01班,兴趣班不支持新建学生)。",
   "ssNoSettingAnswer":"未设置正确答案",
   "allGrades": "全部年级",
   "ssVoteTopic": "投票主题"

+ 9 - 2
src/lang/en.json

@@ -1050,6 +1050,7 @@
   "ssOnlyStudentsDesc":"Only visible to students in the published class, others cannot access",
   "ssOrganizationVisible":"Organization visible",
   "ssOrganizationDesc":"All teachers in the school can view",
+  "ssAIAssistant":"AI Assistant",
   "ssCourseCover":"Course Cover",
   "ssHoverToSelectUpload":"Hover to select upload method",
   "ssUploadFromLocal":"Upload from local",
@@ -1882,6 +1883,9 @@
   "ssCourseDesign":"Course Design",
   "ssInterVideo":"Interactive Video",
   "ssPhoto":"Photo",
+  "ssPhotoTip":"Photo Guide",
+  "ssTakePhoto":"Take Photo",
+  "ssFileUpload":"File Upload",
   "ssAIAgent":"AI Agent",
   "ssPPT":"PPT",
   "ssModify":"Modify",
@@ -1927,6 +1931,7 @@
   "ssBilibiliVideo":"Youtube Video",
   "ssQAQuestion":"QA Question",
   "ssQAQuestionTool":"QA Question Tool",
+  "ssPhotoTool":"Photo Tool",
   "ssBilibiliVideoSearch":"Search YouTube Videos",
   "ssBiliLoading":"Searching, please wait...",
   "ssBiliSearchKey":"Search video keywords (multiple can be separated by commas)",
@@ -2010,7 +2015,8 @@
   "ssUploadTip":"Supported: xlsx, xls , up to 10MB",
   "ssUploadTempLbl":"Upload template:",
   "ssDownloadTemp":"Download template",
-  "ssUploadNote":"Tip: Please fill in student information according to the template format to avoid import failure",
+  "ssUploadNote":"Tip: Please fill in student information according to the template format.",
+  "ssAccColOptional":"Account column is optional: manual input takes priority; if empty, it will be auto-generated by the system.",
   "ssGetSuffixReUp":"Getting suffix, please re-upload",
   "ssGetSuffixReAdd":"Getting suffix, please re-add",
   "ssCheckStuNameCol":"Please check whether the student name column in the uploaded file is correct",
@@ -2035,6 +2041,7 @@
   "ssPPtUpProgress":"Uploading (*)",
   "ssBilibiliVideoSearchKeyword":"Please enter a keyword",
   "ssEditGrade":"Edit Grade",
+  "ssStuAccHd":"Account",
   "ssConfirmDeleteClassStudentone":"Confirm remove * student?",
   "ssExplanationTip":"Explanation",
   "ssAIGenerate":"AI Generate",
@@ -2047,7 +2054,7 @@
   "ssSelectedCourse":"Selected * courses",
   "ssSelectedApp":"Selected * apps",
   "ssNoSettingAnswer":"No correct answer set",
-  "ssSyncImportClassInfo":"Tip: If you need to synchronize import class information, please download the import template here, and accurately enter the grade + class name as the student class in the [Class] column (interest classes do not support importing students).",
+  "ssSyncImportClassInfo":"Tip: For importing class information, please enter the grade + class name in the [Class] column as the student class (e.g., 6th grade 01 class, interest classes do not support importing students).",
   "allGrades": "All Grades",
   "ssVoteTopic": "Voting Theme"
 }

+ 9 - 2
src/lang/hk.json

@@ -1053,6 +1053,7 @@
   "ssOnlyStudentsDesc":"僅對發佈的班級學生可見,其他人無法訪問",
   "ssOrganizationVisible":"組織可見",
   "ssOrganizationDesc":"學校內所有教師均可查看",
+  "ssAIAssistant":"AI助手",
   "ssCourseCover":"課程封面",
   "ssHoverToSelectUpload":"懸浮選擇上傳方式",
   "ssUploadFromLocal":"自本地上傳",
@@ -1883,6 +1884,9 @@
   "ssCourseDesign":"課程設計",
   "ssInterVideo":"交互視頻",
   "ssPhoto":"拍照",
+  "ssPhotoTip":"拍照指引",
+  "ssTakePhoto":"拍照上傳",
+  "ssFileUpload":"文件上傳",
   "ssAIAgent":"AI智能體",
   "ssPPT":"PPT",
   "ssModify":"修 改",
@@ -1927,6 +1931,7 @@
   "ssBilibiliVideo":"Youtube視頻",
   "ssQAQuestion":"問答題",
   "ssQAQuestionTool":"問答題工具",
+  "ssPhotoTool":"拍照工具",
   "ssBilibiliVideoSearch":"Youtube視頻檢索",
   "ssBiliLoading":"正在檢索中,請稍等...",
   "ssBiliSearchKey":"搜索視頻關鍵字(如需搜索多個可,隔開)",
@@ -2010,7 +2015,8 @@
   "ssUploadTip":"支持格式:.xlsx,.xls,大小不超過10MB",
   "ssUploadTempLbl":"上傳模板:",
   "ssDownloadTemp":"下載模板",
-  "ssUploadNote":"提示:請按照模板格式填寫學生信息,避免導入失敗",
+  "ssUploadNote":"提示:請按照模板格式填寫學生信息。",
+  "ssAccColOptional":"賬戶列非必填:手動輸入則以輸入為準,未輸入則由系統自動生成。",
   "ssGetSuffixReUp":"正在獲取後綴,請重新上傳",
   "ssGetSuffixReAdd":"正在獲取後綴,請重新添加",
   "ssCheckStuNameCol":"請檢查上傳文件學生姓名列是否填寫正確",
@@ -2035,6 +2041,7 @@
   "ssPPtUpProgress":"上傳進度(*)",
   "ssBilibiliVideoSearchKeyword":"請輸入關鍵詞",
   "ssEditGrade":"修改年級",
+  "ssStuAccHd":"賬戶",
   "ssConfirmDeleteClassStudentone":"確定移除 * 名學生嗎?",
   "ssExplanationTip":"解釋說明",
   "ssAIGenerate":"AI生成",
@@ -2048,7 +2055,7 @@
   "ssSelectedApp":"已選擇 * 個應用",
   "ssCocoNoteUpdateTips":"協同建構不支持修改基本信息,只支持加入分組。",
   "ssNoSettingAnswer":"未設置正確答案",
-  "ssSyncImportClassInfo":"提示: 如需同步導入班級信息,請於此處下載導入模板,並於【班級】列準確輸入年級+班級名稱作為學生班級(興趣班不支持導入學生)。",
+  "ssSyncImportClassInfo":"提示:如需同步導入班級信息,請於模板中的班級列,輸入當前年級+班級名稱作為學生班級(如六年級01班,興趣班不支持導入學生)。",
   "allGrades": "全部年級",
   "ssVoteTopic": "投票主題"
 }

Some files were not shown because too many files changed in this diff