2025-07-24 | 杨磊 | ![]() |
2025-07-24 | 杨磊 | ![]() |
2025-07-24 | zhongshujie | ![]() |
src/assets/js/config.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/child.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/plugin/axios/index.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/readerPages/home.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/readerPages/mobileHome.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/readerPages/webHome.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/assets/js/config.ts
@@ -1,10 +1,10 @@ // 测试 // export const requestCtx = "https://www.tepcb.com"; //lvyoushe // export const appId = 2; export const requestCtx = "https://jsek.bnuic.com"; //jsek export const appId = 3; // export const requestCtx = "http://182.92.203.7:3007"; // 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"; export const appId = 27 export const requestTimeOut = 300000; // 请求超时时间 // export const tokenKey = "token"; export const tokenKey = "jsek-token"; @@ -15,17 +15,17 @@ export const goodsStore = `defaultGoodsStore${appId}`; // 默认商品库(书城) // export const digitalTextbooks = "tourism_digitalTextbooks";//旅游社数字教材 export const digitalTextbooks = "jsek_digitalTextbooks";//京师智教数字教材 // export const loginCtx = "http://jsek.bnuic.com/home/#/digitalTextbooks?login=true"; //登录链接 export const loginCtx = ""; //登录链接 export const loginCtx = "http://jsek.bnuic.com/home/#/digitalTextbooks?login=true"; //登录链接 // export const loginCtx = ""; //登录链接 export default { requestCtx, appId, requestTimeOut, tokenKey, userInfoKey, appRefCode, goodsStore, digitalTextbooks, loginCtx } requestCtx, appId, requestTimeOut, tokenKey, userInfoKey, appRefCode, goodsStore, digitalTextbooks, loginCtx } src/child.ts
@@ -104,9 +104,20 @@ entry: '//182.92.203.7:3007/books/book/MMVRTCMP', container: '#container', activeRule: '/home' }, toddlerGameImplementation: { name: 'app-content', entry: '//182.92.203.7:3007/books/book/toddlerGameImplementation', container: '#container', activeRule: '/home' //匹配所有以/subPath开头的为子应用 }, regionalAnatomy: { name: 'app-content', entry: '//182.92.203.7:3007/books/book/regionalAnatomy', container: '#container', activeRule: '/home' //匹配所有以/subPath开头的为子应用 } } const jsekBooks = { childHealth: { @@ -205,9 +216,20 @@ entry: '//jsek.bnuic.com/books/book/kindergartenActivitiesDesignGuidance', container: '#container', activeRule: '/home' }, textToddlerSportsSafetyProtection: { name: 'app-content', entry: '//jsek.bnuic.com/books/book/textToddlerSportsSafetyProtection', container: '#container', activeRule: '/home' }, OralAndBroadcasting: { name: 'app-content', entry: '//jsek.bnuic.com/books/book/OralAndBroadcasting', container: '#container', activeRule: '/home' } } const tourismBooks = { policiesAndRegulations: { @@ -232,7 +254,7 @@ } } export const microApps = jsekBooks export const microApps = testBooks window.qiankunActions = actions src/main.ts
@@ -14,42 +14,49 @@ import { loginCtx } from '@/assets/js/config.ts' // 公式输入 import { MathfieldElement } from "mathlive" import { MathfieldElement } from 'mathlive' // 公式解析 import VueLatex from 'vatex' const handleGetToken = () => { return localStorage.getItem('token') return localStorage.getItem('token') } // 路由执行之前的一些操作 router.beforeEach((to, from, next) => { const isInternalLink = from.fullPath.includes('/testBookReader') if (isInternalLink) { sessionStorage.removeItem('loginCtx') } else { sessionStorage.setItem('loginCtx', loginCtx) } const url = window.location.href if (url.includes('&token=')) { const token = url.split('&token=')[1] localStorage.setItem('token', token) if (token) { next() } return false } const isInternalLink = from.fullPath.includes('/testBookReader') if (isInternalLink) { sessionStorage.removeItem('loginCtx') } else { sessionStorage.setItem('loginCtx', loginCtx) } next() // if (handleGetToken()) { // // 是否是登录页面,直接到首页 // if (to.path === '/login') { // next({ path: '/home', query: { bookId: localStorage.getItem('bookId') } }) // } else { // // 如果不是登录页面,跳转到目标的页面 // next() // } // } else { // // 没有token // if (!to.meta || !to.meta.auth) { // // 在免登录白名单,直接进入 // next() // } else { // next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 // } // } next() // if (handleGetToken()) { // // 是否是登录页面,直接到首页 // if (to.path === '/login') { // next({ path: '/home', query: { bookId: localStorage.getItem('bookId') } }) // } else { // // 如果不是登录页面,跳转到目标的页面 // next() // } // } else { // // 没有token // if (!to.meta || !to.meta.auth) { // // 在免登录白名单,直接进入 // next() // } else { // next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 // } // } }) // qiankun主应用与微应用通讯 @@ -57,7 +64,7 @@ // import state from './qiankunState/state' // state.bb = (data) => { // console.log(data); // console.log(data); // } // 初始化 state @@ -65,8 +72,8 @@ // 监听state变化 // actions.onGlobalStateChange((state: any, prev: any) => { // // state: 变更后的状态; prev 变更前的状态 // console.log("父层change:",state, prev) // // state: 变更后的状态; prev 变更前的状态 // console.log("父层change:",state, prev) // }) // 设置state的值 // actions.setGlobalState(state) @@ -81,7 +88,6 @@ const app = createApp(App) app.provide('toolClass', toolClass) app.provide('MG', MG) app.provide('config', config) @@ -90,7 +96,7 @@ app.use(ElementPlus) app.use(pinia) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) app.component(key, component) } app.mount('#parentApp') src/plugin/axios/index.ts
@@ -1,12 +1,10 @@ import axios from 'axios' import { ctx } from '../../../electron/config' import router from '@/router' import { tokenKey } from '@/assets/js/config.ts' import { requestCtx,tokenKey } from '@/assets/js/config.ts' // 创建 axios 实例 const service = axios.create({ baseURL: ctx, baseURL: requestCtx, timeout: 300000 // 请求超时时间 }) src/views/readerPages/home.vue
@@ -1,7 +1,7 @@ <template> <div class="homePage"> <webHome v-if="homeBoxWebHide" /> <mobileHome v-if="homeBoxHide" /> <mobileHome v-if="homeBoxWebHide" /> <webHome v-else /> </div> <div class="pdfDialog"> <el-dialog v-model="dialogState.dialogVisible" width="60vw" top="2vh" lock-scroll :show-close="false" @@ -27,7 +27,6 @@ const screenWidth = ref( window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth ) const homeBoxHide = ref(false) const homeBoxWebHide = ref(false) const dialogState = reactive({ dialogVisible: false, @@ -35,14 +34,24 @@ isClear: false, p_md5: '' }) // 检测是否为移动设备 const checkDevice = () => { const userAgent = navigator.userAgent.toLowerCase() const isMobileAgent = /Android|webOS|iPhone|iPod|BlackBerry/i.test(userAgent) homeBoxWebHide.value = isMobileAgent } onMounted(() => { if (screenWidth.value < 420) { homeBoxHide.value = true homeBoxWebHide.value = false } else { homeBoxWebHide.value = true homeBoxHide.value = false } checkDevice() // if (screenWidth.value < 420) { // homeBoxHide.value = true // homeBoxWebHide.value = false // } else { // homeBoxWebHide.value = true // homeBoxHide.value = false // } window.qiankunActions.setGlobalState({ openPDF: (data) => { console.log('父应用', data) @@ -65,8 +74,8 @@ .custom-dialog { .el-dialog { padding: 0; } padding: 0; } .el-dialog__header { background-color: rgba(0, 0, 0, 0.8); src/views/readerPages/mobileHome.vue
@@ -1,15 +1,13 @@ <template> <div class="mobileHomeBox"> <div class="headerBox"> <el-icon @click="goHome"><ArrowLeft /></el-icon> <el-icon @click="goHome"> <ArrowLeft /> </el-icon> <div class="bookName">{{ bookConfig.bookName }}</div> </div> <div class="contentBox"> <div class="pageBox" :style="{ background: settingForm.bgColorActive }" v-show="activeIndex == '0'" > <div class="pageBox" :style="{ background: settingForm.bgColorActive }" v-show="activeIndex == '0'"> <!-- 头部显示 --> <div class="pageBox-header"> <div class="progress"> @@ -33,17 +31,9 @@ </div> </div> <div class="catalogList" v-if="activeTabs == 'catalog'"> <el-tree ref="catalogTree" default-expand-all="true" :expand-on-click-node="false" node-key="start" highlight-current :data="catalogueData" :props="defaultProps" v-if="catalogueData.length > 0" @node-click="handleNodeClick" > <el-tree ref="catalogTree" default-expand-all="true" :expand-on-click-node="false" node-key="start" highlight-current :data="catalogueData" :props="defaultProps" v-if="catalogueData.length > 0" @node-click="handleNodeClick"> <template #default="{ node, data }"> <div class="custom-tree-node"> <div class="catalogueLabel" :title="node.label">{{ node.label }}</div> @@ -89,15 +79,8 @@ </div> <div class="resourceSearchBox" v-if="classifySelectList.length > 0"> <div class="classification"> <div v-for="item in classifySelectList" :key="item.key" class="flex1 hover" @click="classifyClick(item)" > <div :class="item.key == activeClassify ? 'activeClassify classifyItem' : 'classifyItem'" > <div v-for="item in classifySelectList" :key="item.key" class="flex1 hover" @click="classifyClick(item)"> <div :class="item.key == activeClassify ? 'activeClassify classifyItem' : 'classifyItem'"> <div class="title">{{ item.title }}</div> <div class="count">{{ item.count }}</div> </div> @@ -110,14 +93,8 @@ </div> <div class="searchBox"> <div class="inputBox" v-if="!searchShow"> <el-input class="custom-input" placeholder="请输入内容" v-model="searchText" @keyup.enter="searchBook" clearable @clear="handleClear" > <el-input class="custom-input" placeholder="请输入内容" v-model="searchText" @keyup.enter="searchBook" clearable @clear="handleClear"> <template #prefix> <img :src="listSearch" @click="searchBook" /> </template> @@ -130,63 +107,49 @@ <div class="resourceImg"> <img :src="item.resourcePath" mode="" v-if="activeClassify == 'image'" /> <img :src="item.icon" mode="" v-else-if="item.icon && activeClassify != 'image'" /> <el-icon v-else-if="activeClassify == 'audio'" size="30"><Headset /></el-icon> <el-icon v-else-if="activeClassify == 'video'" size="30"><VideoCamera /></el-icon> <el-icon v-else-if="activeClassify == 'other'" size="30"><Files /></el-icon> <el-icon v-else-if="activeClassify == 'exercises'" size="30"><Tickets /></el-icon> <el-icon v-else-if="activeClassify == 'audio'" size="30"> <Headset /> </el-icon> <el-icon v-else-if="activeClassify == 'video'" size="30"> <VideoCamera /> </el-icon> <el-icon v-else-if="activeClassify == 'other'" size="30"> <Files /> </el-icon> <el-icon v-else-if="activeClassify == 'exercises'" size="30"> <Tickets /> </el-icon> </div> <div class="rName"> <div>{{ item.resourceName }}</div> <div class="handleBox"> <el-icon class="icon hover" size="20" @click="JumpPosition(item)" v-if="resourceType == 'default'" ><LocationInformation /></el-icon> <el-icon @click="goPlay(item)" size="20" class="icon hover" v-if="item.resourceType == '视频'" ><VideoPlay /></el-icon> <el-icon @click="goPlay(item, index)" size="20" class="icon hover" v-if="item.resourceType == '音频' && playIndex != index" ><VideoPlay /></el-icon> <el-icon @click="goPause()" size="20" class="icon hover" v-if="item.resourceType == '音频' && playIndex == index" ><VideoPause /></el-icon> <el-icon @click="getCapture(item, index)" size="20" class="icon hover" v-if="item.resourceType == '图片'" ><View /></el-icon> <el-icon size="20" class="icon hover" @click="goPlay(item)" v-if=" !( item.resourceType == '视频' || item.resourceType == '音频' || item.resourceType == '习题' || item.resourceType == '图片' ) " ><Download /></el-icon> <el-icon class="icon hover" size="20" @click="JumpPosition(item)" v-if="resourceType == 'default'"> <LocationInformation /> </el-icon> <el-icon @click="goPlay(item)" size="20" class="icon hover" v-if="item.resourceType == '视频'"> <VideoPlay /> </el-icon> <el-icon @click="goPlay(item, index)" size="20" class="icon hover" v-if="item.resourceType == '音频' && playIndex != index"> <VideoPlay /> </el-icon> <el-icon @click="goPause()" size="20" class="icon hover" v-if="item.resourceType == '音频' && playIndex == index"> <VideoPause /> </el-icon> <el-icon @click="getCapture(item, index)" size="20" class="icon hover" v-if="item.resourceType == '图片'"> <View /> </el-icon> <el-icon size="20" class="icon hover" @click="goPlay(item)" v-if=" !( item.resourceType == '视频' || item.resourceType == '音频' || item.resourceType == '习题' || item.resourceType == '图片' ) "> <Download /> </el-icon> </div> </div> </div> @@ -198,14 +161,8 @@ <div class="noteBox" v-show="activeIndex == '3'"> <div class="searchBox"> <div class="inputBox"> <el-input class="custom-input" placeholder="请输入内容" v-model="searchText" @keyup.enter="searchBook" clearable @clear="handleClear" > <el-input class="custom-input" placeholder="请输入内容" v-model="searchText" @keyup.enter="searchBook" clearable @clear="handleClear"> <template #prefix> <img :src="listSearch" @click="searchBook" /> </template> @@ -217,36 +174,25 @@ <div class="flex1 hover" @click="searchClick('all')"> <div :class="menuState.notesColor == 'all' ? ' allActive' : 'all'">全部</div> </div> <div v-for="item in colorSelectList" :key="item.key" class="flex1 hover" @click="searchClick(item)" > <div :style="{ background: item.key }" :class="item.key == menuState.notesColor ? 'activeScribe scribeItem' : 'scribeItem'" ></div> <div v-for="item in colorSelectList" :key="item.key" class="flex1 hover" @click="searchClick(item)"> <div :style="{ background: item.key }" :class="item.key == menuState.notesColor ? 'activeScribe scribeItem' : 'scribeItem'"></div> </div> </div> <div v-if="scribeData.noteList.length > 0"> <div v-for="(noteItem, index) in scribeData.noteList" :key="noteItem"> <div class="chapterName"> <el-icon @click="noteClose(index)" v-if="scribeData.isShow && scribeData.openIndex == index" class="hover" ><ArrowDown /></el-icon> <el-icon @click="noteOpen(index)" v-else class="hover"><ArrowRight /></el-icon> <el-icon @click="noteClose(index)" v-if="scribeData.isShow && scribeData.openIndex == index" class="hover"> <ArrowDown /> </el-icon> <el-icon @click="noteOpen(index)" v-else class="hover"> <ArrowRight /> </el-icon> <span>{{ noteItem.chapterName }}</span> </div> <div v-for="(item, index1) in noteItem.noteList" :key="item.key" class="listItem" v-show="scribeData.isShow && scribeData.openIndex == index" > <div v-for="(item, index1) in noteItem.noteList" :key="item.key" class="listItem" v-show="scribeData.isShow && scribeData.openIndex == index"> <div class="textBox"> <div class="title"> <div class="title-con"> @@ -258,24 +204,20 @@ <img :src="shanchu" @click="deleteBtn(item)" class="hover" /> </div> </div> <div class="noteText hover 123456" @click="jumpContent(item)" :style="{ background: item.color == '#F5E12A' ? 'rgba(255,234,41,0.1)' : item.color == '#76F0AE' ? 'rgba(83,255,162,0.1)' : item.color == '#59CFF5' ? 'rgba(93,216,255,0.1)' : item.color == '#CAA5FC' ? 'rgba(205,167,255,0.1)' : item.color == '#F5A0B9' ? 'rgba(255,167,193,0.1)' : item.color }" > <div class="noteText hover 123456" @click="jumpContent(item)" :style="{ background: item.color == '#F5E12A' ? 'rgba(255,234,41,0.1)' : item.color == '#76F0AE' ? 'rgba(83,255,162,0.1)' : item.color == '#59CFF5' ? 'rgba(93,216,255,0.1)' : item.color == '#CAA5FC' ? 'rgba(205,167,255,0.1)' : item.color == '#F5A0B9' ? 'rgba(255,167,193,0.1)' : item.color }"> <div class="con hover"> {{ item.note }} </div> @@ -292,14 +234,8 @@ <div class="allSearchBox" v-show="activeIndex == '7'"> <div class="searchBox"> <div class="inputBox"> <el-input class="custom-input" placeholder="请输入内容" v-model="searchText" @keyup.enter="searchBook" clearable @clear="handleClear" > <el-input class="custom-input" placeholder="请输入内容" v-model="searchText" @keyup.enter="searchBook" clearable @clear="handleClear"> <template #prefix> <img :src="listSearch" @click="searchBook" /> </template> @@ -310,21 +246,17 @@ <div v-if="allSearchReault.length > 0" class="allSearchList"> <div v-for="(reault, index) in allSearchReault" :key="index"> <div class="chapterName"> <el-icon @click="searchClose(index)" v-if="searchReaultData.isShow && searchReaultData.openIndex == index" class="hover" ><ArrowDown /></el-icon> <el-icon @click="searchOpen(index)" v-else class="hover"><ArrowRight /></el-icon> <el-icon @click="searchClose(index)" v-if="searchReaultData.isShow && searchReaultData.openIndex == index" class="hover"> <ArrowDown /> </el-icon> <el-icon @click="searchOpen(index)" v-else class="hover"> <ArrowRight /> </el-icon> <span>{{ reault.chapterName }} ({{ reault.itemList.length }})</span> </div> <div v-for="(item, index1) in reault.itemList" :key="index1" class="searchItem" v-show="searchReaultData.isShow && searchReaultData.openIndex == index" > <div v-for="(item, index1) in reault.itemList" :key="index1" class="searchItem" v-show="searchReaultData.isShow && searchReaultData.openIndex == index"> <div class="index">{{ index1 + 1 }}.</div> <div class="searchCon hover" @click="goSearchContent(item)"> {{ item.txt }} @@ -339,13 +271,7 @@ </div> </div> <div class="footerBox"> <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" ellipsis @select="handleSelect" > <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" ellipsis @select="handleSelect"> <el-menu-item index="1" class="menu-item">目录</el-menu-item> <el-menu-item index="2" class="menu-item">资源</el-menu-item> <el-menu-item index="3" class="menu-item">笔记</el-menu-item> @@ -356,28 +282,17 @@ </el-menu> </div> <!-- 设置 --> <el-drawer v-model="settingDrawer" title="设置" direction ="btt" size="35%" > <el-drawer v-model="settingDrawer" title="设置" direction="btt" size="35%"> <div> <div class="settingBox"> <el-form :model="settingForm" label-width="auto" style="max-width: 400px"> <el-form-item label="字体大小"> <div class="lineStyle"> <div class="lineTypeBox"> <div v-for="item in settingForm.fontSizeList" :key="item.key" :class=" settingForm.fontSizeActive == item.key ? 'typeItem lineTypeActive' : 'typeItem' " @click="fontSizeSelect(item)" > <div v-for="item in settingForm.fontSizeList" :key="item.key" :class="settingForm.fontSizeActive == item.key ? 'typeItem lineTypeActive' : 'typeItem' " @click="fontSizeSelect(item)"> {{ item.lable }} <div class="activeIcon" v-if="settingForm.fontSizeActive == item.key"> <img :src="xuanzhong" /> @@ -388,19 +303,12 @@ </el-form-item> <el-form-item label="底色"> <div class="bgColor"> <div v-for="item in settingForm.bgColorList" :key="item.key" class="flex1 hover" @click="bgColorSelect(item)" > <div :style="{ background: item.key, 'border-color': item.key == settingForm.bgColorActive ? '#0093FF' : '#EBEBEB' }" class="scribeItem" > <div v-for="item in settingForm.bgColorList" :key="item.key" class="flex1 hover" @click="bgColorSelect(item)"> <div :style="{ background: item.key, 'border-color': item.key == settingForm.bgColorActive ? '#0093FF' : '#EBEBEB' }" class="scribeItem"> <img :src="xuanzhong1" v-if="item.key == settingForm.bgColorActive" /> </div> </div> @@ -411,19 +319,10 @@ </div> </el-drawer> <!-- 选中工具栏 --> <div class="dialogToolBox" id="dialogToolBox" v-show="showToolBox" :style="{ top: `${dialogToolData.top}px`, left: `${dialogToolData.left}px` }" > <div class="dialogToolBox" id="dialogToolBox" v-show="showToolBox" :style="{ top: `${dialogToolData.top}px`, left: `${dialogToolData.left}px` }"> <div class="colorSelectBox" v-show="toolActive == '高亮' || toolActive == '划线'"> <div v-for="item in colorSelectList" :key="item.key" class="flex1 hover" @click="clickSelect(item)" > <div v-for="item in colorSelectList" :key="item.key" class="flex1 hover" @click="clickSelect(item)"> <div :style="{ background: item.key }" class="scribeItem"> <img :src="xuanzhong1" v-if="item.key == colorActive" /> </div> @@ -431,10 +330,7 @@ </div> <div class="toolSelectBox" v-show="toolActive != '高亮' && toolActive != '划线'"> <div v-for="item in dialogToolList" :key="item.icon" @click="dialogToolHandle(item)"> <div :class="item.name == toolActive ? 'dialogToolItem active' : 'dialogToolItem'" v-if="item.isShow" > <div :class="item.name == toolActive ? 'dialogToolItem active' : 'dialogToolItem'" v-if="item.isShow"> <el-tooltip class="box-item" effect="dark" :content="item.name" placement="bottom"> <img :src="item.icon" alt="" /> </el-tooltip> @@ -444,11 +340,8 @@ </div> </div> <!-- 划线,高亮删除 --> <div class="lineDeleteBox" v-show="lineDelete.showLineDelete" :style="{ top: `${lineDelete.top}px`, left: `${lineDelete.left}px` }" > <div class="lineDeleteBox" v-show="lineDelete.showLineDelete" :style="{ top: `${lineDelete.top}px`, left: `${lineDelete.left}px` }"> <!-- <el-button @click="delUserKey">删除</el-button> --> <div class="dialogToolItem"> <el-tooltip class="box-item" effect="dark" content="删除" placement="bottom"> @@ -462,28 +355,12 @@ </div> </div> </div> <el-dialog title="添加笔记" align-center v-model="addNoteVisble" :before-close="handleClose" class="myNoteDialogs" > <el-dialog title="添加笔记" align-center v-model="addNoteVisble" :before-close="handleClose" class="myNoteDialogs"> <div class="formBox"> <el-input type="textarea" :rows="4" v-model="formData.desc" placeholder="请输入笔记内容" ></el-input> <el-input type="textarea" :rows="4" v-model="formData.desc" placeholder="请输入笔记内容"></el-input> </div> <div class="noteColorSelectBox"> <div v-for="item in colorSelectList" :key="item.key" class="flex1 hover" @click="clickSelectColor(item)" > <div v-for="item in colorSelectList" :key="item.key" class="flex1 hover" @click="clickSelectColor(item)"> <div :style="{ background: item.key }" class="scribeItem"> <img :src="xuanzhong" v-if="item.key == noteColorActive" /> </div> @@ -498,21 +375,10 @@ </template> </el-dialog> <!-- 图片 --> <el-image-viewer v-if="confirmDialog" :zoom-rate="1.2" @close="closePreview" :initial-index="previewIndex" :url-list="imgPreviewList" /> <el-dialog title="资源" align-center v-model="resourVisble" width="845" class="resourDialog" :before-close="resourVisbleClose" > <el-image-viewer v-if="confirmDialog" :zoom-rate="1.2" @close="closePreview" :initial-index="previewIndex" :url-list="imgPreviewList" /> <el-dialog title="资源" align-center v-model="resourVisble" width="845" class="resourDialog" :before-close="resourVisbleClose"> <div class="videoBox" v-if="resourType == '视频'"> <video controls controlslist="nodownload" :src="testVideo"></video> </div> @@ -526,25 +392,26 @@ </div> </template> <script setup lang="ts"> import { ref, reactive, watch, onMounted, onBeforeUnmount,inject } from 'vue' import { ref, reactive, watch, onMounted, onBeforeUnmount, inject } from 'vue' import axios from 'axios' import { digitalTextbooks } from '@/assets/js/config.ts' import { ElMessage, ElMessageBox, valueEquals } from 'element-plus' import useClipboard from 'vue-clipboard3' const { toClipboard } = useClipboard() const MG: any = inject('MG') const toolClass = inject('toolClass') import { loadMicroApp } from 'qiankun' import { useRouter, useRoute } from 'vue-router' import { microApps } from '@/child.ts' //获取当前路由的信息 import moment from 'moment' import bianji from '@/assets/images/operation/bianji.png' import shanchu from '@/assets/images/operation/delete.png' import listSearch from '@/assets/images/operation/list-search.svg' import search from '@/assets/images/operation/search.png' import search1 from '@/assets/images/operation/search1.png' import xuanzhong from '@/assets/images/operation/xuanzhong.png' //获取当前路由的信息 const router = useRouter() let token = localStorage.getItem('token') const bookInfo = ref() const isBuy = ref(false) @@ -712,7 +579,7 @@ const getBookInfo = () => { const obj = { storeInfo: 'jsek_digitalTextbooks', storeInfo: digitalTextbooks, path: '*', queryType: '*', coverSize: { @@ -750,7 +617,7 @@ const handleSelect = (key: string, keyPath: string[]) => { console.log(key, keyPath) if (key == '4') { settingDrawer.value=true settingDrawer.value = true } else { activeIndex.value = key switch (activeIndex.value) { @@ -767,6 +634,7 @@ } } const goHome = () => { router.go(-1) activeIndex.value = '0' } @@ -1018,14 +886,14 @@ item.icon = '' } if (resourceType.value == 'default') { if (item.isDefaultResource == '是') { defaultResourceList.value.push(item) } } else { if (item.isTeacherResource == '是' && item.isDefaultResource == '否') { teacherResourceList.value.push(item) } if (item.isDefaultResource == '是') { defaultResourceList.value.push(item) } } else { if (item.isTeacherResource == '是' && item.isDefaultResource == '否') { teacherResourceList.value.push(item) } } }) if (defaultResourceList.value.length > 0) { let imgCount = 0 @@ -1513,7 +1381,7 @@ } }) }) .catch(() => {}) .catch(() => { }) } const searchText = ref('') @@ -1818,6 +1686,7 @@ .mobileHomeBox { width: 100%; height: 100%; .headerBox { width: 100%; height: 50px; @@ -1829,14 +1698,17 @@ z-index: 2; background-color: #fff; border-bottom: 1px solid #e0e0e0; .el-icon { margin: 0 10px; } .bookName { flex: 1; text-align: center; } } .footerBox { width: 100%; height: 50px; @@ -1846,18 +1718,22 @@ z-index: 2020; background-color: #fff; border-top: 1px solid #e0e0e0; .el-menu-demo { width: 100%; justify-content: center; .menu-item { min-width: calc(100% / 4); } } } .contentBox { margin: 50px 0; height: 100%; width: 100%; .pageBox { .pageBox-header { width: 100%; @@ -1866,58 +1742,72 @@ line-height: 30px; text-align: right; } .pageBox-content { height: calc(100vh - 130px); #container { background: #fbf9f4; height: 100%; #__qiankun_microapp_wrapper_for_app_content_1__ { height: 100%; } #__qiankun_microapp_wrapper_for_app_content__{ #__qiankun_microapp_wrapper_for_app_content__ { height: 100%; } } } } .catalogBox { height: calc(100vh - 100px); .catalogTab { height: 50px; display: flex; // justify-content: center; align-items: center; border-bottom: 1px solid #e0e0e0; .tabItem { flex: 1; text-align: center; .textActive { color: #0093ff; } } } .catalogList { height: calc(100vh - 150px); overflow: auto; padding: 20px; } .reMarkList { padding: 20px; .reMarkItem { border-bottom: 1px solid #efefef; padding: 10px 0; .deleteReMarkImg { text-align: right; } } } } .searchBox { padding: 5px; .inputBox { width: 85%; margin: 10px auto; .custom-input { border: 1px solid #0093ff !important; border-radius: 50px; @@ -1929,17 +1819,20 @@ .is-focus, .el-input__wrapper { box-shadow: none !important; .el-input__inner { border: none !important; height: 34px !important; } } .el-input-group__append { padding: 0 10px !important; background: none !important; } } } .resourceBox { .resourceTab { width: 100%; @@ -1949,11 +1842,13 @@ align-items: center; font-size: 16px; border-bottom: 1px solid #e0e0e0; .tabItem { flex: 1; text-align: center; line-height: 47px; } .text { width: 43px; height: 3px; @@ -1961,26 +1856,32 @@ background: #0093ff; border-radius: 3px 3px 0px 0px; } .line { height: 3px; } } .resourceSearchBox { border-bottom: 1px solid #efefef; } .classification { width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 10px; .flex1 { flex: 1; text-align: center; } .title { color: #999999; } .count { width: 35px; margin: 0 auto; @@ -1991,16 +1892,19 @@ height: 18px; font-size: 12px; } .activeClassify, .classifyItem:hover { .title { color: #0093ff; } .count { background: #0093ff; color: #fff; } } .showSearch { .imgBox { width: 39px; @@ -2008,20 +1912,25 @@ border-radius: 16px; margin: 0 auto; } .imgBox:hover, .activeSearch { border: 1px solid #0093ff; } } } .inputBox { margin: 0 auto !important; } .resourceList { padding: 20px; .resourceItem { padding: 10px 0; display: flex; .resourceImg { width: 150px; height: 80px; @@ -2033,20 +1942,24 @@ justify-content: center; position: relative; border: 1px solid #efefef; img { height: 100%; width: 100%; object-fit: contain; } } .rName { flex: 1; margin-left: 20px; position: relative; .handleBox { position: absolute; bottom: 0; left: 0; .el-icon { margin-right: 10px; } @@ -2055,10 +1968,12 @@ } } } .screenBox { display: flex; padding: 0 10px; width: 350px; .title { margin: 0; padding: 0 10px; @@ -2114,10 +2029,12 @@ margin: 15px; display: flex; align-items: center; span { margin-left: 5px; } } .listItem { border-bottom: 1px solid rgba(212, 212, 212, 0.16); position: relative; @@ -2126,22 +2043,26 @@ background: #fff; border-radius: 5px; padding: 10px 0; .textBox { .title { display: flex; justify-content: space-between; align-items: center; margin-right: 10px; .border-left { height: 25px; border-right: 4px solid; border-radius: 0 5px 5px 0; margin-right: 10px; } .title-con { display: flex; align-items: center; color: #949494; .round { width: 10px; height: 10px; @@ -2154,6 +2075,7 @@ margin-left: 5px; } } .chapter { color: #b7b7b7; margin: 5px 5px 5px 14px; @@ -2166,10 +2088,12 @@ padding: 0 5px; } } .noteText { margin: 10px 10px 10px 15px; border-radius: 3px; padding: 2px 5px; .con { max-height: 65px; display: -webkit-box; @@ -2180,8 +2104,10 @@ } } } .allSearch { padding: 20px; .allSearchList { .searchItem { margin: 15px; @@ -2189,10 +2115,12 @@ border-radius: 10px; padding: 10px; display: flex; .index { line-height: 24px; width: 25px; } .searchCon { flex: 1; width: 240px; @@ -2209,7 +2137,8 @@ } } } .settingBox{ .settingBox { margin-bottom: 50px !important; } } src/views/readerPages/webHome.vue
@@ -119,8 +119,12 @@ <div>默认资源</div> <div :class="resourceType == 'default' ? 'text' : 'line'"></div> </div> <hr class="hr" v-if="userInfo.role == 'Teacher'"/> <div class="tabItem hover" @click="selectResourceType('teacher')" v-if="userInfo.role == 'Teacher'"> <hr class="hr" v-if="userInfo.role == 'Teacher'" /> <div class="tabItem hover" @click="selectResourceType('teacher')" v-if="userInfo.role == 'Teacher'" > <div>教师资源</div> <div :class="resourceType == 'teacher' ? 'text' : 'line'"></div> </div> @@ -585,14 +589,19 @@ </div> <!-- 题库底部收藏夹和错题集 --> <ul class="question-bottom" v-if="activeMenu == '题库'"> <li @click="selectExercisesType('collection')" v-if="bookConfig.textbookComponents.indexOf('A434F2C0') > -1"> <div><img :src="shouCang" class="hover" /></div> <li @click="selectExercisesType('collection')" v-if="bookConfig.textbookComponents.indexOf('A434F2C0') > -1" > <div><img :src="shouCang" class="hover" /></div> <div>收藏夹</div> </li> <li @click="selectExercisesType('wrong')" v-if="bookConfig.textbookComponents.indexOf('AFC1A288') > -1"> <div><img :src="cuoTi" class="hover" /></div> <li @click="selectExercisesType('wrong')" v-if="bookConfig.textbookComponents.indexOf('AFC1A288') > -1" > <div><img :src="cuoTi" class="hover" /></div> <div>错题本</div> </li> </ul> <!-- 菜单内容收起 --> @@ -660,11 +669,18 @@ <div class="watch-box" v-if="pomodoroRef && pomodoroRef.isShow" :style="{ top:position.x + 'px', left:position.y + 'px'}" :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> <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> @@ -821,7 +837,9 @@ </div> </div> <div class="flex1"> <div :class="toolSelectData.graphType == 'rotundity' ? 'acitveGraphType' : ''"> <div :class="toolSelectData.graphType == 'rotundity' ? 'acitveGraphType' : ''" > <div class="rotundity hover" @click="graphSelect('rotundity')"></div> </div> </div> @@ -831,7 +849,9 @@ </div> </div> <div class="flex1"> <div :class="toolSelectData.graphType == 'lineSegment' ? 'acitveGraphType' : ''"> <div :class="toolSelectData.graphType == 'lineSegment' ? 'acitveGraphType' : ''" > <div class="lineSegment hover" @click="graphSelect('lineSegment')">/</div> </div> </div> @@ -1285,6 +1305,77 @@ </div> </el-dialog> <el-dialog title="名词索引" align-center v-model="nounIndexVisible" width="80%" class="myAnserDialogs" > <div class="nounBox"> <div class="leftBox"> <ul> <li v-for="item in nounIndexData" class="itemIndex" :class="{ activeNoun: item == activeNoun }" :key="item" @click="clickNounIndex(item)" > {{ item }} </li> </ul> </div> <div class="rightBox"> <div class="searchBox"> <el-input v-model="nounIndexKeyWords" placeholder="请输入搜索关键字" style="width: 70%" > <template #append> <el-button @click="searchNounIndex" :icon="Search" /> </template> </el-input > <el-select v-model="nounState" class="m-2" placeholder="Select" size="large" style="width: 240px" > <el-option v-for="item in nounOption" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </div> <div class="collapseBox"> <el-collapse v-model="activeNames" @change="handleChange"> <el-collapse-item :name="index + 1" v-for="(item, index) in temp_nounIndexList" :key="index"> <template #title> <div class="collapseTitle"> <div class="titleName"> {{ item.name + `(${item.english})` }} </div> <div class="pageInfoBox"> <div class="pageItem" @click.stop="toPage(citem)" v-for="(citem, cindex) in item.pageInfo" :key="cindex"> <el-icon><Position /></el-icon> {{citem}} </div> </div> </div> </template> <div style="padding: 10px"> {{ item.explain }} </div> </el-collapse-item> </el-collapse> </div> </div> </div> </el-dialog> <el-dialog title="GGB函数工具" align-center v-model="functionVisible" @@ -1359,6 +1450,7 @@ const { formatTime } = useFormatData() const MG: any = inject('MG') const toolClass = inject('toolClass') import { Search } from '@element-plus/icons-vue' //获取路由器 let router = useRouter() //获取当前路由的信息 @@ -1470,7 +1562,7 @@ import { loadMicroApp } from 'qiankun' import { microApps } from '@/child.ts' import { open } from 'fs' import { digitalTextbooks, tokenKey} from '@/assets/js/config.ts' import { digitalTextbooks, tokenKey } from '@/assets/js/config.ts' let token = localStorage.getItem(tokenKey) const canvasWith = ref(800) const canvasheight = ref(3000) @@ -1485,7 +1577,47 @@ const bookInfo = ref() const isBuy = ref(false) const tryPageCount = ref(0) const nounIndexKeyWords = ref('') const searchText = ref() const nounIndexData = reactive([ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ]) const searchNounIndex = () => { console.log(nounIndexKeyWords.value); if (nounIndexKeyWords.value) { temp_nounIndexList.value = temp_nounIndexList.value.filter(item => item.name.toLowerCase().includes(nounIndexKeyWords.value.toLowerCase())) }else{ temp_nounIndexList.value = nounIndexList.value } } onMounted(() => { if (token) { getUserInfo() @@ -1493,6 +1625,7 @@ if (localStorage.getItem('bookId')) { getBookInfo() } temp_nounIndexList.value = nounIndexList.value setTimeout(() => { canvasWith.value = document.querySelector('.content-box').offsetWidth canvasheight.value = document.querySelector('.content-box').offsetHeight @@ -1669,7 +1802,7 @@ } } MG.store.getProductList(obj).then((res) => { if(res.datas.length > 0){ if (res.datas.length > 0) { bookInfo.value = res.datas[0] if (res.datas[0].purchasedSaleMethodIdList.indexOf(res.datas[0].defaultSaleMethodId) > -1) { isBuy.value = true @@ -1677,7 +1810,7 @@ isBuy.value = false } tryPageCount.value = Number(res.datas[0].probationPage) }else{ } else { tryPageCount.value = 0 } }) @@ -1845,6 +1978,16 @@ name: '番茄闹钟', icon: fanqiezhong, isShow: bookConfig.value.textbookComponents.indexOf('E4DC9777') > -1 }, { name: '待办事项', icon: daiban, isShow: bookConfig.value.textbookComponents.indexOf('FA3A4284') > -1 }, { name: '名词索引', icon: ziyuan, isShow: true } // { // name: '番茄闹钟', @@ -2004,6 +2147,40 @@ const playIndex = ref(null) //音频播放 const audioPlayer = ref(null) const collectResourceList = ref([]) const clickNounIndex = (value) => { activeNoun.value = value } const temp_nounIndexList = ref([]) const nounIndexList = ref( [ { name: '鞍背', english: 'dorsum sellae', pageInfo: ['p36' ,'p93'], explain: '鞍背是马背的一部分,位于马背的前部,是马背的支撑部分。鞍背的形状和质地对马的舒适性和骑乘体验有很大影响。' }, { name: '鞍膈', english: 'diaphragma sellae', pageInfo: ['p36'], explain: '鞍膈是马背的一部分,位于马背的前部,是马背的支撑部分。鞍膈的形状和质地对马的舒适性和骑乘体验有很大影响。' }, { name: '鞍状关节', english: 'saddle joint', pageInfo: ['p36'], explain: '鞍状关节是马背的一部分,位于马背的前部,是马背的支撑部分。鞍状关节的形状和质地对马的舒适性和骑乘体验有很大影响。' } ] ) const getResourceData = () => { if (token) { imgPreviewList.value = [] @@ -2272,7 +2449,11 @@ // } else if (data.resourcePath) { // window.open(bookConfig.value.resourceUrl + '/' + data.resourcePath) // } } else if (data.resourceType == 'PPT' || data.resourceType == 'PDF' || data.resourceType == 'WORD') { } else if ( data.resourceType == 'PPT' || data.resourceType == 'PDF' || data.resourceType == 'WORD' ) { let md5 = data.md5 let dataList = [] MG.file @@ -2342,6 +2523,12 @@ if (window.qiankunState && window.qiankunState.gotoPage) { window.qiankunState.gotoPage(Number(data.chapterNum), Number(data.pagination)) } } const toPage = (data) => { nounIndexVisible.value = false window.qiankunState.gotoPage(1, 4) } //资源类型选择默认/教师 @@ -2708,6 +2895,13 @@ notesColor: 'all' //笔记颜色 }) const nounOption = [ { label: '显示名词解释', key: 'showExplain', value: true }, { label: '隐藏名词解释', key: 'hideExplain', value: false } ] const nounState = ref(true) const activeNoun = ref('a') const settingForm = reactive({ fontSizeList: [ { @@ -2872,7 +3066,7 @@ }) } listLoading.value = false }else{ } else { listLoading.value = false } } @@ -2960,6 +3154,7 @@ type pomodoroType = InstanceType<typeof Pomodoro> const baiduVisible = ref(false) const wendaVisible = ref(false) const nounIndexVisible = ref(false) const cidianVisible = ref(false) const functionVisible = ref(false) const siweiVisble = ref(false) @@ -2973,15 +3168,17 @@ open: true }) const resourceUrl = ref('') const aiQuestion = ref("") const aiQuestion = ref('') const selectTeachTools = (item: any) => { if (token) { activeTool.value = item.name switch (item.name) { case 'AI智能问答': aiQuestion.value = "" aiQuestion.value = '' wendaVisible.value = true aiQuestion.value = bookConfig.value.aiQuestion ? bookConfig.value.aiQuestion : "https://yiyan.baidu.com/" aiQuestion.value = bookConfig.value.aiQuestion ? bookConfig.value.aiQuestion : 'https://yiyan.baidu.com/' break case 'GGB函数工具': functionVisible.value = true @@ -3003,6 +3200,9 @@ calculatorVisble.value = true case '番茄闹钟': pomodoroRef.value.setDialogVisable(true) break case '名词索引': nounIndexVisible.value = true break } } else { @@ -3098,8 +3298,8 @@ canvasShow.value = true toolSelectData.activeTool = 'huabi' canvasBox = new fabric.Canvas('canvasRef') canvasBox.setZoom(1); // 设置画布缩放比例为1 canvasBox.absolutePan({ x: 0, y: 0 }); canvasBox.setZoom(1) // 设置画布缩放比例为1 canvasBox.absolutePan({ x: 0, y: 0 }) break case '白板': whiteBoard.value = true @@ -3198,10 +3398,10 @@ //画笔颜色选择 const lineColorSelect = (item) => { toolSelectData.lineColorActive = item.key if ((toolSelectData.activeTool == 'huabi')) { if (toolSelectData.activeTool == 'huabi') { canvasBox.freeDrawingBrush.color = item.key } if ((toolSelectData.activeTool == 'wenzi')) { if (toolSelectData.activeTool == 'wenzi') { textBox.fill = toolSelectData.lineColorActive } } @@ -4508,8 +4708,8 @@ // 番茄钟移动 const isMove = ref<boolean>(false) const position = reactive({x:100,y:100}) const dragOffset = reactive({x:0,y:0}) 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 @@ -5145,13 +5345,13 @@ border-radius: 10px; background-color: #f9f9f9; text-align: center; padding-top:10px; padding-top: 10px; // display: flex; // justify-content: center; // align-items: center; img{ width:20px; height:20px; img { width: 20px; height: 20px; } } } @@ -5718,7 +5918,7 @@ .wendabox { width: 100%; height: 82vh; padding:20px; padding: 20px; iframe { width: 100%; @@ -5860,4 +6060,75 @@ width: 100%; height: 800px; } .nounBox { display: flex; padding: 10px; height: 82vh; width: 100%; .leftBox { width: 50px; height: 100%; border: 1px solid #ccc; overflow-y: scroll; } } .leftBox::-webkit-scrollbar { display: none; /* 对于Chrome, Safari, Edge */ } .itemIndex { width: 100%; height: 50px; text-align: center; line-height: 50px; border-bottom: 1px solid #ccc; } .itemIndex:last-child { border-bottom: none; } .activeNoun { background-color: #0093ff; color: #fff; } .rightBox { width: calc(100% - 50px); border: 1px solid #ccc; padding: 10px; .searchBox { display: flex; justify-content: space-between; } } .rightBox { width: calc(100% - 50px); border: 1px solid #ccc; padding: 10px; .searchBox { display: flex; justify-content: space-between; } } .collapseBox{ margin-top: 20px; padding: 10px 20px; } .collapseTitle { display: flex; justify-content: space-between; padding: 5px; } .pageInfoBox{ display: flex; justify-content: space-between; } .pageItem{ margin-right: 10px; text-align: center; } .titleName:hover { color: #0093ff; } .pageItem:hover { color: #0093ff; } </style>