From 5f00696dfb25bc90034448ceb634ed1ef256681a Mon Sep 17 00:00:00 2001
From: qiyunfeng-create <1940665526@qq.com>
Date: 星期四, 21 八月 2025 21:13:35 +0800
Subject: [PATCH] Merge branch 'master' of http://182.92.203.7:2001/r/xiehe_website

---
 src/views/classManage/classHome.vue |  778 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 778 insertions(+), 0 deletions(-)

diff --git a/src/views/classManage/classHome.vue b/src/views/classManage/classHome.vue
new file mode 100644
index 0000000..762b46d
--- /dev/null
+++ b/src/views/classManage/classHome.vue
@@ -0,0 +1,778 @@
+<template>
+  <div class="classManagePage-box">
+    <div class="classManagePage-nav" v-if="classInfo">
+      <el-breadcrumb :separator-icon="ArrowRight">
+        <el-breadcrumb-item>鎴戠殑鐝骇</el-breadcrumb-item>
+        <el-breadcrumb-item>{{ classInfo?.name }}</el-breadcrumb-item>
+        <el-breadcrumb-item>鐝骇棣栭〉</el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <div class="classManagePage-content">
+      <div class="content-left fl">
+        <div class="classOverview mainBorder">
+          <div class="">
+            <div class="title mainbg">鐝骇姒傝</div>
+          </div>
+          <div class="bodyBox" v-if="currentClass?.name && !classLoading">
+            <div class="classInfo">
+              <div class="name">{{ currentClass?.name }}</div>
+              <!-- <div class="time">鎶ュ悕鏃堕棿:2024.7.30--2024-8.03</div> -->
+              <div class="time">寮�璇炬椂闂�: {{ currentClass?.classTime }}</div>
+            </div>
+            <div class="line"></div>
+            <div class="classInfoBox">
+              <div class="iconBox">
+                <img :src="currentClass?.bookIcon ? currentClass?.bookIcon : defaultImg" />
+              </div>
+              <div class="infoBox">
+                <div class="main">{{ currentClass?.bookName }}</div>
+                <div class="job">浣滆�咃細{{ classInfo?.author ?? '-' }}</div>
+                <div class="job">ISBN锛歿{ classInfo?.isbn ?? '-' }}</div>
+              </div>
+            </div>
+            <div class="line"></div>
+            <div class="classInfo">
+              <div class="name">鐝骇浜烘暟</div>
+              <div class="con">
+                <span class="main">{{ currentClass?.memberCount }}</span
+                >/{{ currentClass?.maxUserCount }}
+              </div>
+            </div>
+            <div class="line"></div>
+            <div class="classInfo">
+              <div class="name">浣滀笟娆℃暟</div>
+              <div class="con">
+                <span class="main">{{ homeworkCount }}</span>
+              </div>
+            </div>
+            <!-- <div class="line"></div>
+            <div class="classInfo">
+              <div class="name">鏁欏杩涘害</div>
+              <div class="con"><span class="main">0</span>/0</div>
+            </div> -->
+          </div>
+          <div
+            class="bodyBox"
+            style="display: flex; justify-content: center; align-items: center"
+            v-if="classLoading"
+          >
+            <div v-loading="classLoading"></div>
+          </div>
+          <div v-if="!currentClass && !classLoading">
+            <el-empty style="padding: 0" :image-size="100" />
+          </div>
+        </div>
+        <div class="classNotice">
+          <div class="titleBox">
+            <div class="border mainbg"></div>
+            <div class="title">
+              <span>鐝骇閫氱煡</span>
+              <el-icon
+                style="cursor: pointer"
+                color="#FF6D00"
+                v-if="noticeList.length > 0 && userInfo.role == 'Teacher'"
+                @click="toInfo"
+              >
+                <ArrowRightBold />
+              </el-icon>
+            </div>
+          </div>
+          <div class="noticeList" v-if="noticeList.length > 0 && !noticeLoading">
+            <div class="noticeItem" v-for="(item, index) in noticeList" :key="index">
+              <div class="noticeContent">
+                <span class="title">{{ item.name }}锛�</span>
+                <div class="contentText">{{ item.content }}</div>
+              </div>
+              <span class="time">{{ item.createDate }}</span>
+            </div>
+          </div>
+          <div v-if="noticeLoading" v-loading="noticeLoading"></div>
+          <div v-if="noticeList.length == 0 && !noticeLoading" class="notBox">
+            <el-empty :image-size="100" />
+          </div>
+        </div>
+        <div class="classTalk">
+          <div class="titleBox">
+            <div class="border mainbg"></div>
+            <div class="title">
+              <span>鐝粍璇濋</span>
+              <el-icon
+                style="cursor: pointer"
+                color="#FF6D00"
+                v-if="messageList.length > 0"
+                @click="toTalk"
+              >
+                <ArrowRightBold />
+              </el-icon>
+            </div>
+          </div>
+          <div class="noticeList" v-if="messageList.length > 0 && !messageLoading">
+            <div class="noticeItem" v-for="(item, index) in messageList" :key="index">
+              <div class="noticeContent">
+                <span class="title">{{ item.name }}</span>
+                <div class="content" v-if="item.publicText">
+                  <span>{{ item.publicText.publishRole }}锛�</span>
+                  <span>{{ item.publicText.publisher }}</span>
+                </div>
+                <span>鏈�杩戝洖澶嶏細{{ item.updateDate }}</span>
+              </div>
+              <span class="time">{{ item.createDate }}</span>
+            </div>
+          </div>
+          <div v-if="messageLoading" v-loading="messageLoading"></div>
+          <div v-if="messageList.length == 0 && !messageLoading" class="notBox">
+            <el-empty :image-size="100" />
+          </div>
+        </div>
+        <div class="classTask">
+          <div class="titleBox" style="margin-bottom: 5px">
+            <div class="border mainbg"></div>
+            <div class="title">
+              <span>鐝骇浣滀笟姒傝</span>
+              <!-- <el-icon
+                style="cursor: pointer"
+                color="#FF6D00"
+                v-if="tableData.length > 0"
+                @click="toWorkList"
+              >
+                <ArrowRightBold />
+              </el-icon> -->
+            </div>
+          </div>
+          <div class="tableWall">
+            <el-table :data="tableData" border style="width: 100%; font-size: 14px" size="small">
+              <el-table-column prop="name" label="鍚嶇О" />
+              <el-table-column prop="beginDate" label="寮�濮嬫椂闂�" />
+              <el-table-column prop="endDate" label="鎴鏃堕棿" />
+              <el-table-column prop="submitCount" label="瀹屾垚鎯呭喌(鎻愪氦浜烘暟)" width="180" />
+            </el-table>
+          </div>
+        </div>
+        <!-- <div class="classTask">
+          <div class="titleBox" style="margin-bottom: 5px">
+            <div class="border mainbg"></div>
+            <div class="title">
+              <span>鏁欏浜掑姩</span>
+              <el-icon
+                style="cursor: pointer"
+                color="#FF6D00"
+                v-if="tableData.length > 0"
+                @click="toTeaching"
+              >
+                <ArrowRightBold />
+              </el-icon>
+            </div>
+          </div>
+          <div class="tableWall">
+            <el-table :data="[]" border style="width: 100%; font-size: 14px" size="small">
+              <el-table-column prop="index" label="搴忓彿" />
+              <el-table-column prop="name" label="鏍囬" />
+              <el-table-column prop="beginDate" label="浜掑姩瀛︾敓鏁�(宸蹭簰鍔�/鍏ㄩ儴瀛︾敓)" />
+              <el-table-column prop="endDate" label="鏈�鍚庢彁浜ゆ椂闂�" />
+            </el-table>
+          </div>
+        </div> -->
+      </div>
+      <div class="content-right fr">
+        <div class="assistant">
+          <div class="titleBox">
+            <div class="border mainbg"></div>
+            <div class="title">鍔╂暀鍒楄〃</div>
+            <div class="options">
+              <!-- <div class="optionsItem">绉婚櫎</div> -->
+              <div class="copyIdBtn" @click="copy(currentClass)">澶嶅埗閭�璇风爜</div>
+            </div>
+          </div>
+          <div class="avatarList" style="max-height: 147px; overflow-y: auto">
+            <div class="avatarItem" v-for="(item, index) in teacherList" :key="index">
+              <el-avatar v-if="item.appUser?.icon" :size="35" :src="item.appUser?.icon" />
+              <el-avatar v-else :size="35" :icon="UserFilled" />
+              <el-tooltip :content="item.appUser?.name" placement="top" effect="light">
+                <span class="userName">{{ item.appUser?.name }}</span>
+              </el-tooltip>
+            </div>
+            <div class="nullBox" v-if="!Sloading && teacherList.length == 0">
+              <el-empty :image-size="100" />
+            </div>
+          </div>
+        </div>
+        <div class="student">
+          <div class="titleBox">
+            <div class="border mainbg"></div>
+            <div class="title">瀛︾敓鍒楄〃</div>
+            <div class="options">
+              <div class="copyIdBtn" @click="copy(currentClass)">澶嶅埗閭�璇风爜</div>
+            </div>
+          </div>
+          <div class="avatarList" style="max-height: 570px; overflow-y: auto">
+            <div class="avatarItem02" v-for="(item, index) in studentList" :key="index">
+              <el-avatar v-if="item.appUser?.icon" :size="35" :src="item.appUser?.icon" />
+              <el-avatar v-else :size="35" :icon="UserFilled" />
+              <el-tooltip :content="item.appUser?.name" placement="top" effect="light">
+                <span class="userName">{{ item.appUser?.name }}</span>
+              </el-tooltip>
+            </div>
+            <div class="nullBox" v-if="!Sloading && studentList.length == 0">
+              <el-empty :image-size="100" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { useRoute, useRouter } from 'vue-router'
+import { getPublicImage } from '@/assets/js/middleGround/tool.js'
+import useClipboard from 'vue-clipboard3'
+import { inject, onMounted, ref } from 'vue'
+import moment from 'moment'
+import { ElMessage } from 'element-plus'
+import { ArrowRight, UserFilled } from '@element-plus/icons-vue'
+import defaultImg from '@/assets/images/default-book-img.png'
+
+const { toClipboard } = useClipboard()
+const route: any = useRoute()
+const router: any = useRouter()
+const classInfo = JSON.parse(route.query.classInfo)
+const MG: any = inject('MG')
+const config: any = inject('config')
+const userInfo: any = ref()
+
+const currentClass = ref()
+const classLoading = ref(true)
+const messageTopicInfo = ref()
+const talkTopicInfo = ref()
+const noticeList: any = ref([])
+const noticeLoading = ref(true)
+const messageList: any = ref([])
+const messageLoading = ref(true)
+const tableData: any = ref([])
+const homeworkCount = ref(0)
+const studentList: any = ref([])
+const teacherList: any = ref([])
+const Sloading = ref(false)
+
+onMounted(() => {
+  const userCache: any = localStorage.getItem(config.userInfoKey)
+  if (userCache) {
+    userInfo.value = JSON.parse(userCache)
+  }
+  getData()
+  getStudentList()
+  getTaskList()
+})
+
+// 澶嶅埗
+const copy = async (val: any) => {
+  try {
+    await toClipboard(val.refCode)
+    ElMessage({
+      message: '澶嶅埗鎴愬姛',
+      type: 'success'
+    })
+  } catch (e) {
+    console.error(e)
+  }
+}
+
+// 鑾峰彇鐝骇
+const getData = () => {
+  MG.edu
+    .getCourseClass({
+      ClassIdOrRefCode: String(classInfo.id)
+    })
+    .then((res: any) => {
+      if (res) {
+        res.bookName = res.linkProductDto.product.name
+        res.bookIcon = getPublicImage(res.linkProductDto.product.icon, 100)
+        res.classTime =
+          moment(res.beginDate).format('YYYY.MM.DD') +
+          '--' +
+          moment(res.endDate).format('YYYY.MM.DD')
+      }
+      currentClass.value = res
+      classLoading.value = false
+      getTopicInfo()
+    })
+}
+
+// 鑾峰彇topic
+const getTopicInfo = () => {
+  const pramas = {
+    classId: classInfo.id,
+    refCodes: [config.refCodes.message, config.refCodes.talk]
+  }
+  MG.edu.getClassTopic(pramas).then((res: any) => {
+    const list = res
+    messageTopicInfo.value = list.find((item: any) => item.refCode == config.refCodes.message)
+    if (messageTopicInfo.value.id) {
+      sessionStorage.messageId = messageTopicInfo.value.id
+      noticeLoading.value = true
+      getNotice()
+    }
+    talkTopicInfo.value = list.find((item: any) => item.refCode == config.refCodes.talk)
+    if (talkTopicInfo.value.id) {
+      sessionStorage.talkId = talkTopicInfo.value.id
+      messageLoading.value = true
+      getMessage()
+    }
+  })
+}
+
+// 鑾峰彇鐝骇閫氱煡
+const getNotice = () => {
+  const data = {
+    start: 0,
+    size: 3,
+    appRefCode: config.appRefCode,
+    topicIdOrRefCode: String(messageTopicInfo.value.id),
+    sort: {
+      type: 'Desc',
+      field: 'CreateDate',
+      subSorts: []
+    }
+  }
+  MG.ugc.getTopicMessageList(data).then((res: any) => {
+    noticeLoading.value = false
+    const list = res.datas
+    noticeList.value = list.map((item: any) => {
+      return {
+        ...item,
+        createDate: moment(item.createDate).format('YYYY-MM-DD')
+      }
+    })
+  })
+}
+
+// 鑾峰彇鐝骇璇濋
+const getMessage = () => {
+  const data = {
+    start: 0,
+    size: 3,
+    appRefCode: config.appRefCode,
+    topicIdOrRefCode: String(talkTopicInfo.value.id),
+    sort: {
+      type: 'Desc',
+      field: 'CreateDate',
+      subSorts: []
+    }
+  }
+  MG.ugc.getTopicMessageList(data).then((res: any) => {
+    messageLoading.value = false
+    const list = res.datas
+    messageList.value = list.map((item: any, i: number) => {
+      const str = item.content.indexOf('publisher')
+      if (str > -1) {
+        item.publicText = JSON.parse(item.content)
+        if (item.publicText && item.publicText.publishRole) {
+          item.publicText.publishRole = item.publicText.publishRole == 'Teacher' ? '鍔╂暀' : '瀛︾敓'
+        }
+      }
+      return {
+        ...item,
+        index: i + 1,
+        createDate: moment(item.createDate).format('YYYY-MM-DD HH:mm:ss'),
+        updateDate: moment(item.updateDate).format('YYYY-MM-DD HH:mm:ss')
+      }
+    })
+  })
+}
+
+// 鑾峰彇鏁欏笀/瀛︾敓鍒楄〃
+const getStudentList = () => {
+  Sloading.value = true
+  const data = {
+    start: 0,
+    size: 999,
+    groupId: classInfo.id,
+    filterList: [
+      {
+        value: 'Normal',
+        field: 'State',
+        subFilters: []
+      }
+    ]
+  }
+  MG.identity.getGroupUserList(data).then((res: any) => {
+    const { datas } = res
+    Sloading.value = false
+    let list: any = []
+    if (datas.length > 0) {
+      list = datas.map((item: any, index: number) => {
+        if (item.linkType == 'Creator') {
+          const userInfo = item.appUser?.infoList?.find((citem: any) => citem.type == 'teacherInfo')
+          item.appUser.name = userInfo.name
+          item.appUser.icon = userInfo.icon
+          if (userInfo?.data) {
+            const iconData = JSON.parse(userInfo.data)
+            item.appUser.icon = getPublicImage(iconData?.relevantCertificates[0]?.md5, 100) ?? ''
+          }
+        }
+        if (item.linkType == 'RefCode' || item.linkType == 'Teacher') {
+          let userInfo = null
+          const wechatData = item.appUser?.infoList?.find((citem: any) => citem.type == 'WeChat')
+          const defaultData = item.appUser?.infoList?.find((citem: any) => citem.type == 'Default')
+          userInfo = defaultData
+          if (wechatData?.name) {
+            userInfo = wechatData
+          }
+          item.appUser.name = userInfo.name
+          item.appUser.icon = userInfo.icon
+        }
+        return {
+          ...item,
+          index: index + 1,
+          createDate: moment(item.createDate).format('YYYY-MM-DD')
+        }
+      })
+    }
+    teacherList.value = list.filter((item: any) => item.linkType != 'RefCode')
+    studentList.value = list.filter((item: any) => item.linkType == 'RefCode')
+  })
+}
+
+// 鍓嶅線璇濋
+const toTalk = () => {
+  classInfo.index = 5
+  if (userInfo.value?.role != 'Teacher') {
+    classInfo.index = 3
+  }
+  router.push({
+    path: '/talkingPoint',
+    query: {
+      classInfo: JSON.stringify(classInfo)
+    }
+  })
+}
+
+// 鍓嶅線閫氱煡
+const toInfo = () => {
+  classInfo.index = 0
+  router.push({
+    path: '/info',
+    query: {
+      classInfo: JSON.stringify(classInfo)
+    }
+  })
+}
+
+// 鏁欏浜掑姩
+const toTeaching = () => {}
+
+// 鐝骇浣滀笟姒傝
+const getTaskList = () => {
+  const data = {
+    start: 0,
+    size: 3,
+    sort: {
+      type: 'Desc',
+      field: 'CreateDate',
+      subSorts: []
+    },
+    filterList: [
+      // {
+      //   value: 'Normal',
+      //   field: 'State',
+      //   subFilters: []
+      // },
+      {
+        value: config.taskType.homeWork,
+        field: 'Type',
+        subFilters: []
+      }
+    ],
+    groupId: classInfo?.id
+  }
+  MG.edu
+    .getTaskList(data)
+    .then((res: any) => {
+      let list: any = []
+      if (res.datas.length > 0) {
+        list = res.datas
+          ?.map((item: any) => {
+            return {
+              ...item,
+              beginDate: moment(item.beginDate).format('YYYY-MM-DD'),
+              endDate: moment(item.endDate).format('YYYY-MM-DD')
+            }
+          })
+          .slice(0, 3)
+      }
+      tableData.value = list
+      homeworkCount.value = res.totalSize
+    })
+    .catch((e: any) => {
+      console.log(e)
+    })
+}
+</script>
+
+<style lang="less" scoped>
+.nullBox {
+  width: 100%;
+  display: flex;
+  justify-content: center;
+}
+.classManagePage-box {
+  padding: 20px;
+  .classManagePage-nav {
+    padding-bottom: 20px;
+    border-bottom: 1px solid #e6e8ed;
+  }
+  .classManagePage-content {
+    display: flex;
+    justify-content: space-between;
+    .content-left {
+      width: 70%;
+      min-width: 950px;
+      .classOverview {
+        height: 190px;
+        margin-top: 30px;
+        border-radius: 10px;
+        .title {
+          width: 80px;
+          text-align: center;
+          padding: 7px;
+          border-radius: 8px 0 8px 0;
+        }
+        .bodyBox {
+          display: flex;
+          justify-content: space-between;
+          margin-top: 20px;
+          padding: 0 20px;
+          .classInfoBox {
+            padding: 0 20px;
+            display: flex;
+            .iconBox {
+              width: 90px;
+              height: 120px;
+              img {
+                width: 100%;
+                height: 100%;
+                object-fit: contain;
+              }
+            }
+            .infoBox {
+              flex: 1;
+              padding-left: 10px;
+              .main {
+                font-size: 16px;
+                line-height: 20px;
+              }
+              .job {
+                // padding:10px;
+                margin-top: 20px;
+              }
+            }
+          }
+          .line {
+            width: 1px;
+            height: 130px;
+            background: linear-gradient(
+              180deg,
+              rgba(255, 255, 255, 0) 0%,
+              #b7b7b7 51%,
+              rgba(255, 255, 255, 0) 100%
+            );
+          }
+          .classInfo {
+            padding: 0 20px;
+            font-size: 16px;
+            min-width: 120px;
+            .name {
+              font-weight: bold;
+              margin-bottom: 20px;
+              text-align: center;
+            }
+            .con {
+              margin-top: 40px;
+              font-size: 22px;
+              text-align: center;
+            }
+            .time {
+              line-height: 30px;
+            }
+          }
+        }
+      }
+      .classNotice {
+        height: 200px;
+        margin-top: 20px;
+        border-radius: 20px;
+        background: linear-gradient(180deg, #fffcf1 0%, #ffffff 100%);
+        border: 1px solid rgba(249, 200, 35, 0.2);
+      }
+      .classTalk {
+        height: 200px;
+        margin-top: 20px;
+        border-radius: 20px;
+        background: linear-gradient(180deg, #edf0ff 0%, #ffffff 100%);
+        border: 1px solid rgba(154, 171, 251, 0.2);
+      }
+      .classTask {
+        min-height: 200px;
+        margin-top: 20px;
+        border-radius: 20px;
+        border: 1px solid #e8ebf5;
+        .tableWall {
+          width: 100%;
+          padding: 10px 5px;
+          box-sizing: border-box;
+        }
+      }
+      .titleBox {
+        display: flex;
+        align-items: center;
+        margin: 20px 0;
+        font-size: 16px;
+        .title {
+          width: 100%;
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          padding-right: 10px;
+        }
+        .border {
+          width: 4px;
+          height: 23px;
+          border-radius: 0px 10px 10px 0px;
+          margin-right: 10px;
+        }
+      }
+    }
+    .content-right {
+      width: 28%;
+      margin-left: 20px;
+      min-width: 270px;
+
+      .assistant {
+        min-height: 160px;
+        margin-top: 30px;
+        border-radius: 10px;
+        border: 1px solid #e8ebf5;
+        overflow: hidden;
+      }
+      .student {
+        height: 640px;
+        margin-top: 20px;
+        border-radius: 10px;
+        border: 1px solid #e8ebf5;
+        overflow: hidden;
+      }
+      .titleBox {
+        display: flex;
+        align-items: center;
+        margin: 10px 0;
+        .border {
+          width: 4px;
+          height: 23px;
+          border-radius: 0px 10px 10px 0px;
+          margin-right: 10px;
+        }
+      }
+    }
+    .notBox {
+      width: 100%;
+      height: 100px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+  .options {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    padding-right: 10px;
+    .optionsItem {
+      color: #999;
+      margin-right: 10px;
+      cursor: pointer;
+    }
+    .copyIdBtn {
+      background-color: #fff;
+      color: #3b93fe;
+      padding: 0 6px;
+      border-radius: 50px;
+      overflow: hidden;
+      cursor: pointer;
+    }
+  }
+  .avatarList {
+    display: flex;
+    flex-wrap: wrap;
+    width: 100%;
+    padding: 0 20px;
+    box-sizing: border-box;
+    .avatarItem,
+    .avatarItem02 {
+      width: 68px;
+      max-height: 88px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      padding: 6px 4px;
+      position: relative;
+      margin-left: 1px;
+
+      .userName {
+        width: 100%;
+        margin: 3px 0;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        text-align: center;
+        min-height: 30px;
+        line-height: 30px;
+        font-size: 12px;
+      }
+    }
+    // .avatarItem:hover {
+    //   background-image: url('@/assets/images/class/avabg.png');
+    //   background-size: 100% 100%;
+    //   background-position: center;
+    //   background-repeat: no-repeat;
+    //   cursor: pointer;
+    // }
+    .avatarItem:hover,
+    .avatarItem02:hover {
+      background: #eee;
+    }
+  }
+  .noticeList {
+    width: 100%;
+    height: calc(100% - 63px);
+    padding: 5px 25px;
+    overflow: auto;
+    .noticeItem {
+      display: flex;
+      justify-content: space-between;
+      font-family: PingFang SC;
+      font-weight: 400;
+      font-size: 14px;
+      line-height: 32px;
+      .noticeContent {
+        display: flex;
+        justify-content: space-between;
+        color: #000000;
+        max-width: 800px;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        .title {
+          margin-right: 30px;
+        }
+        .content {
+          margin-right: 30px;
+        }
+      }
+      .time {
+        color: #b7b7b7;
+      }
+    }
+  }
+}
+</style>

--
Gitblit v1.9.1