Merge branch 'main' into zhuhao_dev
This commit is contained in:
commit
0e5ca5eff2
|
@ -13,11 +13,6 @@ asarUnpack:
|
||||||
win:
|
win:
|
||||||
executableName: AIx
|
executableName: AIx
|
||||||
icon: resources/logo2.ico
|
icon: resources/logo2.ico
|
||||||
extraFiles:
|
|
||||||
- from: ./node_modules/im_electron_sdk/lib/
|
|
||||||
to: ./resources
|
|
||||||
filter:
|
|
||||||
- '**/*'
|
|
||||||
nsis:
|
nsis:
|
||||||
oneClick: false
|
oneClick: false
|
||||||
allowToChangeInstallationDirectory: true
|
allowToChangeInstallationDirectory: true
|
||||||
|
@ -50,3 +45,9 @@ publish:
|
||||||
url: https://file.ysaix.com:7868/src/assets/smarttalk/
|
url: https://file.ysaix.com:7868/src/assets/smarttalk/
|
||||||
electronDownload:
|
electronDownload:
|
||||||
mirror: https://npmmirror.com/mirrors/electron/
|
mirror: https://npmmirror.com/mirrors/electron/
|
||||||
|
# 额外依赖打包到输出目录
|
||||||
|
extraFiles:
|
||||||
|
- from: ./node_modules/im_electron_sdk/lib/
|
||||||
|
to: ./resources
|
||||||
|
filter:
|
||||||
|
- '**/*'
|
||||||
|
|
14
package.json
14
package.json
|
@ -30,6 +30,7 @@
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"electron-dl-manager": "^3.0.0",
|
"electron-dl-manager": "^3.0.0",
|
||||||
"electron-log": "^5.1.7",
|
"electron-log": "^5.1.7",
|
||||||
|
"electron-store": "8.0.0",
|
||||||
"electron-updater": "^6.1.7",
|
"electron-updater": "^6.1.7",
|
||||||
"element-plus": "^2.7.6",
|
"element-plus": "^2.7.6",
|
||||||
"fabric": "^5.3.0",
|
"fabric": "^5.3.0",
|
||||||
|
@ -63,18 +64,5 @@
|
||||||
"vite-plugin-windicss": "^1.9.3",
|
"vite-plugin-windicss": "^1.9.3",
|
||||||
"vue": "^3.4.30",
|
"vue": "^3.4.30",
|
||||||
"windicss": "^3.5.6"
|
"windicss": "^3.5.6"
|
||||||
},
|
|
||||||
"build": {
|
|
||||||
"win": {
|
|
||||||
"extraFiles": [
|
|
||||||
{
|
|
||||||
"from": "./node_modules/im_electron_sdk/lib/",
|
|
||||||
"to": "./resources",
|
|
||||||
"filter": [
|
|
||||||
"**/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
|
@ -3,13 +3,17 @@ import { join } from 'path'
|
||||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||||
import icon from '../../resources/icon.png?asset'
|
import icon from '../../resources/icon.png?asset'
|
||||||
import File from './file'
|
import File from './file'
|
||||||
import chat from './chat' // chat封装
|
import chat from './chat' // chat封装
|
||||||
|
import Store from './store' // Store封装
|
||||||
|
import updateInit from './update'
|
||||||
|
|
||||||
// 代理 electron/remote
|
// 代理 electron/remote
|
||||||
// 第一步:引入remote
|
// 第一步:引入remote
|
||||||
import remote from '@electron/remote/main'
|
import remote from '@electron/remote/main'
|
||||||
// 第二步: 初始化remote
|
// 第二步: 初始化remote
|
||||||
remote.initialize()
|
remote.initialize()
|
||||||
import updateInit from './update'
|
// 持久化数据-初始化
|
||||||
|
Store.initialize()
|
||||||
|
|
||||||
File({ app, shell, BrowserWindow, ipcMain })
|
File({ app, shell, BrowserWindow, ipcMain })
|
||||||
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
|
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* @description 解决 主进程|渲染进程 数据共享
|
||||||
|
*/
|
||||||
|
import Store from 'electron-store' // 持久化存储
|
||||||
|
|
||||||
|
// 设置ipc与渲染器通信
|
||||||
|
Store.initRenderer()
|
||||||
|
|
||||||
|
// 默认共享数据
|
||||||
|
const defaultData = {
|
||||||
|
model: 'select', // 悬浮球-当前模式
|
||||||
|
showBoardAll: false, // 全屏画板-是否显示
|
||||||
|
isPdfWin: false, // pdf窗口是否打开
|
||||||
|
isToolWin: false, // 工具窗口是否打开
|
||||||
|
curSubjectNode: {
|
||||||
|
data: {}, // 当前教材节点 (包含当前教材 单元)
|
||||||
|
querySearch: {} // 查询资源所需参数
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
export function initialize(){
|
||||||
|
const store = new Store({
|
||||||
|
name: 'cache-store', // 存储文件名
|
||||||
|
fileExtension: 'ini', // 文件后缀名
|
||||||
|
encryptionKey: 'Eihrjwi7h104h2Kub423' // 数据加密-防止用户直接改配置
|
||||||
|
})
|
||||||
|
store.clear() // 先清除-所有缓存数据
|
||||||
|
store.set(defaultData) // 初始化-默认数据
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
export default { initialize }
|
|
@ -50,7 +50,7 @@ export function getClassmain(id) {
|
||||||
// 获取小组列表
|
// 获取小组列表
|
||||||
export function listClassgroup(query) {
|
export function listClassgroup(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/education/classgroup/list',
|
url: '/education/classgroup/new/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
|
|
|
@ -163,6 +163,10 @@ const handleNodeClick = (data,node) => {
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
titleName.value = `${useStore.user.edustage}-${useStore.user.edusubject}`
|
titleName.value = `${useStore.user.edustage}-${useStore.user.edusubject}`
|
||||||
treeLoading.value = true
|
treeLoading.value = true
|
||||||
|
//存在查看无课程的情况,两秒后关闭loading框
|
||||||
|
setTimeout(() => {
|
||||||
|
treeLoading.value = false
|
||||||
|
},2000)
|
||||||
})
|
})
|
||||||
//监听数据变化
|
//监听数据变化
|
||||||
watch(() => useThird,() => {
|
watch(() => useThird,() => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<el-tabs v-model="active" class="demo-tabs" @tab-change="handleClick">
|
<el-tabs v-model="active" class="demo-tabs" @tab-change="handleClick">
|
||||||
<template v-for="(item,index) in gradeList" :key="index">
|
<template v-for="(item,index) in gradeList" :key="index">
|
||||||
<el-tab-pane :label="item.label" :name="item.value">
|
<el-tab-pane :label="item.label" :name="item.value" disabled>
|
||||||
<SelectSubject ref="selectSubject" :subjectList="subjectList" @clickTag="getTagId"></SelectSubject>
|
<SelectSubject ref="selectSubject" :subjectList="subjectList" @clickTag="getTagId"></SelectSubject>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</template>
|
</template>
|
||||||
|
@ -24,7 +24,9 @@ const active = ref(1)
|
||||||
const subjectList = ref([])
|
const subjectList = ref([])
|
||||||
//用来获取学科的id
|
//用来获取学科的id
|
||||||
const textbookVersionId = ref(0)
|
const textbookVersionId = ref(0)
|
||||||
|
//不需要切换年级教材了
|
||||||
const handleClick = (tab) => {
|
const handleClick = (tab) => {
|
||||||
|
console.log(tab,'tab')
|
||||||
getSubject(tab)
|
getSubject(tab)
|
||||||
}
|
}
|
||||||
//获取当前学段所有学科
|
//获取当前学段所有学科
|
||||||
|
@ -32,6 +34,7 @@ const getSubject = (value) => {
|
||||||
const currentIndex = gradeList.findIndex(item => item.value === value)
|
const currentIndex = gradeList.findIndex(item => item.value === value)
|
||||||
getSubjects({stage:value}).then(res => {
|
getSubjects({stage:value}).then(res => {
|
||||||
if(res.code === 200){
|
if(res.code === 200){
|
||||||
|
if(res.data.length === 0) return
|
||||||
subjectList.value = res.data.map(item => {
|
subjectList.value = res.data.map(item => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
|
|
|
@ -250,10 +250,10 @@ const onSubmit = (formEl) => {
|
||||||
saveByClassWorkArray({
|
saveByClassWorkArray({
|
||||||
classworkarray: JSON.stringify(ary)
|
classworkarray: JSON.stringify(ary)
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then((res) => {
|
||||||
setLoading.value = false
|
setLoading.value = false
|
||||||
ElMessage.success('操作成功')
|
ElMessage.success('操作成功')
|
||||||
emit('on-success')
|
emit('on-success', res.data)
|
||||||
cloneDialog(formEl)
|
cloneDialog(formEl)
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
class="flex"
|
class="flex"
|
||||||
:style="{'color' : item.color}"
|
:style="{'color' : item.color}"
|
||||||
:class="currentRoute === item.url ? 'active-li' : ''"
|
:class="currentRoute === item.url ? 'active-li' : ''"
|
||||||
@click="handleOutLink(item.url,item.type)"
|
@click="handleOutLink(item.url,item.type, item.name)"
|
||||||
>
|
>
|
||||||
<i :class="item.img"></i>
|
<i :class="item.img"></i>
|
||||||
<span class="text">{{ item.name }}</span>
|
<span class="text">{{ item.name }}</span>
|
||||||
|
@ -57,6 +57,7 @@ import WindowTools from '@/components/window-tools/index.vue'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import routerStore from '@/store/modules/route'
|
import routerStore from '@/store/modules/route'
|
||||||
import outLink from '@/utils/linkConfig'
|
import outLink from '@/utils/linkConfig'
|
||||||
|
|
||||||
const routeHeader = routerStore()
|
const routeHeader = routerStore()
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
@ -64,7 +65,7 @@ const router = useRouter()
|
||||||
const currentRoute = ref('')
|
const currentRoute = ref('')
|
||||||
const dev_api = ref(import.meta.env.VITE_APP_BASE_API)
|
const dev_api = ref(import.meta.env.VITE_APP_BASE_API)
|
||||||
|
|
||||||
const handleOutLink = (path, type) => {
|
const handleOutLink = (path, type, name) => {
|
||||||
if (!path) return
|
if (!path) return
|
||||||
if (type === 'hash') {
|
if (type === 'hash') {
|
||||||
router.push(path)
|
router.push(path)
|
||||||
|
@ -73,6 +74,11 @@ const handleOutLink = (path, type) => {
|
||||||
let configObj = outLink().getBaseData()
|
let configObj = outLink().getBaseData()
|
||||||
let fullPath = configObj.fullPath + path
|
let fullPath = configObj.fullPath + path
|
||||||
fullPath = fullPath.replaceAll('//', '/')
|
fullPath = fullPath.replaceAll('//', '/')
|
||||||
|
const { levelFirstId, levelSecondId } = JSON.parse(localStorage.getItem('unitId'))
|
||||||
|
let unitId = levelSecondId ? levelSecondId :levelFirstId
|
||||||
|
if(name == '教材分析' || name == '高考研究'){
|
||||||
|
fullPath += `?unitId=${unitId}`
|
||||||
|
}
|
||||||
// 通知主进程
|
// 通知主进程
|
||||||
ipcRenderer.send('openWindow', {
|
ipcRenderer.send('openWindow', {
|
||||||
key: path,
|
key: path,
|
||||||
|
|
|
@ -76,3 +76,36 @@ export const toTimeText = (timeStamp, simple) => {
|
||||||
}
|
}
|
||||||
return timeText
|
return timeText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns 当前年-月-日
|
||||||
|
*/
|
||||||
|
export const getCurrentTime = (format)=> {
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
const day = now.getDate().toString().padStart(2, '0');
|
||||||
|
const hours = now.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||||
|
if(format == 'YYYY-MM-DD'){
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
if(format == 'HH:mm'){
|
||||||
|
return `${hours}:${minutes}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} m 指定时间
|
||||||
|
* @returns 指定时间之后的 小时:分钟
|
||||||
|
*/
|
||||||
|
export const getAfterMinutes = (m) => {
|
||||||
|
const now = new Date();
|
||||||
|
const afterMinutes = new Date(now.getTime() + m * 60 * 1000);
|
||||||
|
let hours = afterMinutes.getHours();
|
||||||
|
hours = hours < 10 ? ('0' + hours) : hours
|
||||||
|
let minutes = afterMinutes.getMinutes();
|
||||||
|
minutes = minutes < 10 ? ('0' + minutes) : minutes
|
||||||
|
return `${hours}:${minutes}`;
|
||||||
|
}
|
|
@ -6,12 +6,14 @@
|
||||||
// Remote.app.getAppPath() E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar
|
// Remote.app.getAppPath() E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar
|
||||||
// path.join(__dirname) 根目录 E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar\out\renderer
|
// path.join(__dirname) 根目录 E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar\out\renderer
|
||||||
|
|
||||||
const isNode = typeof require !== 'undefined' // 是否支持node函数
|
const isNode = typeof require !== 'undefined' // 是否支持node函数
|
||||||
const path = isNode?require('path'):{}
|
const path = isNode?require('path'):{}
|
||||||
const Remote = isNode?require('@electron/remote'):{}
|
const Remote = isNode?require('@electron/remote'):{}
|
||||||
const { ipcRenderer } = isNode?require('electron'):window.electron || {}
|
const { ipcRenderer } = isNode?require('electron'):window.electron || {}
|
||||||
const API = isNode?window.api:{} // preload-api
|
const API = isNode?window.api:{} // preload-api
|
||||||
import { useToolState } from '@/store/modules/tool' // 获取store状态
|
import { useToolState } from '@/store/modules/tool' // 获取store状态
|
||||||
|
const Store = isNode?require('electron-store'):null // 持久化存储
|
||||||
|
|
||||||
// 常用变量
|
// 常用变量
|
||||||
const BaseUrl = isNode?process.env['ELECTRON_RENDERER_URL']+'/#':''
|
const BaseUrl = isNode?process.env['ELECTRON_RENDERER_URL']+'/#':''
|
||||||
const isDev = isNode?process.env.NODE_ENV !== 'production':''
|
const isDev = isNode?process.env.NODE_ENV !== 'production':''
|
||||||
|
@ -19,6 +21,12 @@ const toolState = useToolState() // 获取store状态
|
||||||
|
|
||||||
// 暴露Remote中的属性
|
// 暴露Remote中的属性
|
||||||
export const ipcMain = Remote?.ipcMain || {}
|
export const ipcMain = Remote?.ipcMain || {}
|
||||||
|
// 暴露Store存储对象
|
||||||
|
export const store = Store ? new Store({
|
||||||
|
name: 'cache-store', // 存储文件名
|
||||||
|
fileExtension: 'ini', // 文件后缀名
|
||||||
|
encryptionKey: 'Eihrjwi7h104h2Kub423' // 数据加密-防止用户直接改配置
|
||||||
|
}) : {}
|
||||||
/**
|
/**
|
||||||
* 获取静态资源,开发和生产环境
|
* 获取静态资源,开发和生产环境
|
||||||
* @param {*} url
|
* @param {*} url
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
placeholder="请选择日期"
|
placeholder="请选择日期"
|
||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
|
:disabled-date="disabledDate"
|
||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -53,6 +54,8 @@
|
||||||
range-separator="-"
|
range-separator="-"
|
||||||
start-placeholder="开始时间"
|
start-placeholder="开始时间"
|
||||||
end-placeholder="结束时间"
|
end-placeholder="结束时间"
|
||||||
|
:disabled-hours="disabledHours"
|
||||||
|
:disabled-minutes="disabledMinute"
|
||||||
/>
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -81,6 +84,8 @@ import { ref, defineExpose, onMounted, reactive, computed, watch } from 'vue'
|
||||||
import { addSmartClassReserv, updateSmartClassReserv, listClassmain } from '@/api/classManage'
|
import { addSmartClassReserv, updateSmartClassReserv, listClassmain } from '@/api/classManage'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { getCurrentTime, getAfterMinutes } from '@/utils/date'
|
||||||
|
|
||||||
const emit = defineEmits(['addSuccess'])
|
const emit = defineEmits(['addSuccess'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
bookId: {
|
bookId: {
|
||||||
|
@ -143,6 +148,52 @@ const locationOptions = [
|
||||||
const locationMessage = computed(() => {
|
const locationMessage = computed(() => {
|
||||||
return locationOptions.find((item) => item.value === form.type).message
|
return locationOptions.find((item) => item.value === form.type).message
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 设置一个月后的日期不能选择
|
||||||
|
const disabledDate = (time)=> {
|
||||||
|
// 禁用今天之前的日期
|
||||||
|
const today = new Date();
|
||||||
|
if (time.getTime() < today.getTime() - 8.64e7) {
|
||||||
|
// 返回true表示禁用
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 同时禁用超过一个月后的日期
|
||||||
|
const oneMonthLater = new Date(today.getTime() + 30 * 24 * 60 * 60 * 1000);
|
||||||
|
if (time.getTime() > oneMonthLater.getTime()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限制小时-返回被禁选的小时
|
||||||
|
const disabledHours = ()=>{
|
||||||
|
if(getCurrentTime('YYYY-MM-DD') == form.day){
|
||||||
|
const arrs = []
|
||||||
|
for (let i = 0; i < 24; i++) {
|
||||||
|
if (new Date().getHours() <= i) continue;
|
||||||
|
arrs.push(i)
|
||||||
|
}
|
||||||
|
return arrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 限制分-返回被禁选的
|
||||||
|
const disabledMinute = (hour,role) => {
|
||||||
|
if(getCurrentTime('YYYY-MM-DD') == form.day){
|
||||||
|
const arrs = []
|
||||||
|
if(role == 'start'){
|
||||||
|
for (let i = 0; i < 60; i++) {
|
||||||
|
if (new Date().getMinutes() <= i) continue;
|
||||||
|
arrs.push(i)
|
||||||
|
}
|
||||||
|
return arrs;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(form.time[0]) return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const openDialog = (data) => {
|
const openDialog = (data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
updateForm.value = data
|
updateForm.value = data
|
||||||
|
@ -154,6 +205,11 @@ const openDialog = (data) => {
|
||||||
form.resource = data.classList.split(',').map((item) => parseInt(item))
|
form.resource = data.classList.split(',').map((item) => parseInt(item))
|
||||||
form.classRoom = data.classRoom
|
form.classRoom = data.classRoom
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
// 默认当前时间
|
||||||
|
form.day = getCurrentTime('YYYY-MM-DD')
|
||||||
|
form.time = [getCurrentTime('HH:mm'), getAfterMinutes(45)]
|
||||||
|
}
|
||||||
centerDialogVisible.value = true
|
centerDialogVisible.value = true
|
||||||
}
|
}
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
|
|
|
@ -422,7 +422,6 @@ export default {
|
||||||
this.uploadData.levelSecondId = cata[1]
|
this.uploadData.levelSecondId = cata[1]
|
||||||
this.uploadData.levelThirdId = cata[2]
|
this.uploadData.levelThirdId = cata[2]
|
||||||
this.uploadData.textbookId = data.textBook.curBookId
|
this.uploadData.textbookId = data.textBook.curBookId
|
||||||
const toolStore = useToolState()
|
|
||||||
toolStore.curSubjectNode.data = data
|
toolStore.curSubjectNode.data = data
|
||||||
toolStore.curSubjectNode.querySearch = this.uploadData
|
toolStore.curSubjectNode.querySearch = this.uploadData
|
||||||
this.initHomeWork()
|
this.initHomeWork()
|
||||||
|
|
|
@ -70,6 +70,8 @@ const getData = (data) => {
|
||||||
levelSecondId
|
levelSecondId
|
||||||
}
|
}
|
||||||
sourceStore.handleQuery()
|
sourceStore.handleQuery()
|
||||||
|
// 头部 教材分析打开外部链接需要当前章节ID
|
||||||
|
localStorage.setItem('unitId', JSON.stringify({ levelFirstId, levelSecondId}))
|
||||||
}
|
}
|
||||||
const getDataOther = (data) => {
|
const getDataOther = (data) => {
|
||||||
sourceStore.thirdQuery.chapterId = data.chapterId
|
sourceStore.thirdQuery.chapterId = data.chapterId
|
||||||
|
|
|
@ -19,6 +19,7 @@ const emit = defineEmits(['update:modelValue'])
|
||||||
onMounted(async() => {
|
onMounted(async() => {
|
||||||
if (canvasRef.value) {
|
if (canvasRef.value) {
|
||||||
FabricVue.drawConfig.drawColors = ['red']
|
FabricVue.drawConfig.drawColors = ['red']
|
||||||
|
FabricVue.drawConfig.drawWidth = 3
|
||||||
FabricVue.boardConfig.mode = TYPES.ActionMode.OTHER
|
FabricVue.boardConfig.mode = TYPES.ActionMode.OTHER
|
||||||
FabricVue.boardConfig.backgroundColor = 'transparent'
|
FabricVue.boardConfig.backgroundColor = 'transparent'
|
||||||
const option = { freeDrawingCursor: 'default' }
|
const option = { freeDrawingCursor: 'default' }
|
||||||
|
|
|
@ -111,9 +111,10 @@ const closeHomework = async() => {
|
||||||
ipcMsgSend('tool-sphere:set:ignore', true)
|
ipcMsgSend('tool-sphere:set:ignore', true)
|
||||||
}
|
}
|
||||||
// 推送成功
|
// 推送成功
|
||||||
const successHomework = ()=>{
|
const successHomework = (data)=>{
|
||||||
|
// console.log('推送成功', data)
|
||||||
// 发送im消息-推送作业(app|平板)
|
// 发送im消息-推送作业(app|平板)
|
||||||
ipcMsgInvoke('im-chat:msg', curRow.value.id, MsgEnum.HEADS.MSG_0016)
|
ipcMsgInvoke('im-chat:msg', data, MsgEnum.HEADS.MSG_0016)
|
||||||
}
|
}
|
||||||
// 章节目录change
|
// 章节目录change
|
||||||
const changeChapter = async (data)=>{
|
const changeChapter = async (data)=>{
|
||||||
|
|
|
@ -2,17 +2,19 @@
|
||||||
<div class="warp" ref="btnRef" :style="isFold?'min-height:auto;':''">
|
<div class="warp" ref="btnRef" :style="isFold?'min-height:auto;':''">
|
||||||
<slot name="start"></slot>
|
<slot name="start"></slot>
|
||||||
<!-- 工具按钮 -->
|
<!-- 工具按钮 -->
|
||||||
<el-space direction="vertical" v-show="!isFold">
|
<transition name="el-zoom-in-bottom">
|
||||||
<template v-for="(item,index) in list">
|
<el-space direction="vertical" v-show="!isFold">
|
||||||
<slot :name="item.prop" :item="item" :index="index">
|
<template v-for="(item,index) in list">
|
||||||
<div class="c-btn flex flex-col items-center gap-2 p-2" @click.stop="clickHandel(item,$event)">
|
<slot :name="item.prop" :item="item" :index="index">
|
||||||
<i class="iconfont" :class="item.icon" :style="item.style" />
|
<div class="c-btn flex flex-col items-center gap-2 p-2" @click.stop="clickHandel(item,$event)">
|
||||||
<span>{{item.label||item.text||item.name}}</span>
|
<i class="iconfont" :class="item.icon" :style="item.style" />
|
||||||
</div>
|
<span>{{item.label||item.text||item.name}}</span>
|
||||||
</slot>
|
</div>
|
||||||
</template>
|
</slot>
|
||||||
<slot name="append"></slot>
|
</template>
|
||||||
</el-space>
|
<slot name="append"></slot>
|
||||||
|
</el-space>
|
||||||
|
</transition>
|
||||||
<slot name="end">
|
<slot name="end">
|
||||||
<span class="fold" @click="isFold=!isFold" :style="isFold?'margin: 5px;':''">
|
<span class="fold" @click="isFold=!isFold" :style="isFold?'margin: 5px;':''">
|
||||||
{{isFold?'<<<':'>>>'}}
|
{{isFold?'<<<':'>>>'}}
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Drag {
|
||||||
const {cx, cy} = this.getMousePos(e)
|
const {cx, cy} = this.getMousePos(e)
|
||||||
this.x = cx
|
this.x = cx
|
||||||
this.y = cy
|
this.y = cy
|
||||||
|
this.getCurPos() // 被拖拽元素初始坐标
|
||||||
// 手动-触发事件 v-drag-start
|
// 手动-触发事件 v-drag-start
|
||||||
this.el.dispatchEvent(new CustomEvent('v-drag-start', {detail:{drag: this}}))
|
this.el.dispatchEvent(new CustomEvent('v-drag-start', {detail:{drag: this}}))
|
||||||
}
|
}
|
||||||
|
@ -85,12 +86,20 @@ class Drag {
|
||||||
}
|
}
|
||||||
// 获取移动后坐标
|
// 获取移动后坐标
|
||||||
getPos(x, y) {
|
getPos(x, y) {
|
||||||
const w = this.max.w - this.toRound(this.el.clientWidth)
|
// 边界控制:图标元素
|
||||||
const h = this.max.h - this.toRound(this.el.clientHeight)
|
// const w = this.max.w - this.toRound(this.el.clientWidth)
|
||||||
|
// const h = this.max.h - this.toRound(this.el.clientHeight)
|
||||||
|
// 边界控制:整个工具
|
||||||
|
const w = this.max.w - this.toRound(this.handle.clientWidth)
|
||||||
|
const h = this.max.h - this.toRound(this.handle.clientHeight)
|
||||||
x = x < 0 ? 0 : x > w ? w : x
|
x = x < 0 ? 0 : x > w ? w : x
|
||||||
y = y < 0 ? 0 : y > h ? h : y
|
y = y < 0 ? 0 : y > h ? h : y
|
||||||
return { x, y }
|
return { x, y }
|
||||||
}
|
}
|
||||||
|
getCurPos(dom) {
|
||||||
|
const pos = this[dom||'handle']?.getBoundingClientRect()
|
||||||
|
this.data = {left:this.toRound(pos.left), top:this.toRound(pos.top)}
|
||||||
|
}
|
||||||
// 小数转整数
|
// 小数转整数
|
||||||
toRound = v => Math.round(v)
|
toRound = v => Math.round(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,17 +20,19 @@
|
||||||
<el-image :src="logo" draggable="false" />
|
<el-image :src="logo" draggable="false" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tool-btns" v-show="!isFold">
|
<transition name="a-fade">
|
||||||
<el-segmented class="c-btns" v-model="tabActive" :options="btnList" size="large" block
|
<div class="tool-btns" v-if="!isFold">
|
||||||
@change="tabChange">
|
<el-segmented class="c-btns" v-model="tabActive" :options="btnList" size="large" block
|
||||||
<template #default="{item}">
|
@change="tabChange">
|
||||||
<div class="c-btn flex flex-col items-center gap-2 p-2">
|
<template #default="{item}">
|
||||||
<i class="iconfont" :class="item.icon" :style="item.style" />
|
<div class="c-btn flex flex-col items-center gap-2 p-2">
|
||||||
<span>{{item.label}}</span>
|
<i class="iconfont" :class="item.icon" :style="item.style" />
|
||||||
</div>
|
<span>{{item.label}}</span>
|
||||||
</template>
|
</div>
|
||||||
</el-segmented>
|
</template>
|
||||||
</div>
|
</el-segmented>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -41,7 +43,7 @@ import { onMounted, ref, reactive, watchEffect } from 'vue'
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
import { ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||||
import * as classManageApi from '@/api/classManage'
|
import * as classManageApi from '@/api/classManage'
|
||||||
import logo from '@root/resources/icon.png' // logo
|
import logo from '@root/resources/logo.png' // logo
|
||||||
import boardVue from './components/board.vue' // 画板-子组件
|
import boardVue from './components/board.vue' // 画板-子组件
|
||||||
import sideVue from './components/side.vue' // 画板-子组件
|
import sideVue from './components/side.vue' // 画板-子组件
|
||||||
import upvoteVue from './components/upvote.vue' // 点赞-子组件
|
import upvoteVue from './components/upvote.vue' // 点赞-子组件
|
||||||
|
@ -109,6 +111,23 @@ const tabChange = (val) => {
|
||||||
const logoHandle = (e,t) => {
|
const logoHandle = (e,t) => {
|
||||||
if (Date.now() - dragtime.value < 200) {
|
if (Date.now() - dragtime.value < 200) {
|
||||||
isFold.value = !isFold.value
|
isFold.value = !isFold.value
|
||||||
|
setTimeout(() => {
|
||||||
|
// 处理: 工具被拖动到右侧时功能被遮挡
|
||||||
|
const dom = document.querySelector('.tool-bottom-all')
|
||||||
|
const { x } = dom.getBoundingClientRect()
|
||||||
|
const w = window.innerWidth - (470 || 80)
|
||||||
|
// if (x > w) dom.style.left = `${w}px`
|
||||||
|
if (x > w) { // 动画
|
||||||
|
let left = x
|
||||||
|
const animatFn = () => {
|
||||||
|
left-=30
|
||||||
|
if (left < w) left == w
|
||||||
|
dom.style.left = `${left}px`
|
||||||
|
if (left > w) requestAnimationFrame(animatFn)
|
||||||
|
}
|
||||||
|
requestAnimationFrame(animatFn)
|
||||||
|
}
|
||||||
|
}, 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 底部工具栏:移入移出-是否穿透
|
// 底部工具栏:移入移出-是否穿透
|
||||||
|
@ -262,4 +281,15 @@ watchEffect(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.a-fade-leave-active,.a-fade-enter-active{
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.a-fade-enter-from,.a-fade-leave-to{
|
||||||
|
width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.a-fade-enter-to,.a-fade-leave-from{
|
||||||
|
width: 350px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue