From becd90b00649284b4e2a962b7712ef3042b20f28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BD=8A?= <23>
Date: Mon, 27 Jul 2026 16:59:53 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
application-tenant/tenant-admin/pom.xml | 5 +
.../apelet/tenantadmin/TenantAdminApplication.java | 3 +-
.../apelet/tenantadmin/config/FilterConfig.java | 1 +
.../tenantadmin/config/MultiDataSourceConfig.java | 3 +-
.../upms/controller/LoginController.java | 1 +
.../src/main/resources/application-config.yml | 16 +-
.../tenant-admin/src/main/resources/bootstrap.yml | 2 +-
.../src/main/resources/tenant-admin-dev.yml | 12 +-
common/common-association/pom.xml | 8 +
.../AssociationActivitiesController.java | 4 +-
.../association/controller/CourseController.java | 171 ++++++++++++++++
.../controller/DoPracticeProblemsController.java | 183 +++++++++++++++++
.../association/dao/CourseCoursewareMapper.java | 8 +
.../java/apelet/association/dao/CourseMapper.java | 7 +
.../apelet/association/dao/CourseVideoMapper.java | 8 +
.../java/apelet/association/dao/ExamMapper.java | 8 +
.../association/dao/ExamQuestionsEntryMapper.java | 8 +
.../association/dao/ExamQuestionsMapper.java | 8 +
.../association/dao/QuestionBankEntryMapper.java | 8 +
.../apelet/association/dao/QuestionBankMapper.java | 8 +
.../association/dao/UserCourseProgressMapper.java | 8 +
.../apelet/association/dao/UserExerciseMapper.java | 8 +
.../apelet/association/dto/QuestionBankDto.java | 10 +
.../apelet/association/dto/UserExerciseDto.java | 24 +++
.../main/java/apelet/association/model/Course.java | 224 +++++++++++++++++++++
.../apelet/association/model/CourseCourseware.java | 131 ++++++++++++
.../java/apelet/association/model/CourseVideo.java | 180 +++++++++++++++++
.../main/java/apelet/association/model/Exam.java | 175 ++++++++++++++++
.../apelet/association/model/ExamQuestions.java | 81 ++++++++
.../association/model/ExamQuestionsEntry.java | 53 +++++
.../apelet/association/model/QuestionBank.java | 77 +++++++
.../association/model/QuestionBankEntry.java | 56 ++++++
.../association/model/UserCourseProgress.java | 109 ++++++++++
.../apelet/association/model/UserExercise.java | 93 +++++++++
.../plugin/active/ActivityInfoUpdatePlugin.java | 2 +-
.../plugin/active/ActivitySchedulePlugin.java | 2 +-
.../plugin/active/ActivitySignConfigPlugin.java | 38 ++--
.../active/CompetitionActivitiesListPlugin.java | 6 +-
.../plugin/active/CompetitionDetailsPlugin.java | 39 ++++
.../plugin/active/SubmissionWorksUpdatePlugin.java | 10 +-
.../BusinessSaveOpPlugin.java | 38 ++--
.../plugin/clueManage/ClueActivateOpPlugin.java | 28 +--
.../plugin/clueManage/ClueAuditOpPlugin.java | 30 +--
.../plugin/clueManage/ClueManageFormPlugin.java | 16 +-
.../plugin/clueManage/ClueSubmitOpPlugin.java | 23 ++-
.../plugin/course/courseFormPlugin.java | 11 +-
.../CourseCoursewareFromPlugin.java | 6 +-
.../plugin/courseVideo/CourseVideoFormPlugin.java | 10 +-
.../ElectronicJournalFormPlugin.java | 22 +-
.../ElectronicJournalListPlugin.java | 13 +-
.../ElectronicJournalOfflineOpPlugin.java | 22 +-
.../ElectronicJournalOnlineOpPlugin.java | 22 +-
.../expertManage/ExpertManageAuditOpPlugin.java | 30 +--
.../expertManage/ExpertManageSubmitOpPlugin.java | 23 +--
.../fileLibraryMange/FileLibrayFormPlugin.java | 89 ++++----
.../fileLibraryMange/FileLibrayListPlugin.java | 9 +-
.../FileLibrayOfflineOpPlugin.java | 23 ++-
.../fileLibraryMange/FileLibrayOnlineOpPlugin.java | 22 +-
.../member/MembershipApplyListFilterPlugin.java | 6 -
.../plugin/member/MembershipPayPopupPlugin.java | 4 +-
.../plugin/member/MembershipPayShowHidePlugin.java | 10 +-
.../plugin/member/UnitNameChangePopupPlugin.java | 41 ++--
.../question/DoPracticeProblemsSavePlugin.java | 66 ++++++
.../plugin/question/QuestionBankListPlugin.java | 74 +++++++
.../plugin/quotation/ConfirmPlugin.java | 20 +-
.../plugin/quotation/ContractPlugin.java | 4 +-
.../plugin/quotation/OpenPopupPlugin.java | 8 +-
.../plugin/quotation/PopupGetIdPlugin.java | 6 +-
.../plugin/quotation/QuotationPlugin.java | 65 +++---
.../plugin/quotation/ReviewPastPlugin.java | 22 +-
.../plugin/quotation/ReviewRefusePlugin.java | 23 +--
.../plugin/quotation/StatusChangePlugin.java | 22 +-
.../service/CourseCoursewareService.java | 25 +++
.../apelet/association/service/CourseService.java | 11 +
.../association/service/CourseVideoService.java | 29 +++
.../service/ExamQuestionsEntryService.java | 9 +
.../association/service/ExamQuestionsService.java | 9 +
.../apelet/association/service/ExamService.java | 10 +
.../service/QuestionBankEntryService.java | 9 +
.../association/service/QuestionBankService.java | 9 +
.../service/UserCourseProgressService.java | 9 +
.../association/service/UserExerciseService.java | 9 +
.../service/impl/CourseCoursewareServiceImpl.java | 57 ++++++
.../service/impl/CourseServiceImpl.java | 21 ++
.../service/impl/CourseVideoServiceImpl.java | 70 +++++++
.../impl/ExamQuestionsEntryServiceImpl.java | 13 ++
.../service/impl/ExamQuestionsServiceImpl.java | 13 ++
.../association/service/impl/ExamServiceImpl.java | 20 ++
.../service/impl/QuestionBankEntryServiceImpl.java | 13 ++
.../service/impl/QuestionBankServiceImpl.java | 13 ++
.../impl/UserCourseProgressServiceImpl.java | 13 ++
.../service/impl/UserExerciseServiceImpl.java | 13 ++
.../association/task/UserRenewalReminderTask.java | 9 +-
.../association/utils/DataTransformationUtil.java | 24 +--
.../java/apelet/association/utils/MyFileUtil.java | 64 +++---
.../java/apelet/association/utils/QRCodeUtil.java | 16 +-
.../java/apelet/association/utils/VideoCvUtil.java | 126 ++++++++++++
.../main/java/apelet/association/vo/VideoMeta.java | 19 ++
98 files changed, 2805 insertions(+), 434 deletions(-)
create mode 100644 common/common-association/src/main/java/apelet/association/controller/CourseController.java
create mode 100644 common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/CourseCoursewareMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/CourseMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/CourseVideoMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/ExamMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/ExamQuestionsEntryMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/ExamQuestionsMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/QuestionBankEntryMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/QuestionBankMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/UserCourseProgressMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dao/UserExerciseMapper.java
create mode 100644 common/common-association/src/main/java/apelet/association/dto/QuestionBankDto.java
create mode 100644 common/common-association/src/main/java/apelet/association/dto/UserExerciseDto.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/Course.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/CourseCourseware.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/CourseVideo.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/Exam.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/ExamQuestions.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/ExamQuestionsEntry.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/QuestionBank.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/QuestionBankEntry.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/UserCourseProgress.java
create mode 100644 common/common-association/src/main/java/apelet/association/model/UserExercise.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/active/CompetitionDetailsPlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/question/DoPracticeProblemsSavePlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/plugin/question/QuestionBankListPlugin.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/CourseCoursewareService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/CourseService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/CourseVideoService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/ExamQuestionsEntryService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/ExamQuestionsService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/ExamService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/QuestionBankEntryService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/QuestionBankService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/UserCourseProgressService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/UserExerciseService.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/CourseCoursewareServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/CourseServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/CourseVideoServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/ExamQuestionsEntryServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/ExamQuestionsServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/ExamServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/QuestionBankEntryServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/QuestionBankServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/UserCourseProgressServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/service/impl/UserExerciseServiceImpl.java
create mode 100644 common/common-association/src/main/java/apelet/association/utils/VideoCvUtil.java
create mode 100644 common/common-association/src/main/java/apelet/association/vo/VideoMeta.java
diff --git a/application-tenant/tenant-admin/pom.xml b/application-tenant/tenant-admin/pom.xml
index e33206c..eb54156 100644
--- a/application-tenant/tenant-admin/pom.xml
+++ b/application-tenant/tenant-admin/pom.xml
@@ -149,6 +149,11 @@
apelet
+ common-msg-notice
+ 1.0.0
+
+
+ apelet
common-association
1.0.0
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/TenantAdminApplication.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/TenantAdminApplication.java
index 3a0d02d..00ac785 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/TenantAdminApplication.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/TenantAdminApplication.java
@@ -15,9 +15,10 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* @date 2023-08-04
*/
@ComponentScan("apelet")
+@EnableDiscoveryClient
@EnableScheduling
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
-@MapperScan("apelet.common.**.dao")
+@MapperScan({"apelet.common.**.dao", "apelet.msgnotice.mapper"})
public class TenantAdminApplication {
public static void main(String[] args) {
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/FilterConfig.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/FilterConfig.java
index 43dd5ba..f5a18c3 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/FilterConfig.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/FilterConfig.java
@@ -42,6 +42,7 @@ public class FilterConfig {
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addExposedHeader(applicationConfig.getRefreshedTokenHeaderKey());
corsConfiguration.setAllowCredentials(true);
+ corsConfiguration.setMaxAge(3600L);
configSource.registerCorsConfiguration("/**", corsConfiguration);
}
return new CorsFilter(configSource);
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/MultiDataSourceConfig.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/MultiDataSourceConfig.java
index 2a39305..957958b 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/MultiDataSourceConfig.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/config/MultiDataSourceConfig.java
@@ -21,8 +21,7 @@ import java.util.Map;
* @date 2023-08-04
*/
@Configuration
-@EnableTransactionManagement
-@MapperScan(value = {"apelet.tenantadmin.upms.dao","apelet.tenantadmin.tenant.dao", "apelet.common.*.dao"})
+@MapperScan(value = {"apelet.tenantadmin.upms.dao","apelet.tenantadmin.tenant.dao", "apelet.common.*.dao", "apelet.association.dao"})
public class MultiDataSourceConfig extends BaseMultiDataSourceConfig {
@Bean(initMethod = "init", destroyMethod = "close")
diff --git a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
index e106625..9516e0e 100644
--- a/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
+++ b/application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/controller/LoginController.java
@@ -1080,6 +1080,7 @@ public class LoginController {
}
List menuList = allMenuList.stream()
.filter(m -> m.getMenuType() <= SysMenuType.TYPE_MENU).collect(Collectors.toList());
+ jsonData.put("user", user);
jsonData.put("menuList", menuList);
jsonData.put("permCodeList", permCodeList);
Set permSet = null;
diff --git a/application-tenant/tenant-admin/src/main/resources/application-config.yml b/application-tenant/tenant-admin/src/main/resources/application-config.yml
index 23b47e3..f753b89 100644
--- a/application-tenant/tenant-admin/src/main/resources/application-config.yml
+++ b/application-tenant/tenant-admin/src/main/resources/application-config.yml
@@ -86,13 +86,13 @@ knife4j:
aliyun:
oss:
- enabled: false
+ enabled: true
expireSeconds: 1000
- # 下面几项均需在申请阿里云OSS后,根据自己的实际情况进行配置。
- endpoint:
- accessKey:
- secretKey:
- bucketName:
+ endpoint: https://oss-cn-beijing.aliyuncs.com
+ accessKey: LTAI5t5fEgzRRtdmBvczVS6r
+ secretKey: uESFiyyi6EwCkM5w4a4pbx6TmVhqgx
+ bucketName: yy-test12
+
minio:
enabled: false
@@ -145,7 +145,7 @@ common-redis:
# master-slave:
# 每个节点逗号分隔,第一个为主节点,其余为从节点。同时每个节点前必须以redis://开头。
# address: redis://localhost:6379,redis://localhost:6378,...
- address: redis://localhost:6379
+ address: redis://192.168.100.25:6379
# 链接超时,单位毫秒。
timeout: 6000
# 单位毫秒。分布式锁的超时检测时长。
@@ -153,7 +153,7 @@ common-redis:
lockWatchdogTimeout: 60000
# redis 密码,空可以不填。
password:
- database: 0
+ database: 1
pool:
# 连接池数量。
poolSize: 20
diff --git a/application-tenant/tenant-admin/src/main/resources/bootstrap.yml b/application-tenant/tenant-admin/src/main/resources/bootstrap.yml
index 7b52d96..b74406d 100644
--- a/application-tenant/tenant-admin/src/main/resources/bootstrap.yml
+++ b/application-tenant/tenant-admin/src/main/resources/bootstrap.yml
@@ -2,7 +2,7 @@ spring:
application:
name: tenant-admin
profiles:
- active: @profile.name@
+ active: dev
main:
allow-bean-definition-overriding: true
allow-circular-references: true
diff --git a/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml b/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml
index 304caf6..d622b1e 100644
--- a/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml
+++ b/application-tenant/tenant-admin/src/main/resources/tenant-admin-dev.yml
@@ -5,7 +5,7 @@ logging:
config: classpath:logback-spring.xml
server:
- port: 8077
+ port: 8099
application:
# Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。
@@ -133,7 +133,7 @@ sequence:
# 是否使用基于美团Leaf的分布式Id生成器。
advanceIdGenerator: true
# 多个zk服务之间逗号分隔。
- zkAddress: localhost:2181
+ zkAddress: 192.168.100.25:2181
# 与本机的ip一起构成zk中标识不同服务实例的key值。
idPort: 18083
# zk中生成WorkNode的路径。不同的业务可以使用不同的路径,以免冲突。
@@ -146,7 +146,7 @@ common-log:
kafkaTopic: SysOperationLog-TenantAdmin
mybatis-plus:
- mapper-locations: classpath:apelet/tenantadmin/tenant/dao/mapper/*Mapper.xml,apelet/tenantadmin/upms/dao/mapper/*Mapper.xml,apelet/common/report/dao/mapper/*Mapper.xml,apelet/common/datasync/dao/mapper/*Mapper.xml,apelet/common/log/dao/mapper/*Mapper.xml,apelet/common/flow/dao/mapper/*Mapper.xml,apelet/common/online/dao/mapper/*Mapper.xml,apelet/common/generator/dao/mapper/*Mapper.xml,apelet/common/botp/dao/mapper/*Mapper.xml,apelet/tenantadmin/app/dao/mapper/*Mapper.xml,apelet/common/mobile/dao/mapper/*Mapper.xml,apelet/common/eas/dao/mapper/*Mapper.xml
+ mapper-locations: classpath:apelet/tenantadmin/tenant/dao/mapper/*Mapper.xml,apelet/common/demo/report/dao/mapper/*Mapper.xml,apelet/tenantadmin/upms/dao/mapper/*Mapper.xml,apelet/common/report/dao/mapper/*Mapper.xml,apelet/common/datasync/dao/mapper/*Mapper.xml,apelet/common/log/dao/mapper/*Mapper.xml,apelet/common/flow/dao/mapper/*Mapper.xml,apelet/common/online/dao/mapper/*Mapper.xml,apelet/common/generator/dao/mapper/*Mapper.xml,apelet/common/botp/dao/mapper/*Mapper.xml,apelet/tenantadmin/app/dao/mapper/*Mapper.xml,apelet/common/mobile/dao/mapper/*Mapper.xml,apelet/common/eas/dao/mapper/*Mapper.xml,classpath:mapper/*Mapper.xml
type-aliases-package: apelet.tenantadmin.*.model,apelet.common.report.model,apelet.common.datasync.model,apelet.common.log.model,apelet.common.flow.model,apelet.common.online.model,apelet.common.mobile.model,apelet.common.eas.model
global-config:
db-config:
@@ -203,17 +203,17 @@ spring:
druid:
# 租户管理数据源。
tenant-admin:
- url: jdbc:mysql://frp-use.com:51850/apelet_xhgl?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
+ url: jdbc:mysql://192.168.100.35:3306/apelet_xhgl?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root
password: X7&9p8L2@6z4K7!8
# 租户业务平台的通用业务数据,如字典、在线表单、流程、报表的定义等数据。
tenant-common:
- url: jdbc:mysql://frp-use.com:51850/apelet_xhgl?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
+ url: jdbc:mysql://192.168.100.35:3306/apelet_xhgl?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: X7&9p8L2@6z4K7!8
# 默认生成的操作日志数据源配置。
operation-log:
- url: jdbc:mysql://frp-use.com:51850/apelet_xhgl?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
+ url: jdbc:mysql://192.168.100.35:3306/apelet_xhgl?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root
password: X7&9p8L2@6z4K7!8
driverClassName: com.mysql.cj.jdbc.Driver
diff --git a/common/common-association/pom.xml b/common/common-association/pom.xml
index 2226fb4..8740d9b 100644
--- a/common/common-association/pom.xml
+++ b/common/common-association/pom.xml
@@ -23,6 +23,7 @@
javacv-platform
1.5.13
+
apelet
common-msg-notice
@@ -35,6 +36,11 @@
apelet
+ common-aliyun-oss
+ 1.0.0
+
+
+ apelet
common-generator
1.0.0
@@ -63,6 +69,8 @@
javase
3.5.1
+
+
diff --git a/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java b/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java
index 4f635ad..91060c2 100644
--- a/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java
+++ b/common/common-association/src/main/java/apelet/association/controller/AssociationActivitiesController.java
@@ -14,7 +14,9 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
-import java.util.*;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
@RestController
diff --git a/common/common-association/src/main/java/apelet/association/controller/CourseController.java b/common/common-association/src/main/java/apelet/association/controller/CourseController.java
new file mode 100644
index 0000000..61eb0b9
--- /dev/null
+++ b/common/common-association/src/main/java/apelet/association/controller/CourseController.java
@@ -0,0 +1,171 @@
+package apelet.association.controller;
+
+import apelet.association.model.CourseCourseware;
+import apelet.association.model.CourseVideo;
+import apelet.association.service.CourseCoursewareService;
+import apelet.association.service.CourseService;
+import apelet.association.service.CourseVideoService;
+import apelet.common.aliyun.oss.config.AliyunOssProperties;
+import apelet.common.aliyun.oss.wrapper.AliyunOssTemplate;
+
+import apelet.common.core.exception.MyRuntimeException;
+import apelet.common.core.object.*;
+import apelet.common.generator.utils.OrmGenDataSourceUtil;
+import apelet.common.orm.impl.Filter;
+import apelet.common.orm.impl.FilterItem;
+import apelet.common.orm.impl.Selector;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.model.GetObjectRequest;
+import com.aliyun.oss.model.OSSObject;
+import com.aliyun.oss.model.ObjectMetadata;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+
+
+/**
+ * 课程管理
+ */
+@RestController
+@RequestMapping("/tenantadmin/Course")
+public class CourseController {
+
+
+ @Autowired
+ private CourseCoursewareService courseCoursewareService;
+ @Autowired
+ private CourseVideoService courseVideoService;
+ @Autowired
+ private AliyunOssTemplate aliyunOssTemplate;
+ @Autowired
+ private OSS ossClient;
+
+
+ private static final String VIDEO_MIME = "video/mp4";
+
+ /**
+ * 视频断点续播 —— 根据学习进度自动从对应字节偏移量开始流式输出
+ */
+ @GetMapping("/queryVideoProgress")
+ public void queryVideoProgress(
+ @RequestParam("videoId") Long videoId,
+ @RequestParam("userId") Long userId,
+ HttpServletRequest request,
+ HttpServletResponse response) throws IOException {
+
+ CourseVideo courseVideo = courseVideoService.getById(videoId);
+ if (courseVideo == null || courseVideo.getVideoUrl() == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "视频不存在");
+ return;
+ }
+
+ String videoUrl = courseVideo.getVideoUrl();
+ JSONArray jsonArray = JSON.parseArray(videoUrl);
+ JSONObject urlObject = jsonArray.getJSONObject(0);
+ String filePath = urlObject.getString("uploadPath") + "/" + urlObject.getString("filename");
+ AliyunOssProperties properties = aliyunOssTemplate.getProperties();
+ String bucketName = properties.getBucketName();
+ ObjectMetadata meta = ossClient.getObjectMetadata(bucketName, filePath);
+ long totalSize = meta.getContentLength();
+ long start = courseVideoService.getByteOffsetByTime(videoId, userId);
+ long end = totalSize - 1;
+ String rangeHeader = request.getHeader(HttpHeaders.RANGE);
+ if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
+ String rangeVal = rangeHeader.substring(6);
+ String[] arr = rangeVal.split("-");
+ if (!CharSequenceUtil.isBlank(arr[0])) {
+ start = Long.parseLong(arr[0]);
+ }
+ if (arr.length > 1 && !CharSequenceUtil.isBlank(arr[1])) {
+ end = Long.parseLong(arr[1]);
+ }
+ }
+ start = Math.max(start, 0);
+ end = Math.min(end, totalSize - 1);
+ if (start >= totalSize) {
+ response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes */" + totalSize);
+ response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+ return;
+ }
+ long sliceLength = end - start + 1;
+ response.setContentType(VIDEO_MIME);
+ response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
+ response.setHeader(HttpHeaders.CONTENT_RANGE,
+ String.format("bytes %d-%d/%d", start, end, totalSize));
+ response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(sliceLength));
+ response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+ GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, filePath);
+ getObjectRequest.setRange(start, end);
+ try (OSSObject ossObject = ossClient.getObject(getObjectRequest);
+ InputStream is = ossObject.getObjectContent()) {
+ byte[] buffer = new byte[8192];
+ int read;
+ while ((read = is.read(buffer)) != -1) {
+ response.getOutputStream().write(buffer, 0, read);
+ }
+ response.getOutputStream().flush();
+ }
+ }
+
+
+ /**
+ * 保存课程视频学习记录
+ *
+ * @return
+ */
+ @PostMapping("/videoLearning")
+ public ResponseResult> videoLearning(@RequestBody CourseVideo courseVideo) {
+ courseVideoService.saveVideoLearning(courseVideo);
+ return ResponseResult.success();
+ }
+
+
+ /**
+ * 查询课件学习进度
+ *
+ * @param coursewareId
+ * @param userId
+ * @return
+ */
+ @GetMapping("/queryCoursewareProgress")
+ public ResponseResult> queryCoursewareProgress(
+ @RequestParam("coursewareId") Long coursewareId, @RequestParam("userId") Long userId) {
+ Object result = courseCoursewareService.getCourseLearningProgress(coursewareId, userId);
+ return ResponseResult.success(result);
+ }
+
+
+ /**
+ * 课程课件学习记录
+ *
+ * @return
+ */
+ @PostMapping("/coursewareLearning")
+ public ResponseResult> coursewareLearning(@RequestBody CourseCourseware courseCourseware) {
+ courseCoursewareService.saveCoursewareLearning(courseCourseware);
+ return ResponseResult.success();
+ }
+
+
+}
diff --git a/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java b/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java
new file mode 100644
index 0000000..4b73ddd
--- /dev/null
+++ b/common/common-association/src/main/java/apelet/association/controller/DoPracticeProblemsController.java
@@ -0,0 +1,183 @@
+package apelet.association.controller;
+
+import apelet.association.dto.UserExerciseDto;
+import apelet.association.model.*;
+import apelet.association.service.*;
+import apelet.common.core.exception.MyRuntimeException;
+import apelet.common.core.object.*;
+import apelet.common.generator.utils.OrmGenDataSourceUtil;
+import apelet.common.orm.impl.Filter;
+import apelet.common.orm.impl.FilterItem;
+import apelet.common.orm.impl.Selector;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.IdUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/tenantadmin/questionBank")
+public class DoPracticeProblemsController {
+
+ @Autowired
+ private OrmGenDataSourceUtil ormGenDataSourceUtil;
+
+ @Autowired
+ private ExamService examService;
+
+ @Autowired
+ private QuestionBankService questionBankService;
+ @Autowired
+ private QuestionBankEntryService questionBankEntryService;
+
+ @Autowired
+ private ExamQuestionsService examQuestionsService;
+ @Autowired
+ private ExamQuestionsEntryService examQuestionsEntryService;
+
+ @Autowired
+ private RedissonClient redissonClient;
+
+ @PostConstruct
+ public void checkRedisConfig() throws IOException {
+ System.out.println("Redisson config: {}" + redissonClient.getConfig().toYAML());
+ System.out.println("Redisson config: {}" + redissonClient.getConfig().toYAML());
+ System.out.println("Redisson config: {}" + redissonClient.getConfig().toYAML());
+ }
+
+ /**
+ * 刷题
+ *
+ * @param id 题库id
+ * @return
+ */
+ @GetMapping("/doPracticeProblems")
+ public ResponseResult> doPracticeProblems(@RequestParam(name = "id") String id) {
+ Map result = new HashMap<>();
+ ObjectValue questionBank = ormGenDataSourceUtil.queryOne("question_bank", id);
+ ObjectCollection collection = questionBank.getObjectCollection("question_bank_entry");
+ if (collection == null || collection.isEmpty()) {
+ throw new MyRuntimeException("题库下没有试题, 请先添加试题!!!");
+ }
+ result.put("questionBankId", id);
+ result.put("questionBankName", questionBank.getString("name"));
+ List list = new ArrayList<>();
+
+ //保存用户刷题记录
+ long batchNumber = IdUtil.getSnowflakeNextId();
+ result.put("batchNumber", batchNumber);
+
+ collection.forEach(f -> {
+ ObjectValue examQuestions = f.getObjectValue("exam_questions_id");
+ list.add(examQuestions.getString("id"));
+
+ ObjectValue userExercise = new ObjectValue("user_exercise");
+ ObjectValue xySysUser = new ObjectValue("xy_sys_user");
+ xySysUser.put("id", TokenData.takeFromRequest().getUserId());
+ userExercise.put("question_bank_id", questionBank);
+ userExercise.put("exam_questions_id", examQuestions);
+ userExercise.put("membership_apply_id", xySysUser);
+ userExercise.put("batch", batchNumber);
+ userExercise.put("is_correct", 0);
+ userExercise.put("create_time", DateUtil.now());
+ try {
+ ormGenDataSourceUtil.addNew(userExercise.getTableName(), userExercise);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ List