QYF-GitLab1
32 分钟以前 264a2c1e93e9b9cd3c7e0568b656325b12b008ec
src/views/personalCenter/class.vue
@@ -1,7 +1,449 @@
<template>
  <div class="myBook">
    <div class="myBook_header">
      <div class="myBook_header_title">我的班级</div>
  <div class="coursePage">
    <div class="personalPage-title">我的班级</div>
    <div class="tabs">
      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
        <el-tab-pane :label="'当前班级(' + calssList.length + ')'" name="1"></el-tab-pane>
        <!-- <el-tab-pane label="历史班级(5)" name="2"></el-tab-pane> -->
      </el-tabs>
    </div>
    <div class="headerBox">
      <div class="searchBox">
        <el-input v-model="searchKey" clearable @clear="searchList()" placeholder="请输入关键字">
          <template #append>
            <el-button type="primary" class="searchBtn" @click="searchList()" :icon="Search" />
          </template>
        </el-input>
      </div>
      <el-button type="primary" class="applyStartClasses" @click="openJoin()">加入班级</el-button>
      <el-dialog v-model="dialogVisible" title="加入班级" width="500">
        <div class="codeContent">
          <span>邀请码:</span>
          <el-input style="width: 330px" v-model="codeText" placeholder="请输入邀请码" />
          <el-button type="primary" @click="getClassDetail">确认</el-button>
        </div>
        <div class="classInfo" v-if="classDetail?.name">
          <div class="itemCon">
            <span>班级名称:</span>
            <span>{{ classDetail.name }}</span>
          </div>
          <div class="itemCon">
            <span>班级人数:</span>
            <span>{{ classDetail.memberCount }} / {{ classDetail.maxUserCount }}</span>
          </div>
          <div class="itemCon">
            <span>开课时间:</span>
            <span
              >{{ moment(classDetail.beginDate).format('YYYY-MM-DD') }} -
              {{ moment(classDetail.endDate).format('YYYY-MM-DD') }}</span
            >
          </div>
        </div>
        <template #footer>
          <div class="dialog-footer">
            <el-button @click="dialogVisible = false"> 取消 </el-button>
            <el-button type="primary" :disabled="!classDetail?.name" @click="joinClass()">
              加入
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>
    <div class="courseListBox" v-if="calssList.length > 0 && !isLoading">
      <div class="courseItem" v-for="(item, index) in calssList" :key="index">
        <div class="itemHeader">
          <div class="title">{{ item.name }}</div>
          <div class="courseId">(ID:{{ item.id }})</div>
          <!-- <div class="copyIdBtn" @click="copy(item.refCode)">复制邀请码</div> -->
        </div>
        <div class="itemInfo" @click="goClassManage(item)">
          <div class="infoBox">
            <p>
              状态:<span v-if="item.userState == 'WaitValid'" style="color: #ef9f29"> 审核中 </span
              ><span v-if="item.userState == 'Normal'" style="color: #1dbd11"> 进行中 </span
              ><span v-if="item.userState == 'Reject'" style="color: red"> 未通过 </span>
            </p>
            <p>班级人数:{{ item.memberCount }} / {{ item.maxUserCount }}</p>
            <p>有效期:{{ item.classTime }}</p>
          </div>
        </div>
      </div>
    </div>
    <el-empty description="暂无数据" v-if="calssList.length == 0 && !isLoading" />
    <div style="min-height: 200px" v-if="isLoading" v-loading="isLoading"></div>
    <div class="pageBox">
      <el-pagination
        v-model:current-page="pages.currentPage"
        :page-size="pages.pageSize"
        :size="'small'"
        :disabled="pages.count <= 1"
        layout="total, prev, pager, next"
        :total="pages.count"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, inject, watch } from 'vue'
