初始化项目:添加后端代码、ThinkPHP框架、前端资源

This commit is contained in:
amb
2026-09-03 12:42:39 +08:00
commit 482bece22e
3726 changed files with 416708 additions and 0 deletions
@@ -0,0 +1,104 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class Exercises extends Model
{
// 表名
protected $name = 'app_exam_exercises';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
'status_text'
];
public function getStatusList()
{
return ['1' => __('Status 1'), '0' => __('Status 0')];
}
public function getHideList()
{
return ['1' => __('Hide 1'), '0' => __('Hide 0')];
}
public function getSalesTypeList()
{
return ['1' => __('Sales_type 1'), '3' => __('Sales_type 3'), '2' => __('Sales_type 2')];
}
public function getQuestionModeList()
{
return ['sort' => __('Question_mode sort'), 'random' => __('Question_mode random')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function course()
{
return $this->belongsTo('app\admin\model\course\Course', 'bind_course', 'id', [], 'LEFT')->setEagerlyType(0);
}
/**
* 获取绑定的题库分组
* @param $exercisesId
* @return mixed
*/
public function getBindWarehouseGroup($exercisesId){
$data = \app\admin\model\app\exam\ExercisesBindWarehouseGroup::with(['group'])->where([
'exercises_id'=>$exercisesId,
])->order('id','asc')->select();
// 转换为数组处理
$result = collection($data)->toArray();
// 处理未分组的情况(warehouse_group_id = 0 或 group.id 为 null
$allGroupIds = null;
foreach ($result as &$item) {
// 检查 group.id 是否为 null(表示关联的分组不存在)
if (empty($item['group']['id'])) {
// 计算未分组的题目数量(只查询一次)
if ($allGroupIds === null) {
$allGroupIds = \app\admin\model\app\exam\WarehouseGroup::field('id')->column('id');
}
$questionCount = \app\admin\model\app\exam\WarehouseQuestion::where(['group_id' => ['NOT IN', $allGroupIds]])->count();
// 设置未分组信息
$item['group'] = [
'id' => 0,
'name' => '未分组',
'question_count' => $questionCount
];
}
}
return $result;
}
}
@@ -0,0 +1,70 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class ExercisesBindWarehouseGroup extends Model
{
// 表名
protected $name = 'app_exam_exercises_bind_warehouse_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
];
public function group()
{
return $this->belongsTo('app\admin\model\app\exam\WarehouseGroup', 'warehouse_group_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function exercises()
{
return $this->belongsTo('Exercises', 'exercises_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
/**
* 通过练习ID绑定题库分组
* @param $exercisesId
* @param $groupIds
* @return bool
*/
public static function exercisesBindWarehouseGroup($exercisesId,$groupIds){
self::where([
'exercises_id'=>$exercisesId,
'uniacid'=>UNIACID
])->delete();
if($groupIds){
foreach ($groupIds as $itemId){
self::insert([
'exercises_id'=>$exercisesId,
'uniacid'=>UNIACID,
'warehouse_group_id'=>$itemId,
'createtime'=>time()
]);
}
}
return true;
}
}
@@ -0,0 +1,57 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
use think\Db;
class ExercisesGroup extends Model
{
// 表名
protected $name = 'app_exam_exercises_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
'status_text'
];
public function getStatusList()
{
return ['11' => __('Status 11')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 获取排序
* @return void
*/
public function defineSort(){
$maxItem = self::field("sort")->order("sort desc")->find();
if(!$maxItem){
return 0;
}
return $maxItem['sort'] + 1;
}
}
@@ -0,0 +1,59 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class ExercisesLog extends Model
{
// 表名
protected $name = 'app_exam_exercises_log';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
'status_text'
];
public function getStatusList()
{
return ['1' => __('Status 1'),'0' => __('Status 0')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function exercises()
{
return $this->belongsTo('Exercises', 'exercises_id', 'id', [], 'RIGHT')->setEagerlyType(0);
}
public function user()
{
return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'RIGHT')->setEagerlyType(0);
}
}
@@ -0,0 +1,50 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class ExercisesSubscribe extends Model
{
// 表名
protected $name = 'app_exam_exercises_subscribe';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
];
public function exercises()
{
return $this->belongsTo('Exercises', 'exercises_id', 'id', [], 'RIGHT')->setEagerlyType(0);
}
public function user()
{
return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'RIGHT')->setEagerlyType(0);
}
}
@@ -0,0 +1,77 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class WarehouseGroup extends Model
{
// 表名
protected $name = 'app_exam_warehouse_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
'status_text',
'question_count'
];
public $defaultGroudId = 990000;
public function getStatusList()
{
return ['11' => __('Status 11')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
/**
* 获取分组绑定的题目数量
* @param $value
* @param $data
* @return mixed
*/
public function getQuestionCountAttr($value, $data)
{
if(!$data['id']){
$ids = self::field('id')->column('id');
$count = \app\admin\model\app\exam\WarehouseQuestion::where(['group_id'=>['NOT IN',$ids]])->count();
return $count;
}
$count = \app\admin\model\app\exam\WarehouseQuestion::where([
'group_id'=>$data['id']
])->count();
return $count;
}
}
@@ -0,0 +1,260 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class WarehouseImport extends Model
{
protected $excelSheetNoTypes = ['single','multiple','judge','indefinite','fillblank','essay'];
/**
* 获取每一行的数据
* @param $data 题目数据
* @param $type 题目类型下标
* @param $groupId 分组ID
* @return false|mixed|null
*/
public function getRowData($data,$typeIndex,$groupId=0){
$rowData = false;
$type = $this->excelSheetNoTypes[$typeIndex];
if(empty($data[0])){
return $rowData;
}
switch ($type){
case 'judge':
if(count($data) != 3){
return false;
}
if(!in_array($data[1],["错误","正确","",""])){
return false;
}
$rowData = $this->parseJudge($data);
break;
case 'single':
if(count($data) < 13){
return false;
}
//判断是不是字母
if(!$data[11] || strlen($data[11]) != 1 || !ctype_alpha($data[11])){
return false;
}
$rowData = $this->parseSingle($data);
break;
case 'multiple':
if(count($data) < 13){
return false;
}
if(!$data[11] || strlen($data[11]) > 10 || !ctype_alpha($data[11])){
return false;
}
$rowData = $this->parseMultiple($data);
break;
case 'indefinite':
if(count($data) < 13){
return false;
}
if(!$data[11] || strlen($data[11]) > 10 || !ctype_alpha($data[11])){
return false;
}
$rowData = $this->parseMultiple($data, 'indefinite');
break;
case 'fillblank':
if(count($data) != 3){
return false;
}
$rowData = $this->parseFillblank($data);
break;
case 'essay':
if(count($data) != 3){
return false;
}
$rowData = $this->parseEssay($data);
break;
}
return $rowData;
}
/**
* 格式化单选题
* @param $data
* @return array|false
*/
public function parseSingle($data){
$rowData = [
'type'=>'single',
'question'=>$data[0],
'option'=>[],
'answer'=>0,
'analysis'=>$data[12]
];
foreach($data as $index => $option){
if($index > 0 && $index < 11){
if(!$option){
break;
}
if($option instanceof \PhpOffice\PhpSpreadsheet\RichText\RichText){
$option = $option->getPlainText();
}
$rowData['option'][] = $option;
}
}
$answer = ord($data[11]) - 65;
if($answer < 0 || ($answer > count($rowData['option']) - 1)){
return false;
}
$rowData['option'] = json_encode($rowData['option'],true);
$rowData['answer'] = $answer;
return $rowData;
}
/**
* 解析判断题
* @param $data
* @return array
*/
public function parseJudge($data){
$rowData = [
'type'=>'judge',
'question'=>$data[0],
'option'=>json_encode([]),
'answer'=>'',
'analysis'=>$data[2]
];
$rowData['answer'] = 1;
if(in_array($data[1],["","正确"])){
$rowData['answer'] = 0;
}
return $rowData;
}
/**
* 解析多选题
* @param $data
* @return array|false
*/
public function parseMultiple($data, $type = 'multiple'){
$rowData = [
'type'=>$type,
'question'=>$data[0],
'option'=>[],
'answer'=>'',
'analysis'=>$data[12]
];
foreach($data as $index => $option){
if($index > 0 && $index < 11){
if(!$option){
break;
}
if($option instanceof \PhpOffice\PhpSpreadsheet\RichText\RichText){
$option = $option->getPlainText();
}
$rowData['option'][] = $option;
}
}
$answer = [];
foreach (str_split($data[11]) as $item){
$item = ord($item) - 65;
if($item < 0 || $item > (count($rowData['option']) -1 )){
return false;
}
$answer[] = $item;
}
$rowData['option'] = json_encode($rowData['option'],true);
if(count($answer) < 2 || count($answer) > 10){
return false;
}
$rowData['answer'] = implode(",",$answer);
return $rowData;
}
/**
* 解析不定项选择题
* @param $data
* @return array|false
*/
public function parseIndefinite($data){
return $this->parseMultiple($data, 'indefinite');
}
/**
* 解析填空题
* 格式:题目、各空格答案(空格用"|"分隔,备选答案用","分隔)、解析
* @param $data
* @return array
*/
public function parseFillblank($data){
$answers = [];
$blanks = explode('|', $data[1]);
foreach($blanks as $blank){
$answers[] = explode(',', $blank);
}
return [
'type'=>'fillblank',
'question'=>$data[0],
'option'=>json_encode([]),
'answer'=>json_encode($answers),
'analysis'=>$data[2]
];
}
/**
* 解析问答题
* 格式:题目、参考答案、解析
* @param $data
* @return array
*/
public function parseEssay($data){
return [
'type'=>'essay',
'question'=>$data[0],
'option'=>json_encode([]),
'answer'=>$data[1],
'analysis'=>$data[2]
];
}
}
@@ -0,0 +1,75 @@
<?php
namespace app\admin\model\app\exam;
use think\Model;
class WarehouseQuestion extends Model
{
// 表名
protected $name = 'app_exam_warehouse_question';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
'option',
'type_text',
];
public function getOptionAttr($value, $data)
{
if(!isset($data['option']) || !$data['option']){
return [];
}
return json_decode($data['option'],true);
}
public function getTypeTextAttr($value, $data)
{
// $lang = require_once APP_PATH."admin/lang/zh-cn/app/exam/warehouse_question.php";
if(!isset($data['type']) || !$data['type']){
return '';
}
return __('Question Type '.$data['type']);
}
public function getTypeList()
{
return ['single' => __('Status single'),'multiple' => __('Status multiple'),'judge' => __('Status judge'),'indefinite' => __('Status indefinite'),'fillblank' => __('Status fillblank'),'essay' => __('Status essay')];
}
//难度
public function getDegreeList()
{
return ['1' => __('Degree 1'),'2' => __('Degree 2'),'3' => __('Degree 3')];
}
public function group()
{
return $this->belongsTo('app\admin\model\app\exam\WarehouseGroup', 'group_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
}
@@ -0,0 +1,12 @@
<?php
namespace app\admin\model\app\exam\warehouse;
use think\Model;
class Group extends Model
{
// 表名
protected $name = 'app_exam_warehouse_group';
}
@@ -0,0 +1,12 @@
<?php
namespace app\admin\model\app\exam\warehouse;
use think\Model;
class Question extends Model
{
// 表名
protected $name = 'app_exam_warehouse_question';
}