闫增涛
2025-04-14 2cac4a0f4ea0b1cf7bff4759fae8136c72792563
番茄闹钟
7个文件已修改
2个文件已添加
572 ■■■■ 已修改文件
.gitignore 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/config.ts 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/main.css 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/style/examination.less 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/child.ts 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/public.ts 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/components/pomodoro.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/readerPages/webHome.vue 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -11,7 +11,7 @@
node_modules
*.lock
package-lock.json
*.mp3
# 编译文件
dist
dist-electron
src/App.vue
@@ -142,7 +142,6 @@
</script>
<style lang="less">
@import './assets/style/examination.less';
.updateDownloadInfo {
  position: fixed;
  top: 2px;
src/assets/js/config.ts
@@ -1,8 +1,8 @@
// 测试
export const requestCtx = "https://jsek.bnuic.com"; //jsek
export const appId = 3;
// export const requestCtx = "http://182.92.203.7:3007"; //jsek
// export const appId = 27
// export const requestCtx = "https://jsek.bnuic.com"; //jsek
// export const appId = 3;
export const requestCtx = "http://182.92.203.7:3007"; //jsek
export const appId = 27
export const requestTimeOut = 300000; // 请求超时时间
export const tokenKey = "token";
export const userInfoKey = "website-front-userInfo"; // 用户信息key 
src/assets/main.css
@@ -1,5 +1,5 @@
@import './base.css';
@import './style/examination.less';
#parentApp {
  width: 100%;
  height: 100%;
src/assets/style/examination.less
@@ -45,13 +45,13 @@
    text-indent: 0em !important;
    margin-left: 20px;
    /deep/ .el-textarea__inner:focus {
    .el-textarea__inner:focus {
      border-color: #15c0f2;
    }
  }
  .input {
    /deep/ .el-input__inner {
    .el-input__inner {
      height: 26px;
    }
  }
@@ -186,11 +186,11 @@
          border-bottom: 1px solid #000;
        }
        /deep/ .el-textarea.is-disabled .el-textarea__inner {
        .el-textarea.is-disabled .el-textarea__inner {
          background-color: #fff;
        }
        /deep/ .el-input.is-disabled .el-input__inner {
        .el-input.is-disabled .el-input__inner {
          background-color: #fff;
        }
@@ -199,11 +199,8 @@
          align-items: center;
        }
      }
      ::v-deep {
        .el-input__wrapper {
          border-top: 0 !important;
        }
      .el-input__wrapper {
        border-top: 0 !important;
      }
    }
@@ -232,12 +229,12 @@
      white-space: pre-wrap !important;
      color: #000;
      /deep/ .el-checkbox__label {
      .el-checkbox__label {
        line-height: 1.5;
      }
    }
    /deep/ .el-radio__inner {
    .el-radio__inner {
      border-color: #a5a3a3;
    }
@@ -262,7 +259,7 @@
  /** 解析 */
  .objective {
    /deep/ .el-collapse-item__header {
    .el-collapse-item__header {
      min-height: 48px;
      height: min-content;
      padding: 0 20px;
@@ -332,11 +329,8 @@
              overflow: hidden;
              text-overflow: ellipsis;
              white-space: nowrap;
              ::v-deep {
                img {
                  max-height: 48px;
                }
              img {
                max-height: 48px;
              }
            }
          }
@@ -352,11 +346,11 @@
    }
  }
  /deep/ .el-collapse-item__header:focus:not(:hover) {
  .el-collapse-item__header:focus:not(:hover) {
    color: #333;
  }
  /deep/ .el-collapse-item__content {
  .el-collapse-item__content {
    width: 93%;
    padding: 0 20px;
    background-color: #f4f4f4;
@@ -364,7 +358,7 @@
    color: #333;
  }
  /deep/ .el-collapse-item__arrow {
  .el-collapse-item__arrow {
    display: none;
  }
@@ -378,7 +372,7 @@
  }
  .subjective {
    /deep/ .el-collapse-item__header {
    .el-collapse-item__header {
      height: 80px;
      background-color: #f4f4f4;
      width: 100%;
@@ -457,7 +451,7 @@
    height: min-content;
    margin-bottom: 6px;
    /deep/ img {
    img {
      margin-left: 10px;
      object-fit: contain;
      vertical-align: middle;
@@ -480,13 +474,11 @@
  }
  .titleTextArea {
    ::v-deep {
      img,
      .el-image__inner {
        max-width: 150px !important;
        max-height: 100px !important;
        object-fit: contain;
      }
    img,
    .el-image__inner {
      max-width: 150px !important;
      max-height: 100px !important;
      object-fit: contain;
    }
  }
@@ -636,9 +628,9 @@
    object-fit: contain;
  }
  /deep/ .examination-math {
  .examination-math {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
  }
}
}
src/child.ts
@@ -106,6 +106,60 @@
    entry: '//182.92.203.7:3007/books/book/botany',
    container: '#container',
    activeRule: '/home' //匹配所有以/subPath开头的为子应用
  },
  aurturingAndEducationAged0to3:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/aurturingAndEducationAged0to3',
    container: '#container',
    activeRule: '/home' //匹配所有以/subPath开头的为子应用
  },
  childcareInstitutionsManagement:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/childcareInstitutionsManagement',
    container: '#container',
    activeRule: '/home' //匹配所有以/subPath开头的为子应用
  },
  preschoolGameGuidance:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/preschoolGameGuidance',
    container: '#container',
    activeRule: '/home'
  },
  kindergartenLanguageActivity:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/kindergartenLanguageActivity',
    container: '#container',
    activeRule: '/home'
  },
  preschoolEvaluation:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/preschoolEvaluation',
    container: '#container',
    activeRule: '/home'
  },
  preschoolBasicKnowledge:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/preschoolBasicKnowledge',
    container: '#container',
    activeRule: '/home'
  },
  kindergartenActivitiesDesignGuidance:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/kindergartenActivitiesDesignGuidance',
    container: '#container',
    activeRule: '/home'
  },
  policiesAndRegulations:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/policiesAndRegulations',
    container: '#container',
    activeRule: '/home'
  },
  OralAndBroadcasting:{
    name: 'app-content',
    entry: '//182.92.203.7:3007/books/book/OralAndBroadcasting',
    container: '#container',
    activeRule: '/home'
  }
}
src/hooks/public.ts
New file
@@ -0,0 +1,21 @@
export const useFormatData = () => {
  const formatTime = (time:number) => {
    if(time == 0) return '00:00'
    const minutes = Math.floor(time / 60)
    const remainingSeconds = time % 60
    return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`
  }
  return {
    formatTime
  }
}
export const useCoordinateData = () => {
  const getPageXY = (e:MouseEvent) => {
  }
  return {
    getPageXY
  }
}
src/views/components/pomodoro.vue
New file
@@ -0,0 +1,197 @@
<template>
  <el-dialog v-model="dialogVisable" title="番茄闹钟" width="500" >
    <div class="ring-box">
      <span class="title-txt">响铃时长</span>
      <el-switch v-model="pageData.isRing" :disabled="isRuning" />
      <el-input-number v-model="pageData.ringTime" :disabled="isRuning" :min="1" step-strictly />
    </div>
    <p class="prompt-txt ring-title">以秒为单位</p>
    <div class="border" ></div>
    <ul class="sustain-box">
      <li>
        <span class="title-txt">持续时间</span>
        <span class="label-txt" >专注时间</span>
        <el-input-number v-model="pageData.workTime" :disabled="isRuning" :min="1" step-strictly />
      </li>
      <li>
        <span class="title-txt"></span>
        <span class="label-txt">短休息</span>
        <el-input-number v-model="pageData.shortTime" :disabled="isRuning" :min="0" step-strictly />
      </li>
      <li>
        <span class="title-txt"></span>
        <span class="label-txt">长休息</span>
        <el-input-number v-model="pageData.longTime" :disabled="isRuning" :min="0" step-strictly />
      </li>
    </ul>
    <p  class="prompt-txt ring-title" >以分钟为单位</p>
    <div class="border" ></div>
    <div>
      <el-button type="primary" @click="startFun" >开始</el-button>
      <el-button type="primary" @click="pauseFun" >停止</el-button>
      <el-button @click="resetFun">重置</el-button>
      <el-button @click="handleRestFun(false)" >长休息</el-button>
      <el-button @click="handleRestFun(true)">短休息</el-button>
    </div>
    {{ formatTime(pageData.currentTime) }}
  </el-dialog>
  <!-- <video src="../../assets/audio/买辣椒也用券.mp3"  ref="audioRef"></video> -->
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { ref, reactive, defineExpose ,watchEffect } from 'vue'
import {useFormatData} from '@/hooks/public'
const isShow =ref<boolean>(false)  // 悬浮框是否显示
const audioRef = ref<HTMLAudioElement>()  // 音频实例
const dialogVisable = ref<boolean>(false)  // 弹窗状态
const timerInterval = ref<any>(null)  // 计时器实例
const isRuning = ref<boolean>(false)  // 计时器是否运行
const isBreak = ref<boolean>(false)  // true 休息  false 工作
const isShortTime = ref<boolean>(false)  // 长短休息模式
const pageData = reactive({
  isRing: true, // 是否响铃
  ringTime: 5, // 响铃时长  秒
  workTime: 25, // 工作时长  分钟
  saveWorkTime: 0,  // 剩余工作时间
  shortTime: 5, // 短休息
  longTime: 5, // 长休息
  currentTime:0,  // 显示时间  秒
})
const { formatTime } = useFormatData()
watchEffect(() => {
  pageData.currentTime = pageData.workTime * 60
})
watchEffect(() => {
  if(!isBreak.value) pageData.saveWorkTime = pageData.currentTime
})
const setDialogVisable = (value: boolean) => {
  dialogVisable.value = value
}
  // 开始计时
const startFun = () => {
  isShow.value = true
  isRuning.value = true
  timerInterval.value = setInterval(() => {
    if(pageData.currentTime > 0) {
      pageData.currentTime--
    } else {
      playAudio()
      if(isBreak.value) {
        // 工作时间赋值
        isBreak.value = false
        if( pageData.saveWorkTime) {
          pageData.currentTime =  pageData.saveWorkTime
          ElMessage.success('休息结束,开始学习吧!')
        } else {
          clearInterval(timerInterval.value)
          isRuning.value = false
          ElMessage.success('学习结束')
        }
      } else {
        // 休息时间赋值
        isBreak.value = true
        pageData.currentTime = isShortTime.value ? pageData.shortTime * 60 : pageData.longTime * 60
        ElMessage.success('休息一下吧!')
      }
    }
  }, 1000)
  dialogVisable.value = false
}
// 暂停计时
const pauseFun = () => {
  isRuning.value =  false
  if(timerInterval.value) {
    clearInterval(timerInterval.value)
  }
}
// 重置计时器
const resetFun = () =>  {
  isRuning.value = false
  isBreak.value = false
  pauseFun()
  pageData.currentTime = pageData.workTime * 60
}
// 休息按钮
const startBreak = () => {
  if(isRuning.value && !isBreak.value) {
    if(pageData.shortTime || pageData.longTime) {
      pageData.saveWorkTime = pageData.currentTime
      isBreak.value = true
      pageData.currentTime = isShortTime.value ? pageData.shortTime * 60 : pageData.longTime * 60
      ElMessage.success('开始休息')
    } else {
      ElMessage.warning('暂未设置休息时间')
    }
  }
}
// 开始响铃
const playAudio = () => {
  audioRef.value!.currentTime = 0
  audioRef.value?.play()
  setTimeout(() => {
    pauseAudio()
  },pageData.ringTime * 1000)
}
 // 暂停响铃
const pauseAudio = () => {
  audioRef.value?.pause()
}
// 长短休息
const handleRestFun = (value:boolean) => {
  isShortTime.value = value
  startBreak()
}
defineExpose({
  isShow,
  isRuning,
  pageData,
  setDialogVisable,
  startFun,
  pauseFun,
  resetFun,
  handleRestFun
})
</script>
<style lang="less" scoped>
.prompt-txt {
  margin-top: 10px;
  font-size: 12px;
  color: #b7b7b7;
}
.title-txt {
  color: #2c2c2c;
  width: 4em;
}
.label-txt {
  width: 4em;
  color:#707070 ;
}
.ring-box {
  width: 300px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.ring-title {
  padding-left: 150px;
}
.sustain-box {
  width: 300px;
  li {
    display: flex;
    justify-content: space-between;
    margin-bottom: 10px;
  }
}
.border {
  height: 1px;
  background-color:#cecece ;
  margin: 10px 0;
}
</style>
src/views/readerPages/webHome.vue
@@ -440,7 +440,11 @@
                            @click="goPlay(item)"
                            size="20"
                            class="icon hover"
                            v-if="item.resourceType != '视频' && item.resourceType != '音频' && item.resourceType != '图片'"
                            v-if="
                              item.resourceType != '视频' &&
                              item.resourceType != '音频' &&
                              item.resourceType != '图片'
                            "
                          >
                            <View />
                          </el-icon>
@@ -644,6 +648,18 @@
            <!-- 画笔画布 -->
            <div class="canvas-box" v-show="canvasShow">
              <canvas id="canvasRef" :width="canvasWith" :height="canvasheight"></canvas>
            </div>
            <!-- 番茄闹钟组件 -->
            <div
              class="watch-box"
              v-if="pomodoroRef && pomodoroRef.isShow"
              :style="{ top:position.x + 'px', left:position.y + 'px'}"
            >
              <p @mousedown.native="mouseDown">{{ formatTime(pomodoroRef.pageData.currentTime) }}</p>
              <span @click="()=> pomodoroRef.isRuning ? pomodoroRef.pauseFun() : pomodoroRef.startFun()">{{pomodoroRef.isRuning ? '暂停': '开始'}}</span>
              <span @click="pomodoroRef.resetFun" >重置</span>
              <span @click="pomodoroRef.handleRestFun(false)">长休息</span>
              <span @click="pomodoroRef.handleRestFun(true)">短休息</span>
            </div>
          </div>
        </div>
@@ -1153,16 +1169,11 @@
    </div>
    <div class="wordBox" v-if="resourType == 'PDF' || resourType == 'PPT' || resourType == 'WORD'">
          <div
            v-for="(item, index) in showData"
            :key="index"
            class="pdfItem"
            :page="index + 1"
          >
            <img :src="item.showSrc" alt="" style="min-height: 550px" loading="lazy" />
            <el-divider content-position="center"> 第 {{ index + 1 }} 页 </el-divider>
          </div>
        </div>
      <div v-for="(item, index) in showData" :key="index" class="pdfItem" :page="index + 1">
        <img :src="item.showSrc" alt="" style="min-height: 550px" loading="lazy" />
        <el-divider content-position="center"> 第 {{ index + 1 }} 页 </el-divider>
      </div>
    </div>
  </el-dialog>
  <div class="audioBox" v-show="false">
    <!-- <video controls controlslist="nodownload" :src="testVideo"></video> -->
@@ -1276,7 +1287,7 @@
  </el-dialog>
  <el-dialog title="模型工具" align-center v-model="modelTool" width="80%" class="myDialogs">
    <div class="wendabox">
      <iframe src='https://adjam93.github.io/threejs-model-viewer/#' frameborder="0"></iframe>
      <iframe src="https://adjam93.github.io/threejs-model-viewer/#" frameborder="0"></iframe>
    </div>
  </el-dialog>
  <el-dialog title="生词卡片" align-center v-model="shengciVisble" width="800" class="myDialogs">
@@ -1295,12 +1306,7 @@
      <wrongQuestion />
    </div>
  </el-dialog>
  <el-dialog
    title="公式编辑"
    align-center
    v-model="formulaDialog"
    class="myDialogs"
  >
  <el-dialog title="公式编辑" align-center v-model="formulaDialog" class="myDialogs">
    <div class="wendabox">
      <formula />
    </div>
@@ -1318,14 +1324,19 @@
    <!-- <calculatorNew></calculatorNew> -->
    <iframe src="https://www.geogebra.org/scientific" frameborder="0" class="iframe-box"></iframe>
  </el-dialog>
  <!-- 番茄闹钟 -->
  <!-- <pomodoro ref="pomodoroRef" /> -->
</template>
<script setup lang="ts">
import examination from '@/views/examination/index.vue'
import pomodoro from '@/views/components/pomodoro.vue'
import { ref, reactive, watch, onMounted, onBeforeMount, onBeforeUnmount, inject } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox, valueEquals } from 'element-plus'
import { useFormatData } from '@/hooks/public'
import useClipboard from 'vue-clipboard3'
const { toClipboard } = useClipboard()
const { formatTime } = useFormatData()
const MG: any = inject('MG')
const toolClass = inject('toolClass')
//获取路由器
@@ -1495,7 +1506,6 @@
        window.qiankunState.initTestBook(localStorage.getItem('bookId') + '', tryPageCount.value)
      }
    }
  })
  // 定义父层方法
@@ -1585,7 +1595,6 @@
  // if (window.qiankunState && window.qiankunState.getAnswers){
  //   window.qiankunState.getAnswers(localStorage.getItem(""))
  // }
})
onBeforeUnmount(() => {
@@ -1636,6 +1645,7 @@
  }
  MG.store.getProductList(obj).then((res) => {
    console.log(res.datas, '图书信息')
    if (!res.datas.length) return
    bookInfo.value = res.datas[0]
    if (res.datas[0].purchasedSaleMethodIdList.includes(res.datas[0].defaultSaleMethodId)) {
      isBuy.value = true
@@ -1808,6 +1818,11 @@
      icon: fanqiezhong,
      isShow: bookConfig.value.textbookComponents.indexOf('E4DC9777') > -1
    }
    // {
    //   name: '番茄闹钟',
    //   icon: fanqiezhong,
    //   isShow: true
    // }
  ]
  floatingToolBox = [
    {
@@ -1899,9 +1914,9 @@
      if (localStorage.getItem('chapter') && localStorage.getItem('startPage')) {
        let chapter = Number(localStorage.getItem('chapter'))
        let start = Number(localStorage.getItem('startPage'))
        if (window.qiankunState && window.qiankunState.gotoPage) {
          window.qiankunState.gotoPage(chapter,start)
          window.qiankunState.gotoPage(chapter, start)
          localStorage.removeItem('chapter')
          localStorage.removeItem('startPage')
        }
@@ -1909,7 +1924,6 @@
    })
    .catch(function (error) {
      listLoading.value = false
    })
}
const defaultProps = {
@@ -2063,8 +2077,12 @@
                if (resItem1.resourceType == classifySelectList.value[0].title) {
                  resourceDataList.value.push(resItem1)
                }
                if(activeClassify.value == 'other'){
                  if (resItem1.resourceType != '图片' && resItem1.resourceType != '视频' && resItem1.resourceType != '音频') {
                if (activeClassify.value == 'other') {
                  if (
                    resItem1.resourceType != '图片' &&
                    resItem1.resourceType != '视频' &&
                    resItem1.resourceType != '音频'
                  ) {
                    resourceDataList.value.push(resItem1)
                  }
                }
@@ -2142,8 +2160,12 @@
                if (resItem1.resourceType == classifySelectList.value[0].title) {
                  resourceDataList.value.push(resItem1)
                }
                if(activeClassify.value == 'other'){
                  if (resItem1.resourceType != '图片' && resItem1.resourceType != '视频' && resItem1.resourceType != '音频') {
                if (activeClassify.value == 'other') {
                  if (
                    resItem1.resourceType != '图片' &&
                    resItem1.resourceType != '视频' &&
                    resItem1.resourceType != '音频'
                  ) {
                    resourceDataList.value.push(resItem1)
                  }
                }
@@ -2182,7 +2204,7 @@
const sceneUrl = ref()
const showData = ref()
const goPlay = (data, index) => {
  console.log(data.resourceType,123)
  console.log(data.resourceType, 123)
  resourType.value = data.resourceType
  if (data.resourceType == '视频') {
    if (data.md5) {
@@ -2200,12 +2222,19 @@
    }
    autoPlay()
  } else if (data.resourceType == '模型') {
    console.log(data,222)
    console.log(data, 222)
    let file = bookConfig.value.requestCtx + '/file/api/ApiDownload?md5=' + data.md5
    console.log(file.exd,777)
    console.log(file.exd, 777)
    const ctx = 'https://jsek.bnuic.com'
    if (data.md5) {
      sceneUrl.value = 'https://jsek.bnuic.com/books/book/civilAviation/static/modelView/index.html?md5=' + data.md5 + '&name=je' + '&domain=' + ctx + '&exd=obj' + '&target=iframe'
      sceneUrl.value =
        'https://jsek.bnuic.com/books/book/civilAviation/static/modelView/index.html?md5=' +
        data.md5 +
        '&name=je' +
        '&domain=' +
        ctx +
        '&exd=obj' +
        '&target=iframe'
    } else {
      sceneUrl.value = bookConfig.value.resourceUrl + '/' + data.resourcePath
    }
@@ -2215,38 +2244,37 @@
    // } else if (data.resourcePath) {
    //   window.open(bookConfig.value.resourceUrl + '/' + data.resourcePath)
    // }
  }else if(data.resourceType == 'PPT' || data.resourceType == 'PDF'){
  } else if (data.resourceType == 'PPT' || data.resourceType == 'PDF') {
    let md5 = data.md5
    let dataList = []
      MG.file
        .getPdfInfo({
          md5
        })
        .then((res: any) => {
          console.log()
          if (res && res.totalPages) {
            for (let i = 0; i < res.totalPages; i++) {
              const src =
    MG.file
      .getPdfInfo({
        md5
      })
      .then((res: any) => {
        console.log()
        if (res && res.totalPages) {
          for (let i = 0; i < res.totalPages; i++) {
            const src =
              bookConfig.value.requestCtx +
                '/file/GetPdfPageImage?md5=' +
                md5 +
                '&index=' +
                (i + 1) +
                '&dpi=300'
              dataList.push({
                showSrc: src
              })
            }
            console.log(dataList)
            showData.value = dataList
            // 启动页码观察
            setTimeout(() => {
              resourVisble.value = true
            }, 500)
              '/file/GetPdfPageImage?md5=' +
              md5 +
              '&index=' +
              (i + 1) +
              '&dpi=300'
            dataList.push({
              showSrc: src
            })
          }
        })
  }else {
          console.log(dataList)
          showData.value = dataList
          // 启动页码观察
          setTimeout(() => {
            resourVisble.value = true
          }, 500)
        }
      })
  } else {
    if (data.md5) {
      window.open(bookConfig.value.requestCtx + '/file/api/ApiDownload?md5=' + data.md5)
    } else if (data.resourcePath) {
@@ -2258,7 +2286,7 @@
  //   testWord.value = bookConfig.value.resourceUrl + '/' + data.resourcePath
  // }
}
const goDownload =(data) =>{
const goDownload = (data) => {
  if (data.md5) {
    window.open(bookConfig.value.requestCtx + '/file/api/ApiDownload?md5=' + data.md5)
  } else if (data.resourcePath) {
@@ -2405,8 +2433,12 @@
                if (resItem1.resourceType == classifySelectList.value[0].title) {
                  resourceDataList.value.push(resItem1)
                }
                if(activeClassify.value == 'other'){
                  if (resItem1.resourceType != '图片' && resItem1.resourceType != '视频' && resItem1.resourceType != '音频') {
                if (activeClassify.value == 'other') {
                  if (
                    resItem1.resourceType != '图片' &&
                    resItem1.resourceType != '视频' &&
                    resItem1.resourceType != '音频'
                  ) {
                    resourceDataList.value.push(resItem1)
                  }
                }
@@ -2895,7 +2927,7 @@
      break
  }
}
type pomodoroType = InstanceType<typeof Pomodoro>
const baiduVisible = ref(false)
const wendaVisible = ref(false)
const cidianVisible = ref(false)
@@ -2905,13 +2937,14 @@
const modelTool = ref(false)
const shengciVisble = ref(false)
const calculatorVisble = ref(false)
const pomodoroRef = ref<pomodoroType>()
const activeTool = ref(0)
const toolState = reactive({
  open: true
})
const resourceUrl = ref('')
const selectTeachTools = (item) => {
const selectTeachTools = (item: any) => {
  if (token) {
    activeTool.value = item.name
    switch (item.name) {
@@ -2925,7 +2958,7 @@
        siweiVisble.value = true
        break
      case '模型工具':
      modelTool.value = true
        modelTool.value = true
        break
      case '词典':
        cidianVisible.value = true
@@ -2936,6 +2969,8 @@
        break
      case '计算器':
        calculatorVisble.value = true
      case '番茄闹钟':
        pomodoroRef.value.setDialogVisable(true)
        break
    }
  } else {
@@ -4215,6 +4250,29 @@
const openFormulaDialog = () => {
  formulaDialog.value = true
}
// 番茄钟移动
const isMove = ref<boolean>(false)
const position = reactive({x:100,y:100})
const dragOffset = reactive({x:0,y:0})
const mouseDown = (e: MouseEvent) => {
  isMove.value = true
  dragOffset.x = e.clientX - position.x
  dragOffset.y = e.clientY - position.y
  document.addEventListener('mousemove', mouseMove)
  document.addEventListener('mouseup', mouseUp)
}
const mouseUp = (e: MouseEvent) => {
  isMove.value = false
  document.removeEventListener('mousemove', mouseMove)
  document.removeEventListener('mouseup', mouseUp)
}
const mouseMove = (e: MouseEvent) => {
  if (isMove.value) {
    position.x = e.clientX - dragOffset.x
    position.y = e.clientY - dragOffset.y
  }
}
</script>
<style lang="less">
@@ -4965,6 +5023,33 @@
          z-index: 96;
          background: rgba(255, 255, 255, 0.2);
        }
        .watch-box {
          display: flex;
          align-items: center;
          position: absolute;
          background-color: #555;
          color: #fff;
          padding: 10px;
          border-radius: 5px;
          width: max-content;
          p {
            cursor: move;
            padding: 0 8px;
            font-size: 18px;
            border-radius: 4px;
            margin-right: 10px;
            background-color: #666;
          }
          span {
            cursor: pointer;
            border-right: 1px solid #fff;
            padding: 0 4px;
            font-size: 14px;
            &:last-child {
              border-right: none;
            }
          }
        }
      }
    }
@@ -5475,14 +5560,14 @@
  width: 100%;
  overflow-y: scroll;
    img {
      display: block;
      margin: 0 auto;
      width: 90%;
      height: auto;
      box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.1);
      object-fit: contain;
    }
  img {
    display: block;
    margin: 0 auto;
    width: 90%;
    height: auto;
    box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.1);
    object-fit: contain;
  }
}
.imgUrlBox {
@@ -5500,7 +5585,7 @@
  left: 50px;
}
.iframe-box {
  width:100%;
  width: 100%;
  height: 800px;
}
</style>