Compare commits

..

32 Commits

Author SHA1 Message Date
白了个白 634ae460f3 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk into baigl 2024-09-13 15:32:58 +08:00
yangws e907a1c07a Merge pull request 'fix: 解决资源库报错的问题;' (#204) from yangws into main
Reviewed-on: #204
2024-09-12 16:53:15 +08:00
yangws 1afaed082a fix: 解决资源库报错的问题; 2024-09-12 16:52:47 +08:00
lyc 69362a6153 Merge pull request 'lyc-dev' (#203) from lyc-dev into main 2024-09-12 16:03:56 +08:00
lyc 1da3ca0ee0 Merge branch 'main' into lyc-dev 2024-09-12 16:03:42 +08:00
lyc d4a6f74cfc 首页调整 2024-09-12 16:03:21 +08:00
zouyf f57c67aab2 Merge pull request 'zouyf_dev' (#202) from zouyf_dev into main
Reviewed-on: #202
2024-09-12 15:58:59 +08:00
“zouyf” 63ad74c77f Merge branch 'main' into zouyf_dev 2024-09-12 15:58:28 +08:00
“zouyf” d171117f03 tmp 2024-09-12 15:58:12 +08:00
lyc 0426b85d3f Merge pull request '工作台' (#201) from lyc-dev into main 2024-09-12 15:42:55 +08:00
lyc 17b8ce1dda 工作台 2024-09-12 15:42:43 +08:00
yangws 5778a8955d Merge pull request 'fix: 提示教材没有时选择教材;' (#200) from yangws into main
Reviewed-on: #200
2024-09-12 09:48:40 +08:00
朱浩 e4e23e7508 Merge pull request '排序问题处理' (#199) from zhuhao_dev into main
Reviewed-on: #199
2024-09-12 09:48:14 +08:00
yangws 6a33ea8023 fix: 提示教材没有时选择教材; 2024-09-12 09:47:46 +08:00
朱浩 bc0579fa32 排序问题处理 2024-09-12 09:47:35 +08:00
yangws 3357cf8a78 Merge pull request 'fix: 样式修改,以及第三方资源名称不对应的情况;' (#198) from yangws into main
Reviewed-on: #198
2024-09-12 09:31:57 +08:00
yangws 3fdf500366 fix: 样式修改,以及第三方资源名称不对应的情况; 2024-09-12 09:30:44 +08:00
zhengdegang e985417675 Merge pull request 'zdg' (#197) from zdg into main
Reviewed-on: #197
2024-09-11 20:06:20 +08:00
zdg 1978d1bac1 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk into zdg 2024-09-11 20:05:30 +08:00
zdg b9014b950a 密码找回 2024-09-11 20:05:18 +08:00
lyc 03ecbb1d50 Merge pull request 'ai助手-拖动' (#196) from lyc-dev into main 2024-09-11 16:51:56 +08:00
lyc ec3b978185 ai助手-拖动 2024-09-11 16:50:47 +08:00
zdg 3632beebfa Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk into zdg 2024-09-11 16:17:16 +08:00
zdg f0e87338fb 注册优化,修复 2024-09-11 16:17:05 +08:00
lyc 54266f8a37 Merge pull request '图片' (#195) from lyc-dev into main 2024-09-11 16:05:04 +08:00
lyc 82bed1be03 图片 2024-09-11 16:04:36 +08:00
lyc 8a74f17266 Merge pull request '头部展示学科' (#194) from lyc-dev into main 2024-09-11 15:42:39 +08:00
lyc 40c6e1303b 头部展示学科 2024-09-11 15:39:54 +08:00
yangws ee196b6eb8 Merge pull request 'fix:解决个人中心班级限制问题;' (#193) from yangws into main
Reviewed-on: #193
2024-09-11 14:43:25 +08:00
yangws 6c60cd4442 fix:解决个人中心班级限制问题; 2024-09-11 14:42:48 +08:00
baigl 471d73a224 Merge pull request '作业批阅:新增空列表展示与loading加载效果' (#192) from baigl into main
Reviewed-on: #192
2024-09-11 14:30:31 +08:00
baigl d4b1e547de Merge pull request 'baigl' (#191) from baigl into main
Reviewed-on: #191
2024-09-11 11:29:52 +08:00
19 changed files with 449 additions and 237 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "aix-win", "name": "aix-win",
"version": "1.2.0", "version": "1.2.2",
"description": "An Electron application with Vue", "description": "An Electron application with Vue",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "example.com", "author": "example.com",
@ -29,6 +29,7 @@
"@vue-office/excel": "^1.7.11", "@vue-office/excel": "^1.7.11",
"@vue-office/pdf": "^2.0.2", "@vue-office/pdf": "^2.0.2",
"@vueuse/core": "^10.11.0", "@vueuse/core": "^10.11.0",
"circular-json": "^0.5.9",
"cropperjs": "^1.6.2", "cropperjs": "^1.6.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.5.1", "echarts": "^5.5.1",

View File

@ -53,7 +53,7 @@ function createLoginWindow() {
updateInit(loginWindow) updateInit(loginWindow)
} }
// loginWindow.webContents.openDevTools() loginWindow.webContents.openDevTools()
loginWindow.once('ready-to-show', () => { loginWindow.once('ready-to-show', () => {
loginWindow.show() loginWindow.show()
}) })
@ -297,4 +297,4 @@ function appWatchError() {
app.on('child-process-gone', async (event, details) => { app.on('child-process-gone', async (event, details) => {
console.error(`APP-ERROR:child-process-gone; event: ${JSON.stringify(event)}; details:${JSON.stringify(details)}`) console.error(`APP-ERROR:child-process-gone; event: ${JSON.stringify(event)}; details:${JSON.stringify(details)}`)
}) })
} }

View File

@ -88,6 +88,15 @@ export function signIn(data) {
}) })
} }
//登录模块-找回密码
export function retrievePwd(data) {
return request({
url: '/smarttalk/register/authRetrievePwd',
method: 'post',
data
})
}
//注册模块-获取学校 //注册模块-获取学校
export function deptTree(data) { export function deptTree(data) {
return request({ return request({

View File

@ -3,21 +3,20 @@
<svg class="icon ai-icon" aria-hidden="true" @click="isOpen = true; isMax = false" v-if="!isOpen"> <svg class="icon ai-icon" aria-hidden="true" @click="isOpen = true; isMax = false" v-if="!isOpen">
<use xlink:href="#icon-aijiqiren"></use> <use xlink:href="#icon-aijiqiren"></use>
</svg> </svg>
<el-card v-else shadow="always" class="chart-card" :class="[isMax ? 'card-max' : '']"> <div v-else v-drag shadow="always" class="chart-card" :class="[isMax ? 'card-max' : '']">
<template #header> <div class="flex chart-header">
<div class="flex chart-header"> <div class="header-name flex">
<div class="header-name flex"> <svg class="icon header-icon" aria-hidden="true">
<svg class="icon header-icon" aria-hidden="true"> <use xlink:href="#icon-aijiqiren"></use>
<use xlink:href="#icon-aijiqiren"></use> </svg>
</svg> <span>教学助手</span>
<span>教学助手</span>
</div>
<div class="header-tool">
<i class="iconfont icon-window-max_line icon-tool" @click="isMax = !isMax"></i>
<i class="iconfont icon-close icon-tool" @click="closeChart"></i>
</div>
</div> </div>
</template> <div class="header-tool">
<i class="iconfont icon-window-max_line icon-tool" @click="isMax = !isMax"></i>
<i class="iconfont icon-close icon-tool" @click="closeChart"></i>
</div>
</div>
<div class="chart-body"> <div class="chart-body">
<el-scrollbar ref="chatref"> <el-scrollbar ref="chatref">
<div class="default-chart flex"> <div class="default-chart flex">
@ -55,12 +54,13 @@
</div> </div>
</div> </div>
</el-scrollbar> </el-scrollbar>
<div class="chart-input">
<el-input v-model="msgVal" size="large" class="chart-ipt" @keyup.enter="sendMsg" @focus="isFocus = true" @blur="isFocus = false" />
<i class="iconfont icon-tujing" :class="[isFocus ? 'icon-focus' : '']" @click="sendMsg"></i>
</div>
</div> </div>
<div class="chart-input">
<el-input v-model="msgVal" size="large" class="chart-ipt" @keyup.enter="sendMsg" @focus="isFocus = true" @blur="isFocus = false" /> </div>
<i class="iconfont icon-tujing" :class="[isFocus ? 'icon-focus' : '']" @click="sendMsg"></i>
</div>
</el-card>
</div> </div>
</template> </template>
@ -75,7 +75,6 @@ import vDrag from '@/views/tool/directive/drag'
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
const userStore = useUserStore().user const userStore = useUserStore().user
@ -115,28 +114,28 @@ const outerAi = [
id: 1, id: 1,
title: '生成图片', title: '生成图片',
secondTit: '文生图大模型', secondTit: '文生图大模型',
img: '../../../src/assets/images/ai-01.png', img: new URL('../../../src/assets/images/ai-01.png', import.meta.url).href,
path: '/ais/aisd3' path: '/ais/aisd3'
}, },
{ {
id: 2, id: 2,
title: '教学大模型', title: '教学大模型',
secondTit: '中小学基础教学大模型', secondTit: '中小学基础教学大模型',
img: '../../../src/assets/images/ai-02.png', img: new URL('../../../src/assets/images/ai-02.png', import.meta.url).href,
disabled: true, disabled: true,
}, },
{ {
id: 3, id: 3,
title: '育人大模型', title: '育人大模型',
secondTit: '全场域育人大模型', secondTit: '全场域育人大模型',
img: '../../../src/assets/images/ai-03.png', img: new URL('../../../src/assets/images/ai-03.png', import.meta.url).href,
path: '/ais/aimodel' path: '/ais/aimodel'
}, },
{ {
id: 4, id: 4,
title: 'ChatTTS', title: 'ChatTTS',
secondTit: '文字转语音大模型', secondTit: '文字转语音大模型',
img: '../../../src/assets/images/ai-04.png', img: new URL('../../../src/assets/images/ai-04.png', import.meta.url).href,
path: '/ais/aiChatTTS' path: '/ais/aiChatTTS'
} }
] ]
@ -218,6 +217,7 @@ onMounted(() => {
} }
.page-ai-chart { .page-ai-chart {
.ai-icon { .ai-icon {
position: fixed; position: fixed;
right: 30px; right: 30px;
@ -227,41 +227,38 @@ onMounted(() => {
} }
.chart-card { .chart-card {
background-color: #fff;
position: fixed; position: fixed;
bottom: 20px; bottom: 20px;
right: 20px; right: 20px;
width: 300px; width: 300px;
height: calc(100% - 110px); height: calc(100% - 110px);
border-radius: 10px; border-radius: 10px;
z-index: 10;
:deep(.el-card__header) { box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);
padding: 10px;
}
:deep(.el-card__body) {
height: calc(100% - 50px);
padding: 10px 15px;
}
.chart-body { .chart-body {
height: calc(100% - 60px); padding: 10px 15px;
height: calc(100% - 110px);
-webkit-app-region: no-drag;
} }
} }
.card-max { .card-max {
width: 100%; width: 100%;
height: 100%; height: 100%;
left: 0; left: 0 !important;
top: 0; top: 0 !important;
} }
.chart-header { .chart-header {
justify-content: space-between; justify-content: space-between;
font-size: 14px; font-size: 14px;
padding: 10px;
border-bottom: 1px solid #e4e7ed;
-webkit-app-region: no-drag;
.header-name { .header-name {
align-items: center; align-items: center;
.header-icon { .header-icon {
font-size: 28px; font-size: 28px;
align-items: center; align-items: center;
@ -354,7 +351,10 @@ onMounted(() => {
} }
.chart-input { .chart-input {
position: relative; position: absolute;
width: 90%;
left: 5%;
bottom: 15px;
display: flex; display: flex;
align-items: center; align-items: center;
padding-top: 15px; padding-top: 15px;

View File

@ -264,7 +264,7 @@ const transData = (data) => {
// //
const getSubject = async () => { const getSubject = async () => {
const { rows } = await listEvaluation({ itemkey: "version", edusubject, edustage, pageSize: 10000 }) const { rows } = await listEvaluation({ itemkey: "version", edusubject, edustage, pageSize: 10000,orderby: 'orderidx asc', })
// subjectList.value = rows.filter(item => item.edustage == edustage && item.edusubject == edusubject) // subjectList.value = rows.filter(item => item.edustage == edustage && item.edusubject == edusubject)
subjectList.value = rows subjectList.value = rows

View File

@ -41,7 +41,9 @@ const getSubject = (value) => {
gradeName:gradeList[currentIndex].label gradeName:gradeList[currentIndex].label
} }
}) })
const nameIndex = subjectList.value.findIndex(item => item.subjectName === useStore.user.edusubject) //
const nameIndex = subjectList.value.findIndex(item => item.subjectName === useStore.user.edusubject || item.subjectName.includes(useStore.user.edusubject))
if(nameIndex === -1) return;
getTagId({subjectId:subjectList.value[nameIndex].subjectId,subjectName:subjectList.value[nameIndex].subjectName}) getTagId({subjectId:subjectList.value[nameIndex].subjectId,subjectName:subjectList.value[nameIndex].subjectName})
if(textbookVersionId.value === 0){ if(textbookVersionId.value === 0){
getTagId(subjectList.value[0]) getTagId(subjectList.value[0])

View File

@ -51,6 +51,8 @@ const closeWindow = () => {
<style lang="scss" scoped> <style lang="scss" scoped>
.header-tool { .header-tool {
width: 100%;
justify-content: flex-end;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
span { span {

View File

@ -2,28 +2,16 @@
<div class="title-bar flex"> <div class="title-bar flex">
<div class="left-section"> <div class="left-section">
<div class="flex title-box"> <div class="flex title-box">
<el-image style="width: 23px; height: 23px" :src="logoIco" /> <el-image style="width: 23px; height: 23px" :src="logoIco" />
<span class="title" @click="changeTab">AIX智慧课堂</span> <span class="title" @click="changeTab">AIX智慧课堂</span>
</div> </div>
<div class="change-tab"> <div class="change-tab">
<ul class="flex"> <ul class="flex">
<li class="flex" :class="[activeId == menu.path ? 'active-li' : '', menu.disabled ? 'disabled' : '']" <li class="flex" :class="[activeId == menu.path ? 'active-li' : '', menu.disabled ? 'disabled' : '']"
v-for="menu in headerMenus" :key="menu.id" @click="clickMenu(menu)"> v-for="menu in headerMenus" :key="menu.id" @click="clickMenu(menu)">
<i class="iconfont" :class="menu.icon"></i> <i class="iconfont" :class="menu.icon"></i>
<span class="text">{{ menu.name }}</span> <span class="text">{{ menu.name }}</span>
</li> </li>
<!-- <li
v-for="(item, index) in routeHeader.nowRouter"
:key="index"
class="flex"
:style="{'color' : item.color}"
:class="currentRoute === item.url ? 'active-li' : ''"
@click="handleOutLink(item.url,item.type, item.name)"
>
<i :class="item.img"></i>
<span class="text">{{ item.name }}</span>
</li> -->
</ul> </ul>
</div> </div>
</div> </div>
@ -32,26 +20,41 @@
<WindowTools /> <WindowTools />
<div class="user flex"> <div class="user flex">
<div class="avatar-container"> <div class="avatar-container">
<el-dropdown <div class="avatar-wrapper flex">
class="right-menu-item hover-effect" <el-dropdown class="right-menu-item hover-effect" @command="handleCommand">
trigger="click"
@command="handleCommand"
>
<div class="avatar-wrapper">
<img :src="dev_api + userStore.user.avatar" class="user-avatar" style="float: left" /> <img :src="dev_api + userStore.user.avatar" class="user-avatar" style="float: left" />
<div style="margin-top: 18px; font-size: 0.8em">{{ userStore.user.nickName }}</div> <template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="changePage('/profile')">个人中心</el-dropdown-item>
<el-dropdown-item @click="changePage('/classReserv')">课程预约</el-dropdown-item>
<el-dropdown-item @click="changePage('/class')">班级中心</el-dropdown-item>
<el-dropdown-item divided command="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="user-info flex">
<span class="user-name">{{ userStore.user.nickName }}</span>
<div class="flex">
<div class="user-depname">{{ userStore.user.deptName }}</div>
<el-dropdown @command="changeSubject">
<div class="user-subject">{{ userStore.user.edusubject }}
<el-icon class="el-icon--right"><arrow-down />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in userSubjectList" :key="item.id" :command="item">
{{ item.edustage }}-{{ item.edusubject }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div> </div>
<template #dropdown> </div>
<el-dropdown-menu>
<el-dropdown-item @click="changePage('/profile')">个人中心</el-dropdown-item>
<el-dropdown-item @click="changePage('/classReserv')">课程预约</el-dropdown-item>
<el-dropdown-item @click="changePage('/class')">班级中心</el-dropdown-item>
<el-dropdown-item divided command="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div> </div>
</div> </div>
</div> </div>
@ -59,22 +62,23 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue' import { ref, watch, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { ArrowDown } from '@element-plus/icons-vue'
import WindowTools from '@/components/window-tools/index.vue' 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 { updateUserInfo } from '@/api/system/user'
import outLink from '@/utils/linkConfig' import outLink from '@/utils/linkConfig'
import logoIco from '@/assets/images/logo.png' import logoIco from '@/assets/images/logo.png'
import { listEvaluation } from '@/api/classManage/index'
const routeHeader = routerStore()
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
const userStore = useUserStore() const userStore = useUserStore()
const router = useRouter() 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 userSubjectList = ref([])
const handleOutLink = (path, type, name) => { const handleOutLink = (path, type, name) => {
if (!path) return if (!path) return
@ -86,9 +90,9 @@ const handleOutLink = (path, type, name) => {
let fullPath = configObj.fullPath + path let fullPath = configObj.fullPath + path
fullPath = fullPath.replaceAll('//', '/') fullPath = fullPath.replaceAll('//', '/')
const { levelFirstId, levelSecondId } = JSON.parse(localStorage.getItem('unitId')) const { levelFirstId, levelSecondId } = JSON.parse(localStorage.getItem('unitId'))
let unitId = levelSecondId ? levelSecondId :levelFirstId let unitId = levelSecondId ? levelSecondId : levelFirstId
if(name == '教材分析' || name == '考试分析'){ if (name == '教材分析' || name == '考试分析') {
fullPath += `?unitId=${unitId}` fullPath += `?unitId=${unitId}`
} }
// //
ipcRenderer.send('openWindow', { ipcRenderer.send('openWindow', {
@ -127,34 +131,11 @@ const headerMenus = [
} }
] ]
const clickMenu = ({ id, disabled, path }) =>{ const clickMenu = ({ id, disabled, path }) => {
if(disabled) return if (disabled) return
activeId.value = id activeId.value = id
router.push(path) router.push(path)
} }
/*const menus = ref([
{
icon: 'icon-zhuye2 icon-homepage',
name: '主页',
path: '/homepage'
},
{
icon: 'icon-jiaoxueziyuan icon-resource',
name: '资源',
path: '/resource'
},
{
icon: 'icon-beike icon-prepare',
name: '备课',
path: '/prepare'
},
{
icon: 'icon-jiangke1 icon-teach',
name: '授课',
path: '/teach'
}
])*/
// //
watch( watch(
@ -200,13 +181,42 @@ function logout() {
ipcRenderer && ipcRenderer.send('openLoginWindow') ipcRenderer && ipcRenderer.send('openLoginWindow')
}) })
}) })
.catch(() => {}) .catch(() => { })
} }
const emits = defineEmits(['setLayout']) const emits = defineEmits(['setLayout'])
function setLayout() { function setLayout() {
emits('setLayout') emits('setLayout')
} }
//
const changeSubject = async (command) =>{
const { userId, userName, phonenumber, plainpwd } = userStore.user
const data = {
userId,
userName,
edustage: command.edustage,
edusubject: command.edusubject
}
await updateUserInfo(data)
await userStore.login({username: phonenumber, password: plainpwd})
await userStore.getInfo()
router.go()
}
//
const getAllSubject = async () => {
const { rows } = await listEvaluation({ itemkey: "subject", pageSize: 500 })
if(!userStore.user.subject) return
const subject = userStore.user.subject.split(',')
userSubjectList.value = rows.filter(item =>
subject.some(el => item.id == el)
)
}
onMounted(() => {
getAllSubject()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -222,17 +232,20 @@ function setLayout() {
align-items: flex-start; align-items: flex-start;
flex-direction: column; flex-direction: column;
width: 50%; width: 50%;
.title-box{
.title-box {
padding-top: 8px; padding-top: 8px;
box-sizing: border-box; box-sizing: border-box;
align-items: center; align-items: center;
padding-left: 20px; padding-left: 20px;
.title { .title {
color: #4b73df; color: #4b73df;
font-size: 13px; font-size: 13px;
padding: 0 5px; padding: 0 5px;
} }
} }
.change-tab { .change-tab {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
margin-left: 20px; margin-left: 20px;
@ -273,13 +286,16 @@ function setLayout() {
color: #409eff; color: #409eff;
} }
} }
.disabled{
.disabled {
cursor: not-allowed; cursor: not-allowed;
color: #bfbfbf; color: #bfbfbf;
&:hover{
&:hover {
color: #bfbfbf; color: #bfbfbf;
} }
} }
.active-li { .active-li {
color: #409eff; color: #409eff;
} }
@ -290,7 +306,7 @@ function setLayout() {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }
} }
.right-section { .right-section {
@ -302,11 +318,25 @@ function setLayout() {
flex-direction: column; flex-direction: column;
.user { .user {
padding-right: 10px;
.user-info { .user-info {
padding-right: 5px; padding-right: 5px;
align-items: center; align-items: flex-start;
flex-direction: column; flex-direction: column;
font-size: 12px; font-size: 12px;
height: 100%;
justify-content: space-around;
.user-depname {
margin-right: 5px;
}
.user-subject {
display: flex;
align-items: center;
font-size: 12px;
}
} }
} }
} }
@ -316,12 +346,12 @@ function setLayout() {
.avatar-wrapper { .avatar-wrapper {
display: flex; display: flex;
align-items: center;
.user-avatar { .user-avatar {
width: 30px; width: 35px;
height: 30px; height: 35px;
border-radius: 10px; border-radius: 10px;
margin-top: 8px;
margin-right: 10px; margin-right: 10px;
} }

View File

@ -4,6 +4,7 @@
const isNode = typeof require !== 'undefined' // 是否支持node函数 const isNode = typeof require !== 'undefined' // 是否支持node函数
const { ipcRenderer } = isNode?require('electron'):{} // app使用 const { ipcRenderer } = isNode?require('electron'):{} // app使用
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import CircularJSON from 'circular-json'
// import { diff } from 'jsondiffpatch' // import { diff } from 'jsondiffpatch'
// const Remote = isNode?require('@electron/remote'):{} // 远程模块 // const Remote = isNode?require('@electron/remote'):{} // 远程模块
@ -173,6 +174,7 @@ const findDifferences = (obj1, obj2) => {
for (const key in o1) { for (const key in o1) {
if (o1.hasOwnProperty(key)) { if (o1.hasOwnProperty(key)) {
const newPath = path ? `${path}.${key}` : key; const newPath = path ? `${path}.${key}` : key;
if(!o2) return
if (o2.hasOwnProperty(key)) { if (o2.hasOwnProperty(key)) {
const v1 = toJsonStr(o1[key]) const v1 = toJsonStr(o1[key])
const v2 = toJsonStr(o2[key]) const v2 = toJsonStr(o2[key])
@ -202,6 +204,6 @@ const findDifferences = (obj1, obj2) => {
return differences; return differences;
} }
// 对象克隆 // 对象克隆
const objClone = (obj) => JSON.parse(JSON.stringify(obj)) const objClone = (obj) => JSON.parse(CircularJSON.stringify(obj))
// 转换为json // 转换为json
const toJsonStr = (obj) => JSON.stringify(obj) const toJsonStr = (obj) => CircularJSON.stringify(obj)

View File

@ -88,6 +88,9 @@ export const getCurrentTime = (format)=> {
const day = now.getDate().toString().padStart(2, '0'); const day = now.getDate().toString().padStart(2, '0');
const hours = now.getHours().toString().padStart(2, '0'); const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0');
if(format == 'YYYY-MM-DD HH:mm'){
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
if(format == 'YYYY-MM-DD'){ if(format == 'YYYY-MM-DD'){
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
} }

View File

@ -34,7 +34,6 @@ const emits = defineEmits(['handleSelect'])
// //
const handleSelect = (itemDom,pathKey) => { const handleSelect = (itemDom,pathKey) => {
console.log(itemDom,pathKey)
const parts = pathKey[1].split("-") const parts = pathKey[1].split("-")
const result = parts.slice(0, 2).join("-") const result = parts.slice(0, 2).join("-")
const index = props.menuItems.findIndex(item=>item.index===result) const index = props.menuItems.findIndex(item=>item.index===result)

View File

@ -2,8 +2,8 @@
<div class="common-layout"> <div class="common-layout">
<el-container> <el-container>
<el-aside style="width: 200px;margin-top: 20px"> <el-aside style="width: 200px;margin-top: 20px">
<el-card style="width: 200px" class="el-card-demo" :style="{'min-height': (viewportHeight - 164) + 'px'}"> <el-card style="width: 200px" class="el-card-demo" :style="{'min-height': (viewportHeight - 164) + 'px','max-height': (viewportHeight - 164) + 'px'}">
<div :style="{'max-height': (viewportHeight - 164) + 'px','overflow-y': 'auto'}"> <div >
<Aside :menuItems="menuItems" :classList="classList" @handleSelect="handleSelect"></Aside> <Aside :menuItems="menuItems" :classList="classList" @handleSelect="handleSelect"></Aside>
</div> </div>
<!-- 隐藏操作按钮--> <!-- 隐藏操作按钮-->
@ -198,9 +198,14 @@
} }
}); });
listClassmain({entpid: userStore.deptId, status: 'open', pageSize: 100}).then(response => { listClassmain({entpid: userStore.deptId, status: 'open', pageSize: 100}).then(response => {
//
let arr = [...response.rows]
classList.value.forEach(item => {
const currentIndex = arr.findIndex(items => items.id === item.id)
if(currentIndex) arr.splice(currentIndex, 1)
})
// //
gradeTree.value = groupByCondition(response.rows, item => item.agekey); gradeTree.value = groupByCondition(arr, item => item.agekey);
console.log(gradeTree.value,'gradeTree.value')
}) })
} }
// //
@ -293,13 +298,15 @@
// } // }
// //
const btnSave = () => { const btnSave = () => {
addClasses({classIds:classids.value.join(','),regId:userStore.userId}).then(res => { addClasses({classIds:classids.value.join(','),userId:userStore.userId}).then(res => {
if (res.code === 200) { if (res.code === 200) {
dialogVisible.value = false dialogVisible.value = false
ElMessage({ ElMessage({
message: res.msg, message: res.msg,
type: 'success', type: 'success',
}) })
//
classids.value = []
}else{ }else{
ElMessage({ ElMessage({
message: res.msg, message: res.msg,

View File

@ -2,7 +2,7 @@
<div class="class-reserv-item"> <div class="class-reserv-item">
<div class="class-reserv-item-body"> <div class="class-reserv-item-body">
<div class="class-reserv-item-title1"> <div class="class-reserv-item-title1">
<el-tag style="margin-left: 5px" :type="item.workclass"> {{ item.worktype }}</el-tag> <el-tag style="margin-left: 5px" :type="item.workclass?item.workclass:'info'"> {{ item.worktype }}</el-tag>
<label style="margin-left: 10px">{{ item.uniquekey }}</label> <label style="margin-left: 10px">{{ item.uniquekey }}</label>
</div> </div>

View File

@ -1,92 +1,209 @@
<template> <template>
<div class="desktop-item"> <div class="desktop-work-item">
<div class="item-title flex"> <div class="item-title flex">
<span>工作动态</span> <span>工作动态</span>
<el-radio-group v-model="type"> <el-radio-group v-model="type" @change="changeTab">
<el-radio-button label="全部" :value="-1" /> <el-radio-button label="全部" :value="-1" />
<el-radio-button label="备课" :value="1" /> <el-radio-button label="备课" :value="1" disabled />
<el-radio-button label="上课" :value="2" /> <el-radio-button label="上课" :value="2" disabled />
<el-radio-button label="作业" :value="3" /> <el-radio-button label="作业" :value="3" />
</el-radio-group> </el-radio-group>
</div> </div>
<div class="item-content"> <div class="item-content" v-loading="loading">
<ul> <el-scrollbar height="500px">
<li class="flex class-item" v-for="item in classList" :key="item.id"> <ul>
<div class="class-left flex"> <!--上课-->
<div class="class-name flex"> <template v-if="type == 2 || type == -1">
<span>{{ item.className }}</span> <li class="flex class-item" v-for="item in classList" :key="item.id">
</div> <div class="class-left flex">
<div class="class-time"> {{ item.classDay }}&nbsp;{{ item.startTime }} ~ {{ item.classDay }}&nbsp;{{ item.endTime }}</div> <div class="class-name flex">
<div class="class-grade"> <span class="name">{{ item.className }}</span>
<span v-for="(tag, index) in item.classItemList" :key="index" style="margin-left: 5px"> </div>
{{ index === 0 ? tag.name : '、' + tag.name }} <div class="class-time"> {{ item.classDay }}&nbsp;{{ item.startTime }} ~ {{ item.classDay }}&nbsp;{{
</span> item.endTime }}</div>
</div> <div class="class-grade">
</div> <span v-for="(tag, index) in item.classItemList" :key="index" style="margin-left: 5px">
<div class="class-right"> {{ index === 0 ? tag.name : '、' + tag.name }}
<el-button type="primary" size="small">上课</el-button> </span>
</div> </div>
</li> </div>
</ul> <div class="class-right">
<el-button type="primary" size="small">上课</el-button>
</div>
</li>
</template>
<!--作业-->
<template v-if="type == 3 || type == -1">
<li class="flex class-item home-list" v-for="item in homeworkList" :key="item.id">
<div class="class-left flex">
<div class="class-name flex">
<span class="name">{{ item.uniquekey }}</span>
<el-tag class="tag" round :type="tagType(item.deaddate)" effect="dark" size="small">{{
getCurrentTime('YYYY-MM-DD HH:mm') > item.deaddate ? '已结束' : '进行中' }}</el-tag>
</div>
<div class="class-time">{{ item.classcaption }} | 截止时间{{ item.deaddate }} </div>
</div>
<div class="class-right">
<div><span class="num">{{ item.workdataresultcount }}</span> / {{ item.workdatacount }}</div>
<div>已交</div>
</div>
</li>
</template>
</ul>
</el-scrollbar>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import useUserStore from '@/store/modules/user'
import { getSelfReserv } from '@/api/classManage' import { getSelfReserv } from '@/api/classManage'
import { homeworklist } from '@/api/teaching/classwork'
import { getCurrentTime } from '@/utils/date'
const type = ref(-1) const type = ref(-1)
const classList = ref([]) const user = useUserStore().user
const loading = ref(false)
const classList = ref([])
const homeworkList = ref([])
// //
const getClass = () =>{ const getClass = async () => {
getSelfReserv().then((res) => { loading.value = true
let list = res.data || [] try {
list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 }) const res = await getSelfReserv()
classList.value = list.filter(item => item.status !== '已结束') let list = res.data || []
list.sort((a, b) => { if (a.status == '上课中') return -1; else return 0 })
}) classList.value = list.filter(item => item.status !== '已结束')
} finally {
loading.value = false
} }
}
//
const getHomework = async () => {
loading.value = true
const { edustage, edusubject } = user
try {
const { rows } = await homeworklist({ edituserid: user.userId, edustage, edusubject, orderby: 'uniquekey DESC', pageSize: 500 })
homeworkList.value = rows.filter(item => item.deaddate && item.uniquekey)
homeworkList.value.forEach((item) => {
item.workdatacount = JSON.parse('[' + item.classworkdatastudentids + ']').length
})
} finally {
loading.value = false
}
}
onMounted(()=>{ const tagType = (time) => {
getClass() return getCurrentTime('YYYY-MM-DD HH:mm') > time ? 'info' : 'warning'
}) }
//
const changeTab = (val) =>{
switch(val){
case -1:
// getClass()
getHomework()
break;
case 1:
break;
case 2:
getClass()
break;
default:
getHomework()
}
}
onMounted(() => {
// getClass()
getHomework()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.desktop-item{ .desktop-work-item {
margin-bottom: 20px; align-items: center;
height: 100%;
.item-title {
height: 32px;
text-align: left;
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
align-items: center; align-items: center;
.item-title{ justify-content: space-between;
height: 32px; }
text-align: left;
font-size: 18px; .item-content {
font-weight: bold; background-color: #fff;
margin-bottom: 10px; border-radius: 5px;
align-items: center; padding: 10px 15px;
font-size: 13px;
height: calc(100% - 60px);
.class-item {
justify-content: space-between; justify-content: space-between;
} align-items: center;
.item-content{ background: #eff5fa;
background-color: #fff;
border-radius: 5px; border-radius: 5px;
padding: 10px 15px; margin-bottom: 10px;
font-size: 13px; padding: 10px;
.class-item{
justify-content: space-between; .class-left {
align-items: center; flex-direction: column;
background: #e2e4f4; align-items: flex-start;
border-radius: 5px; width: 90%;
margin-bottom: 10px;
padding: 10px; .class-name {
.class-left{ display: flex;
flex-direction: column; align-items: center;
align-items: flex-start;
.class-time{ .name {
font-size: 13px; font-size: 14px;
color: #bfbfbf; font-weight: bold;
} }
.tag {
margin-left: 5px;
border: none;
:deep(.el-tag__content) {
font-size: 12px;
}
}
}
.class-time {
font-size: 13px;
color: #a5a4a4;
padding-top: 3px;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
}
.class-right {
font-size: 12px;
color: #a5a4a4;
flex-shrink: 0;
font-size: 13px;
.num {
font-size: 14px;
color: #409EFF;
font-weight: bold;
} }
} }
} }
.class-grade {
padding-top: 3px
}
} }
}
</style> </style>

View File

@ -1,12 +1,12 @@
<template> <template>
<el-dialog <el-dialog
v-model="dialogVisible" v-model="dialogVisible"
title="注册账号" :title="type==1?'注册账号':'找回密码'"
:fullscreen="true" :fullscreen="true"
center center
:before-close="handleClose" :before-close="handleClose"
> >
<el-steps style="max-width: 100%;-webkit-app-region: no-drag;height:35px" :active="activeIndex" finish-status="success" simple> <el-steps v-if="type==1" style="max-width: 100%;-webkit-app-region: no-drag;height:35px" :active="activeIndex" finish-status="success" simple>
<el-step title="1.基本信息" @click="activeIndex=1" /> <el-step title="1.基本信息" @click="activeIndex=1" />
<el-step title="2.在校信息" /> <el-step title="2.在校信息" />
</el-steps> </el-steps>
@ -18,10 +18,10 @@
status-icon status-icon
ref="ruleFormRef" ref="ruleFormRef"
> >
<el-form-item label="姓名" prop="name" v-if="activeIndex==1"> <el-form-item label="姓名" prop="name" v-if="type==1 && activeIndex==1">
<el-input v-model="ruleForm.name" /> <el-input v-model="ruleForm.name" />
</el-form-item> </el-form-item>
<el-form-item label="身份证号" prop="idNumber" v-if="activeIndex==1"> <el-form-item label="身份证号" prop="idNumber" v-if="type==1 && activeIndex==1">
<el-input v-model="ruleForm.idNumber" /> <el-input v-model="ruleForm.idNumber" />
</el-form-item> </el-form-item>
<el-form-item label="手机号" prop="phoneNumber" v-if="activeIndex==1"> <el-form-item label="手机号" prop="phoneNumber" v-if="activeIndex==1">
@ -60,14 +60,14 @@
<el-form-item label="学科" prop="discipline" v-if="activeIndex==2"> <el-form-item label="学科" prop="discipline" v-if="activeIndex==2">
<div v-for="item in schoolSubject" style="display: flex;"> <div v-for="item in schoolSubject" style="display: flex;">
<span style="width:50px">{{ item.name }}</span> <span style="width:50px">{{ item.name }}</span>
<el-checkbox-group style="width:100%" v-model="ruleForm.discipline" > <el-checkbox-group style="width:100%" v-model="ruleForm.discipline">
<el-checkbox style="margin-right:10px" v-for="el in item.children" :key="el.id" :label="el.itemtitle" :value="el" /> <el-checkbox style="margin-right:10px" v-for="el in item.children" :key="el.id" :label="el.itemtitle" :value="el" />
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item v-if="activeIndex==1"> <el-form-item v-if="activeIndex==1">
<div class="centerDiv"> <div class="centerDiv">
<el-button type="primary" @click="nextStep(ruleFormRef)">下一步</el-button> <el-button type="primary" @click="nextStep(ruleFormRef)">{{ ['下一步','重置密码'][type-1]||'未知异常' }}</el-button>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item v-if="activeIndex==2"> <el-form-item v-if="activeIndex==2">
@ -109,7 +109,7 @@
<script setup> <script setup>
import { ref, defineExpose, reactive ,onMounted} from 'vue' import { ref, defineExpose, reactive ,onMounted} from 'vue'
import {captchaImg,sendCode,deptTree,getDept,listClassmain,listEvaluation,signIn} from '@/api/login' import {captchaImg,sendCode,deptTree,getDept,listClassmain,listEvaluation,signIn, retrievePwd} from '@/api/login'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import {setToken, removeToken } from '@/utils/auth' import {setToken, removeToken } from '@/utils/auth'
import { regionData, codeToText } from 'element-china-area-data' import { regionData, codeToText } from 'element-china-area-data'
@ -225,8 +225,12 @@ const rules = reactive({
},] },]
}) })
const dialogVisible = ref(false) const dialogVisible = ref(false)
const type = ref(1) // 1 2
// //
const OpenModel = () =>{ const OpenModel = v =>{
if (!v) return ElMessage.success('操作失败')
type.value = v
dialogVisible.value=true dialogVisible.value=true
} }
// //
@ -241,33 +245,51 @@ const nextStep = (formEl) => {
if (!formEl) return if (!formEl) return
formEl.validate((valid) => { formEl.validate((valid) => {
if (valid) { if (valid) {
activeIndex.value=2 // type 1 2
// if (type.value == 2) {
deptTree({phone:ruleForm.phoneNumber}).then(res=>{ let params = {
optionsSchool.value=res.data mobile:ruleForm.phoneNumber,
optionsSchool.value.forEach(item=>{ code:ruleForm.Code,
item.value=item.id password:ruleForm.password,
if(!item.children){ confirmPassword:ruleForm.confirmPassword,
item.disabled=true }
} retrievePwd(params).then(res=>{
if(item.children){ if(res.code==200){
item.children.forEach(child=>{ ElMessage.success(res.msg)
child.value=child.id handleClose()
if(!child.children){ }else{
child.disabled=true ElMessage.error(res.msg)
}
if(child.children){
child.children.forEach(grandson=>{
grandson.value=grandson.id
})
}
})
} }
}) })
getSubject() } else {
console.log(res) activeIndex.value=2
}) //
console.log('submit!') deptTree({phone:ruleForm.phoneNumber}).then(res=>{
optionsSchool.value=res.data
optionsSchool.value.forEach(item=>{
item.value=item.id
if(!item.children){
item.disabled=true
}
if(item.children){
item.children.forEach(child=>{
child.value=child.id
if(!child.children){
child.disabled=true
}
if(child.children){
child.children.forEach(grandson=>{
grandson.value=grandson.id
})
}
})
}
})
getSubject()
console.log(res)
})
console.log('submit!')
}
} else { } else {
console.log('error submit!') console.log('error submit!')
} }
@ -296,7 +318,7 @@ const submitForm = async (formEl) => {
schoolId:ruleForm.school[2], schoolId:ruleForm.school[2],
classIds:ruleForm.class.join(','), classIds:ruleForm.class.join(','),
subjectIds:ruleForm.discipline.map(o=>o.id).join(','), subjectIds:ruleForm.discipline.map(o=>o.id).join(','),
subject:ruleForm.discipline.map(o=>o.itemtitle).join(','), subject:ruleForm.discipline.map(o=>`${o.edustage}-${o.edusubject}`).join(','),
areaIds:ruleForm.address.join(','), areaIds:ruleForm.address.join(','),
area:araname area:araname
} }
@ -333,7 +355,7 @@ const sendcaptchaImg=()=>{
if(ruleForm.phoneNumber){ if(ruleForm.phoneNumber){
const pattern = /^1[3-9]\d{9}$/; const pattern = /^1[3-9]\d{9}$/;
if( pattern.test(ruleForm.phoneNumber) ){ if( pattern.test(ruleForm.phoneNumber) ){
captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{ captchaImg({mobile:ruleForm.phoneNumber, type: type.value}).then(res=>{
ruleForm.imgCode=null ruleForm.imgCode=null
isImg.value=true isImg.value=true
isPeopleImg.value='data:image/jpg;base64,'+res.img isPeopleImg.value='data:image/jpg;base64,'+res.img
@ -354,7 +376,7 @@ const sendcaptchaImg=()=>{
} }
// //
const refreshImg=()=>{ const refreshImg=()=>{
captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{ captchaImg({mobile:ruleForm.phoneNumber, type: type.value}).then(res=>{
isPeopleImg.value='data:image/jpg;base64,'+res.img isPeopleImg.value='data:image/jpg;base64,'+res.img
if(res.token){ if(res.token){
setToken(res.token) setToken(res.token)
@ -365,7 +387,14 @@ const refreshImg=()=>{
// //
const sbmitImg=()=>{ const sbmitImg=()=>{
if(ruleForm.imgCode){ if(ruleForm.imgCode){
sendCode({mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}).then(res=>{ // {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
const { phoneNumber:mobile,imgCode:code } = ruleForm
const params = {
mobile, code,
uuid: resImg.imgData.uuid,
type: type.value
}
sendCode(params).then(res=>{
if(res.code==200){ if(res.code==200){
ruleForm.Code=res.data ruleForm.Code=res.data
isImg.value=false isImg.value=false

View File

@ -32,9 +32,9 @@
> >
</el-form-item> </el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;"> <div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a style="margin-right: 10px;" @click="RegisterModel">注册账号</a> <a class="hover:text-sky-500" style="margin-right: 10px;" @click="RegisterModel(1)">注册账号</a>
<!-- | --> <!-- | -->
<!-- <a style="margin-left: 10px;">忘记密码</a> --> <a class="hover:text-sky-500" style="margin-left: 10px;" @click="RegisterModel(2)">忘记密码</a>
</div> </div>
</el-form> </el-form>
</div> </div>
@ -98,8 +98,8 @@ ipcRenderer.on('update-app-progress', (e, prop) => {
showDownLoading.value = prop !== 100 showDownLoading.value = prop !== 100
}) })
// //
const RegisterModel = () =>{ const RegisterModel = type =>{
RegModel.value.OpenModel() RegModel.value.OpenModel(type)
} }
// //
const submitForm = async (formEl) => { const submitForm = async (formEl) => {

View File

@ -270,6 +270,11 @@ const updateClassReserv = (formData) => {
} }
const addClassReserv = (formData) => { const addClassReserv = (formData) => {
let ids = formData.resource.join(',') let ids = formData.resource.join(',')
//
if(!props.bookId){
ElMessage.warning('请选择教材')
return
}
let param = { let param = {
className: formData.name, className: formData.name,
classType: formData.type, classType: formData.type,

View File

@ -40,7 +40,7 @@
</template> </template>
<script setup> <script setup>
import { ref, getCurrentInstance } from 'vue' import { ref, getCurrentInstance,onMounted } from 'vue'
import {updateUserInfo } from '@/api/system/user' import {updateUserInfo } from '@/api/system/user'
import { listEvaluation } from '@/api/subject/index' import { listEvaluation } from '@/api/subject/index'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
@ -90,9 +90,12 @@ const rules = ref({
const subjectList = ref([]) const subjectList = ref([])
// //
listEvaluation({ itemkey: 'subject', pageSize: 500 }).then((res) => { const getSubject = () => {
subjectList.value = res.rows listEvaluation({ itemkey: 'subject', pageSize: 500 }).then((res) => {
}) const arr = userStore.user.subject.split(',')
subjectList.value = res.rows.filter(item => arr.includes(String(item.id))).map(items => items)
})
}
setTimeout(() => { setTimeout(() => {
if (props.user.edudegree != '') { if (props.user.edudegree != '') {
@ -150,4 +153,7 @@ const semeterChange = (item) => {
props.user.edusubject = '' props.user.edusubject = ''
} }
} }
onMounted(() => {
getSubject()
})
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-loading="sourceStore.loading" class="resource-list"> <div class="resource-list">
<el-scrollbar> <el-scrollbar>
<el-empty v-if="!sourceStore.thirdResult.list.length" description="暂无数据" /> <el-empty v-if="!sourceStore.thirdResult.list.length" description="暂无数据" />
<ul> <ul>