Merge branch 'main' into lyc-dev

This commit is contained in:
lyc 2024-09-04 13:46:36 +08:00
commit 28a815169d
13 changed files with 94 additions and 45 deletions

View File

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = AIx数字平台 VITE_APP_TITLE = AIx数字平台(测试版)
# 生产环境配置 # 生产环境配置
VITE_APP_ENV = 'production' VITE_APP_ENV = 'production'

View File

@ -34,10 +34,10 @@
"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",
"im_electron_sdk": "^8.0.5904",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"jsondiffpatch": "0.6.0", "jsondiffpatch": "0.6.0",
"im_electron_sdk": "^8.0.5904",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"pdfjs-dist": "4.4.168", "pdfjs-dist": "4.4.168",
"pinia": "^2.1.7", "pinia": "^2.1.7",

View File

@ -42,19 +42,23 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
let filePath = appRootFilePath + fileNewName let filePath = appRootFilePath + fileNewName
let uploadId = null let uploadId = null
let isOn = false let isOn = false
let lastMTime = fs.statSync(filePath).mtime.getTime()
console.log(lastMTime)
setInterval(() => { setInterval(() => {
getFileMD5(filePath).then((md5New) => { getFileMsg(filePath).then((msg) => {
if (md5New !== md5) { if (msg !== lastMTime) {
md5 = md5New lastMTime = msg
if (uploadId) { if (uploadId) {
clearTimeout(uploadId) clearTimeout(uploadId)
} }
if (isOn === false) { if (isOn === false) {
console.log(fileNewName)
e.reply('listen-file-change-on' + fileNewName) e.reply('listen-file-change-on' + fileNewName)
isOn = true isOn = true
} }
//倒数十秒提交更改,十秒之内有继续修改则重置倒数 //倒数十秒提交更改,十秒之内有继续修改则重置倒数
uploadId = setTimeout(() => { uploadId = setTimeout(() => {
console.log(223)
//执行更新,上传文件 //执行更新,上传文件
let formData = new FormData() let formData = new FormData()
formData.append('id', id) formData.append('id', id)
@ -77,12 +81,19 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
console.error('Error uploading file:', err) console.error('Error uploading file:', err)
} }
}) })
}, 20000) }, 5000)
} }
}) })
}, 10000) }, 1000)
}) })
function getFileMsg(path) {
return new Promise((resolve, reject) => {
const stats = fs.statSync(path)
return resolve(stats.mtime.getTime())
})
}
function getFileMD5(path) { function getFileMD5(path) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.readFile(path, (err, dataFile) => { fs.readFile(path, (err, dataFile) => {
@ -121,13 +132,14 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' }) e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' })
return return
} }
getFileMD5(filePath).then((localMd5) => { getFileMsg(filePath).then((msg) => {
if (localMd5 === md5) { let time = new Date(lastModifyTime).getTime();
msg = parseInt(msg/1000)*1000;
if (msg == time) {
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: false, type: '' }) e.reply('is-async-local-file-reply' + fileNewName, { isAsync: false, type: '' })
} else { } else {
const stats = fs.statSync(filePath) const stats = fs.statSync(filePath)
//如果线上时间大于线下时间,就需要从线上下载,否则则需要上传 //如果线上时间大于线下时间,就需要从线上下载,否则则需要上传
let time = new Date(lastModifyTime)
if (time > stats.mtime.getTime()) { if (time > stats.mtime.getTime()) {
e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' }) e.reply('is-async-local-file-reply' + fileNewName, { isAsync: true, type: 'down' })
} else if (time < stats.mtime.getTime()) { } else if (time < stats.mtime.getTime()) {

View File

@ -141,6 +141,11 @@ async function createLinkWin(data) {
.then(() => {}) .then(() => {})
.catch((error) => {}) .catch((error) => {})
data.fullPath = data.fullPath.replaceAll('//', '/') data.fullPath = data.fullPath.replaceAll('//', '/')
if (data.fullPath.indexOf('?') !== -1) {
data.fullPath += '&urlSource=smarttalk'
}else {
data.fullPath += '?urlSource=smarttalk'
}
linkWin[data.key].loadURL(data.fullPath) linkWin[data.key].loadURL(data.fullPath)
linkWin[data.key].once('ready-to-show', () => { linkWin[data.key].once('ready-to-show', () => {

View File

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>AIx智慧教育</title> <title>%VITE_APP_TITLE%</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<!-- <meta <!-- <meta
http-equiv="Content-Security-Policy" http-equiv="Content-Security-Policy"

View File

@ -68,6 +68,18 @@ function stateSyncInit(wid, store) {
ipcRenderer.invoke('pinia-state-init', wid, storeName, curJson) ipcRenderer.invoke('pinia-state-init', wid, storeName, curJson)
} }
// 监听session数据变化
function sessionWatch(store) {
const unsubscribe = sessionStore.onDidAnyChange((newV, oldV) => {
if (newV !== oldV) {
console.log('session-change', newV, oldV)
// 通知主线程更新
// ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
}
})
// unsubscribe() 取消监听
}
// 同步数据-接收主线程消息 // 同步数据-接收主线程消息
function stateChange(store) { function stateChange(store) {
const storeName = store.$id const storeName = store.$id
@ -124,5 +136,10 @@ const filterByKey = (obj, key, value) => {
} }
return res; return res;
} }
// 获取对象值
const getObjValue = (obj, key) => {
}
// 对象克隆 // 对象克隆
const objClone = (obj) => JSON.parse(JSON.stringify(obj)) const objClone = (obj) => JSON.parse(JSON.stringify(obj))

View File

@ -11,14 +11,14 @@ 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 Store = isNode?require('electron-store'):null // 持久化存储
import store from './store' import store from './store'
// 常用变量 // 常用变量
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':''
// const toolState = useToolState() // 获取store状态
const appPath = isNode?Remote.app.getAppPath():'' // 应用目录
// 暴露Remote中的属性 // 暴露Remote中的属性
export const ipcMain = Remote?.ipcMain || {} export const ipcMain = Remote?.ipcMain || {}
@ -110,6 +110,7 @@ export const createWindow = async (type, data) => {
resizable: false, // 禁止窗口大小缩放 resizable: false, // 禁止窗口大小缩放
transparent: true, // 设置透明 transparent: true, // 设置透明
alwaysOnTop: true, // 窗口是否总是显示在其他窗口之前 alwaysOnTop: true, // 窗口是否总是显示在其他窗口之前
type: 'toolbar', // 创建的窗口类型为工具栏窗口
// parent: mainWin, // 父窗口 // parent: mainWin, // 父窗口
// autoClose: true, // 关闭窗口后自动关闭 // autoClose: true, // 关闭窗口后自动关闭
} }
@ -141,8 +142,8 @@ export const createWindow = async (type, data) => {
const option = data.option||{} const option = data.option||{}
const defOption = { const defOption = {
frame: false, // 要创建无边框窗口 frame: false, // 要创建无边框窗口
resizable: true, // 禁止窗口大小缩放 resizable: true, // 禁止窗口大小缩放
alwaysOnTop: false, // 窗口是否总是显示在其他窗口之前 alwaysOnTop: false, // 窗口是否总是显示在其他窗口之前
} }
data.isConsole = true // 是否开启控制台 data.isConsole = true // 是否开启控制台
data.option = {...defOption, ...option} data.option = {...defOption, ...option}
@ -179,8 +180,7 @@ export function toolWindow({url, isConsole, isWeb=true, option={}}) {
return new Promise((resolve) => { return new Promise((resolve) => {
const config = { const config = {
width, height, width, height,
type: 'toolbar', // 创建的窗口类型为工具栏窗口 icon: path.join(appPath, '/resources/logo2.ico'),
// icon: path.join(__dirname, '../../resources/logo2.ico'),
webPreferences: { webPreferences: {
preload: path.join(API.preloadPath, '/index.js'), preload: path.join(API.preloadPath, '/index.js'),
sandbox: false, sandbox: false,
@ -221,6 +221,7 @@ export function toolWindow({url, isConsole, isWeb=true, option={}}) {
* @param {*} win 窗口对象 * @param {*} win 窗口对象
*/ */
const eventHandles = (type, win) => { const eventHandles = (type, win) => {
const toolState = useToolState() // 获取store状态
const winAll = Remote.BrowserWindow.getAllWindows() const winAll = Remote.BrowserWindow.getAllWindows()
const mainWin = winAll.find(o => o.type == 'main') // 主窗口对象 const mainWin = winAll.find(o => o.type == 'main') // 主窗口对象
// 公共方法 // 公共方法
@ -250,6 +251,9 @@ const eventHandles = (type, win) => {
Remote.ipcMain.removeHandler('tool-sphere:set:ignore', setIgnore) Remote.ipcMain.removeHandler('tool-sphere:set:ignore', setIgnore)
Remote.ipcMain.removeHandler('tool-sphere:reset') Remote.ipcMain.removeHandler('tool-sphere:reset')
// Remote.ipcMain.removeAllListeners() // 移除所有监听事件 // Remote.ipcMain.removeAllListeners() // 移除所有监听事件
// 设置状态(再次设置-防止未设置到)
if(toolState.isToolWin) toolState.isToolWin = false
// sessionStore.set('isToolWin', false)
} }
} }
publicMethods(on) // 加载公共方法 publicMethods(on) // 加载公共方法
@ -269,6 +273,8 @@ const eventHandles = (type, win) => {
const on = { const on = {
onClosed: () => { onClosed: () => {
Remote.ipcMain.removeHandler('open-PDF:minimize') Remote.ipcMain.removeHandler('open-PDF:minimize')
// 设置状态(再次设置-防止未设置到)
if(toolState.isPdfWin) toolState.isPdfWin = false
} }
} }
publicMethods(on) // 加载公共方法 publicMethods(on) // 加载公共方法

View File

@ -31,6 +31,7 @@ import { getSelfReserv } from '@/api/classManage'
import ReservItem from '@/views/classManage/reserv-item.vue' import ReservItem from '@/views/classManage/reserv-item.vue'
import Reserv from '@/views/prepare/container/reserv.vue' import Reserv from '@/views/prepare/container/reserv.vue'
import { useToolState } from '@/store/modules/tool' import { useToolState } from '@/store/modules/tool'
import { sessionStore } from '@/utils/tool'
const reservDialog = ref(null) const reservDialog = ref(null)
const tabOptions = ref(['进行中', '已结束']) const tabOptions = ref(['进行中', '已结束'])
const tabActive = ref('进行中') const tabActive = ref('进行中')
@ -51,21 +52,27 @@ const doneDataList = computed(() => {
return item.status === '已结束' return item.status === '已结束'
}) })
}) })
//
const getData = () => {
getSelfReserv().then((res) => {
const list = res.data || []
list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
dataList.value = list
})
}
const toolStore = useToolState() const toolStore = useToolState()
watch( watch(
() => [dataList,toolStore.isToolWin], () => [dataList,toolStore.isToolWin],
() => { () => {
console.log('====',toolStore)
setTimeout(()=>{ setTimeout(()=>{
getSelfReserv().then((res) => { getData() //
dataList.value = [...res.data]
})
},300) },300)
} }
) )
onMounted(() => { onMounted(() => {
getSelfReserv().then((res) => { getData() //
dataList.value = res.data
})
}) })
</script> </script>

View File

@ -20,14 +20,14 @@
</div> </div>
</div> </div>
<div class="class-reserv-item-tool"> <div class="class-reserv-item-tool">
<el-button v-if="item.status !== '已结束'" type="primary" @click="startClassR(item)" <el-button v-if="item.status !== '已结束'" :disabled="toolStore.isToolWin" type="primary" @click="startClassR(item)"
>上课</el-button >{{item.status == '上课中'?'上课中':'上课'}}</el-button
> >
<el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button> <el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>
<!-- <el-button v-if="item.status === '上课中'" type="info" @click="endClassR(item)" <!-- <el-button v-if="item.status === '上课中'" type="info" @click="endClassR(item)"
>下课</el-button >下课</el-button
>--> >-->
<el-button type="danger" @click="deleteReserv">删除</el-button> <el-button v-if="item.status!='上课中'" type="danger" @click="deleteReserv">删除</el-button>
</div> </div>
</div> </div>
</template> </template>
@ -46,6 +46,7 @@ const props = defineProps({
} }
}) })
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
const toolStore = useToolState() // -tool
const openEdit = () => { const openEdit = () => {
emit('openEdit', props.item) emit('openEdit', props.item)
} }
@ -61,18 +62,20 @@ const deleteReserv = () => {
}) })
} }
const startClassR = (item) => { const startClassR = (item) => {
startClass(item.id).then((res) => { // startClass(item.id).then((res) => {
if (res.data === true) { // if (res.data === true) {
item.status = '上课中' // item.status = ''
openLesson() // openLesson()
} // }
}) // })
item.status = '上课中'
openLesson()
} }
// const toolStore = useToolState() // const toolStore = useToolState()
let wins = null; let wins = null;
// - // -
const openLesson = () => { const openLesson = () => {
startClass(props.item.id) // startClass(props.item.id)
listEntpcourse({ listEntpcourse({
evalid: props.item.ex2, evalid: props.item.ex2,
edituserid: useUserStore().user.userId, edituserid: useUserStore().user.userId,

View File

@ -13,7 +13,7 @@
<div> <div>
<div class="studentContent"> <div class="studentContent">
<template v-if="studentList.length > 0"> <template v-if="studentList.length > 0">
<div v-for="(item,index) in studentList" :key="index" style="width: 10%" @click="addStudent(item.studentid)"> <div v-for="(item,index) in studentList" :key="index" style="width: 10%">
<div> <div>
<el-avatar <el-avatar
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"

View File

@ -246,12 +246,12 @@ export default {
fileType: item.fileType fileType: item.fileType
}) })
ipcRenderer.on('listen-file-change-on' + item.fileNewName, () => { ipcRenderer.on('listen-file-change-on' + item.fileNewName, () => {
item.async = 'on' items.async = 'on'
}) })
ipcRenderer.on('listen-file-change-success' + item.fileNewName, (e, { data, md5 }) => { ipcRenderer.on('listen-file-change-success' + item.fileNewName, (e, { data, md5 }) => {
item.fileSize = data.fileSize items.fileSize = data.fileSize
item.md5 = md5 items.md5 = md5
item.async = true items.async = true
}) })
} }
}) })

View File

@ -20,11 +20,11 @@
</div> </div>
<el-button <el-button
:type="!curClassReserv.id ? 'info' : 'primary'" :type="!curClassReserv.id ? 'info' : 'primary'"
:disabled="!curClassReserv.id" :disabled="!curClassReserv.id||toolStore.isToolWin"
class="to-class-btn" class="to-class-btn"
@click="openLesson" @click="openLesson"
> >
<label><i class="iconfont icon-lingdang"></i>上课</label> <label><i class="iconfont icon-lingdang"></i>{{curClassReserv.status=='上课中'?'上课中':'上课'}}</label>
<label>{{ curClassReserv.classDay }} {{ getWeekday1(curClassReserv.classDay) }}</label> <label>{{ curClassReserv.classDay }} {{ getWeekday1(curClassReserv.classDay) }}</label>
<label>{{ curClassReserv.startTime }}-{{ curClassReserv.endTime }}</label> <label>{{ curClassReserv.startTime }}-{{ curClassReserv.endTime }}</label>
</el-button> </el-button>
@ -630,6 +630,7 @@ export default {
cursor: pointer !important; cursor: pointer !important;
} }
& > :deep(span) { & > :deep(span) {
pointer-events: none;
flex-direction: column !important; flex-direction: column !important;
font-size: 12px; font-size: 12px;
} }

View File

@ -83,9 +83,6 @@ const btnList = [ // 工具栏按钮列表
// === === // === ===
onMounted(async() => { onMounted(async() => {
if (!electron) return // if (!electron) return //
// console.log(sessionStore)
// window.test = sessionStore
// window.test1 = toolStore
getClassInfo() // ex3 getClassInfo() // ex3
resetStatus() // - resetStatus() // -
}) })
@ -96,10 +93,11 @@ const getClassInfo = async () => {
const { data } = await classManageApi.getClassInfo(classObj.id) const { data } = await classManageApi.getClassInfo(classObj.id)
classObj.data = data classObj.data = data
// id // id
let timGroupId = data?.ex3 || '' let timGroupId = data?.ex3 || '@TGS#36AICW6O6'
console.log('获取群ID:', timGroupId) console.log('获取群ID:', timGroupId)
const chat = await imChatRef.value?.initImChat(timGroupId) // im-chat const chat = await imChatRef.value?.initImChat(timGroupId) // im-chat
if (!timGroupId) timGroupId = chat?.timGroupId if (!timGroupId) timGroupId = chat?.timGroupId
if (!timGroupId) return ElMessage.error('房间创建-失败')
classManageApi.startClass(classObj.id, timGroupId) // classManageApi.startClass(classObj.id, timGroupId) //
} }
// tab-change // tab-change