This commit is contained in:
朱浩 2024-11-18 17:29:10 +08:00
commit 6e3efe7843
21 changed files with 2510 additions and 185 deletions

View File

@ -20,7 +20,7 @@
</template> </template>
</el-dropdown> </el-dropdown>
<div> <div>
<el-button type="primary" link @click="keywordDialog = true"> <el-button type="primary" link @click="wordDialog = true">
<el-icon> <el-icon>
<Plus /> <Plus />
</el-icon> </el-icon>
@ -31,35 +31,7 @@
</div> </div>
</div> </div>
</div> </div>
<el-dialog v-model="keywordDialog" :show-close="false" width="600"> <keywordDialog v-model="wordDialog"/>
<template #header>
<div class="custom-header flex">
<span>添加提示词</span>
<i class="iconfont icon-guanbi" @click="isDialog = false"></i>
</div>
</template>
<div class="dialog-content">
<el-form :model="form" label-width="auto">
<el-form-item label="名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="提示词">
<el-input v-model="form.desc" type="textarea" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="keywordDialog = false">取消</el-button>
<el-button type="primary" @click="keywordDialog = false">
确定
</el-button>
</div>
</template>
</el-dialog>
<Dialog v-model="showDialog" :modeType="type" /> <Dialog v-model="showDialog" :modeType="type" />
</template> </template>
@ -69,8 +41,9 @@ import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { modelList } from '@/api/mode/index' import { modelList } from '@/api/mode/index'
import Dialog from './dialog.vue' import Dialog from './dialog.vue'
import keywordDialog from './keyword-dialog.vue'
const keywordDialog = ref(false) const wordDialog = ref(false)
const props = defineProps({ const props = defineProps({
type: { type: {
type: Number, type: Number,
@ -120,13 +93,6 @@ const changeTemplate = (val) => {
}) })
} }
const form = reactive({
name: '',
desc: '',
})
onMounted(() => { onMounted(() => {
getTemplateList() getTemplateList()
}) })
@ -143,8 +109,6 @@ onMounted(() => {
width: 50%; width: 50%;
align-items: center; align-items: center;
padding-left: 20px; padding-left: 20px;
} }
.header-right { .header-right {
@ -160,13 +124,4 @@ onMounted(() => {
} }
} }
.custom-header {
justify-content: space-between;
align-items: center;
.icon-guanbi {
cursor: pointer;
font-weight: bold;
}
}
</style> </style>

View File

@ -0,0 +1,72 @@
<template>
<el-dialog v-model="mode" :show-close="false" width="600">
<template #header>
<div class="custom-header flex">
<span>{{ isAdd ? '添加' : '编辑' }}提示词</span>
<i class="iconfont icon-guanbi" @click="mode = false"></i>
</div>
</template>
<div class="dialog-content">
<el-form :model="form" label-width="auto">
<el-form-item label="名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="提示词">
<el-input v-model="form.prompt" type="textarea" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="mode = false">取消</el-button>
<el-button type="primary" @click="mode = false">
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watch } from 'vue'
const mode = defineModel()
const props = defineProps({
isAdd: {
type: Boolean,
default: true
},
item: {
type: Object
}
})
const form = reactive({
name: '',
prompt: '',
})
watch(() => props.isAdd, (newVal) => {
if (!newVal) {
console.log(props.item)
form.name = props.item.name
form.prompt = props.item.prompt
}
}, { immediate: true })
</script>
<style lang="scss" scoped>
.custom-header {
justify-content: space-between;
align-items: center;
.icon-guanbi {
cursor: pointer;
font-weight: bold;
}
}
</style>

View File