import { Search } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getPublicImage } from '@/assets/js/middleGround/tool.js'
import moment from 'moment'
import useClipboard from 'vue-clipboard3'
const { toClipboard } = useClipboard()
const MG: any = inject('MG')
const config: any = inject('config')
const router = useRouter()
const activeName = ref('1')
interface ClassItem {
  id: string
  name: string
  memberCount: number
  maxUserCount: number
  userState: string
  beginDate: string
  endDate: string
  classTime: string
  linkProductDto: {
    product: {
      name: string
      icon: string
    }
  }
}
const calssList = ref<ClassItem[]>([])
const searchKey = ref('')
const codeText = ref('')
const dialogVisible = ref(false)
const classDetail = ref()
const isLoading = ref(true)
let pages = reactive({
  currentPage: 1,
  page: 1,
  pageSize: 6,
  count: 0,
  loading: false,
})
onMounted(() => {
  getCurrentClassList()
})
//  分页
const handleSizeChange = (val: number) => {
  pages.pageSize = val
  getCurrentClassList()
}
const handleCurrentChange = (val: number) => {
  pages.page = val
  pages.currentPage = val
  getCurrentClassList()
}
const handleClick = (val: any) => {
  activeName.value = val
}
const openJoin = () => {
  dialogVisible.value = true
  classDetail.value = null
  codeText.value = ''
}
// 搜索
const searchList = () => {
  pages.page = 1
  pages.currentPage = 1
  getCurrentClassList()
}
// 复制
const copy = async (text: string) => {
  try {
    await toClipboard(text)
    ElMessage({
      message: '复制成功',
      type: 'success',
    })
  } catch (e) {
    console.error(e)
  }
}
// 加入班级
const joinClass = () => {
  if (!codeText.value) {
    ElMessage({
      message: '无效的邀请码',
      type: 'error',
    })
    return false
  }
  const data = { refCode: codeText.value }
  MG.identity.joinGroupByRefCode(data).then((res: any) => {
    if (res == '组不存在') {
      ElMessage({
        message: '无效的班级',
        type: 'error',
      })
    }
    if (res == '组成员数量已最大,不能加入') {
      ElMessage({
        message: '班级成员数量已最大,不能加入',
        type: 'error',
      })
    }
    if (res == '已经申请过加入此组') {
      ElMessage({
        message: '已经申请过加入此班级',
        type: 'error',
      })
    }
    dialogVisible.value = false
    getCurrentClassList()
  })
}
// 获取当前班级列表
const getCurrentClassList = () => {
  isLoading.value = true
  const data = {
    start: (pages.page - 1) * pages.pageSize,
    size: pages.pageSize,
    sort: {
      type: 'Desc',
      field: 'CreateDate',
      subSorts: [],
    },
    filterList: [],
    searchList: searchKey.value
      ? [
          {
            keywords: searchKey.value,
            field: 'Name',
            compareType: 'Contains',
          },
        ]
      : [],
  }
  MG.identity.joinedGroupByList(data).then((res: any) => {
    isLoading.value = false
    pages.count = res.totalSize
    if (res.datas) {
      calssList.value = res.datas.map((item: any) => {
        return {
          ...item,
          classTime:
            moment(item.beginDate).format('YYYY.MM.DD') +
            '--' +
            moment(item.endDate).format('YYYY.MM.DD'),
          bookName: item.linkProductDto.product.name,
          bookIcon: getPublicImage(item.linkProductDto.product.icon, 100),
        }
      })
    }
  })
}
// 跳转班级管理
const goClassManage = async (item: any) => {
  if (item.userState == 'WaitValid') {
    ElMessage({
      message: '正在审核中....',
      type: 'warning',
    })
    return false
  }
  if (item.userState == 'Reject') {
    ElMessage({
      message: '审核未通过',
      type: 'warning',
    })
    return false
  }
  const bookInfo = await getBookDetail(item.linkProductDto?.product)
  let info = {
    id: item.id,
    name: item.name,
    icon: bookInfo.icon,
    rootCmsItemId: bookInfo.rootCmsItemId,
    bookId: bookInfo.id,
    author: bookInfo.author,
    isbn: bookInfo.isbn,
    bookRefCode: bookInfo.refCode,
  }
  let page = router.resolve({
    path: '/classManage',
    query: {
      classInfo: JSON.stringify(info),
    },
  })
  window.open(page.href, '_blank')
  // router.push({
  //   path: '/classManage',
  //   query: {
  //     classInfo: JSON.stringify(info)
  //   }
  // })
}
// 获取教材详情
const getBookDetail = async (item: any) => {
  const path = item.refCode ? '*' : config.goodsStore
  let query = {
    path,
    queryType: '*',
    productId: String(item.id),
    coverSize: {
      height: 300,
      width: 210,
    },
    fields: {
      author: [],
      isbn: [],
    },
  }
  const res = await MG.store.getProductDetail(query)
  return res.datas ?? null
}
// 通过code查询班级
const getClassDetail = () => {
  if (codeText.value == '') {
    ElMessage({
      message: '请输入邀请码',
      type: 'warning',
    })
    return false
  }
  const data = {
    classIdOrRefCode: codeText.value,
  }
  MG.edu
    .getCourseClass(data)
    .then((res: any) => {
      classDetail.value = res
    })
    .catch((err: any) => {
      console.log(err)
    })
}
</script>
<style lang="less" scoped>
.coursePage {
  .tabs {
    padding: 0 20px;
  }
  .headerBox {
    padding: 5px 20px;
    margin-bottom: 10px;
    overflow: hidden;
    .searchBox {
      width: 300px;
      float: left;
      .searchBtn {
        background-color: var(--el-color-primary);
        color: #fff;
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
      }
    }
    .applyStartClasses {
      float: right;
    }
  }
  .courseListBox {
    overflow: hidden;
    .courseItem {
      float: left;
      width: 45%;
      margin: 0 2% 20px;
      border-radius: 8px;
      border: 1px solid #efefef;
      overflow: hidden;
      .itemHeader {
        height: 40px;
        line-height: 40px;
        padding: 0 20px;
        // color: #fff;
        background-color: #f8f8f8;
        box-sizing: border-box;
        .title {
          font-weight: 600;
        }
        div {
          display: inline-block;
        }
        .courseId {
          margin-left: 6px;
          font-size: 12px;
          color: #999;
        }
        .copyIdBtn {
          float: right;
          height: 20px;
          line-height: 20px;
          margin-top: 10px;
          font-size: 12px;
          background-color: #fff;
          color: #019e58;
          padding: 0 6px;
          border-radius: 50px;
          overflow: hidden;
          cursor: pointer;
        }
      }
      .itemInfo {
        padding: 15px;
        box-sizing: border-box;
        flex: 1;
        display: flex;
        cursor: pointer;
        .imgBox {
          width: 90px;
          height: 120px;
          margin-right: 20px;
        }
        .infoBox {
          flex: 1;
          font-size: 12px;
          padding: 10px 0;
          p {
            margin-bottom: 10px;
          }
        }
      }
    }
  }
  .codeContent {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 30px;
  }
  .classInfo {
    padding: 30px 0;
    border-top: 2px dashed #ccc;
    .itemCon {
      margin-bottom: 20px;
    }
  }
  .pageBox {
    padding: 10px 0;
    display: flex;
    justify-content: center;
  }
}
</style>