judgeCase;
+
+ @Schema(description = "判题配置(JSON格式)", example = "{\"timeLimit\":3000,\"memoryLimit\":256}")
+ private JudgeConfig judgeConfig;
+
+
+}
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java
new file mode 100644
index 0000000..4a26ad7
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java
@@ -0,0 +1,18 @@
+package cn.meowrain.aioj.backend.question.dto.resp;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 题目响应 DTO
+ */
+@Data
+@Schema(description = "题目响应")
+public class QuestionResponseDTO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java
new file mode 100644
index 0000000..30ec4ca
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java
@@ -0,0 +1,17 @@
+package cn.meowrain.aioj.backend.question.dto.resp;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 题目提交响应 DTO
+ */
+@Data
+@Schema(description = "题目提交响应")
+public class QuestionSubmitResponseDTO implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java
new file mode 100644
index 0000000..18b95c2
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 题目服务模块
+ *
+ * 提供编程题目管理、测试用例管理等功能
+ */
+package cn.meowrain.aioj.backend.question;
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java
new file mode 100644
index 0000000..8d5cf55
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java
@@ -0,0 +1,54 @@
+package cn.meowrain.aioj.backend.question.service;
+
+import cn.meowrain.aioj.backend.question.dao.entity.Question;
+import cn.meowrain.aioj.backend.question.dto.req.QuestionQueryRequestDTO;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 题目服务接口
+ */
+public interface QuestionService extends IService {
+
+ /**
+ * 创建题目
+ * @param question 题目信息
+ * @return 题目ID
+ */
+ Long createQuestion(Question question);
+
+ /**
+ * 更新题目
+ * @param question 题目信息
+ * @return 是否成功
+ */
+ Boolean updateQuestion(Question question);
+
+ /**
+ * 删除题目
+ * @param questionId 题目ID
+ * @return 是否成功
+ */
+ Boolean deleteQuestion(Long questionId);
+
+ /**
+ * 根据ID获取题目详情
+ * @param questionId 题目ID
+ * @return 题目详情
+ */
+ Question getQuestionById(Long questionId);
+
+ /**
+ * 根据ID获取题目详情(内部接口)
+ * @param questionId 题目ID
+ * @return 题目详情
+ */
+ Question getQuestionByIdInner(Long questionId);
+
+ /**
+ * 分页查询题目列表
+ * @param request 查询条件
+ * @return 题目分页列表
+ */
+ Page listQuestions(QuestionQueryRequestDTO request);
+}
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java
new file mode 100644
index 0000000..3bb4ccc
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java
@@ -0,0 +1,31 @@
+package cn.meowrain.aioj.backend.question.service;
+
+import cn.meowrain.aioj.backend.question.dao.entity.QuestionSubmit;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 题目提交服务接口
+ */
+public interface QuestionSubmitService extends IService {
+
+ /**
+ * 创建提交记录
+ * @param questionSubmit 提交信息
+ * @return 提交ID
+ */
+ Long createSubmit(QuestionSubmit questionSubmit);
+
+ /**
+ * 更新提交状态
+ * @param questionSubmit 提交信息
+ * @return 是否成功
+ */
+ Boolean updateSubmitStatus(QuestionSubmit questionSubmit);
+
+ /**
+ * 根据ID获取提交记录
+ * @param submitId 提交ID
+ * @return 提交记录
+ */
+ QuestionSubmit getSubmitById(Long submitId);
+}
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java
new file mode 100644
index 0000000..0928787
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java
@@ -0,0 +1,85 @@
+package cn.meowrain.aioj.backend.question.service.impl;
+
+import cn.meowrain.aioj.backend.question.dao.entity.Question;
+import cn.meowrain.aioj.backend.question.dao.mapper.QuestionMapper;
+import cn.meowrain.aioj.backend.question.dto.req.QuestionQueryRequestDTO;
+import cn.meowrain.aioj.backend.question.service.QuestionService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+/**
+ * 题目服务实现
+ */
+@Service
+@RequiredArgsConstructor
+public class QuestionServiceImpl extends ServiceImpl implements QuestionService {
+
+ @Override
+ public Long createQuestion(Question question) {
+ this.save(question);
+ return question.getId();
+ }
+
+ @Override
+ public Boolean updateQuestion(Question question) {
+ return this.updateById(question);
+ }
+
+ @Override
+ public Boolean deleteQuestion(Long questionId) {
+ return this.removeById(questionId);
+ }
+
+ @Override
+ public Question getQuestionById(Long questionId) {
+ return this.getById(questionId);
+ }
+
+ @Override
+ public Question getQuestionByIdInner(Long questionId) {
+ return this.getById(questionId);
+ }
+
+ @Override
+ public Page listQuestions(QuestionQueryRequestDTO request) {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+
+ // ID 精确查询
+ if (request.getId() != null) {
+ wrapper.eq(Question::getId, request.getId());
+ }
+
+ // 标题模糊查询
+ if (StringUtils.isNotBlank(request.getTitle())) {
+ wrapper.like(Question::getTitle, request.getTitle());
+ }
+
+ // 难度精确查询
+ if (StringUtils.isNotBlank(request.getDifficulty())) {
+ wrapper.eq(Question::getDifficulty, request.getDifficulty());
+ }
+
+ // 创建者 ID 查询
+ if (request.getUserId() != null) {
+ wrapper.eq(Question::getUserId, request.getUserId());
+ }
+
+ // 排序
+ if (StringUtils.isNotBlank(request.getSortField())) {
+ if ("asc".equalsIgnoreCase(request.getSortOrder())) {
+ wrapper.orderByAsc(Question::getCreateTime);
+ } else {
+ wrapper.orderByDesc(Question::getCreateTime);
+ }
+ } else {
+ wrapper.orderByDesc(Question::getCreateTime);
+ }
+
+ // 直接使用 request 作为分页对象
+ return this.page(request, wrapper);
+ }
+}
diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java
new file mode 100644
index 0000000..a637500
--- /dev/null
+++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java
@@ -0,0 +1,32 @@
+package cn.meowrain.aioj.backend.question.service.impl;
+
+import cn.meowrain.aioj.backend.question.dao.entity.QuestionSubmit;
+import cn.meowrain.aioj.backend.question.dao.mapper.QuestionSubmitMapper;
+import cn.meowrain.aioj.backend.question.service.QuestionSubmitService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 题目提交服务实现
+ */
+@Service
+@RequiredArgsConstructor
+public class QuestionSubmitServiceImpl extends ServiceImpl implements QuestionSubmitService {
+
+ @Override
+ public Long createSubmit(QuestionSubmit questionSubmit) {
+ this.save(questionSubmit);
+ return questionSubmit.getId();
+ }
+
+ @Override
+ public Boolean updateSubmitStatus(QuestionSubmit questionSubmit) {
+ return this.updateById(questionSubmit);
+ }
+
+ @Override
+ public QuestionSubmit getSubmitById(Long submitId) {
+ return this.getById(submitId);
+ }
+}
diff --git a/aioj-backend-question-service/src/main/resources/application-dev.yml b/aioj-backend-question-service/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..f186dc2
--- /dev/null
+++ b/aioj-backend-question-service/src/main/resources/application-dev.yml
@@ -0,0 +1,19 @@
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://10.0.0.10/aioj_dev
+ username: root
+ password: root
+ data:
+ redis:
+ host: 10.0.0.10
+ port: 6379
+ password: 123456
+ cloud:
+ nacos:
+ discovery:
+ enabled: true
+ register-enabled: true
+ server-addr: 10.0.0.10:8848
+ username: nacos
+ password: nacos
diff --git a/aioj-backend-question-service/src/main/resources/application-prod.yml b/aioj-backend-question-service/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..258ae4b
--- /dev/null
+++ b/aioj-backend-question-service/src/main/resources/application-prod.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://10.0.0.10/aioj_prod
+ username: root
+ password: root
+ data:
+ redis:
+ host: 10.0.0.10
+ port: 6379
+ password: 123456
diff --git a/aioj-backend-question-service/src/main/resources/application-test.yml b/aioj-backend-question-service/src/main/resources/application-test.yml
new file mode 100644
index 0000000..422826b
--- /dev/null
+++ b/aioj-backend-question-service/src/main/resources/application-test.yml
@@ -0,0 +1,11 @@
+spring:
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://10.0.0.10/aioj_test
+ username: root
+ password: 123456
+ data:
+ redis:
+ host: 10.0.0.10
+ port: 6379
+ password: 123456
diff --git a/aioj-backend-question-service/src/main/resources/application.yml b/aioj-backend-question-service/src/main/resources/application.yml
new file mode 100644
index 0000000..ee32550
--- /dev/null
+++ b/aioj-backend-question-service/src/main/resources/application.yml
@@ -0,0 +1,49 @@
+spring:
+ application:
+ name: aioj-question-service
+ profiles:
+ active: @env@
+server:
+ port: 18083
+ servlet:
+ context-path: /api
+ error:
+ include-stacktrace: never
+springdoc:
+ api-docs:
+ enabled: true
+ path: /v3/api-docs
+ default-flat-param-object: true
+ swagger-ui:
+ path: /swagger-ui.html
+ tags-sorter: alpha
+ operations-sorter: alpha
+ group-configs:
+ - group: 'default'
+ paths-to-match: '/api/**'
+ packages-to-scan: cn.meowrain.aioj.backend.questionservice.controller
+knife4j:
+ basic:
+ enable: true
+ setting:
+ language: zh_cn
+mybatis-plus:
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ map-underscore-to-camel-case: true
+ mapper-locations: classpath*:/mapper/**/*.xml
+
+# JWT 配置(必须与 auth-service 保持一致)
+jwt:
+ enabled: true
+ secret: "12345678901234567890123456789012" # 至少32字节
+ access-expire: 900000 # 15分钟
+ refresh-expire: 604800000 # 7天
+
+aioj:
+ log:
+ enabled: true
+ max-length: 20000
+logging:
+ file:
+ path: ./logs/${spring.application.name}
diff --git a/aioj-backend-question-service/src/main/resources/logback-spring.xml b/aioj-backend-question-service/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..5111287
--- /dev/null
+++ b/aioj-backend-question-service/src/main/resources/logback-spring.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+ UTF-8
+
+
+
+
+ ${LOG_FILE_PATH}/${time-month}/${time-month-day}/info.log
+
+ ${LOG_FILE_PATH}/${time-month}/${time-month-day}/info.%d{yyyy-MM-dd}.%i.log.gz
+ 100MB
+ 31
+ 100GB
+
+
+ ${FILE_LOG_PATTERN}
+ UTF-8
+
+
+ INFO
+
+
+
+ ${LOG_FILE_PATH}/${time-month}/${time-month-day}/error.log
+
+ ${LOG_FILE_PATH}/${time-month}/${time-month-day}/error.%d{yyyy-MM-dd}.%i.log.gz
+ 100MB
+ 31
+ 100GB
+
+
+ ${FILE_LOG_PATTERN}
+ UTF-8
+
+
+ ERROR
+ ACCEPT
+ DENY
+
+
+
+
+ 0
+ 512
+
+
+
+ 0
+ 512
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+