Browse Source

Merge remote-tracking branch 'origin/master'

master
liutong 10 months ago
parent
commit
b962be05ec
  1. 58
      admin/src/app/api/class_resources_rel.ts
  2. 4
      admin/src/app/api/exam_questions.ts
  3. 5
      admin/src/app/api/sys.ts
  4. 17
      admin/src/app/lang/zh-cn/class_resources_rel.class_resources_rel.json
  5. 201
      admin/src/app/views/class_resources_rel/class_resources_rel.vue
  6. 251
      admin/src/app/views/class_resources_rel/components/class-resources-rel-edit.vue
  7. 5
      admin/src/app/views/exam_questions/components/exam-questions-edit.vue
  8. 58
      admin/src/app/views/exam_questions/exam_questions.vue
  9. 2
      admin/src/app/views/student/components/student-edit.vue
  10. 19
      admin/src/app/views/student/student.vue
  11. 104
      niucloud/app/adminapi/controller/class_resources_rel/ClassResourcesRel.php
  12. 6
      niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php
  13. 43
      niucloud/app/adminapi/route/class_resources_rel.php
  14. 1
      niucloud/app/adminapi/route/exam_questions.php
  15. 68
      niucloud/app/model/class_resources_rel/ClassResourcesRel.php
  16. 117
      niucloud/app/service/admin/class_resources_rel/ClassResourcesRelService.php
  17. 79
      niucloud/app/service/admin/exam_questions/ExamQuestionsService.php
  18. 14
      niucloud/app/service/admin/student/StudentService.php
  19. 35
      niucloud/app/validate/class_resources_rel/ClassResourcesRel.php

58
admin/src/app/api/class_resources_rel.ts