@ -6,7 +6,21 @@
<el-row v-for="(item, index) in childTempList"> <el-row v-for="(item, index) in childTempList">
<el-col :span="24"> <el-col :span="24">
<div class="template-item" v-loading="item.loading"> <div class="template-item" v-loading="item.loading">
<div class="item-header"><span class="blue">#</span>{{ item.name }}</div> <div class="item-header">
<div>
<span class="blue">#</span>{{ item.name }}
</div>
<el-popover placement="bottom-end" trigger="hover" popper-class="template-custom-popover" >
<template #reference>
<el-button link type="primary">
<i class="iconfont icon-shenglvehao"></i></el-button>
</template>
<template #default>
<el-button type="primary" link @click="editKeyWord(item)">编辑</el-button>
<el-button type="primary" link>移除</el-button>
</template>
</el-popover>
</div>
<div class="item-text"> <div class="item-text">
{{ item.prompt }} {{ item.prompt }}
</div> </div>
@ -40,6 +54,8 @@
<EditDialog v-model="isEdit" :item="editItem" @saveEdit="saveEdit" /> <EditDialog v-model="isEdit" :item="editItem" @saveEdit="saveEdit" />
<!--AI 对话调整--> <!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :item="editItem" @saveAdjust="saveAdjust" /> <AdjustDialog v-model="isAdjust" :item="editItem" @saveAdjust="saveAdjust" />
<!--编辑提示词-->
<keywordDialog v-model="isEditKeyWord" :isAdd="false" :item="keywordItem"/>
</div> </div>
</template> </template>
@ -47,6 +63,7 @@
import { ref, reactive, onMounted, watch } from 'vue'; import { ref, reactive, onMounted, watch } from 'vue';
import EditDialog from './edit-dialog.vue' import EditDialog from './edit-dialog.vue'
import AdjustDialog from './adjust-dialog.vue' import AdjustDialog from './adjust-dialog.vue'
import keywordDialog from './keyword-dialog.vue';
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { conversation, completion, modelList } from '@/api/mode/index' import { conversation, completion, modelList } from '@/api/mode/index'
@ -180,10 +197,19 @@ const saveAdjust = (item) =>{
childTempList.value[curIndex.value].answer = answer childTempList.value[curIndex.value].answer = answer
} }
//
const keywordItem = reactive({})
const isEditKeyWord = ref(false)
const editKeyWord = (item) =>{
isEditKeyWord.value = true
Object.assign(keywordItem, item)
}
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data);
}) })
defineExpose({ defineExpose({
@ -249,6 +275,7 @@ defineExpose({
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
color: #000; color: #000;
justify-content: space-between;
.blue { .blue {
font-size: 22px; font-size: 22px;
@ -290,19 +317,24 @@ defineExpose({
} }
} }
.text-answer { .text-answer {
color: #409eff; color: #409eff;
} }
.ai-btn { .ai-btn {
margin-top: 10px; margin-top: 10px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
.iconfont { .iconfont {
margin-right: 3px; margin-right: 3px;
} }
:deep(.el-button) { :deep(.el-button) {
font-size: 13px; font-size: 13px;
} }
.icon-ai1 { .icon-ai1 {
font-size: 18px; font-size: 18px;
} }
@ -382,8 +414,22 @@ defineExpose({
} }
} }
.icon-shenglvehao{
font-weight: bold;
font-size: 22px;
}
:deep(.el-popover) {
min-width: 50px;
width: 50px !important;
}
.pl-25 { .pl-25 {
padding-left: 25px; padding-left: 25px;
} }
</style>
<style>
.template-custom-popover {
width: 110px !important;
min-width: 110px !important;
}
</style> </style>

View File

@ -0,0 +1,34 @@
import { ElMessageBox, ElMessage } from "element-plus";
/**
* @description 操作单条数据信息(二次确认删除禁用启用重置密码)
* @param {Function} api 操作数据接口的api方法(必传)
* @param {Object} params 携带的操作数据参数 {id,params}(必传)
* @param {String} message 提示信息(必传)
* @param {String} confirmType icon类型(不必传,默认为 warning) | "success" | "warning" | "info" | "error"
* @return Promise
*/
export const useHandleData = (
api,
params,
message,
confirmType= "warning"
) => {
return new Promise((resolve, reject) => {
ElMessageBox.confirm(`是否${message}?`, "温馨提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: confirmType,
draggable: true
}).then(async () => {
const res = await api(params);
if (!res) return reject(false);
ElMessage({
type: "success",
message: `${message}成功!`
});
resolve(true);
}).catch(() => { });
});
};

View File

@ -65,7 +65,21 @@ export const constantRoutes = [
path: 'management', path: 'management',
component: () => import('@/views/job-management/index.vue'), component: () => import('@/views/job-management/index.vue'),
name: 'job-management', name: 'job-management',
meta: { title: '作业管理' } meta: { title: '作业管理' },
// children: [
// {
// path: 'details',
// component: () => import('@/views/job-management/Details/index.vue'),
// name: 'details',
// meta: { title: '详情' }
// },
// {
// path: 'right',
// component: () => import('@/views/job-management/Right/index.vue'),
// name: 'right',
// meta: { title: '主页' }
// },
// ]
}, },
] ]
}, },
@ -122,6 +136,12 @@ const dynamicRoutes = [
name: 'classTaskAssign', name: 'classTaskAssign',
meta: { title: '作业布置', showBread: true } meta: { title: '作业布置', showBread: true }
}, },
{
path: 'newClassTaskAssign',
component: () => import('@/views/classTask/newClassTaskAssign/index.vue'),
name: 'newClassTaskAssign',
meta: { title: '新作业设计', showBread: true }
},
{ {
path: 'classTask', path: 'classTask',
component: () => import('@/views/classTask/classTask.vue'), component: () => import('@/views/classTask/classTask.vue'),

View File

@ -513,13 +513,6 @@ const handleQueryFromEntpCourseWork= async (queryType) => {
pageParams.value.loading = true; pageParams.value.loading = true;
// ( warn: )
// if (this.courseObj.edusubject=='' && this.courseObj.edustage=='') {
// // [+][+]
// queryForm.edusubject = '';
// }
client(t('任务1', 1500)).then(res => { client(t('任务1', 1500)).then(res => {
//console.log("",res); //console.log("",res);
// if(paginationParams.pageNum == 1){ // if(paginationParams.pageNum == 1){
@ -741,10 +734,6 @@ const handleClassWorkSave = async () => {
return; return;
} }
if (classWorkForm.worktype === "课堂展示") { if (classWorkForm.worktype === "课堂展示") {
boardLoading.value = true boardLoading.value = true
let canvasJson = proxy.$refs.boardref.getCanvasJson() let canvasJson = proxy.$refs.boardref.getCanvasJson()

View File

@ -16,6 +16,7 @@
<!-- <i v-if="!isCollapse" class="iconfont icon-xiangzuo" style="color: blue;"></i> --> <!-- <i v-if="!isCollapse" class="iconfont icon-xiangzuo" style="color: blue;"></i> -->
<span>作业设计</span> <span>作业设计</span>
<!-- <i v-if="isCollapse" class="iconfont icon-xiangyou" style="color: blue;"></i> --> <!-- <i v-if="isCollapse" class="iconfont icon-xiangyou" style="color: blue;"></i> -->
<!-- <el-button type="primary" @click="goToNewClassTaskAssign">新版作业管理</el-button> -->
</div> </div>
<div v-else class="unit-top-left"> <div v-else class="unit-top-left">
<i class="iconfont icon-xiangzuo cursor-pointer" style="color: blue;" @click="goBack">返回上页</i> <i class="iconfont icon-xiangzuo cursor-pointer" style="color: blue;" @click="goBack">返回上页</i>
@ -80,6 +81,9 @@ const courseObj = reactive({
}) })
// --------------------------------------------------- // ---------------------------------------------------
const goToNewClassTaskAssign = () => {
router.push({ path: '/newClassTaskAssign', query: { courseObj: JSON.stringify(courseObj)} });
}
// //
const getData = (data) => { const getData = (data) => {

View File

@ -0,0 +1,94 @@
<template>
<div class="list-container">
<div class="content-list" v-for="(item, index) in items" :key="index" @click="handleClick(item)">
<div class="item-content">
<div class="item-text">
<div class="item-title">{{ item.title }}</div>
<div class="item-description">{{ item.description }}</div>
</div>
<el-icon class="item-icon"><component :is="item.icon" /></el-icon>
</div>
</div>
</div>
</template>
<script setup>
import { shallowRef } from 'vue';
import { ElMessage } from 'element-plus'
import { Plus, ArrowDown, Document, User, Setting } from '@element-plus/icons-vue';
const emit = defineEmits(['itemClick'])
const items = shallowRef([
{ title: '自主搜题', description: '1111111', icon: Document },
{ title: '校本题库', description: '222222', icon: User },
{ title: '个人题库', description: '333333', icon: Setting },
{ title: '智能推荐', description: '444444', icon: Plus },
{ title: '课堂展示', description: '555555', icon: ArrowDown },
{ title: '常规作业', description: '555555', icon: ArrowDown },
{ title: 'AI设计作业', description: '555555', icon: ArrowDown },
]);
const handleClick = (item) => {
console.log('Clicked on:', item.title);
if(item.title === '智能推荐' || item.title === 'AI设计作业') {
ElMessage({
message: '该作业类型暂未开放!',
type: 'warning',
})
return;
}
emit('itemClick', item.title)
};
</script>
<style scoped>
.list-container {
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 16px;
/* background-color: #f5f5f5; */
}
.content-list {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
padding: 16px;
width: calc(33.333% - 32px); /* 3列布局每列减去gap */
cursor: pointer;
transition: all 0.3s ease;
}
.content-list:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.15);
}
.item-content {
display: flex;
align-items: center;
}
.item-icon {
font-size: 24px;
color: #409eff;
margin-right: 16px;
}
.item-text {
flex: 1;
}
.item-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
}
.item-description {
font-size: 14px;
color: #909399;
}
</style>

View File

@ -0,0 +1,813 @@
<template>
<div class="page">
<div class="page-top">
<div class="page-top-left">
<el-button type="danger" :icon="Delete" @click="handleDelete">删除</el-button>
<el-button type="success" @click="handleTaskAssignToAllClass()">批量推送</el-button>
</div>
<div v-if="currentRow.id > 0" class="page-top-right">
<el-button type="primary" @click="handleNewAllClass">设计新作业</el-button>
</div>
</div>
<div class="page-resource">
<div class="page-left">
<el-table
ref="taskTable"
v-loading="loading"
:data="taskList"
:tree-props="{checkStrictly: true}"
row-key="id"
style="width: 100%;height: 100%; border: 1px solid #dcdfe6;border-radius: 3px;flex:1"
highlight-current-row
@current-change="handleCurrentChange"
>
<el-table-column type="selection" min-width="2%" align="center" :selectable="selectable"/>
<el-table-column label="作业布置" min-width="18%" align="center">
<template #default="scope">
<div style="height: 100px;">
<div class="pageleft-table-top">
<span>{{ scope.row.uniquekey }}</span>
</div>
<div class="pageleft-table-top">
<el-tag :type="scope.row.workclass" size="default">{{ scope.row.worktype }}</el-tag>
<span>{{ scope.row.timestamp }}</span>
</div>
<div class="pageleft-table-cont">
<p class="ellipsis "> {{ scope.row.worktype == "课堂展示" ? scope.row.worktag : scope.row.title }}</p>
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div v-if="currentRow.id == 0" style="width: 100%; height: 100%;">
<!-- 默认的习题类型卡片 -->
<Right @itemClick="handleItemClick" />
</div>
<div v-if="(currentRow.worktype == '习题训练' || classWorkForm.worktype == '习题训练') && currentRow.id>0" class="page-center">
<el-tabs v-model="activeAptTab" style="height: 100%;">
<el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst">
<SearchQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd" />
</el-tab-pane>
<el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk">
<SchoolQuestion />
</el-tab-pane>
<el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst">
<MyQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd"/>
</el-tab-pane>
</el-tabs>
</div>
<div v-if="(currentRow.worktype == '课堂展示' || classWorkForm.worktype == '课堂展示') && currentRow.id>0" class="page-center">
<div v-loading="boardLoading" class="board-wrap" style="height: 100%; flex: 1; overflow: hidden;">
<!-- <whiteboard v-if="isShowBoard" ref="boardref" :height="mainHeight - 150" :isShowSave="false" :data="whiteboardObj"/> -->
<whiteboard ref="boardref" height=" 100%" :isShowSave="false" :data="classWorkForm.whiteboardObj"/>
</div>
</div>
<div v-if="(currentRow.worktype == '常规作业' || classWorkForm.worktype == '常规作业')&& currentRow.id>0" class="page-center">
<div v-loading="fileLoading" class="upload-homework">
<FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
</div>
</div>
<div v-if="currentRow.id>0 " class="page-right">
<div class="prepare-top" >
<el-button v-if="currentRow.id != 1 " type="success" @click="openSet(currentRow,'item')"> </el-button>
<el-button type="primary" @click="handleClassWorkSave"> </el-button>
</div>
<div class="prepare-con" >
<el-form
ref="classWorkFormRef"
:model="classWorkForm"
label-width="90"
style=" height: 100%; overflow: hidden;display: flex;flex-direction: column;"
>
<div >
<el-form-item label="作业名称">
<el-input v-model="classWorkForm.uniquekey" type="text" placeholder="请输入作业名称"/>
</el-form-item>
<el-form-item label="作业说明" style="margin: 10px 0;">
<el-input v-if="classWorkForm.worktype != '课堂展示'" v-model="classWorkForm.title" style="width: 400px" placeholder="请输入作业说明"/>
<!-- 课堂展示 这里字段不一样 -->
<el-input v-if="classWorkForm.worktype == '课堂展示'" v-model="classWorkForm.question" type="textarea" placeholder="请输入作业说明" />
</el-form-item>
</div>
<div v-if="classWorkForm.worktype == '习题训练'" class="pageRight-list">
<div :style="{height: '100%', 'overflow': 'auto', 'border':'1px dotted blue','border-radius':'5px', 'background-color': '#f7f7f7'}">
<template v-for="(item,index) in classWorkForm.quizlist" :key="item.id">
<div style="margin: 5px; background-color: white">
<div v-html="item.titleFormat" style="padding: 15px 20px 5px 20px"></div>
<div style="display: flex;">
<el-form-item label="分值">
<el-input-number v-model="item.score" :min="1" :max="100" size="small"></el-input-number >
</el-form-item>
<div style="margin-left: auto; padding: 0px 20px"><el-button size="small" type="danger" @click="handleClassWorkFormQuizRemove(index)">删除</el-button></div>
</div>
</div>
</template>
</div>
</div>
</el-form>
</div>
</div>
</div>
<!-- 推送作业的配置对话框 -->
<SetHomework v-model="setDialog" :entpcourseid="entpcourseid" :rows="rowsList" @on-close="closeHomework" @on-success="successHomework"/>
</div>
</template>
<script setup>
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { cloneDeep } from 'lodash'
import { delClasswork } from '@/api/teaching/classwork'
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
import { addClassworkReturnId } from '@/api/teaching/classwork'
import { updateClasswork, listEvaluationclue, listClassworkeval,delClassworkeval,addClassworkeval,updateClassworkeval } from '@/api/classTask'
import { processList } from '@/hooks/useProcessList'
import { editListItem } from '@/hooks/useClassTask'
import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue'
import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue'
import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue'
import whiteboard from '@/components/whiteboard/whiteboard.vue'
import FileUpload from "@/components/FileUpload/index.vue";
import Right from './Right/index.vue'
import SetHomework from '@/components/set-homework/index.vue'
import { useGetHomework } from '@/hooks/useGetHomework'
import { sessionStore } from '@/utils/store'
import { useRouter, useRoute } from 'vue-router'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
const route = useRoute();
const { proxy } = getCurrentInstance()
const props = defineProps({
})
const propsQueryCourseObj = route.query.courseObj;//
const courseObj = reactive({
// : id,id,id,
textbookId: '',
levelFirstId: '',
levelSecondId: '',
coursetitle:'',
node: null, //
//
})
const taskTable = ref(null);
const activeAptTab = ref("自主搜题");
const taskList = ref([]); //
const tasklist_loading = ref(false); //
const classWorkFormRef = ref(null);
//
const setDialog = ref(false); //
const rowsList = ref([]) //
const entpcourseid = ref('') // id
const currentRow = ref({id:0}); // --
// -------
const boardLoading = ref(false);
//----------
const fileLoading = ref(false); // loading
onMounted(() => {
currentRow.value = {id:0};
console.log('propsQueryCourseObj', JSON.parse(propsQueryCourseObj));
if(propsQueryCourseObj&&JSON.parse(propsQueryCourseObj)){
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj //
courseObj.levelFirstId = JSON.parse(propsQueryCourseObj).levelFirstId //
courseObj.levelSecondId = JSON.parse(propsQueryCourseObj).levelSecondId //
courseObj.coursetitle = JSON.parse(propsQueryCourseObj).coursetitle // (/)
courseObj.node = JSON.parse(propsQueryCourseObj).node; //
}
initHomeWork();
})
//------------
const handleItemClick = (itemName) => {
console.log('itemName', itemName);
currentRow.value = {id:1}; //
/**
* 智能推荐AI设计作业
* 习题训练 自主搜题 校本题库 个人题库
* 课堂展示
* 常规作业
*/
const typeName = itemName == "自主搜题" || itemName == "校本题库"|| itemName == "个人题库" ? "习题训练" : itemName;
activeAptTab.value = itemName;
//
classWorkForm.id = 0;
classWorkForm.uniquekey = ""; //
classWorkForm.worktype = typeName; //
classWorkForm.title = ""; //
classWorkForm.quizlist = []; //
classWorkForm.chooseWorkLists = []; // list
classWorkForm.fileHomeworkList = []; //
classWorkForm.whiteboardObj = ""; // -
classWorkForm.question = ""; // -
}
//-----------------------
const selectable=(row, index)=>{
return row.status == '10';
};
/**
* 获取 entpcourseid 获取作业列表
*/
const initHomeWork = async()=> {
tasklist_loading.value = true;
// const { res, chapterId } = await useGetHomework(courseObj.node);
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
console.log('entpcourseid', chapterId);
console.log('res', res);
entpcourseid.value = chapterId;
taskList.value = res;
tasklist_loading.value = false;
}
const handleNewAllClass = () => {
taskTable.value.setCurrentRow({});//
currentRow.value = {id:0}; //
//--------
classWorkForm.id = 0;
classWorkForm.uniquekey = ""; //
classWorkForm.worktype = ''; //
classWorkForm.title = ""; //
classWorkForm.quizlist = []; //
classWorkForm.chooseWorkLists = []; // list
classWorkForm.fileHomeworkList = []; //
classWorkForm.whiteboardObj = ""; // -
classWorkForm.question = ""; // -
}
/**
* 删除按钮操作
* */
const handleDelete =() => {
let rows = proxy.$refs.taskTable.getSelectionRows();
if (rows.length > 0) {
proxy.$modal.confirm('是否确认选中的学习任务?').then(()=> {
let ids = [];
for (let i = 0; i < rows.length; i++) {
ids.push(rows[i].id);
}
return delClasswork(ids.join(','));
}).then(() => {
taskTable.value.setCurrentRow({});//
currentRow.value = {id:0}; //
taskList.value = [];
// initHomeWork();
setTimeout(() => {
initHomeWork();
}, 1500);
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {})
}else{
proxy.$modal.alertWarning("请选择删除项")
}
};
/**
* 一键推送
*/
const handleTaskAssignToAllClass = () => {
let rows = proxy.$refs.taskTable.getSelectionRows();
if (rows.length > 0) {
proxy.$modal.confirm('是否确认推送选中的学习任务?').then(()=> {
}).then(() => {
//
openSet(rows,'list');
}).catch(() => {})
}else{
return proxy.$modal.alertWarning("请选择需要推送的任务!");
}
}
/**
* 推送作业配置
* //list
*/
//
const openSet=(row, type)=> {
if(type == 'list'){
// row rows
rowsList.value = row;
setDialog.value = true;
}else{
// row row,
rowsList.value = [row];
setDialog.value = true;
}
}
/**
* 关闭布置作业窗口
*/
const closeHomework = () => {
rowsList.value = [];
setDialog.value = false;
}
/**
* 推送布置作业成功
*/
const successHomework = () => {
rowsList.value = [];
setDialog.value = false;
//
nextTick(() => {
initHomeWork();
})
}
// --------------------
let classWorkForm = reactive({
id: '',// cloneDeep(props.propsformobj.id),
uniquekey: '',// props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):'', //
worktype: '',// props.propsformobj.worktype?cloneDeep(props.propsformobj.worktype): '', //
title: '',// props.propsformobj.title?cloneDeep(props.propsformobj.title):'',//
quizlist: [],// props.propsformobj.quizlist?cloneDeep(props.propsformobj.quizlist):[], //
chooseWorkLists: [],// props.propsformobj.chooseWorkLists?cloneDeep(props.propsformobj.chooseWorkLists):[], // list
fileHomeworkList: [],// props.propsformobj.fileHomeworkList?cloneDeep(props.propsformobj.fileHomeworkList):[], //
whiteboardObj: '',// props.propsformobj.whiteboardObj?cloneDeep(props.propsformobj.whiteboardObj):'', // -
question: '',// props.propsformobj.question?cloneDeep(props.propsformobj.question):'', // -
}); //
let propsformobj = reactive({
id: '',// cloneDeep(props.propsformobj.id),
uniquekey: '',// props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):'', //
worktype: '',// props.propsformobj.worktype?cloneDeep(props.propsformobj.worktype): '', //
title: '',// props.propsformobj.title?cloneDeep(props.propsformobj.title):'',//
quizlist: [],// props.propsformobj.quizlist?cloneDeep(props.propsformobj.quizlist):[], //
chooseWorkLists: [],// props.propsformobj.chooseWorkLists?cloneDeep(props.propsformobj.chooseWorkLists):[], // list
fileHomeworkList: [],// props.propsformobj.fileHomeworkList?cloneDeep(props.propsformobj.fileHomeworkList):[], //
whiteboardObj: '',// props.propsformobj.whiteboardObj?cloneDeep(props.propsformobj.whiteboardObj):'', // -
question: '',// props.propsformobj.question?cloneDeep(props.propsformobj.question):'', // -
}); //
/***
* 选中的布置作业行
*/
const handleCurrentChange = (val) => {
console.log(val,'???????????')
if(val && val.id >0 ) {
currentRow.value = val;
editListItem(val, courseObj).then((obj) => {
if(obj){
propsformobj = obj;
//
classWorkForm.id = obj.id;
classWorkForm.uniquekey = cloneDeep(obj.uniquekey); //
classWorkForm.worktype = cloneDeep(obj.worktype); //
classWorkForm.title = cloneDeep(obj.title); //
classWorkForm.quizlist = cloneDeep(obj.quizlist); //
classWorkForm.chooseWorkLists = cloneDeep(obj.chooseWorkLists); // list
classWorkForm.fileHomeworkList = cloneDeep(obj.fileHomeworkList); //
classWorkForm.whiteboardObj = cloneDeep(obj.whiteboardObj); // -
classWorkForm.question = cloneDeep(obj.question); // -
}
});
}
}
/**
* 添加作业
* @param entpcourseworkid
*/
const handleClassWorkQuizAdd = (entpcourseworkid) => {
var exist = false;
for (var i=0; i< classWorkForm.quizlist.length; i++) {
if (classWorkForm.quizlist[i].id == entpcourseworkid) {
exist = true;
break;
}
}
if (exist == false) {
getEntpcoursework(entpcourseworkid).then(res => {
//res.data.titletext = res.data.title.replace(/<[^>]+>/g, '');
//
if(res.data.score == null){
res.data.score = 4;
}
classWorkForm.quizlist.push(res.data);
//
processList(classWorkForm.quizlist);
})
} else {
ElMessage('试题已经存在')
}
}
/** 右侧资源删除按钮 习题list */
const handleClassWorkFormQuizRemove = (index) =>{
classWorkForm.quizlist.splice(index, 1);
}
/**
* 作业设计-提交
*/
const handleClassWorkSave = async () => {
await nextTick(); // DOM
proxy.$refs["classWorkFormRef"].validate(async valid => {
if (valid) {
//
// const { chapterId } = await useGetHomework(courseObj.node)
// this.entpcourseid = chapterId
const cform = {
id: 0,
workdate: classWorkForm.workdate, // //web
deaddate: '', //
entpid: userStore.deptId, //
level: 1,
parentid: 0,
worktype: classWorkForm.worktype, //
workkey: '',
worktag: '',
uniquekey: classWorkForm.uniquekey,//
classid: 0,
classcourseid: 0,
entpcourseid: entpcourseid.value, //
slideid: 0,
title: classWorkForm.title, //
workcodes: JSON.stringify(classWorkForm.workcodes), //
edusubject: userStore.edusubject, //
evalid: courseObj.levelSecondId, //userStore.evalid, // // ID
edustage: userStore.edustage, // ,,
status: '10', //2024-09-11
edituserid: userStore.userId, // id
entpcourseworklist: '', // list
};
// [] newWorkSpaceEdit true
if(classWorkForm.id != '' ) {// id
editWork(cform); //
return;
}
if (classWorkForm.worktype === "课堂展示") {
boardLoading.value = true
let canvasJson = proxy.$refs.boardref.getCanvasJson()
let canvasBase64 = await proxy.$refs.boardref.getCanvasBase64()
//
cform.worktag = classWorkForm.question;
cform.title = classWorkForm.title;
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
try {
addClassworkReturnId(cform).then(() => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "课堂展示";
classWorkForm.uniquekey = '';// classWorkForm.uniquekey, //
classWorkForm.title = "";
classWorkForm.question = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = []; // list
classWorkForm.whiteboardObj = ''; // ? //
boardLoading.value = false
})
} finally {
boardLoading.value = false
}
}
else if(classWorkForm.worktype === "常规作业"){
fileLoading.value = true
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
try {
addClassworkReturnId(cform).then(() => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "常规作业";
classWorkForm.uniquekey = ''; // props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = []; // list
classWorkForm.whiteboardObj = ''; // ? //
classWorkForm.fileHomeworkList = []; // list
fileLoading.value = false
})
} finally {
fileLoading.value = false
}
}
else {
//
var ll = [];
if (classWorkForm.worktype === "习题训练") {
for (var i=0; i< classWorkForm.quizlist.length; i++) {
//
ll.push({'id': classWorkForm.quizlist[i].id, 'score': classWorkForm.quizlist[i].score});
}
}else if( classWorkForm.worktype === "框架梳理") {
classWorkForm.chooseWorkLists.filter((item) => {
if (item.worktype === classWorkForm.worktype) {
ll.push({'id':item.id, 'score': item.score});
}
})
}
// list
if (ll.length > 0) {
cform.entpcourseworklist = JSON.stringify(ll);
} else {
cform.entpcourseworklist = '';
}
console.log(cform,'提交的数据');
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
addClassworkReturnId(cform).then(workres => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "习题训练";
classWorkForm.uniquekey = '',// props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = [];
classWorkForm.whiteboardObj = ''; // ? //
// refresh the list
//
// this.getClassWorkAllList();
})
}
console.log('该清空左侧列表数据了');
//
currentRow.value = {id:0};
initHomeWork();
// if(props.isback){
// //
// router.back();
// }else{
// //
// router.push({ path: '/classTaskAssign' });
// }
}
});
};
/**
* 编辑作业内容
* @param cform 表单数据
*/
const editWork = async (cform) =>{
//
cform.id= classWorkForm.id;
// 0.
if (classWorkForm.worktype == '习题训练') {
if (classWorkForm.quizlist.length == 0) {
ElMessage.error('请先添加作业资源!');
return;
}
}else if (classWorkForm.worktype == '课堂展示' || classWorkForm.worktype == '常规作业') {
//
}else {
if (classWorkForm.chooseWorkLists.length == 0) {
//
ElMessage.error('请先添加作业资源!');
return;
}
}
//
if (classWorkForm.worktype=='习题训练'){
// 1.
let needUplEval = false;
if (classWorkForm.quizlist.length != propsformobj.quizlist.length) {
needUplEval = true;
}else {
//
needUplEval = classWorkForm.quizlist.some(cur =>
!propsformobj.quizlist.some(last =>
last.id === cur.id && last.score === cur.score
)
);
}
// 2.eval
if (needUplEval) {
// : , ,
// 2.1.workidid
let arrEvalids = [];
const wevalres = await listClassworkeval({'workid': classWorkForm.id});
wevalres.rows.forEach(element => {
arrEvalids.push(element.id);
});
const ids = arrEvalids.join(',');
// 2.2.
const delRes = await delClassworkeval(ids);
// 2.3.
for(let i=0; i< classWorkForm.quizlist.length; i++){
const addRes = await addClassworkeval({
'workid': classWorkForm.id,
'entpcourseworkid': classWorkForm.quizlist[i].id,
'workdataid': 0,
'score': classWorkForm.quizlist[i].score}
);
}
}
// 3.-
}
else if (classWorkForm.worktype=='框架梳理') {
// 1.workidid
const wevalres = await listClassworkeval({'workid': classWorkForm.id});
if (wevalres.rows.length == 0) {
ElMessage.error('未找到原框架梳理任务,请或退出重试');
return;
}
// 2.
let needUplEval = false;
if (classWorkForm.chooseWorkLists.length !== propsformobj.chooseWorkLists.length) {
needUplEval = true;
}else {
//
needUplEval = classWorkForm.chooseWorkLists.some(cur =>
!propsformobj.chooseWorkLists.some(last =>
last.id === cur.id && last.score === cur.score
)
);
}
if (needUplEval) {
const uplParams = {
id: wevalres.rows[0].id,
entpcourseworkid: classWorkForm.chooseWorkLists[0].id,
score: classWorkForm.chooseWorkLists[0].score,
}
//
let res = await updateClassworkeval(uplParams);
}
}
else if (classWorkForm.worktype=='课堂展示') {
let canvasJson = proxy.$refs.boardref.getCanvasJson()
let canvasBase64 = await proxy.$refs.boardref.getCanvasBase64()
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
cform.worktag = classWorkForm.question;
}
else if (classWorkForm.worktype=='常规作业') {
// 1. (, )
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
}
// 3.
let res = await updateClasswork(cform);
if (res.code == 200) {
ElMessage.success('更新成功');
//
currentRow.value = {id:0};
initHomeWork();
// //
// router.back()
}
}
//----
</script>
<style scoped lang="scss">
.page {
height: 100%;
.page-top {
height: 50px;
margin-bottom: 5px;
padding: 0 10px;
display: flex;
justify-content: space-between;
background-color: white;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(99, 99, 99, 0.06);
align-items: center;
}
.page-resource {
user-select: none;
height: calc(100% - 55px);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
:deep(.el-tabs__nav) {
.el-tabs__item{
font-weight: bold;
font-size: 18px;
}
}
.page-left {
width: 300px;
background-color: white;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(99, 99, 99, 0.06);
.pageleft-table-top {
height: 35px;
display: flex;
justify-content: space-between;
align-items: center;
}
.pageleft-table-cont {
height: 35px;
// width: 100%;
// text-align: justify;
// display: flex;
// overflow: hidden;
// flex-direction: row;
// text-overflow: ellipsis;
width: 230px; /* 设置容器的宽度 */
overflow: hidden; /* 隐藏超出容器的部分 */
white-space: nowrap; /* 防止文本换行 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
.ellipsis {
width: 100%;
text-align: left;
}
}
}
.page-center{
flex: 1;
// width: 100%;
height: 100%;
padding: 0 5px;
margin: 0 5px;
overflow: hidden;
border-radius: 10px;
background-color: white;
.prepare-center-zzst{
height: 100%;
display: flex;
flex-direction: column;
}
.prepare-center-xbtk{
height: 100%;
}
.prepare-center-grst{
height: 100%;
}
.upload-homework{
padding: 20px;
box-sizing: border-box;
}
}
.page-right {
overflow: hidden;
position: relative;
min-width: 375px;
width: 375px;
height: 100%;
background: #ffffff;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(99, 99, 99, 0.06);
display: flex;
flex-direction: column;
.prepare-top {
display: flex;
height: 40px;
margin: 0 10px;
border-bottom: 2px solid #e5e7eb;
align-items: center;
justify-content: flex-end;
}
.prepare-con{
height: 100%;
padding: 5px 10px;
overflow: hidden;
display: flex;
flex-direction: column;
.pageRight-list {
height: 100%;
padding: 0 0 0 5px;
overflow: auto;
line-height: 26px;
overflow: hidden;
}
}
}
}
}
</style>

View File

@ -0,0 +1,420 @@
<template>
<div class="page">
<!-- 习题筛选1 -->
<el-row style="width: 100%; height: 50px;">
<el-col :span="7">
<el-form-item label="题型" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.worktype" placeholder="请选择" >
<el-option v-for="(item, index) in entpCourseWorkTypeList" :key="index" :label="item.label" :value="item">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="题源" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.workgroup" placeholder="请选择" >
<el-option v-for="(item, index) in entpCourseWorkGroupList" :key="index" :label="item.Value" :value="item.Key" ></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="年份" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.yearStr" placeholder="请选择" >
<el-option v-for="(item, index) in entpCourseWorkYearList" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 习题筛选2 -->
<el-row style="width: 100%; height: 50px;">
<el-col :span="12">
<el-form-item label="关键词" label-width="70">
<el-input
v-model="entpCourseWorkQueryParams.keyWord"
type="text"
placeholder="请输入关键词"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-button @click="handleQueryParamFromEntpCourseWork(1)"><el-icon><Search /></el-icon> </el-button>
</el-col>
</el-row>
<!-- 习题表格 -->
<div class="page-table" >
<el-table
:data="workResource.entpCourseWorkList"
style="width: 100%; height: calc(100% - 55px);"
v-loading="pageParams.loading"
>
<el-table-column type="index" width="60" />
<el-table-column align="left" >
<template #header>
<div style="display: flex">
<div style="align-items: center;">题目内容</div>
</div>
</template>
<template #default="scope">
<div @click="showExamAnalyseDrawer(scope.row)">
<div style="overflow: hidden; text-overflow: ellipsis" v-html="scope.row.titleFormat"></div>
<div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px;" v-html="scope.row.workdescFormat"></div>
<el-col :span="24" style="display: flex">
<div style="font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.entpname }} {{ scope.row.editusername }}</div>
<div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.worktag }}</div>
</el-col>
</div>
</template>
</el-table-column>
<el-table-column width="100">
<template #default="scope">
<div>
<el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button>
<div style="padding: 5px;"></div>
<el-button type="danger" @click="handleDelete(scope.row, scope.$index)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页-->
<div style="height: 55px;">
<el-pagination
v-show="workResource.entpCourseWorkTotal > 0"
v-model:page="paginationParams.pageNum"
v-model:limit="paginationParams.pageSize"
:total="workResource.entpCourseWorkTotal"
:style="{ position: 'relative', 'margin-top': '5px' }"
@change="getPaginationList" />
</div>
</div>
<!-- 试题详细信息 -->
<examDetailsDrawer ref="examDetailsDrawerRef"></examDetailsDrawer>
</div>
</template>
<script setup>
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
import { listEntpcoursework } from '@/api/education/entpCourseWork'
import { listEvaluationclue } from '@/api/classTask'
import { delEntpcoursework } from "@/api/education/entpCourseWork";
import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import { useHandleData } from "@/hooks/useHandleData";
import { processList } from '@/hooks/useProcessList'
import { useGetHomework } from '@/hooks/useGetHomework'
import { sessionStore } from '@/utils/store'
import {throttle,debounce } from '@/utils/comm'
import useUserStore from '@/store/modules/user'
// emit
const emit = defineEmits(['addQuiz'])
const { proxy } = getCurrentInstance()
const userStore = useUserStore().user
const props = defineProps({
bookobj: {
type: Object,
default: () => ({})
},
})
const entpCourseWorkTypeList = ref([
{value: 0, label: "不限"},
{value: 1, label: "单选题"},
{value: 2, label: "填空题"},
{value: 3, label: "多选题"},
{value: 4, label: "判断题"},
{value: 5, label: "主观题"},
{value: 6, label: "复合题"},
]); // -
const entpCourseWorkGroupList = ref([{
Key: -1,
Value: '不限',
}, {
Key: 1,
Value: '真题',
}, {
Key: 0,
Value: '非真题',
}]); // -
const knowledgePointProps = ref({value: 'thirdId', label: 'title'});
const entpCourseWorkYearList =ref([
{label: '不限', value: '-1'},
{label: '2024', value: '2024'},
{label: '2023', value: '2023'},
{label: '2022', value: '2022'},
{label: '2021', value: '2021'},
{label: '2020', value: '2020'},
]); // -
//
const entpCourseWorkQueryParams = reactive({
worktype: {
label: '不限',
value: 0,
},
workgroup: 0,
yearStr: '-1',
point: [],
keyWord: '',
});
const paginationParams = reactive({
pageNum: 1,
pageSize: 10,
}); //
const pageParams = ref({
loading: false, //
originCount: 0, //
isFirst: true, //
total: 0,
})
const workResource = reactive({
options: ['学习任务', '云题库'],
worktype: '全部',
activeIndex: "3",
dialogOfTaskOpen: false,
dislogOfAssignOpen: false,
quiztype: '',
queryForm: {},
classWorkList: [], //
entpCourseWorkList: [], //
entpCourseWorkTotal: 0, //
}); //
onMounted(() => {
debounceQueryData(); //
})
const initPageParams = () => {
//
workResource.entpCourseWorkList = [];
workResource.entpCourseWorkTotal = 0
//
pageParams.value.loading = false;
pageParams.value.isFirst = true;
pageParams.value.originCount = 0;
pageParams.value.total = 0;
//
paginationParams.pageNum = 1;
paginationParams.pageSize = 10;
}
/**
* @desc: 1习题训练 - 新查询试题
* @return: {*}
* @param {*} queryType
* 0 - 标准查询
* 1 - 按条件查询
* 2 - 按关键词查询
*/
let obj = {};
function Apis(key) {
obj[key] = [];
return function(task) {
return new Promise((resolve, reject) => {
obj[key].push(task);
Promise.all([...obj[key]]).then(res => {
const i = obj[key].findIndex(item => {
return item == task;
});
resolve(obj[key][i]);
//arr.splice(i, 1);
})
})
}
}
const client = new Apis('/paht');
const t = function(name, time) {
return new Promise(resolve => {
const queryForm = {
//
worktype: entpCourseWorkQueryParams.worktype.label == '不限' ? '' : entpCourseWorkQueryParams.worktype.label,
// TODO web
// workgroup: entpCourseWorkQueryParams.workgroup,
// TODO web
// yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
//
title: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
//
pageNum: paginationParams.pageNum,
pageSize: paginationParams.pageSize,
//
edustage: userStore.edustage, // this.userStore.edustage,
edusubject: userStore.edusubject, // this.userStore.edusubject,
evalid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
orderby: 'concat(worktype,timestamp) DESC',
}
const entpcourseworkres = listEntpcoursework(queryForm);
resolve(entpcourseworkres);
})
}
const handleQueryFromEntpCourseWork= async (queryType) => {
pageParams.value.loading = true;
client(t('任务1', 1500)).then(res => {
const data = res.rows || [];
if(data && data.length>0){
// data.forEach(item=> {
// if (item.worktype == '') {
// item.worktype = ''
// }
// })
//
processList(data);
workResource.entpCourseWorkList = data;
workResource.entpCourseWorkTotal = res.total;
}
pageParams.value.loading = false;
});
}
//
/**
* 2框架设计教学资源从课标分析教材分析里来
*/
const getQueryFromEvaluationclue = () => {
// props.bookobj.levelSecondId, //userStore.evalid, // // ID
listEvaluationclue({ cluegroup: 'teachresource', evalid: props.bookobj.levelSecondId, pageSize: 1000 }).then((clueres) => {
for (var i=0; i<clueres.rows.length; i++) {
if (clueres.rows[i].cluetag == 'standardview') {
clueres.rows[i].worktype = '课标研读';
} else if (clueres.rows[i].cluetag == 'targetview') {
clueres.rows[i].worktype = '目标设定';
} else if (clueres.rows[i].cluetag == 'contentview') {
clueres.rows[i].worktype = '教材研读';
} else if (clueres.rows[i].cluetag == 'frameview') {
clueres.rows[i].worktype = '框架梳理';
} else if (clueres.rows[i].cluetag == 'mapview') {
clueres.rows[i].worktype = '学科定位';
}
console.log("clueres.rows[i].childlist",clueres.rows[i].childlist);
if (clueres.rows[i].childlist != '') {
clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
}
} else {
clueres.rows[i].childArray = {};
}
}
console.log("框架梳理、课标研读、目标设定、教材研读、学科定位的资源",clueres.rows);
workResource.teachResourceList = clueres.rows;
})
}
/**
* @desc: 根据查询参数查询试题
* @return: {*}
* @param {*} queryType
* 1 - 按条件查询
* 2 - 按关键词查询
*/
const handleQueryParamFromEntpCourseWork = (queryType) => {
//
// this.paginationParams = {pageNum: 1,pageSize: 10};
//
initPageParams();
handleQueryFromEntpCourseWork(queryType);
};
/**
* 查看试题详细信息
* @param row 单题数据
*/
const showExamAnalyseDrawer = (row) => {
nextTick(() => {
const activeParams = {
activeExam: row,
}
proxy.$refs.examDetailsDrawerRef.acceptParams(activeParams);
})
}
const getPaginationList = ( page, limit ) => {
paginationParams.pageNum = page;
paginationParams.pageSize = limit;
console.log(page, limit)
handleQueryFromEntpCourseWork(0);
}
/** 删除题目按钮操作 */
const handleDelete = async(item, index) => {
await useHandleData(delEntpcoursework, item.id, `确认删除编号为【${index+1}】的题目?` );
debounceQueryData();
}
/**
* 添加资源
* @param fromsrc - 试题来源
* @param entpcourseworkid
*/
const handleClassWorkQuizAdd = (fromsrc, entpcourseworkid) => {
emit('addQuiz', entpcourseworkid);
// var exist = false;
// for (var i=0; i< classWorkForm.quizlist.length; i++) {
// if (classWorkForm.quizlist[i].id == entpcourseworkid) {
// exist = true;
// break;
// }
// }
// if (exist == false) {
// getEntpcoursework(entpcourseworkid).then(res => {
// //res.data.titletext = res.data.title.replace(/<[^>]+>/g, '');
// //
// if(res.data.score == null){
// res.data.score = 4;
// }
// classWorkForm.quizlist.push(res.data);
// //
// processList(classWorkForm.quizlist);
// })
// } else {
// ElMessage('')
// }
};
//
const debounceQueryData = debounce(() => {
console.log("防抖 加载数据中...")
//
initPageParams();
// //
handleQueryFromEntpCourseWork(0);
// //
// getQueryFromEvaluationclue();
}, 1000);
watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
console.log(props.bookobj,'课程选择')
debounceQueryData();
})
</script>
<style scoped lang="scss">
.page {
height: 100%;
display: flex;
flex-direction: column;
.page-table {
width: 100%;
height: calc(100% - 100px);
}
}
</style>
<style src="@/assets/styles/JYStyle.css"></style>

View File

@ -0,0 +1,34 @@
<template>
<div class="page">
校本题库
</div>
</template>
<script setup>
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
import { delClasswork } from '@/api/teaching/classwork'
import { useGetHomework } from '@/hooks/useGetHomework'
import { sessionStore } from '@/utils/store'
const { proxy } = getCurrentInstance()
const props = defineProps({
// courseObj: {
// type: Object,
// default: () => ({})
// }
})
onMounted(() => {
})
</script>
<style scoped lang="scss">
.page {
height: 100%;
}
</style>

View File

@ -0,0 +1,498 @@
<template>
<div class="page">
<!-- 习题筛选1 -->
<el-row style="width: 100%; height: 50px;">
<el-col :span="7">
<el-form-item label="题型" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.worktype" placeholder="请选择" >
<el-option v-for="(item, index) in entpCourseWorkTypeList" :key="index" :label="item.label" :value="item">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="题源" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.workgroup" placeholder="请选择" >
<el-option v-for="(item, index) in entpCourseWorkGroupList" :key="index" :label="item.Value" :value="item.Key" ></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="知识点" label-width="70">
<el-cascader
v-model="entpCourseWorkQueryParams.point"
clearable
style="width: 100%"
:options="entpCourseWorkPointList"
:props="knowledgePointProps"
popper-class="my-popper"
:show-all-levels="false"
collapse-tags
collapse-tags-tooltip
/>
</el-form-item>
</el-col>
</el-row>
<!-- 习题筛选2 -->
<el-row style="width: 100%; height: 50px;">
<el-col :span="7">
<el-form-item label="年份" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.yearStr" placeholder="请选择" >
<el-option v-for="(item, index) in entpCourseWorkYearList" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="关键词" label-width="70">
<el-input
v-model="entpCourseWorkQueryParams.keyWord"
type="text"
placeholder="请输入关键词"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-button @click="handleQueryParamFromEntpCourseWork(1)"><el-icon><Search /></el-icon> </el-button>
</el-col>
</el-row>
<!-- 习题表格 -->
<div class="page-table" >
<el-table
:data="workResource.entpCourseWorkList"
style="width: 100%; height: calc(100% - 55px);"
v-loading="pageParams.loading"
>
<el-table-column type="index" width="60" />
<el-table-column align="left" >
<template #header>
<div style="display: flex">
<div style="align-items: center;">题目内容</div>
</div>
</template>
<template #default="scope">
<div @click="showExamAnalyseDrawer(scope.row)">
<div style="overflow: hidden; text-overflow: ellipsis" v-html="scope.row.titleFormat"></div>
<div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px;" v-html="scope.row.workdescFormat"></div>
<el-col :span="24" style="display: flex">
<div style="font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.entpname }} {{ scope.row.editusername }}</div>
<div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.worktag }}</div>
</el-col>
</div>
</template>
</el-table-column>
<el-table-column align="left" width="100">
<template #default="scope">
<el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页-->
<div style="height: 55px;">
<el-pagination
v-show="pageParams.total > 0"
v-model:page="paginationParams.pageNum"
v-model:limit="paginationParams.pageSize"
:total="pageParams.total"
:style="{ position: 'relative', 'margin-top': '5px' }"
@change="getPaginationList" />
</div>
</div>
<!-- 试题详细信息 -->
<examDetailsDrawer ref="examDetailsDrawerRef"></examDetailsDrawer>
</div>
</template>
<script setup>
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
import { updateClasswork, listEvaluationclue, listClassworkeval,delClassworkeval,addClassworkeval,updateClassworkeval } from '@/api/classTask'
import { listEvaluation } from '@/api/subject'
import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import { processList } from '@/hooks/useProcessList'
import { useGetHomework } from '@/hooks/useGetHomework'
import { sessionStore } from '@/utils/store'
import {throttle,debounce } from '@/utils/comm'
import useUserStore from '@/store/modules/user'
// emit
const emit = defineEmits(['addQuiz'])
const { proxy } = getCurrentInstance()
const userStore = useUserStore().user
const props = defineProps({
bookobj: {
type: Object,
default: () => ({})
},
})
const entpCourseWorkTypeList = ref([
{value: 0, label: "不限"},
{value: 1, label: "单选题"},
{value: 2, label: "填空题"},
{value: 3, label: "多选题"},
{value: 4, label: "判断题"},
{value: 5, label: "主观题"},
{value: 6, label: "复合题"},
]); // -
const entpCourseWorkGroupList = ref([{
Key: -1,
Value: '不限',
}, {
Key: 1,
Value: '真题',
}, {
Key: 0,
Value: '非真题',
}]); // -
const entpCourseWorkPointList = ref([
{label: '不限', value: []},
]); // -
const knowledgePointProps = ref({value: 'thirdId', label: 'title'});
const entpCourseWorkYearList =ref([
{label: '不限', value: '-1'},
{label: '2024', value: '2024'},
{label: '2023', value: '2023'},
{label: '2022', value: '2022'},
{label: '2021', value: '2021'},
{label: '2020', value: '2020'},
]); // -
//
const entpCourseWorkQueryParams = reactive({
worktype: {
label: '不限',
value: 0,
},
workgroup: 0,
yearStr: '-1',
point: [],
keyWord: '',
});
const paginationParams = reactive({
pageNum: 1,
pageSize: 10,
}); //
const pageParams = ref({
loading: false, //
originCount: 0, //
isFirst: true, //
total: 0,
})
const workResource = reactive({
options: ['学习任务', '云题库'],
worktype: '全部',
activeIndex: "3",
dialogOfTaskOpen: false,
dislogOfAssignOpen: false,
quiztype: '',
queryForm: {},
classWorkList: [], //
entpCourseWorkList: [], //
entpCourseWorkTotal: 0, //
}); //
onMounted(() => {
debounceQueryData(); //
})
const initPageParams = () => {
//
workResource.entpCourseWorkList = [];
workResource.entpCourseWorkTotal = 0
//
pageParams.value.loading = false;
pageParams.value.isFirst = true;
pageParams.value.originCount = 0;
pageParams.value.total = 0;
//
paginationParams.pageNum = 1;
paginationParams.pageSize = 10;
}
/**
* @desc: 1习题训练 - 新查询试题
* @return: {*}
* @param {*} queryType
* 0 - 标准查询
* 1 - 按条件查询
* 2 - 按关键词查询
*/
let obj = {};
function Apis(key) {
obj[key] = [];
return function(task) {
return new Promise((resolve, reject) => {
obj[key].push(task);
Promise.all([...obj[key]]).then(res => {
const i = obj[key].findIndex(item => {
return item == task;
});
resolve(obj[key][i]);
//arr.splice(i, 1);
})
})
}
}
const client = new Apis('/paht');
const t = function(name, time) {
return new Promise(resolve => {
const queryForm = {
//
currentPage: paginationParams.pageNum,
pageSize: paginationParams.pageSize,
//
eid: props.bookobj.levelSecondId,
sectionName: props.bookobj.coursetitle,
edusubject: userStore.edusubject,
edustage: userStore.edustage,
//
//
worktype: entpCourseWorkQueryParams.worktype.label,
workTypeId: entpCourseWorkQueryParams.worktype.value,
//
workgroup: entpCourseWorkQueryParams.workgroup,
//
yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
//
thirdId: entpCourseWorkQueryParams.point&&entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[0]:'',
//
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
}
const entpcourseworkres = listEntpcourseworkNew(queryForm);
resolve(entpcourseworkres);
})
}
const handleQueryFromEntpCourseWork= async (queryType) => {
pageParams.value.loading = true;
client(t('任务1', 1500)).then(res => {
//console.log("",res);
// if(paginationParams.pageNum == 1){
// workResource.entpCourseWorkList = [];
// workResource.entpCourseWorkTotal = 0;
// //
// // pageParams.value.loading = false;
// // pageParams.value.isFirst = true;
// // pageParams.value.originCount = 0;
// }
const data = res.data || [];
if(data && data.length>0){
// workResource.entpCourseWorkList = entpcourseworkres.data;
// workResource.entpCourseWorkTotal = entpcourseworkres.data.length;
data.forEach(item=> {
if (item.worktype == '选择题') {
item.worktype = '单选题'
}
})
//
processList(data);
//workResource.entpCourseWorkList.push(...data);
workResource.entpCourseWorkList = data;
//
if (pageParams.value.isFirst) {
pageParams.value.isFirst = false;
pageParams.value.originCount = workResource.entpCourseWorkList.length;
pageParams.value.total = parseInt(res.msg);
paginationParams.pageNum = Math.ceil(parseInt(res.msg)/paginationParams.pageSize);
console.log('first->', pageParams.value, paginationParams);
}
}
pageParams.value.loading = false;
});
}
//
/**
* 2框架设计教学资源从课标分析教材分析里来
*/
const getQueryFromEvaluationclue = () => {
// props.bookobj.levelSecondId, //userStore.evalid, // // ID
listEvaluationclue({ cluegroup: 'teachresource', evalid: props.bookobj.levelSecondId, pageSize: 1000 }).then((clueres) => {
for (var i=0; i<clueres.rows.length; i++) {
if (clueres.rows[i].cluetag == 'standardview') {
clueres.rows[i].worktype = '课标研读';
} else if (clueres.rows[i].cluetag == 'targetview') {
clueres.rows[i].worktype = '目标设定';
} else if (clueres.rows[i].cluetag == 'contentview') {
clueres.rows[i].worktype = '教材研读';
} else if (clueres.rows[i].cluetag == 'frameview') {
clueres.rows[i].worktype = '框架梳理';
} else if (clueres.rows[i].cluetag == 'mapview') {
clueres.rows[i].worktype = '学科定位';
}
console.log("clueres.rows[i].childlist",clueres.rows[i].childlist);
if (clueres.rows[i].childlist != '') {
clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
}
} else {
clueres.rows[i].childArray = {};
}
}
console.log("框架梳理、课标研读、目标设定、教材研读、学科定位的资源",clueres.rows);
workResource.teachResourceList = clueres.rows;
})
}
/**
* 3知识点
*/
const getEntpCourseWorkPointList = () => {
//
//
listEvaluation({ itemkey: "subject", pageSize: 10, edustage: userStore.edustage, edusubject: userStore.edusubject }).then((res) => {
const evalId = res.rows
const queryParams = {
evalId: evalId[0]?.id,
pageNum: 1,
pageSize: 5000,
}
listKnowledgePoint(queryParams).then(res => {
entpCourseWorkPointList.value = res.rows;
});
});
}
/**
* @desc: 根据查询参数查询试题
* @return: {*}
* @param {*} queryType
* 1 - 按条件查询
* 2 - 按关键词查询
*/
const handleQueryParamFromEntpCourseWork = (queryType) => {
//
// this.paginationParams = {pageNum: 1,pageSize: 10};
//
initPageParams();
handleQueryFromEntpCourseWork(queryType);
};
/**
* 查看试题详细信息
* @param row 单题数据
*/
const showExamAnalyseDrawer = (row) => {
nextTick(() => {
const activeParams = {
activeExam: row,
}
proxy.$refs.examDetailsDrawerRef.acceptParams(activeParams);
})
}
const getPaginationList = ( page, limit ) => {
paginationParams.pageNum = page;
paginationParams.pageSize = limit;
console.log(page, limit)
handleQueryFromEntpCourseWork(0);
}
/**
* 添加资源
* @param fromsrc - 试题来源
* @param entpcourseworkid
*/
const handleClassWorkQuizAdd = (fromsrc, entpcourseworkid) => {
emit('addQuiz', entpcourseworkid);
// var exist = false;
// for (var i=0; i< classWorkForm.quizlist.length; i++) {
// if (classWorkForm.quizlist[i].id == entpcourseworkid) {
// exist = true;
// break;
// }
// }
// if (exist == false) {
// getEntpcoursework(entpcourseworkid).then(res => {
// //res.data.titletext = res.data.title.replace(/<[^>]+>/g, '');
// //
// if(res.data.score == null){
// res.data.score = 4;
// }
// classWorkForm.quizlist.push(res.data);
// //
// processList(classWorkForm.quizlist);
// })
// } else {
// ElMessage('')
// }
};
//
const debounceQueryData = debounce(() => {
console.log("防抖 加载数据中...")
//
initPageParams();
//
handleQueryFromEntpCourseWork(0);
//
getQueryFromEvaluationclue();
//
getEntpCourseWorkPointList();
}, 1000);
watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
console.log(props.bookobj,'课程选择')
debounceQueryData();
})
</script>
<style scoped lang="scss">
.page {
height: 100%;
display: flex;
flex-direction: column;
.page-table {
width: 100%;
height: calc(100% - 100px);
}
// .el-form-work-list{
// display: flex;
// flex: 1;
// font-size: var(--font-size);
// line-height: 32px;
// min-width: 0;
// position: relative;
// flex-direction: column;
// :deep(.el-form-item__content){
// display: flex;
// flex: 1;
// font-size: var(--font-size);
// line-height: 32px;
// min-width: 0;
// position: relative;
// flex-direction: column;
// }
// .page-table {
// width: 100%;
// height: calc(100% - 100px);
// }
// }
}
</style>
<style src="@/assets/styles/JYStyle.css"></style>

