Compare commits
358 Commits
Author | SHA1 | Date |
---|---|---|
|
84a8c702a9 | 4 days ago |
|
af0a57f04a | 4 days ago |
|
1b60049f8b | 5 days ago |
|
2d68a45db6 | 5 days ago |
|
6a440fe111 | 5 days ago |
|
032b740238 | 6 days ago |
|
1f1c4f1340 | 6 days ago |
|
614c67653b | 6 days ago |
|
874d277271 | 2 weeks ago |
|
cac52d6d4f | 2 weeks ago |
|
ad4bebd1b9 | 3 weeks ago |
|
4d4ca44dce | 3 weeks ago |
|
28c746c662 | 3 weeks ago |
|
afab1c74c3 | 3 weeks ago |
|
85ca360ca2 | 3 weeks ago |
|
fe68059867 | 3 weeks ago |
|
97806f846d | 3 weeks ago |
|
75659eedce | 3 weeks ago |
|
9b4a5a668a | 3 weeks ago |
|
ccce75df4f | 4 weeks ago |
|
0a61041432 | 4 weeks ago |
|
6f2c55ce26 | 4 weeks ago |
|
1bae224374 | 1 month ago |
|
dbd9aed46f | 1 month ago |
|
b67bc9faf0 | 1 month ago |
|
418392c189 | 1 month ago |
|
41d2b200bd | 1 month ago |
|
46bd3f90bb | 2 months ago |
|
3568abad10 | 2 months ago |
|
c6c301c532 | 2 months ago |
|
aef11a583c | 2 months ago |
|
a3bbce2897 | 2 months ago |
|
d37286b83e | 2 months ago |
|
cb74969301 | 2 months ago |
|
a1ad6463b6 | 2 months ago |
|
9fe2a914d1 | 2 months ago |
|
de8d00c913 | 2 months ago |
|
7530edc04a | 2 months ago |
|
c74df513b4 | 2 months ago |
|
e47903b31d | 2 months ago |
|
b7cee64e37 | 2 months ago |
|
687e28f3df | 2 months ago |
|
dfadaf37bc | 2 months ago |
|
731c8d827e | 2 months ago |
|
74e51efc65 | 2 months ago |
|
48c0351628 | 2 months ago |
|
c1ce2d0be6 | 2 months ago |
|
8edae6b9a2 | 2 months ago |
|
2e5d3f5e24 | 2 months ago |
|
94d490c1df | 2 months ago |
|
42ce72f520 | 2 months ago |
|
096710b3a6 | 2 months ago |
|
289b34c477 | 2 months ago |
|
0523d7c774 | 2 months ago |
|
fb2e273060 | 2 months ago |
|
ff696685ef | 2 months ago |
|
b610b0cac9 | 2 months ago |
|
9e388fd1f7 | 2 months ago |
|
c8787b2d33 | 2 months ago |
|
2b56f1b454 | 2 months ago |
|
8ec3179cbb | 2 months ago |
|
523de5aed6 | 2 months ago |
|
d53c4817d2 | 2 months ago |
|
247a60b066 | 2 months ago |
|
42015cbade | 2 months ago |
|
68182c0c21 | 2 months ago |
|
6e938227cb | 2 months ago |
|
6569df58a7 | 2 months ago |
|
10608541fd | 2 months ago |
|
195e62ef50 | 2 months ago |
|
158ef4b621 | 2 months ago |
|
f3e16be199 | 2 months ago |
|
c9eba804ab | 2 months ago |
|
58ff2e7eb1 | 2 months ago |
|
da7a35a3d7 | 2 months ago |
|
1944abb0bc | 2 months ago |
|
42d5d59699 | 2 months ago |
|
40d2f399eb | 2 months ago |
|
d8b9df497d | 2 months ago |
|
042979a5ae | 2 months ago |
|
31df666440 | 2 months ago |
|
e886151639 | 3 months ago |
|
6fd0925977 | 3 months ago |
|
b160e7fca4 | 3 months ago |
|
07165e5e61 | 3 months ago |
|
eb9fc54440 | 3 months ago |
|
4f23439230 | 3 months ago |
|
4a8bf051e9 | 3 months ago |
|
ab6b726b9c | 3 months ago |
|
0dd6d01a98 | 3 months ago |
|
4aaa07f8e4 | 3 months ago |
|
cf3f5d300b | 3 months ago |
|
eb617c938f | 4 months ago |
|
c030a0d58a | 4 months ago |
|
81a79cdc6a | 4 months ago |
|
d03ab5dc90 | 4 months ago |
|
66aa7ede34 | 4 months ago |
|
c6b2b1c6b2 | 4 months ago |
|
3ce2cb9b75 | 4 months ago |
|
8a5ec1021b | 4 months ago |
|
7dff0ddea9 | 4 months ago |
|
93f4929922 | 4 months ago |
|
fc53b9a31b | 4 months ago |
|
0d2b6c038c | 4 months ago |
|
0928fd045a | 4 months ago |
|
c8089b9a99 | 4 months ago |
|
4eb23c5208 | 4 months ago |
|
4d50be7421 | 4 months ago |
|
00377bf32b | 4 months ago |
|
02fa60e427 | 5 months ago |
|
d0379cd7b8 | 5 months ago |
|
74148a068a | 5 months ago |
|
af6536c0fe | 5 months ago |
|
a04ba227ec | 5 months ago |
|
e57affb790 | 5 months ago |
|
128a05e90a | 5 months ago |
|
13d095d02b | 5 months ago |
|
cd421db42b | 5 months ago |
|
18b0acd648 | 5 months ago |
|
e447351729 | 5 months ago |
|
49cfb37404 | 5 months ago |
|
c1bbd8a7ac | 5 months ago |
|
e746605ee0 | 5 months ago |
|
ab78ec557f | 6 months ago |
|
de621c8541 | 6 months ago |
|
4153162ff1 | 6 months ago |
|
a9c6c6a499 | 6 months ago |
|
be289caf37 | 6 months ago |
|
1dd21b136e | 6 months ago |
|
6e1bfdc6c9 | 6 months ago |
|
5933e2daee | 6 months ago |
|
1dcd782331 | 6 months ago |
|
3449d2bcbd | 6 months ago |
|
7ec8d20ae8 | 6 months ago |
|
12ad733286 | 6 months ago |
|
f07b7e9257 | 6 months ago |
|
d038fd631e | 6 months ago |
|
e64b8d8e8c | 6 months ago |
|
99337c5835 | 6 months ago |
|
7358250cd3 | 6 months ago |
|
8057c0f18f | 7 months ago |
|
bb417b8613 | 7 months ago |
|
20a0bbfe8e | 7 months ago |
|
9e76f8ca43 | 7 months ago |
|
ab67d282f1 | 7 months ago |
|
0d4864f7f7 | 7 months ago |
|
692015b0c7 | 7 months ago |
|
a5d404a025 | 7 months ago |
|
8100e15948 | 7 months ago |
|
65d4740084 | 7 months ago |
|
146adb9ae6 | 7 months ago |
|
baea216357 | 7 months ago |
|
ffb8af9546 | 7 months ago |
|
817fe06787 | 7 months ago |
|
dda1342731 | 7 months ago |
|
d1018c375c | 7 months ago |
|
469f19384b | 7 months ago |
|
50f94cb38a | 7 months ago |
|
8c2a543bbb | 7 months ago |
|
b68b576b8c | 7 months ago |
|
5eb9dcaadc | 7 months ago |
|
82f67e1afe | 7 months ago |
|
3fcc218292 | 8 months ago |
|
6b07db26bd | 8 months ago |
|
fcfda1760a | 8 months ago |
|
2f8bb75d6f | 8 months ago |
|
87f75f34e5 | 8 months ago |
|
e7607e4b52 | 8 months ago |
|
8b3ec87fb4 | 8 months ago |
|
63de395694 | 8 months ago |
|
0e5267f2ca | 8 months ago |
|
47bd34e760 | 8 months ago |
|
bdd19d81b7 | 8 months ago |
|
bde76c5140 | 8 months ago |
|
26e7574eec | 8 months ago |
|
7ddcf2aed5 | 8 months ago |
|
8879b87bd2 | 8 months ago |
|
f52559da2b | 8 months ago |
|
763ce06af1 | 8 months ago |
|
4f3b4e6d6b | 8 months ago |
|
ec65450007 | 8 months ago |
|
4f2ea3d672 | 8 months ago |
|
5c47b00105 | 8 months ago |
|
267facc601 | 9 months ago |
|
436e4d807a | 9 months ago |
|
54bf566482 | 9 months ago |
|
aeb6b5d17e | 9 months ago |
|
abb7d9a136 | 9 months ago |
|
472ad1589b | 9 months ago |
|
c6e51008f1 | 9 months ago |
|
f8b29d0b2f | 9 months ago |
|
9b99c7db28 | 9 months ago |
|
5efd36bce8 | 9 months ago |
|
ab5ad3088b | 9 months ago |
|
741330e678 | 9 months ago |
|
8eba7eb8dc | 9 months ago |
|
110177681b | 9 months ago |
|
1fdc914ed6 | 9 months ago |
|
e5b87627cf | 9 months ago |
|
cf1d4cbf30 | 9 months ago |
|
ccda6b3c12 | 9 months ago |
|
b332503a9e | 9 months ago |
|
2b1c8e7264 | 9 months ago |
|
70c3aaefbe | 9 months ago |
|
dc2a311ead | 9 months ago |
|
5658dabd32 | 9 months ago |
|
2e6d04aeff | 9 months ago |
|
b9337b4f39 | 9 months ago |
|
0e38d74d08 | 9 months ago |
|
1b67461abb | 9 months ago |
|
fd9909a5c4 | 9 months ago |
|
af0a9eb205 | 9 months ago |
|
d2fe43d289 | 9 months ago |
|
8198da6fa5 | 9 months ago |
|
bfb5eb7beb | 9 months ago |
|
a1da5adc6f | 9 months ago |
|
d173babbd7 | 9 months ago |
|
fa2bad9f86 | 9 months ago |
|
a70efb3c7b | 9 months ago |
|
e5196290b2 | 9 months ago |
|
39f6e1eb8f | 9 months ago |
|
33aaf13e9d | 9 months ago |
|
0fc74a1819 | 9 months ago |
|
37abc6a90c | 9 months ago |
|
35a3d285c1 | 9 months ago |
|
72380dc68a | 9 months ago |
|
e8dfcf7f9f | 9 months ago |
|
523dfa47b6 | 9 months ago |
|
5200ec6f8c | 9 months ago |
|
678e7d302b | 9 months ago |
|
d333e6809f | 9 months ago |
|
812456a8e1 | 9 months ago |
|
81a83a7566 | 9 months ago |
|
6587bcca67 | 9 months ago |
|
d880be517b | 9 months ago |
|
f46d24223f | 9 months ago |
|
8e9d78dcc4 | 9 months ago |
|
c20bbd2cf4 | 9 months ago |
|
3451287df9 | 9 months ago |
|
a1aa8c7187 | 9 months ago |
|
db6c7d402f | 9 months ago |
|
a801724b75 | 9 months ago |
|
c9e7268d87 | 1 year ago |
|
b7126f7bd8 | 1 year ago |
|
5d33226f94 | 1 year ago |
|
5caf6de0ec | 1 year ago |
|
2698f759a4 | 1 year ago |
|
f966dacb9c | 1 year ago |
|
a53efd1f7a | 1 year ago |
|
acf448e980 | 1 year ago |
|
9aec66d1a7 | 1 year ago |
|
b53fe0f7d6 | 1 year ago |
|
ea5c6fcb81 | 1 year ago |
|
52773b45ff | 1 year ago |
|
bbef6070fd | 1 year ago |
|
a00e0eaf2e | 1 year ago |
|
1a006ee304 | 1 year ago |
|
7aa14b1b82 | 1 year ago |
|
c2c1f9cd0b | 1 year ago |
|
32f2414cd8 | 1 year ago |
|
fa1c6a9b20 | 1 year ago |
|
b9950c6022 | 1 year ago |
|
da1bb7fc87 | 1 year ago |
|
09140678bc | 1 year ago |
|
9ff280a94e | 1 year ago |
|
29f1fed4f1 | 1 year ago |
|
94ac4286c3 | 1 year ago |
|
9f0cd7d01a | 1 year ago |
|
a539afb9e8 | 1 year ago |
|
21790d5666 | 1 year ago |
|
53f9492eb0 | 1 year ago |
|
079f2fbf6f | 1 year ago |
|
bc13f67a29 | 1 year ago |
|
d5ad605b35 | 1 year ago |
|
118fc413d3 | 1 year ago |
|
0ac22b5353 | 1 year ago |
|
8b25e112e8 | 1 year ago |
|
f3e3f48422 | 1 year ago |
|
e74fee8812 | 1 year ago |
|
8bc0da460b | 1 year ago |
|
70ffad27a3 | 1 year ago |
|
2fb38aa62c | 1 year ago |
|
48588b12fc | 1 year ago |
|
256b233b4c | 1 year ago |
|
8c15427ff7 | 1 year ago |
|
d155efe947 | 1 year ago |
|
1a18105096 | 1 year ago |
|
327e399d5a | 1 year ago |
|
9f77aa9ede | 1 year ago |
|
38699011e6 | 1 year ago |
|
eec45f6921 | 1 year ago |
|
65c8fd598f | 1 year ago |
|
5c01fca6c1 | 1 year ago |
|
0ded5af82d | 1 year ago |
|
ab2aaa1757 | 1 year ago |
|
f2e0c0b19e | 1 year ago |
|
fb49fea68e | 1 year ago |
|
d1bb7d56a9 | 1 year ago |
|
56700192d9 | 1 year ago |
|
c9309087c3 | 1 year ago |
|
8301c973c0 | 1 year ago |
|
178e3cfc03 | 1 year ago |
|
83bdf4d6c1 | 1 year ago |
|
2f972c65e3 | 1 year ago |
|
ae729c05e8 | 1 year ago |
|
40d4826695 | 1 year ago |
|
ef1979cbd7 | 1 year ago |
|
cec0a7e58d | 1 year ago |
|
6cf0ebaef3 | 1 year ago |
|
316f9daa4a | 1 year ago |
|
d185a3ffe7 | 1 year ago |
|
646caaa926 | 1 year ago |
|
76499c3904 | 1 year ago |
|
fede04c70d | 1 year ago |
|
fa03927579 | 1 year ago |
|
6ea7454973 | 1 year ago |
|
ccbd59f18f | 1 year ago |
|
fee64cb1ac | 1 year ago |
|
0bae71207b | 1 year ago |
|
aa35b01844 | 1 year ago |
|
8ddf66c97d | 1 year ago |
|
890d23ae6a | 1 year ago |
|
b610194f30 | 1 year ago |
|
7918786641 | 1 year ago |
|
79db32c215 | 1 year ago |
|
3477592027 | 1 year ago |
|
83c980dcae | 1 year ago |
|
a138e16b40 | 1 year ago |
|
6d631563c6 | 1 year ago |
|
8f7b1f9cc1 | 1 year ago |
|
c54edf3cfe | 1 year ago |
|
a3922d8c2d | 1 year ago |
|
6c47e0c59e | 1 year ago |
|
18d42a36e6 | 1 year ago |
|
a09d61b020 | 1 year ago |
|
c34e87ca0d | 1 year ago |
|
18cfb50a46 | 1 year ago |
|
a2d75a1c3d | 1 year ago |
|
29d21f0233 | 1 year ago |
|
6dffd636ec | 1 year ago |
|
8301cfd96d | 1 year ago |
|
aa582361f8 | 1 year ago |
|
38f5bf39ef | 1 year ago |
|
edc79455cc | 1 year ago |
|
610c6d4e81 | 1 year ago |
|
5e06e8ed1e | 1 year ago |
|
d9a19736f2 | 1 year ago |
|
2b271547e7 | 1 year ago |
|
148c31b323 | 1 year ago |
|
68f5303a4c | 1 year ago |
|
1be6ca7e02 | 1 year ago |
|
46b88742d7 | 1 year ago |
|
676f6fc46b | 1 year ago |
|
a16e8f8de8 | 2 years ago |
|
f0a9ba9243 | 2 years ago |
|
46fa7bf45e | 2 years ago |
|
c1e2a62527 | 2 years ago |
|
38bb428c59 | 2 years ago |
@ -0,0 +1,31 @@
|
|||||||
|
# TeamModel extension
|
||||||
|
> SpringBoot base version of TeamModel extension
|
||||||
|
>
|
||||||
|
> **注意**: 所有复盘输出均已脱敏,不包含任何业务,密码等关键信息
|
||||||
|
|
||||||
|
## 迁移目录:
|
||||||
|
- Azure OIDC(SSO) 迁移
|
||||||
|
- id-token(jwt) 验证迁移 (出现语言框架之间的签名算法规范问题,解决见: [输出复盘](https://juejin.cn/post/7300036605099163702))
|
||||||
|
- 钉钉告警: 异常通知
|
||||||
|
- 异常文件记录
|
||||||
|
|
||||||
|
### MILESTONE:
|
||||||
|
- Java 框架搭建
|
||||||
|
- 教育评价系统前后台实现
|
||||||
|
- Chat with AI 接入
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 数据表规则:
|
||||||
|
> ID 没有特殊之指明则为 UUID
|
||||||
|
### 教育评价树
|
||||||
|
分区键: `Appraise` , 表内 `schoolId` 区分学校, `periodId` 区分学区
|
||||||
|
|
||||||
|
### 教育评价项
|
||||||
|
> 学生每学期所有的评价项都在一个项中,按学校进行分区
|
||||||
|
>
|
||||||
|
> 注意: 如果学生中途换班,也就是 classId 发生变动,那么会给这个学生在本学期新开一个文档,也就是说一个学生在一个学期的文档可能不止一个(小概率)
|
||||||
|
>
|
||||||
|
|
||||||
|
分区键: `AppraiseRecord-{学校id}`
|
||||||
|
academicYearId: `学年 + semesterId` -> eg: 2022.uuid
|
@ -0,0 +1,117 @@
|
|||||||
|
package cn.teammodel.ai;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import cn.teammodel.ai.cache.HistoryCache;
|
||||||
|
import cn.teammodel.ai.domain.SparkChatRequestParam;
|
||||||
|
import cn.teammodel.ai.listener.SparkGptStreamListener;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spark Gpt client
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-15 14:29
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
public class SparkGptClient implements InitializingBean {
|
||||||
|
@Resource
|
||||||
|
private SparkGptProperties sparkGptProperties;
|
||||||
|
private OkHttpClient okHttpClient;
|
||||||
|
// private String authUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态构造对象方法
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
// 初始化缓存
|
||||||
|
HistoryCache.init(sparkGptProperties.getCache_timeout(), sparkGptProperties.getCache_context());
|
||||||
|
// 初始化 authUrl
|
||||||
|
// log.info("[SPARK CHAT] 鉴权 endpoint : {}", this.authUrl);
|
||||||
|
this.okHttpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(180, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(180, TimeUnit.SECONDS) // sse 接口的 readTimeout 不能设置小了
|
||||||
|
.writeTimeout(180, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流式的生成结果,以 sse 的方式向客户端推送
|
||||||
|
*/
|
||||||
|
public void streamChatCompletion(SparkChatRequestParam param, SparkGptStreamListener listener) {
|
||||||
|
try {
|
||||||
|
param.setAppId(sparkGptProperties.getAppId());
|
||||||
|
String authUrl = genAuthUrl(sparkGptProperties.getEndpoint(), sparkGptProperties.getApiKey(), sparkGptProperties.getApiSecret());
|
||||||
|
authUrl = authUrl.replace("http://", "ws://").replace("https://", "wss://");
|
||||||
|
Request request = new Request.Builder().url(authUrl).build();
|
||||||
|
// 设置请求参数
|
||||||
|
listener.setRequestJson(param.toJsonParams());
|
||||||
|
log.info("[SPARK CHAT] 请求参数 {}", JSONUtil.parseObj(param.toJsonParams()).toStringPretty());
|
||||||
|
// 不能使用单例 client
|
||||||
|
okHttpClient.newWebSocket(request, listener);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[SPARK CHAT] Spark AI 请求异常: {}", e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 生成鉴权URL
|
||||||
|
*/
|
||||||
|
public static String genAuthUrl(String endpoint, String apiKey, String apiSecret) {
|
||||||
|
URL url = null;
|
||||||
|
String date = null;
|
||||||
|
String preStr = null;
|
||||||
|
Mac mac = null;
|
||||||
|
try {
|
||||||
|
url = new URL(endpoint);
|
||||||
|
// 时间
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||||
|
format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
date = format.format(new Date());
|
||||||
|
// 拼接
|
||||||
|
preStr = "host: " + url.getHost() + "\n" +
|
||||||
|
"date: " + date + "\n" +
|
||||||
|
"GET " + url.getPath() + " HTTP/1.1";
|
||||||
|
// SHA256加密
|
||||||
|
mac = Mac.getInstance("hmacsha256");
|
||||||
|
SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
|
||||||
|
mac.init(spec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[SPARK CHAT] 生成鉴权URL失败, endpoint: {}, apiKey: {}, apiSecret: {}", endpoint, apiKey, apiSecret);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
|
||||||
|
// Base64加密
|
||||||
|
String sha = Base64.getEncoder().encodeToString(hexDigits);
|
||||||
|
// 拼接
|
||||||
|
String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
|
||||||
|
// 拼接地址
|
||||||
|
HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().
|
||||||
|
addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).
|
||||||
|
addQueryParameter("date", date).//
|
||||||
|
addQueryParameter("host", url.getHost()).//
|
||||||
|
build();
|
||||||
|
return httpUrl.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package cn.teammodel.ai;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-15 14:29
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "spark.gpt")
|
||||||
|
public class SparkGptProperties {
|
||||||
|
private String endpoint;
|
||||||
|
private String appId;
|
||||||
|
private String apiKey;
|
||||||
|
private String apiSecret;
|
||||||
|
/**
|
||||||
|
* 单个会话的缓存过期时间
|
||||||
|
*/
|
||||||
|
private Long cache_timeout;
|
||||||
|
/**
|
||||||
|
* 历史上下文数
|
||||||
|
*/
|
||||||
|
private Integer cache_context;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package cn.teammodel.ai;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
@Slf4j
|
||||||
|
public class SseHelper {
|
||||||
|
/**
|
||||||
|
* 断开 server 与 client 的 sse 连接
|
||||||
|
*/
|
||||||
|
public void complete(SseEmitter sseEmitter) {
|
||||||
|
try {
|
||||||
|
sseEmitter.complete();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向 client 发送消息
|
||||||
|
*/
|
||||||
|
public void send(SseEmitter sseEmitter, Object data) {
|
||||||
|
try {
|
||||||
|
sseEmitter.send(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("sseEmitter send error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package cn.teammodel.ai.cache;
|
||||||
|
|
||||||
|
import cn.hutool.cache.CacheUtil;
|
||||||
|
import cn.hutool.cache.impl.TimedCache;
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import cn.teammodel.model.entity.ai.ChatSession.Message;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 聊天记录上下文的缓存
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-20 11:02
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class HistoryCache {
|
||||||
|
private static TimedCache<Object, Object> HISTORY;
|
||||||
|
private static Integer contextSize = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化缓存
|
||||||
|
*/
|
||||||
|
public static void init(Long timeout, Integer contextNum) {
|
||||||
|
contextSize = contextNum;
|
||||||
|
HISTORY = CacheUtil.newTimedCache(timeout);
|
||||||
|
// 一分钟清理一次
|
||||||
|
HISTORY.schedulePrune(60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Message> getContext(String sessionId) {
|
||||||
|
return (List<Message>) HISTORY.get(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putContext(String sessionId, List<Message> context) {
|
||||||
|
HISTORY.put(sessionId, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeContext(String sessionId) {
|
||||||
|
HISTORY.remove(sessionId);}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新上下文, 保证上下文的数量在 contextSize 之内
|
||||||
|
*/
|
||||||
|
public static void updateContext(String sessionId, Message message) {
|
||||||
|
List<Message> messages = (List<Message>)HISTORY.get(sessionId);
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(messages)) {
|
||||||
|
List<Message> context = ListUtil.of(message);
|
||||||
|
HISTORY.put(sessionId, context);
|
||||||
|
} else if (messages.size() >= contextSize) {
|
||||||
|
// 队列
|
||||||
|
messages.remove(0);
|
||||||
|
messages.add(message);
|
||||||
|
} else {
|
||||||
|
messages.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,366 @@
|
|||||||
|
package cn.teammodel.ai.deepseek;
|
||||||
|
|
||||||
|
import cn.teammodel.ai.SparkGptClient;
|
||||||
|
import cn.teammodel.ai.SseHelper;
|
||||||
|
import cn.teammodel.ai.cache.HistoryCache;
|
||||||
|
import cn.teammodel.ai.domain.SparkChatRequestParam;
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.common.PK;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import cn.teammodel.model.dto.ai.ChatCompletionReqDto;
|
||||||
|
import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatRequestDto;
|
||||||
|
import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatResponse;
|
||||||
|
import cn.teammodel.model.dto.ai.deepseek.ChatReqDto;
|
||||||
|
import cn.teammodel.model.entity.ai.ChatSession;
|
||||||
|
import cn.teammodel.repository.ChatSessionRepository;
|
||||||
|
import cn.teammodel.utils.JsonUtil;
|
||||||
|
import com.azure.cosmos.models.CosmosPatchOperations;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.sun.org.apache.bcel.internal.generic.NEW;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.*;
|
||||||
|
import okio.Buffer;
|
||||||
|
import okio.BufferedSource;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class DeepSeekClient {
|
||||||
|
public static final String API_Key;
|
||||||
|
public static final String API_Url;
|
||||||
|
public static String API_Model;
|
||||||
|
//public static String API_Model_Url;
|
||||||
|
//public static String API_Model_Reasoner;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private static ChatSessionRepository chatSessionRepository;
|
||||||
|
|
||||||
|
private static final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
/**
|
||||||
|
* 读取配置文件 读取key 和url
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
Properties props = new Properties();
|
||||||
|
try {
|
||||||
|
InputStream is = DeepSeekClient.class.getResourceAsStream("/DeepSeekConfig.properties");
|
||||||
|
props.load(is);
|
||||||
|
API_Key = props.getProperty("key");
|
||||||
|
API_Url = props.getProperty("url");
|
||||||
|
API_Model = props.getProperty("model");
|
||||||
|
//API_Model_Url = props.getProperty("modelReasonerUrl");
|
||||||
|
//API_Model_Reasoner = props.getProperty("modelReasoner");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提问题 测试使用
|
||||||
|
* @param mssage
|
||||||
|
*/
|
||||||
|
private static Map<String, Object> ask(ChatReqDto mssage)
|
||||||
|
{
|
||||||
|
Map<String, Object> mapper = new HashMap<>();
|
||||||
|
//创建消息列表
|
||||||
|
List<ChatReqDto> msg = new ArrayList<>();
|
||||||
|
msg.add(mssage);
|
||||||
|
|
||||||
|
//构建请求头
|
||||||
|
DeepSeekChatRequestDto requestBody = new DeepSeekChatRequestDto();
|
||||||
|
requestBody.setModel(API_Model);
|
||||||
|
requestBody.setMessages(msg);
|
||||||
|
requestBody.setTemperature(0);
|
||||||
|
requestBody.setMax_tokens(1024);
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
//发起请求
|
||||||
|
DeepSeekChatResponse response = SendRequests(requestBody);
|
||||||
|
//Map<String, Object> response = SendRequest(requestBody);
|
||||||
|
Long endTime = System.currentTimeMillis();
|
||||||
|
//思考耗时 秒
|
||||||
|
long time = (endTime-startTime)/1000;
|
||||||
|
response.setWasteTime(time);
|
||||||
|
return mapper;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* OkHttpClient 方式请求
|
||||||
|
* 返回请求结果 转 实体有问题
|
||||||
|
* @param requestBody
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static DeepSeekChatResponse SendRequests(DeepSeekChatRequestDto requestBody)
|
||||||
|
{
|
||||||
|
DeepSeekChatResponse chatResponse = new DeepSeekChatResponse();
|
||||||
|
//OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(60, TimeUnit.SECONDS).build();//设置连接超时时间 1分钟
|
||||||
|
OkHttpClient client = new OkHttpClient().newBuilder().build();//设置连接超时时间 1分钟
|
||||||
|
|
||||||
|
|
||||||
|
MediaType mediaType = MediaType.parse("application/json");
|
||||||
|
//String content = "{\n \"messages\": [\n {\n \"content\": \"You are a helpful assistant\",\n \"role\": \"system\"\n },\n {\n \"content\": \"Hi\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"deepseek-chat\",\n \"frequency_penalty\": 0,\n \"max_tokens\": 2048,\n \"presence_penalty\": 0,\n \"response_format\": {\n \"type\": \"text\"\n },\n \"stop\": null,\n \"stream\": false,\n \"stream_options\": null,\n \"temperature\": 1,\n \"top_p\": 1,\n \"tools\": null,\n \"tool_choice\": \"none\",\n \"logprobs\": false,\n \"top_logprobs\": null\n}";
|
||||||
|
String content = JsonUtil.convertToJson(requestBody);
|
||||||
|
|
||||||
|
RequestBody body = RequestBody.create(mediaType, content);
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(API_Url)
|
||||||
|
.method("POST", body)
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.addHeader("Authorization", "Bearer "+API_Key)
|
||||||
|
.build();
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
try(Response response = client.newCall(request).execute()) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
StringBuilder responseBody = new StringBuilder();
|
||||||
|
try (BufferedSource source = response.body().source()) {
|
||||||
|
Buffer buffer = new Buffer();
|
||||||
|
while (source.read(buffer, 2048) != -1) {
|
||||||
|
// 处理流式数据
|
||||||
|
String chunk = buffer.readUtf8();
|
||||||
|
if (chunk.startsWith("data:") && !chunk.contains("data: [DONE]")) {
|
||||||
|
String[] split = chunk.split("data:");
|
||||||
|
for (String result : split) {
|
||||||
|
if (StringUtils.hasLength(result) && StringUtils.hasLength(result.trim())) {
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(result);
|
||||||
|
if (!ObjectUtils.isEmpty(jsonNode.get("choices"))) {
|
||||||
|
JsonNode delta = jsonNode.get("choices").get(0).get("delta");
|
||||||
|
log.debug("Delta Content: {}", delta.get("content").asText());
|
||||||
|
responseBody.append(delta.get("content").asText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String responseBody1 = response.body().string();
|
||||||
|
// 使用 Gson 将 JSON 字符串转换为 MyEntity 对象
|
||||||
|
Gson gson = new Gson();
|
||||||
|
chatResponse = gson.fromJson(responseBody1, DeepSeekChatResponse.class);
|
||||||
|
// 确保关闭响应体以释放资源
|
||||||
|
response.body().close();
|
||||||
|
chatResponse.setCode(200);
|
||||||
|
chatResponse.setMsg("成功");
|
||||||
|
} else {
|
||||||
|
chatResponse.setCode( response.code());
|
||||||
|
chatResponse.setMsg(response.body().string());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (e.getMessage().equals("Connection timed out") || e.getMessage().equals("timeout"))
|
||||||
|
{
|
||||||
|
chatResponse.setCode(408);
|
||||||
|
chatResponse.setMsg("请求DeepSeek服务器超时");
|
||||||
|
}else {
|
||||||
|
chatResponse.setCode( 500);
|
||||||
|
chatResponse.setMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chatResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OkHttpClient 方式请求 流式返回
|
||||||
|
* @param requestBody
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static SseEmitter SendRequestsEmitter(DeepSeekChatRequestDto requestBody)
|
||||||
|
{
|
||||||
|
SseEmitter sseEmitter = new SseEmitter(-1L);
|
||||||
|
//OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(60, TimeUnit.SECONDS).build();//设置连接超时时间 1分钟
|
||||||
|
OkHttpClient client = new OkHttpClient().newBuilder().build();//
|
||||||
|
|
||||||
|
MediaType mediaType = MediaType.parse("application/json");
|
||||||
|
//String content = "{\n \"messages\": [\n {\n \"content\": \"You are a helpful assistant\",\n \"role\": \"system\"\n },\n {\n \"content\": \"Hi\",\n \"role\": \"user\"\n }\n ],\n \"model\": \"deepseek-chat\",\n \"frequency_penalty\": 0,\n \"max_tokens\": 2048,\n \"presence_penalty\": 0,\n \"response_format\": {\n \"type\": \"text\"\n },\n \"stop\": null,\n \"stream\": false,\n \"stream_options\": null,\n \"temperature\": 1,\n \"top_p\": 1,\n \"tools\": null,\n \"tool_choice\": \"none\",\n \"logprobs\": false,\n \"top_logprobs\": null\n}";
|
||||||
|
String content = JsonUtil.convertToJson(requestBody);
|
||||||
|
|
||||||
|
RequestBody body = RequestBody.create(mediaType, content);
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(API_Url)
|
||||||
|
.method("POST", body)
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.addHeader("Authorization", "Bearer "+API_Key)
|
||||||
|
.build();
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
try(Response response = client.newCall(request).execute()) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
StringBuilder responseBody = new StringBuilder();
|
||||||
|
try (BufferedSource source = response.body().source()) {
|
||||||
|
Buffer buffer = new Buffer();
|
||||||
|
while (source.read(buffer, 2048) != -1) {
|
||||||
|
// 处理流式数据
|
||||||
|
String chunk = buffer.readUtf8();
|
||||||
|
if (chunk.startsWith("data:") && !chunk.contains("data: [DONE]")) {
|
||||||
|
String[] split = chunk.split("data:");
|
||||||
|
for (String result : split) {
|
||||||
|
if (StringUtils.hasLength(result) && StringUtils.hasLength(result.trim())) {
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(result);
|
||||||
|
if (!ObjectUtils.isEmpty(jsonNode.get("choices"))) {
|
||||||
|
JsonNode delta = jsonNode.get("choices").get(0).get("delta");
|
||||||
|
log.debug("Delta Content: {}", delta.get("content").asText());
|
||||||
|
sseEmitter.send(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (IOException e) {
|
||||||
|
sseEmitter.completeWithError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sseEmitter.completeWithError(new Exception("请求DeepSeek服务器失败"));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
sseEmitter.completeWithError(e);
|
||||||
|
}
|
||||||
|
return sseEmitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HttpClient 方式请求
|
||||||
|
* @param chatCompletionReqDto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static SseEmitter HttpClientSendRequests(ChatCompletionReqDto chatCompletionReqDto){
|
||||||
|
SseEmitter emitter = new SseEmitter(-1L);
|
||||||
|
List<ChatReqDto> msg = new ArrayList<>();
|
||||||
|
msg.add(new ChatReqDto(chatCompletionReqDto.getSessionId(), "user", chatCompletionReqDto.getText()));
|
||||||
|
//构建请求头
|
||||||
|
DeepSeekChatRequestDto requestBody = new DeepSeekChatRequestDto();
|
||||||
|
requestBody.setModel(DeepSeekClient.API_Model);
|
||||||
|
requestBody.setMessages(msg);
|
||||||
|
requestBody.setTemperature(0);
|
||||||
|
requestBody.setStream(true);
|
||||||
|
|
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||||
|
// 创建HttpPost对象
|
||||||
|
HttpPost httpPost = new HttpPost(API_Url);
|
||||||
|
//添加请求头
|
||||||
|
httpPost.setHeader("Content-Type", "application/json");
|
||||||
|
httpPost.setHeader("Accept", "application/json");
|
||||||
|
httpPost.setHeader("Authorization", "Bearer " + API_Key);
|
||||||
|
|
||||||
|
requestBody.setStream(true);
|
||||||
|
// 设置请求体
|
||||||
|
String jsonContent = JsonUtil.convertToJson(requestBody);
|
||||||
|
httpPost.setEntity(new StringEntity(jsonContent, ContentType.create("application/json", "UTF-8")));
|
||||||
|
StringBuilder responseBody = new StringBuilder();
|
||||||
|
try (CloseableHttpResponse response = httpClient.execute(httpPost);
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {
|
||||||
|
String line;
|
||||||
|
StringBuilder strContent = new StringBuilder();
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (line.startsWith("data: ")) {
|
||||||
|
String jsonData = line.substring(6);
|
||||||
|
if ("[DONE]".equals(jsonData)) {
|
||||||
|
//SseHelper.send(emitter, "[DONE]");
|
||||||
|
emitter.send("[DONE]");
|
||||||
|
// 更新历史会话记录
|
||||||
|
ChatSession.Message message = ChatSession.Message.of(chatCompletionReqDto.getText(), strContent.toString(),chatCompletionReqDto.getModel());
|
||||||
|
HistoryCache.updateContext(chatCompletionReqDto.getSessionId(), message);
|
||||||
|
CosmosPatchOperations options = CosmosPatchOperations.create()
|
||||||
|
.replace("/updateTime", Instant.now().toEpochMilli())
|
||||||
|
.add("/history/-", message);
|
||||||
|
chatSessionRepository.save(chatCompletionReqDto.getSessionId(), PK.of(PK.CHAT_SESSION), ChatSession.class, options);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
JsonNode node = objectMapper.readTree(jsonData);
|
||||||
|
String content = node.path("choices")
|
||||||
|
.path(0)
|
||||||
|
.path("delta")
|
||||||
|
.path("content")
|
||||||
|
.asText("");
|
||||||
|
if (!content.isEmpty()) {
|
||||||
|
responseBody.append(content);
|
||||||
|
strContent.append(content);
|
||||||
|
emitter.send(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emitter.complete();
|
||||||
|
}catch (Exception e)
|
||||||
|
{
|
||||||
|
emitter.completeWithError(e);
|
||||||
|
}
|
||||||
|
}catch (Exception e) {
|
||||||
|
emitter.completeWithError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* HttpClient 方式请求
|
||||||
|
* @param requestBody
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Map<String, Object> SendRequest(DeepSeekChatRequestDto requestBody) {
|
||||||
|
Map<String, Object> mapper = new HashMap<>();
|
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||||
|
// 创建HttpPost对象
|
||||||
|
HttpPost httpPost = new HttpPost(API_Url);
|
||||||
|
//添加请求头
|
||||||
|
httpPost.setHeader("Content-Type", "application/json");
|
||||||
|
httpPost.setHeader("Accept", "application/json");
|
||||||
|
httpPost.setHeader("Authorization", "Bearer " +API_Key);
|
||||||
|
|
||||||
|
// 设置请求体
|
||||||
|
String jsonContent = JsonUtil.convertToJson(requestBody);
|
||||||
|
httpPost.setEntity(new StringEntity(jsonContent, ContentType.create("application/json", "UTF-8")));
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||||
|
// 获取响应实体
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
if (entity != null) {
|
||||||
|
// 解析响应内容
|
||||||
|
String jsonString = EntityUtils.toString(entity);
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
mapper = objectMapper.readValue(jsonString, TypeFactory.defaultInstance().constructMapType(Map.class, String.class, Object.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查响应状态码
|
||||||
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
|
if (statusCode != 200) throw new RuntimeException("Failed : HTTP error code : " + statusCode);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据解析异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "请求头异常"+e.getMessage());
|
||||||
|
}
|
||||||
|
//TODO 请求接口
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package cn.teammodel.ai.listener;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import cn.teammodel.ai.SseHelper;
|
||||||
|
import cn.teammodel.ai.domain.SparkChatResponse;
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.WebSocket;
|
||||||
|
import okhttp3.WebSocketListener;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* okhttp 调用 ws 接口时的 listener
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-15 16:17
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SparkGptStreamListener extends WebSocketListener {
|
||||||
|
private final SseEmitter sseEmitter;
|
||||||
|
private String requestJson;
|
||||||
|
/**
|
||||||
|
* 模型响应的完整回复
|
||||||
|
*/
|
||||||
|
private String answer = "";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(WebSocket webSocket, @NotNull Response response) {
|
||||||
|
// ws 建立连接后发送请求的数据, 在 onMessage 中接受 server 的响应数据
|
||||||
|
webSocket.send(requestJson);
|
||||||
|
// 执行成功回调
|
||||||
|
try {
|
||||||
|
onOpen.accept(webSocket);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.onFailure(webSocket, e, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(WebSocket webSocket, String text) {
|
||||||
|
// 向 sse 推送消息(一次 onMessage 事件推送一次)
|
||||||
|
SparkChatResponse sparkChatResponse = JSONUtil.toBean(text, SparkChatResponse.class);
|
||||||
|
// 请求是否异常
|
||||||
|
if (sparkChatResponse.getHeader().getCode() != 0) {
|
||||||
|
this.onFailure(
|
||||||
|
webSocket,
|
||||||
|
new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(),
|
||||||
|
sparkChatResponse.getHeader().getMessage()),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 推送回答 segment
|
||||||
|
String msgSegment = sparkChatResponse.getPayload().getChoices().getText().get(0).getContent();
|
||||||
|
// 处理消息格式(空格和换行符)
|
||||||
|
// msgSegment = StrUtil.replace(msgSegment, " ", " ").replaceAll("\n", "\n");
|
||||||
|
msgSegment = StrUtil.replace(msgSegment, " ", " ").replaceAll("\n", "<br>");
|
||||||
|
answer += msgSegment;
|
||||||
|
SseHelper.send(sseEmitter, msgSegment);
|
||||||
|
|
||||||
|
// 处理模型的最终响应
|
||||||
|
if (sparkChatResponse.getHeader().getStatus() == 2) {
|
||||||
|
// 其实 spark 会主动断开连接
|
||||||
|
webSocket.close(1000, "done");
|
||||||
|
onComplete.accept(answer);
|
||||||
|
SseHelper.complete(sseEmitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(WebSocket webSocket, Throwable t, @Nullable Response response) {
|
||||||
|
webSocket.close(1000, t.getMessage());
|
||||||
|
this.onError.accept(t);
|
||||||
|
// 失败时结束 sse 连接
|
||||||
|
SseHelper.send(sseEmitter,t.getMessage() + "[DONE]");
|
||||||
|
SseHelper.complete(sseEmitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 这几个 function 可以在 listener 被调用时设置, 实现类似事件的回调(可以使用模板方法模式实现)
|
||||||
|
protected Consumer<WebSocket> onOpen = (s) -> {};
|
||||||
|
protected Consumer<Throwable> onError = (s) -> {};
|
||||||
|
protected Consumer<String> onComplete = (s) -> {};
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package cn.teammodel.callAble;
|
||||||
|
|
||||||
|
import cn.teammodel.model.entity.school.LessonRecord;
|
||||||
|
import cn.teammodel.repository.LessonRecordRepository;
|
||||||
|
import com.azure.spring.data.cosmos.core.query.CosmosPageRequest;
|
||||||
|
import org.springframework.data.domain.Slice;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
public class LessonRecordQueryTask implements Callable<List<LessonRecord>> {
|
||||||
|
private final LessonRecordRepository repository;
|
||||||
|
private final String lessonRecordKey;
|
||||||
|
private final Long startTime;
|
||||||
|
private final Long endTime;
|
||||||
|
private final String subjectId;
|
||||||
|
private final String tmdId;
|
||||||
|
private final String grade;
|
||||||
|
private final String periodId;
|
||||||
|
private static final int SLICE_SIZE = 1000;
|
||||||
|
|
||||||
|
public LessonRecordQueryTask(LessonRecordRepository repository, String lessonRecordKey,
|
||||||
|
long startTime, long endTime,
|
||||||
|
String subjectId, String tmdId, String grade,
|
||||||
|
String periodId) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.lessonRecordKey = lessonRecordKey;
|
||||||
|
this.startTime = startTime;
|
||||||
|
this.endTime = endTime;
|
||||||
|
this.subjectId = subjectId;
|
||||||
|
this.tmdId = tmdId;
|
||||||
|
this.grade = grade;
|
||||||
|
this.periodId = periodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LessonRecord> call() throws Exception {
|
||||||
|
List<LessonRecord> result = new ArrayList<>();
|
||||||
|
CosmosPageRequest pageRequest = new CosmosPageRequest(0, SLICE_SIZE, null);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Slice<LessonRecord> slice = repository.getLessonsByConditions(
|
||||||
|
lessonRecordKey, startTime, endTime, subjectId, tmdId, grade, periodId, pageRequest
|
||||||
|
);
|
||||||
|
result.addAll(slice.getContent());
|
||||||
|
|
||||||
|
if (!slice.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pageRequest = (CosmosPageRequest) slice.nextPageable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-02-01 15:30
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum ChatAppScopeEnum {
|
||||||
|
PUBLIC("public", "公共"),
|
||||||
|
SCHOOL("school", "学校"),
|
||||||
|
PRIVATE("private", "私人");
|
||||||
|
private final String code;
|
||||||
|
private final String name;
|
||||||
|
public static List<String> codes() {
|
||||||
|
return Arrays.stream(values()).map(ChatAppScopeEnum::getCode).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 name 获取 code
|
||||||
|
*/
|
||||||
|
public static String getCodeByName(String name) {
|
||||||
|
ChatAppScopeEnum chatAppScopeEnum = Arrays.stream(values()).filter(item -> item.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
String res = null;
|
||||||
|
if (chatAppScopeEnum != null) {
|
||||||
|
res = chatAppScopeEnum.getCode();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatAppScopeEnum(String code, String name) {
|
||||||
|
this.code = code;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-29 14:26
|
||||||
|
*/
|
||||||
|
public interface CommonConstant {
|
||||||
|
String DASH = "-";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
public enum ErrorCode {
|
||||||
|
|
||||||
|
SUCCESS(200, "ok"),
|
||||||
|
PARAMS_ERROR(40000, "请求参数错误"),
|
||||||
|
NOT_LOGIN_ERROR(40100, "未登录"),
|
||||||
|
NO_AUTH_ERROR(40101, "无权限"),
|
||||||
|
NOT_FOUND_ERROR(40400, "请求数据不存在"),
|
||||||
|
FORBIDDEN_ERROR(40300, "禁止访问"),
|
||||||
|
SYSTEM_ERROR(50000, "系统内部异常"),
|
||||||
|
OPERATION_ERROR(50001, "操作失败"),
|
||||||
|
DATA_FORMAT_ERROR(40001, "数据格式错误"),
|
||||||
|
PARAM_ERROR(40002, "数据为空");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态码
|
||||||
|
*/
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 信息
|
||||||
|
*/
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
ErrorCode(int code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 五育枚举
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-14 12:19
|
||||||
|
*/
|
||||||
|
public enum FiveEducations {
|
||||||
|
VIRTUE("virtue", "德育"),
|
||||||
|
INTELLIGENCE("intelligence","智育"),
|
||||||
|
SPORTS("sports", "体育"),
|
||||||
|
ART("art", "美育"),
|
||||||
|
LABOUR("labour", "劳育");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static List<String> codes() {
|
||||||
|
return Arrays.stream(values()).map(FiveEducations::getCode).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 name 获取 code
|
||||||
|
*/
|
||||||
|
public static String getCodeByName(String name) {
|
||||||
|
FiveEducations fiveEducation = Arrays.stream(values()).filter(item -> item.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
String res = null;
|
||||||
|
if (fiveEducation != null) {
|
||||||
|
res = fiveEducation.getCode();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
FiveEducations(String code, String name) {
|
||||||
|
this.code = code;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-04 9:55
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class IdRequest {
|
||||||
|
@NotBlank(message = "id 不能为空")
|
||||||
|
private String id;
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
import com.azure.cosmos.models.PartitionKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分区键常量
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 15:31
|
||||||
|
*/
|
||||||
|
public interface PK {
|
||||||
|
/**
|
||||||
|
* 评价树
|
||||||
|
*/
|
||||||
|
String PK_APPRAISE = "Appraise";
|
||||||
|
/**
|
||||||
|
* 学生的评价记录
|
||||||
|
* 参数数量: 1 , 拼接: SchoolId
|
||||||
|
*/
|
||||||
|
String PK_APPRAISE_RECORD = "AppraiseRecord-%s";
|
||||||
|
String COMMON_BASE = "Base";
|
||||||
|
String PK_LESSON_RECORD = "LessonRecord-%s";
|
||||||
|
/**
|
||||||
|
* 学生,拼接学校 id
|
||||||
|
*/
|
||||||
|
String STUDENT = "Base-%s";
|
||||||
|
String CLASS = "Class-%s";
|
||||||
|
String CHAT_SESSION = "ChatSession";
|
||||||
|
/**
|
||||||
|
* DeepSeek问答会话
|
||||||
|
*/
|
||||||
|
String DEEPSEEK_SESSION ="DeepSeekSession";
|
||||||
|
String WEEK_DUTY = "Duty";
|
||||||
|
String WEEK_DUTY_RECORD = "DutyRecord-%s";
|
||||||
|
String CHAT_APP = "ChatApp";
|
||||||
|
String NEWS = "News-%s";
|
||||||
|
String CLASS_RESULT = "ExamClassResult-%s";
|
||||||
|
String EXAM = "Exam-%s";
|
||||||
|
String PTTEACHER = "PtTeacher-%s";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建分区键
|
||||||
|
*/
|
||||||
|
static PartitionKey of(String pk) {
|
||||||
|
return new PartitionKey(pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要传参构建分区键<br/>
|
||||||
|
* 注意: 参数的个数不会在编译时被校验,需自己注意
|
||||||
|
*/
|
||||||
|
static PartitionKey buildOf(String pk, String... args) {
|
||||||
|
String pkStr = String.format(pk, args);
|
||||||
|
return new PartitionKey(pkStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-08 17:30
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PageVo<T> {
|
||||||
|
private Integer totalPages;
|
||||||
|
private Long totalItems;
|
||||||
|
private List<T> content;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package cn.teammodel.common;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-05 14:58
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PageableRequest {
|
||||||
|
@ApiModelProperty("当前页码, 默认: 0")
|
||||||
|
private Integer current = 0;
|
||||||
|
@ApiModelProperty("每页数量, 默认: 10")
|
||||||
|
private Integer size = 10;
|
||||||
|
}
|
@ -1,37 +1,48 @@
|
|||||||
package cn.teammodel.common;
|
package cn.teammodel.common;
|
||||||
|
|
||||||
public class R {
|
import lombok.Data;
|
||||||
private Integer code;
|
|
||||||
private String message;
|
import java.io.Serializable;
|
||||||
private String data;
|
|
||||||
|
@Data
|
||||||
public R(Integer code, String message, String data) {
|
public class R<T> implements Serializable {
|
||||||
this.code = code;
|
|
||||||
this.message = message;
|
private int code;
|
||||||
this.data = data;
|
|
||||||
}
|
private T data;
|
||||||
|
|
||||||
public Integer getCode() {
|
private String message;
|
||||||
return code;
|
|
||||||
}
|
public R(int code, T data, String message) {
|
||||||
|
this.code = code;
|
||||||
public void setCode(Integer code) {
|
this.data = data;
|
||||||
this.code = code;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public R(int code, T data) {
|
||||||
return message;
|
this(code, data, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessage(String message) {
|
public R(ErrorCode errorCode) {
|
||||||
this.message = message;
|
this(errorCode.getCode(), null, errorCode.getMessage());
|
||||||
}
|
}
|
||||||
|
public R(ErrorCode errorCode, T data) {
|
||||||
public String getData() {
|
this(errorCode.getCode(), data, errorCode.getMessage());
|
||||||
return data;
|
}
|
||||||
}
|
|
||||||
|
public static <T> R<T> success(T data) {
|
||||||
public void setData(String data) {
|
return new R<>(ErrorCode.SUCCESS, data);
|
||||||
this.data = data;
|
}
|
||||||
}
|
|
||||||
}
|
public static <T> R<T> error(String msg) {
|
||||||
|
return new R<>(ErrorCode.SYSTEM_ERROR.getCode(), null, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> R<T> error(Integer code, String msg) {
|
||||||
|
return new R<>(code, null, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> R<T> error(ErrorCode errorCode) {
|
||||||
|
return new R<>(errorCode);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package cn.teammodel.config;
|
||||||
|
|
||||||
|
import cn.teammodel.config.intercepter.EnhanceRequestServletFilter;
|
||||||
|
import cn.teammodel.config.intercepter.UploadApiLogInterceptor;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebMvc配置 : 静态文件、拦截器等
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-01-15 17:06
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WebMvcConfig implements WebMvcConfigurer {
|
||||||
|
private final UploadApiLogInterceptor uploadApiLogInterceptor;
|
||||||
|
/**
|
||||||
|
* 拦截器配置
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(@NotNull InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(uploadApiLogInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册过滤器
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean<EnhanceRequestServletFilter> filterRegistrationBean(){
|
||||||
|
FilterRegistrationBean<EnhanceRequestServletFilter> filterRegistrationBean=new FilterRegistrationBean<>();
|
||||||
|
filterRegistrationBean.setFilter(new EnhanceRequestServletFilter());
|
||||||
|
filterRegistrationBean.addUrlPatterns("/*");
|
||||||
|
//order的数值越小 则优先级越高,这里直接使用的最高优先级
|
||||||
|
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||||
|
return filterRegistrationBean;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package cn.teammodel.config.exception;
|
||||||
|
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.manager.notification.NotificationService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.MissingPathVariableException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理器
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private NotificationService notificationService;
|
||||||
|
/**
|
||||||
|
* 业务异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(ServiceException.class)
|
||||||
|
public R<?> handleServiceException(ServiceException e, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
Integer code = e.getCode();
|
||||||
|
return ObjectUtils.isNotEmpty(code) ? R.error(code, e.getMessage()) : R.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||||
|
public R<?> handleHttpMsgNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return R.error(ErrorCode.PARAMS_ERROR.getCode(), "参数格式有误");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求路径中缺少必需的路径变量
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MissingPathVariableException.class)
|
||||||
|
public R<?> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
String requestURI = request.getRequestURI();
|
||||||
|
log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
|
||||||
|
return R.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求参数类型不匹配
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||||
|
public R<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
String requestURI = request.getRequestURI();
|
||||||
|
log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
|
||||||
|
return R.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截未知的运行时异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(RuntimeException.class)
|
||||||
|
public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
String requestURI = request.getRequestURI();
|
||||||
|
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
||||||
|
notificationService.send("RuntimeException 告警: " + getCausesAsString(e, 5));
|
||||||
|
return R.error(ErrorCode.SYSTEM_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public R<?> handleException(Exception e, HttpServletRequest request)
|
||||||
|
{
|
||||||
|
String requestURI = request.getRequestURI();
|
||||||
|
log.error("请求地址'{}',发生系统异常.", requestURI, e);
|
||||||
|
|
||||||
|
notificationService.send("Exception 告警: " + getCausesAsString(e, 5));
|
||||||
|
return R.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义验证异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
public R<?> handleBindException(BindException e)
|
||||||
|
{
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||||
|
return R.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义验证异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
|
||||||
|
{
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
|
||||||
|
return R.error(message);
|
||||||
|
}
|
||||||
|
private static String getCausesAsString(Throwable throwable, int maxDepth) {
|
||||||
|
return Stream.iterate(throwable, Throwable::getCause)
|
||||||
|
.limit(maxDepth)
|
||||||
|
.map(e -> e.getClass().getSimpleName() + ": " + e.getMessage())
|
||||||
|
.collect(Collectors.joining(" <- "));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package cn.teammodel.config.ies;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Configuration
|
||||||
|
public class IESConfig {
|
||||||
|
@Value("${ies.server-url}")
|
||||||
|
private String serverUrl;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
package cn.teammodel.config.intercepter;
|
||||||
|
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.hutool.extra.servlet.ServletUtil;
|
||||||
|
import cn.hutool.jwt.JWTUtil;
|
||||||
|
import cn.teammodel.manager.notification.NotificationService;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传接口调用日志拦截器
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-03-18 10:00
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class UploadApiLogInterceptor implements HandlerInterceptor {
|
||||||
|
@Value("${spring.env}")
|
||||||
|
private String env;
|
||||||
|
@Resource
|
||||||
|
private NotificationService notificationService;
|
||||||
|
|
||||||
|
private final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
|
||||||
|
if (!env.equals("dev")) {
|
||||||
|
doUploadLog(request);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doUploadLog(@NotNull HttpServletRequest request) throws IOException {
|
||||||
|
String ip = ServletUtil.getClientIP(request);
|
||||||
|
String client = "";
|
||||||
|
String tokenSha = "";
|
||||||
|
String id = "";
|
||||||
|
String name = "";
|
||||||
|
String school = "";
|
||||||
|
String scope = "";
|
||||||
|
String referer = request.getHeader("Referer");
|
||||||
|
Long requestTime = Instant.now().toEpochMilli();
|
||||||
|
// 获取 json 请求参数(这里读了后,后面就再也读不到了,需要处理)
|
||||||
|
BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
|
||||||
|
StringBuilder responseStrBuilder = new StringBuilder();
|
||||||
|
String inputStr;
|
||||||
|
while ((inputStr = streamReader.readLine()) != null)
|
||||||
|
responseStrBuilder.append(inputStr);
|
||||||
|
|
||||||
|
JsonNode jsonNode = mapper.readTree(responseStrBuilder.toString());
|
||||||
|
String xAuthToken = request.getHeader("x-auth-AuthToken");
|
||||||
|
// 如果有 authorization
|
||||||
|
String authorization = request.getHeader("Authorization");
|
||||||
|
if (StringUtils.isNotBlank(authorization)) {
|
||||||
|
authorization = authorization.replace("Bearer ", "");
|
||||||
|
List<String> roles = (List<String>) JWTUtil.parseToken(authorization).getPayload("roles");
|
||||||
|
if (ObjectUtils.isNotEmpty(roles)) {
|
||||||
|
client = roles.get(0);
|
||||||
|
}
|
||||||
|
tokenSha = SecureUtil.sha1("Bearer " + authorization);
|
||||||
|
}
|
||||||
|
String xAuthIdToken = request.getHeader("X-Auth-IdToken");
|
||||||
|
if (StringUtils.isNotBlank(xAuthIdToken)) {
|
||||||
|
id = (String) JWTUtil.parseToken(xAuthIdToken).getPayload("sub");
|
||||||
|
name = (String) JWTUtil.parseToken(xAuthIdToken).getPayload("name");
|
||||||
|
if (StringUtils.isNotBlank(tokenSha)) {
|
||||||
|
tokenSha = SecureUtil.sha1(xAuthIdToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String xAuthSchool = request.getHeader("X-Auth-School");
|
||||||
|
if (StringUtils.isNotBlank(xAuthSchool)) {
|
||||||
|
school = xAuthSchool;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(xAuthToken)) {
|
||||||
|
id = (String) JWTUtil.parseToken(xAuthToken).getPayload("sub");
|
||||||
|
name = (String) JWTUtil.parseToken(xAuthToken).getPayload("name");
|
||||||
|
school = (String) JWTUtil.parseToken(xAuthToken).getPayload("azp");
|
||||||
|
scope = (String) JWTUtil.parseToken(xAuthToken).getPayload("scope");
|
||||||
|
if (StringUtils.isNotBlank(tokenSha)) {
|
||||||
|
tokenSha = SecureUtil.sha1(xAuthToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectNode root = mapper.createObjectNode();
|
||||||
|
root.put("ip", ip);
|
||||||
|
root.put("time", requestTime);
|
||||||
|
root.put("id", id);
|
||||||
|
root.put("name", name);
|
||||||
|
root.set("param", jsonNode);
|
||||||
|
root.put("school", school);
|
||||||
|
root.put("client", client);
|
||||||
|
root.put("tid", tokenSha);
|
||||||
|
root.put("scope", scope);
|
||||||
|
root.put("path", request.getContextPath() + request.getRequestURI());
|
||||||
|
root.put("host", request.getServerName());
|
||||||
|
root.put("p", "appraisal");
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
// OkHttpClient okHttpClient = new OkHttpClient();
|
||||||
|
// String requestData = root.toString();
|
||||||
|
// RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), requestData);
|
||||||
|
// Request okRequest = new Request.Builder()
|
||||||
|
// .url("http://52.130.252.100:8806/api/http-log")
|
||||||
|
// .post(requestBody)
|
||||||
|
// .build();
|
||||||
|
//
|
||||||
|
// okHttpClient.newCall(okRequest).enqueue(new Callback() {
|
||||||
|
// @Override
|
||||||
|
// public void onFailure(Call call, IOException e) {
|
||||||
|
// log.error("UploadApiLogIntercepter error") ;
|
||||||
|
// notificationService.send("日志上传告警: 请求发送失败,检查请求发送客户端");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void onResponse(Call call, Response response) throws IOException {
|
||||||
|
// if (!response.isSuccessful()) {
|
||||||
|
// log.error("UploadApiLogIntercepter error" ) ;
|
||||||
|
// notificationService.send("日志上传告警: 请求响应异常,检查 API 源是否正常");
|
||||||
|
// } else {
|
||||||
|
// log.info("UploadApiLogIntercepter success");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package cn.teammodel.config.knife;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Profile;
|
||||||
|
|
||||||
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Knife4j 接口文档配置 <br/>
|
||||||
|
* https://doc.xiaominfo.com/knife4j/documentation/get_start.html
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableSwagger2
|
||||||
|
@Profile({"dev", "test"})
|
||||||
|
public class Knife4jConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Docket defaultApi2() {
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.apiInfo(new ApiInfoBuilder()
|
||||||
|
.title("五育评价接口文档")
|
||||||
|
.description("五育评价接口描述")
|
||||||
|
.version("1.0.1")
|
||||||
|
.build())
|
||||||
|
.select()
|
||||||
|
// 指定 Controller 扫描包路径
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("cn.teammodel.controller"))
|
||||||
|
.paths(PathSelectors.any())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package cn.teammodel.config.redis;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||||
|
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LettuceConnectionFactory dbConnectionFactory() {
|
||||||
|
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("52.130.252.100", 6379);
|
||||||
|
config.setDatabase(8); // 设置数据库编号为8
|
||||||
|
config.setPassword("habook");
|
||||||
|
return new LettuceConnectionFactory(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public StringRedisTemplate db1Template(LettuceConnectionFactory dbConnectionFactory) {
|
||||||
|
StringRedisTemplate template = new StringRedisTemplate();
|
||||||
|
template.setConnectionFactory(dbConnectionFactory);
|
||||||
|
template.setKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
package cn.teammodel.controller;
|
|
||||||
|
|
||||||
import cn.teammodel.common.R;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/")
|
|
||||||
public class HelloController {
|
|
||||||
|
|
||||||
@GetMapping("hello")
|
|
||||||
public R helo() {
|
|
||||||
return new R(200, "sucess","hello world");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,39 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.AdminAppraiseService;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.UpdateAchievementRuleDto;
|
||||||
|
import cn.teammodel.model.entity.appraise.AchievementRule;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-13 16:07
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/appraise")
|
||||||
|
@Api(tags = "管理员端-学生评价管理")
|
||||||
|
public class AdminAppraiseController {
|
||||||
|
@Resource
|
||||||
|
private AdminAppraiseService adminAppraiseService;
|
||||||
|
|
||||||
|
@PostMapping("updateAchieveRule")
|
||||||
|
@ApiOperation("更新的 rule 节点将会直接覆盖老节点")
|
||||||
|
public R<List<AchievementRule>> updateAchieveRule(@RequestBody @Valid UpdateAchievementRuleDto ruleDto) {
|
||||||
|
List<AchievementRule> res = adminAppraiseService.updateAchieveRule(ruleDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getAchieveRules/{periodId}")
|
||||||
|
@ApiOperation("获取当前学段下的成就规则")
|
||||||
|
public R<List<AchievementRule>> getAchieveRules(@PathVariable String periodId){
|
||||||
|
List<AchievementRule> res = adminAppraiseService.getAchieveRules(periodId);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.AdminIndexDutyService;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.TimeRangeDto;
|
||||||
|
import cn.teammodel.model.dto.admin.teacher.TeacherDto;
|
||||||
|
import cn.teammodel.model.dto.admin.weekduty.AdminFindDutyRecordDto;
|
||||||
|
import cn.teammodel.model.dto.weekDuty.LessonRecordDto;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyIndexData;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyNodeRankVo;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyRankPo;
|
||||||
|
import cn.teammodel.model.vo.weekDuty.DutyRecordVo;
|
||||||
|
import cn.teammodel.service.DutyService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-01-09 17:59
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/duty")
|
||||||
|
@Api(tags = "管理员端-值周巡检")
|
||||||
|
public class AdminDutyController {
|
||||||
|
@Resource
|
||||||
|
private DutyService dutyService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdminIndexDutyService adminIndexDutyService;
|
||||||
|
|
||||||
|
@PostMapping("records")
|
||||||
|
@ApiOperation("获取班级评价数据")
|
||||||
|
public R<List<DutyRecordVo>> findRecords(@Valid @RequestBody AdminFindDutyRecordDto adminFindDutyRecordDto) {
|
||||||
|
List<DutyRecordVo> res = dutyService.findAdminRecords(adminFindDutyRecordDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("index")
|
||||||
|
@ApiOperation("获取首页数据")
|
||||||
|
public R<DutyIndexData> index(@Valid @RequestBody TimeRangeDto timeRangeDto){
|
||||||
|
DutyIndexData dutyIndexData = adminIndexDutyService.getIndexData(timeRangeDto);
|
||||||
|
return R.success(dutyIndexData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("classRank")
|
||||||
|
@ApiOperation("班级评价活跃排行榜: Top10")
|
||||||
|
public R<List<DutyRankPo>> classRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<DutyRankPo> res = adminIndexDutyService.classRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("teacherRank")
|
||||||
|
@ApiOperation("老师评价活跃排行榜: Top10")
|
||||||
|
public R<List<DutyRankPo>> teacherRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<DutyRankPo> res = adminIndexDutyService.teacherRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("dutyNodeRank")
|
||||||
|
@ApiOperation("评价指标活跃排行榜: Top10")
|
||||||
|
public R<List<DutyNodeRankVo>> appraiseNodeRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<DutyNodeRankVo> res = adminIndexDutyService.appraiseNodeRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getLessonRecord")
|
||||||
|
@ApiOperation("获取课堂记录")
|
||||||
|
public R<Map<String, Object> > appraiseNodeRank(@Valid @RequestBody LessonRecordDto lessonRecordDto , HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = adminIndexDutyService.getLessonRecord(lessonRecordDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeachingQuality")
|
||||||
|
@ApiOperation("获取教学质量")
|
||||||
|
public R<List<Map<String, Object>> > getTeachingQuality(@Valid @RequestBody TeacherDto teacherDto , HttpServletRequest request) {
|
||||||
|
List<Map<String, Object>> res = adminIndexDutyService.getTeachingQuality(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.ArtService;
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtAnalysisDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtFindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.DataFileCommentDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.DataFileDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GroupDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RGroupList;
|
||||||
|
import cn.teammodel.model.vo.admin.ArtElementsVo;
|
||||||
|
import cn.teammodel.model.vo.admin.DataFileVo;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zzzzz
|
||||||
|
* @since 2024-01-09 17:59
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/art")
|
||||||
|
@Api(tags = "管理员端-艺术评测")
|
||||||
|
public class ArtController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ArtService ArtService;
|
||||||
|
|
||||||
|
@PostMapping("getArtList")
|
||||||
|
@ApiOperation("获取当前学校艺术评测列表")
|
||||||
|
public R<List<ArtElementsVo>> findRecords(@Valid @RequestBody ArtFindDto artFindDto,HttpServletRequest request) {
|
||||||
|
List<ArtElementsVo> res = ArtService.getArtList(artFindDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getGroupList")
|
||||||
|
@ApiOperation("获取当前学校指定成员名单详细信息")
|
||||||
|
public R<List<RGroupList>> findGroups(@Valid @RequestBody GroupDto groupDto, HttpServletRequest request) {
|
||||||
|
List<RGroupList> res = ArtService.getGroupList(groupDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getPdfData")
|
||||||
|
@ApiOperation("请求学生的pdf数据文件")
|
||||||
|
public R<List<DataFileVo>> getPdfData(@Valid @RequestBody DataFileDto dataFileDto, HttpServletRequest request) {
|
||||||
|
List<DataFileVo> res = ArtService.getPdfData(dataFileDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("updateComment")
|
||||||
|
@ApiOperation("更新评论")
|
||||||
|
public R<List<DataFileVo>> updateComment(@Valid @RequestBody DataFileCommentDto dataFileCommentDto, HttpServletRequest request) {
|
||||||
|
List<DataFileVo> res = ArtService.updateComment(dataFileCommentDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("artAnalysis")
|
||||||
|
@ApiOperation("艺术评测校级看板分析")
|
||||||
|
public R<Map<String,Object>> getArtAnalysis(@Valid @RequestBody ArtAnalysisDto artAnalysisDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = ArtService.getArtAnalytics(artAnalysisDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.BlobService;
|
||||||
|
import cn.teammodel.model.dto.admin.exam.BlobSasDto;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/blob")
|
||||||
|
@Api(tags = "管理员-blob相关操作")
|
||||||
|
public class BlobController {
|
||||||
|
@Resource
|
||||||
|
private BlobService blobService;
|
||||||
|
@PostMapping("getBlobSas")
|
||||||
|
@ApiOperation("获取blob 读写权限")
|
||||||
|
public R<Map<String, Object>> getBlobSas(@Valid @RequestBody BlobSasDto blobSasDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = blobService.getBlobSas(blobSasDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getSasR99")
|
||||||
|
@ApiOperation("获取某个容器的只读权限")
|
||||||
|
public R<Map<String, Object>> getSasR99(@Valid @RequestBody BlobSasDto blobSasDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = blobService.getSasR99(blobSasDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.CommonService;
|
||||||
|
import cn.teammodel.model.dto.admin.common.CommentDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GCDto;
|
||||||
|
import cn.teammodel.model.entity.common.Comment;
|
||||||
|
import cn.teammodel.model.vo.admin.GradeAndClassVo;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/common")
|
||||||
|
@Api(tags = "管理员端-公共组件")
|
||||||
|
public class CommonController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CommonService commonService ;
|
||||||
|
@PostMapping("getGradeAndClass")
|
||||||
|
@ApiOperation("获取当前学校当前学段年级班级信息")
|
||||||
|
public R<List<GradeAndClassVo>> findRecords(@Valid @RequestBody GCDto gcDto) {
|
||||||
|
List<GradeAndClassVo> res = commonService.getGradeAndClass(gcDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("save")
|
||||||
|
@ApiOperation("保存评语")
|
||||||
|
public R<Comment> saveOrUpdateComment(@Valid @RequestBody Comment comment) {
|
||||||
|
Comment res = commonService.saveOrUpdateComment(comment);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("delete")
|
||||||
|
@ApiOperation("删除评语")
|
||||||
|
public R<List<String>> deleteComment(@Valid @RequestBody CommentDto comment) {
|
||||||
|
List<String> res = commonService.deleteComment(comment);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("find")
|
||||||
|
@ApiOperation("根据ID查询评语")
|
||||||
|
public R<List<Comment>> findComment(@Valid @RequestBody Comment comment) {
|
||||||
|
List<Comment> res = commonService.getCommentById(comment);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.ExamService;
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtFindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.exam.*;
|
||||||
|
import cn.teammodel.model.vo.admin.ArtElementsVo;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/exam")
|
||||||
|
@Api(tags = "管理员端-智育分析")
|
||||||
|
public class ExamController {
|
||||||
|
@Resource
|
||||||
|
private ExamService examService;
|
||||||
|
@PostMapping("getOverView")
|
||||||
|
@ApiOperation("获取智育看板详细内容")
|
||||||
|
public R<Map<String, Object>> getOverView(@Valid @RequestBody OverViewDto overViewDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = examService.getAnalysis(overViewDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getExamList")
|
||||||
|
@ApiOperation("获取该学校该学段全年评测数据")
|
||||||
|
public R<Map<String, Object>> getExamList(@Valid @RequestBody AnalysisDto analysisDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = examService.getExamList(analysisDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getExamRecord")
|
||||||
|
@ApiOperation("获取该活动的作答记录")
|
||||||
|
public R<Map<String, Object>> getExamRecord(@Valid @RequestBody ExamRecordDto examRecordDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = examService.getExamRecord(examRecordDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getExamSummary")
|
||||||
|
@ApiOperation("获取该活动详细信息和部分分析结果")
|
||||||
|
public R<Map<String, Object>> getExamSummary(@Valid @RequestBody FindExamDto findExamDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = examService.getExamSimpleAnalysis(findExamDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("getExamByStudent")
|
||||||
|
@ApiOperation("获取单个学生的简易分析结果")
|
||||||
|
public R<Map<String, Object>> getExamByStudent(@Valid @RequestBody FindByStudentDto findByStudentDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = examService.getExamByStudent(findByStudentDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.AdminAppraiseService;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.TimeRangeDto;
|
||||||
|
import cn.teammodel.model.vo.admin.*;
|
||||||
|
import cn.teammodel.model.vo.appraise.RecordVo;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员首页
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-06 14:37
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/index")
|
||||||
|
@Api(tags = "管理员端-首页数据")
|
||||||
|
public class IndexController {
|
||||||
|
@Resource
|
||||||
|
private AdminAppraiseService adminAppraiseService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/")
|
||||||
|
@ApiOperation("获取首页数据")
|
||||||
|
public R<AppraiseIndexData> index(@Valid @RequestBody TimeRangeDto timeRangeDto){
|
||||||
|
AppraiseIndexData appraiseIndexData = adminAppraiseService.getIndexData(timeRangeDto);
|
||||||
|
return R.success(appraiseIndexData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("latestRecord")
|
||||||
|
@ApiOperation("查询时间范围最近评价(无参则当前周的所有记录)")
|
||||||
|
public R<List<RecordVo>> latestRecord(@Valid @RequestBody TimeRangeDto timeRangeDto, HttpServletRequest request) {
|
||||||
|
List<RecordVo> res = adminAppraiseService.conditionLatestRecord(timeRangeDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("classRank")
|
||||||
|
@ApiOperation("班级评价活跃排行榜: Top10")
|
||||||
|
public R<List<RankPo>> classRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<RankPo> res = adminAppraiseService.classRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("studentRank")
|
||||||
|
@ApiOperation("学生评价活跃排行榜: Top10")
|
||||||
|
public R<List<StudentRankVo>> studentRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<StudentRankVo> res = adminAppraiseService.studentRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("teacherRank")
|
||||||
|
@ApiOperation("老师评价活跃排行榜: Top10")
|
||||||
|
public R<List<RankVo>> teacherRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<RankVo> res = adminAppraiseService.teacherRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("appraiseNodeRank")
|
||||||
|
@ApiOperation("评价指标活跃排行榜: Top10")
|
||||||
|
public R<List<AppraiseNodeRankVo>> appraiseNodeRank(@Valid @RequestBody TimeRangeDto timeRangeDto) {
|
||||||
|
List<AppraiseNodeRankVo> res = adminAppraiseService.appraiseNodeRank(timeRangeDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.ExamService;
|
||||||
|
import cn.teammodel.controller.admin.service.LaborEducationService;
|
||||||
|
import cn.teammodel.model.dto.admin.exam.OverViewDto;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.FindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.LaborDto;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/labor")
|
||||||
|
@Api(tags = "管理员端-德育分析")
|
||||||
|
public class LaborEducationController {
|
||||||
|
@Resource
|
||||||
|
private LaborEducationService laborEducationService;
|
||||||
|
@PostMapping("getLaborAnalysis")
|
||||||
|
@ApiOperation("获取德育看板详细内容")
|
||||||
|
public R<Map<String, Object>> getLaborAnalysis(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = laborEducationService.getAnalysis(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getDetails")
|
||||||
|
@ApiOperation("获取指定学生评测和评价数据")
|
||||||
|
public R<Map<String, Object>> getDetails(@Valid @RequestBody FindDto findDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = laborEducationService.getDetails(findDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getStudentSemesterScores")
|
||||||
|
@ApiOperation("分学期比对分析")
|
||||||
|
public R<Map<String, Object>> getStudentSemesterScores(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = laborEducationService.getStudentSemesterScores(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("getStudentMonthlyScores")
|
||||||
|
@ApiOperation("按月比对分析")
|
||||||
|
public R<Map<String,List<Map<String, Object>>>> getStudentMonthlyScores(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String,List<Map<String, Object>>> res = laborEducationService.getStudentMonthlyScores(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getExamDetails")
|
||||||
|
@ApiOperation("获取指定考试数据")
|
||||||
|
public R<Map<String, Object>> getExamDetails(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = laborEducationService.getExamDetails(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.MoralEducationService;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.FindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.LaborDto;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/moral")
|
||||||
|
@Api(tags = "管理员端-劳育分析")
|
||||||
|
public class MoralEducationController {
|
||||||
|
@Resource
|
||||||
|
private MoralEducationService moralEducationService;
|
||||||
|
@PostMapping("getMoralAnalysis")
|
||||||
|
@ApiOperation("获取劳育看板详细内容")
|
||||||
|
public R<Map<String, Object>> getMoralAnalysis(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = moralEducationService.getAnalysis(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getDetails")
|
||||||
|
@ApiOperation("获取指定学生评测和评价数据")
|
||||||
|
public R<Map<String, Object>> getDetails(@Valid @RequestBody FindDto findDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = moralEducationService.getDetails(findDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getStudentSemesterScores")
|
||||||
|
@ApiOperation("分学期比对分析")
|
||||||
|
public R<Map<String, Object>> getStudentSemesterScores(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = moralEducationService.getStudentSemesterScores(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("getStudentMonthlyScores")
|
||||||
|
@ApiOperation("按月比对分析")
|
||||||
|
public R<Map<String,List<Map<String, Object>>>> getStudentMonthlyScores(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String,List<Map<String, Object>>> res = moralEducationService.getStudentMonthlyScores(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("getExamDetails")
|
||||||
|
@ApiOperation("获取指定考试数据")
|
||||||
|
public R<Map<String, Object>> getExamDetails(@Valid @RequestBody LaborDto laborDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = moralEducationService.getExamDetails(laborDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.test.RedisService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/test")
|
||||||
|
public class RedisController {
|
||||||
|
|
||||||
|
private final RedisService redisService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public RedisController(RedisService redisService) {
|
||||||
|
this.redisService = redisService;
|
||||||
|
}
|
||||||
|
@PostMapping("/redis")
|
||||||
|
public Map<Object, Object> getValueByKey(@RequestBody @Valid String key) {
|
||||||
|
Map<Object,Object> juri = redisService.getValueByKey(key);
|
||||||
|
return R.success(juri).getData();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package cn.teammodel.controller.admin.controller;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.controller.admin.service.TeacherService;
|
||||||
|
import cn.teammodel.model.dto.admin.teacher.TeacherDto;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/teacher")
|
||||||
|
@Api(tags = "教师相关接口内容")
|
||||||
|
public class TeacherController {
|
||||||
|
@Resource
|
||||||
|
private TeacherService teacherService;
|
||||||
|
@PostMapping("getCount")
|
||||||
|
@ApiOperation("获取教师基础数据统计内容")
|
||||||
|
public R<List<Map<String, Integer>>> getCount(@Valid @RequestBody TeacherDto teacherDto) {
|
||||||
|
List<Map<String, Integer>> res = teacherService.getTeacherList(teacherDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeacherDetail")
|
||||||
|
@ApiOperation("获取教师详细数据")
|
||||||
|
public R<Map<String, Object>> getTeacherDetail(@Valid @RequestBody TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = teacherService.getTeacherDetail(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeacherCountRecordOfWeek")
|
||||||
|
@ApiOperation("获取当前学期指定教师每周课程数")
|
||||||
|
public R<Map<Long, Integer>> getTeacherCountRecordOfWeek(@Valid @RequestBody TeacherDto teacherDto) {
|
||||||
|
Map<Long, Integer> res = teacherService.getTeacherByRecord(teacherDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeacherLearningCategoryCount")
|
||||||
|
@ApiOperation("获取指定教师教学法统计")
|
||||||
|
public R<Map<String, Object>> getTeacherLearningCategoryCount(@Valid @RequestBody TeacherDto teacherDto) {
|
||||||
|
Map<String, Object> res = teacherService.getTeacherLearningCategory(teacherDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeacherGradeCount")
|
||||||
|
@ApiOperation("获取年级人数以及分配情况")
|
||||||
|
public R<Map<String, Object>> getTeacherGradeCount(@Valid @RequestBody TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> res = teacherService.getTeacherGradeCount(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getDistributionOfTeachers")
|
||||||
|
@ApiOperation("获取教师分布情况")
|
||||||
|
public R<List<Map<String,Map<String, Long>>>> getDistributionOfTeachers(@Valid @RequestBody TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
List<Map<String,Map<String, Long>>> res = teacherService.getDistributionOfTeachers(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("getTeachingAndResearch")
|
||||||
|
@ApiOperation("获取教师教研数据")
|
||||||
|
public R<Map<String,Object>> getTeachingAndResearch(@Valid @RequestBody TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
Map<String,Object> res = teacherService.getTeachingAndResearch(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeachingOfTeacher")
|
||||||
|
@ApiOperation("获取教师教学法数据")
|
||||||
|
public R<List<LinkedHashMap<String, LinkedHashMap<String,Object>>> > getTeachingOfTeacher(@Valid @RequestBody TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
List<LinkedHashMap<String,LinkedHashMap<String,Object>>> res = teacherService.getTeachingOfTeacher(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("getTeacherOfCapabilityAssessment")
|
||||||
|
@ApiOperation("获取教师能力考核数据")
|
||||||
|
public R<Map<String,Object>> getTeacherOfCapabilityAssessment(@Valid @RequestBody TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
Map<String,Object> res = teacherService.getTeacherOfCapabilityAssessment(teacherDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("update")
|
||||||
|
@ApiOperation("更新教师信息")
|
||||||
|
public R<String> update(@Valid @RequestBody TeacherDto teacherDto) {
|
||||||
|
teacherService.update(teacherDto);
|
||||||
|
return R.success("更新成功");
|
||||||
|
}
|
||||||
|
@PostMapping("findIdentityByTmdId")
|
||||||
|
@ApiOperation("根据tmdId获取教师身份")
|
||||||
|
public R<Map<String, Object>> findIdentityByTmdId(@Valid @RequestBody TeacherDto teacherDto) {
|
||||||
|
Map<String, Object> res = teacherService.findIdentityByTmdId(teacherDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
@PostMapping("delete")
|
||||||
|
@ApiOperation("删除教师信息")
|
||||||
|
public R<String> delete(@Valid @RequestBody TeacherDto teacherDto) {
|
||||||
|
teacherService.delete(teacherDto);
|
||||||
|
return R.success("删除成功");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.TimeRangeDto;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.UpdateAchievementRuleDto;
|
||||||
|
import cn.teammodel.model.entity.appraise.AchievementRule;
|
||||||
|
import cn.teammodel.model.vo.admin.*;
|
||||||
|
import cn.teammodel.model.vo.appraise.RecordVo;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-06 14:45
|
||||||
|
*/
|
||||||
|
public interface AdminAppraiseService {
|
||||||
|
AppraiseIndexData getIndexData(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按时期分页获取最新的评价数据
|
||||||
|
*/
|
||||||
|
List<RecordVo> conditionLatestRecord(TimeRangeDto timeRangeDto, HttpServletRequest request);
|
||||||
|
|
||||||
|
List<RankPo> classRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<RankVo> teacherRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<AppraiseNodeRankVo> appraiseNodeRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<StudentRankVo> studentRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<AchievementRule> updateAchieveRule(UpdateAchievementRuleDto ruleDto);
|
||||||
|
|
||||||
|
List<AchievementRule> getAchieveRules(String periodId);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.TimeRangeDto;
|
||||||
|
import cn.teammodel.model.dto.admin.teacher.TeacherDto;
|
||||||
|
import cn.teammodel.model.dto.weekDuty.LessonRecordDto;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyIndexData;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyNodeRankVo;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyRankPo;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-02-28 15:07
|
||||||
|
*/
|
||||||
|
public interface AdminIndexDutyService {
|
||||||
|
DutyIndexData getIndexData(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<DutyRankPo> classRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<DutyRankPo> teacherRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
List<DutyNodeRankVo> appraiseNodeRank(TimeRangeDto timeRangeDto);
|
||||||
|
|
||||||
|
Map<String, Object> getLessonRecord (LessonRecordDto lessonRecordDto, HttpServletRequest request);
|
||||||
|
List<Map<String, Object>> getTeachingQuality (TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtAnalysisDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtFindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.DataFileCommentDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.DataFileDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GroupDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RGroupList;
|
||||||
|
import cn.teammodel.model.vo.admin.ArtElementsVo;
|
||||||
|
import cn.teammodel.model.vo.admin.DataFileVo;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ArtService {
|
||||||
|
List<ArtElementsVo> getArtList(ArtFindDto artFindDto, HttpServletRequest request);
|
||||||
|
List<RGroupList> getGroupList(GroupDto groupDto, HttpServletRequest request);
|
||||||
|
List<DataFileVo> getPdfData(DataFileDto dataFileDto,HttpServletRequest request);
|
||||||
|
List<DataFileVo> updateComment(DataFileCommentDto dataFileCommentDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getArtAnalytics(ArtAnalysisDto artAnalysisDto, HttpServletRequest request);
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.exam.BlobSasDto;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface BlobService {
|
||||||
|
Map<String,Object> getBlobSas(BlobSasDto blobSasDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getSasR99(BlobSasDto blobSasDto, HttpServletRequest request);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.common.CommentDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GCDto;
|
||||||
|
import cn.teammodel.model.entity.common.Comment;
|
||||||
|
import cn.teammodel.model.vo.admin.GradeAndClassVo;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
public interface CommonService {
|
||||||
|
List<GradeAndClassVo> getGradeAndClass(GCDto gcDto);
|
||||||
|
Comment saveOrUpdateComment(Comment comment);
|
||||||
|
List<String> deleteComment(CommentDto comment);
|
||||||
|
List<Comment> getCommentById(Comment comment);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.exam.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ExamService {
|
||||||
|
Map<String,Object> getAnalysis(OverViewDto overViewDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getExamList(AnalysisDto analysisDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getExamSimpleAnalysis(FindExamDto findExamDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getExamRecord(ExamRecordDto examRecordDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getExamByStudent(FindByStudentDto findByStudentDto, HttpServletRequest request);
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.exam.OverViewDto;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.FindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.LaborDto;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface LaborEducationService {
|
||||||
|
Map<String,Object> getAnalysis(LaborDto laborDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getDetails(FindDto findDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getStudentSemesterScores(LaborDto laborDto, HttpServletRequest request);
|
||||||
|
Map<String,List<Map<String, Object>>> getStudentMonthlyScores(LaborDto laborDto,HttpServletRequest request);
|
||||||
|
Map<String,Object> getExamDetails(LaborDto laborDto,HttpServletRequest request);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.labor.FindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.labor.LaborDto;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface MoralEducationService {
|
||||||
|
Map<String,Object> getAnalysis(LaborDto laborDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getDetails(FindDto findDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getStudentSemesterScores(LaborDto laborDto, HttpServletRequest request);
|
||||||
|
Map<String,List<Map<String, Object>>> getStudentMonthlyScores(LaborDto laborDto,HttpServletRequest request);
|
||||||
|
Map<String,Object> getExamDetails(LaborDto laborDto,HttpServletRequest request);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package cn.teammodel.controller.admin.service;
|
||||||
|
|
||||||
|
import cn.teammodel.model.dto.admin.teacher.GpTeacherDto;
|
||||||
|
import cn.teammodel.model.dto.admin.teacher.TeacherDto;
|
||||||
|
import cn.teammodel.model.entity.teacher.PtTeacherInfo;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface TeacherService {
|
||||||
|
List<Map<String,Integer>> getTeacherList(TeacherDto teacherDto);
|
||||||
|
Map<String,Object> getTeacherDetail(TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
Map<Long, Integer> getTeacherByRecord(TeacherDto teacherDto);
|
||||||
|
Map<String,Object> getTeacherLearningCategory(TeacherDto teacherDto);
|
||||||
|
Map<String,Object> getTeacherGradeCount(TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
List<Map<String,Map<String, Long>>> getDistributionOfTeachers(TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getTeachingAndResearch(TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
List<LinkedHashMap<String, LinkedHashMap<String,Object>>> getTeachingOfTeacher(TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
Map<String,Object> getTeacherOfCapabilityAssessment(TeacherDto teacherDto, HttpServletRequest request);
|
||||||
|
void update (TeacherDto teacherDto);
|
||||||
|
Map<String,Object> findIdentityByTmdId(TeacherDto teacherDto);
|
||||||
|
void delete(TeacherDto teacherDto);
|
||||||
|
}
|
@ -0,0 +1,472 @@
|
|||||||
|
package cn.teammodel.controller.admin.service.impl;
|
||||||
|
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.common.PK;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import cn.teammodel.controller.admin.service.AdminAppraiseService;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GroupDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RGroupList;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RMember;
|
||||||
|
import cn.teammodel.repository.*;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.TimeRangeDto;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.UpdateAchievementRuleDto;
|
||||||
|
import cn.teammodel.model.entity.User;
|
||||||
|
import cn.teammodel.model.entity.appraise.AchievementRule;
|
||||||
|
import cn.teammodel.model.entity.appraise.Appraise;
|
||||||
|
import cn.teammodel.model.entity.appraise.AppraiseTreeNode;
|
||||||
|
import cn.teammodel.model.entity.school.ClassInfo;
|
||||||
|
import cn.teammodel.model.entity.school.School;
|
||||||
|
import cn.teammodel.model.entity.school.Student;
|
||||||
|
import cn.teammodel.model.entity.school.Teacher;
|
||||||
|
import cn.teammodel.model.vo.admin.*;
|
||||||
|
import cn.teammodel.model.vo.appraise.RecordVo;
|
||||||
|
import cn.teammodel.security.utils.SecurityUtil;
|
||||||
|
import cn.teammodel.utils.GroupUtil;
|
||||||
|
import cn.teammodel.utils.RepositoryUtil;
|
||||||
|
import cn.teammodel.utils.SchoolDateUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
import com.azure.cosmos.models.CosmosPatchOperations;
|
||||||
|
import com.azure.cosmos.models.PartitionKey;
|
||||||
|
import com.azure.spring.data.cosmos.core.query.CosmosPageRequest;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.data.domain.Slice;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.time.*;
|
||||||
|
import java.time.temporal.TemporalAdjusters;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.teammodel.utils.SchoolDateUtil.calculateWeekNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-06 14:46
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class AdminAppraiseServiceImpl implements AdminAppraiseService {
|
||||||
|
@Resource
|
||||||
|
private SchoolRepository schoolRepository;
|
||||||
|
@Resource
|
||||||
|
private ClassRepository classRepository;
|
||||||
|
@Resource
|
||||||
|
private TeacherRepository teacherRepository;
|
||||||
|
@Resource
|
||||||
|
private AppraiseRepository appraiseRepository;
|
||||||
|
@Resource
|
||||||
|
private StudentRepository studentRepository;
|
||||||
|
@Resource
|
||||||
|
private AppraiseRecordRepository appraiseRecordRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Environment env; // 非静态字段
|
||||||
|
|
||||||
|
private static Environment environment; // 静态字段
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
AdminAppraiseServiceImpl.environment = env; // 在初始化时将非静态字段赋值给静态字段
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppraiseIndexData getIndexData(TimeRangeDto timeRangeDto) {
|
||||||
|
final int SLICE_SIZE = 100;
|
||||||
|
if (StringUtils.isBlank(timeRangeDto.getPeriodId())) {
|
||||||
|
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
final AppraiseIndexData appraiseIndexData = new AppraiseIndexData();
|
||||||
|
int totalCount = 0;
|
||||||
|
int criticalCount = 0;
|
||||||
|
Set<String> creatorIdSet = new HashSet<>();
|
||||||
|
Set<String> studentSet = new HashSet<>();
|
||||||
|
User loginUser = SecurityUtil.getLoginUser();
|
||||||
|
String schoolId = loginUser.getSchoolId();
|
||||||
|
|
||||||
|
// 获取学期起止时间
|
||||||
|
List<School.Semester> semesters = schoolRepository.findSemestersById(schoolId, timeRangeDto.getPeriodId());
|
||||||
|
SchoolDateUtil.semesterModel semesterModel = SchoolDateUtil.getSemesterByNow(semesters, LocalDate.now());
|
||||||
|
LocalDateTime startDatetime = null;
|
||||||
|
LocalDateTime endDatetime = null;
|
||||||
|
String academicYearId = null;
|
||||||
|
if(timeRangeDto.getStartTime() != null) {
|
||||||
|
startDatetime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeRangeDto.getStartTime()), ZoneId.systemDefault());
|
||||||
|
endDatetime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeRangeDto.getEndTime()), ZoneId.systemDefault());
|
||||||
|
academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
}else {
|
||||||
|
academicYearId = semesterModel.getAcademicYearId();
|
||||||
|
startDatetime = semesterModel.getStartDatetime();
|
||||||
|
endDatetime = semesterModel.getEndDatetime();
|
||||||
|
|
||||||
|
}
|
||||||
|
if (startDatetime == null || endDatetime == null) throw new ServiceException(ErrorCode.PARAMS_ERROR);
|
||||||
|
long totalWeek = calculateWeekNum(startDatetime, endDatetime, null);
|
||||||
|
|
||||||
|
// slice 分段读取
|
||||||
|
CosmosPageRequest pageRequest = new CosmosPageRequest(0, SLICE_SIZE, null);
|
||||||
|
Slice<RecordVo> slice;
|
||||||
|
Map<Long, Integer> countByWeek = SchoolDateUtil.createEmptyWeekMap(totalWeek);
|
||||||
|
|
||||||
|
do {
|
||||||
|
slice = appraiseRecordRepository.findAllByAcademicYearId(String.format(PK.PK_APPRAISE_RECORD, schoolId), academicYearId, pageRequest);
|
||||||
|
List<RecordVo> content = slice.getContent();
|
||||||
|
if (ObjectUtils.isEmpty(content)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分批次计算
|
||||||
|
for (RecordVo item : content) {
|
||||||
|
// 处理每周的评价数
|
||||||
|
long weekNum = calculateWeekNum(startDatetime, endDatetime, item.getCreateTime());
|
||||||
|
countByWeek.put(weekNum, countByWeek.getOrDefault(weekNum, 0) + 1);
|
||||||
|
// 处理总评价数
|
||||||
|
totalCount++;
|
||||||
|
// 处理批评数
|
||||||
|
if (!item.isPraise()) {
|
||||||
|
criticalCount++;
|
||||||
|
}
|
||||||
|
// 处理已评价老师总数
|
||||||
|
creatorIdSet.add(item.getCreatorId());
|
||||||
|
// 处理被评价的学生数
|
||||||
|
if ("student".equals(item.getTargetType())) {
|
||||||
|
studentSet.add(item.getTargetId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.hasNext()) {
|
||||||
|
pageRequest = (CosmosPageRequest) slice.nextPageable();
|
||||||
|
}
|
||||||
|
} while (slice.hasNext());
|
||||||
|
|
||||||
|
// 组装数据
|
||||||
|
appraiseIndexData.setCountByWeek(countByWeek);
|
||||||
|
appraiseIndexData.setTotalCount(totalCount);
|
||||||
|
appraiseIndexData.setCriticalCount(criticalCount);
|
||||||
|
appraiseIndexData.setPraiseCount(totalCount - criticalCount);
|
||||||
|
appraiseIndexData.setTeacherCount(creatorIdSet.size());
|
||||||
|
appraiseIndexData.setStudentCount(studentSet.size());
|
||||||
|
return appraiseIndexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RecordVo> conditionLatestRecord(TimeRangeDto timeRangeDto, HttpServletRequest request) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
String typeName = null;
|
||||||
|
String type = timeRangeDto.getType();
|
||||||
|
if(type != null && !type.isEmpty()) {
|
||||||
|
if (timeRangeDto.getType().equals("moral")) {
|
||||||
|
typeName = "德育";
|
||||||
|
}else if (timeRangeDto.getType().equals("labour")){
|
||||||
|
typeName = "劳育";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixme: 是否对时间范围做一些限制(不能确保当前周有数据)
|
||||||
|
// 无参默认当前周
|
||||||
|
if (startTime == null || endTime == null) {
|
||||||
|
// 将时间范围调整为当前周的周一到当前时间
|
||||||
|
LocalDateTime mondayOfCurWeek = LocalDateTime.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||||
|
.withHour(0)
|
||||||
|
.withMinute(0)
|
||||||
|
.withSecond(0)
|
||||||
|
.withNano(0);
|
||||||
|
startTime = mondayOfCurWeek.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli();
|
||||||
|
endTime = Instant.now().toEpochMilli();
|
||||||
|
}
|
||||||
|
List<ClassInfo> classes = classRepository.findClassBySchoolIdAndPeriodId(timeRangeDto.getPeriodId(), String.format(PK.CLASS, schoolId));
|
||||||
|
if (classes.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<String> classIds = classes.stream().map(ClassInfo::getId).collect(Collectors.toList());
|
||||||
|
List<RecordVo> res = appraiseRecordRepository.latestRecords(
|
||||||
|
String.format(PK.PK_APPRAISE_RECORD, schoolId),
|
||||||
|
academicYearId,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
typeName,
|
||||||
|
classIds
|
||||||
|
);
|
||||||
|
|
||||||
|
GroupDto groupDto = new GroupDto();
|
||||||
|
groupDto.setIds(classIds);
|
||||||
|
groupDto.setSchoolId(schoolId);
|
||||||
|
String url = environment.getProperty("ies.server-url-group");
|
||||||
|
Map<String, Object> groupId = GroupUtil.getGroupId(groupDto, new GroupUtil(environment), request, url);
|
||||||
|
List<RGroupList> rGroupList = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (key.equals("groups")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
rGroupList = JSON.parseObject(jsonGroups, new TypeReference<List<RGroupList>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (res != null) {
|
||||||
|
res = res.stream().sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime())).collect(Collectors.toList());
|
||||||
|
for (RecordVo recordVo : res) {
|
||||||
|
List<RGroupList> finalRGroupList = rGroupList;
|
||||||
|
String className = Optional.ofNullable(recordVo.getClassName())
|
||||||
|
.orElseGet(() -> finalRGroupList.stream()
|
||||||
|
.filter(group -> group.getId().equals(recordVo.getClassId()))
|
||||||
|
.map(RGroupList::getName)
|
||||||
|
.findFirst()
|
||||||
|
.orElse("未知班级"));
|
||||||
|
recordVo.setClassName(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RankPo> classRank(TimeRangeDto timeRangeDto) {
|
||||||
|
// todo 不要 page| 批评和表扬数量
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
|
||||||
|
List<RankPo> rankPoList = appraiseRecordRepository.classRank(
|
||||||
|
String.format(PK.PK_APPRAISE_RECORD, schoolId),
|
||||||
|
academicYearId,
|
||||||
|
startTime,
|
||||||
|
endTime
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(rankPoList)) return null;
|
||||||
|
Set<String> classIdSet = rankPoList.stream().map(RankPo::getId).collect(Collectors.toSet());
|
||||||
|
// 注意: 如果查询 in 的查询集在数据库中不存在,则在结果集也不会为 null.
|
||||||
|
if (ObjectUtils.isEmpty(classIdSet)) return rankPoList;
|
||||||
|
List<ClassInfo> classes = classRepository.findAllByCodeAndIdIn(String.format(PK.CLASS, schoolId), classIdSet);
|
||||||
|
Map<String, String> idNameMap = classes.stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getName));
|
||||||
|
rankPoList.forEach(rankVo -> rankVo.setName(idNameMap.get(rankVo.getId())));
|
||||||
|
return rankPoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RankVo> teacherRank(TimeRangeDto timeRangeDto) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
|
||||||
|
List<RankPo> rankPoList = appraiseRecordRepository.teacherRank(
|
||||||
|
String.format(PK.PK_APPRAISE_RECORD, schoolId),
|
||||||
|
academicYearId,
|
||||||
|
startTime,
|
||||||
|
endTime
|
||||||
|
);
|
||||||
|
// 根据 id 分组
|
||||||
|
Map<String, List<RankPo>> idRankPoMap = rankPoList.stream().collect(Collectors.groupingBy(RankPo::getId));
|
||||||
|
final List<RankVo> rankVos = new ArrayList<>();
|
||||||
|
|
||||||
|
idRankPoMap.forEach((id, list) -> {
|
||||||
|
RankVo rankVo = new RankVo();
|
||||||
|
int praiseCount = 0;
|
||||||
|
int criticalCount = 0;
|
||||||
|
rankVo.setId(id);
|
||||||
|
|
||||||
|
for (RankPo po : list) {
|
||||||
|
if (po.getIsPraise()) {
|
||||||
|
praiseCount += po.getCount();
|
||||||
|
} else {
|
||||||
|
criticalCount += po.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rankVo.setPraiseCount(praiseCount);
|
||||||
|
rankVo.setCriticalCount(criticalCount);
|
||||||
|
rankVo.setTotalCount(praiseCount + criticalCount);
|
||||||
|
rankVos.add(rankVo);
|
||||||
|
});
|
||||||
|
// 排序
|
||||||
|
List<RankVo> res = rankVos.stream()
|
||||||
|
.sorted(Comparator.comparing(RankVo::getTotalCount).reversed())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 设置 name
|
||||||
|
if (ObjectUtils.isEmpty(res)) return null;
|
||||||
|
Set<String> teacherIdSet = res.stream().map(RankVo::getId).collect(Collectors.toSet());
|
||||||
|
if (ObjectUtils.isEmpty(teacherIdSet)) return res;
|
||||||
|
List<Teacher> teachers = teacherRepository.findAllByCodeAndIdIn(PK.COMMON_BASE, teacherIdSet);
|
||||||
|
Map<String, String> idNameMap = teachers.stream().collect(Collectors.toMap(Teacher::getId, Teacher::getName));
|
||||||
|
res.forEach(rankVo -> rankVo.setName(idNameMap.get(rankVo.getId())));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AppraiseNodeRankVo> appraiseNodeRank(TimeRangeDto timeRangeDto) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
|
||||||
|
List<AppraiseNodeRankVo> rankVoList = appraiseRecordRepository.appraiseNodeRank(
|
||||||
|
String.format(PK.PK_APPRAISE_RECORD, schoolId),
|
||||||
|
academicYearId,
|
||||||
|
startTime,
|
||||||
|
endTime
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rankVoList == null) return null;
|
||||||
|
List<String> names = rankVoList.stream().map(AppraiseNodeRankVo::getName).collect(Collectors.toList());
|
||||||
|
if (ObjectUtils.isEmpty(names)) return null;
|
||||||
|
// 去重后的 nodes
|
||||||
|
List<AppraiseTreeNode> nodesByName = appraiseRecordRepository.findAppraiseRecordInNames(String.format(PK.PK_APPRAISE_RECORD, schoolId), academicYearId, names);
|
||||||
|
// 正常情况下 name 一一对应 todo: 临时解决
|
||||||
|
Map<String, AppraiseTreeNode> nameNodeMap = nodesByName.stream()
|
||||||
|
.collect(Collectors.toMap(AppraiseTreeNode::getName, item -> item, (existing, replacement) -> {
|
||||||
|
if (replacement.getPath() != null) {
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
return existing;
|
||||||
|
}));
|
||||||
|
|
||||||
|
rankVoList = rankVoList.stream()
|
||||||
|
.sorted(Comparator.comparing(RankPo::getCount).reversed())
|
||||||
|
// 流中对元素操作但不改变流
|
||||||
|
.peek(s -> {
|
||||||
|
AppraiseTreeNode node = nameNodeMap.get(s.getName());
|
||||||
|
if (node != null) {
|
||||||
|
s.setPath(node.getPath());
|
||||||
|
s.setIsPraise(node.isPraise());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return rankVoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StudentRankVo> studentRank(TimeRangeDto timeRangeDto) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
|
||||||
|
List<RankPo> rankPoList = appraiseRecordRepository.studentRank(
|
||||||
|
String.format(PK.PK_APPRAISE_RECORD, schoolId),
|
||||||
|
academicYearId,
|
||||||
|
startTime,
|
||||||
|
endTime
|
||||||
|
);
|
||||||
|
// 根据 id 分组
|
||||||
|
Map<String, List<RankPo>> idRankPoMap = rankPoList.stream().collect(Collectors.groupingBy(RankPo::getId));
|
||||||
|
final List<StudentRankVo> rankVos = new ArrayList<>();
|
||||||
|
|
||||||
|
idRankPoMap.forEach((id, list) -> {
|
||||||
|
StudentRankVo rankVo = new StudentRankVo();
|
||||||
|
int praiseCount = 0;
|
||||||
|
int criticalCount = 0;
|
||||||
|
rankVo.setId(id);
|
||||||
|
|
||||||
|
for (RankPo po : list) {
|
||||||
|
if (po.getIsPraise()) {
|
||||||
|
praiseCount += po.getCount();
|
||||||
|
} else {
|
||||||
|
criticalCount += po.getCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rankVo.setPraiseCount(praiseCount);
|
||||||
|
rankVo.setCriticalCount(criticalCount);
|
||||||
|
rankVo.setTotalCount(praiseCount + criticalCount);
|
||||||
|
rankVos.add(rankVo);
|
||||||
|
});
|
||||||
|
// 排序
|
||||||
|
List<StudentRankVo> res = rankVos.stream()
|
||||||
|
.sorted(Comparator.comparing(StudentRankVo::getTotalCount).reversed())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
// 设置 student name
|
||||||
|
if (ObjectUtils.isEmpty(res)) return null;
|
||||||
|
Set<String> studentIdSet = res.stream().map(StudentRankVo::getId).collect(Collectors.toSet());
|
||||||
|
if (ObjectUtils.isEmpty(studentIdSet)) return res;
|
||||||
|
|
||||||
|
List<Student> students = studentRepository.findAllByCodeAndIdIn(String.format(PK.STUDENT, schoolId), studentIdSet);
|
||||||
|
// 利用数组作为三元组,提取 Student 中的 name 和 classId, picture
|
||||||
|
Map<String, String[]> idNameMap = students.stream().collect(Collectors.toMap(Student::getId, item -> {
|
||||||
|
String[] studentInfo = new String[3];
|
||||||
|
studentInfo[0] = item.getName();
|
||||||
|
studentInfo[1] = item.getClassId();
|
||||||
|
studentInfo[2] = item.getPicture();
|
||||||
|
return studentInfo;
|
||||||
|
}));
|
||||||
|
res.forEach(rankVo -> {
|
||||||
|
rankVo.setName(idNameMap.get(rankVo.getId())[0]);
|
||||||
|
rankVo.setClassName(idNameMap.get(rankVo.getId())[1]);
|
||||||
|
rankVo.setPicture(idNameMap.get(rankVo.getId())[2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设置 class name
|
||||||
|
Set<String> classIds = students.stream().map(Student::getClassId).collect(Collectors.toSet());
|
||||||
|
List<ClassInfo> classes = classRepository.findAllByCodeAndIdIn(String.format(PK.CLASS, schoolId), classIds);
|
||||||
|
Map<String, String> idClassNameMap = classes.stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getName));
|
||||||
|
res.forEach(rankVo -> rankVo.setClassName(idClassNameMap.getOrDefault(rankVo.getClassName(), null)));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AchievementRule> updateAchieveRule(UpdateAchievementRuleDto ruleDto) {
|
||||||
|
String periodId = ruleDto.getPeriodId();
|
||||||
|
UpdateAchievementRuleDto.UpdateRule updateRule = ruleDto.getUpdateRule();
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(updateRule) || StringUtils.isBlank(updateRule.getId()) || ObjectUtils.isEmpty(updateRule.getName())) {
|
||||||
|
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "rule id/name 不能为空");
|
||||||
|
}
|
||||||
|
if (updateRule.getLevelCount() == null || updateRule.getLevelCount() <= 0 || updateRule.getPromotionLevel() == null || updateRule.getPromotionLevel() <= 0) {
|
||||||
|
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "规则不能为空或小于等于0");
|
||||||
|
}
|
||||||
|
User user = SecurityUtil.getLoginUser();
|
||||||
|
String schoolId = user.getSchoolId();
|
||||||
|
|
||||||
|
Appraise appraise = RepositoryUtil.findOne(appraiseRepository.findRulesById(schoolId, periodId), "参数错误,找不到该学段下的评价规则");
|
||||||
|
List<AchievementRule> rules = appraise.getAchievementRules();
|
||||||
|
if (ObjectUtils.isEmpty(rules)) {
|
||||||
|
throw new ServiceException(ErrorCode.OPERATION_ERROR.getCode(), "该学段暂无没有成就规则");
|
||||||
|
}
|
||||||
|
// sort rules by level
|
||||||
|
rules = rules.stream().sorted(Comparator.comparing(AchievementRule::getLevel)).collect(Collectors.toList());
|
||||||
|
boolean flag = false;
|
||||||
|
int lastPromotionCount = 0;
|
||||||
|
for (AchievementRule rule : rules) {
|
||||||
|
if (updateRule.getId().equals(rule.getId())) {
|
||||||
|
BeanUtils.copyProperties(updateRule, rule);
|
||||||
|
lastPromotionCount = rule.getLevelCount() * rule.getPromotionLevel();
|
||||||
|
rule.setPromotionCount(lastPromotionCount);
|
||||||
|
flag = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 处理后面的节点,将 promotionCount 依次修改
|
||||||
|
if (flag) {
|
||||||
|
lastPromotionCount = lastPromotionCount + rule.getLevelCount() * rule.getPromotionLevel();
|
||||||
|
rule.setPromotionCount(lastPromotionCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CosmosPatchOperations operations = CosmosPatchOperations.create().replace("/achievementRules", rules);
|
||||||
|
Appraise saved = appraiseRepository.save(appraise.getId(), new PartitionKey(PK.PK_APPRAISE), Appraise.class, operations);
|
||||||
|
return saved.getAchievementRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AchievementRule> getAchieveRules(String periodId) {
|
||||||
|
User user = SecurityUtil.getLoginUser();
|
||||||
|
String schoolId = user.getSchoolId();
|
||||||
|
|
||||||
|
Appraise appraise = RepositoryUtil.findOne(appraiseRepository.findRulesById(schoolId, periodId), "还未创建该学段下的评价规则");
|
||||||
|
List<AchievementRule> rules = appraise.getAchievementRules();
|
||||||
|
if (ObjectUtils.isEmpty(rules)) {
|
||||||
|
rules = Collections.emptyList();
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,387 @@
|
|||||||
|
package cn.teammodel.controller.admin.service.impl;
|
||||||
|
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.common.PK;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import cn.teammodel.controller.admin.service.AdminIndexDutyService;
|
||||||
|
import cn.teammodel.model.dto.admin.appraise.TimeRangeDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GroupDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RGroupList;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RMember;
|
||||||
|
import cn.teammodel.model.dto.admin.teacher.TeacherDto;
|
||||||
|
import cn.teammodel.model.dto.weekDuty.LessonRecordDto;
|
||||||
|
import cn.teammodel.model.entity.User;
|
||||||
|
import cn.teammodel.model.entity.school.ClassInfo;
|
||||||
|
import cn.teammodel.model.entity.school.LessonRecord;
|
||||||
|
import cn.teammodel.model.entity.school.School;
|
||||||
|
import cn.teammodel.model.entity.school.Teacher;
|
||||||
|
import cn.teammodel.model.entity.weekDuty.WeekDuty;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyIndexData;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyIndexPo;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyNodeRankVo;
|
||||||
|
import cn.teammodel.model.vo.admin.DutyRankPo;
|
||||||
|
import cn.teammodel.repository.*;
|
||||||
|
import cn.teammodel.security.utils.SecurityUtil;
|
||||||
|
import cn.teammodel.test.LessonRecordQueryService;
|
||||||
|
import cn.teammodel.utils.GroupUtil;
|
||||||
|
import cn.teammodel.utils.SchoolDateUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
import com.azure.spring.data.cosmos.core.query.CosmosPageRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.data.domain.Slice;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.teammodel.utils.SchoolDateUtil.calculateWeekNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-02-28 15:07
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class AdminIndexDutyServiceImpl implements AdminIndexDutyService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SchoolRepository schoolRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TeacherRepository teacherRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ClassRepository classRepository;
|
||||||
|
@Resource
|
||||||
|
private DutyRecordRepository dutyRecordRepository;
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
@Resource
|
||||||
|
private LessonRecordRepository lessonRecordRepository;
|
||||||
|
@Resource
|
||||||
|
private StudentRepository studentRepository;
|
||||||
|
|
||||||
|
/* @Autowired
|
||||||
|
public AdminIndexDutyServiceImpl(Environment env) {
|
||||||
|
this.env = env;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DutyIndexData getIndexData(TimeRangeDto timeRangeDto) {
|
||||||
|
User loginUser = SecurityUtil.getLoginUser();
|
||||||
|
String schoolId = loginUser.getSchoolId();
|
||||||
|
|
||||||
|
final int SLICE_SIZE = 100;
|
||||||
|
if (StringUtils.isBlank(timeRangeDto.getPeriodId())) {
|
||||||
|
throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "不能为空");
|
||||||
|
}
|
||||||
|
final DutyIndexData DutyIndexData = new DutyIndexData();
|
||||||
|
int totalCount = 0;
|
||||||
|
int negetiveCount = 0;
|
||||||
|
Set<String> creatorIdSet = new HashSet<>();
|
||||||
|
// todo
|
||||||
|
Set<String> classIdSet = new HashSet<>();
|
||||||
|
|
||||||
|
// 获取学期起止时间
|
||||||
|
List<School.Semester> semesters = schoolRepository.findSemestersById(schoolId, timeRangeDto.getPeriodId());
|
||||||
|
SchoolDateUtil.semesterModel semesterModel = SchoolDateUtil.getSemesterByNow(semesters, LocalDate.now());
|
||||||
|
LocalDateTime startDatetime;
|
||||||
|
LocalDateTime endDatetime;
|
||||||
|
String academicYearId;
|
||||||
|
if(timeRangeDto.getStartTime() != null) {
|
||||||
|
startDatetime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeRangeDto.getStartTime()), ZoneId.systemDefault());
|
||||||
|
endDatetime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeRangeDto.getEndTime()), ZoneId.systemDefault());
|
||||||
|
academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
}else {
|
||||||
|
academicYearId = semesterModel.getAcademicYearId();
|
||||||
|
startDatetime = semesterModel.getStartDatetime();
|
||||||
|
endDatetime = semesterModel.getEndDatetime();
|
||||||
|
|
||||||
|
}
|
||||||
|
if (startDatetime == null || endDatetime == null) throw new ServiceException(ErrorCode.PARAMS_ERROR);
|
||||||
|
long totalWeek = calculateWeekNum(startDatetime, endDatetime, null);
|
||||||
|
|
||||||
|
// slice 分段读取
|
||||||
|
CosmosPageRequest pageRequest = new CosmosPageRequest(0, SLICE_SIZE, null);
|
||||||
|
Slice<DutyIndexPo> slice;
|
||||||
|
Map<Long, Integer> countByWeek = SchoolDateUtil.createEmptyWeekMap(totalWeek);
|
||||||
|
|
||||||
|
do {
|
||||||
|
slice = dutyRecordRepository.findAllByAcademicYearId(String.format(PK.WEEK_DUTY_RECORD, schoolId), academicYearId, pageRequest);
|
||||||
|
List<DutyIndexPo> content = slice.getContent();
|
||||||
|
if (ObjectUtils.isEmpty(content)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分批次计算
|
||||||
|
for (DutyIndexPo item : content) {
|
||||||
|
// 处理每周的评价数
|
||||||
|
long weekNum = calculateWeekNum(startDatetime, endDatetime, item.getCreateTime());
|
||||||
|
countByWeek.put(weekNum, countByWeek.getOrDefault(weekNum, 0) + 1);
|
||||||
|
// 处理总评价数
|
||||||
|
totalCount++;
|
||||||
|
// 处理批评数
|
||||||
|
if (item.getDutyTreeNodeScore() < 0) {
|
||||||
|
negetiveCount++;
|
||||||
|
}
|
||||||
|
// 处理已评价老师总数
|
||||||
|
creatorIdSet.add(item.getCreatorId());
|
||||||
|
// 处理被评价的学生数
|
||||||
|
classIdSet.add(item.getClassId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slice.hasNext()) {
|
||||||
|
pageRequest = (CosmosPageRequest) slice.nextPageable();
|
||||||
|
}
|
||||||
|
} while (slice.hasNext());
|
||||||
|
|
||||||
|
// 组装数据
|
||||||
|
DutyIndexData.setCountByWeek(countByWeek);
|
||||||
|
DutyIndexData.setTotalCount(totalCount);
|
||||||
|
DutyIndexData.setClassCount(classIdSet.size());
|
||||||
|
DutyIndexData.setPositiveCount(totalCount - negetiveCount);
|
||||||
|
DutyIndexData.setTeacherCount(creatorIdSet.size());
|
||||||
|
return DutyIndexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DutyRankPo> classRank(TimeRangeDto timeRangeDto) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
List<DutyRankPo> res = dutyRecordRepository.classRank(String.format(PK.WEEK_DUTY_RECORD, schoolId), academicYearId, startTime, endTime);
|
||||||
|
if (ObjectUtils.isEmpty(res)) return null;
|
||||||
|
List<String> classIds = res.stream().map(DutyRankPo::getId).collect(Collectors.toList());
|
||||||
|
if (ObjectUtils.isEmpty(classIds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<ClassInfo> classes = classRepository.findAllByCodeAndIdIn(String.format(PK.CLASS, schoolId), classIds);
|
||||||
|
Map<String, String> idNameMap = classes.stream().collect(Collectors.toMap(ClassInfo::getId, ClassInfo::getName));
|
||||||
|
// reversed sort by score
|
||||||
|
res = res.stream().peek(s -> s.setName(idNameMap.get(s.getId()))).sorted((a, b) -> b.getScore() - a.getScore()).collect(Collectors.toList());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DutyRankPo> teacherRank(TimeRangeDto timeRangeDto) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
List<DutyRankPo> res = dutyRecordRepository.teacherRank(String.format(PK.WEEK_DUTY_RECORD, schoolId), academicYearId, startTime, endTime);
|
||||||
|
// set teacher name
|
||||||
|
if (ObjectUtils.isEmpty(res)) return null;
|
||||||
|
Set<String> teacherIdSet = res.stream().map(DutyRankPo::getId).collect(Collectors.toSet());
|
||||||
|
if (ObjectUtils.isEmpty(teacherIdSet)) return res;
|
||||||
|
List<Teacher> teachers = teacherRepository.findAllByCodeAndIdIn(PK.COMMON_BASE, teacherIdSet);
|
||||||
|
Map<String, String> idNameMap = teachers.stream().collect(Collectors.toMap(Teacher::getId, Teacher::getName));
|
||||||
|
res = res.stream().peek(s -> s.setName(idNameMap.get(s.getId()))).sorted((a, b) -> b.getScore() - a.getScore()).collect(Collectors.toList());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DutyNodeRankVo> appraiseNodeRank(TimeRangeDto timeRangeDto) {
|
||||||
|
Long startTime = timeRangeDto.getStartTime();
|
||||||
|
Long endTime = timeRangeDto.getEndTime();
|
||||||
|
String academicYearId = timeRangeDto.getAcademicYearId();
|
||||||
|
String schoolId = SecurityUtil.getLoginUser().getSchoolId();
|
||||||
|
|
||||||
|
List<DutyNodeRankVo> res = dutyRecordRepository.dutyNodeRank(String.format(PK.WEEK_DUTY_RECORD, schoolId), academicYearId, startTime, endTime);
|
||||||
|
if (ObjectUtils.isEmpty(res)) return null;
|
||||||
|
List<String> names = res.stream().map(DutyNodeRankVo::getName).collect(Collectors.toList());
|
||||||
|
if (ObjectUtils.isEmpty(names)) return null;
|
||||||
|
// 去重后的 nodes
|
||||||
|
List<WeekDuty.DutyTreeNode> nodesByName = dutyRecordRepository.findDutyRecordInNames(String.format(PK.WEEK_DUTY_RECORD, schoolId), academicYearId, names);
|
||||||
|
// 正常情况下 name 一一对应 // TODO: 2024/2/29
|
||||||
|
Map<String, WeekDuty.DutyTreeNode> nameNodeMap = nodesByName.stream()
|
||||||
|
.collect(Collectors.toMap(WeekDuty.DutyTreeNode::getName, item -> item, (existing, replacement) -> {
|
||||||
|
if (replacement.getPath() != null) {
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
return existing;
|
||||||
|
}));
|
||||||
|
|
||||||
|
res = res.stream()
|
||||||
|
.sorted(Comparator.comparing(DutyNodeRankVo::getCount).reversed())
|
||||||
|
// 流中对元素操作但不改变流
|
||||||
|
.peek(s -> {
|
||||||
|
WeekDuty.DutyTreeNode node = nameNodeMap.get(s.getName());
|
||||||
|
if (node != null) {
|
||||||
|
s.setPath(node.getPath());
|
||||||
|
s.setScore(node.getScore());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return res;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getLessonRecord(LessonRecordDto lessonRecordDto, HttpServletRequest request) {
|
||||||
|
|
||||||
|
Map<String, Object> mapper;
|
||||||
|
String url = env.getProperty("ies.server-url");
|
||||||
|
// 修复:使用 setOk 方法来设置 ok 属性
|
||||||
|
//lessonRecordDto.setOk(true);
|
||||||
|
/* if(lessonRecordDto.isClassMeeting()) {
|
||||||
|
List<School.Subject> subjects = schoolRepository.findSubjectById(lessonRecordDto.getSchool(), lessonRecordDto.getPeriodId());
|
||||||
|
List<String> subjectIds = subjects.stream().filter(subject -> "班会课".equals(subject.getName()))
|
||||||
|
.map(School.Subject::getId).collect(Collectors.toList());
|
||||||
|
lessonRecordDto.setSubjectId(subjectIds);
|
||||||
|
|
||||||
|
if(subjectIds.isEmpty()) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
mapper = GroupUtil.getGroupId(lessonRecordDto,new GroupUtil(env), request,url);
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getTeachingQuality(TeacherDto teacherDto, HttpServletRequest request) {
|
||||||
|
List<LessonRecord> records;
|
||||||
|
LessonRecordQueryService queryService = new LessonRecordQueryService(lessonRecordRepository);
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
|
//Map<String, Object> mapAll = new HashMap<>();
|
||||||
|
try {
|
||||||
|
String lessonRecordKey = String.format(PK.PK_LESSON_RECORD, teacherDto.getCode());
|
||||||
|
Long startTime = teacherDto.getStartTime();
|
||||||
|
Long endTime = teacherDto.getEndTime();
|
||||||
|
String subjectId = teacherDto.getSubjectId();
|
||||||
|
String tmdId = teacherDto.getTmdId();
|
||||||
|
String grade = teacherDto.getGrade();
|
||||||
|
String periodId = teacherDto.getPeriodId();
|
||||||
|
|
||||||
|
records = queryService.queryLessonsInParallel(
|
||||||
|
lessonRecordKey, startTime, endTime, subjectId, tmdId, grade, periodId
|
||||||
|
);
|
||||||
|
|
||||||
|
Set<String> classIds = records.stream().filter(lessonRecord -> lessonRecord.getTmdid().equalsIgnoreCase(teacherDto.getTmdId()))
|
||||||
|
.flatMap(record -> record.getGroupIds().stream())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
|
GroupDto groupDto = new GroupDto();
|
||||||
|
groupDto.setIds(new ArrayList<>(classIds));
|
||||||
|
groupDto.setSchoolId(teacherDto.getCode());
|
||||||
|
String url = env.getProperty("ies.server-url-group");
|
||||||
|
//List<ClassInfo> classes = classRepository.findAllByCodeAndIdIn("Class-"+artFindDto.getCode(),classIds);
|
||||||
|
Map<String, Object> groupId = GroupUtil.getGroupId(groupDto,new GroupUtil(env), request,url);
|
||||||
|
List<RGroupList> rGroupList = new ArrayList<>();
|
||||||
|
List<RMember> rMembers = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (key.equals("groups")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
rGroupList = JSON.parseObject(jsonGroups, new TypeReference<List<RGroupList>>() {});
|
||||||
|
}
|
||||||
|
if (key.equals("members")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
rMembers = JSON.parseObject(jsonGroups, new TypeReference<List<RMember>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(String classId : classIds) {
|
||||||
|
Map<String, Object> mapper = new HashMap<>();
|
||||||
|
|
||||||
|
// 班级内学生总数
|
||||||
|
//int stuInClassCount = studentRepository.countByClassIdAndCode(classId, String.format(PK.STUDENT, teacherDto.getCode()));
|
||||||
|
int stuInClassCount = 0;
|
||||||
|
String className = "";
|
||||||
|
for (RGroupList rGroup : rGroupList) {
|
||||||
|
if (rGroup.getId().equals(classId)) {
|
||||||
|
List<RMember> members = rGroup.getMembers();
|
||||||
|
stuInClassCount = members.size();
|
||||||
|
className = rGroup.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapper.put("stuInClassCount", stuInClassCount);
|
||||||
|
mapper.put("className", className);
|
||||||
|
// 计算本学期互动总数
|
||||||
|
int totalClientInteractionCount = records.stream().filter(lessonRecord ->
|
||||||
|
lessonRecord.getGroupIds().contains(classId))
|
||||||
|
.mapToInt(LessonRecord::getClientInteractionCount)
|
||||||
|
.sum();
|
||||||
|
mapper.put("totalClientInteractionCount", totalClientInteractionCount);
|
||||||
|
int countRecord = (int) records.stream().filter(lessonRecord ->
|
||||||
|
lessonRecord.getGroupIds().contains(classId)).count();
|
||||||
|
int engagementIndexAvergeSum = records.stream().filter(lessonRecord ->
|
||||||
|
lessonRecord.getGroupIds().contains(classId))
|
||||||
|
.mapToInt(LessonRecord::getEngagementIndexAverge)
|
||||||
|
.sum();
|
||||||
|
if (countRecord == 0) {
|
||||||
|
mapper.put("engagementIndexAverge", 0);
|
||||||
|
continue;
|
||||||
|
}else if (engagementIndexAvergeSum == 0) {
|
||||||
|
mapper.put("engagementIndexAverge", 0);
|
||||||
|
}else {
|
||||||
|
mapper.put("engagementIndexAverge", engagementIndexAvergeSum / countRecord);
|
||||||
|
}
|
||||||
|
// 获取当前月和上个月的时间范围
|
||||||
|
LocalDateTime startOfCurrentMonth = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
|
||||||
|
LocalDateTime startOfLastMonth = startOfCurrentMonth.minusMonths(1);
|
||||||
|
LocalDateTime endOfLastMonth = startOfCurrentMonth.minusSeconds(1);
|
||||||
|
long st = startOfCurrentMonth.atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
|
||||||
|
long et = startOfLastMonth.atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
|
||||||
|
long endMath = endOfLastMonth.atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
|
||||||
|
|
||||||
|
// 过滤出当前月和上个月的记录
|
||||||
|
List<LessonRecord> currentMonthRecords = records.stream()
|
||||||
|
.filter(record -> record.getStartTime() > st && record.getGroupIds().contains(classId))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<LessonRecord> lastMonthRecords = records.stream()
|
||||||
|
.filter(record -> record.getStartTime() > et && record.getStartTime() < endMath && record.getGroupIds().contains(classId))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 计算当前月和上个月的clientInteractionCount总数
|
||||||
|
int currentMonthTotal = currentMonthRecords.stream()
|
||||||
|
.mapToInt(LessonRecord::getClientInteractionCount)
|
||||||
|
.sum();
|
||||||
|
mapper.put("currentMonthTotal", currentMonthTotal);
|
||||||
|
int lastMonthTotal = lastMonthRecords.stream()
|
||||||
|
.mapToInt(LessonRecord::getClientInteractionCount)
|
||||||
|
.sum();
|
||||||
|
mapper.put("lastMonthTotal", lastMonthTotal);
|
||||||
|
// 计算百分比变化
|
||||||
|
double percentageChange = 0;
|
||||||
|
if (lastMonthTotal != 0) {
|
||||||
|
percentageChange = ((double) (currentMonthTotal - lastMonthTotal) / lastMonthTotal) * 100;
|
||||||
|
} else {
|
||||||
|
if (currentMonthTotal > 0) {
|
||||||
|
percentageChange = 100;
|
||||||
|
} else {
|
||||||
|
percentageChange = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
String formattedPercentageChange = String.format("%.2f", percentageChange);
|
||||||
|
mapper.put("percentageChange", formattedPercentageChange);
|
||||||
|
mapper.put("classId", classId);
|
||||||
|
list.add(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println("当前月上浮:" + percentageChange);
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据查询异常");
|
||||||
|
} finally {
|
||||||
|
queryService.shutdown();
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
package cn.teammodel.controller.admin.service.impl;
|
||||||
|
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import cn.teammodel.controller.admin.service.ArtService;
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtAnalysisDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.ArtFindDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.DataFileCommentDto;
|
||||||
|
import cn.teammodel.model.dto.admin.art.DataFileDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GroupDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RGroupList;
|
||||||
|
import cn.teammodel.model.dto.admin.common.RMember;
|
||||||
|
import cn.teammodel.model.vo.admin.ArtElementsVo;
|
||||||
|
import cn.teammodel.model.vo.admin.DataFileVo;
|
||||||
|
import cn.teammodel.repository.ArtRepository;
|
||||||
|
import cn.teammodel.utils.GroupUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
@Service
|
||||||
|
public class ArtServiceImpl implements ArtService {
|
||||||
|
@Resource
|
||||||
|
private ArtRepository artRepository;
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
@Override
|
||||||
|
public List<ArtElementsVo> getArtList(ArtFindDto artFindDto, HttpServletRequest request) {
|
||||||
|
List<ArtElementsVo> artElementsVos = artRepository.findPeriodById(artFindDto.getPeriodId(),"Art-"+ artFindDto.getCode(), artFindDto.getStartTime(), artFindDto.getEndTime());
|
||||||
|
List<String> classIds = artElementsVos.stream()
|
||||||
|
.map(ArtElementsVo::getClasses) // 正确的方法引用
|
||||||
|
.flatMap(List::stream) // 将内部列表扁平化
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
GroupDto groupDto = new GroupDto();
|
||||||
|
groupDto.setIds(classIds);
|
||||||
|
groupDto.setSchoolId(artFindDto.getCode());
|
||||||
|
String url = env.getProperty("ies.server-url-group");
|
||||||
|
//List<ClassInfo> classes = classRepository.findAllByCodeAndIdIn("Class-"+artFindDto.getCode(),classIds);
|
||||||
|
Map<String, Object> groupId = GroupUtil.getGroupId(groupDto,new GroupUtil(env), request,url);
|
||||||
|
List<RGroupList> rGroupList = new ArrayList<>();
|
||||||
|
List<RMember> rMembers = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (key.equals("groups")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
rGroupList = JSON.parseObject(jsonGroups, new TypeReference<List<RGroupList>>() {});
|
||||||
|
}
|
||||||
|
if (key.equals("members")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
rMembers = JSON.parseObject(jsonGroups, new TypeReference<List<RMember>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (ArtElementsVo artElementsVo : artElementsVos) {
|
||||||
|
List<String> classes1 = artElementsVo.getClasses();
|
||||||
|
int stuInClassCount = 0;
|
||||||
|
for(String classId : classes1) {
|
||||||
|
stuInClassCount += (int) rMembers.stream().filter(rMember -> rMember.getClassId().equals(classId)).count();
|
||||||
|
//stuInClassCount += studentRepository.countByClassIdAndCode(classId, String.format(PK.STUDENT, artFindDto.getCode()));
|
||||||
|
ArtElementsVo.ClassInfos classInfos = new ArtElementsVo.ClassInfos();
|
||||||
|
rGroupList.stream().filter(rGroupList1 -> rGroupList1.getId().equals(classId)).findFirst().ifPresent(rGroupList1 -> {
|
||||||
|
classInfos.setId(rGroupList1.getId());
|
||||||
|
classInfos.setName(rGroupList1.getName());
|
||||||
|
});
|
||||||
|
artElementsVo.addClassesInfos(classInfos);
|
||||||
|
}
|
||||||
|
artElementsVo.setCount(stuInClassCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
}
|
||||||
|
return artElementsVos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RGroupList> getGroupList(GroupDto groupDto, HttpServletRequest request) {
|
||||||
|
List<RGroupList> rGroupList = new ArrayList<>();
|
||||||
|
String url = env.getProperty("ies.server-url-group");
|
||||||
|
try {
|
||||||
|
Map<String, Object> groupId = GroupUtil.getGroupId(groupDto,new GroupUtil(env), request,url);
|
||||||
|
//List<RMember> rMembers = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (key.equals("groups")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
rGroupList = JSON.parseObject(jsonGroups, new TypeReference<List<RGroupList>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return rGroupList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DataFileVo> getPdfData(DataFileDto dataFileDto,HttpServletRequest request) {
|
||||||
|
List<DataFileVo> dataFile = new ArrayList<>();
|
||||||
|
String url = env.getProperty("ies.server-url-pdf-data");
|
||||||
|
try {
|
||||||
|
Map<String, Object> groupId = GroupUtil.getGroupId(dataFileDto,new GroupUtil(env), request,url);
|
||||||
|
//List<RMember> rMembers = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (key.equals("dataFiles")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
dataFile = JSON.parseObject(jsonGroups, new TypeReference<List<DataFileVo>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return dataFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DataFileVo> updateComment(DataFileCommentDto dataFileCommentDto, HttpServletRequest request) {
|
||||||
|
List<DataFileVo> dataFile = new ArrayList<>();
|
||||||
|
String url = env.getProperty("ies.server-url-update-custom-comment");
|
||||||
|
try {
|
||||||
|
Map<String, Object> groupId = GroupUtil.getGroupId(dataFileCommentDto,new GroupUtil(env), request,url);
|
||||||
|
//List<RMember> rMembers = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : groupId.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (key.equals("dataFile")) {
|
||||||
|
String jsonGroups = JSON.toJSONString(value);
|
||||||
|
dataFile = JSON.parseObject(jsonGroups, new TypeReference<List<DataFileVo>>() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return dataFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getArtAnalytics(ArtAnalysisDto artAnalysisDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> analysis;
|
||||||
|
String url = env.getProperty("ies.server-url-art-analysis");
|
||||||
|
try {
|
||||||
|
analysis = GroupUtil.getGroupId(artAnalysisDto,new GroupUtil(env), request,url);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return analysis;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package cn.teammodel.controller.admin.service.impl;
|
||||||
|
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import cn.teammodel.controller.admin.service.BlobService;
|
||||||
|
import cn.teammodel.model.dto.admin.exam.BlobSasDto;
|
||||||
|
import cn.teammodel.utils.GroupUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BlobServiceImpl implements BlobService {
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getBlobSas(BlobSasDto blobSasDto, HttpServletRequest request) {
|
||||||
|
|
||||||
|
Map<String, Object> sas;
|
||||||
|
String url = env.getProperty("ies.server-url-blob-sas-rcwld");
|
||||||
|
|
||||||
|
try {
|
||||||
|
sas = GroupUtil.getGroupId(blobSasDto,new GroupUtil(env), request,url);
|
||||||
|
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
}
|
||||||
|
return sas;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getSasR99(BlobSasDto blobSasDto, HttpServletRequest request) {
|
||||||
|
|
||||||
|
Map<String, Object> sas;
|
||||||
|
String url = env.getProperty("ies.server-url-blob-sas-r-99");
|
||||||
|
|
||||||
|
try {
|
||||||
|
sas = GroupUtil.getGroupId(blobSasDto,new GroupUtil(env), request,url);
|
||||||
|
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
}
|
||||||
|
return sas;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,164 @@
|
|||||||
|
package cn.teammodel.controller.admin.service.impl;
|
||||||
|
|
||||||
|
import cn.teammodel.common.PK;
|
||||||
|
import cn.teammodel.controller.admin.service.CommonService;
|
||||||
|
import cn.teammodel.model.dto.admin.common.CommentDto;
|
||||||
|
import cn.teammodel.model.dto.admin.common.GCDto;
|
||||||
|
import cn.teammodel.model.entity.common.Comment;
|
||||||
|
import cn.teammodel.model.entity.school.ClassInfo;
|
||||||
|
import cn.teammodel.model.entity.school.School;
|
||||||
|
import cn.teammodel.model.vo.admin.GradeAndClassVo;
|
||||||
|
import cn.teammodel.repository.ClassRepository;
|
||||||
|
import cn.teammodel.repository.CommentRepository;
|
||||||
|
import cn.teammodel.repository.SchoolRepository;
|
||||||
|
import cn.teammodel.utils.MonthToNumberConverter;
|
||||||
|
import com.azure.cosmos.models.PartitionKey;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.Month;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.time.LocalDate.now;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CommonServiceImpl implements CommonService {
|
||||||
|
@Resource
|
||||||
|
private SchoolRepository schoolRepository;
|
||||||
|
@Resource
|
||||||
|
private ClassRepository classRepository;
|
||||||
|
@Resource
|
||||||
|
private CommentRepository commentRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GradeAndClassVo> getGradeAndClass(GCDto gcDto) {
|
||||||
|
List<GradeAndClassVo> gradeAndClassVos = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
//获取当前学校该学段下详细信息
|
||||||
|
List<School.Period> period = schoolRepository.findPeriodById(gcDto.getSchoolId(), gcDto.getPeriodId());
|
||||||
|
List<ClassInfo> classes = classRepository.findClassBySchoolIdAndPeriodId(gcDto.getPeriodId(), String.format(PK.CLASS, gcDto.getSchoolId()));
|
||||||
|
int year;
|
||||||
|
int mon;
|
||||||
|
int day;
|
||||||
|
if (gcDto.getTime() != null && gcDto.getTime() != 0L) {
|
||||||
|
LocalDate date = Instant.ofEpochMilli(gcDto.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
|
year = date.getYear();
|
||||||
|
mon = date.getMonthValue();
|
||||||
|
day = date.getDayOfMonth();
|
||||||
|
}else {
|
||||||
|
year = now().getYear();
|
||||||
|
Month month = now().getMonth();
|
||||||
|
mon = MonthToNumberConverter.convertMonthToNumber(month.name());
|
||||||
|
day = now().getDayOfMonth();
|
||||||
|
}
|
||||||
|
//处理年级ID
|
||||||
|
for (ClassInfo classInfo : classes) {
|
||||||
|
if(period.get(0).getId().equalsIgnoreCase(classInfo.getPeriodId())) {
|
||||||
|
for (School.Semester semester : period.get(0).getSemesters()) {
|
||||||
|
int time;
|
||||||
|
if(semester.getStart() == 1) {
|
||||||
|
if (mon == semester.getMonth())
|
||||||
|
{
|
||||||
|
time = day >= semester.getDay() ? 0 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time = mon > semester.getMonth() ? 0 : 1;
|
||||||
|
}
|
||||||
|
int eYear = year - time;
|
||||||
|
classInfo.setGrade(eYear- classInfo.getYear());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> grades = period.get(0).getGrades();
|
||||||
|
int index = 0;
|
||||||
|
//根据当前时间去判定各个年级的入学年
|
||||||
|
int time = 0;
|
||||||
|
if(period.get(0).getId().equalsIgnoreCase(gcDto.getPeriodId())) {
|
||||||
|
for (School.Semester semester : period.get(0).getSemesters()) {
|
||||||
|
if(semester.getStart() == 1) {
|
||||||
|
if (mon == semester.getMonth())
|
||||||
|
{
|
||||||
|
time = day >= semester.getDay() ? 0 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time = mon > semester.getMonth() ? 0 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (String grade : grades) {
|
||||||
|
GradeAndClassVo gradeAndClassVo = new GradeAndClassVo();
|
||||||
|
gradeAndClassVo.setGradeId(index);
|
||||||
|
gradeAndClassVo.setYear(year - time - index);
|
||||||
|
gradeAndClassVo.setGradeName(grade);
|
||||||
|
classes.stream().filter(classInfo -> classInfo.getGrade() == gradeAndClassVo.getGradeId()).forEach(classInfo -> {
|
||||||
|
GradeAndClassVo.CI ci = new GradeAndClassVo.CI();
|
||||||
|
ci.setClassId(classInfo.getId());
|
||||||
|
ci.setClassName(classInfo.getName());
|
||||||
|
ci.setYear(classInfo.getYear());
|
||||||
|
gradeAndClassVo.AddClass(ci);
|
||||||
|
});
|
||||||
|
index ++;
|
||||||
|
gradeAndClassVos.add(gradeAndClassVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gradeAndClassVos;
|
||||||
|
}catch (Exception e) {
|
||||||
|
|
||||||
|
throw new RuntimeException("获取当前学校当前学段年级班级信息失败" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comment saveOrUpdateComment(Comment comment) {
|
||||||
|
|
||||||
|
String formattedString = String.format("Comment-%s-%s-%s",
|
||||||
|
comment.getSchool(),
|
||||||
|
comment.getYear(),
|
||||||
|
comment.getSemester());
|
||||||
|
List<Comment> comments = commentRepository.findById(comment.getId(),comment.getSchool(),comment.getActivityType(),formattedString);
|
||||||
|
Comment existingComment = comments.stream().findFirst().orElse(null);
|
||||||
|
if (existingComment != null) {
|
||||||
|
// 如果评论对象存在,则进行更新操作
|
||||||
|
// 这里你可以根据需要更新评论对象的属性
|
||||||
|
existingComment.setContentInfo(comment.getContentInfo());
|
||||||
|
existingComment.setUpdateTime(Instant.now().toEpochMilli());
|
||||||
|
|
||||||
|
//commentRepository.deleteById(existingComment.getId(),new PartitionKey(existingComment.getSchool()));
|
||||||
|
// 最后保存更新后的评论对象
|
||||||
|
return commentRepository.save(existingComment);
|
||||||
|
} else {
|
||||||
|
// 如果评论对象不存在,则创建新的记录
|
||||||
|
|
||||||
|
comment.setCode(formattedString);
|
||||||
|
comment.setCreateTime(Instant.now().toEpochMilli());
|
||||||
|
return commentRepository.save(comment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> deleteComment(CommentDto comment) {
|
||||||
|
for (String id : comment.getIds()) {
|
||||||
|
commentRepository.deleteById(id,new PartitionKey(comment.getCode()));
|
||||||
|
}
|
||||||
|
return comment.getIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Comment> getCommentById(Comment comment) {
|
||||||
|
String formattedString = String.format("Comment-%s-%s-%s",
|
||||||
|
comment.getSchool(),
|
||||||
|
comment.getYear(),
|
||||||
|
comment.getSemester());
|
||||||
|
return commentRepository.findById(comment.getId(),comment.getSchool(),comment.getActivityType(),formattedString);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package cn.teammodel.controller.admin.service.impl;
|
||||||
|
|
||||||
|
import cn.teammodel.common.ErrorCode;
|
||||||
|
import cn.teammodel.config.exception.ServiceException;
|
||||||
|
import cn.teammodel.controller.admin.service.ExamService;
|
||||||
|
import cn.teammodel.model.dto.admin.exam.*;
|
||||||
|
import cn.teammodel.model.entity.common.Exam;
|
||||||
|
import cn.teammodel.model.entity.school.School;
|
||||||
|
import cn.teammodel.repository.ExamRepository;
|
||||||
|
import cn.teammodel.repository.SchoolRepository;
|
||||||
|
import cn.teammodel.utils.GroupUtil;
|
||||||
|
import com.azure.cosmos.models.PartitionKey;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ExamServiceImpl implements ExamService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ExamRepository examRepository;
|
||||||
|
@Resource
|
||||||
|
private SchoolRepository schoolRepository;
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getAnalysis(OverViewDto overViewDto, HttpServletRequest request) {
|
||||||
|
|
||||||
|
Map<String, Object> overView;
|
||||||
|
Map<String, Object> examRate;
|
||||||
|
String url = env.getProperty("ies.server-url-overview");
|
||||||
|
String url_exam = env.getProperty("ies.server-url-exam-rate");
|
||||||
|
try {
|
||||||
|
Optional<School> school = schoolRepository.findById(overViewDto.getSchool(), new PartitionKey("Base"));
|
||||||
|
overView = GroupUtil.getGroupId(overViewDto,new GroupUtil(env), request,url);
|
||||||
|
examRate = GroupUtil.getGroupId(overViewDto,new GroupUtil(env), request,url_exam);
|
||||||
|
//SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1);
|
||||||
|
//overView.put("reportId",generator.nextId());
|
||||||
|
overView.putAll(examRate);
|
||||||
|
school.ifPresent(value -> overView.put("schoolName", value.getName()));
|
||||||
|
school.flatMap(value -> value.getPeriod().stream().filter(period ->
|
||||||
|
period.getId().equals(overViewDto.getPeriodId())).findFirst()).ifPresent(value1 ->
|
||||||
|
overView.put("semesters", value1.getSemesters()));
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return overView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getExamList(AnalysisDto analysisDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> overView;
|
||||||
|
String url = env.getProperty("ies.server-url-exam-analysis-list");
|
||||||
|
try {
|
||||||
|
overView = GroupUtil.getGroupId(analysisDto,new GroupUtil(env), request,url);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return overView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getExamSimpleAnalysis(FindExamDto findExamDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> simpleView;
|
||||||
|
String url_simple = env.getProperty("ies.server-url-analysis-simple");
|
||||||
|
try {
|
||||||
|
List<Exam> examList = examRepository.findExamById("Exam-"+findExamDto.getCode(), findExamDto.getId());
|
||||||
|
simpleView = GroupUtil.getGroupId(findExamDto,new GroupUtil(env), request,url_simple);
|
||||||
|
simpleView.put("examList",examList);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return simpleView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getExamRecord(ExamRecordDto examRecordDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> record;
|
||||||
|
String url = env.getProperty("ies.server-url-exam-find-record");
|
||||||
|
try {
|
||||||
|
record = GroupUtil.getGroupId(examRecordDto,new GroupUtil(env), request,url);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getExamByStudent(FindByStudentDto findByStudentDto, HttpServletRequest request) {
|
||||||
|
Map<String, Object> studentView;
|
||||||
|
String url = env.getProperty("ies.server-url-find-simple-by-student");
|
||||||
|
try {
|
||||||
|
studentView = GroupUtil.getGroupId(findByStudentDto,new GroupUtil(env), request,url);
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new ServiceException(ErrorCode.SYSTEM_ERROR.getCode(), "数据转换错误");
|
||||||
|
|
||||||
|
}
|
||||||
|
return studentView;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,189 @@
|
|||||||
|
package cn.teammodel.controller.frontend;
|
||||||
|
|
||||||
|
import cn.teammodel.common.IdRequest;
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.model.dto.ai.*;
|
||||||
|
import cn.teammodel.model.dto.ai.comment.ChatCommentsDto;
|
||||||
|
import cn.teammodel.model.dto.ai.comment.ChatTeacherCommentDto;
|
||||||
|
import cn.teammodel.model.entity.TmdUserDetail;
|
||||||
|
import cn.teammodel.model.entity.ai.ChatApp;
|
||||||
|
import cn.teammodel.model.entity.ai.ChatSession;
|
||||||
|
import cn.teammodel.security.utils.SecurityUtil;
|
||||||
|
import cn.teammodel.service.ChatAppService;
|
||||||
|
import cn.teammodel.service.ChatMessageService;
|
||||||
|
import cn.teammodel.service.ChatSessionService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ai")
|
||||||
|
@Api(tags = "AI 科大讯飞 能力")
|
||||||
|
public class AiController {
|
||||||
|
@Resource
|
||||||
|
private ChatSessionService chatSessionService;
|
||||||
|
@Resource
|
||||||
|
private ChatMessageService chatMessageService;
|
||||||
|
@Resource
|
||||||
|
private ChatAppService chatAppService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("api/chat/completion")
|
||||||
|
@ApiOperation("与 spark 的流式对话")
|
||||||
|
public SseEmitter chatCompletionToApi(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
return chatMessageService.chatCompletion(chatCompletionReqDto, userId);
|
||||||
|
}
|
||||||
|
@PostMapping("chat/completion")
|
||||||
|
@ApiOperation("与 spark 的流式对话")
|
||||||
|
public SseEmitter chatCompletion(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) {
|
||||||
|
return chatMessageService.chatCompletion(chatCompletionReqDto, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("chat/test/completion")
|
||||||
|
@ApiOperation("与 spark 的流式对话")
|
||||||
|
public SseEmitter testCompletion(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) throws IOException, InterruptedException {
|
||||||
|
SseEmitter sseEmitter = new SseEmitter();
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
sseEmitter.send("曾经以为我们");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
sseEmitter.send("开始了就会走到最后,可是当分手之后才明白我想的");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
sseEmitter.send("你不一定能做到,当我开始去遗忘我们");
|
||||||
|
Thread.sleep(1500);
|
||||||
|
sseEmitter.send("的经历时,却不知道遗忘已变成另一种开始,");
|
||||||
|
Thread.sleep(800);
|
||||||
|
sseEmitter.send("回忆是淡了,可是痛却还在,还是最真实。放手的时候微笑着说无所谓");
|
||||||
|
Thread.sleep(800);
|
||||||
|
sseEmitter.send(",离开了你我还可以过的很好");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
sseEmitter.send(",而你却不知道微笑只是用来掩盖疼痛的伤疤。");
|
||||||
|
Thread.sleep(1200);
|
||||||
|
sseEmitter.send("离开你之后的自己陷入一种无助的状态,空洞的");
|
||||||
|
Thread.sleep(1300);
|
||||||
|
sseEmitter.send("双眼回忆不起曾经的你,那时候以为与世隔绝或许才是维护自己的最好方式。");
|
||||||
|
Thread.sleep(1100);
|
||||||
|
sseEmitter.send("[DONE]");
|
||||||
|
sseEmitter.complete();
|
||||||
|
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sseEmitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("api/session/my")
|
||||||
|
@ApiOperation("查询我的聊天会话")
|
||||||
|
public R<List<ChatSession>> listMySession() {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
List<ChatSession> sessions = chatSessionService.listMySession(userId);
|
||||||
|
return R.success(sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("api/chat/history/{sessionId}")
|
||||||
|
@ApiOperation("查询我的聊天记录")
|
||||||
|
public R<List<ChatSession.Message>> getHistory(@PathVariable String sessionId) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
List<ChatSession.Message> history = chatSessionService.listHistory(sessionId, userId);
|
||||||
|
return R.success(history);
|
||||||
|
}
|
||||||
|
@PostMapping("api/session/create")
|
||||||
|
@ApiOperation("创建聊天会话")
|
||||||
|
public R<String> createSession() {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
String name = (String) ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().get("name");
|
||||||
|
name = StringUtils.isBlank(name) ? "老师" : name;
|
||||||
|
String sessionId = chatSessionService.createSession(userId, name);
|
||||||
|
return R.success(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("api/session/remove")
|
||||||
|
@ApiOperation("删除聊天会话")
|
||||||
|
public R<String> removeSession(@RequestBody @Valid IdRequest idRequest) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
chatSessionService.deleteSession(idRequest.getId(), userId);
|
||||||
|
return R.success("删除会话成功");
|
||||||
|
}
|
||||||
|
@PostMapping("api/session/update")
|
||||||
|
@ApiOperation("更新聊天会话")
|
||||||
|
public R<ChatSession> updateSession(@RequestBody @Valid UpdateSessionDto updateSessionDto) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
ChatSession session = chatSessionService.updateSession(updateSessionDto, userId);
|
||||||
|
return R.success(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("app/list")
|
||||||
|
@ApiOperation("查询聊天应用列表")
|
||||||
|
public R<List<ChatApp>> listApp(@RequestBody @Valid SearchAppDto searchAppDto) {
|
||||||
|
List<ChatApp> chatApps = chatAppService.listApp(searchAppDto);
|
||||||
|
return R.success(chatApps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("app/create")
|
||||||
|
@ApiOperation("创建聊天应用")
|
||||||
|
public R<ChatApp> createApp(@RequestBody @Valid CreateChatAppDto createChatAppDto) {
|
||||||
|
ChatApp chatApp = chatAppService.createApp(createChatAppDto);
|
||||||
|
return R.success(chatApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("app/update")
|
||||||
|
@ApiOperation("更新聊天应用")
|
||||||
|
public R<ChatApp> updateApp(@RequestBody @Valid UpdateChatAppDto updateChatAppDto) {
|
||||||
|
ChatApp chatApp = chatAppService.updateApp(updateChatAppDto);
|
||||||
|
return R.success(chatApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("app/remove")
|
||||||
|
@ApiOperation("删除聊天应用")
|
||||||
|
public R<String> updateApp(@RequestBody @Valid IdRequest idRequest) {
|
||||||
|
chatAppService.deleteApp(idRequest);
|
||||||
|
return R.success("删除应用成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("chat/comments")
|
||||||
|
@ApiOperation("学生设置评语")
|
||||||
|
public SseEmitter chatComments(@RequestBody @Valid ChatCommentsDto chatCommentsDto) {
|
||||||
|
//String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
// 获取getClaims时为空
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getUser().getId();
|
||||||
|
String userName = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getUser().getName();
|
||||||
|
|
||||||
|
//获取会话id 看是否有sessionId 有则直接赋值 没有则赋值userId
|
||||||
|
String sessionId = StringUtils.isBlank(chatCommentsDto.getSessionId()) ? userId: chatCommentsDto.getSessionId();
|
||||||
|
chatCommentsDto.setSessionId(sessionId);
|
||||||
|
int repeat = chatCommentsDto.getRepeat();
|
||||||
|
if (repeat <= 1)
|
||||||
|
{
|
||||||
|
chatCommentsDto.setRepeat(repeat);
|
||||||
|
}
|
||||||
|
return chatMessageService.chatComments(chatCommentsDto, userId, userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ai评语
|
||||||
|
*/
|
||||||
|
@PostMapping("chat/teacherComment")
|
||||||
|
@ApiOperation("教师Ai评语")
|
||||||
|
public SseEmitter chatTeacherComment(@RequestBody @Valid ChatTeacherCommentDto chatTeacherCommentDto){
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getUser().getId();
|
||||||
|
String userName = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getUser().getName();
|
||||||
|
|
||||||
|
//获取会话id 看是否有sessionId 有则直接赋值 没有则赋值userId
|
||||||
|
String sessionId = StringUtils.isBlank(chatTeacherCommentDto.getSessionId()) ? userId: chatTeacherCommentDto.getSessionId();
|
||||||
|
chatTeacherCommentDto.setSessionId(sessionId);
|
||||||
|
|
||||||
|
return chatMessageService.chatTeacherComment(chatTeacherCommentDto,userId, userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
package cn.teammodel.controller.frontend;
|
||||||
|
|
||||||
|
import cn.teammodel.common.IdRequest;
|
||||||
|
import cn.teammodel.model.dto.ai.ChatCompletionReqDto;
|
||||||
|
import cn.teammodel.model.dto.ai.deepseek.DeepSeekChatResponse;
|
||||||
|
import cn.teammodel.model.dto.ai.deepseek.ChatReqDto;
|
||||||
|
import cn.teammodel.model.entity.TmdUserDetail;
|
||||||
|
import cn.teammodel.model.entity.ai.DeepSeekSession;
|
||||||
|
import cn.teammodel.model.entity.ai.DeepSeekSession.DeepSeekMessage;
|
||||||
|
import cn.teammodel.security.utils.SecurityUtil;
|
||||||
|
import cn.teammodel.service.DeepSeekService;
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.service.DeepSeekSessionService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/aiDeepSeek")
|
||||||
|
@Api(tags = "AI DeepSeek 能力")
|
||||||
|
public class AiDeepSeekController {
|
||||||
|
|
||||||
|
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
/**
|
||||||
|
* 访问DeepSeek方法
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private DeepSeekService deepSeekChatService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话管理
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private DeepSeekSessionService deepSeekSessionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建默认会话
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("session/create/default")
|
||||||
|
@ApiOperation("创建默认会话")
|
||||||
|
public R<DeepSeekSession> CreateDefaultSession(){
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
String name = (String) ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().get("name");
|
||||||
|
DeepSeekSession session = deepSeekSessionService.CreateDefaultSession(userId,name);
|
||||||
|
return R.success(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建会话 按照结构传输
|
||||||
|
* @param createSession
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("session/create")
|
||||||
|
@ApiOperation("创建会话(实体)")
|
||||||
|
public R<DeepSeekSession> CreateDefaultSession(@RequestBody @Valid DeepSeekSession createSession){
|
||||||
|
DeepSeekSession session = deepSeekSessionService.CreateSession(createSession);
|
||||||
|
return R.success(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除会话
|
||||||
|
* @param idRequest
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("session/del")
|
||||||
|
@ApiOperation("删除会话")
|
||||||
|
public R<String> removeSession(@RequestBody @Valid IdRequest idRequest) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
deepSeekSessionService.deleteSession(idRequest.getId(), userId);
|
||||||
|
return R.success("删除会话成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新会话
|
||||||
|
* @param upSession
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("session/update")
|
||||||
|
@ApiOperation("更新聊天会话")
|
||||||
|
public R<DeepSeekSession> updateSession(@RequestBody @Valid DeepSeekSession upSession) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
DeepSeekSession session = deepSeekSessionService.updateSession(upSession, userId);
|
||||||
|
return R.success(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询我的会话
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("session/userid")
|
||||||
|
@ApiOperation("查询当前登录的会话列表")
|
||||||
|
public R<List<DeepSeekSession>> UserId(){
|
||||||
|
String userId = SecurityUtil.getLoginUser().getId();
|
||||||
|
List<DeepSeekSession> sessions = deepSeekSessionService.UserSessionList(userId);
|
||||||
|
return R.success(sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询某个会话的聊天记录
|
||||||
|
* @param sessionId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("session/history/{sessionId}")
|
||||||
|
@ApiOperation("查询当前登录的某个聊天记录")
|
||||||
|
public R<List<DeepSeekMessage>> getHistory(@PathVariable String sessionId) {
|
||||||
|
String userId = ((TmdUserDetail) SecurityUtil.getAuthentication().getPrincipal()).getClaims().getSubject();
|
||||||
|
List<DeepSeekMessage> history = deepSeekSessionService.listHistory(sessionId, userId);
|
||||||
|
return R.success(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*与deepseek的对话
|
||||||
|
* @param messageDto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("chat")
|
||||||
|
@ApiOperation("单独 与deepseek的对话")
|
||||||
|
public R<DeepSeekChatResponse> ChatCompletion(@RequestBody @Valid ChatReqDto messageDto) {
|
||||||
|
DeepSeekChatResponse chatResponse = deepSeekChatService.ChatAsk(messageDto);
|
||||||
|
return R.success(chatResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("okhttp/emitter")
|
||||||
|
@ApiOperation("单 与deepseek的对话")
|
||||||
|
public SseEmitter ChatEmiter(@RequestBody @Valid ChatReqDto messageDto) {
|
||||||
|
return deepSeekChatService.OKHttpChatSeeEmitterAsk(messageDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 与deepseek的对话 并保存到数据库中
|
||||||
|
* @param chatCompletionReqDto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("chat/completion")
|
||||||
|
@ApiOperation("与 spark 的流式对话")
|
||||||
|
public SseEmitter chatCompletion(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) {
|
||||||
|
String userId = SecurityUtil.getLoginUser().getId();
|
||||||
|
SseEmitter sseEmitter = new SseEmitter(-1L);
|
||||||
|
return deepSeekChatService.ChatSeeEmitterAsk(chatCompletionReqDto);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 与deepseek的对话 并保存到数据库中
|
||||||
|
* @param chatCompletionReqDto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("chat/deep_ponder")
|
||||||
|
@ApiOperation("与 spark 的流式对话")
|
||||||
|
public SseEmitter deepPonderChatCompletion(@RequestBody @Valid ChatCompletionReqDto chatCompletionReqDto) {
|
||||||
|
String userId = SecurityUtil.getLoginUser().getId();
|
||||||
|
SseEmitter sseEmitter = new SseEmitter(-1L);
|
||||||
|
return deepSeekChatService.ReasonerChatCompletion(chatCompletionReqDto);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package cn.teammodel.controller.frontend;
|
||||||
|
|
||||||
|
import cn.teammodel.common.IdRequest;
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.model.dto.Appraise.*;
|
||||||
|
import cn.teammodel.model.entity.appraise.Appraise;
|
||||||
|
import cn.teammodel.model.vo.appraise.AppraiseRecordVo;
|
||||||
|
import cn.teammodel.model.vo.appraise.StudentReportVo;
|
||||||
|
import cn.teammodel.service.EvaluationService;
|
||||||
|
import com.itextpdf.text.DocumentException;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 15:10
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/appraise")
|
||||||
|
@Api(tags = "学生评价")
|
||||||
|
public class AppraiseController {
|
||||||
|
@Resource
|
||||||
|
private EvaluationService evaluationService;
|
||||||
|
|
||||||
|
@PostMapping("getTrees")
|
||||||
|
@ApiOperation(value = "获取评价树", notes = "获取评价树")
|
||||||
|
public R<Appraise> getEvaluateTree(@RequestBody @Valid GetEvaluateTreeDto getEvaluateTreeDto) {
|
||||||
|
Appraise appraise = evaluationService.getTree(getEvaluateTreeDto);
|
||||||
|
return R.success(appraise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("insertNode")
|
||||||
|
@ApiOperation(value = "新增评价树的节点")
|
||||||
|
public R<Appraise> insertNode(@RequestBody @Valid InsertNodeDto insertNodeDto) {
|
||||||
|
Appraise appraise = evaluationService.insertNode(insertNodeDto);
|
||||||
|
return R.success(appraise);
|
||||||
|
}
|
||||||
|
@PostMapping("updateNode")
|
||||||
|
@ApiOperation(value = "更新评价树的节点", notes = "传递更新后的节点,而不是局部更新的值")
|
||||||
|
public R<Appraise> updateTree(@RequestBody @Valid UpdateNodeDto updateNodeDto) {
|
||||||
|
// fixme: 更新一二级节点应该同时更新三级的 path
|
||||||
|
Appraise appraise = evaluationService.updateNode(updateNodeDto);
|
||||||
|
return R.success(appraise);
|
||||||
|
}
|
||||||
|
@PostMapping("deleteNode")
|
||||||
|
@ApiOperation(value = "删除评价树的节点")
|
||||||
|
public R<Appraise> deleteNode(@RequestBody @Valid DeleteNodeDto deleteNodeDto) {
|
||||||
|
Appraise appraise = evaluationService.deleteNode(deleteNodeDto);
|
||||||
|
return R.success(appraise);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("vote")
|
||||||
|
@ApiOperation(value = "给某个学生评价(投票)")
|
||||||
|
public R<String> vote(@RequestBody @Valid AppraiseVoteDto appraiseVoteDto) {
|
||||||
|
evaluationService.vote(appraiseVoteDto);
|
||||||
|
return R.success("评价成功");
|
||||||
|
}
|
||||||
|
@PostMapping("recallVote")
|
||||||
|
@ApiOperation(value = "撤回给某个学生评价(投票)")
|
||||||
|
public R<String> recallVote(@RequestBody @Valid RecallVoteDto recallVoteDto) {
|
||||||
|
evaluationService.recallVote(recallVoteDto);
|
||||||
|
return R.success("撤回评价成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("findVoteRecord")
|
||||||
|
@ApiOperation(value = "多条件查询当前登录老师的学生评价(投票)")
|
||||||
|
public R<List<AppraiseRecordVo>> findMyVoteRecord(@Valid @RequestBody FindVoteRecordDto findVoteRecordDto, HttpServletRequest request) {
|
||||||
|
List<AppraiseRecordVo> res = evaluationService.findVoteRecord(findVoteRecordDto,request);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("studentReport")
|
||||||
|
@ApiOperation(value = "查看学生当前的学期的实时评价报告")
|
||||||
|
public R<StudentReportVo> studentReport(@Valid @RequestBody IdRequest idRequest) {
|
||||||
|
StudentReportVo res = evaluationService.studentReport(idRequest);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("Reports")
|
||||||
|
@ApiOperation(value = "查看多个学生当前的学期的实时评价报告")
|
||||||
|
public R<List<StudentReportVo>> Reports(@Valid @RequestBody ReportDto reportDto) {
|
||||||
|
List<StudentReportVo> res = evaluationService.Reports(reportDto);
|
||||||
|
return R.success(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("studentReportPDF")
|
||||||
|
@ApiOperation(value = "导出学生当前的学期的实时评价报告 PDF")
|
||||||
|
public void exportStuReportPdf(@Valid @RequestBody IdRequest idRequest, HttpServletResponse response) throws DocumentException, IOException {
|
||||||
|
evaluationService.exportStuReportPdf(idRequest, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package cn.teammodel.controller.frontend;
|
||||||
|
|
||||||
|
import cn.teammodel.common.IdRequest;
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.model.dto.weekDuty.*;
|
||||||
|
import cn.teammodel.model.entity.weekDuty.WeekDuty;
|
||||||
|
import cn.teammodel.model.vo.weekDuty.DutyRecordVo;
|
||||||
|
import cn.teammodel.service.DutyService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-01-03 10:06
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/duty")
|
||||||
|
@Api(tags = "值周巡检")
|
||||||
|
public class DutyController {
|
||||||
|
@Resource
|
||||||
|
private DutyService dutyService;
|
||||||
|
|
||||||
|
@GetMapping("/getTree")
|
||||||
|
@ApiOperation("获取值周评价标准树(不存在则拷贝模板)")
|
||||||
|
public R<WeekDuty> getTree() {
|
||||||
|
WeekDuty weekDuty = dutyService.getTree();
|
||||||
|
return R.success(weekDuty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/insertNode")
|
||||||
|
@ApiOperation("插入值周评价标准树节点")
|
||||||
|
public R<WeekDuty> insertNode(@RequestBody @Valid InsertDutyNodeDto insertDutyNodeDto) {
|
||||||
|
WeekDuty weekDuty = dutyService.insertNode(insertDutyNodeDto);
|
||||||
|
return R.success(weekDuty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteNode")
|
||||||
|
@ApiOperation("删除值周评价标准树节点")
|
||||||
|
public R<WeekDuty> deleteNode(@RequestBody @Valid DeleteDutyNodeDto deleteDutyNodeDto) {
|
||||||
|
WeekDuty weekDuty = dutyService.deleteNode(deleteDutyNodeDto);
|
||||||
|
return R.success(weekDuty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/updateNode")
|
||||||
|
@ApiOperation("更新值周评价标准树节点")
|
||||||
|
public R<WeekDuty> updateNode(@RequestBody @Valid UpdateDutyNodeDto updateDutyNodeDto) {
|
||||||
|
WeekDuty weekDuty = dutyService.updateNode(updateDutyNodeDto);
|
||||||
|
return R.success(weekDuty);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/vote")
|
||||||
|
@ApiOperation("值周评价投票")
|
||||||
|
public R<String> vote(@RequestBody @Valid DutyVoteDto dutyVoteDto) {
|
||||||
|
dutyService.vote(dutyVoteDto);
|
||||||
|
return R.success("评价成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/recallVote")
|
||||||
|
@ApiOperation("撤回评价投票")
|
||||||
|
public R<String> recallVote(@RequestBody @Valid RecallDutyVoteDto recallDutyVoteDto) {
|
||||||
|
dutyService.recallVote(recallDutyVoteDto);
|
||||||
|
return R.success("撤回评价成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/insertSpot")
|
||||||
|
@ApiOperation("插入值周评价地点")
|
||||||
|
public R<List<WeekDuty.DutySpot>> insertSpot(@RequestBody @Valid InsertSpotDto insertSpotDto) {
|
||||||
|
List<WeekDuty.DutySpot> spots = dutyService.insertSpot(insertSpotDto);
|
||||||
|
return R.success(spots);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteSpot")
|
||||||
|
@ApiOperation("删除值周评价地点")
|
||||||
|
public R<List<WeekDuty.DutySpot>> deleteSpot(@RequestBody @Valid IdRequest idRequest) {
|
||||||
|
List<WeekDuty.DutySpot> spots = dutyService.deleteSpot(idRequest.getId());
|
||||||
|
return R.success(spots);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/findRecords")
|
||||||
|
@ApiOperation(value = "多条件查询评价明细", notes = "只带 periodId 默认查询当前登录老师在本周的评价明细")
|
||||||
|
public R<List<DutyRecordVo>> findRecords(@RequestBody @Valid FindDutyRecordDto findDutyRecordDto) {
|
||||||
|
List<DutyRecordVo> items = dutyService.findRecords(findDutyRecordDto);
|
||||||
|
return R.success(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package cn.teammodel.controller.frontend;
|
||||||
|
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.model.entity.school.Teacher;
|
||||||
|
import cn.teammodel.repository.AppraiseRepository;
|
||||||
|
import cn.teammodel.repository.TeacherRepository;
|
||||||
|
import cn.teammodel.service.EvaluationService;
|
||||||
|
import com.itextpdf.text.DocumentException;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/")
|
||||||
|
@Api(tags = "鉴权测试")
|
||||||
|
public class HelloController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private EvaluationService evaluationService;
|
||||||
|
@Resource
|
||||||
|
private AppraiseRepository appraiseRepository;
|
||||||
|
@Resource
|
||||||
|
private TeacherRepository teacherRepository;
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("hello")
|
||||||
|
@PreAuthorize("@ss.hasRole('admin')")
|
||||||
|
public R<String> hello() {
|
||||||
|
System.out.println(SecurityContextHolder.getContext().getAuthentication());
|
||||||
|
|
||||||
|
return new R(200, "success","hello world");
|
||||||
|
}
|
||||||
|
@GetMapping("public/free")
|
||||||
|
@PreAuthorize("permitAll()")
|
||||||
|
public R<String> free() {
|
||||||
|
return new R(200, "success","hello world");
|
||||||
|
}
|
||||||
|
@GetMapping("public/curr")
|
||||||
|
public R<String> curr() {
|
||||||
|
|
||||||
|
String curr = env.getProperty("spring.env");
|
||||||
|
HashSet<String> set= new HashSet<String>() ;
|
||||||
|
set.add("1595321354");
|
||||||
|
List<Teacher> techers= teacherRepository.findAllByCodeAndIdIn("Base", set);
|
||||||
|
return new R(200, techers,curr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("public/pdf")
|
||||||
|
public void freepdf(HttpServletResponse response) throws DocumentException, IOException { // 设置response参数
|
||||||
|
// response.reset();
|
||||||
|
// response.setContentType("application/pdf");
|
||||||
|
// response.setHeader("Content-disposition",
|
||||||
|
// "attachment;filename=report_student_" + System.currentTimeMillis() + ".pdf");
|
||||||
|
// ClassPathResource resource = new ClassPathResource("templates/pdf_templates/student_report.pdf");
|
||||||
|
// InputStream in = resource.getInputStream();
|
||||||
|
// ServletOutputStream os = response.getOutputStream();
|
||||||
|
// // 处理 stampter
|
||||||
|
// PdfReader pdfReader = new PdfReader(in);
|
||||||
|
// PdfStamper stamper = new PdfStamper(pdfReader, os);
|
||||||
|
//
|
||||||
|
// Map<String, String> data = PdfUtil.data();
|
||||||
|
// DefaultPieDataset dataset = new DefaultPieDataset( );
|
||||||
|
// dataset.setValue( "IPhone 5s" , new Double( 20 ) );
|
||||||
|
// dataset.setValue( "SamSung Grand" , new Double( 20 ) );
|
||||||
|
// dataset.setValue( "MotoG" , new Double( 40 ) );
|
||||||
|
// dataset.setValue( "Nokia Lumia" , new Double( 10 ) );
|
||||||
|
//
|
||||||
|
// JFreeChart pieChart = ChartUtil.pieChart("手机销量统计", dataset);
|
||||||
|
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
// ChartUtils.writeChartAsJPEG(bos, pieChart, 850, 440);
|
||||||
|
// // 填充表单
|
||||||
|
// PdfUtil.fillPdfForm(stamper, data);
|
||||||
|
// PdfUtil.fillImage(stamper, "praiseDistribution", bos.toByteArray());
|
||||||
|
// PdfUtil.fillImage(stamper, "criticalDistribution", bos.toByteArray());
|
||||||
|
// // 关闭流
|
||||||
|
// stamper.setFormFlattening(true);
|
||||||
|
// stamper.close();
|
||||||
|
// os.close();
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package cn.teammodel.controller.frontend;
|
||||||
|
|
||||||
|
import cn.teammodel.common.IdRequest;
|
||||||
|
import cn.teammodel.common.R;
|
||||||
|
import cn.teammodel.model.dto.news.CreateNewsDto;
|
||||||
|
import cn.teammodel.model.dto.news.UpdateNewsDto;
|
||||||
|
import cn.teammodel.model.entity.news.News;
|
||||||
|
import cn.teammodel.service.NewsService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-02-26 17:04
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/news")
|
||||||
|
@Api(tags = "新闻设置")
|
||||||
|
public class NewsController {
|
||||||
|
@Resource
|
||||||
|
private NewsService newsService;
|
||||||
|
|
||||||
|
@GetMapping("list/{periodId}")
|
||||||
|
@ApiOperation("查询新闻")
|
||||||
|
public R<List<News>> listNews(@PathVariable String periodId) {
|
||||||
|
List<News> Newss = newsService.listNews(periodId);
|
||||||
|
return R.success(Newss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("get/{newsId}")
|
||||||
|
@ApiOperation("根据id查询新闻")
|
||||||
|
public R<News> getNewsById(@PathVariable String newsId) {
|
||||||
|
News news = newsService.getNewsById(newsId);
|
||||||
|
return R.success(news);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("create")
|
||||||
|
@ApiOperation("创建新闻")
|
||||||
|
public R<News> createNews(@RequestBody @Valid CreateNewsDto createNewsDto) {
|
||||||
|
News News = newsService.createNews(createNewsDto);
|
||||||
|
return R.success(News);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("update")
|
||||||
|
@ApiOperation("更新新闻")
|
||||||
|
public R<News> updateNews(@RequestBody @Valid UpdateNewsDto updateNewsDto) {
|
||||||
|
News News = newsService.updateNews(updateNewsDto);
|
||||||
|
return R.success(News);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("remove")
|
||||||
|
@ApiOperation("删除新闻")
|
||||||
|
public R<String> deleteNews(@RequestBody @Valid IdRequest idRequest) {
|
||||||
|
newsService.deleteNews(idRequest);
|
||||||
|
return R.success("删除新闻成功");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package cn.teammodel.manager.notification;
|
||||||
|
|
||||||
|
import com.dingtalk.api.DefaultDingTalkClient;
|
||||||
|
import com.dingtalk.api.DingTalkClient;
|
||||||
|
import com.dingtalk.api.request.OapiRobotSendRequest;
|
||||||
|
import com.taobao.api.ApiException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钉钉告警服务
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-14 10:11
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class DingAlertNotifier implements NotificationService{
|
||||||
|
private final DingTalkClient client;
|
||||||
|
@Autowired
|
||||||
|
public DingAlertNotifier(@Value("${ding.server-url}") String dingServerUrl) {
|
||||||
|
this.client = new DefaultDingTalkClient(dingServerUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(String message) {
|
||||||
|
OapiRobotSendRequest request = new OapiRobotSendRequest();
|
||||||
|
// 文本消息
|
||||||
|
request.setMsgtype("text");
|
||||||
|
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
|
||||||
|
text.setContent(message);
|
||||||
|
request.setText(text);
|
||||||
|
// at 管理员提醒异常
|
||||||
|
OapiRobotSendRequest.At atAll = new OapiRobotSendRequest.At();
|
||||||
|
atAll.setIsAtAll(true);
|
||||||
|
request.setAt(atAll);
|
||||||
|
try {
|
||||||
|
client.execute(request);
|
||||||
|
} catch (ApiException e) {
|
||||||
|
log.error("钉钉 robot 推送消息渠道异常: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package cn.teammodel.manager.notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息通知接口
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-14 10:08
|
||||||
|
*/
|
||||||
|
public interface NotificationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
* @author: winter
|
||||||
|
* @date: 2023/11/14 10:09
|
||||||
|
*/
|
||||||
|
void send(String message);
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package cn.teammodel.manager.wx;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2024-03-26 11:08
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MiniProgramSevice {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-28 16:16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AppraiseVoteDto {
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty(value = "评价对象 Id")
|
||||||
|
private List<String> targetIds;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty(value = "评价对象类型:", allowableValues = "student ,class")
|
||||||
|
private String targetType;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "评分是否传播到班级下的所有学生(评价 CLASS 时生效)")
|
||||||
|
private boolean spread;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "是否推送给家长(评价 STUDENT 时生效)")
|
||||||
|
private boolean pushParent;
|
||||||
|
/**
|
||||||
|
* 可以当作唯一 id集合
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty(value = "评价项唯一 id", required = true)
|
||||||
|
private List<String> appraiseIds;
|
||||||
|
@ApiModelProperty(value = "评价来源")
|
||||||
|
private String device;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 16:16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeleteNodeDto {
|
||||||
|
@NotNull(message = "学段 id 不能为空")
|
||||||
|
String periodId;
|
||||||
|
@NotNull(message = "评价项节点 id 不能为空")
|
||||||
|
String id;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import cn.teammodel.common.PageableRequest;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-28 16:16
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class FindVoteRecordDto extends PageableRequest {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty(value = "必要参数,用于获取当前学年,注意: 其他参数不传则默认获取登录老师在该学年下评价的所有记录", required = true)
|
||||||
|
private String periodId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "班级或学生 id")
|
||||||
|
private String targetId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "评价对象类型:", allowableValues = "student ,class")
|
||||||
|
private String targetType;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "按班级 id 搜索")
|
||||||
|
private String classId;
|
||||||
|
@ApiModelProperty(value = "是否为表扬")
|
||||||
|
private Boolean isPraise;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 15:21
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GetEvaluateTreeDto {
|
||||||
|
@ApiModelProperty(value = "学段 id", required = true)
|
||||||
|
@NotNull(message = "学段 id 不能为空")
|
||||||
|
String periodId;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 16:16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class InsertNodeDto {
|
||||||
|
@ApiModelProperty(value = "学段 id", required = true)
|
||||||
|
@NotNull(message = "学段 id 不能为空")
|
||||||
|
String periodId;
|
||||||
|
@ApiModelProperty(value = "父亲节点,不传则为根节点")
|
||||||
|
String pid;
|
||||||
|
@ApiModelProperty(value = "父亲节点,不传则为根节点", required = true)
|
||||||
|
@NotBlank(message = "name 不能为空")
|
||||||
|
String name;
|
||||||
|
String logo;
|
||||||
|
Integer order = 0;
|
||||||
|
Integer score = 0;
|
||||||
|
Boolean isPraise = true;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 16:16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RecallVoteDto {
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty(value = "学生评价记录的文档id", required = true)
|
||||||
|
String recordId;
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty(value = "学生评价记录的具体节点id", required = true)
|
||||||
|
String nodeId;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ReportDto {
|
||||||
|
|
||||||
|
@Size(min = 1, message = "ids cannot be empty")
|
||||||
|
public List<String> ids;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package cn.teammodel.model.dto.Appraise;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-11-22 16:16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UpdateNodeDto {
|
||||||
|
@ApiModelProperty(value = "学段 id", required = true)
|
||||||
|
@NotNull(message = "学段 id 不能为空")
|
||||||
|
String periodId;
|
||||||
|
@ApiModelProperty(value = "评价项节点的 id")
|
||||||
|
String id;
|
||||||
|
String name;
|
||||||
|
String logo;
|
||||||
|
Integer order;
|
||||||
|
boolean isPraise;
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package cn.teammodel.model.dto.Wechat;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评价完成通知 请求参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AppraiseReqDto extends BaseInfoReqDto {
|
||||||
|
|
||||||
|
@ApiModelProperty("微信openId")
|
||||||
|
public String openId;
|
||||||
|
|
||||||
|
@ApiModelProperty("跳转页面")
|
||||||
|
public String page = "pages/parent/home";
|
||||||
|
|
||||||
|
@ApiModelProperty("被评价用户")
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
@ApiModelProperty("评价内容")
|
||||||
|
public String content;
|
||||||
|
|
||||||
|
@ApiModelProperty("评价时间")
|
||||||
|
public String appraiseTime;
|
||||||
|
|
||||||
|
@ApiModelProperty("评价人")
|
||||||
|
public String appraiseUser;
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package cn.teammodel.model.dto.Wechat;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BaseInfoReqDto {
|
||||||
|
|
||||||
|
@ApiModelProperty("微信登录code")
|
||||||
|
public String code;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package cn.teammodel.model.dto.Wechat;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 考核成绩发布通知 请求参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ExamReqDto extends BaseInfoReqDto{
|
||||||
|
|
||||||
|
@ApiModelProperty("微信openId")
|
||||||
|
public String openId;
|
||||||
|
|
||||||
|
@ApiModelProperty("跳转页面")
|
||||||
|
public String page = "pages/parent/home";
|
||||||
|
|
||||||
|
@ApiModelProperty("用户信息")
|
||||||
|
public String thing3;
|
||||||
|
|
||||||
|
@ApiModelProperty("考试名称")
|
||||||
|
public String thing1;
|
||||||
|
|
||||||
|
@ApiModelProperty("考试成绩")
|
||||||
|
public int number2 = -1;
|
||||||
|
|
||||||
|
@ApiModelProperty("考试时间")
|
||||||
|
public String time5;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.teammodel.model.dto.Wechat;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报告生成通知 请求参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ReportReqDto extends BaseInfoReqDto {
|
||||||
|
|
||||||
|
@ApiModelProperty("微信openId")
|
||||||
|
public String openId;
|
||||||
|
|
||||||
|
@ApiModelProperty("跳转页面")
|
||||||
|
public String page = "pages/parent/home";
|
||||||
|
|
||||||
|
@ApiModelProperty("用户名称")
|
||||||
|
public String thing8;
|
||||||
|
|
||||||
|
@ApiModelProperty("综合、德智体美劳任意")
|
||||||
|
public String thing1;
|
||||||
|
|
||||||
|
@ApiModelProperty("报告生成时间")
|
||||||
|
public String time2;
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package cn.teammodel.model.dto.Wechat;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 职业测试报告通知 请求参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class VocationalReqDto extends BaseInfoReqDto {
|
||||||
|
|
||||||
|
@ApiModelProperty("微信openId")
|
||||||
|
public String openId;
|
||||||
|
|
||||||
|
@ApiModelProperty("跳转页面")
|
||||||
|
public String page = "pages/parent/home";
|
||||||
|
|
||||||
|
@ApiModelProperty("用户")
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
@ApiModelProperty("时间")
|
||||||
|
public String time2;
|
||||||
|
|
||||||
|
@ApiModelProperty("测评名称")
|
||||||
|
public String thing3;
|
||||||
|
|
||||||
|
@ApiModelProperty("测评的分数/出成绩")
|
||||||
|
public int number4;
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.appraise;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author winter
|
||||||
|
* @create 2023-12-13 17:34
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UpdateAchievementRuleDto {
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty("学段 id")
|
||||||
|
private String periodId;
|
||||||
|
@ApiModelProperty("更新的 rule 节点: 将会直接覆盖老节点")
|
||||||
|
private UpdateRule updateRule;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class UpdateRule {
|
||||||
|
private String id;
|
||||||
|
/**
|
||||||
|
* 等级名称
|
||||||
|
*/
|
||||||
|
private String name = "";
|
||||||
|
@ApiModelProperty("等级 logo")
|
||||||
|
private String logo = "";
|
||||||
|
@ApiModelProperty("每次所需表扬数")
|
||||||
|
private Integer levelCount = 0;
|
||||||
|
@ApiModelProperty("晋级所需下一等级所需当前等级次数")
|
||||||
|
private Integer promotionLevel = 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.art;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ArtFindDto
|
||||||
|
{
|
||||||
|
@ApiModelProperty("学校编码")
|
||||||
|
private String code;
|
||||||
|
@ApiModelProperty("学段ID")
|
||||||
|
private String periodId;
|
||||||
|
@ApiModelProperty("学段类型")
|
||||||
|
private String periodType;
|
||||||
|
@ApiModelProperty("开始时间")
|
||||||
|
private Long startTime;
|
||||||
|
@ApiModelProperty("结束时间")
|
||||||
|
private Long endTime;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.art;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DataFileCommentDto {
|
||||||
|
private String artId;
|
||||||
|
private String schoolId;
|
||||||
|
private String schoolCode;
|
||||||
|
private String headLang;
|
||||||
|
private String studentId;
|
||||||
|
@ApiModelProperty(value = "自定义评语,不传或者传空字符串代表清空之前的")
|
||||||
|
private String comment;
|
||||||
|
@ApiModelProperty(value = "自定义评语音乐,不传或者传空字符串代表清空之前的")
|
||||||
|
private String comment_music;
|
||||||
|
@ApiModelProperty(value = "自定义评语美术,不传或者传空字符串代表清空之前的")
|
||||||
|
private String comment_painting;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.art;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class DataFileDto {
|
||||||
|
private String artId;
|
||||||
|
private String schoolId;
|
||||||
|
private String schoolCode;
|
||||||
|
private String opt;
|
||||||
|
private String headLang;
|
||||||
|
List<String> studentIds;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.common;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GCDto {
|
||||||
|
private String schoolId;
|
||||||
|
private String periodId;
|
||||||
|
private Long time;
|
||||||
|
|
||||||
|
public GCDto(String schoolId, String periodId) {
|
||||||
|
this.schoolId = schoolId;
|
||||||
|
this.periodId = periodId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.common;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GroupDto {
|
||||||
|
public List<String> ids;
|
||||||
|
public String schoolId;
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.exam;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AnalysisDto {
|
||||||
|
@ApiModelProperty("学校编码")
|
||||||
|
private String code;
|
||||||
|
@ApiModelProperty("当前学校指定学段")
|
||||||
|
private String period;
|
||||||
|
@ApiModelProperty("当前评测活动所属范围,目前制定查询属于学校的数据,直接传 school")
|
||||||
|
private String owner;
|
||||||
|
@ApiModelProperty("指定查询的条数,为了后续滚动翻页")
|
||||||
|
private int count;
|
||||||
|
@ApiModelProperty("翻页参数,后续滚动翻页回传给后端,没有就不管")
|
||||||
|
private String token;
|
||||||
|
@ApiModelProperty("开始时间")
|
||||||
|
private Long startTime;
|
||||||
|
@ApiModelProperty("结束时间")
|
||||||
|
private Long endTime;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package cn.teammodel.model.dto.admin.exam;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BlobSasDto {
|
||||||
|
public String name;
|
||||||
|
public String role;
|
||||||
|
public String code;
|
||||||
|
@ApiModelProperty("容器名称")
|
||||||
|
public String containerName;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue