src/api/onlineEducation/count.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/api/onlineEducation/examRecord.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/main.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/utils/directive.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/utils/directivesNew.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/onlineEducation/count/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/onlineEducation/offlineEducation/components/recordDialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/onlineEducation/offlineEducation/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/onlineEducation/count.js
对比新文件 @@ -0,0 +1,9 @@ import request from '@/utils/request' export function getCompanyCount(params) { return request({ url: '/statistic/companyStatistic', method: 'get', params: params }) } src/api/onlineEducation/examRecord.js
对比新文件 @@ -0,0 +1,35 @@ import request from '@/utils/request' export function getRecord(param) { return request({ url: '/exam-record/list', method: 'get', params: param }) } export function addRecord(data) { return request({ url: '/exam-record', method: 'post', data: data }) } export function editRecord(params) { return request({ url: `/exam-record`, method: 'put', data: params }) } export function delRecord(userId) { return request({ url: '/exam-record/' + userId, method: 'delete' }) } src/main.js
@@ -51,6 +51,7 @@ import { Boot } from '@wangeditor/editor' import attachmentModule from '@wangeditor/plugin-upload-attachment' import loadMore from '@/utils/selectLoadMoreDirective' import loadMoreNew from '@/utils/directive' import "video.js/dist/video-js.css" Boot.registerModule(attachmentModule) const app = createApp(App) @@ -83,6 +84,8 @@ app.use(preReClick) app.component('svg-icon', SvgIcon) app.directive('loadMore',loadMore) app.directive('loadMoreNew',loadMoreNew) // app.use(Directives) directive(app) // 使用element-plus 并且设置全局的大小 src/utils/directive.ts
@@ -1,6 +1,6 @@ import { Directive, DirectiveBinding } from 'vue' const loadMore: Directive = { const loadMoreNew: Directive = { beforeMount(el: any, binding: DirectiveBinding) { let arg = binding.arg as any if (!arg) return @@ -23,4 +23,4 @@ } } } export default loadMore export default loadMoreNew src/utils/directivesNew.js
对比新文件 @@ -0,0 +1,48 @@ // // import Vue from 'vue' // // // // export default () => { // // Vue.directive('selectScroll', { // // bind (el, binding) { // // // 如上图,我通过v-if来控制了两个select框,当没有binding.arg这个参数时,我只能监听到企业类型下的select框,所以,我通过传参控制了监听的哪个select框 // // var className = '.' + binding.arg // // el.className = binding.arg // // // 获取滚动页面DOM // // const SCROLL_DOM = el.querySelector(`${className} .el-select-dropdown .el-select-dropdown__wrap`) // // // const SCROLL_DOM = el.querySelector(“.el-select-dropdown .el-select-dropdown__wrap“) // // SCROLL_DOM.addEventListener('scroll', function () { // // // 当前的滚动位置 减去 上一次的滚动位置 // // // 如果为true则代表向上滚动,false代表向下滚动 // // const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight // // // 如果已达到指定位置则触发 // // if (CONDITION) { // // // 将滚动行为告诉组件 // // binding.value() // // } // // }) // // } // // }) // // } // // import { Directive, DirectiveBinding } from 'vue' // // const selectScroll: Directive = { // beforeMount(el: any, binding: DirectiveBinding) { // // 如上图,我通过v-if来控制了两个select框,当没有binding.arg这个参数时,我只能监听到企业类型下的select框,所以,我通过传参控制了监听的哪个select框 // const className = '.' + binding.arg; // el.className = binding.arg // // 获取滚动页面DOM // const SCROLL_DOM = el.querySelector(`${className} .el-select-dropdown .el-select-dropdown__wrap`) // // const SCROLL_DOM = el.querySelector(“.el-select-dropdown .el-select-dropdown__wrap“) // SCROLL_DOM.addEventListener('scroll', function () { // // 当前的滚动位置 减去 上一次的滚动位置 // // 如果为true则代表向上滚动,false代表向下滚动 // const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight // // 如果已达到指定位置则触发 // if (CONDITION) { // // 将滚动行为告诉组件 // binding.value() // } // }) // }, // } // export default selectScroll src/views/onlineEducation/count/index.vue
@@ -1,12 +1,174 @@ <template> <div>数据统计</div> <div class="app-container"> <div style="margin-bottom: 10px"> <el-form style="display: flex"> <el-form-item label="企业:"> <el-select v-model="state.queryParams.companyId" style="width: 100%" v-loadMore="loadMore" class="m-2" placeholder="请选择所属企业" popper-class="more_select_dropdown" > <el-option v-for="item in state.companyList" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="时间范围:" style="margin-left: 20px"> <el-date-picker v-model="searchTime" type="daterange" @change="changeTime" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD 00:00:00" /> </el-form-item> <el-form-item style="margin-left: 50px"> <el-radio-group v-model="state.queryParams.type"> <el-radio :label="1">线上教育</el-radio> <el-radio :label="2">线下教育</el-radio> <el-radio :label="null">全部</el-radio> </el-radio-group> </el-form-item> <el-form-item> <el-button type="primary" style="margin-left: 30px" @click="searchClick">查询</el-button> <el-button plain @click="reset">重置</el-button> </el-form-item> </el-form> </div> <!-- 表格数据 --> <el-table v-loading="loading" :data="state.dataList" :border="true" row-key="id"> <el-table-column label="序号" type="index" align="center" width="80" /> <el-table-column label="企业名称" prop="sort" align="center" /> <el-table-column label="企业编号" prop="sort" align="center" width="80" /> <el-table-column label="总批次/人数" prop="sort" align="center" width="80" /> <el-table-column label="三级" prop="sort" align="center" width="80" /> <el-table-column label="二级" prop="sort" align="center" width="80" /> <el-table-column label="一级" prop="sort" align="center" width="80" /> <el-table-column label="考试人次" prop="sort" align="center" width="80" /> <el-table-column label="合格人次" prop="sort" align="center" width="80" /> <el-table-column label="考试合格率" prop="sort" align="center" width="80" /> </el-table> <pagination v-show="state.total > 0" :total="state.total" v-model:page="state.queryParams.pageNum" v-model:limit="state.queryParams.pageSize" @pagination="getList" /> </div> </template> <script setup> import {getCurrentInstance, onMounted, reactive, ref, toRefs} from "vue"; import {ElMessage, ElMessageBox} from "element-plus"; import {delClassification, getClassification} from "@/api/onlineEducation/courseClass"; import {getCompany} from "@/api/onlineEducation/company"; import {getCompanyCount} from "@/api/onlineEducation/count"; const { proxy } = getCurrentInstance(); const loading = ref(false); const areaRef = ref(); const searchTime = ref([]); const state = reactive({ queryParams: { companyId: '', type: null, endTime: '', startTime: '', pageNum: 1, pageSize: 10, }, total: 0, dataList: [ ], companyList: [], pageNum: 1, pageSize: 10, }); //页面加载 onMounted(() => { getCompanyList(); getList(); }); const getList = async () => { loading.value = true; const res = await getCompanyCount(state.queryParams); if(res.code === 200){ state.dataList = res.data }else{ ElMessage.warning(res.message) } loading.value = false; } const finshed = ref(false) const getCompanyList = async (type)=>{ if (type === 'open' && state.pageNum !== 1) { } else { const queryParams = { pageNum: state.pageNum, pageSize: state.pageSize, } const res = await getCompany(queryParams) if (res.code == 200) { if (res.data.pageNum === state.pageNum) { finshed.value = false; if (state.pageNum == 1) { state.companyList = res.data.list } else { state.companyList = state.companyList.concat(res.data.list) } } else { finshed.value = true; } } else { ElMessage.warning(res.message) } console.log("state.companyList",state.companyList) } } //触底函数 const loadMore = () => { console.log(' 触底了'); // 防抖处理 setTimeout(() => { if (finshed.value) return //值为true,则代表没有数据了 state.pageNum += 1 getCompanyList('') }, 500) } const changeTime=(value)=>{ if(!value){ state.queryParams.endTime = "" state.queryParams.startTime = "" } } const searchClick = () => { if(searchTime.value && searchTime.value.length>0){ state.queryParams.startTime = searchTime.value[0] state.queryParams.endTime = searchTime.value[1] } getList(); } /** 重置新增的表单以及其他数据 */ function reset() { data.queryParams.name = ''; data.queryParams.pageNum = 1; getList(); } </script> <style scoped lang="scss"> </style> src/views/onlineEducation/offlineEducation/components/recordDialog.vue
对比新文件 @@ -0,0 +1,333 @@ <template> <div class="notice"> <el-dialog v-model="dialogVisible" :title="state.title" width="550px" :before-close="handleClose" > <el-form :model="state.form" size="default" ref="superRef" :rules="state.formRules" label-width="180px" > <el-form-item label="企业名称:" prop="companyName" > <el-select v-if="state.isAdmin" v-model="state.form.companyName" style="width: 100%" v-loadMoreNew:[reselect]="handleScroll" :popper-class="reselect.name" @change="selectCompany" class="item-width" > <el-option v-for="item in state.companyList" :key="item.id" :label="item.name" :value="item.name" /> </el-select> <el-input v-else v-model.trim="state.form.companyName" disabled ></el-input> </el-form-item> <el-form-item label="计划名称:" prop="planName" > <el-input v-model.trim="state.form.planName" placeholder="请输入计划名称"></el-input> </el-form-item> <el-form-item label="学员:" prop="studentName" > <el-select v-model="state.form.studentName" style="width: 100%" v-loadMoreNew:[reselectStu]="handleScrollStu" :popper-class="reselectStu.name" class="m-2" @change="selectValue" placeholder="请选择学生" popper-class="more_select_dropdown" > <el-option v-for="item in state.studentList" :key="item.id" :label="item.name" :value="item.name" /> </el-select> </el-form-item> <el-form-item label="课程名称:" prop="courseName" > <el-input v-model.trim="state.form.courseName" :disabled="disabled" placeholder="请输入课程名称" ></el-input> </el-form-item> <el-form-item label="培训等级:" prop="level" > <el-input v-model.trim="state.form.level" :disabled="disabled" placeholder="请输入培训等级" ></el-input> </el-form-item> <el-form-item label="要求课时(分):" prop="period" > <el-input v-model.trim="state.form.period" :disabled="disabled" placeholder="请输入要求课时(分)" ></el-input> </el-form-item> <el-form-item label="实际课时(分):" prop="actualPeriod" > <el-input v-model.trim="state.form.actualPeriod" :disabled="disabled" placeholder="请输入实际课时(分)" ></el-input> </el-form-item> <el-form-item label="考试成绩:" prop="score" > <el-input v-model.trim="state.form.score" :disabled="disabled" placeholder="请输入考试成绩" ></el-input> </el-form-item> <el-form-item label="是否合格:" prop="passed" > <el-radio-group v-model="state.form.passed" :disabled="disabled"> <el-radio :label="0">不合格</el-radio> <el-radio :label="1">合格</el-radio> </el-radio-group> </el-form-item> </el-form> <template #footer v-if="state.title !='查看'"> <span class="dialog-footer"> <el-button @click="handleClose" size="default">取 消</el-button> <el-button type="primary" @click="onSubmit" size="default" v-preReClick>确认</el-button> </span> </template> </el-dialog> </div> </template> <script setup> import {reactive, ref, toRefs, defineEmits, nextTick, onMounted} from 'vue' import InfiniteList from 'vue3-infinite-list'; import { View } from "@element-plus/icons-vue"; import scorllSelect from '@/components/scrollSelect/index.vue' import {ElMessage, ElMessageBox} from "element-plus"; import {verifyPhone, verifyPwd, verifyUsername} from "@/utils/validate"; import { checkUserName, checkPhone } from "@/api/login" import {getStudent, resetPwd} from "@/api/onlineEducation/student" import {Base64} from "js-base64" import Cookies from "js-cookie"; import {addStudent, checkStuIdNo, checkStuPhone, editStudent} from "@/api/onlineEducation/student"; import {addRecord, editRecord} from "@/api/onlineEducation/examRecord"; import {getCompany} from "@/api/onlineEducation/company"; const emit = defineEmits(["getList"]); const dialogVisible = ref(false) const superRef = ref(null) const scrollRef = ref(null) const reselect = reactive({ name: 'company' }) const reselectStu = reactive({ name: 'student' }) const state = reactive({ title: '', form: { id: null, companyName: '', planName: '', studentId: '', level: '', period: '', actualPeriod: '', score: null, passed: 0, studentName: '', courseName: '', companyId: null }, formRules:{ companyName: [{ required: true, message: '请输入企业名称', trigger: 'blur' }], planName: [{ required: true, message: '请输入计划名称', trigger: 'blur' }], studentName: [{ required: true, message: '请选择学员', trigger: 'blur' }], level: [{ required: true, message: '请输入培训等级', trigger: 'blur' }], period: [{ required: true, message: '请输入要求课时(分)', trigger: 'blur' }], actualPeriod: [{ required: true, message: '实际课时(分)', trigger: 'blur' }], score: [{ required: true, message: '请输入考试成绩', trigger: 'blur' }], }, isAdmin: false, studentList: [], stuPageNum: 1, // 当前页码 stuPageSize: 10, // 每页显示的数量 hasMoreStu: null, // 是否还有更多选项 pageNum: 1, pageSize: 10, companyList: [], companyPageNum: 1, // 当前页码 companyPageSize: 10, // 每页显示的数量 hasMoreItems: null, // 是否还有更多选项 }) onMounted(() => { }); const disabled = ref(false); const openDialog = async (type, value) => { await loadMoreStuData(); if(state.isAdmin){ await loadMoreCompanyData(); } const userInfo = JSON.parse(Cookies.get('userInfo')) console.log("userInfo",userInfo) if(userInfo.userType === 0){ state.isAdmin = true; state.form.userType = 0; }else { state.isAdmin = false; state.form.companyId = userInfo.companyId; state.form.companyName = userInfo.companyName; state.form.userType = 1; } state.title = type === 'add' ? '新增' : type ==='edit' ? '编辑' : type ==='pwd' ? '修改密码' : '查看' ; if(type === 'edit' || type === 'view') { if( type === 'view'){ disabled.value = true; } state.form = value // state.form.studentName = value.company.name; console.log("ba",state.form) } if(type == 'pwd'){ state.form.id = value.id } dialogVisible.value = true } const onSubmit = async () => { const valid = await superRef.value.validate(); if(valid){ if(state.title == '新增'){ const {id,...data} = state.form const res = await addRecord(data) if(res.code == 200){ ElMessage.success(res.message) emit('getList') handleClose() dialogVisible.value = false; }else{ ElMessage.warning(res.message) } }else if(state.title == '编辑'){ const {id, name, phone, sex, companyId, empno, post, duty, idNo} = state.form const data = {id, name, phone, sex, companyId, empno, post, duty, idNo} const res = await editRecord(data) if(res.code == 200){ ElMessage.success(res.message) emit('getList') handleClose() }else{ ElMessage.warning(res.message) } }else{ const {id,password} = state.form const data = {id,password} data.password = Base64.encode(data.password) const res = await resetPwd(data) if(res.code == 200){ ElMessage.success(res.message) emit('getList') handleClose() }else{ ElMessage.warning(res.message) } } } } const handleClose = () => { state.form = { id: null, companyName: '', planName: '', studentId: '', level: '', period: '', actualPeriod: '', score: null, passed: 0, studentName: '', courseName: '', companyId: null } state.companyPageNum = 1; state.companyPageSize = 10; state.companyList = []; state.stuPageNum = 1; state.stuPageSize = 10; state.studentList = []; superRef.value.clearValidate(); superRef.value.resetFields() dialogVisible.value = false; } const selectValue = (val) => { state.studentList.forEach(item => { if(item.name === val){ state.form.studentId = item.id } }) } const selectCompany = (val) => { state.companyList.forEach(item => { if(item.name === val){ state.form.companyId = item.id } }) } const handleScrollStu = () => { console.log(' student',state.hasMoreStu); if(state.stuPageNum >= state.hasMoreStu) return state.stuPageNum++; loadMoreStuData() } const loadMoreStuData = async () => { const queryParams = { pageNum: state.stuPageNum, pageSize: state.stuPageSize, } const res = await getStudent(queryParams) if (res.code == 200) { state.hasMoreStu = res.data.totalPage const data = res.data state.studentList = state.studentList.concat(data.list) }else{ ElMessage.warning(res.message) } } const handleScroll = () => { console.log(' Company',state.hasMoreItems); if(state.companyPageNum >= state.hasMoreItems) return state.companyPageNum++; loadMoreCompanyData() } const loadMoreCompanyData = async () => { const queryParams = { pageNum: state.companyPageNum, pageSize: state.companyPageSize, } const res = await getCompany(queryParams) if (res.code == 200) { state.hasMoreItems = res.data.totalPage const data = res.data state.companyList = state.companyList.concat(data.list) }else{ ElMessage.warning(res.message) } } defineExpose({ openDialog }); </script> <style scoped lang="scss"> .notice{ :deep(.el-form .el-form-item__label) { font-size: 15px; } .file { display: flex; flex-direction: column; align-items: flex-start; } } </style> src/views/onlineEducation/offlineEducation/index.vue
@@ -1,12 +1,131 @@ <template> <div>线下教育登记</div> <div class="app-container"> <div style="margin-bottom: 10px"> <el-button type="primary" @click="openDialog('add',{})" >新增登记</el-button> <el-button type="primary" plain >批量导入</el-button> </div> <!-- 表格数据 --> <el-table v-loading="loading" :data="dataList" :border="true"> <el-table-column label="序号" type="index" align="center" width="80" /> <el-table-column label="企业名称" prop="companyName" align="center" /> <el-table-column label="计划名称" prop="planName" align="center" /> <el-table-column label="学员姓名" prop="studentName" align="center" /> <el-table-column label="性别" prop="sex" align="center" > <template #default="scope"> <span>{{scope.row.sex == 0 ? '男':'女'}}</span> </template> </el-table-column> <el-table-column label="身份证号" prop="idNo" align="center" width="200" :show-overflow-tooltip="true"/> <el-table-column label="课程名称" prop="courseName" align="center"/> <el-table-column label="培训等级" prop="level" align="center"/> <el-table-column label="要求课时(分)" prop="period" align="center"/> <el-table-column label="实际课时(分)" prop="actualPeriod" align="center"/> <el-table-column label="考试成绩" prop="score" align="center"/> <el-table-column label="是否合格" prop="passed" align="center"> <template #default="scope"> <span>{{scope.row.passed == 0 ? '不合格':'合格'}}</span> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> <record-dialog ref="dialogRef" @getList=getList></record-dialog> </div> </template> <script setup> import {getCurrentInstance, onMounted, onUnmounted, reactive, ref, toRefs} from "vue"; import {ElMessage, ElMessageBox} from "element-plus"; import {delCompany, getCompany} from "@/api/onlineEducation/company"; import recordDialog from "./components/recordDialog.vue" import {delUser, getUser} from "@/api/onlineEducation/user"; import Cookies from "js-cookie"; import {delStudent, getStudent} from "@/api/onlineEducation/student"; import {getRecord} from "@/api/onlineEducation/examRecord"; const { proxy } = getCurrentInstance(); const loading = ref(false); const dialogRef = ref(); const data = reactive({ queryParams: { pageNum: 1, pageSize: 10, }, total: 0, dataList: [], isAdmin: false }); const { queryParams, total, dataList } = toRefs(data); onMounted(async ()=>{ const userInfo = JSON.parse(Cookies.get('userInfo')) console.log("userInfo",userInfo) if(userInfo.userType === 0){ data.isAdmin = true; }else { data.isAdmin = false; } await getList() }) onUnmounted(()=>{ }) const getList = async () => { loading.value = true const res = await getRecord(data.queryParams) if(res.code == 200){ data.dataList = res.data.list data.total = res.data.total }else{ ElMessage.warning(res.message) } loading.value = false } const openDialog = (type, value) => { dialogRef.value.openDialog(type, value); } /** 重置新增的表单以及其他数据 */ function reset() { proxy.resetForm("roleRef"); } const handleDelete = (val) => { ElMessageBox.confirm( '确定删除此条数据?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }) .then( async() => { const res = await delStudent(val.id) if(res.code == 200){ ElMessage.success('数据删除成功') await getList() }else{ ElMessage.warning(res.message) } }) } </script> <style scoped lang="scss"> </style>