View File

@ -0,0 +1,5 @@
<template>
<div>
2222
</div>
</template>

View File

@ -0,0 +1,96 @@
<template>
<div class="tabs-container">
<div class="button-div">
<el-button @click="goBack" type="primary" size="small">返回主页</el-button>
<el-button type="default" size="small">推送</el-button>
<el-button type="primary" size="small">保存</el-button>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<template v-for="(item,index) in props.parameter.titleList">
<el-tab-pane :label="item.label" :name="item.id">
<el-row :gutter="10" class="tempalte-main">
<el-col :span="16">
<!-- 左侧组件 -->
<transition name="fade">
<component :is="currentComponent"/>
</transition>
</el-col>
<el-col :span="8">
<!-- 右侧 -->
<el-scrollbar class="right-box" :height="pageHeight">
<el-form label-position="top">
<el-form-item label="作业名称">
<el-input></el-input>
</el-form-item>
<el-form-item label="作业说明">
<el-input type="textarea" :row="5"></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-col>
</el-row>
</el-tab-pane>
</template>
</el-tabs>
</div>
</template>
<script setup>
import { ref,defineProps ,defineEmits,nextTick , onMounted,shallowRef } from 'vue'
import ClassroomPresentation from './classroomPresentation/index.vue'
import selfSearchQuestions from './selfSearchQuestions/index.vue'
const props = defineProps({
parameter: Object
});
const emits = defineEmits(['goBack'])
const currentComponent = shallowRef(null)
const activeName = ref(1)
const pageHeight = ref(0)
const handleClick = (tab, event) => {
console.log(tab, event)
}
//
const goBack = () => {
emits('goBack')
}
//
const rightComponets = (str) => {
switch (str) {
case 'classroomPresentation':
return ClassroomPresentation
case 'selfSearchQuestions':
return selfSearchQuestions
default:
return null
}
}
//
onMounted(() => {
currentComponent.value = rightComponets(props.parameter.components)
//
nextTick(() => {
pageHeight.value = window.innerHeight + window.scrollY - 156;
});
})
</script>
<style lang="scss" scoped>
.tabs-container{
position: relative;
}
.button-div{
position: absolute;
top: 5px;
right: 0;
z-index: 999;
}
.right-box{
background-color: #fff;
padding:5px;
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,5 @@
<template>
<div>
11111
</div>
</template>

View File

@ -1,27 +0,0 @@
<template>
<div class="mb-4">
<div>
<el-button type="danger" disabled>批量删除</el-button>
<el-button type="primary" disabled>批量推送</el-button>
</div>
<CustomSelect
:options="options"
placeholder="设计新作业"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
import CustomSelect from '../components/customSelect.vue';
const options = ref(['自主搜题', '校本题库', '个人题库', '智能推荐', '课堂展示', '常规作业', 'AI作业设计']);
</script>
<style lang="scss" scoped>
.mb-4{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
background-color: #fff;
padding: 10px;
}
</style>

View File

@ -2,10 +2,10 @@
<div class="list-container"> <div class="list-container">
<div class="content-list" v-for="(item, index) in items" :key="index" @click="handleClick(item)"> <div class="content-list" v-for="(item, index) in items" :key="index" @click="handleClick(item)">
<div class="item-content"> <div class="item-content">
<el-checkbox v-model="item.checked"/> <el-checkbox v-model="item.checked" @click.stop="clickCheckbox(item)"/>
<div class="item-text"> <div class="item-text">
<div class="title-header"> <div class="title-header">
<div class="item-title">{{ item.title }}</div> <div class="item-title" :title="item.title">{{ item.title }}</div>
<CustomButton :item="{ type: item.type, text: item.text, plain: true }" /> <CustomButton :item="{ type: item.type, text: item.text, plain: true }" />
</div> </div>
<div class="item-description" :title="item.description">{{ item.description }}</div> <div class="item-description" :title="item.description">{{ item.description }}</div>
@ -17,21 +17,39 @@
</template> </template>
<script setup> <script setup>
import { ref,markRaw } from 'vue'; import { ref } from 'vue';
import { ArrowRight } from '@element-plus/icons-vue'; import { ArrowRight } from '@element-plus/icons-vue';
import CustomButton from '../components/button.vue' import CustomButton from '../components/button.vue'
const emits = defineEmits(['checked']);
const items = ref([ const items = ref([
{ title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' }, { id:1,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' },
{ title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'primary',text:'课堂练习' }, { id:2,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'primary',text:'课堂练习' },
{ title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' }, { id:3,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' },
{ title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'danger',text:'常规作业' }, { id:4,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'danger',text:'常规作业' },
{ title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' }, { id:5,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' },
{ id:6,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' },
{ id:7,title: '沁园春-长沙 习题训练作业', description: '沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业沁园春-长沙 习题训练作业',checked:false,type:'default',text:'习题训练' },
]); ]);
// checkboxid
const selectIds = ref([])
const handleClick = (item) => { const handleClick = (item) => {
console.log('Clicked on:', item.title); console.log(item.title);
}; };
//
const clickCheckbox = (item,e) => {
if(item.checked === true){
if(selectIds.value.includes(item.id)){
const index = selectIds.value.indexOf(item.id)
selectIds.value.splice(index,1)
}
}else{
selectIds.value.push(item.id)
}
emits('checked',selectIds.value)
}
</script> </script>
<style scoped> <style scoped>
@ -40,7 +58,7 @@
width: 100%; width: 100%;
max-width: 400px; /* 可以根据需要调整宽度 */ max-width: 400px; /* 可以根据需要调整宽度 */
margin: 0 auto; margin: 0 auto;
padding: 16px; padding: 8px;
background-color: #f5f5f5; background-color: #f5f5f5;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
@ -50,7 +68,7 @@
background-color: #fff; background-color: #fff;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
padding: 16px; padding: 8px;
margin-bottom: 16px; margin-bottom: 16px;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
@ -80,6 +98,7 @@
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
margin-left: 5px; margin-left: 5px;
} }
.title-header{ .title-header{
display: flex; display: flex;
@ -92,6 +111,12 @@
font-weight: 500; font-weight: 500;
color: #303133; color: #303133;
text-align: left; text-align: left;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1; /* 设置最大行数 */
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
} }
.item-description { .item-description {

View File

@ -1,51 +1,125 @@
<template> <template>
<div class="list-content">
<div class="list-container"> <div class="list-container">
<div class="content-list" v-for="(item, index) in items" :key="index" @click="handleClick(item)"> <div class="content-list" v-for="(item, index) in items" :key="index" @click="handleClick(item)">
<div class="item-content"> <div class="item-content">
<div class="item-text"> <div class="item-text">
<div class="title-header">
<div class="item-title">{{ item.title }}</div> <div class="item-title">{{ item.title }}</div>
<div class="item-description">{{ item.description }}</div>
</div>
<el-icon class="item-icon"><component :is="item.icon" /></el-icon> <el-icon class="item-icon"><component :is="item.icon" /></el-icon>
</div> </div>
<div class="item-description">{{ item.description }}</div>
<div class="item-bottom">
<CustomButton :item="{ type: item.type, text: item.text, plain: true }" />
</div> </div>
</div> </div>
</div>
</div>
</div>
</div>
</template> </template>
<script setup> <script setup>
import { shallowRef } from 'vue'; import { ref, markRaw } from 'vue';
import { Plus, ArrowDown, Document, User, Setting } from '@element-plus/icons-vue'; import { Plus, ArrowDown, Document, User, Setting } from '@element-plus/icons-vue';
import CustomButton from '../components/button.vue';
const emits = defineEmits(['skipDetail']);
const items = shallowRef([ const items = ref([
{ title: '自主搜题', description: '1111111', icon: Document }, { title: '自主搜题', description: '1111111', icon: markRaw(Document), type: 'default', text: '习题训练',components:'classroomPresentation',titleList:[
{ title: '校本题库', description: '222222', icon: User }, {
{ title: '个人题库', description: '333333', icon: Setting }, id:1,
{ title: '智能推荐', description: '444444', icon: Plus }, label:'自主搜题',
{ title: '课堂展示', description: '555555', icon: ArrowDown }, },
{ title: '常规作业', description: '555555', icon: ArrowDown }, {
{ title: 'AI设计作业', description: '555555', icon: ArrowDown }, id:2,
label:'校本题库',
},
{
id:3,
label:'个人题库',
},
]},
{ title: '校本题库', description: '222222', icon: markRaw(Document), type: 'default', text: '习题训练',components:'classroomPresentation',titleList:[
{
id:1,
label:'自主搜题',
},
{
id:2,
label:'校本题库',
},
{
id:3,
label:'个人题库',
},
] },
{ title: '个人题库', description: '333333', icon: markRaw(Document), type: 'default', text: '习题训练',components:'classroomPresentation',titleList:[
{
id:1,
label:'自主搜题',
},
{
id:2,
label:'校本题库',
},
{
id:3,
label:'个人题库',
},
] },
{ title: '智能推荐', description: '444444', icon: markRaw(Document), type: '', text: '',components:'classroomPresentation',titleList:[
{
id:1,
label:'智能推荐',
},
] },
{ title: '课堂展示', description: '555555', icon: markRaw(Document), type: 'primary', text: '课堂展示',components:'selfSearchQuestions',titleList:[
{
id:1,
label:'课堂展示',
},
] },
{ title: '常规作业', description: '555555', icon: markRaw(Document), type: 'danger', text: '常规作业',components:'selfSearchQuestions',titleList:[
{
id:1,
label:'常规作业',
},
] },
{ title: 'AI设计作业', description: '555555', icon: markRaw(Document), type: 'danger', text: '常规作业',components:'selfSearchQuestions',titleList:[
{
id:1,
label:'AI设计作业',
},
] },
]); ]);
const handleClick = (item) => { const handleClick = (item) => {
console.log('Clicked on:', item.title); emits('skipDetail', item);
}; };
</script> </script>
<style scoped> <style scoped>
.list-content{
padding: 8px;
background-color: #f5f5f5;
border-radius: 8px;
height: 100%;
}
.list-container { .list-container {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16px; gap: 16px;
padding: 16px;
background-color: #f5f5f5;
} }
.content-list { .content-list {
background-color: #fff; background-color: #fff;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
padding: 16px; padding: 8px;
width: calc(33.333% - 32px); /* 3列布局每列减去gap */ width: calc(25% - 16px);
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
@ -75,10 +149,37 @@ const handleClick = (item) => {
font-weight: 500; font-weight: 500;
color: #303133; color: #303133;
margin-bottom: 4px; margin-bottom: 4px;
font-weight: bold;
} }
.item-description { .item-description {
font-size: 14px; font-size: 14px;
color: #909399; color: #909399;
text-align: left;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; /* 设置最大行数 */
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
.title-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.item-bottom {
text-align: right;
}
/* 过渡动画 */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
} }
</style> </style>

View File

@ -21,7 +21,8 @@
<script setup> <script setup>
import { Plus, ArrowDown } from '@element-plus/icons-vue' import { Plus, ArrowDown } from '@element-plus/icons-vue'
import { ref, computed, defineProps } from 'vue'; import { ref, defineEmits, defineProps } from 'vue';
const emits = defineEmits(['select-click']);
const props = defineProps({ const props = defineProps({
options: { options: {
@ -45,8 +46,8 @@ const toggleDropup = () => {
}; };
const selectOption = (option) => { const selectOption = (option) => {
selectedOption.value = option;
isDropdownOpen.value = false; isDropdownOpen.value = false;
emits('select-click', option)
}; };
</script> </script>
<style scoped> <style scoped>

View File

@ -1,31 +1,115 @@
<template> <template>
<div class="page-template flex"> <div class="page-template flex">
<Header/> <!-- // -->
<div class="mb-4">
<div>
<el-button type="danger" :disabled="!isChceked">批量删除</el-button>
<el-button type="primary" :disabled="!isChceked">批量推送</el-button>
</div>
<CustomSelect
:options="options"
placeholder="设计新作业"
@select-click="selectClick"
/>
</div>
<div :style="{height: viewportHeight - 72 + 'px'}" class="no-horizontal-scroll">
<el-row :gutter="20" class="tempalte-main"> <el-row :gutter="20" class="tempalte-main">
<el-col :span="6"> <el-col :span="6">
<!-- 左侧列表 --> <!-- 左侧列表 -->
<Left/> <Left @checked="checked"/>
</el-col> </el-col>
<el-col :span="18"> <el-col :span="18">
<!-- 右侧 --> <!-- 右侧 -->
<Right/> <component :is="currentComponent" v-on="listeners" :parameter="parameter" />
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
import Header from './Header/index.vue' import { ref, shallowRef, onMounted, nextTick, computed } from 'vue';
import Right from './Right/index.vue' import Right from './Right/index.vue';
import Left from './Left/index.vue' import Left from './Left/index.vue';
import Detials from './Details/index.vue';
import CustomSelect from './components/customSelect.vue';
const options = ref(['自主搜题', '校本题库', '个人题库', '智能推荐', '课堂展示', '常规作业', 'AI作业设计']);
// checkbox
const isChceked = ref(false);
const viewportHeight = ref(0);
const isSkip = ref(false);
//
const parameter = ref({});
// checkbox
const checked = (val) => {
console.log(val);
val.length > 0 ? isChceked.value = true : isChceked.value = false;
}
const currentComponent = shallowRef(Right);
//
const selectClick = (val) => {
console.log(val);
}
//
const skipDetail = (val) => {
parameter.value = Object.assign({}, val);
isSkip.value = true;
currentComponent.value = Detials;
}
//
const goBack = () => {
isSkip.value = false;
currentComponent.value = Right;
}
//
const getViewportHeight = () => {
return Math.max(
document.documentElement.clientHeight,
window.innerHeight || 0
);
}
onMounted(() => {
nextTick(() => {
window.addEventListener('resize', () => {
viewportHeight.value = getViewportHeight();
});
});
});
const listeners = computed(() => ({
skipDetail,
goBack
}));
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mb-4 {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
background-color: #fff;
padding: 10px;
}
.page-template { .page-template {
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
overflow-x: hidden; //
.tempalte-main { .tempalte-main {
flex: 1; flex: 1;
} }
} }
.no-horizontal-scroll {
overflow: auto;
overflow-x: hidden;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer 10+ */
}
</style> </style>

View File

@ -37,8 +37,8 @@
<el-form-item label="手机号" prop="username"> <el-form-item label="手机号" prop="username">
<el-input v-model="ruleForm.username" placeholder="请输入手机号" /> <el-input v-model="ruleForm.username" placeholder="请输入手机号" />
</el-form-item> </el-form-item>
<el-form-item label="验证码" prop="smsCode"> <el-form-item label="验证码" prop="smsCode" style="display: flex">
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button :disabled="codeName!='发送验证码'" type="primary" @click="sendyzm">{{ codeName }}</el-button> <el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" type="primary" @click="sendyzm">发送验证码</el-button>
</el-form-item> </el-form-item>
<el-form-item label="密码" prop="password" > <el-form-item label="密码" prop="password" >
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" /> <el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
@ -58,10 +58,27 @@
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false" <el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
status="success" /> status="success" />
</el-dialog> </el-dialog>
<el-dialog
v-model="isImg"
title="人机验证"
width="500"
style=" -webkit-app-region: no-drag;"
>
<span>根据图片回答相关问题</span>
<div style="display: flex;align-items: center;;margin-top:30px">
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
</div>
<div style="display: flex;justify-content: center;margin-top:30px">
<el-button type="primary" @click="sbmitImg">确定</el-button>
</div>
</el-dialog>
<!--选择学科--> <!--选择学科-->
<SelectSubject v-model="isSubject" :login-data="loginForm" /> <SelectSubject v-model="isSubject" :login-data="loginForm" />
<!--注册弹框--> <!--注册弹框-->
<Register ref="RegModel"></Register> <Register ref="RegModel"></Register>
</template> </template>
<script setup> <script setup>
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
@ -73,7 +90,7 @@ import WindowTools from '@/components/window-tools/index.vue'
import SelectSubject from '@/components/select-subject/index.vue' import SelectSubject from '@/components/select-subject/index.vue'
import Register from './components/Register.vue' import Register from './components/Register.vue'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import {sendcode,instructorregister} from '@/api/login' import {sendcode,instructorregister,getCodeImg} from '@/api/login'
const { session } = require('@electron/remote') const { session } = require('@electron/remote')
const downloadProp = ref(0) const downloadProp = ref(0)
@ -88,6 +105,11 @@ const isRegister = ref(true)
const ruleFormRef = ref(null) const ruleFormRef = ref(null)
const codeName=ref('发送验证码') const codeName=ref('发送验证码')
const timer=ref(null) const timer=ref(null)
const isImg=ref(false)
const isPeopleImg=ref(null)
const type=ref(1) // 1 2
const resImg = reactive({ imgData: {} });
// //
const loginForm = reactive({ const loginForm = reactive({
username: '', username: '',
@ -118,14 +140,48 @@ const gotoreRegister=()=>{
} }
isRegister.value=false isRegister.value=false
} }
//
const refreshImg=()=>{
getCodeImg().then(res=>{
isPeopleImg.value='data:image/jpg;base64,'+res.img
resImg.imgData=res
})
}
//
const sbmitImg=()=>{
if(ruleForm.imgCode){
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
const { username:username,imgCode:code } = ruleForm
const params = {
username, code,
uuid: resImg.imgData.uuid,
source:4
}
sendcode(params).then(res=>{
if(res.code==200){
ElMessage.success('短信发送成功')
ruleForm.Code=res.data
isImg.value=false
}
})
}else{
ElMessage.error('请根据图片输入验证码')
}
//
}
// //
const sendyzm=()=>{ const sendyzm=()=>{
if(ruleForm.username){ if(ruleForm.username){
const pattern = /^1[3-9]\d{9}$/; const pattern = /^1[3-9]\d{9}$/;
if( pattern.test(ruleForm.username) ){ if( pattern.test(ruleForm.username) ){
sendcode({username:ruleForm.username, source: '4'}).then(res=>{
getCodeImg().then(res=>{
if(res.code==200){ if(res.code==200){
ElMessage.success('消息发送成功') ruleForm.imgCode=null
isPeopleImg.value='data:image/jpg;base64,'+res.img
isImg.value=true
resImg.imgData=res
codeName.value=60 codeName.value=60
timer.value=setInterval(()=>{ timer.value=setInterval(()=>{
codeName.value-- codeName.value--