zengyicheng 1 year ago
parent
commit
0d48edd924

BIN
src/assets/icon/newIcons/whiteLast.png


BIN
src/assets/icon/newIcons/whiteLock.png


BIN
src/assets/icon/newIcons/whiteNext.png


+ 228 - 7
src/components/easy2/studyStudent.vue

@@ -243,16 +243,26 @@
               </div>
             </div>
             <div class="btnRight">
-              <div class="last" @click="nextOrpreSteps(0)">
+              <div class="last" @click="nextOrpreSteps(0)" @mouseover="isHovered = true"
+                @mouseout="isHovered = false">
                 <div class="lastImg">
-                  <img src="../../assets/icon/newIcons/last.png" alt="" />
+                  <img :src="
+                      isHovered
+                        ? require('../../assets/icon/newIcons/whiteLast.png')
+                        : require('../../assets/icon/newIcons/last.png')
+                    " alt="" />
                 </div>
                 <div class="lastText">上一步</div>
               </div>
-              <div class="last" @click="nextOrpreSteps(1)">
+              <div class="last" @click="nextOrpreSteps(1)" @mouseover="isHovered1 = true"
+                @mouseout="isHovered1 = false">
                 <div class="lastText">下一步</div>
                 <div class="lastImg">
-                  <img src="../../assets/icon/newIcons/next.png" alt="" />
+                  <img :src="
+                      isHovered1
+                        ? require('../../assets/icon/newIcons/whiteNext.png')
+                        : require('../../assets/icon/newIcons/next.png')
+                    " alt="" />
                 </div>
               </div>
               <!-- <div class="last" @click="juriVisible = true" v-if="tType == 1">
@@ -8864,8 +8874,30 @@
                 @click="previewImg(pz.content)"
               />
             </div>
-            <div class="time">
-              {{ pz.time }}
+            <div class="timeAndReply">
+              <div class="time">
+                {{ pz.time }}
+              </div>
+              <div @click="setReplyIndex(pz.id,pzIndex)">回复</div>
+            </div>
+            
+            <div v-if="pz.hfList && pz.hfList.length > 0" class="hfBox">
+              <div
+                v-for="(h, hIndex) in pz.hfList"
+                :key="hIndex"
+                class="hfItem"
+              >
+                <div class="whoReplyWho">
+                  <div class="hfName">{{ h.username }}</div>
+                  <div class="hfImg"><img src="../../assets/icon/newIcons/right.png" alt="" /></div>
+                  <div class="hfName">{{ pz.username }}</div>
+                </div>
+                <div class="hfContent" v-html="h.content"></div>
+                <div class="hfBottom">
+                  <div class="hfTime">{{ h.time }}</div>
+                  <div @click="deleteReply(h.id)" v-if="userid == h.userid">删除</div>
+                </div>
+              </div>
             </div>
           </div>
         </div>
@@ -8884,6 +8916,41 @@
         </div>
       </div>
     </div>
+    <div v-if="replyDialogVisible == true" class="addDialogCss" v-el-drag-dialog>
+      <div class="pzTop">
+        <div class="teacherPz">
+          <div class="teacherPzImg">
+            <img src="../../assets/icon/teacherPz.png" alt="" />
+          </div>
+          <div style="margin-left: 10px; height: 25px">添加回复</div>
+        </div>
+        <div @click="replyDialogVisible = false">
+          <img src="../../assets/close1.png" class="pzClose" alt="" />
+        </div>
+      </div>
+      <div class="addPzBox">
+        <!-- <div class="addPzCheck">
+          <span :class="{ isChooseActive: pzType == 1 }" @click="pzType = 1"
+            >文本</span
+          >
+          <span :class="{ isChooseActive: pzType == 2 }" @click="pzType = 2"
+            >音频</span
+          >
+        </div> -->
+        <div style="height: calc(100% - 95px)">
+          <editor-bar
+            class="binfo_input pzConText"
+            style="width: 100% !important"
+            placeholder="请输入回复描述"
+            v-model="reply"
+            @change="change"
+          ></editor-bar>
+        </div>
+        <div class="addTextCss" @click="addHf">
+          确定
+        </div>
+      </div>
+    </div>
     <div v-if="addPzDialog == true" class="addDialogCss" v-el-drag-dialog>
       <div class="pzTop">
         <div class="teacherPz">
@@ -11995,6 +12062,9 @@ export default {
       answerDialogVisible: false,
       juriVisible: false,
       timeDialogVisible: false,
+      replyDialogVisible: false,
+      replyIndex: 0,
+      replyPid: "",
       radio: [],
       isAsk: false,
       askJson: {
@@ -12025,6 +12095,8 @@ export default {
       workTypeB: false,
       workTypeC: false,
       isAnswer: false,
+      isHovered: false,
+      isHovered1: false,
       timer: null,
       opertimer: null,
       showType: 0,
@@ -15618,6 +15690,44 @@ export default {
           console.error(err);
         });
     },
+    setReplyIndex(id,i){
+      this.replyIndex = i;
+      this.replyPid = id;
+      this.replyDialogVisible = true;
+    },
+    addHf() {
+      if (this.reply == "") {
+        this.$message.error("回复不能为空!");
+        return;
+      }
+      let params = [
+        {
+          cid: this.id,
+          uid: this.userid,
+          s: this.courseType,
+          t: this.taskCount,
+          type: "1",
+          ct: 2,
+          pid: this.replyPid,
+          c: this.reply.replaceAll(/%/g, "%25"),
+        },
+      ];
+      this.ajax
+        .post(this.$store.state.api + "addHf", params)
+        .then((res) => {
+          this.reply = "";
+          this.$message({
+            message: "回复成功",
+            type: "success",
+          });
+          this.replyDialogVisible = false;
+          this.selectPz();
+        })
+        .catch((err) => {
+          this.$message.error("回复失败");
+          console.error(err);
+        });
+    },
     deletePz(id) {
       this.$confirm("确定删除此批注吗?", "提示", {
         confirmButtonText: "确定",
@@ -15646,6 +15756,34 @@ export default {
         })
         .catch(() => {});
     },
+    deleteReply(id){
+      this.$confirm("确定删除此回复吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deleteReply", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
     selectPz() {
       let params = {
         cid: this.id,
@@ -15658,6 +15796,17 @@ export default {
         .get(this.$store.state.api + "selectPzListType", params)
         .then((res) => {
           this.pzList = res.data[0];
+          var a = res.data[1];
+          for (var i = 0; i < a.length; i++) {
+            for (var j = 0; j < this.pzList.length; j++) {
+              if (!this.pzList[j].hfList) {
+                this.pzList[j].hfList = [];
+              }
+              if (a[i].pid == this.pzList[j].id) {
+                this.pzList[j].hfList.push(a[i]);
+              }
+            }
+          }
         })
         .catch((err) => {
           console.error(err);
@@ -19784,6 +19933,11 @@ export default {
   background: #3681fc;
   color: #fff;
 }
+.last:hover {
+  background: #3383fa !important;
+  color: #fff;
+  border: 1px solid #3383fa !important;
+}
 .last,
 .returnBtn1 {
   width: 90px;
@@ -19791,6 +19945,7 @@ export default {
   background: #ffffff;
   border-radius: 4px;
   border: 1px solid #0061ff;
+  color: #0061ff;
   cursor: pointer;
   display: flex;
   flex-direction: row;
@@ -19813,7 +19968,6 @@ export default {
 .lastText {
   padding: 0 5px 2px 5px;
   box-sizing: border-box;
-  color: #0061ff;
   font-size: 14px;
 }
 .lastImg > img {
@@ -20023,6 +20177,7 @@ export default {
   height: 40px;
   line-height: 40px;
   position: relative;
+  background: #dae6f9;
 }
 
 .noWorksName.isWork {
@@ -22344,4 +22499,70 @@ ol {
   width: 100%;
   height: 100%;
 }
+
+.timeAndReply{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 14px;
+  box-sizing: border-box;
+  padding: 0 10px 10px 0px;
+}
+.timeAndReply .time {
+  color: #bfbfbf;
+  padding: 0 0 0 10px;
+  box-sizing: border-box;
+}
+.timeAndReply>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+
+.hfBox{
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.whoReplyWho{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: flex-start;
+}
+.hfBottom{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: space-between;
+  font-size: 14px;
+}
+.hfBottom>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+.whoReplyWho>.hfImg{
+  width: 12px;
+  height: 12px;
+  margin: 0 5px;
+}
+.whoReplyWho>.hfImg>img{
+  width: 100%;
+  height: 100%;
+}
+.hfContent{
+  padding-top: 10px;
+  box-sizing: border-box;
+}
+
+.hfTime{
+  text-align: left;
+  box-sizing: border-box;
+  padding: 10px 0 10px 0px;
+  color: #bfbfbf;
+  font-size: 14px;
+}
 </style>

+ 228 - 7
src/components/easy3/studyStudent.vue

@@ -243,16 +243,26 @@
               </div>
             </div>
             <div class="btnRight">
-              <div class="last" @click="nextOrpreSteps(0)">
+              <div class="last" @click="nextOrpreSteps(0)" @mouseover="isHovered = true"
+                @mouseout="isHovered = false">
                 <div class="lastImg">
-                  <img src="../../assets/icon/newIcons/last.png" alt="" />
+                  <img :src="
+                      isHovered
+                        ? require('../../assets/icon/newIcons/whiteLast.png')
+                        : require('../../assets/icon/newIcons/last.png')
+                    " alt="" />
                 </div>
                 <div class="lastText">上一步</div>
               </div>
-              <div class="last" @click="nextOrpreSteps(1)">
+              <div class="last" @click="nextOrpreSteps(1)" @mouseover="isHovered1 = true"
+                @mouseout="isHovered1 = false">
                 <div class="lastText">下一步</div>
                 <div class="lastImg">
-                  <img src="../../assets/icon/newIcons/next.png" alt="" />
+                  <img :src="
+                      isHovered1
+                        ? require('../../assets/icon/newIcons/whiteNext.png')
+                        : require('../../assets/icon/newIcons/next.png')
+                    " alt="" />
                 </div>
               </div>
               <!-- <div class="last" @click="juriVisible = true" v-if="tType == 1">
@@ -8853,8 +8863,30 @@
                 @click="previewImg(pz.content)"
               />
             </div>
-            <div class="time">
-              {{ pz.time }}
+            <div class="timeAndReply">
+              <div class="time">
+                {{ pz.time }}
+              </div>
+              <div @click="setReplyIndex(pz.id,pzIndex)">回复</div>
+            </div>
+            
+            <div v-if="pz.hfList && pz.hfList.length > 0" class="hfBox">
+              <div
+                v-for="(h, hIndex) in pz.hfList"
+                :key="hIndex"
+                class="hfItem"
+              >
+                <div class="whoReplyWho">
+                  <div class="hfName">{{ h.username }}</div>
+                  <div class="hfImg"><img src="../../assets/icon/newIcons/right.png" alt="" /></div>
+                  <div class="hfName">{{ pz.username }}</div>
+                </div>
+                <div class="hfContent" v-html="h.content"></div>
+                <div class="hfBottom">
+                  <div class="hfTime">{{ h.time }}</div>
+                  <div @click="deleteReply(h.id)" v-if="userid == h.userid">删除</div>
+                </div>
+              </div>
             </div>
           </div>
         </div>
@@ -8873,6 +8905,41 @@
         </div>
       </div>
     </div>
+    <div v-if="replyDialogVisible == true" class="addDialogCss" v-el-drag-dialog>
+      <div class="pzTop">
+        <div class="teacherPz">
+          <div class="teacherPzImg">
+            <img src="../../assets/icon/teacherPz.png" alt="" />
+          </div>
+          <div style="margin-left: 10px; height: 25px">添加回复</div>
+        </div>
+        <div @click="replyDialogVisible = false">
+          <img src="../../assets/close1.png" class="pzClose" alt="" />
+        </div>
+      </div>
+      <div class="addPzBox">
+        <!-- <div class="addPzCheck">
+          <span :class="{ isChooseActive: pzType == 1 }" @click="pzType = 1"
+            >文本</span
+          >
+          <span :class="{ isChooseActive: pzType == 2 }" @click="pzType = 2"
+            >音频</span
+          >
+        </div> -->
+        <div style="height: calc(100% - 95px)">
+          <editor-bar
+            class="binfo_input pzConText"
+            style="width: 100% !important"
+            placeholder="请输入回复描述"
+            v-model="reply"
+            @change="change"
+          ></editor-bar>
+        </div>
+        <div class="addTextCss" @click="addHf">
+          确定
+        </div>
+      </div>
+    </div>
     <div v-if="addPzDialog == true" class="addDialogCss" v-el-drag-dialog>
       <div class="pzTop">
         <div class="teacherPz">
@@ -11984,6 +12051,9 @@ export default {
       answerDialogVisible: false,
       juriVisible: false,
       timeDialogVisible: false,
+      replyDialogVisible: false,
+      replyIndex: 0,
+      replyPid: "",
       radio: [],
       isAsk: false,
       askJson: {
@@ -12014,6 +12084,8 @@ export default {
       workTypeB: false,
       workTypeC: false,
       isAnswer: false,
+      isHovered: false,
+      isHovered1: false,
       timer: null,
       opertimer: null,
       showType: 0,
@@ -15479,6 +15551,44 @@ export default {
           console.error(err);
         });
     },
+    setReplyIndex(id,i){
+      this.replyIndex = i;
+      this.replyPid = id;
+      this.replyDialogVisible = true;
+    },
+    addHf() {
+      if (this.reply == "") {
+        this.$message.error("回复不能为空!");
+        return;
+      }
+      let params = [
+        {
+          cid: this.id,
+          uid: this.userid,
+          s: this.courseType,
+          t: this.taskCount,
+          type: "1",
+          ct: 2,
+          pid: this.replyPid,
+          c: this.reply.replaceAll(/%/g, "%25"),
+        },
+      ];
+      this.ajax
+        .post(this.$store.state.api + "addHf", params)
+        .then((res) => {
+          this.reply = "";
+          this.$message({
+            message: "回复成功",
+            type: "success",
+          });
+          this.replyDialogVisible = false;
+          this.selectPz();
+        })
+        .catch((err) => {
+          this.$message.error("回复失败");
+          console.error(err);
+        });
+    },
     deletePz(id) {
       this.$confirm("确定删除此批注吗?", "提示", {
         confirmButtonText: "确定",
@@ -15507,6 +15617,34 @@ export default {
         })
         .catch(() => {});
     },
+    deleteReply(id){
+      this.$confirm("确定删除此回复吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deleteReply", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
     selectPz() {
       let params = {
         cid: this.id,
@@ -15519,6 +15657,17 @@ export default {
         .get(this.$store.state.api + "selectPzListType", params)
         .then((res) => {
           this.pzList = res.data[0];
+          var a = res.data[1];
+          for (var i = 0; i < a.length; i++) {
+            for (var j = 0; j < this.pzList.length; j++) {
+              if (!this.pzList[j].hfList) {
+                this.pzList[j].hfList = [];
+              }
+              if (a[i].pid == this.pzList[j].id) {
+                this.pzList[j].hfList.push(a[i]);
+              }
+            }
+          }
         })
         .catch((err) => {
           console.error(err);
@@ -19639,6 +19788,11 @@ export default {
   background: #3681fc;
   color: #fff;
 }
+.last:hover {
+  background: #3383fa !important;
+  color: #fff;
+  border: 1px solid #3383fa !important;
+}
 .last,
 .returnBtn1 {
   width: 90px;
@@ -19646,6 +19800,7 @@ export default {
   background: #ffffff;
   border-radius: 4px;
   border: 1px solid #0061ff;
+  color: #0061ff;
   cursor: pointer;
   display: flex;
   flex-direction: row;
@@ -19668,7 +19823,6 @@ export default {
 .lastText {
   padding: 0 5px 2px 5px;
   box-sizing: border-box;
-  color: #0061ff;
   font-size: 14px;
 }
 .lastImg > img {
@@ -19878,6 +20032,7 @@ export default {
   height: 40px;
   line-height: 40px;
   position: relative;
+  background: #dae6f9;
 }
 .noWorksName.isWork {
   background: #e7ebf1 !important;
@@ -22193,4 +22348,70 @@ ol {
   width: 100%;
   height: 100%;
 }
+
+.timeAndReply{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 14px;
+  box-sizing: border-box;
+  padding: 0 10px 10px 0px;
+}
+.timeAndReply .time {
+  color: #bfbfbf;
+  padding: 0 0 0 10px;
+  box-sizing: border-box;
+}
+.timeAndReply>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+
+.hfBox{
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.whoReplyWho{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: flex-start;
+}
+.hfBottom{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: space-between;
+  font-size: 14px;
+}
+.hfBottom>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+.whoReplyWho>.hfImg{
+  width: 12px;
+  height: 12px;
+  margin: 0 5px;
+}
+.whoReplyWho>.hfImg>img{
+  width: 100%;
+  height: 100%;
+}
+.hfContent{
+  padding-top: 10px;
+  box-sizing: border-box;
+}
+
+.hfTime{
+  text-align: left;
+  box-sizing: border-box;
+  padding: 10px 0 10px 0px;
+  color: #bfbfbf;
+  font-size: 14px;
+}
 </style>

+ 205 - 2
src/components/student/studyStudent.vue

@@ -692,8 +692,30 @@
             <div class="pzContent" v-if="pz.type == '3'">
               <img :src="pz.content" style="width: 90%; margin: 0 auto; display: block" @click="previewImg(pz.content)" />
             </div>
-            <div class="time">
-              {{ pz.time }}
+            <div class="timeAndReply">
+              <div class="time">
+                {{ pz.time }}
+              </div>
+              <div @click="setReplyIndex(pz.id,pzIndex)">回复</div>
+            </div>
+            
+            <div v-if="pz.hfList && pz.hfList.length > 0" class="hfBox">
+              <div
+                v-for="(h, hIndex) in pz.hfList"
+                :key="hIndex"
+                class="hfItem"
+              >
+                <div class="whoReplyWho">
+                  <div class="hfName">{{ h.username }}</div>
+                  <div class="hfImg"><img src="../../assets/icon/newIcons/right.png" alt="" /></div>
+                  <div class="hfName">{{ pz.username }}</div>
+                </div>
+                <div class="hfContent" v-html="h.content"></div>
+                <div class="hfBottom">
+                  <div class="hfTime">{{ h.time }}</div>
+                  <div @click="deleteReply(h.id)" v-if="userid == h.userid">删除</div>
+                </div>
+              </div>
             </div>
           </div>
         </div>
@@ -791,6 +813,41 @@
         </div>
       </div>
     </div>
+    <div v-if="replyDialogVisible == true" class="addDialogCss" v-el-drag-dialog>
+      <div class="pzTop">
+        <div class="teacherPz">
+          <div class="teacherPzImg">
+            <img src="../../assets/icon/teacherPz.png" alt="" />
+          </div>
+          <div style="margin-left: 10px; height: 25px">添加回复</div>
+        </div>
+        <div @click="replyDialogVisible = false">
+          <img src="../../assets/close1.png" class="pzClose" alt="" />
+        </div>
+      </div>
+      <div class="addPzBox">
+        <!-- <div class="addPzCheck">
+          <span :class="{ isChooseActive: pzType == 1 }" @click="pzType = 1"
+            >文本</span
+          >
+          <span :class="{ isChooseActive: pzType == 2 }" @click="pzType = 2"
+            >音频</span
+          >
+        </div> -->
+        <div style="height: calc(100% - 95px)">
+          <editor-bar
+            class="binfo_input pzConText"
+            style="width: 100% !important"
+            placeholder="请输入回复描述"
+            v-model="reply"
+            @change="change"
+          ></editor-bar>
+        </div>
+        <div class="addTextCss" @click="addHf">
+          确定
+        </div>
+      </div>
+    </div>
     <div v-if="addPzDialog == true" class="addDialogCss" v-el-drag-dialog>
       <div class="pzTop">
         <div class="teacherPz">
@@ -1136,6 +1193,9 @@ export default {
       answerDialogVisible: false,
       juriVisible: false,
       timeDialogVisible: false,
+      replyDialogVisible: false,
+      replyIndex: 0,
+      replyPid: "",
       radio: [],
       isAsk: false,
       askJson: {
@@ -1364,6 +1424,44 @@ export default {
           console.error(err);
         });
     },
+    setReplyIndex(id,i){
+      this.replyIndex = i;
+      this.replyPid = id;
+      this.replyDialogVisible = true;
+    },
+    addHf() {
+      if (this.reply == "") {
+        this.$message.error("回复不能为空!");
+        return;
+      }
+      let params = [
+        {
+          cid: this.id,
+          uid: this.userid,
+          s: this.courseType,
+          t: this.taskCount,
+          type: "1",
+          ct: 2,
+          pid: this.replyPid,
+          c: this.reply.replaceAll(/%/g, "%25"),
+        },
+      ];
+      this.ajax
+        .post(this.$store.state.api + "addHf", params)
+        .then((res) => {
+          this.reply = "";
+          this.$message({
+            message: "回复成功",
+            type: "success",
+          });
+          this.replyDialogVisible = false;
+          this.selectPz();
+        })
+        .catch((err) => {
+          this.$message.error("回复失败");
+          console.error(err);
+        });
+    },
     deletePz(id) {
       this.$confirm("确定删除此批注吗?", "提示", {
         confirmButtonText: "确定",
@@ -1392,6 +1490,34 @@ export default {
         })
         .catch(() => { });
     },
+    deleteReply(id){
+      this.$confirm("确定删除此回复吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deleteReply", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
     selectPz() {
       let params = {
         cid: this.id,
@@ -1404,6 +1530,17 @@ export default {
         .get(this.$store.state.api + "selectPzListType", params)
         .then((res) => {
           this.pzList = res.data[0];
+          var a = res.data[1];
+          for (var i = 0; i < a.length; i++) {
+            for (var j = 0; j < this.pzList.length; j++) {
+              if (!this.pzList[j].hfList) {
+                this.pzList[j].hfList = [];
+              }
+              if (a[i].pid == this.pzList[j].id) {
+                this.pzList[j].hfList.push(a[i]);
+              }
+            }
+          }
         })
         .catch((err) => {
           console.error(err);
@@ -6127,4 +6264,70 @@ ol {
 .selectBox>>>.el-input__icon {
   line-height: 30px;
 }
+
+.timeAndReply{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 14px;
+  box-sizing: border-box;
+  padding: 0 10px 10px 0px;
+}
+.timeAndReply .time {
+  color: #bfbfbf;
+  padding: 0 0 0 10px;
+  box-sizing: border-box;
+}
+.timeAndReply>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+
+.hfBox{
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.whoReplyWho{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: flex-start;
+}
+.hfBottom{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: space-between;
+  font-size: 14px;
+}
+.hfBottom>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+.whoReplyWho>.hfImg{
+  width: 12px;
+  height: 12px;
+  margin: 0 5px;
+}
+.whoReplyWho>.hfImg>img{
+  width: 100%;
+  height: 100%;
+}
+.hfContent{
+  padding-top: 10px;
+  box-sizing: border-box;
+}
+
+.hfTime{
+  text-align: left;
+  box-sizing: border-box;
+  padding: 10px 0 10px 0px;
+  color: #bfbfbf;
+  font-size: 14px;
+}
 </style>

+ 205 - 2
src/components/studio/studyStudent.vue

@@ -678,8 +678,30 @@
             <div class="pzContent" v-if="pz.type == '3'">
               <img :src="pz.content" style="width: 90%; margin: 0 auto; display: block" @click="previewImg(pz.content)" />
             </div>
-            <div class="time">
-              {{ pz.time }}
+            <div class="timeAndReply">
+              <div class="time">
+                {{ pz.time }}
+              </div>
+              <div @click="setReplyIndex(pz.id,pzIndex)">回复</div>
+            </div>
+            
+            <div v-if="pz.hfList && pz.hfList.length > 0" class="hfBox">
+              <div
+                v-for="(h, hIndex) in pz.hfList"
+                :key="hIndex"
+                class="hfItem"
+              >
+                <div class="whoReplyWho">
+                  <div class="hfName">{{ h.username }}</div>
+                  <div class="hfImg"><img src="../../assets/icon/newIcons/right.png" alt="" /></div>
+                  <div class="hfName">{{ pz.username }}</div>
+                </div>
+                <div class="hfContent" v-html="h.content"></div>
+                <div class="hfBottom">
+                  <div class="hfTime">{{ h.time }}</div>
+                  <div @click="deleteReply(h.id)" v-if="userid == h.userid">删除</div>
+                </div>
+              </div>
             </div>
           </div>
         </div>
@@ -777,6 +799,41 @@
         </div>
       </div>
     </div>
+    <div v-if="replyDialogVisible == true" class="addDialogCss" v-el-drag-dialog>
+      <div class="pzTop">
+        <div class="teacherPz">
+          <div class="teacherPzImg">
+            <img src="../../assets/icon/teacherPz.png" alt="" />
+          </div>
+          <div style="margin-left: 10px; height: 25px">添加回复</div>
+        </div>
+        <div @click="replyDialogVisible = false">
+          <img src="../../assets/close1.png" class="pzClose" alt="" />
+        </div>
+      </div>
+      <div class="addPzBox">
+        <!-- <div class="addPzCheck">
+          <span :class="{ isChooseActive: pzType == 1 }" @click="pzType = 1"
+            >文本</span
+          >
+          <span :class="{ isChooseActive: pzType == 2 }" @click="pzType = 2"
+            >音频</span
+          >
+        </div> -->
+        <div style="height: calc(100% - 95px)">
+          <editor-bar
+            class="binfo_input pzConText"
+            style="width: 100% !important"
+            placeholder="请输入回复描述"
+            v-model="reply"
+            @change="change"
+          ></editor-bar>
+        </div>
+        <div class="addTextCss" @click="addHf">
+          确定
+        </div>
+      </div>
+    </div>
     <div v-if="addPzDialog == true" class="addDialogCss" v-el-drag-dialog>
       <div class="pzTop">
         <div class="teacherPz">
@@ -1122,6 +1179,9 @@ export default {
       answerDialogVisible: false,
       juriVisible: false,
       timeDialogVisible: false,
+      replyDialogVisible: false,
+      replyIndex: 0,
+      replyPid: "",
       radio: [],
       isAsk: false,
       askJson: {
@@ -1350,6 +1410,44 @@ export default {
           console.error(err);
         });
     },
+    setReplyIndex(id,i){
+      this.replyIndex = i;
+      this.replyPid = id;
+      this.replyDialogVisible = true;
+    },
+    addHf() {
+      if (this.reply == "") {
+        this.$message.error("回复不能为空!");
+        return;
+      }
+      let params = [
+        {
+          cid: this.id,
+          uid: this.userid,
+          s: this.courseType,
+          t: this.taskCount,
+          type: "1",
+          ct: 2,
+          pid: this.replyPid,
+          c: this.reply.replaceAll(/%/g, "%25"),
+        },
+      ];
+      this.ajax
+        .post(this.$store.state.api + "addHf", params)
+        .then((res) => {
+          this.reply = "";
+          this.$message({
+            message: "回复成功",
+            type: "success",
+          });
+          this.replyDialogVisible = false;
+          this.selectPz();
+        })
+        .catch((err) => {
+          this.$message.error("回复失败");
+          console.error(err);
+        });
+    },
     deletePz(id) {
       this.$confirm("确定删除此批注吗?", "提示", {
         confirmButtonText: "确定",
@@ -1378,6 +1476,34 @@ export default {
         })
         .catch(() => { });
     },
+    deleteReply(id){
+      this.$confirm("确定删除此回复吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deleteReply", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
     selectPz() {
       let params = {
         cid: this.id,
@@ -1390,6 +1516,17 @@ export default {
         .get(this.$store.state.api + "selectPzListType", params)
         .then((res) => {
           this.pzList = res.data[0];
+          var a = res.data[1];
+          for (var i = 0; i < a.length; i++) {
+            for (var j = 0; j < this.pzList.length; j++) {
+              if (!this.pzList[j].hfList) {
+                this.pzList[j].hfList = [];
+              }
+              if (a[i].pid == this.pzList[j].id) {
+                this.pzList[j].hfList.push(a[i]);
+              }
+            }
+          }
         })
         .catch((err) => {
           console.error(err);
@@ -6012,4 +6149,70 @@ ol {
 .selectBox>>>.el-input__icon {
   line-height: 30px;
 }
+
+.timeAndReply{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 14px;
+  box-sizing: border-box;
+  padding: 0 10px 10px 0px;
+}
+.timeAndReply .time {
+  color: #bfbfbf;
+  padding: 0 0 0 10px;
+  box-sizing: border-box;
+}
+.timeAndReply>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+
+.hfBox{
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.whoReplyWho{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: flex-start;
+}
+.hfBottom{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: space-between;
+  font-size: 14px;
+}
+.hfBottom>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+.whoReplyWho>.hfImg{
+  width: 12px;
+  height: 12px;
+  margin: 0 5px;
+}
+.whoReplyWho>.hfImg>img{
+  width: 100%;
+  height: 100%;
+}
+.hfContent{
+  padding-top: 10px;
+  box-sizing: border-box;
+}
+
+.hfTime{
+  text-align: left;
+  box-sizing: border-box;
+  padding: 10px 0 10px 0px;
+  color: #bfbfbf;
+  font-size: 14px;
+}
 </style>

+ 338 - 13
src/components/studyStudent.vue

@@ -261,9 +261,18 @@
                 class="last"
                 @click="nextOrpreSteps(0)"
                 v-if="!(IsFollow && tType == 2)"
+                @mouseover="isHovered = true"
+                @mouseout="isHovered = false"
               >
                 <div class="lastImg">
-                  <img src="../assets/icon/newIcons/last.png" alt="" />
+                  <img
+                    :src="
+                      isHovered
+                        ? require('../assets/icon/newIcons/whiteLast.png')
+                        : require('../assets/icon/newIcons/last.png')
+                    "
+                    alt=""
+                  />
                 </div>
                 <div class="lastText">上一步</div>
               </div>
@@ -271,15 +280,37 @@
                 class="last"
                 @click="nextOrpreSteps(1)"
                 v-if="!(IsFollow && tType == 2)"
+                @mouseover="isHovered1 = true"
+                @mouseout="isHovered1 = false"
               >
                 <div class="lastText">下一步</div>
                 <div class="lastImg">
-                  <img src="../assets/icon/newIcons/next.png" alt="" />
+                  <img
+                    :src="
+                      isHovered1
+                        ? require('../assets/icon/newIcons/whiteNext.png')
+                        : require('../assets/icon/newIcons/next.png')
+                    "
+                    alt=""
+                  />
                 </div>
               </div>
-              <div class="last" @click="juriVisible = true" v-if="tType == 1">
+              <div
+                class="last"
+                @click="juriVisible = true"
+                v-if="tType == 1"
+                @mouseover="isHovered2 = true"
+                @mouseout="isHovered2 = false"
+              >
                 <div class="lastImg">
-                  <img src="../assets/icon/newIcons/lock.png" alt="" />
+                  <img
+                    :src="
+                      isHovered2
+                        ? require('../assets/icon/newIcons/whiteLock.png')
+                        : require('../assets/icon/newIcons/lock.png')
+                    "
+                    alt=""
+                  />
                 </div>
                 <div class="lastText">权限</div>
               </div>
@@ -1245,7 +1276,16 @@
                     </div>
                     <div class="tooldetail" v-if="tool.toolDetail != ''">
                       <!-- <div class="toolTitle">工具描述</div> -->
-                      <div v-html="contentConvent(tool.toolDetail)"></div>
+                      <div v-html="contentConvent(tool.toolDetail)" v-if="toolDetailIndex != toolIndex" @click.stop="updateToolDetail(toolIndex)"></div>
+                      <div v-else @click.stop="">
+                        <el-input
+                          type="textarea"
+                          :rows="3"
+                          resize="none"
+                          v-model="updateToolDetailInner"
+                          placeholder="请输入任务描述"
+                        ></el-input>
+                      </div>
                     </div>
                     <el-button
                       type="primary"
@@ -7536,9 +7576,38 @@
                 @click="previewImg(pz.content)"
               />
             </div>
-            <div class="time">
-              {{ pz.time }}
+            <div class="timeAndReply">
+              <div class="time">
+                {{ pz.time }}
+              </div>
+              <div @click="setReplyIndex(pz.id,pzIndex)">回复</div>
+            </div>
+            
+            <div v-if="pz.hfList && pz.hfList.length > 0" class="hfBox">
+              <div
+                v-for="(h, hIndex) in pz.hfList"
+                :key="hIndex"
+                class="hfItem"
+              >
+                <div class="whoReplyWho">
+                  <div class="hfName">{{ h.username }}</div>
+                  <div class="hfImg"><img src="../assets/icon/newIcons/right.png" alt="" /></div>
+                  <div class="hfName">{{ pz.username }}</div>
+                </div>
+                <div class="hfContent" v-html="h.content"></div>
+                <div class="hfBottom">
+                  <div class="hfTime">{{ h.time }}</div>
+                  <div @click="deleteReply(h.id)" v-if="userid == h.userid">删除</div>
+                </div>
+              </div>
             </div>
+
+            <!-- <div class="replyBox" v-if="replyIndex[pzIndex] && replyIndex[pzIndex] == true">
+              <div class="replyInput">
+                <el-input v-model="reply[pzIndex]"></el-input>
+              </div>
+              <el-button @click="addHf(pz.id, pzIndex)">回复</el-button>
+            </div> -->
           </div>
         </div>
         <div class="noPz" v-else>
@@ -7556,6 +7625,41 @@
         </div>
       </div>
     </div>
+    <div v-if="replyDialogVisible == true" class="addDialogCss" v-el-drag-dialog>
+      <div class="pzTop">
+        <div class="teacherPz">
+          <div class="teacherPzImg">
+            <img src="../assets/icon/teacherPz.png" alt="" />
+          </div>
+          <div style="margin-left: 10px; height: 25px">添加回复</div>
+        </div>
+        <div @click="replyDialogVisible = false">
+          <img src="../assets/close1.png" class="pzClose" alt="" />
+        </div>
+      </div>
+      <div class="addPzBox">
+        <!-- <div class="addPzCheck">
+          <span :class="{ isChooseActive: pzType == 1 }" @click="pzType = 1"
+            >文本</span
+          >
+          <span :class="{ isChooseActive: pzType == 2 }" @click="pzType = 2"
+            >音频</span
+          >
+        </div> -->
+        <div style="height: calc(100% - 95px)">
+          <editor-bar
+            class="binfo_input pzConText"
+            style="width: 100% !important"
+            placeholder="请输入回复描述"
+            v-model="reply"
+            @change="change"
+          ></editor-bar>
+        </div>
+        <div class="addTextCss" @click="addHf">
+          确定
+        </div>
+      </div>
+    </div>
     <div v-if="addPzDialog == true" class="addDialogCss" v-el-drag-dialog>
       <div class="pzTop">
         <div class="teacherPz">
@@ -10611,6 +10715,7 @@ export default {
       likes: require("../assets/icon/comment/likes.png"),
       scoreImg: require("../assets/score.png"),
       courseDetail: {},
+      reply: "",
       isSelect: false,
       chapInfo: [],
       chapInfoList: [],
@@ -10717,6 +10822,9 @@ export default {
       answerDialogVisibleTeacher: false,
       juriVisible: false,
       timeDialogVisible: false,
+      replyDialogVisible: false,
+      replyIndex: 0,
+      replyPid: "",
       radio: [],
       isAsk: false,
       askJson: {
@@ -10740,10 +10848,14 @@ export default {
       isWorksS: [],
       noWorksStudent: [],
       toolindex: 0,
+      toolDetailIndex:null,
       groupIndex: 0,
       workTypeB: false,
       workTypeC: false,
       isAnswer: false,
+      isHovered: false,
+      isHovered1: false,
+      isHovered2: false,
       timer: null,
       opertimer: null,
       showType: 0,
@@ -10807,6 +10919,8 @@ export default {
       checktoolArray: [],
       vChapterData: [],
       isUpdateToolDetail: false,
+      isUpdateToolDetail1: false,
+      updateToolDetailInner: "",
       checkboxList: [],
       plIndex: "",
       worksSName2: "",
@@ -10880,6 +10994,47 @@ export default {
           document.querySelector(".student_body").offsetTop;
       }, 500);
     },
+    updateToolDetail(i){
+      this.toolDetailIndex = i;
+      if (!this.isUpdateToolDetail1) {
+        this.isUpdateToolDetail1 = true;
+        this.updateToolDetailInner = JSON.parse(
+          JSON.stringify(this.chapInfoList[this.courseType].chapterInfo[0].taskJson[
+          this.taskCount
+        ].toolChoose[i].toolDetail)
+        );
+      } else {
+        this.chapInfoList[this.courseType].chapterInfo[0].taskJson[
+          this.taskCount
+        ].toolChoose[i].toolDetail = JSON.parse(
+          JSON.stringify(this.updateToolDetailInner)
+        );
+        let params = [
+          {
+            cid: this.id,
+            chapters: JSON.stringify(this.chapInfoList),
+            uid: this.userid,
+            unitIndex: this.courseType,
+          },
+        ];
+        this.ajax
+          .post(this.$store.state.api + "updateWorkNew4", params)
+          .then((res) => {
+            this.isUpdateToolDetail1 = false;
+            this.$message({
+              message: "修改成功",
+              type: "success",
+            });
+            this.toolDetailIndex = null;
+            this.updateToolDetailInner = "";
+            this.getCourseDetail(2);
+            this.$forceUpdate();
+          })
+          .catch((err) => {
+            console.error(err);
+          });
+      }
+    },
     jumpGj(i, j, k, l) {
       for (var z = 0; z < this.navList.length; z++) {
         for (var q = 0; q < this.navList[z].task.length; q++) {
@@ -14862,6 +15017,44 @@ export default {
           console.error(err);
         });
     },
+    setReplyIndex(id,i){
+      this.replyIndex = i;
+      this.replyPid = id;
+      this.replyDialogVisible = true;
+    },
+    addHf() {
+      if (this.reply == "") {
+        this.$message.error("回复不能为空!");
+        return;
+      }
+      let params = [
+        {
+          cid: this.id,
+          uid: this.userid,
+          s: this.courseType,
+          t: this.taskCount,
+          type: "1",
+          ct: 2,
+          pid: this.replyPid,
+          c: this.reply.replaceAll(/%/g, "%25"),
+        },
+      ];
+      this.ajax
+        .post(this.$store.state.api + "addHf", params)
+        .then((res) => {
+          this.reply = "";
+          this.$message({
+            message: "回复成功",
+            type: "success",
+          });
+          this.replyDialogVisible = false;
+          this.selectPz();
+        })
+        .catch((err) => {
+          this.$message.error("回复失败");
+          console.error(err);
+        });
+    },
     deletePz(id) {
       this.$confirm("确定删除此批注吗?", "提示", {
         confirmButtonText: "确定",
@@ -14890,6 +15083,34 @@ export default {
         })
         .catch(() => {});
     },
+    deleteReply(id){
+      this.$confirm("确定删除此回复吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          let params = [
+            {
+              id: id,
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "deleteReply", params)
+            .then((res) => {
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+              this.selectPz();
+            })
+            .catch((err) => {
+              this.$message.error("网络异常");
+              console.error(err);
+            });
+        })
+        .catch(() => {});
+    },
     setPz() {
       if (this.ispzType == 4) {
         this.ispzType = 0;
@@ -14912,11 +15133,47 @@ export default {
         .get(this.$store.state.api + "selectPzListType", params)
         .then((res) => {
           this.pzList = res.data[0];
+          var a = res.data[1];
+          for (var i = 0; i < a.length; i++) {
+            for (var j = 0; j < this.pzList.length; j++) {
+              if (!this.pzList[j].hfList) {
+                this.pzList[j].hfList = [];
+              }
+              if (a[i].pid == this.pzList[j].id) {
+                this.pzList[j].hfList.push(a[i]);
+              }
+            }
+          }
         })
         .catch((err) => {
           console.error(err);
         });
     },
+    // selectHf() {
+    //   let params = {
+    //     cid: this.id,
+    //     s: this.courseType,
+    //     t: this.taskCount,
+    //   };
+    //   this.ajax
+    //     .get(this.$store.state.api + "selectHfList", params)
+    //     .then((res) => {
+    //       var a = res.data[0];
+    //       for (var i = 0; i < a.length; i++) {
+    //         for (var j = 0; j < this.pzList.length; j++) {
+    //           if (!this.pzList[i].hfList) {
+    //             this.pzList[i].hfList = [];
+    //           }
+    //           if (a[i].pid == this.pzList[j].id) {
+    //             this.pzList[i].hfList.push(a[i]);
+    //           }
+    //         }
+    //       }
+    //     })
+    //     .catch((err) => {
+    //       console.error(err);
+    //     });
+    // },
     updateSLook() {
       let params = {
         sopen: this.sIsOpen == false ? 1 : 2,
@@ -17412,6 +17669,11 @@ export default {
     },
   },
   mounted() {
+    document.body.addEventListener("click", (e) => {
+      if (this.isUpdateToolDetail1) {
+        this.updateToolDetail(this.toolDetailIndex);
+      }
+    });
     if (this.screenType == 2) {
       window.parent.postMessage({ allScreen: 4 }, "*");
     } else if (this.screenType == 3) {
@@ -18985,6 +19247,11 @@ export default {
   background: #3681fc;
   color: #fff;
 }
+.last:hover {
+  background: #3383fa !important;
+  color: #fff;
+  border: 1px solid #3383fa !important;
+}
 .last,
 .returnBtn1 {
   width: 90px;
@@ -18992,6 +19259,7 @@ export default {
   background: #ffffff;
   border-radius: 4px;
   border: 1px solid #0061ff;
+  color: #0061ff;
   cursor: pointer;
   display: flex;
   flex-direction: row;
@@ -19014,7 +19282,6 @@ export default {
 .lastText {
   padding: 0 5px 2px 5px;
   box-sizing: border-box;
-  color: #0061ff;
   font-size: 14px;
 }
 .lastImg > img {
@@ -19164,6 +19431,7 @@ export default {
   height: 40px;
   line-height: 40px;
   position: relative;
+  background: #dae6f9;
 }
 
 .isWorksName {
@@ -20312,13 +20580,24 @@ export default {
   width: 100%;
   height: 100%;
 }
-
-.pzList .time {
-  text-align: right;
+.timeAndReply{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 14px;
   box-sizing: border-box;
   padding: 0 10px 10px 0px;
-  color: #949494;
-  font-size: 14px;
+}
+.timeAndReply .time {
+  color: #bfbfbf;
+  padding: 0 0 0 10px;
+  box-sizing: border-box;
+}
+.timeAndReply>div:last-child{
+  cursor: pointer;
+  color: #777;
 }
 
 /* table 样式 */
@@ -21413,4 +21692,50 @@ ol {
   line-height: 25px;
   margin-right: 5px;
 }
+
+.hfBox{
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.whoReplyWho{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: flex-start;
+}
+.hfBottom{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  align-items: baseline;
+  justify-content: space-between;
+  font-size: 14px;
+}
+.hfBottom>div:last-child{
+  cursor: pointer;
+  color: #777;
+}
+.whoReplyWho>.hfImg{
+  width: 12px;
+  height: 12px;
+  margin: 0 5px;
+}
+.whoReplyWho>.hfImg>img{
+  width: 100%;
+  height: 100%;
+}
+.hfContent{
+  padding-top: 10px;
+  box-sizing: border-box;
+}
+
+.hfTime{
+  text-align: left;
+  box-sizing: border-box;
+  padding: 10px 0 10px 0px;
+  color: #bfbfbf;
+  font-size: 14px;
+}
 </style>