diff --git a/admin/src/app/api/class_resources_rel.ts b/admin/src/app/api/class_resources_rel.ts new file mode 100644 index 00000000..32f68af1 --- /dev/null +++ b/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) { + 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) { + return request.post('class_resources_rel/class_resources_rel', params, { showErrorMessage: true, showSuccessMessage: true }) +} + +/** + * 编辑班级和资源 + * @param id + * @param params + * @returns + */ +export function editClassResourcesRel(params: Record) { + 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){ + return request.get('class_resources_rel/class_grade_all', {params}) +}export function getWithCustomerResourcesList(params: Record){ + return request.get('class_resources_rel/customer_resources_all', {params}) +}export function getWithCampusList(params: Record){ + return request.get('class_resources_rel/campus_all', {params}) +} + +// USER_CODE_END -- class_resources_rel diff --git a/admin/src/app/api/exam_questions.ts b/admin/src/app/api/exam_questions.ts index d8fb2843..7d7554a9 100644 --- a/admin/src/app/api/exam_questions.ts +++ b/admin/src/app/api/exam_questions.ts @@ -55,3 +55,7 @@ export function randomQuestionsList(params: Record) { // USER_CODE_END -- exam_questions + +export function toLeadInto(params: Record) { + return request.post(`exam_questions/to_lead_into`, params, { showErrorMessage: true, showSuccessMessage: true }) +} diff --git a/admin/src/app/api/sys.ts b/admin/src/app/api/sys.ts index 8ab32776..8f9d0f04 100644 --- a/admin/src/app/api/sys.ts +++ b/admin/src/app/api/sys.ts @@ -786,3 +786,8 @@ export function getJlyjConfig() { export function getHome(params: Record) { return request.post('sys/home', params) } + + +export function setDocument(params: Record) { + return request.post('sys/document/document', params) +} \ No newline at end of file diff --git a/admin/src/app/lang/zh-cn/class_resources_rel.class_resources_rel.json b/admin/src/app/lang/zh-cn/class_resources_rel.class_resources_rel.json new file mode 100644 index 00000000..fdff50b9 --- /dev/null +++ b/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":"请选择结束时间" +} \ No newline at end of file diff --git a/admin/src/app/views/class_resources_rel/class_resources_rel.vue b/admin/src/app/views/class_resources_rel/class_resources_rel.vue new file mode 100644 index 00000000..88d9c0d5 --- /dev/null +++ b/admin/src/app/views/class_resources_rel/class_resources_rel.vue @@ -0,0 +1,201 @@ + + + + + diff --git a/admin/src/app/views/class_resources_rel/components/class-resources-rel-edit.vue b/admin/src/app/views/class_resources_rel/components/class-resources-rel-edit.vue new file mode 100644 index 00000000..4dd22664 --- /dev/null +++ b/admin/src/app/views/class_resources_rel/components/class-resources-rel-edit.vue @@ -0,0 +1,251 @@ + + + + + + diff --git a/admin/src/app/views/exam_questions/components/exam-questions-edit.vue b/admin/src/app/views/exam_questions/components/exam-questions-edit.vue index 2efcdf11..a1704b3d 100644 --- a/admin/src/app/views/exam_questions/components/exam-questions-edit.vue +++ b/admin/src/app/views/exam_questions/components/exam-questions-edit.vue @@ -83,7 +83,7 @@ - 添加选项 + 添加选项 @@ -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) => { diff --git a/admin/src/app/views/exam_questions/exam_questions.vue b/admin/src/app/views/exam_questions/exam_questions.vue index 0225bc45..b9898692 100644 --- a/admin/src/app/views/exam_questions/exam_questions.vue +++ b/admin/src/app/views/exam_questions/exam_questions.vue @@ -35,6 +35,13 @@ {{ t('search') }} {{ t('reset') }} + 下载导入模板 + + + 导入 + + + @@ -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() +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 = { + 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([]) diff --git a/admin/src/app/views/student/components/student-edit.vue b/admin/src/app/views/student/components/student-edit.vue index f44e52bd..0b967cd3 100644 --- a/admin/src/app/views/student/components/student-edit.vue +++ b/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)" /> diff --git a/admin/src/app/views/student/student.vue b/admin/src/app/views/student/student.vue index bf1c7624..2781b97a 100644 --- a/admin/src/app/views/student/student.vue +++ b/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'])" /> @@ -68,12 +68,12 @@ - + @@ -122,6 +122,7 @@ @@ -136,6 +137,8 @@ + + @@ -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 | null = ref(null) + +const classEvent = (data: any) => { + classStudentDialog.value.setFormData(data) + classStudentDialog.value.showDialog = true +} + + /** * 删除学员 */ diff --git a/niucloud/app/adminapi/controller/class_resources_rel/ClassResourcesRel.php b/niucloud/app/adminapi/controller/class_resources_rel/ClassResourcesRel.php new file mode 100644 index 00000000..e23c0641 --- /dev/null +++ b/niucloud/app/adminapi/controller/class_resources_rel/ClassResourcesRel.php @@ -0,0 +1,104 @@ +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()); + } + +} diff --git a/niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php b/niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php index 6c659725..9f16d121 100644 --- a/niucloud/app/adminapi/controller/exam_questions/ExamQuestions.php +++ b/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); + } + + } diff --git a/niucloud/app/adminapi/route/class_resources_rel.php b/niucloud/app/adminapi/route/class_resources_rel.php new file mode 100644 index 00000000..b02adcdf --- /dev/null +++ b/niucloud/app/adminapi/route/class_resources_rel.php @@ -0,0 +1,43 @@ +middleware([ + AdminCheckToken::class, + AdminCheckRole::class, + AdminLog::class +]); +// USER_CODE_END -- class_resources_rel diff --git a/niucloud/app/adminapi/route/exam_questions.php b/niucloud/app/adminapi/route/exam_questions.php index f54840ba..3e555683 100644 --- a/niucloud/app/adminapi/route/exam_questions.php +++ b/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, diff --git a/niucloud/app/model/class_resources_rel/ClassResourcesRel.php b/niucloud/app/model/class_resources_rel/ClassResourcesRel.php new file mode 100644 index 00000000..38c26d8f --- /dev/null +++ b/niucloud/app/model/class_resources_rel/ClassResourcesRel.php @@ -0,0 +1,68 @@ +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']); + } + +} diff --git a/niucloud/app/service/admin/class_resources_rel/ClassResourcesRelService.php b/niucloud/app/service/admin/class_resources_rel/ClassResourcesRelService.php new file mode 100644 index 00000000..0c149cc8 --- /dev/null +++ b/niucloud/app/service/admin/class_resources_rel/ClassResourcesRelService.php @@ -0,0 +1,117 @@ +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(); + } + + +} diff --git a/niucloud/app/service/admin/exam_questions/ExamQuestionsService.php b/niucloud/app/service/admin/exam_questions/ExamQuestionsService.php index a969bf51..9abb6263 100644 --- a/niucloud/app/service/admin/exam_questions/ExamQuestionsService.php +++ b/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()); + } + + } } diff --git a/niucloud/app/service/admin/student/StudentService.php b/niucloud/app/service/admin/student/StudentService.php index 2d6b0e0d..3f88769a 100644 --- a/niucloud/app/service/admin/student/StudentService.php +++ b/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; } diff --git a/niucloud/app/validate/class_resources_rel/ClassResourcesRel.php b/niucloud/app/validate/class_resources_rel/ClassResourcesRel.php new file mode 100644 index 00000000..b6888913 --- /dev/null +++ b/niucloud/app/validate/class_resources_rel/ClassResourcesRel.php @@ -0,0 +1,35 @@ + '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'] + ]; + +}