瀏覽代碼

Merge branch 'beta'

SanHQin 1 月之前
父節點
當前提交
1d72c405bf
共有 33 個文件被更改,包括 2437 次插入90 次删除
  1. 1 1
      dist/index.html
  2. 0 0
      dist/static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css
  3. 0 0
      dist/static/css/app.2f9d44a02620843ebcc0419c2bd7a586.css
  4. 0 0
      dist/static/css/app.2f9d44a02620843ebcc0419c2bd7a586.css.map
  5. 0 0
      dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css
  6. 0 0
      dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css.map
  7. 0 0
      dist/static/css/workPage.55d056a84d889305d0062550f70d674d.css
  8. 0 0
      dist/static/css/workPage.55d056a84d889305d0062550f70d674d.css.map
  9. 0 0
      dist/static/js/app.b520dbc5f4631f6c25f3.js
  10. 0 0
      dist/static/js/app.b520dbc5f4631f6c25f3.js.map
  11. 0 0
      dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map
  12. 0 0
      dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map
  13. 0 0
      dist/static/js/workPage.b8a98faedbade6fa9418.js
  14. 0 0
      dist/static/js/workPage.b8a98faedbade6fa9418.js.map
  15. 0 0
      dist/static/js/workPage.e8ba67d8caed072748d8.js
  16. 0 0
      dist/static/js/workPage.e8ba67d8caed072748d8.js.map
  17. 1 1
      dist/workPage.html
  18. 5 0
      src/App.vue
  19. 9 2
      src/components/pages/pptEasy/addCourse2.vue
  20. 57 8
      src/components/pages/pptEasy/addCourse3.vue
  21. 2 2
      src/components/pages/pptEasy/commpont/aidia.vue
  22. 767 0
      src/components/pages/pptEasy/dialog/BilibiliSearchDialog2.vue
  23. 293 0
      src/components/pages/pptEasy/dialog/VideoUploadDialog2.vue
  24. 886 0
      src/components/pages/pptEasy/dialog/appDialog.vue
  25. 63 18
      src/components/pages/studentManageNew/component/addstu.vue
  26. 5 5
      src/components/pages/studentManageNew/component/table.vue
  27. 3 3
      src/components/pages/studentManageNew/index.vue
  28. 55 5
      src/components/pages/workPage/components/choiceQuestion.vue
  29. 250 30
      src/components/pages/workPage/components/setChoiceQuestion.vue
  30. 2 0
      src/components/pages/workPage/components/setQuestionsAndAnswers.vue
  31. 21 5
      src/lang/cn.json
  32. 9 4
      src/lang/en.json
  33. 8 6
      src/lang/hk.json

+ 1 - 1
dist/index.html

@@ -37,7 +37,7 @@
       width: 100%;
       width: 100%;
       background: #e6eaf0;
       background: #e6eaf0;
       font-family: '黑体';
       font-family: '黑体';