@ -0,0 +1,58 @@
import request from '@/utils/request'
// USER_CODE_BEGIN -- class_resources_rel
/**
*
* @param params
* @returns
*/
export function getClassResourcesRelList(params: Record<string, any>) {
return request.get(`class_resources_rel/class_resources_rel`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getClassResourcesRelInfo(id: number) {
return request.get(`class_resources_rel/class_resources_rel/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addClassResourcesRel(params: Record<string, any>) {
return request.post('class_resources_rel/class_resources_rel', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @param params
* @returns
*/
export function editClassResourcesRel(params: Record<string, any>) {
return request.put(`class_resources_rel/class_resources_rel/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteClassResourcesRel(id: number) {
return request.delete(`class_resources_rel/class_resources_rel/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
export function getWithClassGradeList(params: Record<string,any>){
return request.get('class_resources_rel/class_grade_all', {params})
}export function getWithCustomerResourcesList(params: Record<string,any>){
return request.get('class_resources_rel/customer_resources_all', {params})
}export function getWithCampusList(params: Record<string,any>){
return request.get('class_resources_rel/campus_all', {params})
}
// USER_CODE_END -- class_resources_rel

4
admin/src/app/api/exam_questions.ts

@ -55,3 +55,7 @@ export function randomQuestionsList(params: Record<string, any>) {
// USER_CODE_END -- exam_questions
export function toLeadInto(params: Record<string, any>) {
return request.post(`exam_questions/to_lead_into`, params, { showErrorMessage: true, showSuccessMessage: true })
}

5
admin/src/app/api/sys.ts

@ -786,3 +786,8 @@ export function getJlyjConfig() {
export function getHome(params: Record<string, any>) {
return request.post('sys/home', params)
}
export function setDocument(params: Record<string, any>) {
return request.post('sys/document/document', params)
}

17
admin/src/app/lang/zh-cn/class_resources_rel.class_resources_rel.json

@ -0,0 +1,17 @@
{
"classId":"班级",
"classIdPlaceholder":"请输入班级",
"resourceId":"资源",
"resourceIdPlaceholder":"请输入资源",
"campusId":"校区",
"campusIdPlaceholder":"请输入校区",
"sourceType":"数据资源类型",
"sourceTypePlaceholder":"请输入数据资源类型",
"status":"状态",
"statusPlaceholder":"请输入状态",
"addClassResourcesRel":"添加班级和资源",
"updateClassResourcesRel":"编辑班级和资源",
"classResourcesRelDeleteTips":"确定要删除该数据吗?",
"startDate":"请选择开始时间",
"endDate":"请选择结束时间"
}

201
admin/src/app/views/class_resources_rel/class_resources_rel.vue

@ -0,0 +1,201 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addClassResourcesRel') }}
</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="classResourcesRelTable.searchParam" ref="searchFormRef">
<el-form-item>
<el-button type="primary" @click="loadClassResourcesRelList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table :data="classResourcesRelTable.data" size="large" v-loading="classResourcesRelTable.loading">
<template #empty>
<span>{{ !classResourcesRelTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="class_id_name" :label="t('classId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="resource_id_name" :label="t('resourceId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('sourceType')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in source_typeList">
<div v-if="item.value == row.source_type">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column :label="t('status')" min-width="180" align="center" :show-overflow-tooltip="true">
<template #default="{ row }">
<div v-for="(item, index) in statusList">
<div v-if="item.value == row.status">{{ item.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="classResourcesRelTable.page" v-model:page-size="classResourcesRelTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="classResourcesRelTable.total"
@size-change="loadClassResourcesRelList()" @current-change="loadClassResourcesRelList" />
</div>
</div>
<edit ref="editClassResourcesRelDialog" @complete="loadClassResourcesRelList" />
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getClassResourcesRelList, deleteClassResourcesRel, getWithClassGradeList, getWithCustomerResourcesList, getWithCampusList } from '@/app/api/class_resources_rel'
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/class_resources_rel/components/class-resources-rel-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
let classResourcesRelTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam:{
}
})
const searchFormRef = ref<FormInstance>()
//
const selectData = ref<any[]>([])
//
const source_typeList = ref([] as any[])
const source_typeDictList = async () => {
source_typeList.value = await (await useDictionary('sj_type')).data.dictionary
}
source_typeDictList();
const statusList = ref([] as any[])
const statusDictList = async () => {
statusList.value = await (await useDictionary('student_status')).data.dictionary
}
statusDictList();
/**
* 获取班级和资源列表
*/
const loadClassResourcesRelList = (page: number = 1) => {
classResourcesRelTable.loading = true
classResourcesRelTable.page = page
getClassResourcesRelList({
page: classResourcesRelTable.page,
limit: classResourcesRelTable.limit,
...classResourcesRelTable.searchParam
}).then(res => {
classResourcesRelTable.loading = false
classResourcesRelTable.data = res.data.data
classResourcesRelTable.total = res.data.total
}).catch(() => {
classResourcesRelTable.loading = false
})
}
loadClassResourcesRelList()
const editClassResourcesRelDialog: Record<string, any> | null = ref(null)
/**
* 添加班级和资源
*/
const addEvent = () => {
editClassResourcesRelDialog.value.setFormData()
editClassResourcesRelDialog.value.showDialog = true
}
/**
* 编辑班级和资源
* @param data
*/
const editEvent = (data: any) => {
editClassResourcesRelDialog.value.setFormData(data)
editClassResourcesRelDialog.value.showDialog = true
}
/**
* 删除班级和资源
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('classResourcesRelDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
).then(() => {
deleteClassResourcesRel(id).then(() => {
loadClassResourcesRelList()
}).catch(() => {
})
})
}
const classIdList = ref([])
const setClassIdList = async () => {
classIdList.value = await (await getWithClassGradeList({})).data
}
setClassIdList()
const resourceIdList = ref([])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadClassResourcesRelList()
}
</script>
<style lang="scss" scoped>
/* 多行超出隐藏 */
.multi-hidden {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>

251
admin/src/app/views/class_resources_rel/components/class-resources-rel-edit.vue

@ -0,0 +1,251 @@
<template>
<el-dialog v-model="showDialog" title="班级分配" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('campusId')" >
<el-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('classId')" prop="class_id">
<el-select class="input-width" v-model="formData.class_id" clearable :placeholder="t('classIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in classIdList"
:key="index"
:label="item['class_name']"
:value="item['id']"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="资源" >
<el-select class="input-width" v-model="formData.resource_id" clearable :placeholder="t('resourceIdPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in resourceIdList"
:key="index"
:label="item['name']"
:value="item['id']"
/>
</el-select>
</el-form-item> -->
<el-form-item label="数据资源类型" >
<el-select class="input-width" v-model="formData.source_type" clearable placeholder="请选择数据资源类型">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in source_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('status')" >
<el-select class="input-width" v-model="formData.status" clearable :placeholder="t('statusPlaceholder')">
<el-option label="请选择" value=""></el-option>
<el-option
v-for="(item, index) in statusList"
:key="index"
:label="item.name"
:value="Number(item.value)"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
t('confirm')
}}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addClassResourcesRel, editClassResourcesRel, getClassResourcesRelInfo, getWithClassGradeList, getWithCustomerResourcesList, getWithCampusList } from '@/app/api/class_resources_rel'
let showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
class_id: '',
// resource_id: '',
campus_id: '',
source_type: '',
status: '',
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const formRules = computed(() => {
return {
class_id: [
{ required: true, message: t('classIdPlaceholder'), trigger: 'blur' },
]
,
resource_id: [
{ required: true, message: t('resourceIdPlaceholder'), trigger: 'blur' },
]
,
campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
]
,
source_type: [
{ required: true, message: t('sourceTypePlaceholder'), trigger: 'blur' },
]
,
status: [
{ required: true, message: t('statusPlaceholder'), trigger: 'blur' },
]
,
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
let save = formData.id ? editClassResourcesRel : addClassResourcesRel
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
let data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(err => {
loading.value = false
})
}
})
}
//
let source_typeList = ref([])
const source_typeDictList = async () => {
source_typeList.value = await (await useDictionary('sj_type')).data.dictionary
}
source_typeDictList();
watch(() => source_typeList.value, () => { formData.source_type = source_typeList.value[0].value })
let statusList = ref([])
const statusDictList = async () => {
statusList.value = await (await useDictionary('student_status')).data.dictionary
}
statusDictList();
watch(() => statusList.value, () => { formData.status = statusList.value[0].value })
const classIdList = ref([] as any[])
const setClassIdList = async () => {
classIdList.value = await (await getWithClassGradeList({})).data
}
setClassIdList()
const resourceIdList = ref([] as any[])
const setResourceIdList = async () => {
resourceIdList.value = await (await getWithCustomerResourcesList({})).data
}
setResourceIdList()
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if(row){
const data = await (await getClassResourcesRelInfo(row.id)).data
if (data) Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
loading.value = false
}
//
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
} else {
callback()
}
}
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
}
//
const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label{
height: auto !important;
}
</style>

5
admin/src/app/views/exam_questions/components/exam-questions-edit.vue

@ -83,7 +83,7 @@
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addOption">添加选项</el-button>
<el-button type="primary" @click="addOption" v-if="formData.option_json.length <= 3">添加选项</el-button>
</el-form-item>
@ -132,14 +132,15 @@
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const addOption = () => {
const index = formData.option_json.length;
formData.option_json.push({
option_content_type: 'text',
option_content: '',
correct_answer: false,
option:alphabet[index] || ''
})
}
const removeOption = (index) => {

58
admin/src/app/views/exam_questions/exam_questions.vue

@ -35,6 +35,13 @@
<el-form-item>
<el-button type="primary" @click="loadExamQuestionsList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
<el-button @click="DownloadExcel">下载导入模板</el-button>
<el-upload v-bind="upload" style="margin-left: 10px;">
<el-button type="primary">导入</el-button>
</el-upload>
</el-form-item>
</el-form>
</el-card>
@ -98,11 +105,13 @@
import { reactive, ref, watch } from 'vue'
import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict'
import { getExamQuestionsList, deleteExamQuestions } from '@/app/api/exam_questions'
import { img } from '@/utils/common'
import { getExamQuestionsList, deleteExamQuestions,toLeadInto } from '@/app/api/exam_questions'
import { img,getToken } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/exam_questions/components/exam-questions-edit.vue'
import { useRoute } from 'vue-router'
import { UploadFile, ElMessage } from 'element-plus'
const route = useRoute()
const pageName = route.meta.title;
@ -121,6 +130,51 @@ let examQuestionsTable = reactive({
const searchFormRef = ref<FormInstance>()
const DownloadExcel = () => {
const link = document.createElement('a');
link.href = 'https://zh.hnhbty.cn/excel.xlsx'; //
link.download = '题目导入模板.xlsx';
link.click();
}
const prop = defineProps({
modelValue: {
type: String,
default: '',
},
api: {
type: String,
default: 'sys/document/document',
},
})
const upload: Record<string, any> = {
action: `${import.meta.env.VITE_APP_BASE_URL}/${prop.api}`,
showFileList: false,
headers: {},
accept: '.xls,.xlsx',
onSuccess: (response: any, uploadFile: UploadFile) => {
if (response.code != undefined && response.code != 1) {
ElMessage({ message: response.msg, type: 'error' })
return
}
Import(response.data.url);
},
}
upload.headers[import.meta.env.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
const Import = async(url) => {
examQuestionsTable.loading = true
toLeadInto({url:url}).then(res => {
examQuestionsTable.loading = false
loadExamQuestionsList();
}).catch(() => {
examQuestionsTable.loading = false
})
}
//
const selectData = ref<any[]>([])

2
admin/src/app/views/student/components/student-edit.vue

@ -48,7 +48,7 @@
v-for="(item, index) in genderList"
:key="index"
:label="item.name"
:value="item.value"
:value="Number(item.value)"
/>
</el-select>
</el-form-item>

19
admin/src/app/views/student/student.vue

@ -18,7 +18,7 @@
v-for="(item, index) in campusIdList"
:key="index"
:label="item['campus_name']"
:value="item['id']"
:value="Number(item['id'])"
/>
</el-select>
</el-form-item>
@ -68,12 +68,12 @@
<template #empty>
<span>{{ !studentTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<!-- <el-table-column prop="user_id_name" :label="t('userId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column prop="class_id_name" :label="t('classId')" min-width="120" :show-overflow-tooltip="true"/>
-->
<el-table-column prop="name" :label="t('name')" min-width="120" :show-overflow-tooltip="true"/>
<el-table-column :label="t('gender')" min-width="180" align="center" :show-overflow-tooltip="true">
@ -122,6 +122,7 @@
<el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<el-button type="primary" link @click="classEvent(row.getInfoRel)">班级分配</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
@ -136,6 +137,8 @@
</div>
<edit ref="editStudentDialog" @complete="loadStudentList" />
<class ref="classStudentDialog" @complete="loadStudentList" />
</el-card>
</div>
</template>
@ -148,6 +151,7 @@ import { getStudentList, deleteStudent, getWithCustomerResourcesList, getWithCam
import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/student/components/student-edit.vue'
import Class from '@/app/views/class_resources_rel/components/class-resources-rel-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title;
@ -232,6 +236,15 @@ const editEvent = (data: any) => {
editStudentDialog.value.showDialog = true
}
const classStudentDialog: Record<string, any> | null = ref(null)
const classEvent = (data: any) => {
classStudentDialog.value.setFormData(data)
classStudentDialog.value.showDialog = true
}
/**
* 删除学员
*/

104
niucloud/app/adminapi/controller/class_resources_rel/ClassResourcesRel.php

@ -0,0 +1,104 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\adminapi\controller\class_resources_rel;
use core\base\BaseAdminController;
use app\service\admin\class_resources_rel\ClassResourcesRelService;
/**
* 班级和资源控制器
* Class ClassResourcesRel
* @package app\adminapi\controller\class_resources_rel
*/
class ClassResourcesRel extends BaseAdminController
{
/**
* 获取班级和资源列表
* @return \think\Response
*/
public function lists(){
$data = $this->request->params([
]);
return success((new ClassResourcesRelService())->getPage($data));
}
/**
* 班级和资源详情
* @param int $id
* @return \think\Response
*/
public function info(int $id){
return success((new ClassResourcesRelService())->getInfo($id));
}
/**
* 添加班级和资源
* @return \think\Response
*/
public function add(){
$data = $this->request->params([
["class_id",0],
["resource_id",0],
["campus_id",0],
["source_type",""],
["status",0],
]);
$this->validate($data, 'app\validate\class_resources_rel\ClassResourcesRel.add');
$id = (new ClassResourcesRelService())->add($data);
return success('ADD_SUCCESS', ['id' => $id]);
}
/**
* 班级和资源编辑
* @param $id 班级和资源id
* @return \think\Response
*/
public function edit(int $id){
$data = $this->request->params([
["class_id",0],
["campus_id",0],
["source_type",""],
["status",0],
]);
// $this->validate($data, 'app\validate\class_resources_rel\ClassResourcesRel.edit');
(new ClassResourcesRelService())->edit($id, $data);
return success('EDIT_SUCCESS');
}
/**
* 班级和资源删除
* @param $id 班级和资源id
* @return \think\Response
*/
public function del(int $id){
(new ClassResourcesRelService())->del($id);
return success('DELETE_SUCCESS');
}
public function getClassGradeAll(){
return success(( new ClassResourcesRelService())->getClassGradeAll());
}
public function getCustomerResourcesAll(){
return success(( new ClassResourcesRelService())->getCustomerResourcesAll());
}
public function getCampusAll(){
return success(( new ClassResourcesRelService())->getCampusAll());
}
}

6
niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php

@ -105,4 +105,10 @@ class ExamQuestions extends BaseAdminController
}
public function to_lead_into(){
$data = $this->request->post();
return (new ExamQuestionsService())->to_lead_into($data);
}
}

43
niucloud/app/adminapi/route/class_resources_rel.php

@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- class_resources_rel
Route::group('class_resources_rel', function () {
//班级和资源列表
Route::get('class_resources_rel', 'class_resources_rel.ClassResourcesRel/lists');
//班级和资源详情
Route::get('class_resources_rel/:id', 'class_resources_rel.ClassResourcesRel/info');
//添加班级和资源
Route::post('class_resources_rel', 'class_resources_rel.ClassResourcesRel/add');
//编辑班级和资源
Route::put('class_resources_rel/:id', 'class_resources_rel.ClassResourcesRel/edit');
//删除班级和资源
Route::delete('class_resources_rel/:id', 'class_resources_rel.ClassResourcesRel/del');
Route::get('class_grade_all','class_resources_rel.ClassResourcesRel/getClassGradeAll');
Route::get('customer_resources_all','class_resources_rel.ClassResourcesRel/getCustomerResourcesAll');
Route::get('campus_all','class_resources_rel.ClassResourcesRel/getCampusAll');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,
AdminLog::class
]);
// USER_CODE_END -- class_resources_rel

1
niucloud/app/adminapi/route/exam_questions.php

@ -32,6 +32,7 @@ Route::group('exam_questions', function () {
Route::post('random_questions_list', 'exam_questions.ExamQuestions/random_questions_list');
Route::post('to_lead_into', 'exam_questions.ExamQuestions/to_lead_into');
})->middleware([
AdminCheckToken::class,

68
niucloud/app/model/class_resources_rel/ClassResourcesRel.php

@ -0,0 +1,68 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\class_resources_rel;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
use app\model\class_grade\ClassGrade;
use app\model\customer_resources\CustomerResources;
use app\model\campus\Campus;
/**
* 班级和资源模型
* Class ClassResourcesRel
* @package app\model\class_resources_rel
*/
class ClassResourcesRel extends BaseModel
{
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'class_resources_rel';
public function classGrade(){
return $this->hasOne(ClassGrade::class, 'id', 'class_id')->joinType('left')->withField('class_name,id')->bind(['class_id_name'=>'class_name']);
}
public function customerResources(){
return $this->hasOne(CustomerResources::class, 'id', 'resource_id')->joinType('left')->withField('name,id')->bind(['resource_id_name'=>'name']);
}
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
}

117
niucloud/app/service/admin/class_resources_rel/ClassResourcesRelService.php

@ -0,0 +1,117 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\class_resources_rel;
use app\model\class_resources_rel\ClassResourcesRel;
use app\model\class_grade\ClassGrade;
use app\model\customer_resources\CustomerResources;
use app\model\campus\Campus;
use core\base\BaseAdminService;
/**
* 班级和资源服务层
* Class ClassResourcesRelService
* @package app\service\admin\class_resources_rel
*/
class ClassResourcesRelService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new ClassResourcesRel();
}
/**
* 获取班级和资源列表
* @param array $where
* @return array
*/
public function getPage(array $where = [])
{
$field = 'id,class_id,resource_id,campus_id,source_id,source_type,join_time,out_time,status,create_time,update_time';
$order = 'id desc';
$search_model = $this->model->withSearch([], $where)->with(['classGrade','customerResources','campus'])->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* 获取班级和资源信息
* @param int $id
* @return array
*/
public function getInfo(int $id)
{
$field = 'id,class_id,resource_id,campus_id,source_id,source_type,join_time,out_time,status,create_time,update_time';
$info = $this->model->field($field)->where([['id', "=", $id]])->with(['classGrade','customerResources','campus'])->findOrEmpty()->toArray();
return $info;
}
/**
* 添加班级和资源
* @param array $data
* @return mixed
*/
public function add(array $data)
{
$res = $this->model->create($data);
return $res->id;
}
/**
* 班级和资源编辑
* @param int $id
* @param array $data
* @return bool
*/
public function edit(int $id, array $data)
{
$this->model->where([['id', '=', $id]])->update($data);
return true;
}
/**
* 删除班级和资源
* @param int $id
* @return bool
*/
public function del(int $id)
{
$model = $this->model->where([['id', '=', $id]])->find();
$res = $model->delete();
return $res;
}
public function getClassGradeAll(){
$classGradeModel = new ClassGrade();
return $classGradeModel->select()->toArray();
}
public function getCustomerResourcesAll(){
$customerResourcesModel = new CustomerResources();
return $customerResourcesModel->select()->toArray();
}
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
}

79
niucloud/app/service/admin/exam_questions/ExamQuestionsService.php

@ -14,6 +14,7 @@ namespace app\service\admin\exam_questions;
use app\model\exam_questions\ExamQuestions;
use core\base\BaseAdminService;
use PhpOffice\PhpSpreadsheet\IOFactory;
/**
@ -120,5 +121,83 @@ class ExamQuestionsService extends BaseAdminService
return success("随机成功", ['questions_ids' => implode(',', $questions_ids)]);
}
public function to_lead_into(array $data)
{
$filePath = public_path() . $data['url'];
try {
$spreadsheet = IOFactory::load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$highestRow = $worksheet->getHighestRow();
$list = [];
// 遍历每一行
foreach ($worksheet->getRowIterator() as $rowIndex => $row) {
if ($rowIndex == 1) {
// 跳过第一行(表头)和最后一行
continue;
}
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
$data = [];
foreach ($cellIterator as $cell) {
$value = $cell->getValue(); // 获取每个单元格的值
if ($value instanceof \PhpOffice\PhpSpreadsheet\RichText\RichText) {
$value = $value->getPlainText();
}
$data[] = $value;
}
$list[] = $data;
}
$inserAll = [];
$question_type_arr = ['单选' => 'single_choice','多选'=>'multiple_choice','判断' => 'true_false'];
foreach ($list as $key => $item) {
$option_json = [
[
'option_content_type' => $item[4],
'option_content' => $item[5],
'option' => 'A',
'correct_answer' => str_contains($item[12], 'A')
],
[
'option_content_type' => $item[6],
'option_content' => $item[7],
'option' => 'B',
'correct_answer' => str_contains($item[12], 'B')
],
[
'option_content_type' => $item[8],
'option_content' => $item[9],
'option' => 'C',
'correct_answer' => str_contains($item[12], 'C')
],
[
'option_content_type' => $item[10],
'option_content' => $item[11],
'option' => 'D',
'correct_answer' => str_contains($item[12], 'D')
]
];
$inserAll[] = [
'title' => $item[0],
'question_type' =>$question_type_arr[$item[1]],
'question_content_type' => $item[2],
'question_content' => $item[3],
'option_json' => json_encode($option_json, JSON_UNESCAPED_UNICODE),
'correct_answer' => $item[12]
];
}
$this->model->insertAll($inserAll);
return success("导入成功");
} catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
return fail($e->getMessage());
}
}
}

14
niucloud/app/service/admin/student/StudentService.php

@ -11,6 +11,7 @@
namespace app\service\admin\student;
use app\model\class_resources_rel\ClassResourcesRel;
use app\model\student\Student;
use app\model\customer_resources\CustomerResources;
use app\model\campus\Campus;
@ -42,7 +43,7 @@ class StudentService extends BaseAdminService
public function getPage(array $where = [])
{
$field = 'id,user_id,campus_id,class_id,name,gender,age,birthday,member_label,emergency_contact,contact_phone,note,status,created_at,updated_at,deleted_at';
$order = 'id asc';
$order = 'id desc';
$search_model = $this->model->withSearch(["campus_id", "name", "emergency_contact", "contact_phone", "created_at", "member_label"], $where)->with(['customerResources', 'campus', 'classGrade'])->field($field)->order($order);
return $this->pageQuery($search_model, function ($item, $key) {
@ -60,6 +61,17 @@ class StudentService extends BaseAdminService
$field = 'id,user_id,campus_id,class_id,name,gender,age,birthday,emergency_contact,member_label,contact_phone,note,status,created_at,updated_at,deleted_at';
$info = $this->makeUp($this->model->field($field)->where([['id', "=", $id]])->with(['customerResources', 'campus', 'classGrade'])->findOrEmpty()->toArray());
$info['getInfoRel'] = $this->getInfoRel($info['user_id']);
return $info;
}
public function getInfoRel(int $resource_id)
{
$rel = new ClassResourcesRel();
$field = 'id,class_id,resource_id,campus_id,source_id,source_type,join_time,out_time,status,create_time,update_time';
$info = $rel->field($field)->where([['resource_id', "=", $resource_id]])->with(['classGrade','customerResources','campus'])->findOrEmpty()->toArray();
return $info;
}

35
niucloud/app/validate/class_resources_rel/ClassResourcesRel.php

@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\validate\class_resources_rel;
use core\base\BaseValidate;
/**
* 班级和资源验证器
* Class ClassResourcesRel
* @package addon\app\validate\class_resources_rel
*/
class ClassResourcesRel extends BaseValidate
{
protected $rule = [
'class_id' => 'require',
];
protected $message = [
'class_id.require' => ['common_validate.require', ['class_id']],
];
protected $scene = [
"add" => ['class_id', 'resource_id', 'campus_id', 'source_type', 'status'],
"edit" => ['class_id', 'resource_id', 'campus_id', 'source_type', 'status']
];
}
Loading…
Cancel
Save