增加考题管理模块

This commit is contained in:
2025-11-17 17:38:34 +08:00
parent e98b30edd3
commit 0fff276e59
13 changed files with 1951 additions and 45 deletions
+340
View File
@@ -0,0 +1,340 @@
package controllers
import (
"encoding/json"
"strconv"
"server/models"
"server/services"
beego "github.com/beego/beego/v2/server/web"
)
type ExamQuestionController struct {
beego.Controller
}
type ExamQuestionBankController struct {
beego.Controller
}
// Get list
// @router /exam-questions [get]
func (c *ExamQuestionController) GetList() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
keyword := c.GetString("keyword")
typeStr := c.GetString("type")
var qtype *int8
if typeStr != "" {
if iv, err := strconv.Atoi(typeStr); err == nil {
v := int8(iv)
qtype = &v
}
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 10)
list, total, err := services.GetExamQuestions(services.QuestionListParams{
TenantId: tenantId,
Keyword: keyword,
QuestionType: qtype,
Page: page,
PageSize: pageSize,
})
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "获取试题列表失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
// build minimal DTO to limit fields in response
items := make([]map[string]interface{}, 0, len(list))
for _, q := range list {
if q == nil {
continue
}
items = append(items, map[string]interface{}{
"id": q.Id,
"tenant_id": q.TenantId,
"question_type": q.QuestionType,
"question_title": q.QuestionTitle,
"score": q.Score,
})
}
c.Data["json"] = map[string]interface{}{
"code": 0,
"message": "ok",
"data": map[string]interface{}{
"list": items,
"total": total,
},
}
c.ServeJSON()
}
// Get detail
// @router /exam-questions/:id [get]
func (c *ExamQuestionController) GetDetail() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
id, err := c.GetInt64(":id")
if err != nil || id <= 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "ID无效", "data": nil}
c.ServeJSON()
return
}
detail, err := services.GetExamQuestionDetail(tenantId, id)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "试题不存在", "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": detail}
c.ServeJSON()
}
// Create
// @router /exam-questions [post]
func (c *ExamQuestionController) Create() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
var payload struct {
QuestionTitle string `json:"question_title"`
QuestionType int8 `json:"question_type"`
Score float64 `json:"score"`
QuestionAnalysis string `json:"question_analysis"`
Options []map[string]string `json:"options"`
Answer interface{} `json:"answer"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &payload); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数错误: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
q := &models.ExamQuestion{
TenantId: tenantId,
QuestionType: payload.QuestionType,
QuestionTitle: payload.QuestionTitle,
QuestionAnalysis: payload.QuestionAnalysis,
Score: payload.Score,
Status: 1,
}
var opts []models.ExamQuestionOption
for _, o := range payload.Options {
opts = append(opts, models.ExamQuestionOption{OptionLabel: o["label"], OptionContent: o["content"]})
}
answerContent := ""
switch v := payload.Answer.(type) {
case string:
answerContent = v
case []interface{}:
for i, item := range v {
if s, ok := item.(string); ok {
if i == 0 {
answerContent = s
} else {
answerContent += "," + s
}
}
}
}
id, err := services.CreateExamQuestion(tenantId, q, opts, answerContent)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "创建失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "创建成功", "data": map[string]interface{}{"id": id}}
c.ServeJSON()
}
// Update
// @router /exam-questions/:id [put]
func (c *ExamQuestionController) Update() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
id, err := c.GetInt64(":id")
if err != nil || id <= 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "ID无效", "data": nil}
c.ServeJSON()
return
}
var payload struct {
QuestionTitle string `json:"question_title"`
QuestionType int8 `json:"question_type"`
Score float64 `json:"score"`
QuestionAnalysis string `json:"question_analysis"`
Options []map[string]string `json:"options"`
Answer interface{} `json:"answer"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &payload); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数错误: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
q := &models.ExamQuestion{QuestionType: payload.QuestionType, QuestionTitle: payload.QuestionTitle, QuestionAnalysis: payload.QuestionAnalysis, Score: payload.Score}
var opts []models.ExamQuestionOption
for _, o := range payload.Options {
opts = append(opts, models.ExamQuestionOption{OptionLabel: o["label"], OptionContent: o["content"]})
}
answerContent := ""
switch v := payload.Answer.(type) {
case string:
answerContent = v
case []interface{}:
for i, item := range v {
if s, ok := item.(string); ok {
if i == 0 {
answerContent = s
} else {
answerContent += "," + s
}
}
}
}
if err := services.UpdateExamQuestion(tenantId, id, q, opts, answerContent); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "更新失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "更新成功", "data": nil}
c.ServeJSON()
}
// Delete
// @router /exam-questions/:id [delete]
func (c *ExamQuestionController) Delete() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
id, err := c.GetInt64(":id")
if err != nil || id <= 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "ID无效", "data": nil}
c.ServeJSON()
return
}
if err := services.DeleteExamQuestion(tenantId, id); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "删除失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "删除成功", "data": nil}
c.ServeJSON()
}
// GetBankList
// @router /exam-question-banks [get]
func (c *ExamQuestionBankController) GetBankList() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
keyword := c.GetString("keyword")
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 10)
list, total, err := services.GetExamQuestionBanks(services.BankListParams{
TenantId: tenantId,
Keyword: keyword,
Page: page,
PageSize: pageSize,
})
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "获取试题库列表失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": map[string]interface{}{"list": list, "total": total}}
c.ServeJSON()
}
// GetBankDetail
// @router /exam-question-banks/:id [get]
func (c *ExamQuestionBankController) GetBankDetail() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
id, err := c.GetInt64(":id")
if err != nil || id <= 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "ID无效", "data": nil}
c.ServeJSON()
return
}
bank, err := services.GetExamQuestionBankDetail(tenantId, id)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "试题库不存在", "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": bank}
c.ServeJSON()
}
// CreateBank
// @router /exam-question-banks [post]
func (c *ExamQuestionBankController) CreateBank() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
var payload struct {
BankName string `json:"bank_name"`
BankDesc string `json:"bank_desc"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &payload); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数错误: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
bank := &models.ExamQuestionBank{
TenantId: tenantId,
BankName: payload.BankName,
BankDesc: payload.BankDesc,
Status: 1,
}
id, err := services.CreateExamQuestionBank(tenantId, bank)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "创建失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "创建成功", "data": map[string]interface{}{"id": id}}
c.ServeJSON()
}
// UpdateBank
// @router /exam-question-banks/:id [put]
func (c *ExamQuestionBankController) UpdateBank() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
id, err := c.GetInt64(":id")
if err != nil || id <= 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "ID无效", "data": nil}
c.ServeJSON()
return
}
var payload struct {
BankName string `json:"bank_name"`
BankDesc string `json:"bank_desc"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &payload); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数错误: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
bank := &models.ExamQuestionBank{
Id: id,
TenantId: tenantId,
BankName: payload.BankName,
BankDesc: payload.BankDesc,
}
if err := services.UpdateExamQuestionBank(tenantId, id, bank); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "更新失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "更新成功", "data": nil}
c.ServeJSON()
}
// DeleteBank
// @router /exam-question-banks/:id [delete]
func (c *ExamQuestionBankController) DeleteBank() {
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
id, err := c.GetInt64(":id")
if err != nil || id <= 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "ID无效", "data": nil}
c.ServeJSON()
return
}
if err := services.DeleteExamQuestionBank(tenantId, id); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "删除失败: " + err.Error(), "data": nil}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"code": 0, "message": "删除成功", "data": nil}
c.ServeJSON()
}
+25 -1
View File
@@ -1,4 +1,4 @@
-- MySQL dump 10.13 Distrib 8.0.41, for Win64 (x86_64)
-- MySQL dump 10.13 Distrib 8.0.41, for Win64 (x86_64)
--
-- Host: 212.64.112.158 Database: gotest
-- ------------------------------------------------------
@@ -228,6 +228,30 @@ CREATE TABLE `yz_exam_category` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试分类表(含多租户隔离)';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `yz_exam_question_bank`
--
DROP TABLE IF EXISTS `yz_exam_question_bank`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `yz_exam_question_bank` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '题库ID',
`tenant_id` int(11) NOT NULL COMMENT '租户ID(多租户隔离)',
`bank_name` varchar(100) NOT NULL COMMENT '题库名称',
`bank_desc` varchar(500) DEFAULT '' COMMENT '题库描述',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态(1-启用,0-禁用)',
`sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序序号',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间(软删除)',
PRIMARY KEY (`id`),
KEY `idx_tenant_status` (`tenant_id`,`status`),
KEY `idx_tenant_name` (`tenant_id`,`bank_name`),
KEY `idx_delete_time` (`delete_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试题库表(支持租户隔离、软删除)';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `yz_exam_users`
--
+79
View File
@@ -0,0 +1,79 @@
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// ExamQuestion 对应表 yz_exam_question
type ExamQuestion struct {
Id int64 `orm:"column(id);auto" json:"id"`
TenantId int `orm:"column(tenant_id)" json:"tenant_id"`
QuestionType int8 `orm:"column(question_type)" json:"question_type"`
QuestionTitle string `orm:"column(question_title);size(1000)" json:"question_title"`
QuestionAnalysis string `orm:"column(question_analysis);size(2000);null" json:"question_analysis"`
Score float64 `orm:"column(score);digits(5);decimals(2)" json:"score"`
SortOrder int8 `orm:"column(sort_order);null" json:"sort_order"`
Status int8 `orm:"column(status)" json:"status"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"`
}
func (q *ExamQuestion) TableName() string {
return "yz_exam_question"
}
// ExamQuestionOption 对应表 yz_exam_question_option
type ExamQuestionOption struct {
Id int64 `orm:"column(id);auto" json:"id"`
TenantId int `orm:"column(tenant_id)" json:"tenant_id"`
QuestionId int64 `orm:"column(question_id)" json:"question_id"`
OptionLabel string `orm:"column(option_label);size(10)" json:"option_label"`
OptionContent string `orm:"column(option_content);size(500)" json:"option_content"`
SortOrder int8 `orm:"column(sort_order);null" json:"sort_order"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"`
}
func (o *ExamQuestionOption) TableName() string {
return "yz_exam_question_option"
}
// ExamQuestionAnswer 对应表 yz_exam_question_answer
type ExamQuestionAnswer struct {
Id int64 `orm:"column(id);auto" json:"id"`
TenantId int `orm:"column(tenant_id)" json:"tenant_id"`
QuestionId int64 `orm:"column(question_id)" json:"question_id"`
AnswerContent string `orm:"column(answer_content);size(1000)" json:"answer_content"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"`
}
func (a *ExamQuestionAnswer) TableName() string {
return "yz_exam_question_answer"
}
// ExamQuestionBank 对应表 yz_exam_question_bank
type ExamQuestionBank struct {
Id int64 `orm:"column(id);auto" json:"id"`
TenantId int `orm:"column(tenant_id)" json:"tenant_id"`
BankName string `orm:"column(bank_name);size(100)" json:"bank_name"`
BankDesc string `orm:"column(bank_desc);size(500);null" json:"bank_desc"`
Status int8 `orm:"column(status)" json:"status"`
SortOrder int8 `orm:"column(sort_order);null" json:"sort_order"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"`
}
func (b *ExamQuestionBank) TableName() string {
return "yz_exam_question_bank"
}
func init() {
orm.RegisterModel(new(ExamQuestion), new(ExamQuestionOption), new(ExamQuestionAnswer), new(ExamQuestionBank))
}
+13 -5
View File
@@ -283,12 +283,20 @@ func init() {
beego.Router("/api/files/search", &controllers.FileController{}, "get:SearchFiles")
beego.Router("/api/files/statistics", &controllers.FileController{}, "get:GetFileStatistics")
// 考试题目路由
beego.Router("/api/exam-questions", &controllers.ExamQuestionController{}, "get:GetList;post:Create")
beego.Router("/api/exam-questions/:id", &controllers.ExamQuestionController{}, "get:GetDetail;put:Update;delete:Delete")
// 考试题库路由
beego.Router("/api/exam-question-banks", &controllers.ExamQuestionBankController{}, "get:GetBankList;post:CreateBank")
beego.Router("/api/exam-question-banks/:id", &controllers.ExamQuestionBankController{}, "get:GetBankDetail;put:UpdateBank;delete:DeleteBank")
// 知识库路由
beego.Router("/api/knowledge/list", &controllers.KnowledgeController{}, "get:List")
beego.Router("/api/knowledge/count", &controllers.KnowledgeController{}, "get:GetCount")
beego.Router("/api/knowledge/detail", &controllers.KnowledgeController{}, "get:Detail")
beego.Router("/api/knowledge/create", &controllers.KnowledgeController{}, "post:Create")
beego.Router("/api/knowledge/update", &controllers.KnowledgeController{}, "post:Update")
// ...
beego.Router("/api/knowledge/delete", &controllers.KnowledgeController{}, "post:Delete")
beego.Router("/api/knowledge/categories", &controllers.KnowledgeController{}, "get:GetCategories")
beego.Router("/api/knowledge/tags", &controllers.KnowledgeController{}, "get:GetTags")
@@ -314,10 +322,10 @@ func init() {
// OA基础数据合并接口(一次性获取部门、职位、角色)
beego.Router("/api/oa/base-data/:tenantId", &controllers.OAController{}, "get:GetOABaseData")
// OA任务管理路由
beego.Router("/api/oa/tasks", &controllers.TaskController{}, "get:GetTasks;post:CreateTask")
beego.Router("/api/oa/tasks/:id", &controllers.TaskController{}, "get:GetTaskById;put:UpdateTask;delete:DeleteTask")
beego.Router("/api/oa/tasks/todo", &controllers.TaskController{}, "get:GetTodoTasks")
// OA任务管理路由
beego.Router("/api/oa/tasks", &controllers.TaskController{}, "get:GetTasks;post:CreateTask")
beego.Router("/api/oa/tasks/:id", &controllers.TaskController{}, "get:GetTaskById;put:UpdateTask;delete:DeleteTask")
beego.Router("/api/oa/tasks/todo", &controllers.TaskController{}, "get:GetTodoTasks")
// CRM 客户路由
beego.Router("/api/crm/customer/list", &controllers.CustomerController{}, "get:List")
+224
View File
@@ -0,0 +1,224 @@
package services
import (
"errors"
"time"
"server/models"
"github.com/beego/beego/v2/client/orm"
)
type QuestionListParams struct {
TenantId int
Keyword string
QuestionType *int8
Page int
PageSize int
}
type QuestionWithMeta struct {
Question *models.ExamQuestion
Options []*models.ExamQuestionOption
Answer *models.ExamQuestionAnswer
}
type BankListParams struct {
TenantId int
Keyword string
Page int
PageSize int
}
func GetExamQuestions(params QuestionListParams) ([]*models.ExamQuestion, int64, error) {
o := orm.NewOrm()
qs := o.QueryTable(new(models.ExamQuestion)).Filter("delete_time__isnull", true).Filter("status", 1)
if params.TenantId > 0 {
qs = qs.Filter("tenant_id", params.TenantId)
}
if params.Keyword != "" {
qs = qs.Filter("question_title__icontains", params.Keyword)
}
if params.QuestionType != nil {
qs = qs.Filter("question_type", *params.QuestionType)
}
total, err := qs.Count()
if err != nil {
return nil, 0, err
}
if params.Page <= 0 {
params.Page = 1
}
if params.PageSize <= 0 {
params.PageSize = 10
}
offset := (params.Page - 1) * params.PageSize
var list []*models.ExamQuestion
_, err = qs.OrderBy("-id").Limit(params.PageSize, offset).All(&list, "Id", "TenantId", "QuestionType", "QuestionTitle", "Score")
return list, total, err
}
func GetExamQuestionDetail(tenantId int, id int64) (*QuestionWithMeta, error) {
o := orm.NewOrm()
q := new(models.ExamQuestion)
if err := o.QueryTable(q).Filter("id", id).Filter("delete_time__isnull", true).One(q); err != nil {
return nil, err
}
if tenantId > 0 && q.TenantId != tenantId {
return nil, errors.New("not found")
}
var opts []*models.ExamQuestionOption
_, _ = o.QueryTable(new(models.ExamQuestionOption)).Filter("question_id", q.Id).Filter("delete_time__isnull", true).All(&opts)
a := new(models.ExamQuestionAnswer)
_ = o.QueryTable(a).Filter("question_id", q.Id).Filter("delete_time__isnull", true).One(a)
return &QuestionWithMeta{Question: q, Options: opts, Answer: a}, nil
}
func CreateExamQuestion(tenantId int, q *models.ExamQuestion, options []models.ExamQuestionOption, answerContent string) (int64, error) {
o := orm.NewOrm()
if tenantId > 0 {
q.TenantId = tenantId
}
q.Status = 1
if _, err := o.Insert(q); err != nil {
return 0, err
}
for i := range options {
options[i].TenantId = q.TenantId
options[i].QuestionId = q.Id
_, _ = o.Insert(&options[i])
}
ans := &models.ExamQuestionAnswer{TenantId: q.TenantId, QuestionId: q.Id, AnswerContent: answerContent}
_, _ = o.Insert(ans)
return q.Id, nil
}
func UpdateExamQuestion(tenantId int, id int64, q *models.ExamQuestion, options []models.ExamQuestionOption, answerContent string) error {
o := orm.NewOrm()
existing := models.ExamQuestion{Id: id}
if err := o.Read(&existing); err != nil {
return err
}
if tenantId > 0 && existing.TenantId != tenantId {
return errors.New("not found")
}
existing.QuestionType = q.QuestionType
existing.QuestionTitle = q.QuestionTitle
existing.QuestionAnalysis = q.QuestionAnalysis
existing.Score = q.Score
if _, err := o.Update(&existing, "QuestionType", "QuestionTitle", "QuestionAnalysis", "Score"); err != nil {
return err
}
// soft delete old options and answer
now := time.Now()
o.QueryTable(new(models.ExamQuestionOption)).Filter("question_id", id).Filter("delete_time__isnull", true).Update(orm.Params{"delete_time": now})
o.QueryTable(new(models.ExamQuestionAnswer)).Filter("question_id", id).Filter("delete_time__isnull", true).Update(orm.Params{"delete_time": now})
for i := range options {
options[i].TenantId = existing.TenantId
options[i].QuestionId = id
_, _ = o.Insert(&options[i])
}
ans := &models.ExamQuestionAnswer{TenantId: existing.TenantId, QuestionId: id, AnswerContent: answerContent}
_, _ = o.Insert(ans)
return nil
}
func DeleteExamQuestion(tenantId int, id int64) error {
o := orm.NewOrm()
existing := models.ExamQuestion{Id: id}
if err := o.Read(&existing); err != nil {
return err
}
if tenantId > 0 && existing.TenantId != tenantId {
return errors.New("not found")
}
now := time.Now()
if _, err := o.QueryTable(new(models.ExamQuestion)).Filter("id", id).Update(orm.Params{"delete_time": now}); err != nil {
return err
}
o.QueryTable(new(models.ExamQuestionOption)).Filter("question_id", id).Filter("delete_time__isnull", true).Update(orm.Params{"delete_time": now})
o.QueryTable(new(models.ExamQuestionAnswer)).Filter("question_id", id).Filter("delete_time__isnull", true).Update(orm.Params{"delete_time": now})
return nil
}
func GetExamQuestionBanks(params BankListParams) ([]*models.ExamQuestionBank, int64, error) {
o := orm.NewOrm()
qs := o.QueryTable(new(models.ExamQuestionBank)).Filter("delete_time__isnull", true).Filter("status", 1)
if params.TenantId > 0 {
qs = qs.Filter("tenant_id", params.TenantId)
}
if params.Keyword != "" {
qs = qs.Filter("bank_name__icontains", params.Keyword)
}
total, err := qs.Count()
if err != nil {
return nil, 0, err
}
if params.Page <= 0 {
params.Page = 1
}
if params.PageSize <= 0 {
params.PageSize = 10
}
offset := (params.Page - 1) * params.PageSize
var list []*models.ExamQuestionBank
_, err = qs.OrderBy("-id").Limit(params.PageSize, offset).All(&list, "Id", "TenantId", "BankName", "BankDesc")
return list, total, err
}
func GetExamQuestionBankDetail(tenantId int, id int64) (*models.ExamQuestionBank, error) {
o := orm.NewOrm()
bank := new(models.ExamQuestionBank)
if err := o.QueryTable(bank).Filter("id", id).Filter("delete_time__isnull", true).One(bank); err != nil {
return nil, err
}
if tenantId > 0 && bank.TenantId != tenantId {
return nil, errors.New("not found")
}
return bank, nil
}
func CreateExamQuestionBank(tenantId int, bank *models.ExamQuestionBank) (int64, error) {
o := orm.NewOrm()
if tenantId > 0 {
bank.TenantId = tenantId
}
bank.Status = 1
if _, err := o.Insert(bank); err != nil {
return 0, err
}
return bank.Id, nil
}
func UpdateExamQuestionBank(tenantId int, id int64, bank *models.ExamQuestionBank) error {
o := orm.NewOrm()
existing := models.ExamQuestionBank{Id: id}
if err := o.Read(&existing); err != nil {
return err
}
if tenantId > 0 && existing.TenantId != tenantId {
return errors.New("not found")
}
existing.BankName = bank.BankName
existing.BankDesc = bank.BankDesc
if _, err := o.Update(&existing, "BankName", "BankDesc"); err != nil {
return err
}
return nil
}
func DeleteExamQuestionBank(tenantId int, id int64) error {
o := orm.NewOrm()
existing := models.ExamQuestionBank{Id: id}
if err := o.Read(&existing); err != nil {
return err
}
if tenantId > 0 && existing.TenantId != tenantId {
return errors.New("not found")
}
now := time.Now()
if _, err := o.QueryTable(new(models.ExamQuestionBank)).Filter("id", id).Update(orm.Params{"delete_time": now}); err != nil {
return err
}
return nil
}