-    }</style><link href=./static/css/app.14aba7d36141b10cf095aa5442b4c6fe.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.202dce7582036aaca568.js></script></body></html><script>function stopSafari() {
+    }</style><link href=./static/css/app.2f9d44a02620843ebcc0419c2bd7a586.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.b520dbc5f4631f6c25f3.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {
     document.documentElement.addEventListener("touchstart", function (event) {

文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/app.14aba7d36141b10cf095aa5442b4c6fe.css


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/app.2f9d44a02620843ebcc0419c2bd7a586.css


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/app.2f9d44a02620843ebcc0419c2bd7a586.css.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/workPage.3639185b5b0b118d5c023498ff9db830.css.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/workPage.55d056a84d889305d0062550f70d674d.css


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/workPage.55d056a84d889305d0062550f70d674d.css.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/app.b520dbc5f4631f6c25f3.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/app.b520dbc5f4631f6c25f3.js.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/manifest.23ea04dc469b57e2b4f8.js.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/workPage-manifest.2ece51fa34be51c8610a.js.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/workPage.b8a98faedbade6fa9418.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/workPage.b8a98faedbade6fa9418.js.map


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/workPage.e8ba67d8caed072748d8.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/workPage.e8ba67d8caed072748d8.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.3639185b5b0b118d5c023498ff9db830.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.e8ba67d8caed072748d8.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.55d056a84d889305d0062550f70d674d.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.b8a98faedbade6fa9418.js></script></body></html><script>function stopSafari() {
     //阻止safari浏览器双击放大功能
     //阻止safari浏览器双击放大功能
     let lastTouchEnd = 0  //更新手指弹起的时间
     let lastTouchEnd = 0  //更新手指弹起的时间
     document.documentElement.addEventListener("touchstart", function (event) {
     document.documentElement.addEventListener("touchstart", function (event) {

+ 5 - 0
src/App.vue

@@ -545,4 +545,9 @@ html::-webkit-scrollbar-thumb {
   background: none;
   background: none;
   z-index: 99999;
   z-index: 99999;
 }
 }
+
+.orange_number {
+  color: #FF9400;
+  font-weight: bold;
+}
 </style>
 </style>

+ 9 - 2
src/components/pages/pptEasy/addCourse2.vue

@@ -1623,9 +1623,16 @@ export default {
       if (this.uploadWorkLoading) return;
       if (this.uploadWorkLoading) return;
       this.uploadWorkLoading = true;
       this.uploadWorkLoading = true;
       let _pptData = await this.getPPtJson();
       let _pptData = await this.getPPtJson();
-
+      const _pptData2 = JSON.parse(JSON.stringify(_pptData))
+      if (_pptData2.slides) {
+        _pptData2.slides.forEach((slide) => {
+          if (slide.elements) {
+            slide.elements = slide.elements.filter((element) => element.type !== 'image')
+          }
+        })
+      }
       // 用_pptData生成json文件,并生成File对象
       // 用_pptData生成json文件,并生成File对象
-      const pptJsonStr = JSON.stringify(_pptData, null, 2);
+      const pptJsonStr = JSON.stringify(_pptData2, null, 2);
       const pptJsonFile = new File([pptJsonStr], this.courseName + ".json", { type: "application/json" });
       const pptJsonFile = new File([pptJsonStr], this.courseName + ".json", { type: "application/json" });
       // 你可以根据需要将pptJsonFile上传或保存
       // 你可以根据需要将pptJsonFile上传或保存
 
 

+ 57 - 8
src/components/pages/pptEasy/addCourse3.vue

@@ -466,7 +466,7 @@
     <!-- Bilibili视频检索弹窗 -->
     <!-- Bilibili视频检索弹窗 -->
     <BilibiliSearchDialog :visible.sync="dialogVisibleBilibiliSearch" :courseName="courseName"
     <BilibiliSearchDialog :visible.sync="dialogVisibleBilibiliSearch" :courseName="courseName"
       :grade="selectedGradeName" @addVideo="handleBilibiliVideoAdd" />
       :grade="selectedGradeName" @addVideo="handleBilibiliVideoAdd" />
-    <appDialog ref="appDialog" @success="selectAppSuccess"></appDialog>
+    <appDialog ref="appDialog" @success="selectAppSuccess"  @success2="selectAppSuccess2"></appDialog>
     <el-dialog :title="lang.ssCreateChoice" :visible.sync="dialogVisibleChoice" :append-to-body="true" width="800px"
     <el-dialog :title="lang.ssCreateChoice" :visible.sync="dialogVisibleChoice" :append-to-body="true" width="800px"
       :before-close="done => {
       :before-close="done => {
         closePan(45);
         closePan(45);
@@ -914,13 +914,13 @@
 import "../../../common/aws-sdk-2.235.1.min.js";
 import "../../../common/aws-sdk-2.235.1.min.js";
 import { tools as toolsData } from "../../../common/tools.js";
 import { tools as toolsData } from "../../../common/tools.js";
 import $ from "jquery";
 import $ from "jquery";
-import appDialog from "../components/appDialog.vue";
+import appDialog from "./dialog/appDialog.vue";
 import { myMixin } from "@/mixins/mixin.js";
 import { myMixin } from "@/mixins/mixin.js";
 import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
 import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
-import BilibiliSearchDialog from "./dialog/BilibiliSearchDialog.vue";
+import BilibiliSearchDialog from "./dialog/BilibiliSearchDialog2.vue";
 import { v4 as uuidv4 } from "uuid";
 import { v4 as uuidv4 } from "uuid";
 import InteractiveToolDialog from "./dialog/InteractiveToolDialog.vue";
 import InteractiveToolDialog from "./dialog/InteractiveToolDialog.vue";
-import VideoUploadDialog from "./dialog/VideoUploadDialog.vue";
+import VideoUploadDialog from "./dialog/VideoUploadDialog2.vue";
 
 
 var OpenCC = require("opencc-js");
 var OpenCC = require("opencc-js");
 let converter = OpenCC.Converter({
 let converter = OpenCC.Converter({
@@ -1901,9 +1901,16 @@ export default {
         this.uploadWorkLoading = true;
         this.uploadWorkLoading = true;
       }
       }
       let _pptData = await this.getPPtJson();
       let _pptData = await this.getPPtJson();
-
+      const _pptData2 = JSON.parse(JSON.stringify(_pptData))
+      if (_pptData2.slides) {
+        _pptData2.slides.forEach((slide) => {
+          if (slide.elements) {
+            slide.elements = slide.elements.filter((element) => element.type !== 'image')
+          }
+        })
+      }
       // 用_pptData生成json文件,并生成File对象
       // 用_pptData生成json文件,并生成File对象
-      const pptJsonStr = JSON.stringify(_pptData, null, 2);
+      const pptJsonStr = JSON.stringify(_pptData2, null, 2);
       const pptJsonFile = new File([pptJsonStr], this.courseName + ".json", { type: "application/json" });
       const pptJsonFile = new File([pptJsonStr], this.courseName + ".json", { type: "application/json" });
       // 你可以根据需要将pptJsonFile上传或保存
       // 你可以根据需要将pptJsonFile上传或保存
       console.log(_url)
       console.log(_url)
@@ -2482,11 +2489,11 @@ export default {
         // this.dialogVisible8 = true;
         // this.dialogVisible8 = true;
       } else if (tool == 72) {
       } else if (tool == 72) {
         this.$refs.appDialog.openG(
         this.$refs.appDialog.openG(
-          { url: "" },
+          [],
           "",
           "",
           "",
           "",
           "",
           "",
-          2
+          1
         );
         );
       } else if (tool == 73) {
       } else if (tool == 73) {
         this.line = "";
         this.line = "";
@@ -2625,6 +2632,21 @@ export default {
       this.editId = null;
       this.editId = null;
       this.setPPtToolList();
       this.setPPtToolList();
     },
     },
+    selectAppSuccess2({ data, type }) {
+      for (let i = 0; i < data.length; i++) {
+        let _data = { id: new Date().getTime(), tool: 72, title: data[i].name, brief: data[i].detail, json: data[i], icon: data[i].json.icon, url: data[i].url }
+        if (this.editId) {
+          let oldData = this.pptCourseJson.toolsList.find(i => i.id === this.editId);
+          _data.id = oldData.id;
+          this.pptCourseJson.toolsList.splice(this.pptCourseJson.toolsList.findIndex(i => i.id === this.editId), 1, _data);
+        } else {
+          this.pptCourseJson.toolsList.push(_data);
+          this.addContent(_data)
+        }
+      }
+      this.editId = null;
+      this.setPPtToolList();
+    },
     // 打开应用中心
     // 打开应用中心
     openApplicationCenter() {
     openApplicationCenter() {
       // 创建Cocorobo链接工具项
       // 创建Cocorobo链接工具项
@@ -3057,6 +3079,32 @@ export default {
         });
         });
       }
       }
     },
     },
+    toolBtn2(type, id, tool){
+      let _data = this.pptCourseJson.toolsList.find(i => i.id === id || i.url === id);
+      this.editId = _data.id;
+      if (tool == 45) {
+        this.testJsonName = "";
+        this.testJsonBrief = "";
+        this.testJson = {
+          testCount: 1,
+          testTitle: "",
+          testJson: [
+            {
+              teststitle: "",
+              testItem: 1,
+              checkList: [],
+              timuList: [],
+              answer: [],
+              type: "1"
+            }
+          ]
+        };
+         this.addTest()
+      } else if (tool == 15) {
+        this.answerQ = "";
+        this.addAnswer();
+      }
+    },
     clearLine() {
     clearLine() {
       this.line = "";
       this.line = "";
       this.dialogVisible7 = false;
       this.dialogVisible7 = false;
@@ -3275,6 +3323,7 @@ export default {
     window.openVideoUploadDialog = () => this.openVideoUploadDialog(); // 打开视频上传弹窗
     window.openVideoUploadDialog = () => this.openVideoUploadDialog(); // 打开视频上传弹窗
     window.openApplicationCenter = () => this.openApplicationCenter(); // 打开应用中心弹窗
     window.openApplicationCenter = () => this.openApplicationCenter(); // 打开应用中心弹窗
     window.toolBtn = (type, id) => this.toolBtn(type, id); // 工具按钮点击事件
     window.toolBtn = (type, id) => this.toolBtn(type, id); // 工具按钮点击事件
+    window.toolBtn2 = (type, id, tool) => this.toolBtn2(type, id, tool); // 工具按钮点击事件
     window.previewVideo = (id) => this.previewVideo(id); // 预览视频
     window.previewVideo = (id) => this.previewVideo(id); // 预览视频
     window.goBack = () => this.goTo(`/course?userid=${this.userid}&oid=${this.oid}&org=${this.org}&role=${this.role}`);
     window.goBack = () => this.goTo(`/course?userid=${this.userid}&oid=${this.oid}&org=${this.org}&role=${this.role}`);
     window.lastSteps = () => this.lastSteps(); // 上一步
     window.lastSteps = () => this.lastSteps(); // 上一步

+ 2 - 2
src/components/pages/pptEasy/commpont/aidia.vue

@@ -40,10 +40,10 @@
                     </div>
                     </div>
             </div>
             </div>
             <div class="course_item_footer">
             <div class="course_item_footer">
-                <div>{{ lang.ssSelectedCourse.replace(/\*/g, selectedCourseList.length) }}</div>
+                <div v-html="lang.ssSelectedCourse.replace(/\*/g, '<span class=&quot;orange_number&quot;>' + selectedCourseList.length + '</span>')"></div>
                 <div class="confirm_btn" @click="confirmAddCourse">
                 <div class="confirm_btn" @click="confirmAddCourse">
                     <img src="../../../../assets/stuImg/ai6dui.svg" alt="">
                     <img src="../../../../assets/stuImg/ai6dui.svg" alt="">
-                    {{ lang.ssConfirm }}
+                    {{ lang.ssAdd }}
                 </div>
                 </div>
             </div>
             </div>
         </el-dialog>
         </el-dialog>

+ 767 - 0
src/components/pages/pptEasy/dialog/BilibiliSearchDialog2.vue

@@ -0,0 +1,767 @@
+<template>
+	<div class="bilibili-search-modal" v-if="dialogVisible">
+		<div class="modal-overlay"></div>
+		<div class="modal-content bilibili-search-content">
+			<div class="modal-header">
+				<h3 class="modal-title">{{ lang.ssBilibiliVideoSearch }}</h3>
+				<div class="modal-close" @click="handleClose()">×</div>
+			</div>
+			<div class="modal-body" v-loading="loading" :element-loading-text="lang.ssBilibiliVideoSearchLoading">
+				<!-- 搜索和筛选区域 -->
+				<div class="search-filter-box">
+					<div class="search-item">
+						<div class="search-input-wrapper">
+							<el-input 
+								class="inputC" 
+								:placeholder="lang.ssBilibiliVideoSearchKeyword" 
+								v-model="searchKeyword"
+								@keyup.enter.native="handleSearch"
+							></el-input>
+							<div class="search_img" @click="handleSearch">
+								<img src="../../../../assets/icon/search.png" alt />
+							</div>
+						</div>
+					</div>
+					<div class="filter-item">
+						<el-select v-model="navActive" @change="navClick" :placeholder="lang.ssBiSort" class="sort-select">
+							<el-option :label="lang.ssBiSort" :value="0"></el-option>
+							<el-option :label="lang.ssBiPlay" :value="1"></el-option>
+							<el-option :label="lang.ssBiRelease" :value="2"></el-option>
+							<el-option :label="lang.ssBitDanmaku" :value="3"></el-option>
+							<el-option :label="lang.ssBiFavorite" :value="4"></el-option>
+						</el-select>
+					</div>
+					<div class="add-item">
+						<el-button type="primary" style="background-color: #FF9300;border-color: #FF9300;" @click="batchAdd" :disabled="selectedVideos.length === 0">{{ lang.ssAddbl }}</el-button>
+					</div>
+				</div>
+				<!-- 视频列表 -->
+				<div class="Box" v-if="lang.lang == 'cn'">
+					<div 
+						class="video_box video_box2" 
+						:class="{ 'selected': isVideoSelected(item) }"
+						v-for="(item, index) in paginatedData" 
+						:key="index"
+						@click="toggleVideoSelection(item)"
+					>
+						<div class="video-checkbox" @click.stop>
+							<el-checkbox 
+                class="check"
+								:value="isVideoSelected(item)" 
+								@change="toggleVideoSelection(item)"
+							></el-checkbox>
+						</div>
+						<span class="name" v-html="item.title"></span>
+						<span class="detail">{{ item.description || '' }}</span>
+						<div class="video-info">
+							<span class="author">{{ lang.ssAut }}:{{ item.author || '' }}</span>
+							<span class="duration">{{ lang.ssDuration }}:{{ item.duration || '' }}</span>
+						</div>
+						<div class="tag" v-if="item.tag && typeof item.tag === 'string' && item.tag.split(',').length > 0">
+							<el-tooltip :content="tag" placement="top" effect="dark" v-for="(tag, index) in item.tag.split(',').slice(0, 5)" :key="index">
+								<span>{{ tag }}</span>
+							</el-tooltip>
+						</div>
+						<div class="external-link" @click.stop="openUrl(item.bvid)" :title="lang.ssView">
+							<svg t="1755224440400" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4991" width="16" height="16">
+								<path d="M853.333 469.333a42.667 42.667 0 0 0-42.666 42.667v256a42.667 42.667 0 0 1-42.667 42.667H256a42.667 42.667 0 0 1-42.667-42.667V256a42.667 42.667 0 0 1 42.667-42.667h256a42.667 42.667 0 0 0 0-85.333H256a128 128 0 0 0-128 128v512a128 128 0 0 0 128 128h512a128 128 0 0 0 128-128V512a42.667 42.667 0 0 0-42.667-42.667z" fill="#909399" p-id="4992"></path>
+								<path d="M682.667 213.333h270.933v270.933a42.667 42.667 0 1 0 85.334 0V170.667a42.667 42.667 0 0 0-42.667-42.667H682.667a42.667 42.667 0 0 0 0 85.333z" fill="#909399" p-id="4993"></path>
+								<path d="M894.293 174.293a42.667 42.667 0 0 0-60.586 0L591.147 417.707a42.667 42.667 0 0 0 60.586 60.586L894.293 234.88a42.667 42.667 0 0 0 0-60.587z" fill="#909399" p-id="4994"></path>
+							</svg>
+						</div>
+					</div>
+					<div v-if="data.length == 0" class="no_data">{{ lang.ssNoData }}</div>
+				</div>
+				<div class="Box" v-else>
+					<div 
+						class="video_box video_box2" 
+						:class="{ 'selected': isVideoSelected(item) }"
+						v-for="(item, index) in paginatedData" 
+						:key="index"
+						@click="toggleVideoSelection(item)"
+					>
+						<div class="video-checkbox" @click.stop>
+							<el-checkbox 
+								:value="isVideoSelected(item)" 
+								@change="toggleVideoSelection(item)"
+							></el-checkbox>
+						</div>
+						<span class="name" v-html="item.title"></span>
+						<span class="detail">{{ item.description || '' }}</span>
+						<div class="video-info">
+							<span class="author">{{ lang.ssAut }}:{{ item.channel.title || '' }}</span>
+							<span class="duration">{{ lang.ssDuration }}:{{ item.length || '' }}</span>
+						</div>
+						<div class="tag" v-if="item.badges && item.badges.length > 0">
+							<el-tooltip :content="tag" placement="top" effect="dark" v-for="(tag, index) in item.badges" :key="index">
+								<span>{{ tag }}</span>
+							</el-tooltip>
+						</div>
+						<div class="external-link" @click.stop="openUrl(item.id)" :title="lang.ssView">
+							<svg t="1755224440400" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4991" width="16" height="16">
+								<path d="M853.333 469.333a42.667 42.667 0 0 0-42.666 42.667v256a42.667 42.667 0 0 1-42.667 42.667H256a42.667 42.667 0 0 1-42.667-42.667V256a42.667 42.667 0 0 1 42.667-42.667h256a42.667 42.667 0 0 0 0-85.333H256a128 128 0 0 0-128 128v512a128 128 0 0 0 128 128h512a128 128 0 0 0 128-128V512a42.667 42.667 0 0 0-42.667-42.667z" fill="#909399" p-id="4992"></path>
+								<path d="M682.667 213.333h270.933v270.933a42.667 42.667 0 1 0 85.334 0V170.667a42.667 42.667 0 0 0-42.667-42.667H682.667a42.667 42.667 0 0 0 0 85.333z" fill="#909399" p-id="4993"></path>
+								<path d="M894.293 174.293a42.667 42.667 0 0 0-60.586 0L591.147 417.707a42.667 42.667 0 0 0 60.586 60.586L894.293 234.88a42.667 42.667 0 0 0 0-60.587z" fill="#909399" p-id="4994"></path>
+							</svg>
+						</div>
+					</div>
+					<div v-if="data.length == 0" class="no_data">{{ lang.ssNoData }}</div>
+				</div>
+
+				<!-- 分页控件 -->
+				<div class="pagination-box" v-if="data.length > 0">
+					<el-button 
+						:disabled="currentPage === 1" 
+						@click="prevPage"
+						size="small"
+					>←{{ lang.ssPrevPage }}</el-button>
+					<span class="page-info">{{ lang.ssPageInfo.replace('*', currentPage / totalPages) }}</span>
+					<el-button 
+						:disabled="currentPage >= totalPages" 
+						@click="nextPage"
+						size="small"
+					>{{ lang.ssNextPage }}→</el-button>
+				</div>
+			</div>
+			<div class="modal-footer">
+				<el-button @click="handleClose" style="background-color: #fff;border-color: #DCDFE6;color: #606266;">{{ lang.ssClose }}</el-button>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import _ from "lodash";
+
+export default {
+  name: "BilibiliSearchDialog",
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    courseName: {
+      type: String,
+      default: ""
+    },
+    grade: {
+      type: String,
+      default: ""
+    }
+  },
+  data() {
+    return {
+      dialogVisible: false,
+      searchKeyword: "",
+      loading: false,
+      data: [],
+      navActive: 0,
+      selectedVideos: [], // 选中的视频列表
+      currentPage: 1, // 当前页码
+      pageSize: 50, // 每页显示数量
+      totalPages: 1 // 总页数
+    };
+  },
+  watch: {
+    visible(newVal) {
+      this.dialogVisible = newVal;
+      if (newVal) {
+        this.initDialog();
+      }
+    },
+    dialogVisible(newVal) {
+      this.$emit('update:visible', newVal);
+    }
+  },
+  methods: {
+    handleClose() {
+      this.dialogVisible = false;
+      this.selectedVideos = [];
+      this.searchKeyword = "";
+      this.data = [];
+      this.currentPage = 1;
+    },
+    initDialog() {
+      this.selectedVideos = [];
+      // 默认以课程标题和已选择的年级为关键词
+      let keywords = [];
+      if (this.courseName) {
+        keywords.push(this.courseName);
+      }
+      if (this.grade) {
+        // 如果grade是多个年级用逗号分隔的,也需要处理
+        keywords.push(this.grade);
+      }
+      this.searchKeyword = keywords.join(',');
+      this.data = [];
+      this.currentPage = 1;
+      if (this.searchKeyword) {
+        this.handleSearch();
+      }
+    },
+    // 搜索视频
+    async handleSearch() {
+      if (!this.searchKeyword) {
+        this.$message.error(this.lang.ssEnterKeyword);
+        return;
+      }
+      try {
+        this.loading = true;
+        let keywords = [];
+        if (this.searchKeyword.split(",").length > 1) {
+          keywords = this.searchKeyword.split(",");
+        } else {
+          keywords = this.searchKeyword.split(",");
+        }
+        this.data = [];
+        let data2 = [];
+        for (var a = 0; a < keywords.length; a++) {
+          let _data = this.lang.lang == 'cn' ? await this.searchBilibili(keywords[a]) : await this.aiGet2(keywords[a]);
+          data2[a] = _data;
+        }
+        this.data = _.flatMap(_.zip(...data2), (pair) => pair.filter(value => value !== undefined));
+        this.currentPage = 1;
+        this.updateTotalPages();
+        this.loading = false;
+      } catch (error) {
+        console.log(error);
+        this.loading = false;
+        this.$message.error(this.lang.ssSearchFail);
+      }
+    },
+    async aiGet2(msg) {
+            let _this = this
+            return new Promise((resolve, reject) => {
+                this.ajax.post(`https://gpt4.cocorobo.cn/get_network_search`, {
+                    engine: "youtubeNew",
+                    keyword: msg,
+                    page: 1,
+                    page_size: 50,
+                    order: this.navActive,
+                    duration: 0,
+                }).then(response => {
+                    console.log(response);
+                    // _this.data = [..._this.data,...response.data.FunctionResponse]
+                    resolve(response.data.FunctionResponse)
+                })
+                    .catch((error) => {
+                        resolve([])
+                        console.log(error);
+                    });
+            });
+        },
+    // Bilibili搜索接口
+    async searchBilibili(keyword) {
+      return new Promise((resolve, reject) => {
+        this.ajax.post(`https://gpt4.cocorobo.cn/get_network_search`, {
+          engine: "bilibiliNew",
+          keyword: keyword,
+          page: 1,
+          page_size: 50,
+          order: this.navActive,
+          duration: 0,
+        }).then(response => {
+          console.log(response);
+          resolve(response.data.FunctionResponse || []);
+        }).catch((error) => {
+          console.log(error);
+          resolve([]);
+        });
+      });
+    },
+    // 切换排序方式
+    navClick(value) {
+      if (this.navActive == value) {
+        return;
+      }
+      this.navActive = value;
+      if (this.searchKeyword) {
+        this.handleSearch();
+      }
+    },
+    // 打开视频链接
+    openUrl(bvid) {
+      if (this.lang.lang == 'cn') {
+        window.open(`//www.bilibili.com/video/${bvid}`);
+      } else {
+        window.open('https://www.youtube.com/watch?v='+bvid)
+      }
+      // window.open(`//www.bilibili.com/video/${bvid}`);
+    },
+    // 添加单个视频
+    addSingleVideo(item) {
+      const videoTitle = item.title.replace(/<[^>]*>?/gm, ''); // 移除HTML标签
+      let url = '';
+      if (this.lang.lang == 'cn') {
+        url = `//player.bilibili.com/player.html?isOutside=true&bvid=${item.bvid}`;
+      } else {
+        url = 'https://www.youtube.com/embed/'+item.id;
+      }
+      const videoData = {
+        name: "链接",
+        title: item.title.replace(/<[^>]*>?/gm, ''),
+        url: url,
+        id: new Date().getTime(),
+        bvid: this.lang.lang == 'cn' ? item.bvid : item.id,
+        type: 75  // B站视频使用type 75
+      };
+      this.$emit('addVideo', videoData);
+      this.$message.success(this.lang.ssAddSuccess);
+      // 添加成功后关闭弹窗
+      this.handleClose();
+    },
+    // 检查视频是否被选中
+    isVideoSelected(item) {
+      if (this.lang.lang == 'cn') {
+        return this.selectedVideos.some(v => v.bvid === item.bvid);
+      } else {
+        return this.selectedVideos.some(v => v.id === item.id);
+      }
+    },
+    // 切换视频选择状态
+    toggleVideoSelection(item) {
+      let index = 0;
+      if (this.lang.lang == 'cn') {
+        index = this.selectedVideos.findIndex(v => v.bvid === item.bvid);
+      } else {
+        index = this.selectedVideos.findIndex(v => v.id === item.id);
+      }
+      // this.selectedVideos.findIndex(v => v.bvid === item.bvid);
+      if (index > -1) {
+        this.selectedVideos.splice(index, 1);
+      } else {
+        this.selectedVideos.push(item);
+      }
+    },
+    // 批量添加选中的视频
+    batchAdd() {
+      if (this.selectedVideos.length === 0) {
+        this.$message.warning(this.lang.ssSelectVideo);
+        return;
+      }
+      this.selectedVideos.forEach(video => {
+        const videoTitle = video.title.replace(/<[^>]*>?/gm, ''); // 移除HTML标签
+        let url = '';
+        if (this.lang.lang == 'cn') {
+          url = `//player.bilibili.com/player.html?isOutside=true&bvid=${video.bvid}`;
+        } else {
+          url = 'https://www.youtube.com/embed/'+video.id;
+        }
+        const videoData = {
+          name: this.lang.ssLink,
+          title: video.title.replace(/<[^>]*>?/gm, ''),
+          url: url,
+          id: new Date().getTime(),
+          bvid: this.lang.lang == 'cn' ? video.bvid : video.id,
+          type: 75  // B站视频使用type 75
+        };
+        this.$emit('addVideo', videoData);
+      });
+      this.$message.success(this.lang.ssAddSuccessVideo.replace('*', this.selectedVideos.length));
+      this.selectedVideos = [];
+      // 批量添加成功后关闭弹窗
+      this.handleClose();
+    },
+    // 清空选择
+    clearSelection() {
+      this.selectedVideos = [];
+    },
+    // 更新总页数
+    updateTotalPages() {
+      this.totalPages = Math.ceil(this.data.length / this.pageSize);
+    },
+    // 上一页
+    prevPage() {
+      if (this.currentPage > 1) {
+        this.currentPage--;
+      }
+    },
+    // 下一页
+    nextPage() {
+      if (this.currentPage < this.totalPages) {
+        this.currentPage++;
+      }
+    }
+  },
+  computed: {
+    // 获取当前页的数据
+    paginatedData() {
+      const start = (this.currentPage - 1) * this.pageSize;
+      const end = start + this.pageSize;
+      return this.data.slice(start, end);
+    }
+  }
+};
+</script>
+
+<style scoped>
+/* Bilibili搜索弹窗 */
+.bilibili-search-modal {
+	position: fixed;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	z-index: 1002;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.modal-overlay {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background-color: rgba(0, 0, 0, 0.5);
+}
+
+.modal-content {
+	position: relative;
+	z-index: 1003;
+	background-color: white;
+	border-radius: 8px;
+	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+	overflow: hidden;
+	width: 660px;
+	max-height: 90vh;
+	display: flex;
+	flex-direction: column;
+}
+
+.modal-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding: 20px 24px;
+	/* border-bottom: 1px solid #f0f0f0; */
+}
+
+.modal-title {
+	font-size: 18px;
+	font-weight: 600;
+	color: #333;
+	margin: 0;
+}
+
+.modal-close {
+	font-size: 24px;
+	color: #999;
+	cursor: pointer;
+	transition: all 0.3s;
+	width: 32px;
+	height: 32px;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	border-radius: 4px;
+}
+
+.modal-close:hover {
+	background-color: #f3f4f6;
+}
+
+.modal-body {
+	flex: 1;
+	overflow-y: auto;
+	padding: 0;
+	background: #fff;
+}
+
+.modal-footer {
+	padding: 15px 20px;
+	/* border-top: 1px solid #f0f0f0; */
+	background: #fff;
+	display: flex;
+	justify-content: flex-end;
+}
+
+/* 搜索和筛选区域 */
+.search-filter-box {
+    display: flex;
+    align-items: center;
+    gap: 15px;
+    margin-bottom: 15px;
+    padding: 15px;
+}
+
+.search-item {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    gap: 10px;
+}
+
+.search-label {
+    min-width: 80px;
+    font-size: 14px;
+    color: #606266;
+    text-align: right;
+}
+
+.search-input-wrapper {
+    flex: 1;
+    position: relative;
+}
+
+.inputC>>>.el-input__inner {
+    padding-right: 35px;
+    height: 40px;
+    line-height: 40px;
+}
+
+.search_img {
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    right: 10px;
+    top: 50%;
+    transform: translateY(-50%);
+    cursor: pointer;
+    z-index: 10;
+}
+
+.search_img>img {
+    width: 100%;
+    height: 100%;
+}
+
+.filter-item {
+    width: 150px;
+}
+
+.sort-select {
+    width: 100%;
+}
+
+.add-item {
+    width: 80px;
+}
+
+.Box {
+    width: 100%;
+    height: 440px;
+    overflow: auto;
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-start;
+    flex-wrap: wrap;
+    padding: 15px;
+    box-sizing: border-box;
+    background: #fff;
+}
+
+.video_box {
+    width: calc(50% - 10px);
+    margin-right: 10px;
+    display: flex;
+    flex-direction: column;
+    margin-bottom: 15px;
+    cursor: pointer;
+}
+
+.video_box2 {
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+    padding: 15px 20px;
+    box-sizing: border-box;
+    border-radius: 8px;
+    position: relative;
+    background: #fafbfc;
+    cursor: pointer;
+    transition: all 0.3s;
+    border: 1px solid #e5e7eb;
+}
+
+.video_box2:hover {
+    background-color: #fffdfa;
+    border-color: #fffdfa;
+    color: #FF9300;
+    box-shadow: 0 2px 8px rgba(40, 92, 245, 0.1);
+    transform: translateY(-2px);
+}
+
+.video_box2.selected {
+    border: 2px solid #FF9300;
+    background-color: #fffdfa;
+}
+
+/* .video_box2.selected .name {
+    color: #FF9300;
+}
+
+.video_box2.selected .detail {
+    color: #FF9300;
+}
+
+.video_box2.selected .video-info {
+    color: #FF9300;
+} */
+
+.video_box2.selected .tag span {
+    background: #fff5e6;
+    color: #FF9300;
+}
+
+.video-checkbox {
+    position: absolute;
+    top: 8px;
+    right: 8px;
+    z-index: 10;
+    background: rgba(255, 255, 255, 0.95);
+    padding: 2px;
+    border-radius: 4px;
+}
+
+.video-checkbox .check >>> .el-checkbox__input.is-checked .el-checkbox__inner {
+    background-color: #FF9300;
+    border-color: #FF9300;
+}
+
+.video-thumbnail {
+    width: 100%;
+    height: 120px;
+    background: #f0f0f0;
+    border-radius: 4px;
+    margin-bottom: 8px;
+    margin-top: 5px;
+}
+
+.video_box>.detail {
+    color: #cecece;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 3;
+    line-clamp: 3;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    margin: 0 0 5px;
+}
+
+.video_box>.name {
+    color: #000;
+    margin: 5px 0 8px 0;
+    font-weight: bold;
+    font-size: 14px;
+    min-height: 22px;
+    max-height: 44px;
+    line-height: 22px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: block;
+    white-space: normal;
+    word-break: break-all;
+    /* 强制换行成两行,如果内容过多则省略号,且不会折成一行 */
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    width: calc(100% - 20px);
+}
+
+.video-info {
+    display: flex;
+    flex-direction: column;
+    gap: 5px;
+    margin-bottom: 8px;
+    font-size: 12px;
+    color: #909399;
+}
+
+.video_box>.author {
+    margin: 0;
+    width: 100%;
+    display: block;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.video-info .duration {
+    margin: 0;
+    width: 100%;
+    display: block;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.video_box>.tag {
+    display: flex;
+    flex-wrap: nowrap;
+    margin-top: auto;
+    width: calc(100% - 24px);
+}
+
+.video_box>.tag>span {
+    background: #eef3fb;
+    color: #0061ff;
+    padding: 5px 10px;
+    border-radius: 15px;
+    font-size: 0.9em;
+    margin: 0 5px 0 0;
+    max-width: 100%;
+    overflow: hidden;
+    box-sizing: border-box;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    text-align: center;
+}
+
+.external-link {
+    position: absolute;
+    bottom: 10px;
+    right: 10px;
+    width: 24px;
+    height: 24px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    border-radius: 4px;
+    transition: background 0.2s;
+}
+
+.external-link:hover {
+    background: rgba(0, 0, 0, 0.05);
+}
+
+.external-link svg {
+    width: 16px;
+    height: 16px;
+}
+
+.no_data {
+    height: 500px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+}
+
+.pagination-box {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin: 20px 0;
+    gap: 15px;
+}
+
+.page-info {
+    font-size: 14px;
+    color: #606266;
+}
+
+
+@media screen and (max-width: 1080px) {
+    .video_box {
+        width: calc(100% / 3 - 10px) !important;
+    }
+}
+
+@media screen and (max-width: 760px) {
+    .video_box {
+        width: calc(100% / 2 - 10px) !important;
+    }
+}
+</style>
+

+ 293 - 0
src/components/pages/pptEasy/dialog/VideoUploadDialog2.vue

@@ -0,0 +1,293 @@
+<template>
+	<div class="video-source-modal" v-if="show">
+		<div class="modal-overlay"></div>
+		<div class="modal-content video-source-content">
+			<div class="modal-header">
+				<h3 class="modal-title">{{ lang.ssSelectVideoSource }}</h3>
+				<div class="modal-close" @click="close()">×</div>
+			</div>
+			<div class="modal-body video-source-body">
+				<div class="source-options">
+					<div class="source-option" @click="handleLocalUpload">
+						<div class="option-icon">
+							<svg width="48" height="48" viewBox="0 0 48 48" fill="none"
+								xmlns="http://www.w3.org/2000/svg">
+								<g id="Component 1">
+									<path id="Vector" d="M24 10V38" stroke="currentColor" stroke-width="4" />
+									<path id="Vector_2" d="M10 24L24 10L38 24" stroke="currentColor" stroke-width="4" />
+								</g>
+							</svg>
+						</div>
+						<div class="option-text">{{ lang.ssLocalUpload }}</div>
+					</div>
+					<div class="source-option" @click="handleBilibiliSearch">
+						<div class="option-icon">
+							<svg width="48" height="48" viewBox="0 0 48 48" fill="none"
+								xmlns="http://www.w3.org/2000/svg">
+								<g id="Component 1">
+									<path id="Vector"
+										d="M38 8H10C7.79086 8 6 9.79086 6 12V32C6 34.2091 7.79086 36 10 36H38C40.2091 36 42 34.2091 42 32V12C42 9.79086 40.2091 8 38 8Z"
+										stroke="currentColor" stroke-width="4" />
+									<path id="Vector_2" d="M20 18L32 24L20 30V18Z" stroke="currentColor" stroke-width="4" />
+								</g>
+							</svg>
+						</div>
+						<div class="option-text">{{ lang.ssBiliSearch }}</div>
+					</div>
+				</div>
+			</div>
+		</div>
+		<!-- 隐藏的文件输入 -->
+		<input ref="fileInput" type="file" accept="video/*" style="display: none" @change="handleFileChange" />
+	</div>
+</template>
+
+<script>
+import "../../../../common/aws-sdk-2.235.1.min.js";
+
+export default {
+	data() {
+		return {
+			show: false,
+			data: null,
+		};
+	},
+	computed: {},
+	methods: {
+		open(data) {
+			this.data = data;
+			this.show = true;
+		},
+		close() {
+			this.show = false;
+			this.init();
+		},
+		init() {
+			this.data = null;
+		},
+		// 处理本地文件上传
+		handleLocalUpload() {
+			this.$refs.fileInput.click();
+		},
+		// 处理文件选择
+		handleFileChange(event) {
+			const file = event.target.files[0];
+			if (file) {
+				// 验证文件类型
+				if (!file.type.startsWith('video/')) {
+					this.$message.error('请选择视频文件');
+					event.target.value = "";
+					return;
+				}
+				// 上传文件
+				this.uploadVideo(file);
+			}
+			// 重置input,以便可以再次选择同一个文件
+			event.target.value = "";
+		},
+		// 上传视频文件
+		uploadVideo(file) {
+			const uploadId = new Date().getTime();
+			const fileName = file.name;
+
+			// 初始化进度信息
+			this.$emit("uploadProgress", {
+				id: uploadId,
+				fileName: fileName,
+				progress: 0,
+				loaded: 0,
+				total: file.size,
+				status: 'uploading'
+			});
+
+			var credentials = {
+				accessKeyId: "AKIATLPEDU37QV5CHLMH",
+				secretAccessKey: "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"
+			};
+			window.AWS.config.update(credentials);
+			window.AWS.config.region = "cn-northwest-1";
+
+			var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } });
+			var _this = this;
+
+			var params = {
+				Key:
+					file.name.split(".")[0] +
+					new Date().getTime() +
+					"." +
+					file.name.split(".")[file.name.split(".").length - 1],
+				ContentType: file.type,
+				Body: file,
+				"Access-Control-Allow-Credentials": "*",
+				ACL: "public-read"
+			};
+			var options = {
+				partSize: 2048 * 1024 * 1024,
+				queueSize: 2,
+				leavePartsOnError: true
+			};
+			bucket
+				.upload(params, options)
+				.on("httpUploadProgress", function (evt) {
+					// 更新上传进度
+					const progress = Math.round((evt.loaded * 100) / evt.total);
+					_this.$emit("uploadProgress", {
+						id: uploadId,
+						fileName: fileName,
+						progress: progress,
+						loaded: evt.loaded,
+						total: evt.total,
+						status: 'uploading'
+					});
+				})
+				.send(function (err, data) {
+					if (err) {
+						// 上传失败,更新进度状态
+						_this.$emit("uploadProgress", {
+							id: uploadId,
+							fileName: fileName,
+							progress: 0,
+							loaded: 0,
+							total: file.size,
+							status: 'error'
+						});
+						_this.$message.error("上传失败");
+					} else {
+						// 上传成功,触发事件传递文件信息
+						_this.$emit("uploadLocalVideo", {
+							id: uploadId,
+							file: file,
+							url: data.Location,
+							name: file.name
+						});
+						_this.close();
+					}
+				});
+		},
+		// 处理Bilibili搜索
+		handleBilibiliSearch() {
+			// 触发Bilibili搜索事件
+			this.$emit("searchBilibili");
+			this.close();
+		},
+	},
+};
+</script>
+
+<style scoped>
+/* 视频来源选择弹窗 */
+.video-source-modal {
+	position: fixed;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	z-index: 1000;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.modal-overlay {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background-color: rgba(0, 0, 0, 0.5);
+}
+
+.modal-content {
+	position: relative;
+	z-index: 1001;
+	background-color: white;
+	border-radius: 8px;
+	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+	overflow: hidden;
+	width: 600px;
+}
+
+.modal-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding: 20px 24px;
+	/* border-bottom: 1px solid #f0f0f0; */
+}
+
+.modal-title {
+	font-size: 18px;
+	font-weight: 600;
+	color: #333;
+	margin: 0;
+}
+
+.modal-close {
+	font-size: 24px;
+	color: #999;
+	cursor: pointer;
+	transition: all 0.3s;
+}
+
+.modal-close:hover {
+  /* color: #409eff; */
+  background-color: #f3f4f6;
+}
+
+.video-source-body {
+	padding: 0px 24px 30px;
+}
+
+.source-options {
+	display: flex;
+	justify-content: center;
+	gap: 40px;
+}
+
+.source-option {
+	flex: 1;
+	max-width: 200px;
+	padding: 15px 20px;
+	border: 1px solid #e5e7eb;
+	border-radius: 8px;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	cursor: pointer;
+	transition: all 0.3s;
+	background-color: #fafbfc;
+}
+
+.source-option:hover {
+	background-color: #fffdfa;
+	border-color: #fffdfa;
+	color: #FF9300;
+	box-shadow: 0 2px 8px rgba(40, 92, 245, 0.1);
+}
+
+.source-option:hover .option-icon{
+	color: #FF9300;
+}
+
+.option-icon {
+	width: 95%;
+	height: 80px;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	margin-bottom: 20px;
+	border: 1px solid #e5e7eb;
+	color: #6b7280;
+    background: #fff;
+	border-radius: 4px;
+	padding: 10px;
+}
+
+.option-text {
+	font-size: 16px;
+	font-weight: 500;
+	color: #333;
+	text-align: center;
+}
+</style>

+ 886 - 0
src/components/pages/pptEasy/dialog/appDialog.vue

@@ -0,0 +1,886 @@
+<template>
+  <div class="app_dialog">
+    <el-dialog :visible.sync="dialogVisible" width="900px" :show-close="false" class="el-dialogClass dialog_diy"
+      :before-close="handleClose">
+      <template #title>
+        <div class="title_container">
+          <div>{{ lang.ssAppCenter }}</div>
+          <div class="close_btn" @click="dialogVisible = false">×</div>
+        </div>
+      </template>
+      <div class="ac_right" v-loading.lock="getDataLoading" :style="{overflow: getDataLoading ? 'hidden' : 'auto'}">
+        <div class="ac_header">
+          <div class="ac_h_bottom">
+            <div class="ac_h_b_selectList">
+              <div>
+                <el-select v-model="selectJuri" :placeholder="lang.ssSelectScope" @change="changeSelectType"
+                  style="width: 120px;margin-right: 10px;">
+                  <el-option v-for="item in selectList" :key="item.index" :label="item.label"
+                    :value="item.index"></el-option>
+                </el-select>
+                <el-select v-model="selectLabel" :placeholder="lang.ssSelectType" @change="changeSelectType"
+                  style="width: 110px;margin-right: 10px;">
+                  <el-option v-for="item in labelSelect" :key="item.value" :label="item.label"
+                    :value="item.value"></el-option>
+                </el-select>
+
+                <el-select v-model="statusType" :placeholder="lang.ssSelectStatus" @change="changeSelectType"
+                  style="width: 110px;margin-right: 10px;">
+                  <el-option v-for="item in statusList" :key="item.value" :label="item.label"
+                    :value="item.value"></el-option>
+                </el-select>
+              </div>
+
+              <div>
+                <el-input v-model="searchText" style="width: 250px;margin-right: 10px;"
+                  :placeholder="lang.ssEnterAppName" @keyup.enter.native="getData">
+                  <i slot="suffix" class="searchInputIcon el-icon-search" @click="getData"></i>
+                </el-input>
+              </div>
+            </div>
+
+            <div class="ac_h_b_typeList">
+              <span :class="{ ac_h_b_typeList_active: showType === '' }" @click="changeType('')">{{ lang.ssAll }}</span>
+              <span v-for="item in typeList" :key="item.id" :class="{ ac_h_b_typeList_active: showType === item.id }"
+                @click="changeType(item.id)">{{ item.name }}</span>
+            </div>
+          </div>
+        </div>
+
+        <div :class="{'ac_content': showType !== ''}">
+
+
+          <template v-for="(item) in dataList">
+            <div class="ac_c_item" v-if="showType !== '' && !getDataLoading" :key="item.id"
+              :class="{ 'selected': appJson.id == item.id || selectAppObj.id == item.id || selectAppList.map(i => i.id).includes(item.id) }"
+              @click="checkApp(item)">
+              <img class="course_item_selected" src="../../../../assets/stuImg/ai6dui.svg"
+                v-if="appJson.id == item.id || selectAppObj.id == item.id || selectAppList.map(i => i.id).includes(item.id)"
+                alt="">
+              <div class="ac_c_item_img_container">
+                <img v-if="item.json.icon" :src="item.json.icon" class="ac_c_item_img" />
+                <svg v-else t="1732605901531" class="icon ac_c_item_img" viewBox="0 0 1024 1024" version="1.1"
+                  xmlns="http://www.w3.org/2000/svg" p-id="4275">
+                  <path
+                    d="M179.2 153.6a51.2 51.2 0 0 0-51.2 51.2v128a51.2 51.2 0 0 0 51.2 51.2h128a51.2 51.2 0 0 0 51.2-51.2V204.8a51.2 51.2 0 0 0-51.2-51.2H179.2z m0-102.4h128a153.6 153.6 0 0 1 153.6 153.6v128a153.6 153.6 0 0 1-153.6 153.6H179.2a153.6 153.6 0 0 1-153.6-153.6V204.8a153.6 153.6 0 0 1 153.6-153.6z m0 614.4a51.2 51.2 0 0 0-51.2 51.2v128a51.2 51.2 0 0 0 51.2 51.2h128a51.2 51.2 0 0 0 51.2-51.2V716.8a51.2 51.2 0 0 0-51.2-51.2H179.2z m0-102.4h128a153.6 153.6 0 0 1 153.6 153.6v128a153.6 153.6 0 0 1-153.6 153.6H179.2a153.6 153.6 0 0 1-153.6-153.6V716.8a153.6 153.6 0 0 1 153.6-153.6z m611.84-403.4048a51.2 51.2 0 0 0-72.3968 0L646.144 232.2432a51.2 51.2 0 0 0 0 72.3968l72.448 72.3968a51.2 51.2 0 0 0 72.3968 0l72.3968-72.3968a51.2 51.2 0 0 0 0-72.3968L791.04 159.744z m72.3968-72.3968l72.3968 72.3968a153.6 153.6 0 0 1 0 217.2416l-72.3968 72.3968a153.6 153.6 0 0 1-217.2416 0l-72.3968-72.3968a153.6 153.6 0 0 1 0-217.2416l72.3968-72.3968a153.6 153.6 0 0 1 217.2416 0zM699.7504 896a51.2 51.2 0 0 1 0 102.4A162.1504 162.1504 0 0 1 537.6 836.2496v-110.8992A162.1504 162.1504 0 0 1 699.7504 563.2h110.8992a162.1504 162.1504 0 0 1 162.1504 162.1504v8.448a51.2 51.2 0 0 1-102.4 0v-8.448c0-33.024-26.7264-59.7504-59.7504-59.7504h-110.8992c-33.024 0-59.7504 26.7264-59.7504 59.7504v110.8992c0 33.024 26.7264 59.7504 59.7504 59.7504z"
+                    fill="#2C6DD2" p-id="4276"></path>
+                  <path
+                    d="M791.4496 160a51.2 51.2 0 0 0-72.3968 0l-72.448 72.3968a51.2 51.2 0 0 0 0 72.3968l72.448 72.3968a51.2 51.2 0 0 0 72.3968 0l72.3968-72.3968a51.2 51.2 0 0 0 0-72.3968l-72.3968-72.3968z"
+                    fill="#20C997" p-id="4277"></path>
+                </svg>
+              </div>
+              <div class="ac_c_item_name">
+                {{ item.name }}
+              </div>
+              <div class="ac_c_item_desc">
+                {{ item.detail }}
+              </div>
+              <div class="ac_c_item_tags">
+                <div class="ac_c_item_tag" v-if="item.label === 'workflow'">
+                  {{ lang.ssWorkflow }}
+                </div>
+                <div class="ac_c_item_tag" v-if="item.label === 'agent'">
+                  {{ lang.ssAgent }}
+                </div>
+                <div class="ac_c_item_tag" v-if="item.json.status === '1'">
+                  {{ lang.ssTest }}
+                </div>
+                <div class="ac_c_item_tag" v-if="item.json.status === '2'">
+                  {{ lang.ssStable }}
+                </div>
+              </div>
+            </div>
+          </template>
+
+
+          <div class="ac_c_typeCard" v-if="showType == ''">
+            <div class="ac_c_tc_item" v-for="(item2, index2) in typeList" :key="index2">
+              <div class="ac_c_tc_i_top">
+                <div>{{ item2.name }}</div>
+
+                <span @click="changeType(item2.id)">{{ lang.ssViewMore }}
+                  <img src="../../../../assets/icon/appStore/arrow.svg" />
+                </span>
+              </div>
+              <div :class="{'ac_content': !getDataLoading}">
+                <template v-for="(item, index) in dataList.filter(
+                  i => i.type == item2.id
+                )">
+                  <div class="ac_c_item" v-if="index < 8" :key="item.id" @click="checkApp(item)"
+                    :class="{ selected: appJson.id == item.id || selectAppObj.id == item.id || selectAppList.map(i => i.id).includes(item.id) }">
+                    <img class="course_item_selected" src="../../../../assets/stuImg/ai6dui.svg"
+                      v-if="appJson.id == item.id || selectAppObj.id == item.id || selectAppList.map(i => i.id).includes(item.id)"
+                      alt="">
+                    <div class="ac_c_item_img_container">
+                      <img v-if="item.json.icon" :src="item.json.icon" class="ac_c_item_img" />
+                      <svg v-else t="1732605901531" class="icon ac_c_item_img" viewBox="0 0 1024 1024" version="1.1"
+                        xmlns="http://www.w3.org/2000/svg" p-id="4275">
+                        <path
+                          d="M179.2 153.6a51.2 51.2 0 0 0-51.2 51.2v128a51.2 51.2 0 0 0 51.2 51.2h128a51.2 51.2 0 0 0 51.2-51.2V204.8a51.2 51.2 0 0 0-51.2-51.2H179.2z m0-102.4h128a153.6 153.6 0 0 1 153.6 153.6v128a153.6 153.6 0 0 1-153.6 153.6H179.2a153.6 153.6 0 0 1-153.6-153.6V204.8a153.6 153.6 0 0 1 153.6-153.6z m0 614.4a51.2 51.2 0 0 0-51.2 51.2v128a51.2 51.2 0 0 0 51.2 51.2h128a51.2 51.2 0 0 0 51.2-51.2V716.8a51.2 51.2 0 0 0-51.2-51.2H179.2z m0-102.4h128a153.6 153.6 0 0 1 153.6 153.6v128a153.6 153.6 0 0 1-153.6 153.6H179.2a153.6 153.6 0 0 1-153.6-153.6V716.8a153.6 153.6 0 0 1 153.6-153.6z m611.84-403.4048a51.2 51.2 0 0 0-72.3968 0L646.144 232.2432a51.2 51.2 0 0 0 0 72.3968l72.448 72.3968a51.2 51.2 0 0 0 72.3968 0l72.3968-72.3968a51.2 51.2 0 0 0 0-72.3968L791.04 159.744z m72.3968-72.3968l72.3968 72.3968a153.6 153.6 0 0 1 0 217.2416l-72.3968 72.3968a153.6 153.6 0 0 1-217.2416 0l-72.3968-72.3968a153.6 153.6 0 0 1 0-217.2416l72.3968-72.3968a153.6 153.6 0 0 1 217.2416 0zM699.7504 896a51.2 51.2 0 0 1 0 102.4A162.1504 162.1504 0 0 1 537.6 836.2496v-110.8992A162.1504 162.1504 0 0 1 699.7504 563.2h110.8992a162.1504 162.1504 0 0 1 162.1504 162.1504v8.448a51.2 51.2 0 0 1-102.4 0v-8.448c0-33.024-26.7264-59.7504-59.7504-59.7504h-110.8992c-33.024 0-59.7504 26.7264-59.7504 59.7504v110.8992c0 33.024 26.7264 59.7504 59.7504 59.7504z"
+                          fill="#2C6DD2" p-id="4276"></path>
+                        <path
+                          d="M791.4496 160a51.2 51.2 0 0 0-72.3968 0l-72.448 72.3968a51.2 51.2 0 0 0 0 72.3968l72.448 72.3968a51.2 51.2 0 0 0 72.3968 0l72.3968-72.3968a51.2 51.2 0 0 0 0-72.3968l-72.3968-72.3968z"
+                          fill="#20C997" p-id="4277"></path>
+                      </svg>
+                    </div>
+                    <div class="ac_c_item_name">
+                      {{ item.name }}
+                    </div>
+                    <div class="ac_c_item_desc">
+                      {{ item.detail }}
+                    </div>
+                    <div class="ac_c_item_tags">
+                      <div class="ac_c_item_tag" v-if="item.label === 'workflow'">
+                        {{ lang.ssWorkflow }}
+                      </div>
+                      <div class="ac_c_item_tag" v-if="item.label === 'agent'">
+                        {{ lang.ssAgent }}
+                      </div>
+                      <div class="ac_c_item_tag" v-if="item.json.status === '1'">
+                        {{ lang.ssTest }}
+                      </div>
+                      <div class="ac_c_item_tag" v-if="item.json.status === '2'">
+                        {{ lang.ssStable }}
+                      </div>
+                    </div>
+                  </div>
+                </template>
+
+
+                <div class="ac_c_empty" v-if="dataList.filter(i => i.type == item2.id).length === 0">
+                  <span>{{ lang.ssNoData }}</span>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="ac_c_empty" v-if="dataList.length === 0 && showType !== ''">
+            <span>{{ lang.ssNoData }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="course_item_footer">
+        <div v-html="lang.ssSelectedApp.replace(/\*/g, '<span class=&quot;orange_number&quot;>' + selectAppList.length + '</span>')"></div>
+        <div class="confirm_btn" @click="checkAppJson">
+          <img src="../../../../assets/stuImg/ai6dui.svg" alt="">
+          {{ lang.ssAdd }}
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { over } from 'lodash';
+
+export default {
+  data() {
+    return {
+      dialogVisible: false,
+      appJson: {},
+      itemTaskIndex: 0,
+      toolIndex: 0,
+      unitIndex: 0,
+      showType: "",
+      searchText: "",
+      selectJuri: 5,
+      selectLabel: "",
+      typeList: [],
+      selectList: [],
+      statusList: [],
+      statusType: "",
+      labelSelect: [],
+      AreaType: '',
+      AreaSelect: [
+        { value: "cn", label: "cn" },
+        { value: "hk", label: "hk" },
+        { value: "com", label: "com" }
+      ],
+      userId: this.$route.query["userid"],
+      org: this.$route.query["org"],
+      oid: this.$route.query["oid"],
+      getDataLoading: false,
+      dataList: [],
+      recentUse: [],
+      collect: [],
+      editAppCard: null,
+      bannerObj: null,
+      userName: null,
+      controlsObj: null,
+      region: "cn",
+      type: 0,//0 工具  1学习内容添加
+      selectAppList: [],
+      selectAppObj: {},
+    };
+  },
+  watch: {
+    searchText: {
+      immediate: false,
+      handler() {
+        if (this.searchText === "") {
+          this.getData();
+        }
+      }
+    }
+  },
+  computed: {
+    showMenu() {
+      return data => {
+        let _result = false;
+        if (data && this.userId) {
+          if (
+            data.userid === this.userId ||
+            (data.json && data.json.copy === "1")
+          ) {
+            _result = true;
+          }
+        }
+        return _result;
+      };
+    }
+  },
+  methods: {
+    handleClose(done) {
+      done();
+    },
+    async openG(appJson, unitIndex, itemTaskIndex, toolIndex, type = 0) {
+      this.selectAppList = [];
+      this.appJson = {};
+      this.selectAppObj = {};
+      if (type == 0) {
+        this.appJson = appJson;
+        this.itemTaskIndex = itemTaskIndex;
+        this.toolIndex = toolIndex;
+        this.unitIndex = unitIndex;
+      } else if (type == 2) {
+        this.selectAppObj = appJson;
+      }
+      console.log(type)
+      this.type = type;
+      const { data } = await this.ajax.get(this.$store.state.api + 'select_oidArea', { oid: this.oid });
+      this.region = data[0][0].area;
+      this.AreaType = data[0][0].area;
+      this.getAppStoreControl().then(_ => {
+        this.getData();
+        this.getTypeList();
+      });
+      this.dialogVisible = true;
+    },
+    checkAppJson() {
+      if (this.type == 0) {
+        if (!Object.keys(this.appJson).length) {
+          this.$message({ type: 'warning', message: this.lang.ssSelectAppFirst });
+          return
+        }
+        this.$parent.unitJson[this.unitIndex].chapterInfo[0].taskJson[this.itemTaskIndex].toolChoose[this.toolIndex].appJson = this.appJson
+        if (
+          this.$parent.unitJson[this.unitIndex].chapterInfo[0].taskJson[this.itemTaskIndex].toolChoose[this.toolIndex].tool != 72
+        ) {
+          this.$parent.addTools(72, this.itemTaskIndex, this.toolIndex);
+        }
+        this.dialogVisible = false
+        this.$message.success(this.lang.ssAddSuccess)
+      } else if (this.type == 1) {
+        this.$emit("success2", { data: JSON.parse(JSON.stringify(this.selectAppList)), type: this.type })
+        this.dialogVisible = false
+        this.selectAppList = [];
+      } else if (this.type == 2) {
+        this.$emit("success", { data: JSON.parse(JSON.stringify(this.selectAppObj)), type: this.type })
+        this.dialogVisible = false
+        this.selectAppObj = {};
+      }
+    },
+    changeType(newIndex) {
+      let flag = this.showType === newIndex;
+      this.showType = newIndex;
+      if (!flag) {
+        this.getData();
+      }
+    },
+    changeSelectType() {
+      this.getData();
+    },
+    resetData() {
+      this.searchText = "";
+      this.selectJuri = 3;
+      this.showType = "";
+      this.getData();
+    },
+    async openApp(item) {
+      window.open(item.url, "_blank");
+    },
+    checkApp(item) {
+      if (this.type == 0) {
+        if (this.appJson.id == item.id) {
+          this.appJson = {}
+        } else {
+          this.appJson = item
+        }
+      } else if (this.type == 1) {
+        if (this.selectAppList.map(i => i.id).includes(item.id)) {
+          this.selectAppList = this.selectAppList.filter(i => i.id != item.id)
+        } else {
+          this.selectAppList.push(item)
+        }
+      } else if (this.type == 2) {
+        if (this.selectAppObj.id == item.id) {
+          this.selectAppObj = {}
+        } else {
+          this.selectAppObj = item
+        }
+      }
+
+    },
+    getTypeList() {
+      let params = {
+        suserid: this.userId, //用户ID
+        sorg: this.org,
+        soid: this.oid,
+        sstand: this.lang.lang,
+        exportType:
+          this.controlsObj &&
+            this.controlsObj.exportTypeList &&
+            this.controlsObj.exportTypeList.length > 0
+            ? this.controlsObj.exportTypeList.join(",")
+            : ""
+      };
+
+      this.ajax
+        .get(this.$store.state.api + "select_appStoreType_exceptType", params)
+        .then(res => {
+          let data = res.data[0];
+          if (data.length > 0) {
+            // data.forEach(i => {
+            //   if (i.open == undefined) {
+            //     i.open = true;
+            //   }
+            // });
+            this.typeList = data;
+          }
+        })
+        .catch(err => {
+          console.log(err);
+          this.$message.error(this.lang.ssGetAppTypeFail);
+        });
+    },
+    getData() {
+      this.getDataLoading = true;
+      let params = {
+        uid: this.userId, //用户ID
+        name: this.searchText, //应用名称搜索
+        label: this.selectLabel, //应用的标签搜索
+        type: this.showType, //应用的类型
+        juri: this.selectJuri, //应用权限 1:我的  2:组织内  3:所有人
+        stand: this.lang.lang, //cn站还是hk站
+        status: this.statusType,
+        exportType:
+          this.controlsObj &&
+            this.controlsObj.exportTypeList &&
+            this.controlsObj.exportTypeList.length > 0
+            ? this.controlsObj.exportTypeList.join(",")
+            : ""
+      };
+
+      this.ajax
+        .get(this.$store.state.api + "select_appStore_exportType", params)
+        .then(res => {
+          this.getDataLoading = false;
+          let _data = res.data[0];
+          if (_data.length > 0) {
+            _data.forEach(i => {
+              if (i.json) {
+                i.json = JSON.parse(i.json);
+              }
+            });
+            this.dataList = _data;
+          } else {
+            this.dataList = [];
+          }
+        })
+        .catch(err => {
+          this.getDataLoading = false;
+          console.log(err);
+          this.$message.error(this.lang.ssGetAppFail);
+        });
+    },
+    async getAppStoreControl() {
+      return new Promise(resolve => {
+        let params = {
+          uid: this.userId,
+          org: this.org,
+          oid: this.oid
+        };
+
+        let controlsObj = {
+          logoUrl: "",
+          bannerUrl:
+            "https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/default%2FFrame+30141733970358224.svg",
+          exportTypeList: []
+        };
+        this.ajax
+          .get(this.$store.state.api + "select_appStore_controls", params)
+          .then(res => {
+            let _data = res.data[0];
+            if (_data[0]) {
+              console.log(_data[0]);
+              controlsObj = JSON.parse(_data[0].json);
+            }
+            this.controlsObj = controlsObj;
+            resolve();
+          })
+          .catch(err => {
+            console.log(err);
+            this.controlsObj = controlsObj;
+            resolve();
+          });
+      });
+    },
+    praiseFn(item, type = 0) {
+      //点赞
+      if (type === 0) {
+        //点赞
+        let params = [
+          {
+            uid: this.userId,
+            type: 2,
+            aid: item.id,
+            json: ""
+          }
+        ];
+        this.ajax
+          .post(this.$store.state.api + "insert_appStoreSave", params)
+          .then(res => {
+            if (res.data) {
+              let _likeId = res.data[0][0].id;
+              this.dataList.find(i => i.id === item.id).likeCount += 1;
+              this.dataList.find(i => i.id === item.id).likeId = _likeId;
+              this.$message.success(this.lang.ssLikeSuccess);
+            }
+          })
+          .catch(e => {
+            this.$message.error(this.lang.ssLikeFail);
+          });
+      } else if (type === 1) {
+        //取消点赞
+        console.log("取消点赞👉:", item);
+        let params = [
+          {
+            sid: item.likeId
+          }
+        ];
+        this.ajax
+          .post(this.$store.state.api + "delete_appStoreSave", params)
+          .then(res => {
+            if (res.data) {
+              this.dataList.find(i => i.id === item.id).likeCount -= 1;
+              this.dataList.find(i => i.id === item.id).likeId = "";
+              this.$message.success(this.lang.ssCancelLikeOk);
+            }
+          })
+          .catch(e => {
+            console.log(e);
+            this.$message.error(this.lang.ssCancelLikeFail);
+          });
+      }
+    },
+    collectFn(item, type = 0) {
+      //收藏
+      if (type === 0) {
+        //收藏
+        console.log("收藏👉:", item);
+        let params = [
+          {
+            uid: this.userId,
+            type: 0,
+            aid: item.id,
+            json: ""
+          }
+        ];
+        this.ajax
+          .post(this.$store.state.api + "insert_appStoreSave", params)
+          .then(res => {
+            if (res.data) {
+              let _colletId = res.data[0][0].id;
+              this.dataList.find(i => i.id === item.id).collectCount += 1;
+              this.dataList.find(i => i.id === item.id).collectId = _colletId;
+              this.$message.success(this.lang.ssCollectSuccess);
+            }
+            this.getData();
+          })
+          .catch(e => {
+            console.log(e);
+            this.getData();
+            this.$message.error(this.lang.ssCollectFail);
+          });
+      } else if (type === 1) {
+        //取消收藏
+        console.log("取消收藏👉:", item);
+        let params = [
+          {
+            sid: item.collectId
+          }
+        ];
+        this.ajax
+          .post(this.$store.state.api + "delete_appStoreSave", params)
+          .then(res => {
+            if (res.data) {
+              this.dataList.find(i => i.id === item.id).collectCount -= 1;
+              this.dataList.find(i => i.id === item.id).collectId = "";
+              this.$message.success(this.lang.ssCancelCollectOk);
+            }
+            this.getData();
+          })
+          .catch(e => {
+            console.log(e);
+            this.$message.error(this.lang.ssCancelCollectFail);
+            this.getData();
+          });
+      }
+    }
+  },
+  mounted() {
+    this.selectList = [
+      { index: 5, label: this.lang.ssAllApps },
+      { index: 3, label: this.lang.ssOfficial },
+      { index: 2, label: this.lang.ssOrgInternal },
+      { index: 1, label: this.lang.ssMine }
+    ];
+    this.statusList = [
+      { value: "", label: this.lang.ssAllStatus },
+      { value: 1, label: this.lang.ssTest },
+      { value: 2, label: this.lang.ssStable }
+    ];
+    this.labelSelect = [
+      { value: "", label: this.lang.ssAllTypes },
+      { value: "agent", label: this.lang.ssAgent },
+      { value: "workflow", label: this.lang.ssWorkflow }
+    ];
+  }
+};
+</script>
+
+<style scoped>
+.app_dialog>>>.el-dialog {
+  border-radius: 15px;
+  overflow: hidden;
+}
+
+.title_container {
+  display: flex;
+  font-size: 16px;
+  font-weight: bold;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.close_btn {
+  cursor: pointer;
+  background-color: #F5F6F6;
+  padding: 3px 7px;
+  border-radius: 5px;
+}
+
+.app_dialog>>>.el-dialog__body {
+  padding: 10px 20px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  height: 660px;
+  overflow-y: auto;
+}
+
+.el-dialogClass>>>.el-dialog {
+  margin: 40px auto 0 !important;
+}
+
+.el-dialogClass>>>.el-dialog__body {
+  /* height: auto; */
+  overflow-y: auto;
+  overflow-x: hidden;
+  box-sizing: border-box;
+  padding: 10px 20px;
+}
+
+.dialog_diy>>>.el-dialog__header {
+  background: #fff !important;
+  padding: 15px 20px;
+}
+
+.dialog_diy>>>.el-dialog__title {
+  color: #000;
+}
+
+.dialog_diy>>>.el-dialog__headerbtn {
+  top: 19px;
+}
+
+.dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
+  color: #000;
+}
+
+.dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
+  color: #000;
+}
+
+.ac_right {
+  flex: 1;
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  display: flex;
+  flex-direction: column;
+}
+
+.ac_header {
+  width: 100%;
+  height: auto;
+  border-bottom: 1px solid #E5E5E5;
+  padding-bottom: 10px;
+  margin-bottom: 20px;
+}
+
+
+
+.ac_h_bottom {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.ac_h_b_selectList {
+  display: flex;
+  gap: 10px;
+  flex-wrap: wrap;
+}
+
+.ac_h_b_selectList .el-select {
+  border-radius: 10px;
+  background-color: #F5F6F6;
+}
+
+.ac_h_b_selectList .el-select .el-input__inner {
+  background-color: #FAFCFE;
+  border-radius: 10px;
+}
+
+.ac_h_b_typeList {
+  width: 100%;
+  height: auto;
+  display: flex;
+  flex-wrap: wrap;
+  box-sizing: border-box;
+  margin-top: 10px;
+}
+
+.ac_h_b_typeList>span {
+  font-size: 14px;
+  margin-right: 20px;
+  margin-top: 5px;
+  margin-bottom: 5px;
+  cursor: pointer;
+}
+
+.ac_h_b_typeList_active {
+  color: #FF9400;
+  position: relative;
+}
+
+.ac_content {
+  width: 100%;
+  height: auto;
+}
+
+.ac_c_typeCard {
+  width: 100%;
+  height: auto;
+}
+
+.ac_c_item {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  /* height: 230px; */
+  padding: 15px;
+  box-sizing: border-box;
+  border-radius: 10px;
+  position: relative;
+  border: 1px solid #E5E5E5;
+  cursor: pointer;
+}
+
+.ac_c_item.selected {
+  border: 2px solid #FF9400;
+}
+
+.ac_c_item_img {
+  width: 100%;
+  border-radius: 5px;
+  object-fit: contain;
+}
+
+.ac_c_item_name {
+  font-size: 14px;
+  font-weight: bold;
+  text-align: left;
+}
+
+.ac_c_item_desc {
+  font-size: 12px;
+  color: #666;
+  text-align: left;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+
+.ac_c_item_tags {
+  display: flex;
+  gap: 5px;
+  flex-wrap: wrap;
+  margin-top: auto;
+}
+
+.ac_c_item_tag {
+  font-size: 12px;
+  padding: 2px 6px;
+  border-radius: 4px;
+  background-color: #F5F6F6;
+  color: #666;
+}
+
+.course_item_selected {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  width: 20px;
+  height: 20px;
+  padding: 2px;
+  box-sizing: border-box;
+  border-radius: 50%;
+  background-color: #FF9400;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #fff;
+  font-size: 12px;
+  font-weight: bold;
+  z-index: 1;
+}
+
+.ac_c_item_img_container {
+  height: 140px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid #E5E7EB;
+  border-radius: 10px;
+  overflow: hidden;
+}
+
+.ac_c_item_img {
+  width: 100%;
+  height: auto;
+  object-fit: cover;
+  border-radius: 5px;
+}
+
+.ac_content {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 15px;
+  /* min-height: 350px; */
+  overflow-y: auto;
+}
+
+.ac_c_empty {
+  width: 100%;
+  height: 40%;
+  display: flex;
+  box-sizing: border-box;
+  /* padding-top: 2%; */
+  justify-content: center;
+  color: #a1a1a1;
+  /* align-items: center; */
+}
+
+.course_item_footer {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px;
+  box-sizing: border-box;
+  border-top: 1px solid #E5E5E5;
+  margin-top: 20px;
+}
+
+.confirm_btn {
+  background-color: #FF9400;
+  color: #fff;
+  font-size: 14px;
+  border-radius: 10px;
+  display: flex;
+  padding: 7px 10px;
+  align-items: center;
+  justify-content: center;
+  border: none;
+  cursor: pointer;
+}
+
+.confirm_btn img {
+  width: 22px;
+  height: 22px;
+  margin-right: 5px;
+}
+
+.searchInputIcon {
+  width: 20px;
+  height: 20px;
+  position: relative;
+  top: 10px;
+  right: 5px;
+  font-size: 19px;
+  cursor: pointer;
+}
+
+.ac_c_tc_item {
+  width: 100%;
+  height: auto;
+}
+
+.ac_c_tc_i_top {
+  width: 100%;
+  height: 40px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  box-sizing: border-box;
+  /* padding: 0 20px; */
+}
+
+.ac_c_tc_i_top>div {
+  font-size: 26px;
+}
+
+.ac_c_tc_i_top>span {
+  display: flex;
+  align-items: center;
+  color: #a2a2a2;
+  font-size: 16px;
+  cursor: pointer;
+}
+
+.ac_c_tc_i_top>span>img {
+  width: 18px;
+  height: 18px;
+  margin-left: 5px;
+  transition: 0.3s;
+}
+
+.checkActive {
+  border: 2px solid #FF9400
+}
+</style>

+ 63 - 18
src/components/pages/studentManageNew/component/addstu.vue

@@ -169,9 +169,12 @@
                 >{{ lang.ssDownloadTemp }}</span
                 >{{ lang.ssDownloadTemp }}</span
               >
               >
             </div>
             </div>
-            <div style="margin-top: 10px">
+            <div v-if="boxType == 0" style="margin-top: 10px">
               {{ lang.ssUploadNote }}
               {{ lang.ssUploadNote }}
             </div>
             </div>
+            <div v-else style="margin-top: 10px">
+              {{ lang.ssSyncImportClassInfo }}
+            </div>
             <!-- <div style="margin-top: 10px">
             <!-- <div style="margin-top: 10px">
               学生列表批量上传需表格需添加“班级”列
               学生列表批量上传需表格需添加“班级”列
             </div> -->
             </div> -->
@@ -433,7 +436,7 @@ export default {
         var wb; //读取完成的数据
         var wb; //读取完成的数据
         var outdata;
         var outdata;
         var reader = new FileReader();
         var reader = new FileReader();
-        reader.onload = function (e) {
+        reader.onload = async function (e) {
           var bytes = new Uint8Array(reader.result);
           var bytes = new Uint8Array(reader.result);
           var length = bytes.byteLength;
           var length = bytes.byteLength;
           for (var i = 0; i < length; i++) {
           for (var i = 0; i < length; i++) {
@@ -473,7 +476,7 @@ export default {
               } else {
               } else {
                 obj.mail = uuidv4() + "@" + _this.userSuffix;
                 obj.mail = uuidv4() + "@" + _this.userSuffix;
               }
               }
-              obj.class = _this.boxType == 2 ? v[_this.lang.Class] : _this.classInfo.name;
+              obj.class = _this.boxType == 2 ? v[_this.lang.Class] : _this.classInfo.id;
               arr.push(obj);
               arr.push(obj);
             }else{
             }else{
               _this.$message.error(_this.lang.ssCheckStuNameCol);
               _this.$message.error(_this.lang.ssCheckStuNameCol);
@@ -481,22 +484,35 @@ export default {
             }
             }
           });
           });
           console.log(arr);
           console.log(arr);
-          // if (arr.length > 70) {
-          //   _this.$message.error(_this.lang.Limitmore);
-          //   return;
-          // }
-
-          if (this.boxType == 2 && arr.filter(e => e.class) != arr.length) {
-            _this.$message.error(_this.lang.ssCheckClassCol);
-            return;
-          }
-
           if (!arr.length) {
           if (!arr.length) {
             _this.$message.error(
             _this.$message.error(
               _this.lang.ssParseStuFail
               _this.lang.ssParseStuFail
             );
             );
             return;
             return;
           }
           }
+         
+          if (_this.boxType == 2) {
+            let stuClassInfo = await _this.getClassInfo();
+            console.log(stuClassInfo, "stuClassInfo");
+            arr.forEach((e) => {
+              let classInfo = stuClassInfo.find(item => item.name == e.class);
+              if (classInfo) {
+                e.class = classInfo.id;
+              } else {
+                e.class = '';
+              }
+            });
+          }
+          console.log(arr, "arr");
+          
+         
+
+          if (_this.boxType == 2 && arr.filter(e => e.class).length !== arr.length) {
+            _this.$message.error(_this.lang.ssCheckClassCol);
+            return;
+          }
+
+          
           _this.deltypy = 1;
           _this.deltypy = 1;
           _this.popBoxdia= true;
           _this.popBoxdia= true;
           _this.stuexcel = arr;
           _this.stuexcel = arr;
@@ -511,6 +527,37 @@ export default {
         reader.readAsBinaryString(f);
         reader.readAsBinaryString(f);
       }
       }
     },
     },
+    async getClassInfo() {
+      return new Promise((resolve, reject) => {
+        let params = {
+          oid: this.oid,
+        };
+        this.ajax
+          .get(this.$store.state.api + "selectGradeNew", params)
+          .then((res) => {
+            let box1 = JSON.parse(JSON.stringify(res.data[0]));
+            let box2 = JSON.parse(JSON.stringify(res.data[1]));
+          
+            // box1.push({id:0,name:this.lang.ssInterestClass});
+
+            const gradeIds = box1.filter(e => e.id !== 0).map(e => e.id);
+
+            let box3 = [];
+
+            box2.forEach((e) => {
+              if (gradeIds.includes(e.pid)) {
+                e.name = box1.find(item => item.id == e.pid).name + e.name;
+                box3.push(e);
+              }
+            });
+            resolve(box3);
+          })
+          .catch((err) => {
+            console.error(err);
+            reject(err);
+          });
+      });
+    },
     // 手动输入添加学生
     // 手动输入添加学生
     addStu() {
     addStu() {
       this.selectedStuData = this.selectedStuData.filter((item) => item != "");
       this.selectedStuData = this.selectedStuData.filter((item) => item != "");
@@ -550,15 +597,13 @@ export default {
       if (this.boxType == 2) {
       if (this.boxType == 2) {
         classInfo = this.cascaderData.flatMap((item) => item.children).filter((item) => this.cascaderDataPath[1]==item.id)[0];
         classInfo = this.cascaderData.flatMap((item) => item.children).filter((item) => this.cascaderDataPath[1]==item.id)[0];
       }
       }
-      // console.log(classInfo, "classInfo");
       let box = this.selectedStuData.map((item) => {
       let box = this.selectedStuData.map((item) => {
         return {
         return {
           name: item,
           name: item,
           mail: uuidv4() + mail,
           mail: uuidv4() + mail,
-          class: classInfo.name,
+          class: classInfo.id,
         };
         };
       });
       });
-      // console.log(box, "box");
 
 
       this.accUpdate(box);
       this.accUpdate(box);
     },
     },
@@ -606,10 +651,10 @@ export default {
             oid: this.oid,
             oid: this.oid,
           },
           },
         ];
         ];
-      console.log(params, "batchRegistrationMoreCopy");
+      console.log(params, "batchRegistrationMoreCopyNew");
       // batchRegistrationMoreCopy
       // batchRegistrationMoreCopy
         this.ajax
         this.ajax
-          .post(this.$store.state.api + "batchRegistrationMoreCopy", params)
+          .post(this.$store.state.api + "batchRegistrationMoreCopyNew", params)
           .then((res) => {
           .then((res) => {
             console.log(res, "res");
             console.log(res, "res");
             if (res.data.type == 1) {
             if (res.data.type == 1) {

+ 5 - 5
src/components/pages/studentManageNew/component/table.vue

@@ -204,7 +204,7 @@
         <el-table-column
         <el-table-column
           v-for="(item, index) in tableColumns"
           v-for="(item, index) in tableColumns"
           :key="index"
           :key="index"
-          :width="item.wid"
+          :min-width="item.wid"
           show-overflow-tooltip
           show-overflow-tooltip
           :label="item.label"
           :label="item.label"
         >
         >
@@ -786,9 +786,9 @@ export default {
     },
     },
     studentColumns() {
     studentColumns() {
       return [
       return [
-        { label: this.lang.StudentName, prop: "username" },
-        { label: this.lang.Account, prop: "acc" },
-        { label: this.lang.Class, prop: "classname", wid: "360" }
+        { label: this.lang.StudentName, prop: "username",wid:'30%' },
+        { label: this.lang.Account, prop: "acc",wid:'30%' },
+        { label: this.lang.Class, prop: "classname" }
       ];
       ];
     },
     },
     tableInterestClaColumns() {
     tableInterestClaColumns() {
@@ -1419,7 +1419,7 @@ export default {
       console.log(params);
       console.log(params);
 
 
       this.ajax
       this.ajax
-        .post(this.$store.state.api + "addClassgra", params)
+        .post(this.$store.state.api + "addClassgraNew", params)
         .then(res => {
         .then(res => {
           if (res.data[0] && res.data[0][0].classname == 1) {
           if (res.data[0] && res.data[0][0].classname == 1) {
             this.$message({
             this.$message({

+ 3 - 3
src/components/pages/studentManageNew/index.vue

@@ -6,7 +6,7 @@
         <span style="color: #86909c; font-size: 12px">{{ lang.GradeManagement }}</span>
         <span style="color: #86909c; font-size: 12px">{{ lang.GradeManagement }}</span>
       </div>
       </div>
       <div style="display: flex; gap: 10px;">
       <div style="display: flex; gap: 10px;">
-        <div v-if="this.role == 1" class="Clabtn" @click="openaddClass(1)">
+        <div v-if="orglist.includes(org) || role == 1" class="Clabtn" @click="openaddClass(1)">
           <img src="../../../assets/stuImg/jia.svg" alt="" />
           <img src="../../../assets/stuImg/jia.svg" alt="" />
           <span>{{ lang.ssGradeType }}</span>
           <span>{{ lang.ssGradeType }}</span>
         </div>
         </div>
@@ -33,7 +33,7 @@
                   src="../../../assets/stuImg/zankai.svg"
                   src="../../../assets/stuImg/zankai.svg"
                   alt=""
                   alt=""
                 />
                 />
-                <div v-if="role == 1 && (mouseEnterId == item.id || mouseEnterId2 == item.id)">
+                <div v-if="(orglist.includes(org) || role == 1) && (mouseEnterId == item.id || mouseEnterId2 == item.id)">
                   <el-popover
                   <el-popover
                       placement="bottom-end"
                       placement="bottom-end"
                       width="80"
                       width="80"
@@ -508,7 +508,7 @@ export default {
       console.log(params);
       console.log(params);
 
 
       this.ajax
       this.ajax
-        .post(this.$store.state.api + "addClassgra", params)
+        .post(this.$store.state.api + "addClassgraNew", params)
         .then((res) => {
         .then((res) => {
           if (res.data[0] && res.data[0][0].classname == 1) {
           if (res.data[0] && res.data[0][0].classname == 1) {
             this.$message({
             this.$message({

+ 55 - 5
src/components/pages/workPage/components/choiceQuestion.vue

@@ -3,18 +3,18 @@
     <div class="cq_title" v-if="work.testJson[showIndex]">
     <div class="cq_title" v-if="work.testJson[showIndex]">
       <span>{{ work.testJson[showIndex].teststitle }}</span>
       <span>{{ work.testJson[showIndex].teststitle }}</span>
 
 
-      <div class="cq_changeBtnArea" v-if="work.testJson.length>1">
+      <!-- <div class="cq_changeBtnArea" v-if="work.testJson.length>1">
         <span :class="{cq_cba_disabled: showIndex == 0}" @click="changeQuestion('prev')">{{ lang.ssPrevQ }}</span>
         <span :class="{cq_cba_disabled: showIndex == 0}" @click="changeQuestion('prev')">{{ lang.ssPrevQ }}</span>
         <span :class="{cq_cba_disabled: showIndex == work.testJson.length - 1}" @click="changeQuestion('next')">{{ lang.ssNextQ }}</span>
         <span :class="{cq_cba_disabled: showIndex == work.testJson.length - 1}" @click="changeQuestion('next')">{{ lang.ssNextQ }}</span>
-      </div>
+      </div> -->
     </div>
     </div>
 
 
 
 
-    <img class="cq_image" v-if="work.testJson[showIndex].timuList.length>0" :src="work.testJson[showIndex].timuList[0].src" @click="$hevueImgPreview(work.testJson[showIndex].timuList[0].src)">
+    <img class="cq_image" v-if="work.testJson[showIndex] && work.testJson[showIndex].timuList && work.testJson[showIndex].timuList.length>0" :src="work.testJson[showIndex].timuList[0].src" @click="$hevueImgPreview(work.testJson[showIndex].timuList[0].src)">
 
 
     <div class="cq_type" v-if="work.testJson[showIndex]">
     <div class="cq_type" v-if="work.testJson[showIndex]">
-      {{ work.testJson[showIndex].type == 1 ? lang.MultipleChoice : lang.MultipleChoice }}
-      <span v-if="work.testJson.length>1">({{showIndex+1}}/{{work.testJson.length}})</span>
+      {{ work.testJson[showIndex].type == '1' ? lang.SingleChoice : lang.MultipleChoice }}
+      <!-- <span v-if="work.testJson.length>1">({{showIndex+1}}/{{work.testJson.length}})</span> -->
 
 
     </div>
     </div>
     <div class="cq_checkListArea">
     <div class="cq_checkListArea">
@@ -67,6 +67,18 @@
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>
+
+    <div class="cq_changeBtn" v-if="work.testJson.length>1">
+      <div :class="{cq_cb_disabled: showIndex == 0}" @click="changeQuestion('prev')">
+        <svg style="transform: rotate(-90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200"><path d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z" fill=""></path></svg>
+      </div>
+      <span>{{ showIndex+1 }}/{{work.testJson.length}}</span>
+      <div :class="{cq_cb_disabled: showIndex == work.testJson.length - 1}" @click="changeQuestion('next')">
+        <svg style="transform: rotate(90deg);" viewBox="0 0 1024 1024" version="1.1" width="200" height="200"><path d="M512 330.666667c14.933333 0 29.866667 4.266667 40.533333 14.933333l277.33333399 234.666667c27.733333 23.466667 29.866667 64 8.53333301 89.6-23.466667 27.733333-64 29.866667-89.6 8.53333299L512 477.866667l-236.8 200.53333299c-27.733333 23.466667-68.266667 19.19999999-89.6-8.53333299-23.466667-27.733333-19.19999999-68.266667 8.53333301-89.6l277.33333399-234.666667c10.666667-10.666667 25.6-14.933333 40.533333-14.933333z" fill=""></path></svg>
+      </div>
+      <!-- <span :class="{cq_cba_disabled: showIndex == 0}" @click="changeQuestion('prev')">{{ lang.ssPrevQ }}</span>
+      <span :class="{cq_cba_disabled: showIndex == work.testJson.length - 1}" @click="changeQuestion('next')">{{ lang.ssNextQ }}</span> -->
+    </div>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -136,6 +148,7 @@ export default {
       if (this.work.testJson[this.showIndex].type == "1") {
       if (this.work.testJson[this.showIndex].type == "1") {
         this.work.testJson[this.showIndex].userAnswer = index;
         this.work.testJson[this.showIndex].userAnswer = index;
       } else {
       } else {
+        if(typeof this.work.testJson[this.showIndex].userAnswer !== 'object') this.work.testJson[this.showIndex].userAnswer = [];
         if (this.work.testJson[this.showIndex].userAnswer.includes(index)) {
         if (this.work.testJson[this.showIndex].userAnswer.includes(index)) {
           this.work.testJson[this.showIndex].userAnswer = this.work.testJson[
           this.work.testJson[this.showIndex].userAnswer = this.work.testJson[
             this.showIndex
             this.showIndex
@@ -411,4 +424,41 @@ export default {
   z-index: 1; /* after在内容下方 */
   z-index: 1; /* after在内容下方 */
   pointer-events: none;
   pointer-events: none;
 }
 }
+
+.cq_changeBtn{
+  display: flex;
+  align-items: center;
+  gap: 1.5rem;
+  margin-top: 2rem;
+}
+
+.cq_changeBtn>div{
+  padding: .6rem;
+  border-radius: .5rem;
+  border: solid 2px #F6C82B;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  cursor: pointer;
+
+}
+
+.cq_changeBtn>span{
+  font-weight: 500;
+}
+
+.cq_changeBtn>div>svg{
+  fill: #F6C82D;
+  width: 1rem;
+  height: 1rem;
+}
+
+.cq_cb_disabled{
+  cursor: not-allowed !important;
+  border-color: #FEF8E9 !important;
+}
+
+.cq_cb_disabled>svg{
+  fill: #A3A3A3 !important;
+}
 </style>
 </style>

+ 250 - 30
src/components/pages/workPage/components/setChoiceQuestion.vue

@@ -2,7 +2,7 @@
   <div class="setChoiceQuestion">
   <div class="setChoiceQuestion">
     <div class="testItem" v-for="(item, index) in jsonData.testJson" :key="item.id">
     <div class="testItem" v-for="(item, index) in jsonData.testJson" :key="item.id">
       <div class="ti_header">
       <div class="ti_header">
-        <span>{{ lang.ssTopic }}{{ index + 1 }}</span>
+        <span>{{ lang.ssTopic }}{{ index + 1 }} <span v-if="item.answer.length==0">{{lang.ssNoSettingAnswer}}</span></span>
         <div class="ti_h_edit">
         <div class="ti_h_edit">
           <span @click="copyTest(item.id)">
           <span @click="copyTest(item.id)">
             <svg viewBox="0 0 1024 1024" version="1.1" p-id="4608" width="200" height="200">
             <svg viewBox="0 0 1024 1024" version="1.1" p-id="4608" width="200" height="200">
@@ -11,7 +11,26 @@
                 p-id="4609"></path>
                 p-id="4609"></path>
             </svg>
             </svg>
           </span>
           </span>
-          <span @click="deleteTest(item.id)">
+
+          <!-- 上 -->
+          <span @click="changeIndex(item, index, 'up')">
+            <svg viewBox="0 0 1024 1024" width="200" height="200" fill="#6B7280">
+              <path
+                d="M959.804421 511.603981l-84.009346 84.023672L576.143391 293.406446l0 665.582911L448.20351 958.989357 448.20351 293.406446 147.619594 595.628676l-84.024695-84.023672L512.213359 63.546292 959.804421 511.603981z">
+              </path>
+            </svg>
+          </span>
+          <!-- 下 -->
+          <span @click="changeIndex(item, index, 'down')">
+            <svg style="transform: rotate(180deg);" viewBox="0 0 1024 1024" width="200" height="200" fill="#6B7280">
+              <path
+                d="M959.804421 511.603981l-84.009346 84.023672L576.143391 293.406446l0 665.582911L448.20351 958.989357 448.20351 293.406446 147.619594 595.628676l-84.024695-84.023672L512.213359 63.546292 959.804421 511.603981z">
+              </path>
+            </svg>
+
+          </span>
+
+          <span @click="deleteTest(item.id)" v-show="jsonData.testJson.length > 1">
             <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
             <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
               <path
               <path
                 d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
                 d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
@@ -34,16 +53,39 @@
       </div>
       </div>
       <!-- 图片 -->
       <!-- 图片 -->
       <div class="imageList">
       <div class="imageList">
-        <div v-for="(image, imageIndex) in item.timuList" :key="item.id+'_'+imageIndex">
+        <div v-for="(image, imageIndex) in item.timuList" :key="item.id + '_' + imageIndex">
           <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]"
           <el-image style="width: 100px; height: 100px" :src="image.url" :preview-src-list="[image.url]"
             fit="cover"></el-image>
             fit="cover"></el-image>
-            <svg @click="delImage(item.id, 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>
+          <svg @click="delImage(item.id, 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>
       </div>
 
 
       <!-- 选择题 -->
       <!-- 选择题 -->
       <div class="checkList">
       <div class="checkList">
-        <div class="checkItem" v-for="(check, checkIndex) in item.checkList" :key="checkIndex">
+        <div class="checkItem" v-for="(check, checkIndex) in item.checkList" :key="checkIndex"
+            draggable="true"
+            @dragstart="dragStart($event, item, checkIndex)"
+            @dragover.prevent="dragOver($event, item, checkIndex)"
+            @drop="drop($event, item, checkIndex)"
+            @dragend="dragEnd">
+          <div class="drag">
+            <svg viewBox="0 0 1024 1024" width="200" height="200">
+              <path
+                d="M867.995 459.647h-711.99c-27.921 0-52.353 24.434-52.353 52.353s24.434 52.353 52.353 52.353h711.99c27.921 0 52.353-24.434 52.353-52.353s-24.434-52.353-52.353-52.353z"
+                p-id="9455"></path>
+              <path
+                d="M867.995 763.291h-711.99c-27.921 0-52.353 24.434-52.353 52.353s24.434 52.353 52.353 52.353h711.99c27.921 0 52.353-24.434 52.353-52.353s-24.434-52.353-52.353-52.353z"
+                p-id="9456"></path>
+              <path
+                d="M156.005 260.709h711.99c27.921 0 52.353-24.434 52.353-52.353s-24.434-52.353-52.353-52.353h-711.99c-27.921 0-52.353 24.434-52.353 52.353s24.434 52.353 52.353 52.353z">
+              </path>
+            </svg>
+          </div>
           <div class="check" :class="{ 'checked': item.answer.includes(checkIndex) }"
           <div class="check" :class="{ 'checked': item.answer.includes(checkIndex) }"
             @click="checkClick(item.id, checkIndex)">
             @click="checkClick(item.id, checkIndex)">
             <svg v-if="item.answer.includes(checkIndex)" t="1773996159000" viewBox="0 0 1024 1024" version="1.1"
             <svg v-if="item.answer.includes(checkIndex)" t="1773996159000" viewBox="0 0 1024 1024" version="1.1"
@@ -53,13 +95,26 @@
                 p-id="5895"></path>
                 p-id="5895"></path>
             </svg>
             </svg>
           </div>
           </div>
-          <el-input v-model="item.checkList[checkIndex]" :placeholder="lang.ssEnterOption" @blur="setTestJson()"></el-input>
+          <el-input v-model="item.checkList[checkIndex]" :placeholder="lang.ssEnterOption"
+            @blur="setTestJson()"></el-input>
           <div class="btn">
           <div class="btn">
-            <div @click="delCheck(item.id, checkIndex)">
-              <svg viewBox="0 0 1024 1024" version="1.1" p-id="12415" width="200" height="200">
+
+            <div @click="addCheck(item.id, checkIndex)" v-if="item.checkList.length > 2">
+              <svg style="width: .7rem; height: .7rem;" viewBox="0 0 1024 1024" width="200" height="200">
+                <path
+                  d="M47.653 439.326c-24.501 0-44.368 19.881-44.368 44.4v56.548c0 24.492 19.862 44.4 44.368 44.4h928.694c24.501 0 44.368-19.881 44.368-44.4v-56.548c0-24.497-19.862-44.4-44.368-44.4H47.653z"
+                  p-id="11474"></path>
+                <path
+                  d="M586.326 47.653c0-24.501-19.881-44.368-44.4-44.368h-56.548c-24.492 0-44.4 19.862-44.4 44.368v928.694c0 24.501 19.881 44.368 44.4 44.368h56.548c24.497 0 44.4-19.862 44.4-44.368V47.653z">
+                </path>
+              </svg>
+            </div>
+
+            <div @click="delCheck(item.id, checkIndex)" v-if="item.checkList.length > 2">
+              <svg viewBox="0 0 1024 1024" width="200" height="200">
                 <path
                 <path
-                  d="M902.4 282.1H117.7c-13.4 0-23.5-10.1-23.5-23.5v-3.4c0-13.4 10.1-23.5 23.5-23.5h788.1c13.4 0 23.5 10.1 23.5 23.5v3.4c0 13.4-10.1 23.5-26.9 23.5zM634.1 151.3H386c-13.4 0-26.8-10.1-23.5-23.5v-6.7c0-13.4 10.1-23.5 23.5-23.5h248.2c13.4 0 23.5 10.1 23.5 23.5v3.4c3.3 13.3-10.1 26.8-23.6 26.8z m228.1 238.1c0-13.4-10.1-26.8-26.8-26.8-16.8 0-26.8 10.1-26.8 26.8L775 798.5v13.4c0 23.5-10.1 43.6-30.2 53.7-13.4 6.7-30.2 10.1-50.3 10.1H332.3c-33.5 3.4-60.4 0-70.4-33.5-3.4-6.7-6.7-16.8-6.7-26.8l-10.1-104-36.9-322c0-13.4-10.1-23.5-23.5-23.5s-26.8 10.1-26.8 23.5l47 462.8c0 40.2 40.2 73.8 80.5 73.8h459.5c40.2 0 80.5-33.5 80.5-73.8l36.8-462.8c0 3.3 0 0 0 0z m0 0"
-                  p-id="12416"></path>
+                  d="M632.117978 513.833356l361.805812 361.735298a85.462608 85.462608 0 1 1-121.001515 120.789974L511.116463 634.552816 146.913186 998.756094a86.026718 86.026718 0 0 1-121.706652-121.706652L389.480325 512.775651 27.674513 150.969839A85.392095 85.392095 0 0 1 148.393973 30.250379L510.199785 392.056191l366.671258-366.671258a86.026718 86.026718 0 0 1 121.706652 121.706652z">
+                </path>
               </svg>
               </svg>
             </div>
             </div>
           </div>
           </div>
@@ -87,8 +142,8 @@
             <span>{{ lang.ssAIGenerate }}</span>
             <span>{{ lang.ssAIGenerate }}</span>
           </div>
           </div>
         </div>
         </div>
-        <el-input type="textarea" rows="3" resize="none" v-model="item.explanation" :placeholder="lang.ssEnterExplanation"
-          @blur="setTestJson()"></el-input>
+        <el-input type="textarea" rows="3" resize="none" v-model="item.explanation"
+          :placeholder="lang.ssEnterExplanation" @blur="setTestJson()"></el-input>
       </div>
       </div>
     </div>
     </div>
 
 
@@ -119,7 +174,8 @@ export default {
   },
   },
   data() {
   data() {
     return {
     return {
-      jsonData: {}
+      jsonData: {},
+      dragItem: null
     }
     }
   },
   },
   watch: {
   watch: {
@@ -127,7 +183,11 @@ export default {
       handler(newVal, oldVal) {
       handler(newVal, oldVal) {
         if (newVal.type == 45) {
         if (newVal.type == 45) {
           if (JSON.stringify(newVal.json) != JSON.stringify(this.jsonData)) {
           if (JSON.stringify(newVal.json) != JSON.stringify(this.jsonData)) {
+
             this.jsonData = JSON.parse(JSON.stringify(newVal.json));
             this.jsonData = JSON.parse(JSON.stringify(newVal.json));
+            if(this.jsonData.testJson.length == 0){
+              this.addTest();
+            }
           }
           }
         }
         }
       },
       },
@@ -148,7 +208,7 @@ export default {
         id: uuidv4(),
         id: uuidv4(),
         type: "2",
         type: "2",
         teststitle: "",
         teststitle: "",
-        checkList: [''],
+        checkList: ['', '', ''],
         timuList: [],
         timuList: [],
         answer: [],
         answer: [],
         userAnswer: [],
         userAnswer: [],
@@ -184,10 +244,15 @@ export default {
       this.setTestJson();
       this.setTestJson();
     },
     },
     // 添加选项
     // 添加选项
-    addCheck(id) {
+    addCheck(id, checkIndex = null) {
       let index = this.jsonData.testJson.findIndex(item => item.id == id);
       let index = this.jsonData.testJson.findIndex(item => item.id == id);
       let test = this.jsonData.testJson[index];
       let test = this.jsonData.testJson[index];
-      test.checkList.push('');
+      if (!checkIndex) {
+        checkIndex = test.checkList.length;
+      }else{
+        checkIndex = checkIndex + 1;
+      }
+      test.checkList.splice(checkIndex, 0, '');
       this.setTestJson();
       this.setTestJson();
     },
     },
     // 删除选项
     // 删除选项
@@ -236,6 +301,109 @@ export default {
       }
       }
       this.setTestJson();
       this.setTestJson();
     },
     },
+    // 移动题目
+    changeIndex(item, index, direction) {
+      let test = this.jsonData.testJson.find(i => i.id == item.id);
+      if (test) {
+        if (direction == 'up') {
+          if (index == 0) {
+            this.$message.info("已到顶部");
+            return;
+          }
+          this.jsonData.testJson.splice(index, 1);
+          this.jsonData.testJson.splice(index - 1, 0, JSON.parse(JSON.stringify(test)));
+        } else if (direction == 'down') {
+          if (index == this.jsonData.testJson.length - 1) {
+            this.$message.info("已到底部");
+            return;
+          }
+          this.jsonData.testJson.splice(index, 1);
+          this.jsonData.testJson.splice(index + 1, 0, JSON.parse(JSON.stringify(test)));
+        }
+        this.setTestJson();
+      }
+    },
+    // 拖拽相关方法
+    dragStart(e, item, checkIndex) {
+      this.dragItem = { item, checkIndex };
+      const checkItem = e.target.closest('.checkItem');
+      if (checkItem) checkItem.classList.add('dragging');
+      e.dataTransfer.effectAllowed = 'move';
+    },
+    dragOver(e, item, checkIndex) {
+      e.preventDefault();
+      e.dataTransfer.dropEffect = 'move';
+
+      document.querySelectorAll('.checkItem').forEach(el => {
+        el.style.borderTop = '';
+        el.style.borderBottom = '';
+      });
+
+      const checkItems = e.target.closest('.checkItem');
+      if (checkItems && this.dragItem && this.dragItem.checkIndex !== checkIndex) {
+        if (this.dragItem.checkIndex < checkIndex) {
+          checkItems.style.borderBottom = '2px solid #ffa502';
+        } else {
+          checkItems.style.borderTop = '2px solid #ffa502';
+        }
+      }
+    },
+    drop(e, targetItem, targetCheckIndex) {
+      e.preventDefault();
+      document.querySelectorAll('.checkItem').forEach(el => {
+        el.style.borderTop = '';
+        el.style.borderBottom = '';
+        el.classList.remove('dragging');
+      });
+      if (!this.dragItem) return;
+
+      const { item: sourceItem, checkIndex: sourceCheckIndex } = this.dragItem;
+
+      if (sourceItem.id !== targetItem.id) return;
+      if (sourceCheckIndex === targetCheckIndex) return;
+
+      const test = this.jsonData.testJson.find(i => i.id === sourceItem.id);
+      if (test) {
+        let newAnswerIndex;
+
+        if (sourceCheckIndex < targetCheckIndex) {
+          newAnswerIndex = targetCheckIndex - 1;
+        } else {
+          newAnswerIndex = targetCheckIndex;
+        }
+
+        const item = test.checkList[sourceCheckIndex];
+        test.checkList.splice(sourceCheckIndex, 1);
+        test.checkList.splice(targetCheckIndex, 0, item);
+
+        if (test.answer.includes(sourceCheckIndex)) {
+          const answerIndex = test.answer.indexOf(sourceCheckIndex);
+          test.answer.splice(answerIndex, 1);
+          test.answer.push(newAnswerIndex);
+          test.answer.sort((a, b) => a - b);
+        } else {
+          test.answer = test.answer.map(idx => {
+            if (sourceCheckIndex < targetCheckIndex) {
+              return idx > sourceCheckIndex && idx <= targetCheckIndex ? idx - 1 : idx;
+            } else {
+              return idx >= targetCheckIndex && idx < sourceCheckIndex ? idx + 1 : idx;
+            }
+          });
+        }
+
+        this.setTestJson();
+      }
+      this.dragItem = null;
+    },
+    dragEnd(e) {
+      const checkItem = e.target.closest('.checkItem');
+      if (checkItem) checkItem.classList.remove('dragging');
+      document.querySelectorAll('.checkItem').forEach(el => {
+        el.style.borderTop = '';
+        el.style.borderBottom = '';
+      });
+      this.dragItem = null;
+    },
   },
   },
 }
 }
 </script>
 </script>
@@ -292,6 +460,7 @@ export default {
   align-items: center;
   align-items: center;
   justify-content: space-between;
   justify-content: space-between;
 
 
+
 }
 }
 
 
 .ti_header>span {
 .ti_header>span {
@@ -300,6 +469,12 @@ export default {
   color: #ff9300;
   color: #ff9300;
 }
 }
 
 
+.ti_header>span>span {
+  font-size: .8rem;
+  color: rgb(117, 117, 117);
+  margin-left: .5rem;
+}
+
 .ti_h_edit {
 .ti_h_edit {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -344,6 +519,8 @@ export default {
   background: none;
   background: none;
   font-size: .8rem;
   font-size: .8rem;
   resize: none;
   resize: none;
+  max-height: 10rem;
+  overflow: auto;
   /* padding-right: 2rem; */
   /* padding-right: 2rem; */
 }
 }
 
 
@@ -372,7 +549,7 @@ export default {
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   gap: 1rem;
   gap: 1rem;
-  padding-left: 4rem;
+  /* padding-left: 4rem; */
 }
 }
 
 
 .checkItem {
 .checkItem {
@@ -382,9 +559,46 @@ export default {
   align-items: center;
   align-items: center;
   justify-content: flex-start;
   justify-content: flex-start;
   gap: .5rem;
   gap: .5rem;
+  padding: .3rem .5rem;
+  transition: .2s;
+}
+
+.checkItem:hover {
+  background: #F9FAFB;
+}
+
+.drag {
+  width: 1.1rem;
+  height: 1.1rem;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  cursor: move;
+  margin-right: 1rem;
+  opacity: 0;
+  transition: .2s;
+}
 
 
+.checkItem:hover > .drag {
+  opacity: 1;
 }
 }
 
 
+.checkItem[draggable="true"] {
+  cursor: move;
+}
+
+.checkItem.dragging {
+  opacity: 0.5;
+  background: #FEF3C7;
+}
+
+.drag>svg {
+  width: 100%;
+  height: 100%;
+  fill: #D1D5DC;
+}
+
+
 .check {
 .check {
   width: 1.1rem;
   width: 1.1rem;
   height: 1.1rem;
   height: 1.1rem;
@@ -438,24 +652,32 @@ export default {
 .btn {
 .btn {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
-  gap: .25em;
+  gap: 1em;
+  opacity: 0;
+  margin-left: 1rem;
+}
+
+.checkItem:hover>.btn {
+  opacity: 1;
 }
 }
 
 
+
+
 .btn>div {
 .btn>div {
-  width: 1.5rem;
-  height: 1.5rem;
+  width: 1rem;
+  height: 1rem;
   display: flex;
   display: flex;
   justify-content: center;
   justify-content: center;
   align-items: center;
   align-items: center;
-  background: #F9FAFB;
+  /* background: #F9FAFB; */
   border-radius: .4px;
   border-radius: .4px;
   cursor: pointer;
   cursor: pointer;
 }
 }
 
 
 .btn>div>svg {
 .btn>div>svg {
-  width: 1rem;
-  height: 1rem;
-  fill: #6B7280;
+  width: .6rem;
+  height: .6rem;
+  fill: #9DA3AF;
 }
 }
 
 
 .explanation {
 .explanation {
@@ -508,7 +730,8 @@ export default {
   flex-wrap: wrap;
   flex-wrap: wrap;
   gap: 1rem;
   gap: 1rem;
 }
 }
-.imageList>div{
+
+.imageList>div {
   width: 100px;
   width: 100px;
   height: 100px;
   height: 100px;
   display: flex;
   display: flex;
@@ -520,11 +743,11 @@ export default {
 
 
 }
 }
 
 
-.imageList>div:hover>svg{
+.imageList>div:hover>svg {
   display: flex;
   display: flex;
 }
 }
 
 
-.imageList>div>svg{
+.imageList>div>svg {
   width: 1rem;
   width: 1rem;
   height: 1rem;
   height: 1rem;
   position: absolute;
   position: absolute;
@@ -538,7 +761,4 @@ export default {
   justify-content: center;
   justify-content: center;
   display: none;
   display: none;
 }
 }
-
-
-
 </style>
 </style>

+ 2 - 0
src/components/pages/workPage/components/setQuestionsAndAnswers.vue

@@ -267,6 +267,8 @@ export default {
   background: none;
   background: none;
   font-size: .8rem;
   font-size: .8rem;
   resize: none;
   resize: none;
+  max-height:10rem;
+  overflow:auto;
   /* padding-right: 2rem; */
   /* padding-right: 2rem; */
 }
 }
 
 

+ 21 - 5
src/lang/cn.json

@@ -1048,6 +1048,20 @@
   "ssQChainNotGen":"问题链还未生成完,请前往查看,回答完毕后再次操作。",
   "ssQChainNotGen":"问题链还未生成完,请前往查看,回答完毕后再次操作。",
   "ssCourseSettings":"课程设置",
   "ssCourseSettings":"课程设置",
   "ssApply":"应用",
   "ssApply":"应用",
+  "ssPublishCourse":"发布课程",
+  "ssVisibilityRange":"可见范围",
+  "ssOnlyStudentsVisible":"仅发布学生可见",
+  "ssOnlyStudentsDesc":"仅对发布的班级学生可见,其他人无法访问",
+  "ssOrganizationVisible":"组织可见",
+  "ssOrganizationDesc":"学校内所有教师均可查看",
+  "ssCourseCover":"课程封面",
+  "ssHoverToSelectUpload":"悬浮选择上传方式",
+  "ssUploadFromLocal":"自本地上传",
+  "ssSearchFromWeb":"自网页搜索",
+  "ssGenerateFromAI":"自AI生成",
+  "ssWebSearchImage":"网页搜索图片",
+  "ssSearchKeyword":"搜索关键词",
+  "ssConfirmPublish":"确认发布",
   "ssTargetNotGen":"目标层还未生成完,请前往查看,回答完毕后再次操作。",
   "ssTargetNotGen":"目标层还未生成完,请前往查看,回答完毕后再次操作。",
   "ssTaskClusNotGen":"任务簇还未生成完,请前往查看,回答完毕后再次操作。",
   "ssTaskClusNotGen":"任务簇还未生成完,请前往查看,回答完毕后再次操作。",
   "ssGenDescFirst":"请生成简要描述后再生成大纲",
   "ssGenDescFirst":"请生成简要描述后再生成大纲",
@@ -1927,7 +1941,7 @@
   "ssSearchFail":"搜索失败,请重试",
   "ssSearchFail":"搜索失败,请重试",
   "ssSelectVideo":"请先选择要添加的视频",
   "ssSelectVideo":"请先选择要添加的视频",
   "ssAddSuccessVideo":"成功添加*个视频",
   "ssAddSuccessVideo":"成功添加*个视频",
-  "ssSelectVideoSource":"选择一种视频来源",
+  "ssSelectVideoSource":"选择视频来源",
   "ssLocalUpload":"从本地文件上传",
   "ssLocalUpload":"从本地文件上传",
   "ssBiliSearch":"从Bilibili检索",
   "ssBiliSearch":"从Bilibili检索",
   "ssNewGrade":"新年级",
   "ssNewGrade":"新年级",
@@ -1994,11 +2008,11 @@
   "ssUploadTip":"支持格式:.xlsx,.xls,大小不超过10MB",
   "ssUploadTip":"支持格式:.xlsx,.xls,大小不超过10MB",
   "ssUploadTempLbl":"上传模板:",
   "ssUploadTempLbl":"上传模板:",
   "ssDownloadTemp":"下载模板",
   "ssDownloadTemp":"下载模板",
-  "ssUploadNote":"注意:请按照模板格式填写学生信息,避免导入失败",
+  "ssUploadNote":"提示:请按照模板格式填写学生信息并导入。",
   "ssGetSuffixReUp":"正在获取后缀,请重新上传",
   "ssGetSuffixReUp":"正在获取后缀,请重新上传",
   "ssGetSuffixReAdd":"正在获取后缀,请重新添加",
   "ssGetSuffixReAdd":"正在获取后缀,请重新添加",
   "ssCheckStuNameCol":"请检查上传文件学生姓名列是否填写正确",
   "ssCheckStuNameCol":"请检查上传文件学生姓名列是否填写正确",
-  "ssCheckClassCol":"请检查上传文件班级列是否填写正确",
+  "ssCheckClassCol":"有同学班级信息有误,请检查",
   "ssParseStuFail":"未能提取上传学生信息,请检查数据格式,使用模板文件格式上传",
   "ssParseStuFail":"未能提取上传学生信息,请检查数据格式,使用模板文件格式上传",
   "ssEnterStu":"请输入学生",
   "ssEnterStu":"请输入学生",
   "ssAddStuMax70":"一次最多添加70人",
   "ssAddStuMax70":"一次最多添加70人",
@@ -2028,6 +2042,8 @@
   "ssCourseCenter":"课程中心",
   "ssCourseCenter":"课程中心",
   "ssCourseType":"课程类型",
   "ssCourseType":"课程类型",
   "ssSelectCourseType":"请选择课程类型",
   "ssSelectCourseType":"请选择课程类型",
-  "ssSelectedCourse":"已选择 * 个课程"
-
+  "ssSelectedCourse":"已选择 * 个课程",
+  "ssSelectedApp":"已选择 * 个应用",
+  "ssSyncImportClassInfo":"提示: 如需同步导入班级信息,请于此处下载导入模板,并于【班级】列准确输入年级+班级名称作为学生班级(兴趣班不支持导入学生)",
+  "ssNoSettingAnswer":"未设置正确答案"
 }
 }

+ 9 - 4
src/lang/en.json

@@ -1940,7 +1940,7 @@
   "ssSearchFail":"Search failed, please try again",
   "ssSearchFail":"Search failed, please try again",
   "ssSelectVideo":"Please select the video to add",
   "ssSelectVideo":"Please select the video to add",
   "ssAddSuccessVideo":"Successfully added * videos",
   "ssAddSuccessVideo":"Successfully added * videos",
-  "ssSelectVideoSource":"Select a Video Source",
+  "ssSelectVideoSource":"Select Video Source",
   "ssLocalUpload":"Upload from Device",
   "ssLocalUpload":"Upload from Device",
   "ssBiliSearch":"Search on YouTube",
   "ssBiliSearch":"Search on YouTube",
   "ssNewGrade":"New Grade",
   "ssNewGrade":"New Grade",
@@ -2007,11 +2007,11 @@
   "ssUploadTip":"Supported: xlsx, xls , up to 10MB",
   "ssUploadTip":"Supported: xlsx, xls , up to 10MB",
   "ssUploadTempLbl":"Upload template:",
   "ssUploadTempLbl":"Upload template:",
   "ssDownloadTemp":"Download template",
   "ssDownloadTemp":"Download template",
-  "ssUploadNote":"Note: 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 to avoid import failure",
   "ssGetSuffixReUp":"Getting suffix, please re-upload",
   "ssGetSuffixReUp":"Getting suffix, please re-upload",
   "ssGetSuffixReAdd":"Getting suffix, please re-add",
   "ssGetSuffixReAdd":"Getting suffix, please re-add",
   "ssCheckStuNameCol":"Please check whether the student name column in the uploaded file is correct",
   "ssCheckStuNameCol":"Please check whether the student name column in the uploaded file is correct",
-  "ssCheckClassCol":"Please check whether the class column in the uploaded file is correct",
+  "ssCheckClassCol":"Some students have incorrect class information, please check",
   "ssParseStuFail":"Failed to parse student information. Please check the data format and use the template file format",
   "ssParseStuFail":"Failed to parse student information. Please check the data format and use the template file format",
   "ssEnterStu":"Please enter student",
   "ssEnterStu":"Please enter student",
   "ssAddStuMax70":"You can add up to 70 students at a time",
   "ssAddStuMax70":"You can add up to 70 students at a time",
@@ -2041,5 +2041,10 @@
   "ssCourseCenter":"Course Center",
   "ssCourseCenter":"Course Center",
   "ssCourseType":"Course Type",
   "ssCourseType":"Course Type",
   "ssSelectCourseType":"Please select course type",
   "ssSelectCourseType":"Please select course type",
-  "ssSelectedCourse":"Selected * courses"
+  "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)"
+
+
 }
 }

+ 8 - 6
src/lang/hk.json

@@ -1940,7 +1940,7 @@
   "ssSearchFail":"搜索失敗,請重試",
   "ssSearchFail":"搜索失敗,請重試",
   "ssSelectVideo":"請先選擇要添加的視頻",
   "ssSelectVideo":"請先選擇要添加的視頻",
   "ssAddSuccessVideo":"成功添加*個視頻",
   "ssAddSuccessVideo":"成功添加*個視頻",
-  "ssSelectVideoSource":"選擇一種視頻來源",
+  "ssSelectVideoSource":"選擇視頻來源",
   "ssLocalUpload":"從本地文件上傳",
   "ssLocalUpload":"從本地文件上傳",
   "ssBiliSearch":"從Bilibili檢索",
   "ssBiliSearch":"從Bilibili檢索",
   "ssNewGrade":"新年級",
   "ssNewGrade":"新年級",
@@ -2007,11 +2007,11 @@
   "ssUploadTip":"支持格式:.xlsx,.xls,大小不超過10MB",
   "ssUploadTip":"支持格式:.xlsx,.xls,大小不超過10MB",
   "ssUploadTempLbl":"上傳模板:",
   "ssUploadTempLbl":"上傳模板:",
   "ssDownloadTemp":"下載模板",
   "ssDownloadTemp":"下載模板",
-  "ssUploadNote":"注意:請按照模板格式填寫學生信息,避免導入失敗",
+  "ssUploadNote":"提示:請按照模板格式填寫學生信息,避免導入失敗",
   "ssGetSuffixReUp":"正在獲取後綴,請重新上傳",
   "ssGetSuffixReUp":"正在獲取後綴,請重新上傳",
   "ssGetSuffixReAdd":"正在獲取後綴,請重新添加",
   "ssGetSuffixReAdd":"正在獲取後綴,請重新添加",
   "ssCheckStuNameCol":"請檢查上傳文件學生姓名列是否填寫正確",
   "ssCheckStuNameCol":"請檢查上傳文件學生姓名列是否填寫正確",
-  "ssCheckClassCol":"請檢查上傳文件班級列是否填寫正確",
+  "ssCheckClassCol":"有同學班級信息有誤,請檢查",
   "ssParseStuFail":"未能提取上傳學生信息,請檢查數據格式,使用模板文件格式上傳",
   "ssParseStuFail":"未能提取上傳學生信息,請檢查數據格式,使用模板文件格式上傳",
   "ssEnterStu":"請輸入學生",
   "ssEnterStu":"請輸入學生",
   "ssAddStuMax70":"一次最多添加70人",
   "ssAddStuMax70":"一次最多添加70人",
@@ -2041,7 +2041,9 @@
   "ssCourseCenter":"課程中心",
   "ssCourseCenter":"課程中心",
   "ssCourseType":"課程類型",
   "ssCourseType":"課程類型",
   "ssSelectCourseType":"請選擇課程類型",
   "ssSelectCourseType":"請選擇課程類型",
-  "ssSelectedCourse":"已選擇 * 個課程"
-
-
+  "ssSelectedCourse":"已選擇 * 個課程",
+  "ssSelectedApp":"已選擇 * 個應用",
+  "ssCocoNoteUpdateTips":"協同建構不支持修改基本信息,只支持加入分組。",
+  "ssNoSettingAnswer":"未設置正確答案",
+  "ssSyncImportClassInfo":"提示: 如需同步導入班級信息,請於此處下載導入模板,並於【班級】列準確輸入年級+班級名稱作為學生班級(興趣班不支持導入學生)"
 }
 }

部分文件因文件數量過多而無法顯示