Browse Source

Merge branch 'TPE/develop5.0' into TPE/develop5.0_master

jeff 3 years ago
parent
commit
02f28141c5
100 changed files with 6013 additions and 902 deletions
  1. 45 42
      TEAMModeBI/ClientApp/package.json
  2. 12 6
      TEAMModeBI/ClientApp/public/index.html
  3. 5 16
      TEAMModeBI/ClientApp/src/App.vue
  4. 28 0
      TEAMModeBI/ClientApp/src/api/index.js
  5. 66 0
      TEAMModeBI/ClientApp/src/assets/filter/http.js
  6. BIN
      TEAMModeBI/ClientApp/src/assets/img/background1.png
  7. BIN
      TEAMModeBI/ClientApp/src/assets/img/background2.png
  8. BIN
      TEAMModeBI/ClientApp/src/assets/img/background3.png
  9. BIN
      TEAMModeBI/ClientApp/src/assets/img/ddlogin.png
  10. BIN
      TEAMModeBI/ClientApp/src/assets/img/erweima.png
  11. BIN
      TEAMModeBI/ClientApp/src/assets/img/login.png
  12. BIN
      TEAMModeBI/ClientApp/src/assets/img/mima.png
  13. 6 2
      TEAMModeBI/ClientApp/src/main.js
  14. 6 21
      TEAMModeBI/ClientApp/src/router/index.js
  15. 70 0
      TEAMModeBI/ClientApp/src/until/http.js
  16. 171 0
      TEAMModeBI/ClientApp/src/view/bindPhone.vue
  17. 122 0
      TEAMModeBI/ClientApp/src/view/ddlogin.vue
  18. 219 0
      TEAMModeBI/ClientApp/src/view/login.vue
  19. 80 0
      TEAMModeBI/Controllers/AESHelper.cs
  20. 83 0
      TEAMModeBI/Controllers/BIHome/HomeStatisController.cs
  21. 660 0
      TEAMModeBI/Controllers/BIHome/StudyStatisController.cs
  22. 109 0
      TEAMModeBI/Controllers/BISchool/BatchAreaController.cs
  23. 118 0
      TEAMModeBI/Controllers/BISchool/BatchSchoolController.cs
  24. 225 0
      TEAMModeBI/Controllers/DingDingStruc/DDDeptController.cs
  25. 17 0
      TEAMModeBI/Controllers/DingDingStruc/DDPowerController.cs
  26. 530 0
      TEAMModeBI/Controllers/DingDingStruc/DDStructController.cs
  27. 796 15
      TEAMModeBI/Controllers/LoginController.cs
  28. 57 0
      TEAMModeBI/Controllers/SchoolSettingController.cs
  29. 0 40
      TEAMModeBI/Controllers/WeatherForecastController.cs
  30. 6 2
      TEAMModeBI/Program.cs
  31. 3 4
      TEAMModeBI/Properties/launchSettings.json
  32. 99 27
      TEAMModeBI/Startup.cs
  33. 6 6
      TEAMModeBI/TEAMModeBI.csproj
  34. 0 15
      TEAMModeBI/WeatherForecast.cs
  35. 7 0
      TEAMModeBI/appsettings.Development.json
  36. 67 16
      TEAMModelAPI/ApiTokenAttribute.cs
  37. 14 1
      TEAMModelAPI/Controllers/WeatherForecastController.cs
  38. 3 0
      TEAMModelAPI/Program.cs
  39. 1 1
      TEAMModelAPI/appsettings.Development.json
  40. 1 22
      TEAMModelFunction/ActivityHttpTrigger.cs
  41. 1 1
      TEAMModelFunction/MonitorCosmosDB.cs
  42. 250 1
      TEAMModelFunction/MonitorServicesBus.cs
  43. 40 13
      TEAMModelFunction/TriggerCorrect.cs
  44. 282 275
      TEAMModelFunction/TriggerExam.cs
  45. 5 3
      TEAMModelFunction/TriggerExamLite.cs
  46. 6 4
      TEAMModelFunction/TriggerWork.cs
  47. 6 5
      TEAMModelFunction/TriggerStudy.cs
  48. 5 3
      TEAMModelFunction/TriggerSurvey.cs
  49. 5 3
      TEAMModelFunction/TriggerVote.cs
  50. 1 0
      TEAMModelFunction/local.settings.json
  51. 0 32
      TEAMModelOS.SDK/Context/Configuration/BaseConfigModel.cs
  52. 4 4
      TEAMModelOS.SDK/Context/Constant/Constant.cs
  53. 57 0
      TEAMModelOS.SDK/DI/CoreAPI/CoreAPIHttpService.cs
  54. 93 0
      TEAMModelOS.SDK/Helper/Common/StringHelper/PingYinHelper.cs
  55. 2 2
      TEAMModelOS.SDK/Helper/Security/Md5Hash/Md5Hash.cs
  56. 41 0
      TEAMModelOS.SDK/Models/Cosmos/BI/DeptNode.cs
  57. 3 3
      TEAMModelOS.SDK/Models/Cosmos/BI/DingDingUser.cs
  58. 40 0
      TEAMModelOS.SDK/Models/Cosmos/Common/ActivityRecord.cs
  59. 68 0
      TEAMModelOS.SDK/Models/Cosmos/Common/GroupList.cs
  60. 43 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/GroupChange.cs
  61. 2 5
      TEAMModelOS.SDK/Models/Cosmos/Common/Inner/ListChange.cs
  62. 0 45
      TEAMModelOS.SDK/Models/Cosmos/Common/JoinList.cs
  63. 1 0
      TEAMModelOS.SDK/Models/Cosmos/Common/MQActivity.cs
  64. 7 0
      TEAMModelOS.SDK/Models/Cosmos/Common/Notice.cs
  65. 1 9
      TEAMModelOS.SDK/Models/Cosmos/Common/Scoring.cs
  66. 26 7
      TEAMModelOS.SDK/Models/Cosmos/Common/SheetConfig.cs
  67. 5 1
      TEAMModelOS.SDK/Models/Cosmos/Common/StuActivity.cs
  68. 5 1
      TEAMModelOS.SDK/Models/Cosmos/Research/Ability.cs
  69. 6 0
      TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs
  70. 3 3
      TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs
  71. 42 37
      TEAMModelOS.SDK/Models/Cosmos/School/Paper.cs
  72. 91 1
      TEAMModelOS.SDK/Models/Cosmos/School/SchoolProduct.cs
  73. 11 1
      TEAMModelOS.SDK/Models/Cosmos/School/StandardFile.cs
  74. 7 0
      TEAMModelOS.SDK/Models/Cosmos/Student/Student.cs
  75. 2 0
      TEAMModelOS.SDK/Models/Cosmos/Teacher/CorrectTask.cs
  76. 238 1
      TEAMModelOS.SDK/Models/Cosmos/Teacher/Teacher.cs
  77. 14 0
      TEAMModelOS.SDK/Models/Dtos/ItemCondDto.cs
  78. 9 1
      TEAMModelOS.SDK/Models/Service/ExamService.cs
  79. 770 0
      TEAMModelOS.SDK/Models/Service/GroupListService.cs
  80. 29 6
      TEAMModelOS.SDK/Models/Service/HomeworkService.cs
  81. 4 4
      TEAMModelOS.SDK/Models/Service/ItemService.cs
  82. 25 19
      TEAMModelOS.SDK/Models/Service/NotificationService.cs
  83. 1 1
      TEAMModelOS.SDK/Models/Service/StuListService.cs
  84. 8 0
      TEAMModelOS.SDK/Models/Service/SurveyService.cs
  85. 2 0
      TEAMModelOS.SDK/Models/Service/TriggerStuActivity.cs
  86. 0 36
      TEAMModelOS.SDK/Models/Table/KnowledgeBlock.cs
  87. 0 42
      TEAMModelOS.SDK/Models/Table/KnowledgeBlockPoint.cs
  88. 0 44
      TEAMModelOS.SDK/Models/Table/KnowledgePoint.cs
  89. 41 0
      TEAMModelOS.SDK/Models/Cosmos/Api/OpenApi.cs
  90. 0 19
      TEAMModelOS.SDK/Models/Table/ResourceReference.cs
  91. 0 14
      TEAMModelOS.SDK/Models/Table/tmdInfo.cs
  92. 6 2
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  93. 2 1
      TEAMModelOS/ClientApp/package.json
  94. 5 1
      TEAMModelOS/ClientApp/src/api/ability.js
  95. 31 13
      TEAMModelOS/ClientApp/src/api/evaluation.js
  96. 14 3
      TEAMModelOS/ClientApp/src/api/http.js
  97. 5 0
      TEAMModelOS/ClientApp/src/api/knowledge.js
  98. 4 0
      TEAMModelOS/ClientApp/src/api/login.js
  99. 12 0
      TEAMModelOS/ClientApp/src/api/mark.js
  100. 0 0
      TEAMModelOS/ClientApp/src/api/schoolSetting.js

+ 45 - 42
TEAMModeBI/ClientApp/package.json

@@ -1,46 +1,49 @@
 {
-  "name": "clientapp",
-  "version": "0.1.0",
-  "private": true,
-  "scripts": {
-    "serve": "vue-cli-service serve",
-    "build": "vue-cli-service build",
-    "lint": "vue-cli-service lint"
-  },
-  "dependencies": {
-    "axios": "^0.20.0-0",
-    "bootstrap": "^4.5.3",
-    "core-js": "^3.7.0",
-    "vue": "^3.0.2",
-    "vue-loader-v16": "npm:vue-loader@^16.0.0-alpha.3",
-    "vue-router": "^4.0.0-rc.5"
-  },
-  "devDependencies": {
-    "@vue/cli-plugin-babel": "^4.5.9",
-    "@vue/cli-plugin-eslint": "^4.5.9",
-    "@vue/cli-service": "^4.5.9",
-    "@vue/compiler-sfc": "^3.0.2",
-    "babel-eslint": "^10.1.0",
-    "eslint": "^6.8.0",
-    "eslint-plugin-vue": "^7.1.0"
-  },
-  "eslintConfig": {
-    "root": true,
-    "env": {
-      "node": true
+    "name": "clientapp",
+    "version": "0.1.0",
+    "private": true,
+    "scripts": {
+        "serve": "vue-cli-service serve",
+        "build": "vue-cli-service build",
+        "lint": "vue-cli-service lint"
     },
-    "extends": [
-      "plugin:vue/vue3-essential",
-      "eslint:recommended"
-    ],
-    "parserOptions": {
-      "parser": "babel-eslint"
+    "dependencies": {
+        "axios": "^0.20.0-0",
+        "bootstrap": "^4.5.3",
+        "core-js": "^3.7.0",
+        "element-plus": "^1.1.0-beta.24",
+        "less": "^4.1.2",
+        "qs": "^6.10.1",
+        "vue": "^3.2.0",
+        "vue-loader-v16": "npm:vue-loader@^16.0.0-alpha.3",
+        "vue-router": "^4.0.0-rc.5"
     },
-    "rules": {}
-  },
-  "browserslist": [
-    "> 1%",
-    "last 2 versions",
-    "not dead"
-  ]
+    "devDependencies": {
+        "@vue/cli-plugin-babel": "^4.5.9",
+        "@vue/cli-plugin-eslint": "^4.5.9",
+        "@vue/cli-service": "^4.5.9",
+        "@vue/compiler-sfc": "^3.0.2",
+        "babel-eslint": "^10.1.0",
+        "eslint": "^6.8.0",
+        "eslint-plugin-vue": "^7.1.0"
+    },
+    "eslintConfig": {
+        "root": true,
+        "env": {
+            "node": true
+        },
+        "extends": [
+            "plugin:vue/vue3-essential",
+            "eslint:recommended"
+        ],
+        "parserOptions": {
+            "parser": "babel-eslint"
+        },
+        "rules": {}
+    },
+    "browserslist": [
+        "> 1%",
+        "last 2 versions",
+        "not dead"
+    ]
 }

+ 12 - 6
TEAMModeBI/ClientApp/public/index.html

@@ -1,17 +1,23 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
+
+<head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title><%= htmlWebpackPlugin.options.title %></title>
-  </head>
-  <body>
+    <title>
+        <%= htmlWebpackPlugin.options.title %>
+    </title>
+</head>
+<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
+
+<body>
     <noscript>
       <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
     </noscript>
     <div id="app"></div>
     <!-- built files will be auto injected -->
-  </body>
-</html>
+</body>
+
+</html>

+ 5 - 16
TEAMModeBI/ClientApp/src/App.vue

@@ -1,26 +1,15 @@
 <template>
-  <nav-menu></nav-menu>
-  <router-view />
+    <router-view />
 </template>
 
 <script>
-    import NavMenu from './components/NavMenu.vue'
-
 export default {
-  name: 'App',
-  components: {
-      NavMenu
-  }
-}
+    name: "App",
+    components: {},
+};
 </script>
-
 <style>
 #app {
-  font-family: Avenir, Helvetica, Arial, sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  text-align: center;
-  color: #2c3e50;
-  margin-top: 60px;
+    min-width: 1280px;
 }
 </style>

+ 28 - 0
TEAMModeBI/ClientApp/src/api/index.js

@@ -0,0 +1,28 @@
+import { post } from '@/until/http.js'
+// export function Dinglogin(data) {
+//     return post('/common/login/DingLogin', data)
+// }
+// export function Phonepin(data) {
+//     return post('https://api2.teammodel.net/service/sandsms/pin', data)
+// }
+//钉钉登录获取状态
+function Dinglogin(data) {
+    return post('/common/login/DingLogin', data)
+}
+//发送短信验证码
+function Phonepin(data) {
+    return post('/common/login/send-sms', data)
+}
+//验证手机号和验证
+function verifyCode(data) {
+    return post('/common/login/verfiypin', data)
+}
+//手机验证码都通过后,进行绑定操作
+function bindUserid(data) {
+    return post('/common/login/bind', data)
+}
+//正常醍摩豆账号或者手机号登录
+function loginUser(data) {
+    return post('https://api2.teammodel.cn/oauth2/login', data)
+}
+export { Dinglogin, Phonepin, verifyCode, bindUserid, loginUser }

+ 66 - 0
TEAMModeBI/ClientApp/src/assets/filter/http.js

@@ -0,0 +1,66 @@
+import axios from 'axios';
+import router from '@/router/index.js';
+axios.defaults.timeout = 1000000; //设置超时时长
+axios.defaults.baseURL = '';
+
+//http request 拦截器
+axios.interceptors.request.use(
+    config => {
+        // const token = getCookie('名称');
+        config.data = JSON.stringify(config.data);
+        config.headers['access_token'] = localStorage.getItem('accessToken')
+        config.headers['Content-Type'] = 'application/json'
+        return config;
+    },
+    error => {
+        return Promise.reject(error);
+    }
+);
+/**
+ * 封装get方法
+ * @param url
+ * @param data
+ * @returns {Promise}
+ */
+
+export function fetch(url, params) {
+    let data = {};
+    data.method = url;
+    data.params = params;
+    data.lang = localStorage.getItem('local');
+    return new Promise((resolve, reject) => {
+        axios.get(url, data)
+            .then(response => {
+                resolve(response.data);
+                //  this.$Message.success('数据访问成功!');
+            })
+            .catch(error => {
+                reject(error);
+                this.$Message.error('数据访问错误!');
+            })
+    })
+}
+
+/**
+ * 封装post请求
+ * @param url
+ * @param data
+ * @returns {Promise}
+ */
+
+export function post(url, params) {
+    let data = {};
+    data.method = url;
+    data.params = params;
+    data.lang = localStorage.getItem('local');
+    return new Promise((resolve, reject) => {
+        axios.post(url, params)
+            .then(response => {
+                resolve(response.data);
+                // this.$Message.success('数据访问成功!');
+            }, error => {
+                reject(error);
+                //this.$Message.error('数据访问错误!');
+            })
+    })
+}

BIN
TEAMModeBI/ClientApp/src/assets/img/background1.png


BIN
TEAMModeBI/ClientApp/src/assets/img/background2.png


BIN
TEAMModeBI/ClientApp/src/assets/img/background3.png


BIN
TEAMModeBI/ClientApp/src/assets/img/ddlogin.png


BIN
TEAMModeBI/ClientApp/src/assets/img/erweima.png


BIN
TEAMModeBI/ClientApp/src/assets/img/login.png


BIN
TEAMModeBI/ClientApp/src/assets/img/mima.png


+ 6 - 2
TEAMModeBI/ClientApp/src/main.js

@@ -1,6 +1,10 @@
 import 'bootstrap/dist/css/bootstrap.css'
 import { createApp } from 'vue'
 import App from './App.vue'
-import router from './router'
+import router from './router/index.js'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import axios from '@/api/index.js'
 
-createApp(App).use(router).mount('#app')
+createApp(App).use(router).use(ElementPlus).mount('#app')
+createApp(App).config.globalProperties.$api = axios

+ 6 - 21
TEAMModeBI/ClientApp/src/router/index.js

@@ -1,25 +1,10 @@
 import { createWebHistory, createRouter } from "vue-router";
-import Home from "@/components/Home.vue";
-import Counter from "@/components/Counter.vue";
-import FetchData from "@/components/FetchData.vue";
-
-const routes = [
-    {
-        path: "/",
-        name: "Home",
-        component: Home,
-    },
-    {
-        path: "/Counter",
-        name: "Counter",
-        component: Counter,
-    },
-    {
-        path: "/FetchData",
-        name: "FetchData",
-        component: FetchData,
-    }
-];
+import Login from "@/view/login.vue";
+const routes = [{
+    path: "/",
+    name: "Login",
+    component: Login,
+}, ];
 
 const router = createRouter({
     history: createWebHistory(),

+ 70 - 0
TEAMModeBI/ClientApp/src/until/http.js

@@ -0,0 +1,70 @@
+import axios from 'axios';
+import Vue from 'vue'
+import router from '@/router/index.js';
+axios.defaults.timeout = 1000000; //设置超时时长
+axios.defaults.baseURL = '';
+
+//http request 拦截器
+axios.interceptors.request.use(
+    config => {
+        // const token = getCookie('名称');
+        config.data = JSON.stringify(config.data);
+        config.headers = {
+            'Content-Type': 'application/json',
+            'Authorization': ""
+        }
+        return config;
+    },
+    error => {
+        return Promise.reject(err);
+    }
+);
+
+/**
+ * 封装get方法
+ * @param url
+ * @param data
+ * @returns {Promise}
+ */
+
+export function fetch(url, params) {
+    let data = {};
+    data.method = url;
+    data.params = params;
+    data.lang = localStorage.getItem('local');
+    return new Promise((resolve, reject) => {
+        axios.get(url, data)
+            .then(response => {
+                resolve(response.data);
+                //  this.$Message.success('数据访问成功!');
+            })
+            .catch(err => {
+                reject(err);
+                this.$Message.error('数据访问错误!');
+            })
+    })
+}
+
+/**
+ * 封装post请求
+ * @param url
+ * @param data
+ * @returns {Promise}
+ */
+
+export function post(url, params) {
+    let data = {};
+    data.method = url;
+    data.params = params;
+    data.lang = localStorage.getItem('local');
+    return new Promise((resolve, reject) => {
+        axios.post(url, params)
+            .then(response => {
+                resolve(response.data);
+                // this.$Message.success('数据访问成功!');
+            }, err => {
+                reject(err);
+                //this.$Message.error('数据访问错误!');
+            })
+    })
+}

+ 171 - 0
TEAMModeBI/ClientApp/src/view/bindPhone.vue

@@ -0,0 +1,171 @@
+<template>
+    <el-dialog v-model="centerDialogVisible" title="绑定账号" width="30%" center>
+        <div class="bindbox">
+            <div class="bind-phone">
+                <el-row :gutter="20">
+                    <el-input v-model="phonenum.phone" placeholder="请输入绑定的醍摩豆手机号码" prefix-icon="el-icon-phone" @blur="phoneData.to = phonenum.phone" />
+                </el-row>
+            </div>
+            <div class="bind-code">
+                <div class="codenum">
+                    <el-row :gutter="20">
+                        <el-input v-model="phonenum.code" placeholder="" />
+                    </el-row>
+                </div>
+                <div class="sendcode">
+                    <el-button type="primary" v-show="showCode.status" @click="getCode()">验证码</el-button>
+                    <el-button type="primary" disabled v-show="showCode.status ==false">{{showCode.count}}秒</el-button>
+                </div>
+            </div>
+        </div>
+        <template #footer>
+            <span class="dialog-footer">
+                <el-button type="primary" @click="bindUser">绑定</el-button>
+                <el-button @click="centerDialogVisible = false">取消</el-button>
+            </span>
+        </template>
+    </el-dialog>
+</template>
+<script>
+import { reactive, ref } from "vue";
+import { Phonepin, verifyCode, bindUserid } from "@/api/index.js";
+import { ElMessage } from "element-plus";
+export default {
+    setup() {
+        let centerDialogVisible = ref(true);
+        let phonenum = reactive({
+            phone: "",
+            code: "",
+        });
+        //验证冷却
+        let showCode = reactive({
+            status: true,
+            count: "",
+            timer: null,
+        });
+        var phoneData = {
+            to: phonenum.phone,
+            lang: "zh-cn",
+            HasUser: true,
+            country: "86",
+        };
+        var { phoneCode } = pin();
+        //验证码冷却及发送验证码
+        function getCode() {
+            //验证码冷却部分
+            const TIME_COUNT = 60;
+            if (!showCode.timer) {
+                showCode.count = TIME_COUNT;
+                showCode.status = false;
+                showCode.timer = setInterval(() => {
+                    if (showCode.count > 0 && showCode.count <= TIME_COUNT) {
+                        showCode.count--;
+                    } else {
+                        showCode.status = true;
+                        clearInterval(showCode.timer);
+                        showCode.timer = null;
+                    }
+                }, 1000);
+            }
+            //请求接口
+            phoneCode(phoneData);
+        }
+        //手机号码绑定流程
+        function bindUser() {
+            //先获取到手机号和验证码
+            let codeNum = {
+                mobile: phonenum.phone,
+                Authorization_Pin: phonenum.code,
+            };
+            console.log(codeNum, "手机号和验证码");
+            //验证手机号和验证码
+            verifyCode(codeNum).then((res) => {
+                console.log(res, "验证手机号和验证码");
+                if (res.error) {
+                    res.error === 3 || res.error === 4
+                        ? ElMessage.error("验证码错误")
+                        : res.error === 1
+                        ? ElMessage.error("无手机绑定的醍摩豆账号")
+                        : res.error === 5
+                        ? ElMessage.error("无效的手机号码")
+                        : ElMessage.error("接口异常请重新尝试绑定");
+                } else if (res.status && res.status === 200) {
+                    let userInfo = JSON.parse(localStorage.getItem("DingUser"));
+                    console.log(userInfo, "用户信息");
+                    let paramData = { mobile: phonenum.phone, param: userInfo };
+                    bindId(paramData);
+                }
+            });
+        }
+        //绑定操作
+        function bindId(paramData) {
+            bindUserid(paramData).then((res) => {
+                console.log(res, "返回的结果");
+                res.status === 1 || res.status === 3
+                    ? ElMessage.error("绑定失败,请稍后重试")
+                    : res.status === 2
+                    ? ElMessage.error("账户已被绑定,请选择其他账号绑定")
+                    : res.status === 200
+                    ? ElMessage.success("绑定成功,即将跳转...")
+                    : ElMessage.error("出现未知错误");
+            });
+        }
+        return {
+            centerDialogVisible,
+            phonenum,
+            showCode,
+            getCode,
+            phoneCode,
+            phoneData,
+            bindUser,
+            bindId,
+        };
+    },
+};
+//发送验证码API
+function pin() {
+    let phoneCode = (datas) => {
+        let parameter = {
+            to: datas.to,
+            lang: datas.lang,
+            HasUser: datas.HasUser,
+            country: datas.country,
+        };
+        let { codesInfo } = Phonepin(parameter).then((res) => {
+            console.log(res, "接口返回");
+            res.status === 200
+                ? ElMessage.success("验证码发送成功")
+                : ElMessage.error("验证码发送失败");
+        });
+        console.log("codesInfo", codesInfo);
+    };
+    return {
+        phoneCode,
+    };
+}
+</script>
+<style scoped>
+.bindbox {
+    width: 45%;
+    height: auto;
+    margin: 0 auto;
+}
+.bind-code {
+    margin: 10% 0% 20% 0%;
+}
+.codenum {
+    float: left;
+    font-size: 18px;
+    width: 60%;
+}
+.sendcode {
+    float: left;
+    width: 33%;
+    margin-left: 7%;
+}
+</style>
+<style>
+.sendcode button span {
+    font-size: 14px;
+}
+</style>

+ 122 - 0
TEAMModeBI/ClientApp/src/view/ddlogin.vue

@@ -0,0 +1,122 @@
+<template>
+    <div style="width:100%">
+        <div id="login_container" style="margin-bottom:5%;"></div>
+    </div>
+</template>
+ 
+<script>
+import axios from "axios";
+export default {
+    name: "App",
+    components: {},
+    data() {
+        return {
+            appid: "dingrucgsnt8p13rfbgd",
+            redirectUrl: "https://localhost:5001",
+            apiUrl: "/common/login/DingLogin",
+            dingCodeConfig: {
+                id: "login_container",
+                style: "background-color:#FFFFFF;",
+                width: "300",
+                height: "350",
+            },
+        };
+    },
+    computed: {
+        getRedirectUrl() {
+            return encodeURIComponent(this.redirectUrl);
+        },
+        getAuthUrl() {
+            return `https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=${this.appid}&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=${this.getRedirectUrl}`;
+        },
+        getGoto() {
+            return encodeURIComponent(this.getAuthUrl);
+        },
+        getDingCodeConfig() {
+            return { ...this.dingCodeConfig, goto: this.getGoto };
+        },
+    },
+    created() {
+        this.initDingJs();
+    },
+    mounted() {
+        this.addDingListener();
+        this.initDingLogin();
+        this.getUser();
+    },
+    methods: {
+        initDingJs() {
+            !(function (window, document) {
+                function d(a) {
+                    var e,
+                        c = document.createElement("iframe"),
+                        d =
+                            "https://login.dingtalk.com/login/qrcode.htm?goto=" +
+                            a.goto;
+                    (d += a.style
+                        ? "&style=" + encodeURIComponent(a.style)
+                        : ""),
+                        (d += a.href ? "&href=" + a.href : ""),
+                        (c.src = d),
+                        (c.frameBorder = "0"),
+                        (c.allowTransparency = "true"),
+                        (c.scrolling = "no"),
+                        (c.width = a.width ? a.width + "px" : "365px"),
+                        (c.height = a.height ? a.height + "px" : "400px"),
+                        (e = document.getElementById(a.id)),
+                        (e.innerHTML = ""),
+                        e.appendChild(c);
+                }
+
+                window.DDLogin = d;
+            })(window, document);
+        },
+        addDingListener() {
+            let self = this;
+
+            let handleLoginTmpCode = function (loginTmpCode) {
+                window.location.href =
+                    self.getAuthUrl + `&loginTmpCode=${loginTmpCode}`;
+            };
+
+            let handleMessage = function (event) {
+                if (event.origin == "https://login.dingtalk.com") {
+                    handleLoginTmpCode(event.data);
+                }
+            };
+
+            if (typeof window.addEventListener != "undefined") {
+                window.addEventListener("message", handleMessage, false);
+            } else if (typeof window.attachEvent != "undefined") {
+                window.attachEvent("onmessage", handleMessage);
+            }
+        },
+        initDingLogin() {
+            window.DDLogin(this.getDingCodeConfig);
+        },
+        getUser() {
+            let getQueryString = function (name) {
+                var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+                var r = window.location.search.substr(1).match(reg);
+                if (r != null) {
+                    return unescape(r[2]);
+                }
+                return null;
+            };
+
+            let code = getQueryString("code");
+
+            if (code !== null) {
+                axios
+                    .get(`${this.apiUrl}?code=${code}`)
+                    .then((response) => {
+                        console.log(response);
+                    })
+                    .catch((error) => {
+                        console.log(error);
+                    });
+            }
+        },
+    },
+};
+</script>

+ 219 - 0
TEAMModeBI/ClientApp/src/view/login.vue

@@ -0,0 +1,219 @@
+<template>
+    <div class="backgorundbox">
+        <div class="loginbox">
+            <div class="logintitle">醍摩豆账号登录</div>
+            <div class="usrpwd" v-if="loginModel">
+                <div class='userbox' style="margin-bottom:10%">
+                    <el-input v-model="user" placeholder="醍摩豆ID/手机号码" prefix-icon="el-icon-user" />
+                </div>
+                <div class='userbox' @click="userlogin">
+                    <el-input v-model="pwd" placeholder="密码" type="password" prefix-icon="el-icon-key" />
+                    <div class="loginbtn" v-show="user !='' && pwd !='' "><img src="@/assets/img/login.png"></div>
+                </div>
+                <div class="not_has_more">
+                    或下列方式登录
+                    <div class="ddlogin" @click="loginModel=false"><img src="../assets/img/ddlogin.png"></div>
+                </div>
+            </div>
+            <div class="usrpwd" v-else-if="loginModel ==false">
+                <ddlogin></ddlogin>
+            </div>
+            <div class="cut" @click="loginModel = !loginModel">
+                <svg width="52" height="52" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" style="border-top-right-radius:10px">
+                    <mask id="id-3757926926-a" width="52" height="52" x="0" y="0" maskUnits="userSpaceOnUse">
+                        <path fill="#fff" d="M0 0l52 52V0H0z"></path>
+                    </mask>
+                    <g mask="url(#id-3757926926-a)">
+                        <path fill="#ccF" d="M0 0h48a4 4 0 014 4v48L0 0z"></path>
+                        <path fill="url(#pattern0)" d="M0 0h52v52H0z"></path>
+                    </g>
+                    <defs>
+                        <pattern id="pattern0" width="1" height="1" patternContentUnits="objectBoundingBox">
+                            <use transform="scale(.00216)" xlink:href="#image0"></use>
+                        </pattern>
+                        <image id="image0" width="463" height="463" :xlink:href="loginImg"></image>
+                    </defs>
+                </svg>
+            </div>
+        </div>
+        <!-- <div id="login_container" style="transform: scale(.8);">123456</div> -->
+        <bind :callbackStatus=callbackStatus v-if="callbackStatus ===1"></bind>
+    </div>
+</template>
+<script>
+import { ref, watch, onMounted } from "vue";
+import ddlogin from "./ddlogin.vue";
+import bind from "./bindPhone.vue";
+import { Dinglogin, loginUser } from "@/api/index.js";
+import { ElMessage } from "element-plus";
+export default {
+    components: {
+        ddlogin,
+        bind,
+    },
+    setup() {
+        let user = ref("");
+        let pwd = ref("");
+        let loginModel = ref(true);
+        let loginImg = ref(require("../assets/img/erweima.png"));
+        var userCode = "";
+        let callbackStatus = ref("abc");
+        onMounted(() => {
+            console.log(window.location.href, "mounted!");
+            if (window.location.href.indexOf("?code") != -1) {
+                userCode = window.location.href.substring(
+                    window.location.href.indexOf("?") + 6,
+                    window.location.href.indexOf("&state")
+                );
+                console.log(userCode);
+                let sss = editState(userCode);
+                console.log(sss, "123456789");
+            }
+        });
+        //处理登录icon变化
+        watch(loginModel, () => {
+            loginImg.value =
+                loginModel.value == true
+                    ? (loginImg.value = require("../assets/img/erweima.png"))
+                    : (loginImg.value = require("../assets/img/mima.png"));
+        });
+        let { editState } = test(userCode);
+        function test() {
+            let editState = (res) => {
+                let datas = { code: res };
+                Dinglogin(datas).then((res) => {
+                    console.log(res, "接口访问成功");
+                    callbackStatus.value = res.status;
+                    localStorage.setItem(
+                        "DingUser",
+                        JSON.stringify(res.dingDingBind)
+                    );
+                    res.status === 1
+                        ? ElMessage("请进行绑定醍摩豆账号操作")
+                        : res.status === 0
+                        ? ElMessage.error("登录错误,非架构内人员禁止使用")
+                        : res.status === 200
+                        ? ElMessage.success("登录成功")
+                        : ElMessage.error("登录异常");
+                });
+            };
+            return {
+                editState,
+            };
+        }
+        //醍摩豆或手机登录
+        function userlogin() {
+            let nonceNum = Math.floor(Math.random() * 10000);
+            console.log(nonceNum, "随机数");
+            let params = {
+                grant_type: "account",
+                client_id: "c7317f88-7cea-4e48-ac57-a16071f7b884",
+                nonce: "habook",
+                account: user.value,
+                password: pwd.value,
+            };
+            loginUser(params).then((res) => {
+                console.log(res, "登录接口返回成功!");
+            });
+        }
+        return {
+            user,
+            pwd,
+            loginModel,
+            loginImg,
+            userCode,
+            editState,
+            callbackStatus,
+            userlogin,
+        };
+    },
+};
+</script>
+<style scoped>
+.backgorundbox {
+    background: url("../assets/img/background1.png") no-repeat;
+    background-size: cover;
+    width: 100vw;
+    height: 100vh;
+    position: relative;
+    /* filter: blur(2px); */
+}
+.loginbox {
+    position: absolute;
+    width: 550px;
+    height: auto;
+    top: 200px;
+    right: 110px;
+    border-radius: 10px;
+    box-shadow: 1px 1px 5px #ccc;
+}
+.usrpwd {
+    height: 330px;
+    text-align: center;
+}
+.logintitle {
+    text-align: center;
+    font-size: 20px;
+    color: #fff;
+    margin-bottom: 8%;
+    margin-top: 5%;
+}
+.userbox {
+    text-align: center;
+    width: 60%;
+    margin: 0 auto;
+    position: relative;
+}
+.none {
+    display: none;
+}
+.loginbtn {
+    position: absolute;
+    display: block;
+    right: 0px;
+    top: 0px;
+    width: 44px;
+    height: 44px;
+    line-height: 43px;
+}
+.not_has_more {
+    margin: 30px 0px 20px 0px;
+    line-height: 50px;
+    text-align: center;
+    position: relative;
+    height: 95px;
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: rgba(140, 142, 165, 1);
+    line-height: 30px;
+}
+.not_has_more::after,
+.not_has_more::before {
+    position: absolute;
+    width: 54px;
+    height: 0.5px;
+    background: #dadada;
+    content: "";
+    top: 15px;
+    right: 28%;
+}
+.not_has_more::after {
+    left: 28%;
+}
+.ddlogin {
+    margin-top: 3%;
+}
+.cut {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+}
+</style>
+<style>
+.userbox .el-input__inner {
+    height: 45px;
+    border-radius: 30px;
+}
+</style>
+

+ 80 - 0
TEAMModeBI/Controllers/AESHelper.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.Controllers.Third.Helpers
+{
+    public class AESHelper
+    {
+
+        /// <summary>
+        /// 有密码的加密 
+        /// </summary>
+        /// <param name="toEncrypt">加密字符</param>
+        /// <param name="key">加密的密码</param>
+        /// <returns></returns>
+        public static string AESEncrypt(string toEncrypt, string key)
+        {
+            byte[] keyArray = hexStringTobyte(key);
+            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
+            RijndaelManaged rDel = new RijndaelManaged();
+            rDel.KeySize = 128;
+            rDel.BlockSize = 128;
+            rDel.Key = keyArray;
+            rDel.Mode = CipherMode.ECB;
+            rDel.Padding = PaddingMode.PKCS7;
+            ICryptoTransform cTransform = rDel.CreateEncryptor();
+            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
+            return byteToHexString(resultArray);
+        }
+
+        /// <summary>
+        /// 解密
+        /// </summary>
+        /// <param name="toDecrypt">解密字符</param>
+        /// <param name="key">加密的密码</param>
+        /// <returns></returns>
+        public static string AESDecrypt(string toDecrypt, string key)
+        {
+            byte[] keyArray = hexStringTobyte(key);
+            byte[] dest = hexStringTobyte(toDecrypt);
+            RijndaelManaged rDel = new RijndaelManaged();
+            rDel.KeySize = 128;
+            rDel.BlockSize = 128;
+            rDel.Key = keyArray;
+            rDel.Mode = CipherMode.ECB;
+            rDel.Padding = PaddingMode.PKCS7;
+            ICryptoTransform cTransform = rDel.CreateDecryptor();
+            byte[] resultArray = cTransform.TransformFinalBlock(dest, 0, dest.Length);
+            return UTF8Encoding.UTF8.GetString(resultArray);
+        }
+
+
+        private static byte[] hexStringTobyte(String s)
+        {
+            if (string.IsNullOrEmpty(s)) return null;
+            s = s.ToLower();
+            int byteArrayLength = s.Length / 2;
+            byte[] b = new byte[byteArrayLength];
+            for (int i = 0; i < byteArrayLength; i++)
+            {
+                byte b0 = Convert.ToByte(s.Substring(i * 2, 2), 16);
+                b[i] = b0;
+            }
+            return b;
+        }
+
+        public static string byteToHexString(byte[] t)
+        {
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < t.Length; i++)
+            {
+                sb.Append(t[i].ToString("x").PadLeft(2, '0'));
+            }
+            return sb.ToString().ToUpper();
+        }
+    }
+}

+ 83 - 0
TEAMModeBI/Controllers/BIHome/HomeStatisController.cs

@@ -0,0 +1,83 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Text.Json;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.Models;
+using Azure.Cosmos;
+using Microsoft.Extensions.Options;
+
+namespace TEAMModeBI.Controllers.BIHome
+{
+    [Route("homestatis")]
+    [ApiController]
+    public class HomeStatisController : ControllerBase
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+
+        public HomeStatisController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option) 
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _option = option?.Value;
+        }
+
+
+        /// <summary>
+        /// 获取人数
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("numberpeople")]
+        public async Task<IActionResult> NumberPeople(JsonElement jsonElement)  
+        {
+            if (!jsonElement.TryGetProperty("schooolId", out JsonElement schoolId)) return BadRequest();
+
+            var client = _azureCosmos.GetCosmosClient();
+
+            //依据学校查询教师人数
+            List<string> teacherCount_list = new();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: $"select c.id from c join S1 in c.schools where S1.schoolId='{schoolId}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") })) 
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0) 
+                {
+                    var accounts = json.RootElement.GetProperty("Documents").EnumerateArray();
+                    while (accounts.MoveNext()) 
+                    {
+                        JsonElement account = accounts.Current;
+                        teacherCount_list.Add(account.GetProperty("id").GetString());
+                    }
+                }
+            }
+
+            //
+            List<string> studentCount_List = new();
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryStreamIterator(queryText: $"select c.id from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{schoolId}") })) 
+            {
+                using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                {
+                    var accounts = json.RootElement.GetProperty("Documents").EnumerateArray();
+                    while (accounts.MoveNext()) 
+                    {
+                        JsonElement account = accounts.Current;
+                        studentCount_List.Add(account.GetProperty("id").GetString());
+                    }
+                }
+            }
+
+
+
+            return Ok(new { SchoolTeacherCount = teacherCount_list.Count });
+
+
+        }
+    }
+}

+ 660 - 0
TEAMModeBI/Controllers/BIHome/StudyStatisController.cs

@@ -0,0 +1,660 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.Models;
+using TEAMModelOS.SDK.Models.Service; //通知
+using Microsoft.Extensions.Configuration;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using TEAMModelOS.SDK.Extension;
+using System.Text.Json;      //获取Json数据引用
+using Azure.Cosmos;
+using TEAMModelOS.Filter;
+using HTEXLib.COMM.Helpers;
+using TEAMModelOS.SDK;
+
+namespace TEAMModeBI.Controllers.BIHome
+{
+    /// <summary>
+    /// 研修数据统计
+    /// </summary>
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [Route("bihome")]
+    [ApiController]
+    public class StudyStatisController : ControllerBase
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly IConfiguration _configuration;
+        private readonly NotificationService _notificationService; //消息通知
+        private readonly DingDing _dingDing; //钉钉消息通知
+        private readonly Option _option;  //记录信息
+
+
+        public StudyStatisController(AzureCosmosFactory azureCosmos,IConfiguration configuration, NotificationService notificationService,DingDing dingDing, IOptionsSnapshot<Option> option) 
+        {
+            _azureCosmos = azureCosmos;
+            _configuration = configuration;
+            _notificationService = notificationService;
+            _dingDing = dingDing;
+            _option = option?.Value;       
+        } 
+
+        [ProducesDefaultResponseType]
+        [HttpPost("get-studyonline-statis")]
+        //[AuthToken(Roles= "teacher,student,admin,area")]
+        public async Task<IActionResult> GetStudyOnLine(JsonElement jsonElement) 
+        {
+            //var (userid, _, _, __school) = HttpContext.GetAuthTokenInfo();//取得token信息
+            try
+            {
+                if (!jsonElement.TryGetProperty("school", out JsonElement school)) return BadRequest();
+                if (!jsonElement.TryGetProperty("areaID", out JsonElement areaID)) return BadRequest();
+                var client = _azureCosmos.GetCosmosClient();
+
+                AreaSetting setting = null; //统计数据
+
+                //查询学校基础信息
+                School schoolBase = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{school}", new PartitionKey("Base"));
+                //获取学校的地区ID
+                string areadid = schoolBase.areaId;
+                //查询区域信息
+                Area area = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Area>($"{areaID}", new PartitionKey("Base-Area"));
+
+                if (area != null) 
+                {
+                    setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
+                }
+
+                if (setting == null)
+                {
+                    setting = new AreaSetting
+                    {
+                        allTime = 50,
+                        classTime = 5,
+                        submitTime = 15,
+                        onlineTime = 20,
+                        offlineTime = 10,
+                        lessonMinutes = 45,
+                    };
+                }
+
+                List<School> schoolList = new List<School>();
+
+                //await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").GetItemQueryIterator<School>(queryText: $"select value(c) from c where c.areaId='{area.id}' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") })) 
+                await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<School>(queryText: $"select value(c) from c where c.areaId='{area.id}' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
+                {
+                    schoolList.Add(item);
+                }
+
+                HashSet<string> dimensions = new HashSet<string>();
+                List<Ability> abilities = new List<Ability>();
+                List<DimensionCount> areaDimensionCount = new List<DimensionCount>();
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Ability>(queryText: $"select c.id,c.name,c.no,c.dimension,c.env from c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Ability-{area.standard}") })) 
+                {
+                    dimensions.Add(item.dimension);
+                    abilities.Add(item);
+                }
+
+                dimensions.ToList().ForEach(x =>
+                {
+                    areaDimensionCount.Add(new DimensionCount { dimension = x, count = 0 });
+                });
+
+                List<string> abilitie_Id = abilities.Select(x => x.id).ToList();
+                List<AbilityCount> areaAbilityCounts = abilities.Select(x => new AbilityCount { abilityEnv = x.env, abilityId = x.id, abilityName = x.name, abilityNo = x.no, dimension = x.dimension, count = 0 }).ToList();
+
+                List<SchoolCount> schoolDatas = new List<SchoolCount>();
+
+                int schoolCount = 0;
+                int teacherCount = 0;
+                //在线时长
+                int videoTime = 0;
+                //参与人数
+                int joinCount = 0;
+                //能力点订阅数量
+                int subCount = 0;
+                //已完成50个学时的人数
+                int ok50TimeCount = 0;
+                //已完成能力点的校园评审数量
+                int hasScoreCount = 0;
+                //已经提交作品的数量
+                int hasSubmitCount = 0;
+                // 未提交的
+                int unSubmitCount = 0;
+                //未完成能力点学习未完成的
+                int unDoneCount = 0;
+                //合格的能力点作品数量
+                int okCount = 0;
+                int schoolVideoTime = 0;
+
+                ///人数
+                //线上完成人数
+                int onlineTeacherCount = 0;
+                //线下完成人数
+                int offlineTeacherCount = 0;
+                //应用考核完成人数
+                int schoolScoreTeacherCount = 0;
+                //课堂实录完成人数
+                int classVideoTeacherCount = 0;
+
+                ///学时
+                //线上完成学时
+                int onlineTeacherTime = 0;
+                //线下完成学时
+                int offlineTeacherTime = 0;
+                //应用考核完成学时
+                int schoolScoreTeacherTime = 0;
+                //课堂实录完成学时
+                int classVideoTeacherTime = 0;
+
+                List<Study> studies = new List<Study>();
+
+                foreach (var schoolitem in schoolList) 
+                {
+                    List<Study> study_list = new List<Study>();
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<Study>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Study-{schoolitem.id}") })) 
+                    {
+                        if (item.tchLists.IsNotEmpty()) 
+                        {
+                            study_list.Add(item);
+                        }
+                    }
+
+                    HashSet<string> groups = new HashSet<string>();
+                    HashSet<string> groupNames = new HashSet<string>();
+                    List<ClassVideo> classVideos = new List<ClassVideo>();
+                    List<AbilitySub> abilitySubs = new List<AbilitySub>();
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ClassVideo>(queryText: $"select value(c)  from c  ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ClassVideo-{schoolitem.id}") }))
+                    {
+                        classVideos.Add(item);
+                    }
+                    List<TchList> tchLists = new List<TchList>();
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TchList>(queryText: $"select value(c) from c  ",
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TchList-{schoolitem.id}") }))
+                    {
+                        groups.Add(item.name);
+                        tchLists.Add(item);
+                    }
+
+                    List<string> ids = tchLists.Select(x => x.id).ToList();
+                    if (!ids.IsNotEmpty())
+                    {
+                        ids.Add("default");
+                    }
+
+                    (List<TmdInfo> tmdInfos, List<ClassListInfo> classInfos) = await TriggerStuActivity.GetTchList(client, _dingDing, ids, $"{schoolitem.id}");
+                    //总人数
+                    int teacherCount1 = tmdInfos.Count;
+
+                    List<TeacherStatistic> groupMembers = new();
+
+                    foreach (var tmd in tmdInfos)
+                    {
+                        await foreach (var sub in client.GetContainer("TEAMModelOS", "Teacher")
+                           .GetItemQueryIterator<AbilitySub>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{schoolitem.id}-{tmd.id}") }))
+                        {
+                            abilitySubs.Add(sub);
+                        }
+
+                        //总学时
+                        int alltime = 0;
+                        //已学习的能力点
+                        int allAbilityCount = 0;
+                        //获得的在线学时
+                        int onlineTime = 0;
+                        //获得的线下学时
+                        int offlinelTime = 0;
+                        //获得的作品提交,并通过学校评审的学时
+                        int schoolScoreTime = 0;
+                        //获得的课堂实录
+                        int classVideoTime = 0;
+                        //教师应提交的作品数量
+                        int tchSubmitCount = 0;
+                        //教师未提交的作品数量
+                        int tchUnSubmitCount = 0;
+                        //通过能力点自测的数量
+                        int hasAbilityExercise = 0;
+                        //教师订阅的能力点数量
+                        int thcSubCount = 0;
+                        //教师完成能力点学校的数量
+                        int thcSubDoneCount = 0;
+                        //参加校本线下研修的活动
+                        int offlineSchoolCount = 0;
+                        //参加区级线下研修的活动
+                        int offlineAreaCount = 0;
+                        //完成的校本线下研修活动
+                        int offlineSchoolDoneCount = 0;
+                        //完成的区级线下研修或的
+                        int offlineAreaDoneCount = 0;
+
+                        int examCount = 0;
+                        int voteCount = 0;
+                        int surveyCount = 0;
+                        int examDoneCount = 0;
+                        int voteDoneCount = 0;
+                        int surveyDoneCount = 0;
+                        int examAreaCount = 0;
+                        int voteAreaCount = 0;
+                        int surveyAreaCount = 0;
+                        int examAreaDoneCount = 0;
+                        int voteAreaDoneCount = 0;
+                        int surveyAreaDoneCount = 0;
+
+                        await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Study' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{tmd.id}") }))
+                        {
+                            if (item.taskStatus > 0)
+                            {
+                                offlinelTime += 1;
+                            }
+                            if (!string.IsNullOrEmpty(item.owner))
+                            {
+                                if (item.owner.Equals("school"))
+                                {
+                                    offlineSchoolCount += 1;
+                                    if (item.taskStatus > 0)
+                                    {
+                                        offlineSchoolDoneCount += 1;
+                                    }
+                                }
+                                else if (item.owner.Equals("area"))
+                                {
+                                    offlineAreaCount += 1;
+                                    if (item.taskStatus > 0)
+                                    {
+                                        offlineAreaDoneCount += 1;
+                                    }
+                                }
+                            }
+                        }
+
+                        await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher") .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'ExamLite' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{tmd.id}") }))
+                        {
+                            if (item.owner.Equals("school"))
+                            {
+                                examCount += 1;
+                                if (item.taskStatus > 0)
+                                {
+                                    examDoneCount += 1;
+                                }
+                            }
+                            if (item.owner.Equals("area"))
+                            {
+                                examAreaCount += 1;
+                                if (item.taskStatus > 0)
+                                {
+                                    examAreaDoneCount += 1;
+                                }
+                            }
+                        }
+
+                        await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher")
+                          .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Survey' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{tmd.id}") }))
+                        {
+                            if (item.owner.Equals("school"))
+                            {
+                                surveyCount += 1;
+                                if (item.taskStatus > 0)
+                                {
+                                    surveyDoneCount += 1;
+                                }
+                            }
+                            if (item.owner.Equals("area"))
+                            {
+                                surveyAreaCount += 1;
+                                if (item.taskStatus > 0)
+                                {
+                                    surveyAreaDoneCount += 1;
+                                }
+                            }
+                        }
+
+                        await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Vote' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{tmd.id}") }))
+                        {
+                            if (item.owner.Equals("school"))
+                            {
+                                voteCount += 1;
+                                if (item.taskStatus > 0)
+                                {
+                                    voteDoneCount += 1;
+                                }
+                            }
+                            if (item.owner.Equals("area"))
+                            {
+                                voteAreaCount += 1;
+                                if (item.taskStatus > 0)
+                                {
+                                    voteAreaDoneCount += 1;
+                                }
+                            }
+                        }
+
+                        bool isJoinVideo = false;
+                        ClassVideo classVideo = classVideos.Find(x => x.id.Equals(tmd.id));
+
+                        if (classVideo != null && classVideo.files.IsNotEmpty())
+                        {
+                            isJoinVideo = true;
+                            classVideo.files.ForEach(x =>
+                            {
+                                if (x.score > 0)
+                                {
+                                    classVideoTime += 1;
+                                }
+                            });
+                        }
+
+                        List<SubStatistic> subs = new();
+                        abilitySubs.Where(x => x.code.Equals($"AbilitySub-{schoolitem.id}-{tmd.id}")).ToList().ForEach(item =>
+                        {
+                            subCount += 1;
+                            thcSubCount += 1;
+                            if (item.exerciseScore > 0) 
+                            {
+                                hasAbilityExercise += 1;
+                            }
+                            if (item.uploads.IsNotEmpty())
+                            {
+                                //已经有作品提交的
+                                hasSubmitCount += 1;
+                                tchSubmitCount += 1;
+                            }
+                            else
+                            {
+                                //未提交作品的
+                                unSubmitCount += 1;
+                                tchUnSubmitCount += 1;
+                            }
+                            if (!item.done)
+                            {
+                                unDoneCount += 1;
+                            }
+                            else
+                            {
+                                thcSubDoneCount += 1;
+                            }
+                            allAbilityCount += item.abilityCount;
+                            //onlineTime += item.hour;
+                            int vtime = (int)item.videoRcds.Sum(x => x.time);
+                            videoTime += vtime;
+                            schoolVideoTime = schoolVideoTime + vtime;
+                            int lesson = vtime / setting.lessonMinutes;
+                            onlineTime += lesson;
+
+                            if (item.otherScore.IsNotEmpty())
+                            {
+                                var schoolScore = item.otherScore.Where(x => x.roleType.Equals("school")).FirstOrDefault();
+
+                                if (schoolScore != null)
+                                {
+                                    if (schoolScore.score > 0)
+                                    {
+                                        okCount += 1;
+                                        schoolScoreTime += 1;
+                                    }
+                                    else
+                                    {
+                                        hasScoreCount += 1;
+                                    }
+                                }
+                            }
+                            Ability ability = abilities.Find(x => x.id.Equals(item.id));
+                            if (ability != null)
+                            {
+                                subs.Add(new SubStatistic
+                                {
+                                    abilityId = item.id,
+                                    code = item.code,
+                                    uploadCount = item.uploads.IsNotEmpty() ? item.uploads.Count : 0,
+                                    otherScoreCount = item.otherScore.IsNotEmpty() ? item.otherScore.Count : 0,
+                                    comidCount = 0,
+                                    self = item.self,
+                                    abilityName = ability.name,
+                                    no = ability.no,
+                                    dimension = ability.dimension,
+                                    env = ability.env
+                                });
+                            }
+                        });
+
+                        //处理单项 超标准 学时 
+                        alltime += onlineTime >= setting.onlineTime ? setting.onlineTime : onlineTime;
+                        alltime += offlinelTime >= setting.offlineTime ? setting.offlineTime : offlinelTime;
+                        alltime += schoolScoreTime >= setting.submitTime ? setting.submitTime : schoolScoreTime;
+                        alltime += classVideoTime >= setting.classTime ? setting.classTime : classVideoTime;
+                        //人数
+                        onlineTeacherCount = onlineTime >= setting.onlineTime ? onlineTeacherCount + 1 : onlineTeacherCount;
+                        offlineTeacherCount = offlinelTime >= setting.offlineTime ? offlineTeacherCount + 1 : offlineTeacherCount;
+                        schoolScoreTeacherCount = schoolScoreTime >= setting.submitTime ? schoolScoreTeacherCount + 1 : schoolScoreTeacherCount;
+                        classVideoTeacherCount = classVideoTime >= setting.classTime ? classVideoTeacherCount + 1 : classVideoTeacherCount;
+                        //学时
+                        onlineTeacherTime = onlineTime >= setting.onlineTime ? onlineTeacherTime + setting.onlineTime : onlineTeacherTime + onlineTime;
+                        offlineTeacherTime = offlinelTime >= setting.offlineTime ? offlineTeacherTime + setting.offlineTime : offlineTeacherTime + offlinelTime;
+                        schoolScoreTeacherTime = schoolScoreTime >= setting.submitTime ? schoolScoreTeacherTime + setting.submitTime : schoolScoreTeacherTime + schoolScoreTime;
+                        classVideoTeacherTime = classVideoTime >= setting.classTime ? classVideoTeacherTime + setting.classTime : classVideoTeacherTime + classVideoTime;
+                        if (alltime >= setting.allTime)
+                        {
+                            ok50TimeCount += 1;
+                        }
+                        var classes = classInfos.Where(y => y.tmdInfos.Select(z => z.id).Contains(tmd.id)).ToList();
+
+                        //表示有订阅,或者有线下活动参与的,或者有课堂实录视频上传的
+                        if (subs.Count > 0 || schoolScoreTime > 0 || isJoinVideo)
+                        {
+                            //参训人数表示
+                            joinCount += 1;
+                            groupMembers.Add(new TeacherStatistic
+                            {
+                                tchSubmitCount = tchSubmitCount,
+                                tchUnSubmitCount = tchUnSubmitCount,
+                                thcSubCount = thcSubCount,
+                                tmdname = tmd.name,
+                                tmdid = tmd.id,
+                                picture = tmd.picture,
+                                groups = classes.Select(x => new TeacherGroup { groupId = x.id, groupName = x.name }).ToList(),
+                                subs = subs,
+                                alltime = alltime,
+                                allAbilityCount = allAbilityCount,
+                                onlineTime = onlineTime,
+                                offlinelTime = offlinelTime,
+                                schoolScoreTime = schoolScoreTime,
+                                classVideoTime = classVideoTime,
+                                hasAbilityExercise = hasAbilityExercise,
+                                thcSubDoneCount = thcSubDoneCount,
+                                offlineSchoolCount = offlineSchoolCount,
+                                offlineAreaCount = offlineAreaCount,
+                                offlineSchoolDoneCount = offlineSchoolDoneCount,
+                                offlineAreaDoneCount = offlineAreaDoneCount,
+                                examCount = examCount,
+                                voteCount = voteCount,
+                                surveyCount = surveyCount,
+                                examDoneCount = examDoneCount,
+                                voteDoneCount = voteDoneCount,
+                                surveyDoneCount = surveyDoneCount,
+                                examAreaCount = examAreaCount,
+                                voteAreaCount = voteAreaCount,
+                                surveyAreaCount = surveyAreaCount,
+                                examAreaDoneCount = examAreaDoneCount,
+                                voteAreaDoneCount = voteAreaDoneCount,
+                                surveyAreaDoneCount = surveyAreaDoneCount,
+                                videoTime = videoTime
+                            });
+                        }
+
+                    }
+                    List<DimensionCount> dimensionCount = new List<DimensionCount>();
+                    foreach (var dms in dimensions)
+                    {
+                        var list = groupMembers.SelectMany(x => x.subs.Where(y => y.dimension.Equals(dms))).ToList();
+                        dimensionCount.Add(new DimensionCount { dimension = dms, count = list.IsNotEmpty() ? list.Count : 0 });
+                    }
+                    List<AbilityCount> abilityCount = new List<AbilityCount>();
+                    foreach (var abilityId in abilitie_Id)
+                    {
+                        var list = groupMembers.SelectMany(x => x.subs.Where(y => y.abilityId.Equals(abilityId))).ToList();
+                        Ability ability = abilities.Find(x => x.id.Equals(abilityId));
+                        abilityCount.Add(new AbilityCount { abilityId = abilityId, abilityName = ability.name, dimension = ability.dimension, abilityNo = ability.no, abilityEnv = ability.env, count = list.IsNotEmpty() ? list.Count : 0 });
+                    }
+                    SchoolCount schoolCountModel = new SchoolCount
+                    {
+                        name = schoolitem.name,
+                        id = schoolitem.id,
+                        picture = schoolitem.picture,
+                        doneCount = ok50TimeCount,
+                        joinCount = joinCount,
+                        teacherCount = teacherCount,
+                        onlineTeacherTime = onlineTeacherTime,
+                        offlineTeacherTime = offlineTeacherTime,
+                        schoolScoreTeacherTime = schoolScoreTeacherTime,
+                        classVideoTeacherTime = classVideoTeacherTime,
+                        onlineTeacherCount = onlineTeacherCount,
+                        offlineTeacherCount = offlineTeacherCount,
+                        schoolScoreTeacherCount = schoolScoreTeacherCount,
+                        classVideoTeacherCount = classVideoTeacherCount,
+                        videoTime = schoolVideoTime
+                    };
+                }
+                Dictionary<string, Study> dict = new Dictionary<string, Study>();
+                studies.ForEach(x => {
+                    dict[x.id] = x;
+                });
+
+                var studyTypes = dict.Values.ToList().GroupBy(x => x.type).Select(y => new { type = y.Key, count = y.Count() });
+                return Ok(new
+                {
+                    setting,
+                    areaDimensionCount,
+                    areaAbilityCounts,
+                    teacherCount,
+                    joinCount,
+                    schoolCount,
+                    videoTime,
+                    schoolDatas,
+                    onlineTeacherCount,
+                    offlineTeacherCount,
+                    schoolScoreTeacherCount,
+                    classVideoTeacherCount,
+                    studyTypes,
+                    onlineTeacherTime,
+                    offlineTeacherTime,
+                    schoolScoreTeacherTime,
+                    classVideoTeacherTime,
+                    ok50TimeCount
+                });             
+
+            }
+            catch (Exception ex)
+            {
+                //await _dingDing.SendBotMsg($"OS,{_option.Location},\n{ex.Message}{ex.StackTrace}{jsonElement.ToJsonString()}{userid}{__school}", GroupNames.醍摩豆服務運維群組);
+                return Ok(new { error = 1 });
+            }
+        }
+
+        public record DimensionCount
+        {
+            public string dimension { get; set; }
+
+            public int count { get; set; }
+        }
+        public record AbilityCount
+        {
+            public string abilityId { get; set; }
+            public string abilityName { get; set; }
+            public string dimension { get; set; }
+            public string abilityNo { get; set; }
+            public string abilityEnv { get; set; }
+            public int count { get; set; }
+        }
+        public record SchoolCount
+        {
+            public string name { get; set; }
+            public string id { get; set; }
+            public string picture { get; set; }
+            public int teacherCount { get; set; }
+            public int joinCount { get; set; }
+            public int doneCount { get; set; }
+            public int videoTime { get; set; }
+            //人数
+            ///线上完成人数
+            public int onlineTeacherCount { get; set; }
+            ///线下完成人数
+            public int offlineTeacherCount { get; set; }
+            ///应用考核完成人数
+            public int schoolScoreTeacherCount { get; set; }
+            //课堂实录完成人数
+            public int classVideoTeacherCount { get; set; }
+
+            ///学时
+            ///线上完成学时
+            public int onlineTeacherTime { get; set; }
+            ///线下完成学时
+            public int offlineTeacherTime { get; set; }
+            ///应用考核完成学时
+            public int schoolScoreTeacherTime { get; set; }
+            //课堂实录完成学时
+            public int classVideoTeacherTime { get; set; }
+        }
+        public record TeacherStatistic
+        {
+            public List<SubStatistic> subs { get; set; }
+            public string tmdname { get; set; }
+            public string tmdid { get; set; }
+            public string picture { get; set; }
+            public List<TeacherGroup> groups { get; set; } = new List<TeacherGroup>();
+            public int alltime { get; set; }
+            public int allAbilityCount { get; set; }
+            public int onlineTime { get; set; }
+            public int offlinelTime { get; set; }
+            public int schoolScoreTime { get; set; }
+            public int classVideoTime { get; set; }
+            public int tchSubmitCount { get; set; }
+            public int tchUnSubmitCount { get; set; }
+            public int thcSubCount { get; set; }
+            public int thcSubDoneCount { get; set; }
+            public int hasAbilityExercise { get; set; }
+            public int onlineCount { get; set; }
+            public int offlineSchoolCount { get; set; }
+            public int offlineAreaCount { get; set; }
+            public int offlineSchoolDoneCount { get; set; }
+            public int offlineAreaDoneCount { get; set; }
+            public int examCount { get; set; }
+            public int voteCount { get; set; }
+            public int surveyCount { get; set; }
+            public int examDoneCount { get; set; }
+            public int voteDoneCount { get; set; }
+            public int surveyDoneCount { get; set; }
+            public int examAreaCount { get; set; }
+            public int voteAreaCount { get; set; }
+            public int surveyAreaCount { get; set; }
+            public int examAreaDoneCount { get; set; }
+            public int voteAreaDoneCount { get; set; }
+            public int surveyAreaDoneCount { get; set; }
+            public int videoTime { get; set; }
+        }
+        public record SubStatistic
+        {
+            public string abilityId { get; set; }
+            public string code { get; set; }
+            public int uploadCount { get; set; }
+            public int otherScoreCount { get; set; }
+            public int self { get; set; }
+            public int comidCount { get; set; }
+            public string abilityName { get; set; }
+            public string no { get; set; }
+            public string dimension { get; set; }
+            public string env { get; set; }
+        }
+        public record TeacherGroup
+        {
+            public string groupName { get; set; }
+            public string groupId { get; set; }
+
+        }
+
+    }
+
+}

+ 109 - 0
TEAMModeBI/Controllers/BISchool/BatchAreaController.cs

@@ -0,0 +1,109 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+
+using DingTalk.Api;
+using DingTalk.Api.Request;
+using DingTalk.Api.Response;
+
+namespace TEAMModeBI.Controllers.BISchool
+{
+    [Route("batcharea")]
+    [ApiController]
+    public class BatchAreaController : ControllerBase
+    {
+
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureStorageFactory _azureStorage;
+
+        public BatchAreaController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _azureStorage = azureStorage;
+            _option = option?.Value;
+        }
+
+        //public async Task<IActionResult> BatchArea(Area area) 
+        //{
+
+        //}
+
+
+        private readonly IConfiguration _configuration;
+        public IActionResult DingDingLogin(string loginTmpCode)
+        {
+            string appKey = _configuration["DingDingAuth:appKey"];
+            string appSecret = _configuration["DingDingAuth:appSecret"];
+            string getuserinfo_bycode = _configuration["DingDingAuth:getuserinfo_bycode"];
+            //判断参数是否为空
+            if (string.IsNullOrEmpty(loginTmpCode))
+            {
+                return BadRequest("temp code error");
+            }
+            //获取access_token
+            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+            OapiGettokenRequest request = new OapiGettokenRequest();
+            request.Appkey = appKey;
+            request.Appsecret = appSecret;
+            request.SetHttpMethod("Get");
+            OapiGettokenResponse response = client.Execute(request);
+            if (response.IsError)
+            {
+                return BadRequest();
+            }
+            string access_token = response.AccessToken;
+            //获取临时授权码 获取授权用户的个人信息
+            DefaultDingTalkClient client1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");
+            OapiSnsGetuserinfoBycodeRequest bycodeRequest = new OapiSnsGetuserinfoBycodeRequest()
+            {
+                //通过扫描二维码,跳转到指定的Url后,向Url中追加Code临时授权码
+                TmpAuthCode = loginTmpCode
+            };
+            OapiSnsGetuserinfoBycodeResponse bycodeResponse = client1.Execute(bycodeRequest, appKey, appSecret);
+            if (bycodeResponse.IsError)
+            {
+                return BadRequest();
+            }
+            //根据unionid获取userid
+            string unionid = bycodeResponse.UserInfo.Unionid;
+            DefaultDingTalkClient clientDingTalkClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid");
+            OapiUserGetbyunionidRequest byunionidRequest = new OapiUserGetbyunionidRequest()
+            {
+                Unionid = unionid
+            };
+            OapiUserGetbyunionidResponse byunionidResponse = clientDingTalkClient.Execute(byunionidRequest, access_token);
+            if (byunionidResponse.IsError)
+            {
+                return BadRequest();
+            }
+            string userid = byunionidResponse.Result.Userid;
+            //根据userId获取用户信息
+            DefaultDingTalkClient clientDingTalkClient2 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
+            OapiV2UserGetRequest getRequest = new OapiV2UserGetRequest()
+            {
+                Userid = userid,
+                Language = "zh_CN"
+            };
+            getRequest.SetHttpMethod("Get");
+            OapiV2UserGetResponse getResponse = clientDingTalkClient2.Execute(getRequest, access_token);
+            if (getResponse.IsError)
+            {
+                return BadRequest();
+            }
+            return Ok(getResponse.Body);
+        }
+
+
+    }
+}

+ 118 - 0
TEAMModeBI/Controllers/BISchool/BatchSchoolController.cs

@@ -0,0 +1,118 @@
+using Azure.Cosmos;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models;
+using static TEAMModelOS.SDK.Models.Teacher;
+
+namespace TEAMModeBI.Controllers.BISchool
+{
+    [Route("batchchool")]
+    [ApiController]
+    public class BatchSchoolController : ControllerBase
+    {
+        private readonly AzureCosmosFactory _azureCosmos;
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+        private readonly AzureStorageFactory _azureStorage;
+
+        public BatchSchoolController(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option)
+        {
+            _azureCosmos = azureCosmos;
+            _dingDing = dingDing;
+            _azureStorage = azureStorage;
+            _option = option?.Value;
+        }
+
+        /// <summary>
+        /// 批量创校  --完成带测验
+        /// </summary>
+        /// <param name="school"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("batchUpsert")]
+        public async Task<IActionResult> batchUpsert(School school,string number)
+        {
+            List<School> school_list = new List<School>();
+            //创建多个学校
+            for (int i = 0; i < int.Parse(number); i++)
+            {
+                string id = $"{school.id}_{i}";
+                var client = _azureCosmos.GetCosmosClient();
+                var schoolContainer = client.GetContainer(Constant.TEAMModelOS, "School");
+                var response = await schoolContainer.ReadItemStreamAsync(id, new PartitionKey($"Base"));
+                if (response.Status == 200)
+                {
+                    string sql = $"select distinct value(c) from c jion A1 in c.schools where A1.schoolID='{id}'";
+                    List<Teacher> teacher_list = new List<Teacher>();
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
+                    {
+                        teacher_list.Add(item);
+                    }
+
+                    foreach (var item in teacher_list)
+                    {
+                        TeacherSchool teacherSchool = item.schools.Find(x => x.schoolId.Equals(id));
+                        if (teacherSchool != null)
+                        {
+                            teacherSchool.name = $"{school.name}_{i}";
+                            teacherSchool.picture = school.picture;
+                            teacherSchool.areaId = school.areaId;
+                        }
+                        await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(item, item.id, new PartitionKey($"Base"));
+                    }
+                    school.id = id;
+                    school = await schoolContainer.UpsertItemAsync(school, new PartitionKey($"Base"));
+                }
+                else
+                {
+                    school.code = "Base";
+                    school.id = $"{school.id}_{i}";
+                    school = await schoolContainer.CreateItemAsync(school,new PartitionKey($"Base"));
+                }
+            }
+
+            ////创一个学校案例
+            //var client = _azureCosmos.GetCosmosClient();
+            //var schoolContainer = client.GetContainer(Constant.TEAMModelOS, "School");
+            //var response = await schoolContainer.ReadItemStreamAsync(school.id, new PartitionKey($"Base"));
+            //if (response.Status == 200)
+            //{
+            //    string sql = $"select distinct value(c) from c jion A1 in c.schools where A1.schoolID='{school.id}'";
+            //    List<Teacher> teacher_list = new List<Teacher>();
+            //    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Teacher>(sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") })) 
+            //    {
+            //        teacher_list.Add(item);
+            //    }
+
+            //    foreach (var item in teacher_list) 
+            //    {
+            //        TeacherSchool teacherSchool = item.schools.Find(x => x.schoolId.Equals(school.id));
+            //        if (teacherSchool != null) 
+            //        {
+            //            teacherSchool.name = school.name;
+            //            teacherSchool.picture = school.picture;
+            //            teacherSchool.areaId = school.areaId;
+            //        }
+            //        await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(item, item.id, new PartitionKey($"Base"));
+            //    }
+            //    school = await schoolContainer.UpsertItemAsync(school, new PartitionKey($"Base"));
+            //}
+            //else 
+            //{
+            //    school.code = "Base";
+            //    school = await schoolContainer.CreateItemAsync(school,new PartitionKey($"Base"));
+            //}
+
+            return Ok(new { school_list });
+        }
+
+
+    }
+}

+ 225 - 0
TEAMModeBI/Controllers/DingDingStruc/DDDeptController.cs

@@ -0,0 +1,225 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Configuration;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.Models;
+using DingTalk.Api;
+using DingTalk.Api.Request;
+using DingTalk.Api.Response;
+using TEAMModelOS.SDK.Models.Cosmos.BI;
+using System.Text.Json;
+using Azure.Cosmos;
+
+namespace TEAMModeBI.Controllers.DingDingStruc
+{
+    [Route("branch")]
+    [ApiController]
+    public class DDDeptController : ControllerBase
+    {
+        private readonly IConfiguration _configuration;
+        //数据容器
+        private readonly AzureCosmosFactory _azureCosmos;
+        //钉钉提示信息
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+
+        public DDDeptController(IConfiguration configuration,AzureCosmosFactory azureCosmos)
+        {
+            _configuration = configuration;
+            _azureCosmos = azureCosmos;
+        }
+
+        #region   从钉钉拿数据存CosmosDB中
+
+        /// <summary>
+        /// 获取部门机构
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-depts")]
+        public async Task<IActionResult> GetDDDepts() 
+        {
+            try
+            {
+                string appKey = _configuration["DingDingAuth:appKey"];
+                string appSecret = _configuration["DingDingAuth:appSecret"];
+                string agentld = _configuration["DingDingAuth:Agentld"];
+
+                //获取access_token
+                DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+                OapiGettokenRequest request = new OapiGettokenRequest() { Appkey = appKey, Appsecret = appSecret };
+                request.SetHttpMethod("Get");
+                OapiGettokenResponse response = client.Execute(request);
+                if (response.IsError)
+                {
+                    return BadRequest();
+                }
+
+                //access_token的有效期为7200秒(2小时),有效期内重复获取会返回相同结果并自动续期,过期后获取会返回新的access_token
+                string access_token = response.AccessToken;
+
+                //获取一级部门列表
+                IDingTalkClient V2departClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
+                OapiV2DepartmentListsubRequest reqPartment1 = new OapiV2DepartmentListsubRequest() { DeptId = 1L, Language = "zh_CN" };
+                OapiV2DepartmentListsubResponse rspPartment1 = V2departClient.Execute(reqPartment1, access_token);
+                if (rspPartment1.IsError)
+                {
+                    return BadRequest();
+                }
+
+                DeptNode deptNodes = new DeptNode();
+                deptNodes.id = agentld;
+                deptNodes.code = "DDPartment";
+                deptNodes.pk = "DDPartment";
+                deptNodes.ttl = -1;
+
+                List<DeptInfo> deptlist = new List<DeptInfo>();
+                if (rspPartment1.Result != null) 
+                {
+                    foreach (var depts in rspPartment1.Result) 
+                    {
+                        DeptInfo deptInfo = new DeptInfo();
+                        deptInfo.id = depts.DeptId;
+                        deptInfo.pid = depts.ParentId;
+                        deptInfo.name = depts.Name;
+
+                        //获取一级部门用户列表
+                        IDingTalkClient userListClient1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
+                        OapiUserListidRequest reqUsers1 = new OapiUserListidRequest() { DeptId = depts.DeptId };
+                        OapiUserListidResponse rspUsers1 = userListClient1.Execute(reqUsers1, access_token);
+                        if (rspUsers1.Result != null)
+                        {
+                            deptInfo.users = rspUsers1.Result.UseridList;
+                        }
+
+                        //获取二级部门列表
+                        OapiV2DepartmentListsubRequest reqPartment2 = new OapiV2DepartmentListsubRequest() { DeptId = depts.DeptId, Language = "zh_CN" };
+                        OapiV2DepartmentListsubResponse rspPartment2 = V2departClient.Execute(reqPartment2, access_token);
+                        if (rspPartment2.Result != null)
+                        {
+                            foreach (var depts2 in rspPartment2.Result)
+                            {
+                                DeptInfo deptInfo2 = new DeptInfo();
+                                deptInfo2.id = depts2.DeptId;
+                                deptInfo2.pid = depts2.ParentId;
+                                deptInfo2.name = depts2.Name;
+
+                                //获取三级部门用户列表
+                                OapiUserListidRequest reqUsers2 = new OapiUserListidRequest() { DeptId = depts2.DeptId };
+                                OapiUserListidResponse rspUsers2 = userListClient1.Execute(reqUsers2, access_token);
+                                if (rspUsers2.Result != null)
+                                {
+                                    //添加三级部门用户
+                                    deptInfo2.users = rspUsers2.Result.UseridList;
+                                }
+
+                                //获取三级部门列表
+                                OapiV2DepartmentListsubRequest reqPartment3 = new OapiV2DepartmentListsubRequest() { DeptId = depts2.DeptId, Language = "zh_CN" };
+                                OapiV2DepartmentListsubResponse rspPartment3 = V2departClient.Execute(reqPartment3, access_token);
+                                if (rspPartment3.Result != null) 
+                                {
+                                    foreach (var depts3 in rspPartment3.Result) 
+                                    {
+                                        DeptInfo deptInfo3 = new DeptInfo();
+                                        deptInfo3.id = depts3.DeptId;
+                                        deptInfo3.pid = depts3.ParentId;
+                                        deptInfo3.name = depts3.Name;
+
+                                        //获取三级部门用户列表
+                                        OapiUserListidRequest reqUsers3 = new OapiUserListidRequest() { DeptId = depts3.DeptId };
+                                        OapiUserListidResponse rspUsers3 = userListClient1.Execute(reqUsers3, access_token);
+                                        if (rspUsers3.Result != null)
+                                        {
+                                            //添加三级部门用户
+                                            deptInfo3.users = rspUsers3.Result.UseridList;
+                                        }
+
+                                        //获取四级部门列表
+                                        OapiV2DepartmentListsubRequest reqPartment4 = new OapiV2DepartmentListsubRequest() { DeptId = depts3.DeptId, Language = "zh_CN" };
+                                        OapiV2DepartmentListsubResponse rspPartment4 = V2departClient.Execute(reqPartment4, access_token);
+                                        if (rspPartment4.Result != null)
+                                        {
+                                            foreach (var depts4 in rspPartment4.Result)
+                                            {
+                                                DeptInfo deptInfo4 = new DeptInfo();
+                                                deptInfo4.id = depts4.DeptId;
+                                                deptInfo4.pid = depts4.ParentId;
+                                                deptInfo4.name = depts4.Name;
+
+                                                //获取四级部门用户列表
+                                                OapiUserListidRequest reqUsers4 = new OapiUserListidRequest() { DeptId = depts4.DeptId };
+                                                OapiUserListidResponse rspUsers4 = userListClient1.Execute(reqUsers4, access_token);
+                                                if (rspUsers4.Result != null)
+                                                {
+                                                    //添加四级部门用户
+                                                    deptInfo4.users = rspUsers4.Result.UseridList;
+                                                }
+
+                                                deptlist.Add(deptInfo4);
+                                            }                                        
+                                        }
+                                        deptlist.Add(deptInfo3);
+                                    }
+                                }
+                                deptlist.Add(deptInfo2);
+                            }
+                        }
+                        deptlist.Add(deptInfo);
+                    }
+                }
+                deptNodes.depts = deptlist;
+                await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Normal").CreateItemAsync<DeptNode>(deptNodes, new Azure.Cosmos.PartitionKey($"DDPartment"));
+
+                return Ok(new { state = 200, message = "钉钉的组织架构添加到数据库成功", deptNodes = deptNodes });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { state = 1, message = $"访问失败!状态:{ex.StackTrace} 错误:{ex.Message}" });
+            }
+        }
+
+        #endregion  
+
+        #region 从数据库获取(设置、修改、)钉钉组织架构信息
+
+        /// <summary>
+        /// 依据当前部门编号获取下级部门信息
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-partment")]
+        public async Task<IActionResult> GetPartment(JsonElement jsonElement)
+        {
+            try
+            {
+                if (!jsonElement.TryGetProperty("pid", out JsonElement pid)) return BadRequest();
+
+                var client = _azureCosmos.GetCosmosClient();              
+                List<DeptInfo> deptInfos = new List<DeptInfo>();
+                string sqltxt = $"select a1.id,a1.pid,a1.name,a1.users from c join a1 IN c.depts where a1.pid={pid}";
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<DeptInfo>(queryText: sqltxt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("DDPartment") }))
+                {
+                    deptInfos.Add(item);
+                }
+
+                return Ok(new { state = 200, deptInfos });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { state = 1, message = $"访问失败! 状态:{ex.StackTrace} 错误:{ex.Message}" });
+            }
+        }
+
+
+
+
+
+
+        #endregion
+    }
+}

+ 17 - 0
TEAMModeBI/Controllers/DingDingStruc/DDPowerController.cs

@@ -0,0 +1,17 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace TEAMModeBI.Controllers.DingDingStruc
+{
+    [Route("power")]
+    [ApiController]
+    public class DDPowerController : ControllerBase
+    {
+        //public 
+
+    }
+}

+ 530 - 0
TEAMModeBI/Controllers/DingDingStruc/DDStructController.cs

@@ -0,0 +1,530 @@
+using DingTalk.Api;
+using DingTalk.Api.Request;
+using DingTalk.Api.Response;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.Models;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Models.Service;
+
+namespace TEAMModeBI.Controllers.DingDingStruc
+{
+    [Route("dd")]
+    [ApiController]
+    public class DDStructController : ControllerBase
+    {
+        private readonly IConfiguration _configuration;
+        //数据容器
+        private readonly AzureCosmosFactory _azureCosmos;
+        //文件容器
+        private readonly AzureStorageFactory _azureStorage;
+        //钉钉提示信息
+        private readonly DingDing _dingDing;
+        private readonly Option _option;
+
+        public DDStructController(IConfiguration configuration, AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option, CoreAPIHttpService aoreAPIHttpService)
+        {
+            _configuration = configuration;
+            _azureCosmos = azureCosmos;
+            _azureStorage = azureStorage;
+            _dingDing = dingDing;
+            _option = option?.Value;
+        }
+
+        /// <summary>
+        /// 获取组织架构列表
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("ddminstruc")]
+        public async Task<IActionResult> DDMainStruc()
+        {
+            string str_appKey = _configuration["DingDingAuth:appKey"];
+            string str_appSecret = _configuration["DingDingAuth:appSecret"];
+
+            //获取企业内部应用的accessToken
+            IDingTalkClient Iclient = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+            OapiGettokenRequest request = new OapiGettokenRequest();
+            request.Appkey = str_appKey;
+            request.Appsecret = str_appSecret;
+            request.SetHttpMethod("GET");
+            OapiGettokenResponse tokenResponse = Iclient.Execute(request);
+            if (tokenResponse.IsError)
+            {
+                return Ok(new { status = 0, message = "请检查配置" });
+            }
+            string access_token1 = tokenResponse.AccessToken;
+            IDingTalkClient dingTalkClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/org/union/trunk/get");
+            OapiOrgUnionTrunkGetRequest oapiOrgUnionTrunkGetRequest = new OapiOrgUnionTrunkGetRequest();
+            OapiOrgUnionTrunkGetResponse oapiOrgUnionTrunkGetResponse = dingTalkClient.Execute(oapiOrgUnionTrunkGetRequest, tokenResponse.AccessToken);
+
+            return Ok(new { oapiOrgUnionTrunkGetResponse.RequestId , oapiOrgUnionTrunkGetResponse.Body, oapiOrgUnionTrunkGetResponse.Result });
+
+        }
+
+        /// <summary>
+        /// 获取分支组织列表信息
+        /// </summary>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("ddbranchstruc")]
+        public async Task<IActionResult> DDBranchStruc()
+        {
+            string str_appKey = _configuration["DingDingAuth:appKey"];
+            string str_appSecret = _configuration["DingDingAuth:appSecret"];
+
+            //获取企业内部应用的accessToken
+            IDingTalkClient Iclient = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+            OapiGettokenRequest request = new OapiGettokenRequest();
+            request.Appkey = str_appKey;
+            request.Appsecret = str_appSecret;
+            request.SetHttpMethod("GET");
+            OapiGettokenResponse tokenResponse = Iclient.Execute(request);
+            if (tokenResponse.IsError)
+            {
+                return Ok(new { status = 0, message = "请检查配置" });
+            }
+            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/org/union/branch/get");
+            OapiOrgUnionBranchGetRequest req = new OapiOrgUnionBranchGetRequest();
+            OapiOrgUnionBranchGetResponse rsp = client.Execute(req, tokenResponse.AccessToken);
+
+
+            return Ok(new { Result = rsp.Result, Body = rsp.Body, RequestId = rsp.RequestId, SubErrCode = rsp.SubErrCode, Success = rsp.Success });
+        }
+
+
+        /// <summary>
+        /// 获取企业部门列表
+        /// </summary>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-deptlist")]
+        public async Task<IActionResult>  GetDeptList()
+        {
+            try
+            {
+                string appKey = _configuration["DingDingAuth:appKey"];
+                string appSecret = _configuration["DingDingAuth:appSecret"];
+
+                //获取access_token
+                DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+                OapiGettokenRequest request = new OapiGettokenRequest();
+                request.Appkey = appKey;
+                request.Appsecret = appSecret;
+                request.SetHttpMethod("Get");
+                OapiGettokenResponse response = client.Execute(request);
+                if (response.IsError)
+                {
+                    return BadRequest();
+                }
+
+                //access_token的有效期为7200秒(2小时),有效期内重复获取会返回相同结果并自动续期,过期后获取会返回新的access_token
+                string access_token = response.AccessToken;
+
+                //获取一级部门列表
+                IDingTalkClient v2ListsubClient1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
+                OapiV2DepartmentListsubRequest reqlistsub1 = new OapiV2DepartmentListsubRequest() { DeptId = 1L, Language = "zh_CN" };
+                OapiV2DepartmentListsubResponse rsplistsub1 = v2ListsubClient1.Execute(reqlistsub1, access_token);
+                List<DeptInfo> templsit = new List<DeptInfo>();
+
+                if (rsplistsub1.Result != null)
+                {
+                    foreach (var deptList in rsplistsub1.Result)
+                    {
+                        DeptInfo deptInfo = new DeptInfo();
+                        deptInfo.deptId = deptList.DeptId;
+                        deptInfo.deptName = deptList.Name;
+                        deptInfo.parentId = deptList.ParentId;
+
+                        //获取一级部门用户列表
+                        IDingTalkClient userListClient1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
+                        OapiUserListidRequest reqUserList1 = new OapiUserListidRequest() { DeptId = deptList.DeptId };
+                        OapiUserListidResponse rspUserList1 = userListClient1.Execute(reqUserList1, access_token);
+                        if (rspUserList1.Result != null)
+                        {
+                            deptInfo.ddUserList = rspUserList1.Result.UseridList;
+                        }
+
+                        //获取用户详细信息
+                        IDingTalkClient v2UserListClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
+                        OapiV2UserGetRequest reqv2UserList = new OapiV2UserGetRequest();
+                        OapiV2UserGetResponse rspv2UserList = v2UserListClient.Execute(reqv2UserList, access_token);
+
+                        //获取二级部门列表
+                        OapiV2DepartmentListsubRequest reqlistsub = new OapiV2DepartmentListsubRequest() { DeptId = deptList.DeptId, Language = "zh_CN" };
+                        OapiV2DepartmentListsubResponse rsplistsub = v2ListsubClient1.Execute(reqlistsub, access_token);
+
+                        List<DeptBaseResponseDomain> deptBaseResponseDomainList = new List<DeptBaseResponseDomain>();
+                        if (rsplistsub.Result != null)
+                        {
+                            foreach (var deptlist2 in rsplistsub.Result)
+                            {
+                                //添加二级部门
+                                DeptBaseResponseDomain deptBaseResponseDomain2 = new DeptBaseResponseDomain();
+                                deptBaseResponseDomain2.deptId = deptlist2.DeptId;
+                                deptBaseResponseDomain2.Name = deptlist2.Name;
+                                deptBaseResponseDomain2.ParentId = deptlist2.ParentId;
+
+                                //获取三级部门用户列表
+                                OapiUserListidRequest reqUserList2 = new OapiUserListidRequest() { DeptId = deptlist2.DeptId };
+                                OapiUserListidResponse rspUserList2 = userListClient1.Execute(reqUserList2, access_token);
+                                if (rspUserList2.Result != null)
+                                {
+                                    //添加三级部门用户
+                                    deptBaseResponseDomain2.ddUserList = rspUserList2.Result.UseridList;
+                                }
+                                //获取三级部门列表
+                                OapiV2DepartmentListsubRequest reqlistsub3 = new OapiV2DepartmentListsubRequest() { DeptId = deptlist2.DeptId, Language = "zh_CN" };
+                                OapiV2DepartmentListsubResponse rsplistsub3 = v2ListsubClient1.Execute(reqlistsub3, access_token);
+
+                                List<DeptBaseResponseDomain> deptBaseResponseDomain3List = new List<DeptBaseResponseDomain>();
+
+                                if (rsplistsub3.Result != null)
+                                {
+                                    foreach (var dept3List in rsplistsub3.Result)
+                                    {
+                                        //添加三级部门
+                                        DeptBaseResponseDomain deptBaseResponseDomain3 = new DeptBaseResponseDomain();
+                                        deptBaseResponseDomain3.deptId = dept3List.DeptId;
+                                        deptBaseResponseDomain3.Name = dept3List.Name;
+                                        deptBaseResponseDomain3.ParentId = dept3List.ParentId;
+
+                                        //获取部门用户列表
+                                        OapiUserListidRequest reqUserList3 = new OapiUserListidRequest() { DeptId = dept3List.DeptId };
+                                        OapiUserListidResponse rspUserList3 = userListClient1.Execute(reqUserList3, access_token);
+                                        if (rspUserList3.Result != null)
+                                        {
+                                            //添加三级部门的用户
+                                            deptBaseResponseDomain3.ddUserList = rspUserList3.Result.UseridList;
+                                        }
+
+                                        //获取部门列表  四级目录
+                                        OapiV2DepartmentListsubRequest reqlistsub4 = new OapiV2DepartmentListsubRequest() { DeptId = dept3List.DeptId, Language = "zh_CN" };
+                                        OapiV2DepartmentListsubResponse rsplistsu4 = v2ListsubClient1.Execute(reqlistsub4, access_token);
+
+                                        List<DeptBaseResponseDomain> deptBaseResponseDomain4List = new List<DeptBaseResponseDomain>();
+                                        if (rsplistsu4.Result != null)
+                                        {
+
+                                            foreach (var dept4List in rsplistsu4.Result)
+                                            {
+                                                DeptBaseResponseDomain deptBaseResponseDomain4 = new DeptBaseResponseDomain();
+                                                deptBaseResponseDomain4.deptId = dept4List.DeptId;
+                                                deptBaseResponseDomain4.Name = dept4List.Name;
+                                                deptBaseResponseDomain4.ParentId = dept4List.ParentId;
+                                                deptBaseResponseDomain4List.Add(deptBaseResponseDomain4);
+
+                                                //获取三级部门用户列表
+                                                OapiUserListidRequest reqUserList4 = new OapiUserListidRequest() { DeptId = dept4List.DeptId };
+                                                OapiUserListidResponse rspUserList4 = userListClient1.Execute(reqUserList4, access_token);
+                                                if (rspUserList4.Result != null)
+                                                {
+                                                    //添加四级部门的用户
+                                                    deptBaseResponseDomain4.ddUserList = rspUserList4.Result.UseridList;
+                                                }
+                                            }
+                                        }
+                                        //添加四级部门列表
+                                        deptBaseResponseDomain3.LowerDeip_List = deptBaseResponseDomain4List;
+                                        deptBaseResponseDomain3List.Add(deptBaseResponseDomain3);
+                                    }
+                                }
+                                //添加三级部门列表
+                                deptBaseResponseDomain2.LowerDeip_List = deptBaseResponseDomain3List;
+                                deptBaseResponseDomainList.Add(deptBaseResponseDomain2);
+                            }
+                        }
+                        //添加二级部门列表
+                        deptInfo.deptList = deptBaseResponseDomainList;
+                        templsit.Add(deptInfo);
+                    }
+                }
+                return Ok(new { state = 200, deptlist = templsit });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { state = 1, message=$"查询失败!:状态:{ex.StackTrace}错误:{ex.Message}" }) ;
+            }
+        }
+
+        /// <summary>
+        /// 获取当前用户的父级集合
+        /// </summary>
+        /// <param name="jsonElement"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-parentdept")]
+        public async Task<IActionResult> GetParentDept(JsonElement jsonElement) 
+        {
+            try
+            {
+                if (!jsonElement.TryGetProperty("userId", out JsonElement userId)) return Ok(new { state = 1, message = "参数错误!" });
+
+                string appKey = _configuration["DingDingAuth:appKey"];
+                string appSecret = _configuration["DingDingAuth:appSecret"];
+
+                //获取access_token
+                DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+                OapiGettokenRequest request = new OapiGettokenRequest();
+                request.Appkey = appKey;
+                request.Appsecret = appSecret;
+                request.SetHttpMethod("Get");
+                OapiGettokenResponse response = client.Execute(request);
+                if (response.IsError)
+                {
+                    return BadRequest();
+                }
+
+                //access_token的有效期为7200秒(2小时),有效期内重复获取会返回相同结果并自动续期,过期后获取会返回新的access_token
+                string access_token = response.AccessToken; 
+
+                IDingTalkClient v2DeartDeptClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listparentbyuser");
+                OapiV2DepartmentListparentbyuserRequest reqDeartDept = new OapiV2DepartmentListparentbyuserRequest() { Userid = userId.ToString() };
+                OapiV2DepartmentListparentbyuserResponse rspDeartDept = v2DeartDeptClient.Execute(reqDeartDept, access_token);
+
+                if (rspDeartDept.Result != null)
+                {
+                    List<long> userParentDept = new List<long>();
+                    //var parentDept = rspDeartDept.Result.ParentList;
+                    foreach (var temp in rspDeartDept.Result.ParentList)
+                    {
+                        foreach (var deptTemp in temp.ParentDeptIdList)
+                        {
+                            userParentDept.Add(deptTemp);
+                        }
+                    }
+
+                    return Ok(new { state = 200, parentList = userParentDept });
+                }
+
+                return Ok(new { state = 2, message = "访问失败!" });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { state = 2, message = $"访问失败!状态:{ex.StackTrace} 错误:{ex.Message}" });
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <returns></returns>
+        public async Task<IActionResult> SetDeptList(JsonElement jsonElement) 
+        {
+            try
+            {
+                string appKey = _configuration["DingDingAuth:appKey"];
+                string appSecret = _configuration["DingDingAuth:appSecret"];
+
+                //获取access_token
+                DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
+                OapiGettokenRequest request = new OapiGettokenRequest();
+                request.Appkey = appKey;
+                request.Appsecret = appSecret;
+                request.SetHttpMethod("Get");
+                OapiGettokenResponse response = client.Execute(request);
+                if (response.IsError)
+                {
+                    return BadRequest();
+                }
+
+                //access_token的有效期为7200秒(2小时),有效期内重复获取会返回相同结果并自动续期,过期后获取会返回新的access_token
+                string access_token = response.AccessToken;
+
+                //获取部门列表 一级目录
+                IDingTalkClient v2ListsubClient1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
+                OapiV2DepartmentListsubRequest reqlistsub1 = new OapiV2DepartmentListsubRequest() { DeptId = 1L, Language = "zh_CN" };
+                OapiV2DepartmentListsubResponse rsplistsub1 = v2ListsubClient1.Execute(reqlistsub1, access_token);
+                List<DeptInfo> templsit = new List<DeptInfo>();
+
+                if (rsplistsub1.Result != null)
+                {
+                    foreach (var deptList in rsplistsub1.Result)
+                    {
+                        DeptInfo deptInfo = new DeptInfo();
+                        deptInfo.deptId = deptList.DeptId;
+                        deptInfo.deptName = deptList.Name;
+                        deptInfo.parentId = deptList.ParentId;
+
+                        //获取一级部门用户列表
+                        IDingTalkClient userListClient1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
+                        OapiUserListidRequest reqUserList1 = new OapiUserListidRequest() { DeptId = deptList.DeptId };
+                        OapiUserListidResponse rspUserList1 = userListClient1.Execute(reqUserList1, access_token);
+                        if (rspUserList1.Result != null)
+                        {
+                            deptInfo.ddUserList = rspUserList1.Result.UseridList;
+                        }
+
+                        //获取用户详细信息
+                        IDingTalkClient v2UserListClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
+                        OapiV2UserGetRequest reqv2UserList = new OapiV2UserGetRequest();
+                        OapiV2UserGetResponse rspv2UserList = v2UserListClient.Execute(reqv2UserList, access_token);
+
+                        //获取二级部门列表
+                        OapiV2DepartmentListsubRequest reqlistsub = new OapiV2DepartmentListsubRequest() { DeptId = deptList.DeptId, Language = "zh_CN" };
+                        OapiV2DepartmentListsubResponse rsplistsub = v2ListsubClient1.Execute(reqlistsub, access_token);
+
+                        List<DeptBaseResponseDomain> deptBaseResponseDomainList = new List<DeptBaseResponseDomain>();
+                        if (rsplistsub.Result != null)
+                        {
+                            foreach (var deptlist2 in rsplistsub.Result)
+                            {
+                                //添加二级部门
+                                DeptBaseResponseDomain deptBaseResponseDomain2 = new DeptBaseResponseDomain();
+                                deptBaseResponseDomain2.deptId = deptlist2.DeptId;
+                                deptBaseResponseDomain2.Name = deptlist2.Name;
+                                deptBaseResponseDomain2.ParentId = deptlist2.ParentId;
+
+                                //获取三级部门用户列表
+                                OapiUserListidRequest reqUserList2 = new OapiUserListidRequest() { DeptId = deptlist2.DeptId };
+                                OapiUserListidResponse rspUserList2 = userListClient1.Execute(reqUserList2, access_token);
+                                if (rspUserList2.Result != null)
+                                {
+                                    //添加三级部门用户
+                                    deptBaseResponseDomain2.ddUserList = rspUserList2.Result.UseridList;
+                                }
+                                //获取三级部门列表
+                                OapiV2DepartmentListsubRequest reqlistsub3 = new OapiV2DepartmentListsubRequest() { DeptId = deptlist2.DeptId, Language = "zh_CN" };
+                                OapiV2DepartmentListsubResponse rsplistsub3 = v2ListsubClient1.Execute(reqlistsub3, access_token);
+
+                                List<DeptBaseResponseDomain> deptBaseResponseDomain3List = new List<DeptBaseResponseDomain>();
+
+                                if (rsplistsub3.Result != null)
+                                {
+                                    foreach (var dept3List in rsplistsub3.Result)
+                                    {
+                                        //添加三级部门
+                                        DeptBaseResponseDomain deptBaseResponseDomain3 = new DeptBaseResponseDomain();
+                                        deptBaseResponseDomain3.deptId = dept3List.DeptId;
+                                        deptBaseResponseDomain3.Name = dept3List.Name;
+                                        deptBaseResponseDomain3.ParentId = dept3List.ParentId;
+
+                                        //获取部门用户列表
+                                        OapiUserListidRequest reqUserList3 = new OapiUserListidRequest() { DeptId = dept3List.DeptId };
+                                        OapiUserListidResponse rspUserList3 = userListClient1.Execute(reqUserList3, access_token);
+                                        if (rspUserList3.Result != null)
+                                        {
+                                            //添加三级部门的用户
+                                            deptBaseResponseDomain3.ddUserList = rspUserList3.Result.UseridList;
+                                        }
+
+                                        //获取部门列表  四级目录
+                                        OapiV2DepartmentListsubRequest reqlistsub4 = new OapiV2DepartmentListsubRequest() { DeptId = dept3List.DeptId, Language = "zh_CN" };
+                                        OapiV2DepartmentListsubResponse rsplistsu4 = v2ListsubClient1.Execute(reqlistsub4, access_token);
+
+                                        List<DeptBaseResponseDomain> deptBaseResponseDomain4List = new List<DeptBaseResponseDomain>();
+                                        if (rsplistsu4.Result != null)
+                                        {
+
+                                            foreach (var dept4List in rsplistsu4.Result)
+                                            {
+                                                DeptBaseResponseDomain deptBaseResponseDomain4 = new DeptBaseResponseDomain();
+                                                deptBaseResponseDomain4.deptId = dept4List.DeptId;
+                                                deptBaseResponseDomain4.Name = dept4List.Name;
+                                                deptBaseResponseDomain4.ParentId = dept4List.ParentId;
+                                                deptBaseResponseDomain4List.Add(deptBaseResponseDomain4);
+
+                                                //获取三级部门用户列表
+                                                OapiUserListidRequest reqUserList4 = new OapiUserListidRequest() { DeptId = dept4List.DeptId };
+                                                OapiUserListidResponse rspUserList4 = userListClient1.Execute(reqUserList4, access_token);
+                                                if (rspUserList4.Result != null)
+                                                {
+                                                    //添加四级部门的用户
+                                                    deptBaseResponseDomain4.ddUserList = rspUserList4.Result.UseridList;
+                                                }
+                                            }
+                                        }
+                                        //添加四级部门列表
+                                        deptBaseResponseDomain3.LowerDeip_List = deptBaseResponseDomain4List;
+                                        deptBaseResponseDomain3List.Add(deptBaseResponseDomain3);
+                                    }
+                                }
+                                //添加三级部门列表
+                                deptBaseResponseDomain2.LowerDeip_List = deptBaseResponseDomain3List;
+                                deptBaseResponseDomainList.Add(deptBaseResponseDomain2);
+                            }
+                        }
+                        //添加二级部门列表
+                        deptInfo.deptList = deptBaseResponseDomainList;
+                        templsit.Add(deptInfo);
+                    }
+                }
+                return Ok(new { state = 200, deptlist = templsit });
+            }
+            catch (Exception ex)
+            {
+                return Ok(new { state = 1, message = $"查询失败!:状态:{ex.StackTrace}错误:{ex.Message}" });
+            }
+        }
+
+
+
+
+
+        public record DeptInfo 
+        {
+            /// <summary>
+            /// 部门ID
+            /// </summary>
+            public long deptId { get; set; }
+
+            /// <summary>
+            /// 部门名称
+            /// </summary>
+            public string deptName { get; set; }
+
+            /// <summary>
+            /// 父部门id,根部门为1
+            /// </summary>
+            public long parentId { get; set; }
+
+            /// <summary>
+            /// 部门集合
+            /// </summary>
+            public List<DeptBaseResponseDomain> deptList { get; set; }
+
+            /// <summary>
+            /// 钉钉用户列表
+            /// </summary>
+            public List<string> ddUserList { get; set; }
+
+
+        }
+
+        public record DeptBaseResponseDomain 
+        {
+            /// <summary>
+            /// 部门ID
+            /// </summary>
+            public long deptId { get; set; }
+
+            /// <summary>
+            /// 部门名称
+            /// </summary>
+            public string Name { get; set; }
+
+            /// <summary>
+            /// 父部门ID
+            /// </summary>
+            public long ParentId { get; set; }
+
+            /// <summary>
+            /// 下级列表
+            /// </summary>
+            public List<DeptBaseResponseDomain> LowerDeip_List { get; set; }
+
+            /// <summary>
+            /// 钉钉用户列表
+            /// </summary>
+            public List<string> ddUserList { get; set; }
+
+        }
+
+    }
+}

File diff suppressed because it is too large
+ 796 - 15
TEAMModeBI/Controllers/LoginController.cs


+ 57 - 0
TEAMModeBI/Controllers/SchoolSettingController.cs

@@ -0,0 +1,57 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Helper.Common.StringHelper;
+
+namespace TEAMModeBI
+{
+    [ProducesResponseType(StatusCodes.Status200OK)]
+    [ProducesResponseType(StatusCodes.Status400BadRequest)]
+    [Route("school-setting")]
+    [ApiController]
+    public class SchoolSettingController : ControllerBase
+    {
+        private readonly IConfiguration _configuration;
+        public SchoolSettingController(IConfiguration configuration)
+        {
+            _configuration = configuration;
+        }
+        ///<summary>
+        ///查询教师的阅卷任务列表
+        /// </summary>
+        /// <data>
+        ///    ! "code":"tmdid"
+        /// </data>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("convert")]
+        // [AuthToken(Roles = "teacher,admin")]
+        public async Task<IActionResult> convert(JsonElement request) {
+            Dictionary<string, Tuple<string, string>> dict = new
+               Dictionary<string, Tuple<string, string>>() {
+            {"梅钰", new Tuple<string,string>( "meiyu","MY")},
+            {"张洺", new Tuple<string,string>( "zhangming","ZM")},
+            {"王玥", new Tuple<string,string>( "wangyue","WY")},
+            {"王思琪", new Tuple<string,string>( "wangsiqi","WSQ")},
+            {"董云强", new Tuple<string,string>( "dongyunqiang","DYQ")},
+            {"宋红培", new Tuple<string,string>( "songhongpei","SHP")},
+            {"叧叨叭叱叴叵叺", new Tuple<string,string>( "shilei","SL")},
+            };
+            List<string> di = new List<string>();
+            foreach (var keyval in dict) {
+                string f=  PingYinHelper.GetFirstSpell(keyval.Key);
+                di.Add(f);
+                string a = PingYinHelper.ConvertToAllSpell(keyval.Key);
+                di.Add(a);
+            }
+            return   Ok(di);
+        }
+
+    }
+}

+ 0 - 40
TEAMModeBI/Controllers/WeatherForecastController.cs

@@ -1,40 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace TEAMModeBI.Controllers
-{
-    //
-    [ApiController]
-    [Route("[controller]")]
-    public class WeatherForecastController : ControllerBase
-    {
-        private static readonly string[] Summaries = new[]
-        {
-            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
-        };
-
-        private readonly ILogger<WeatherForecastController> _logger;
-
-        public WeatherForecastController(ILogger<WeatherForecastController> logger)
-        {
-            _logger = logger;
-        }
-
-        [HttpGet]
-        public IEnumerable<WeatherForecast> Get()
-        {
-            var rng = new Random();
-            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
-            {
-                Date = DateTime.Now.AddDays(index),
-                TemperatureC = rng.Next(-20, 55),
-                Summary = Summaries[rng.Next(Summaries.Length)]
-            })
-            .ToArray();
-        }
-    }
-}

+ 6 - 2
TEAMModeBI/Program.cs

@@ -4,18 +4,22 @@ using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
+using System.Net;
 using System.Threading.Tasks;
+using TEAMModelOS.Controllers.Third.Helpers;
+using TEAMModelOS.SDK.Extension;
+using System.Text;
 
 namespace TEAMModeBI
 {
     public class Program
-    {
+    {     
         public static void Main(string[] args)
         {
             CreateHostBuilder(args).Build().Run();
         }
-
         public static IHostBuilder CreateHostBuilder(string[] args) =>
             Host.CreateDefaultBuilder(args)
                 .ConfigureWebHostDefaults(webBuilder =>

+ 3 - 4
TEAMModeBI/Properties/launchSettings.json

@@ -3,8 +3,8 @@
     "windowsAuthentication": false,
     "anonymousAuthentication": true,
     "iisExpress": {
-      "applicationUrl": "http://localhost:50598",
-      "sslPort": 0
+      "applicationUrl": "http://localhost:61874/",
+      "sslPort": 44335
     }
   },
   "$schema": "http://json.schemastore.org/launchsettings.json",
@@ -19,11 +19,10 @@
     "TEAMModeBI": {
       "commandName": "Project",
       "launchBrowser": true,
-      "launchUrl": "weatherforecast",
       "environmentVariables": {
         "ASPNETCORE_ENVIRONMENT": "Development"
       },
-      "applicationUrl": "http://localhost:5000"
+      "applicationUrl": "https://localhost:5001;http://localhost:5000"
     }
   }
 }

+ 99 - 27
TEAMModeBI/Startup.cs

@@ -1,7 +1,10 @@
+using Lib.AspNetCore.ServerSentEvents;
 using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.SpaServices;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
@@ -12,9 +15,10 @@ using System.Collections.Generic;
 using System.IdentityModel.Tokens.Jwt;
 using System.Linq;
 using System.Threading.Tasks;
+using TEAMModelOS.Filter;
 using TEAMModelOS.Models;
-using TEAMModelOS.SDK.Context.Configuration;
 using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models.Service;
 using VueCliMiddleware;
 
@@ -28,7 +32,6 @@ namespace TEAMModeBI
         {
             Configuration = configuration;
             environment = env;
-            BaseConfigModel.SetBaseConfig(Configuration, env.ContentRootPath, env.WebRootPath);
         }
 
         public IConfiguration Configuration { get; }
@@ -36,13 +39,13 @@ namespace TEAMModeBI
         // This method gets called by the runtime. Use this method to add services to the container.
         public void ConfigureServices(IServiceCollection services)
         {
-            // true,默認情況下,聲明映射將以舊格式映射聲明名稱,以適應較早的SAML應用程序,RoleClaimType = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'
-            // false,RoleClaimType = 'roles'             
+            // true锛岄粯瑾嶆儏娉佷笅锛岃伈鏄庢槧灏勫皣浠ヨ垔鏍煎紡鏄犲皠鑱叉槑鍚嶇ū锛屼互閬╂噳杓冩棭鐨凷AML鎳夌敤绋嬪簭锛孯oleClaimType = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'
+            // false锛孯oleClaimType = 'roles'             
             JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
             services.AddAuthentication(options => options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
                 .AddJwtBearer(options => //AzureADJwtBearer
                 {
-                    //options.SaveToken = true; //驗證令牌由服務器生成才有效,不適用於服務重啟或分布式架構
+                    //options.SaveToken = true; //椹楄瓑浠ょ墝鐢辨湇鍕欏櫒鐢熸垚鎵嶆湁鏁堬紝涓嶉仼鐢ㄦ柤鏈嶅嫏閲嶅暉鎴栧垎甯冨紡鏋舵�
                     options.Authority = Configuration["Option:Authority"];
                     options.Audience = Configuration["Option:Audience"];
                     options.RequireHttpsMetadata = true;
@@ -52,7 +55,7 @@ namespace TEAMModeBI
                         ValidAudiences = new string[] { Configuration["Option:Audience"], $"api://{Configuration["Option:Audience"]}" }
                     };
                     options.Events = new JwtBearerEvents();
-                    //下列事件有需要紀錄則打開
+                    //涓嬪垪浜嬩欢鏈夐渶瑕佺磤閷勫墖鎵撻枊
                     //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
                     //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
                     //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
@@ -62,13 +65,13 @@ namespace TEAMModeBI
                         if (!context.Principal.Claims.Any(x => x.Type.Equals("http://schemas.microsoft.com/identity/claims/scope")) //ClaimConstants.Scope
                         && !context.Principal.Claims.Any(y => y.Type.Equals("roles"))) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
                         {
-                            //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
+                            //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
                             throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
                         }
                         await Task.FromResult(0);
                     };
                 });
-            //設定跨域請求
+            //瑷�畾璺ㄥ煙璜嬫眰
             services.AddCors(options =>
             {
                 options.AddPolicy(MyAllowSpecificOrigins,
@@ -88,11 +91,12 @@ namespace TEAMModeBI
             services.AddAzureServiceBus(Configuration.GetValue<string>("Azure:ServiceBus:ConnectionString"));
             services.AddSnowflakeId(Convert.ToInt64(Configuration.GetValue<string>("Option:LocationNum")), 1);
             services.AddHttpClient();
-            services.AddHttpClient<DingDing>();
+            services.AddHttpClient<DingDing>(); 
             services.AddHttpClient<NotificationService>();
+            services.AddHttpClient<CoreAPIHttpService>();
             services.AddMemoryCache();
             services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = false; });
-            //HttpContextAccessor,并用来访问HttpContext。(提供組件或非控制器服務存取HttpContext)
+            //HttpContextAccessor,并用来访问HttpContext。(提供組件或非控制器服務存取HttpContext)
             services.AddHttpContextAccessor();
             services.Configure<Option>(options => Configuration.GetSection("Option").Bind(options));
             services.AddControllers();
@@ -100,6 +104,37 @@ namespace TEAMModeBI
             {
                 configuration.RootPath = "ClientApp";
             });
+            services.AddServerSentEvents(o =>
+            {
+                o.KeepaliveMode = ServerSentEventsKeepaliveMode.Always;
+                o.OnClientConnected = async (service, client) =>
+                {
+                    //if (client.Request.Headers.TryGetValue("X-Auth-Name", out StringValues name))
+                    //{
+                    //    client.Client.SetProperty("NAME", name.ToString());
+                    //}
+                    //if (client.Request.Headers.TryGetValue("X-Auth-DID", out StringValues did))
+                    //{
+                    //    client.Client.SetProperty("DID", did.ToString());
+                    //}
+                    //if (client.Request.Headers.TryGetValue("X-Auth-CID", out StringValues cid))
+                    //{
+                    //    client.Client.SetProperty("CID", cid.ToString());
+                    //}
+                    //if (client.Request.Headers.TryGetValue("X-Auth-PIN", out StringValues pin))
+                    //{
+                    //    client.Client.SetProperty("PIN", pin.ToString());
+                    //}
+                    //if (client.Request.Headers.TryGetValue("X-Auth-APP", out StringValues app))
+                    //{
+                    //    client.Client.SetProperty("APP", app.ToString());
+                    //}
+
+                    await client.Client.SendEventAsync(new { sid = client.Client.Id.ToString() }.ToJsonString());
+                };
+            });
+            //等保安全性验证。
+            services.AddScoped<SecurityHeadersAttribute>();
         }
 
         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -111,32 +146,69 @@ namespace TEAMModeBI
             }
 
             app.UseRouting();
-            //以下需要按照順序載入中間件  如果应用调用 UseStaticFiles,请将 UseStaticFiles 置于 UseRouting之前。
+            //以下需要按照順序載入中間件  如果应用调用 UseStaticFiles,请将 UseStaticFiles 置于 UseRouting之前。
             app.UseStaticFiles();
             app.UseSpaStaticFiles();
-            app.UseCors(MyAllowSpecificOrigins); //使用跨域設定
-            app.UseHttpsRedirection(); //開發中暫時關掉
-            //如果应用使用身份验证/授权功能(如 AuthorizePage 或 [Authorize]),请将对 UseAuthentication 和 UseAuthorization的
-            //调用放在之后、UseRouting 和 UseCors,但在 UseEndpoints之前
+            app.UseCors(MyAllowSpecificOrigins); //浣跨敤璺ㄥ煙瑷�畾
+            app.UseHttpsRedirection(); //開發中暫時關掉
+            //如果应用使用身份验证/授权功能(如 AuthorizePage 或 [Authorize]),请将对 UseAuthentication 和 UseAuthorization的
+            //调用放在之后、UseRouting 和 UseCors,但在 UseEndpoints之前
             app.UseAuthentication();
             app.UseAuthorization();
 
+            //app.UseEndpoints(endpoints =>
+            //{
+            //    endpoints.MapControllers();
+            //});
+
+            //app.UseSpa(spa =>
+            //{
+            //    if (env.IsDevelopment())
+            //        spa.Options.SourcePath = "ClientApp/";
+            //    else
+            //        spa.Options.SourcePath = "dist";
+            //    if (env.IsDevelopment())
+            //    {
+            //        spa.UseVueCli(npmScript: "serve");
+            //    }
+            //});
+
+            //app.UseSpa(spa =>
+            //{
+            //    spa.Options.SourcePath = "ClientApp/";
+            //    if (env.IsDevelopment())
+            //    {
+            //        //spa.UseProxyToSpaDevelopmentServer("https://localhost:5001");
+            //        //spa.Options.StartupTimeout = new TimeSpan(0, 0, 80);
+            //        //spa.UseVueCli(npmScript: "serve"); 
+            //        //spa.UseProxyToSpaDevelopmentServer("https://localhost:5001");
+            //        spa.UseVueCli(npmScript: "serve");
+            //    }
+            //});
+
             app.UseEndpoints(endpoints =>
             {
                 endpoints.MapControllers();
-            });
-
-            app.UseSpa(spa =>
-            {
-                if (env.IsDevelopment())
-                    spa.Options.SourcePath = "ClientApp/";
-                else
-                    spa.Options.SourcePath = "dist";
-
-                if (env.IsDevelopment())
+                endpoints.MapServerSentEvents("/service/sse", new ServerSentEventsOptions
                 {
-                    spa.UseVueCli(npmScript: "serve");
-                }
+                    //Authorization = ServerSentEventsAuthorization.Default,
+                    OnPrepareAccept = response =>
+                    {
+                        response.Headers.Append("Cache-Control", "no-cache");
+                        response.Headers.Append("X-Accel-Buffering", "no");
+                    }
+                });
+#if DEBUG
+                endpoints.MapToVueCliProxy(
+                    "{*path}",
+                    new SpaOptions { SourcePath = "ClientApp" },
+                    npmScript: (System.Diagnostics.Debugger.IsAttached) ? "serve" : null,
+                    // regex: "Compiled successfully",
+                    forceKill: true
+                    );
+#else
+                endpoints.MapFallbackToFile("index.html");
+#endif             
 
             });
         }

+ 6 - 6
TEAMModeBI/TEAMModeBI.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <TargetFramework>net5.0</TargetFramework>
     <RootNamespace>TEAMModeBI</RootNamespace>
   </PropertyGroup>
 
@@ -11,7 +11,8 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="VueCliMiddleware" Version="3.0.0" />
+   
+    <PackageReference Include="VueCliMiddleware" Version="5.0.0" />
   </ItemGroup>
 
   <ItemGroup>
@@ -23,10 +24,7 @@
 
   <ItemGroup>
     <ProjectReference Include="..\TEAMModelOS.SDK\TEAMModelOS.SDK.csproj" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <Folder Include="Lib\" />
+    <ProjectReference Include="..\TEAMModelOS\TEAMModelOS.csproj" />
   </ItemGroup>
 
   <ItemGroup>
@@ -63,5 +61,7 @@
     </ItemGroup>
   </Target>
 
+  <ProjectExtensions><VisualStudio><UserProperties clientapp_4package_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
+
 
 </Project>

+ 0 - 15
TEAMModeBI/WeatherForecast.cs

@@ -1,15 +0,0 @@
-using System;
-
-namespace TEAMModeBI
-{
-    public class WeatherForecast
-    {
-        public DateTime Date { get; set; }
-
-        public int TemperatureC { get; set; }
-
-        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-
-        public string Summary { get; set; }
-    }
-}

+ 7 - 0
TEAMModeBI/appsettings.Development.json

@@ -8,6 +8,7 @@
   },
   "AllowedHosts": "*",
   "DingDingAuth": {
+    "Agentld": "1290158212",
     "appKey": "dingrucgsnt8p13rfbgd",
     "appSecret": "Gyx_N57yZslhQOAhAPlvmCwOp_qTm1DScKbd5OoOE0URAW4eViYA2Sk_ZxKb-8WG",
     "getuserinfo_bycode": "https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=xxx&timestamp=xxx&signature=xxx"
@@ -48,6 +49,12 @@
     "CoreId": {
       "userinfo": "https://api2.teammodel.cn/Oauth2/GetUserInfos"
     },
+    "sendSMS": {
+      "smstion": "https://api2.teammodel.net/service/sandsms/pin",      //验证醍摩豆账户是否存在,存在并发送验证码, 失败就不发送验证码
+      "verifiysms": "https://api2.teammodel.net/service/verifiy/pin"    //验证短信验证码信息
+    },
+    "Account": "https://account.teammodel.cn",
+    "CoreAPI": "https://api2.teammodel.cn",
     "CoreService": {
       "clientID": "c7317f88-7cea-4e48-ac57-a16071f7b884",
       "clientSecret": "kguxh:V.PLmxBdaI@jnrTrDSth]A3346",

+ 67 - 16
TEAMModelAPI/ApiTokenAttribute.cs

@@ -7,37 +7,79 @@ using Microsoft.Extensions.Options;
 using Microsoft.Extensions.DependencyInjection;
 using System.IdentityModel.Tokens.Jwt;
 using System.Linq;
+using TEAMModelOS.SDK.DI;
 
 namespace TEAMModelOS.Filter
 {
+    public class LimitPolicy {
+        /// <summary>
+        /// 颁发给谁的主体
+        /// </summary>
+        public string id { get; set; }
+        /// <summary>
+        /// 颁发主体
+        /// </summary>
+        public string school { get; set; }
+        /// <summary>
+        /// AIP的唯一ID
+        /// </summary>
+        public string jti { get; set; }
+        /// <summary>
+        /// minute  分钟,表示按分钟限流,多少分钟内只能访问多少次,
+        /// hour    小时,表示按小时限流,多少小时内只能访问多少次,
+        /// day     天数,表示按天数限流,多少天数内只能访问多少次,
+        /// </summary>
+        public string policy { get; set; }
+        /// <summary>
+        /// policy 策略,分钟,小时,天数对应的时长
+        /// </summary>
+        public int duration { get; set; }
+        /// <summary>
+        /// policy 策略,分钟,小时,天数对应的时长(duration) 可以访问的次数
+        /// </summary>
+        public int times { get; set; }
+        /// <summary>
+        /// 是否免费调用
+        /// </summary>
+        ///public bool free { get; set; }
+        /// <summary>
+        /// 每次调用花费多少钱
+        /// </summary>
+        ///public decimal cost { get; set; }
+    }
+
     public class ApiTokenAttribute : Attribute, IFilterFactory
     {
         public bool IsReusable => true;
-        //public string Roles { get; set; }
-        //public string Permissions { get; set; }
+        public bool Limit { get; set; }
+        public string Auth { get; set; }
 
         public IFilterMetadata CreateInstance(IServiceProvider services)
         {
             var option = services.GetService<IOptions<Option>>();
-            return new InternalAuthTokenFilter(option);
+            var azureRedis = services.GetService<AzureRedisFactory>();
+            return new InternalAuthTokenFilter(option ,azureRedis, Auth,   Limit);
         }
 
         private class InternalAuthTokenFilter : IResourceFilter
         {
             private readonly Option _option;
             //private readonly string _roles;
-            //private readonly string _permissions;
+            private readonly string _auth;
+            private readonly bool _limit;
+            private readonly AzureRedisFactory _azureRedis;
 
-            public InternalAuthTokenFilter(IOptions<Option> option)
+            public InternalAuthTokenFilter(IOptions<Option> option, AzureRedisFactory azureRedis, string auth, bool limit)
             {
                 _option = option.Value;
-                //_roles = roles;
-                //_permissions = permissions;
+                _auth = auth;
+                _limit = limit;
+                _azureRedis = azureRedis;
             }
             public void OnResourceExecuting(ResourceExecutingContext context)
             {
                 bool pass = false;
-                string id = string.Empty, name = string.Empty, school = string.Empty,jti=string.Empty;
+                string id = string.Empty, school = string.Empty,jti=string.Empty;
 
                 var authtoken = context.HttpContext.GetXAuth("ApiToken");
                 if (!string.IsNullOrWhiteSpace(authtoken) && JwtAuthExtension.ValidateApiToken(authtoken, _option.JwtSecretKey))
@@ -46,25 +88,34 @@ namespace TEAMModelOS.Filter
                     id = jwt.Payload.Sub;
                     school = jwt.Payload.Azp;
                     jti = jwt.Payload.Jti;
-                    name = jwt.Claims.FirstOrDefault(claim => claim.Type.Equals("name"))?.Value;
-                    //处理限流问题
-                    if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(school) && !string.IsNullOrEmpty(name)&& !string.IsNullOrEmpty(jti))
+                    var permissions = jwt.Claims.Where(c => c.Type.Equals("auth"));
+                    ///当前请求的api的设置的permission值是否包含在 从jwt的获取["1","2","3","4","5"]值中
+                    if (!string.IsNullOrWhiteSpace(_auth)&& permissions.Count()>0)
                     {
-                        pass = true;
-                    }
-                    else { 
-                        
+                       if (permissions.Select(x=>x.Value).Contains(_auth))
+                       {
+                            pass = true;
+                       }
                     }
+
+                    if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(school) && !string.IsNullOrEmpty(jti))
+                    {
+                        //AIP 开启限流策略 处理限流问题
+                        if (_limit)
+                        {
+                        }
+                    } 
                 }
 
                 if (pass)
                 {
                     context.HttpContext.Items.Add("ID", id);
-                    context.HttpContext.Items.Add("Name", name);
                     context.HttpContext.Items.Add("School", school);
                 }
                 else
+                { 
                     context.Result = new UnauthorizedResult();
+                }
             }
 
             public void OnResourceExecuted(ResourceExecutedContext context)

+ 14 - 1
TEAMModelAPI/Controllers/WeatherForecastController.cs

@@ -32,7 +32,7 @@ namespace TEAMModelAPI.Controllers
         }
 
         [HttpGet]
-        [ApiToken]
+        [ApiToken(Auth ="5")]
         public IEnumerable<WeatherForecast> Get()
         {
             var rng = new Random();
@@ -44,6 +44,19 @@ namespace TEAMModelAPI.Controllers
             })
             .ToArray();
         }
+        [HttpGet("aaaa")]
+        [ApiToken(Auth = "4")]
+        public IEnumerable<WeatherForecast> Getaaaa()
+        {
+            var rng = new Random();
+            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+            {
+                Date = DateTime.Now.AddDays(index),
+                TemperatureC = rng.Next(-20, 55),
+                Summary = Summaries[rng.Next(Summaries.Length)]
+            })
+            .ToArray();
+        }
 
         /// <summary>
         /// 删除prefix  不管是内容 模块还是其他试题试卷 评测 问卷投票等都在使用。

+ 3 - 0
TEAMModelAPI/Program.cs

@@ -13,6 +13,9 @@ namespace TEAMModelAPI
     {
         public static void Main(string[] args)
         {
+            List<string> a = new List<string>() { "1", "2", "3", "4", "5" };
+            List<string> b = new List<string>() { };
+            var c =  b.Where(x => !a.Any(y => y.Equals(x))).ToList();
             CreateHostBuilder(args).Build().Run();
         }
 

+ 1 - 1
TEAMModelAPI/appsettings.Development.json

@@ -12,7 +12,7 @@
     "LocationNum": "1",
     "HostName": "localhost:5001",
     "AllowedHosts": [ "localhost", "*.teammodel.cn", "*.teammodel.net", "*.habookaclass.biz", "test" ],
-    "Issuer": "www.teammodel.cn",
+    "Issuer": "localhost:5001",
     "JwtSecretKey": "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=",
     "Exp": 86400,
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",

+ 1 - 22
TEAMModelFunction/ActivityHttpTrigger.cs

@@ -414,28 +414,7 @@ namespace TEAMModelFunction
             return new OkObjectResult(new { });
         }
         
-        /// <summary>
-        /// 设置问卷调查未初始化学生列表的业务
-        /// </summary>
-        /// <param name="req"></param>
-        /// <param name="log"></param>
-        /// <returns></returns>
-        [FunctionName("refresh-stu-activity")]
-        public async Task<IActionResult> RefreshStuActivity(
-            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
-            ILogger log)
-        {
-            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
-            dynamic json = JsonSerializer.Deserialize<dynamic>(requestBody);
-            string id = json.id;
-            string code = json.code;
-            if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(code)) {
-                return new BadRequestResult();
-            }
-            var client = _azureCosmos.GetCosmosClient();
-            await TriggerStuActivity.RefreshStuActivity(client, _dingDing, id, code);
-            return new OkObjectResult(new {code=200 });
-        }
+       
         /// <summary>
         ///获取单个目录的大小,用于获取评测,试题,试卷,问卷,投票等 文件层级超过两层的文件。
         ///例如 /exam/uuid/xxx  /item/uuid/xxx   /paper/uuid/xxx  /vote/uuid/xxx  /suervy/uuid/xxx

+ 1 - 1
TEAMModelFunction/MonitorCosmosDB.cs

@@ -110,7 +110,7 @@ namespace TEAMModelFunction
                                     TriggerStudy.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
                                     break;
                                 case "Homework":
-                                    TriggerWork.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
+                                    TriggerHomework.Trigger(_serviceBus, _azureStorage, _dingDing, client, input, data, _azureRedis);
                                     break;
 
                             }

+ 250 - 1
TEAMModelFunction/MonitorServicesBus.cs

@@ -15,6 +15,9 @@ using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
+using TEAMModelOS.Services.Common;
+using System.Linq;
+using TEAMModelOS.SDK.Models.Service;
 
 namespace TEAMModelFunction
 {
@@ -374,7 +377,7 @@ namespace TEAMModelFunction
                 //TODO学习活动
                 //await FixActivity(client, stuListChange, "Learn");
                 //TODO作业活动
-                // await FixActivity(client, stuListChange, "Homework");
+                await StuListService.FixActivity(client,_dingDing, stuListChange, "Homework");
 
                 if (stuListChange.type==null||!stuListChange.type.Equals("research")) {
                     //课程名单变动修改学生课程关联信息
@@ -386,7 +389,253 @@ namespace TEAMModelFunction
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-StuListServiceBus-StuList\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.成都开发測試群組);
             }
         }
+        /// <summary>
+        /// 完善课程变更,StuListChange,  originCode是学校编码 则表示名单是学校自定义名单,如果是tmdid则表示醍摩豆的私有名单,scope=school,private。
+        /// </summary>
+        /// <data msg>
+        /// CourseChange
+        ///// </data>
+        /// <param name="msg"></param>
+        /// <returns></returns>
+        [FunctionName("GroupChange")]
+        public async Task GroupChange([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "group-change", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
+        {
+            var client = _azureCosmos.GetCosmosClient();
+            try
+            {
+                var jsonMsg = JsonDocument.Parse(msg);
+                GroupChange groupChange = msg.ToObject<GroupChange>();
+                //名单变动修改学生课程关联信息
+                //await StuListService.FixStuCourse(client, stuListChange);
+                //Vote投票 Survey问卷 Exam评测 Learn学习活动 Homework作业活动
+                //名单变动修改学生问卷关联信息
+                await GroupListService.FixActivity(client, _dingDing, groupChange, "Survey");
+                //名单变动修改学生投票关联信息
+                await GroupListService.FixActivity(client, _dingDing, groupChange, "Vote");
+                //名单变动修改学生评测关联信息
+                await GroupListService.FixActivity(client, _dingDing, groupChange, "Exam");
+                //TODO学习活动
+                //await FixActivity(client, stuListChange, "Learn");
+                //名单变动修改学生作业活动信息
+                await GroupListService.FixActivity(client, _dingDing, groupChange, "Homework");
+
+                if (groupChange.type == null || !groupChange.type.Equals("research"))
+                {
+                    //课程名单变动修改学生课程关联信息
+                    await GroupListService.FixStuCourse(client, _dingDing, groupChange);
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-StuListServiceBus-StuList\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.成都开发測試群組);
+            }
+        }
+        [FunctionName("ItemCond")]
+        public async Task ItemCond([ServiceBusTrigger("%Azure:ServiceBus:ItemCondQueue%", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
+        {
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                var jsonMsg = JsonDocument.Parse(msg);
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n题库数据变更:{msg}", GroupNames.醍摩豆服務運維群組);
+                List<ItemCondDto> itemCondDtos = msg.ToObject<List<ItemCondDto>>();
+                foreach (var itemCondDto in itemCondDtos)
+                {
+                    if (itemCondDto.scope.Equals("school")) {
+                        ItemCond itemCond = null;
+                        List<ItemInfo> items = new List<ItemInfo>();
+                        var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where   c.periodId='{itemCondDto.filed}' and c.pid= null  ";
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.key}") }))
+                        {
+                            items.Add(item);
+                        }
+                        itemCond = new ItemCond()
+                        {
+                            id = $"{itemCondDto.filed}",
+                            code = $"ItemCond-{itemCondDto.key}",
+                            pk = "ItemCond",
+                            ttl = -1,
+                            count = items.Count,
+                            grades = new List<GradeCount>(),
+                            subjects = new List<SubjectCount>()
+                        };
+                        items.ForEach(z =>
+                        {
+                            ItemService.CountItemCond(z, null, itemCond);
+                        });
+                        await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:{itemCondDto.key}", $"{itemCondDto.filed}", itemCond.ToJsonString());
+                    }
+                    else
+                    {
+                        ItemCond itemCond = null;
+                        List<ItemInfo> items = new List<ItemInfo>();
+                        var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.pid= null  ";
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.filed}") }))
+                        {
+                            items.Add(item);
+                        }
+                        itemCond = new ItemCond() { id = $"{itemCondDto.filed}", code = $"ItemCond", pk = "ItemCond", ttl = -1, count = items.Count };
+                        items.ForEach(z =>
+                        {
+                            ItemService.CountItemCond(z, null, itemCond);
+                        });
+                        await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:ItemCond", $"{itemCondDto.filed}", itemCond.ToJsonString());
+                    }
+                }
+                 
+            }
+            catch (CosmosException ex )
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
+            }
+        }
 
+        //更新產品一覽表
+        [FunctionName("Product")]
+        public async Task Product([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "product", Connection = "Azure:ServiceBus:ConnectionString")] string msg, ILogger log)
+        {
+            try
+            {
+                log.LogError("msg:" + msg);
 
+                var jsonMsg = JsonDocument.Parse(msg);
+                jsonMsg.RootElement.TryGetProperty("method", out JsonElement method);
+                jsonMsg.RootElement.TryGetProperty("schoolId", out JsonElement schoolId);
+                jsonMsg.RootElement.TryGetProperty("prodCode", out JsonElement prodCode);
+                jsonMsg.RootElement.TryGetProperty("prodId", out JsonElement prodId);
+                var client = _azureCosmos.GetCosmosClient();
+                string strQuery = string.Empty;
+                //取得所有學校產品
+                ////序號
+                List<SchoolProductSumData> serialsProductSumOrg = new List<SchoolProductSumData>();
+                strQuery = $"SELECT * FROM c WHERE c.dataType = 'serial'";
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            SchoolProductSerial serialInfo = obj.ToObject<SchoolProductSerial>();
+                            SchoolProductSumData serialProd = serialsProductSumOrg.Where(sp => sp.prodCode == serialInfo.prodCode).FirstOrDefault();
+                            if(serialProd == null)
+                            {
+                                SchoolProductSumData serialProdAdd = new SchoolProductSumData();
+                                serialProdAdd.prodCode = serialInfo.prodCode;
+                                serialProdAdd.ids.Add(serialInfo.id);
+                                serialProdAdd.avaliable = serialProdAdd.ids.Count;
+                                serialsProductSumOrg.Add(serialProdAdd);
+                            }
+                            else
+                            {
+                                if(!serialProd.ids.Contains(serialInfo.id))
+                                {
+                                    serialProd.ids.Add(serialInfo.id);
+                                }
+                                serialProd.avaliable = serialProd.ids.Count;
+                            }
+                        }
+                    }
+                }
+                ////服務
+                List<SchoolProductSumData> servicesProductSumOrg = new List<SchoolProductSumData>();
+                long timestampToday = DateTimeOffset.UtcNow.AddSeconds(1).ToUnixTimeSeconds(); //比現實時間延遲1秒
+                strQuery = $"SELECT * FROM c WHERE c.dataType = 'service' AND c.startDate <= {timestampToday} AND {timestampToday} <= c.endDate"; //在授權期間才取
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            SchoolProductService serviceInfo = obj.ToObject<SchoolProductService>();
+                            SchoolProductSumData serviceProd = servicesProductSumOrg.Where(sp => sp.prodCode == serviceInfo.prodCode).FirstOrDefault();
+                            if (serviceProd == null)
+                            {
+                                SchoolProductSumData serviceProdAdd = new SchoolProductSumData();
+                                serviceProdAdd.prodCode = serviceInfo.prodCode;
+                                serviceProdAdd.avaliable = 0;
+                                serviceProdAdd.ids.Add(serviceInfo.id);
+                                serviceProdAdd.avaliable += serviceInfo.number;
+                                servicesProductSumOrg.Add(serviceProdAdd);
+                            }
+                            else
+                            {
+                                if (!serviceProd.ids.Contains(serviceInfo.id))
+                                {
+                                    serviceProd.ids.Add(serviceInfo.id);
+                                    serviceProd.avaliable += serviceInfo.number;
+                                }
+                            }
+                        }
+                    }
+                }
+                ////服務產品特別對應項
+                if (servicesProductSumOrg.Count > 0)
+                {
+                    foreach (SchoolProductSumData servicesProductSumOrgRow in servicesProductSumOrg)
+                    {
+                        //更新學校空間
+                        if (servicesProductSumOrgRow.prodCode.Equals("IPALJ6NY"))
+                        {
+                            School school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{schoolId}", new PartitionKey("Base"));
+                            school.size = (servicesProductSumOrgRow.avaliable < 1) ? 1 : servicesProductSumOrgRow.avaliable;
+                            await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, $"{schoolId}", new PartitionKey("Base"));
+                        }
+                    }
+                }
+
+                ////硬體
+                List<SchoolProductSumDataHard> hardsProductSumOrg = new List<SchoolProductSumDataHard>();
+                strQuery = $"SELECT * FROM c WHERE c.dataType = 'hard'";
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
+                {
+                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            SchoolProductHard hardInfo = obj.ToObject<SchoolProductHard>();
+                            SchoolProductSumData hardProd = hardsProductSumOrg.Where(sp => sp.prodCode == hardInfo.prodCode).FirstOrDefault();
+                            if (hardProd == null)
+                            {
+                                SchoolProductSumDataHard hardProdAdd = new SchoolProductSumDataHard();
+                                hardProdAdd.prodCode = hardInfo.prodCode;
+                                hardProdAdd.model = hardInfo.model;
+                                hardProdAdd.ids.Add(hardInfo.id);
+                                hardProdAdd.avaliable = hardProdAdd.ids.Count;
+                                hardsProductSumOrg.Add(hardProdAdd);
+                            }
+                            else
+                            {
+                                if (!hardProd.ids.Contains(hardInfo.id))
+                                {
+                                    hardProd.ids.Add(hardInfo.id);
+                                }
+                                hardProd.avaliable = hardProd.ids.Count;
+                            }
+                        }
+                    }
+                }
+                //更新學校產品一覽表
+                SchoolProductSum prodSum = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolProductSum>(schoolId.ToString(), new PartitionKey($"ProductSum"));
+                prodSum.serial = serialsProductSumOrg;
+                prodSum.service = servicesProductSumOrg;
+                prodSum.hard = hardsProductSumOrg;
+                await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<SchoolProductSum>(prodSum, prodSum.id, new PartitionKey($"{prodSum.code}"));
+            }
+            catch (CosmosException ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
+            }
+        }
     }
 }

+ 40 - 13
TEAMModelFunction/TriggerCorrect.cs

@@ -40,9 +40,11 @@ namespace TEAMModelFunction
             }
             await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}阅卷配置【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在执行", GroupNames.成都开发測試群組);
             Correct correct = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Correct>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-            List<ChangeRecord> correctRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", correct.progress } });
+            
             if (correct != null)
             {
+                string PartitionKey = string.Format("{0}{1}{2}", correct.code, "-", correct.progress);
+                List<ChangeRecord> correctRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
                 switch (correct.progress)
                 {
                     case "pending":
@@ -61,7 +63,7 @@ namespace TEAMModelFunction
                             ChangeRecord changeRecord = new ChangeRecord
                             {
                                 RowKey = input.Id,
-                                PartitionKey = "pending",
+                                PartitionKey = PartitionKey,
                                 sequenceNumber = start,
                                 msgId = messageCorrect.MessageId
                             };
@@ -69,6 +71,11 @@ namespace TEAMModelFunction
                         }
                         break;
                     case "going":
+                        //评测id
+                        string eid = correct.id;
+                        //评测的分区键
+                        string ecode = correct.scode;
+                        ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{ecode}"));
                         if (correct.subs.IsNotEmpty())
                         {
 
@@ -110,7 +117,8 @@ namespace TEAMModelFunction
                                             //模块数
                                             model = sub.model,
                                             type = 1,
-                                            createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
+                                            createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                                            source = info.source
                                         };
                                         await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<CorrectTask>(task, new Azure.Cosmos.PartitionKey(task.code));
                                     }
@@ -199,16 +207,11 @@ namespace TEAMModelFunction
 
 
                                 }
-                                //调用本次考试所涉及的所有已经作答的数据 并生成阅卷池,存入redis
-                                //评测id
-                                string eid = correct.id;
-                                //评测的分区键
-                                string ecode = correct.scode;
                                 //评测科目
                                 string subjectId = sub.id;
                                 //生成临时作答数据存放到redis
-                                var redisClient = _azureRedis.GetRedisClient(8);
-                                ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(eid, new Azure.Cosmos.PartitionKey(ecode));
+                                //var redisClient = _azureRedis.GetRedisClient(8);
+                                //ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(eid, new Azure.Cosmos.PartitionKey(ecode));
                                 List<ExamClassResult> classResults = new List<ExamClassResult>();
                                 //获取原题配分
                                 int paperIndex = 0;
@@ -224,7 +227,7 @@ namespace TEAMModelFunction
                                     }
                                 }
                                 List<double> paperPoint = info.papers[paperIndex].point;
-
+                                List<List<string>> ans = info.papers[paperIndex].answers;
                                 if (info.scope.Equals("school"))
                                 {
 
@@ -277,6 +280,30 @@ namespace TEAMModelFunction
                                                 items.Add(item);
                                                 qss.Add(qs);
                                             }
+                                            //处理学生未作答 生成阅卷数据时 客观题分数为-1的情况
+                                            List<double> scores = new List<double>();
+                                            int n = 0;
+                                            foreach (List<string> answer in ans)
+                                            {
+                                                var scs = examClass.studentScores[index][n];
+
+                                                if (answer.Count > 0)
+                                                {
+                                                    if (scs == -1)
+                                                    {
+                                                        scores.Add(0);
+                                                    }
+                                                    else
+                                                    {
+                                                        scores.Add(scs);
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    scores.Add(scs);
+                                                }
+                                                n++;
+                                            }
                                             Scoring sc = new Scoring
                                             {
                                                 id = Guid.NewGuid().ToString(),
@@ -285,7 +312,7 @@ namespace TEAMModelFunction
                                                 stuId = stuId,
                                                 examId = eid,
                                                 subjectId = subjectId,
-                                                scores = examClass.studentScores[index],
+                                                scores = scores,
                                                 count = correct.num,
                                                 //marks = marks,
                                                 items = items,
@@ -318,7 +345,7 @@ namespace TEAMModelFunction
                             ChangeRecord changeRecord = new ChangeRecord
                             {
                                 RowKey = input.Id,
-                                PartitionKey = "going",
+                                PartitionKey = PartitionKey,
                                 sequenceNumber = end,
                                 msgId = messageCorrectEnd.MessageId
                             };

+ 282 - 275
TEAMModelFunction/TriggerExam.cs

@@ -23,163 +23,169 @@ namespace TEAMModelFunction
         public static async void Trigger(AzureCosmosFactory _azureCosmos, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
             CosmosClient client, Document input, string code, long stime, long etime, string school)
         {
-            ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
+
             List<ExamClassResult> examClassResults = new List<ExamClassResult>();
             List<ExamSubject> examSubjects = new List<ExamSubject>();
             try
             {
-                if (info.scope.Equals("teacher", StringComparison.OrdinalIgnoreCase) || info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
+                ExamInfo info = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(input.Id, new Azure.Cosmos.PartitionKey($"{code}"));
+                if (info != null)
                 {
-                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
+                    if (info.scope.Equals("teacher", StringComparison.OrdinalIgnoreCase) || info.scope.Equals("private", StringComparison.OrdinalIgnoreCase))
                     {
-                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{info.creatorId}") }))
                         {
-                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                            if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                             {
-                                examClassResults.Add(obj.ToObject<ExamClassResult>());
+                                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                                {
+                                    examClassResults.Add(obj.ToObject<ExamClassResult>());
+                                }
                             }
                         }
                     }
-                }
-                else
-                {
-                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
+                    else
                     {
-                        using var json = await JsonDocument.ParseAsync(item.ContentStream);
-                        if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryStreamIterator(queryText: $"select value(c) from c where c.examId = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamClassResult-{school}") }))
                         {
-                            foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                            using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                            if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                             {
-                                examClassResults.Add(obj.ToObject<ExamClassResult>());
+                                foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                                {
+                                    examClassResults.Add(obj.ToObject<ExamClassResult>());
+                                }
                             }
                         }
                     }
-                }
 
-
-                List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", info.progress } });
-                //处理科目信息
-                List<string> sub = new List<string>();
-                foreach (ExamSubject subject in info.subjects)
-                {
-                    sub.Add(subject.id);
-                }
-                //ChangeRecord record = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
-                switch (info.progress)
-                {
-                    case "pending":
-                        var message = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
-                        message.ApplicationProperties.Add("name", "Exam");
-                        if (records.Count > 0)
-                        {
-                            await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
-                            long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                            records[0].sequenceNumber = start;
-                            await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                            //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
-                        }
-                        else
-                        {
-                            long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
-                            ChangeRecord changeRecord = new ChangeRecord
+                    string PartitionKey = string.Format("{0}{1}{2}", info.code, "-", info.progress);
+                    List<ChangeRecord> records = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
+                    //处理科目信息
+                    List<string> sub = new List<string>();
+                    foreach (ExamSubject subject in info.subjects)
+                    {
+                        sub.Add(subject.id);
+                    }
+                    //ChangeRecord record = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ChangeRecord>(input.Id, new Azure.Cosmos.PartitionKey($"{info.progress}"));
+                    switch (info.progress)
+                    {
+                        case "pending":
+                            var message = new ServiceBusMessage(new { id = input.Id, progress = "going", code = code }.ToJsonString());
+                            message.ApplicationProperties.Add("name", "Exam");
+                            if (records.Count > 0)
                             {
-                                RowKey = input.Id,
-                                PartitionKey = "pending",
-                                sequenceNumber = start,
-                                msgId = message.MessageId
-                            };
-                            await _azureStorage.Save<ChangeRecord>(changeRecord);
-                            //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
-                        }
-                        break;
-                    case "going":
-                        List<string> classes = ExamService.getClasses(info.classes,info.stuLists);
-                        (List<TmdInfo> tmdids, List<StuInfo> studentss,List<ClassListInfo> classLists) = await TriggerStuActivity.GetStuList(client, _dingDing, classes, info.school);
-                        List<StuActivity> stuActivities = new List<StuActivity>();
-                        List<StuActivity> tmdActivities = new List<StuActivity>();
-                        try
-                        {
-                            if (tmdids.IsNotEmpty())
+                                await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
+                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
+                                records[0].sequenceNumber = start;
+                                await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
+                                //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
+                            }
+                            else
                             {
-                                tmdids.ForEach(x =>
+                                long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), message, DateTimeOffset.FromUnixTimeMilliseconds(stime));
+                                //string pk = String.Format("{0}{1}{2}", info.code, "-", "pending");
+                                ChangeRecord changeRecord = new ChangeRecord
                                 {
-                                    tmdActivities.Add(new StuActivity
-                                    {
-                                        pk = "Activity",
-                                        id = info.id,
-                                        code = $"Activity-{x.id}",
-                                        type = "Exam",
-                                        name = info.name,
-                                        startTime = info.startTime,
-                                        endTime = info.endTime,
-                                        scode = info.code,
-                                        scope = info.scope,
-                                        school = info.school,
-                                        creatorId = info.creatorId,
-                                        subjects = sub,
-                                        blob = null,
-                                        owner = info.owner,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1,
-                                        classIds = classes
-
-                                    });;
-                                });
+                                    RowKey = input.Id,
+                                    PartitionKey = PartitionKey,
+                                    sequenceNumber = start,
+                                    msgId = message.MessageId
+                                };
+                                await _azureStorage.Save<ChangeRecord>(changeRecord);
+                                //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
                             }
-                            if (studentss.IsNotEmpty())
+                            break;
+                        case "going":
+
+                            try
                             {
-                                studentss.ForEach(x =>
+                                List<string> classes = ExamService.getClasses(info.classes, info.stuLists);
+                                (List<TmdInfo> tmdids, List<StuInfo> studentss, List<ClassListInfo> classLists) = await TriggerStuActivity.GetStuList(client, _dingDing, classes, info.school);
+                                List<StuActivity> stuActivities = new List<StuActivity>();
+                                List<StuActivity> tmdActivities = new List<StuActivity>();
+                                if (tmdids.IsNotEmpty())
                                 {
-                                    stuActivities.Add(new StuActivity
+                                    tmdids.ForEach(x =>
                                     {
-                                        pk = "Activity",
-                                        id = info.id,
-                                        code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
-                                        type = "Exam",
-                                        name = info.name,
-                                        startTime = info.startTime,
-                                        endTime = info.endTime,
-                                        scode = info.code,
-                                        scope = info.scope,
-                                        school = info.school,
-                                        creatorId = info.creatorId,
-                                        subjects = sub,
-                                        blob = null,
-                                        owner = info.owner,
-                                        classIds = classes,
-                                        createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
-                                        taskStatus = -1
+                                        tmdActivities.Add(new StuActivity
+                                        {
+                                            pk = "Activity",
+                                            id = info.id,
+                                            code = $"Activity-{x.id}",
+                                            type = "Exam",
+                                            name = info.name,
+                                            source = info.source,
+                                            startTime = info.startTime,
+                                            endTime = info.endTime,
+                                            scode = info.code,
+                                            scope = info.scope,
+                                            school = info.school,
+                                            creatorId = info.creatorId,
+                                            subjects = sub,
+                                            blob = null,
+                                            owner = info.owner,
+                                            createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                                            taskStatus = -1,
+                                            classIds = classes
+
+                                        });
                                     });
-                                });
-                            }
-                            await TriggerStuActivity.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities,null);
-                            //向学生或醍摩豆账号发起通知
-                            #region
-                            //Notice notice = new Notice()
-                            //{
-                            //    msgId = info.id,
-                            //    creation = info.startTime,
-                            //    expire = info.endTime,
-                            //    creatorId = info.creatorId,
-                            //    stuids = studentss,
-                            //    tmdids = tmdids,
-                            //    type = "notice",//评测参加通知
-                            //    priority = "normal",
-                            //    school = info.school,
-                            //    scope = info.scope,
-                            //    //data = new { }.ToJsonString()
-                            //    body = new Body { sid = info.id, scode = info.code, spk = info.pk, biztype = "exam-join" }
-
-                            //};
-                            //var messageBlob = new ServiceBusMessage(notice.ToJsonString());
-                            //messageBlob.ApplicationProperties.Add("name", "Notice");
-                            //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageBlob);
-                            #endregion
-                            if (examClassResults.Count == 0)
-                            {
-                                try
+                                }
+                                if (studentss.IsNotEmpty())
                                 {
+                                    studentss.ForEach(x =>
+                                    {
+                                        stuActivities.Add(new StuActivity
+                                        {
+                                            pk = "Activity",
+                                            id = info.id,
+                                            code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}",
+                                            type = "Exam",
+                                            name = info.name,
+                                            source = info.source,
+                                            startTime = info.startTime,
+                                            endTime = info.endTime,
+                                            scode = info.code,
+                                            scope = info.scope,
+                                            school = info.school,
+                                            creatorId = info.creatorId,
+                                            subjects = sub,
+                                            blob = null,
+                                            owner = info.owner,
+                                            classIds = classes,
+                                            createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
+                                            taskStatus = -1
+                                        });
+                                    });
+                                }
+                                await TriggerStuActivity.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, null);
+                                //向学生或醍摩豆账号发起通知
+                                #region
+                                //Notice notice = new Notice()
+                                //{
+                                //    msgId = info.id,
+                                //    creation = info.startTime,
+                                //    expire = info.endTime,
+                                //    creatorId = info.creatorId,
+                                //    stuids = studentss,
+                                //    tmdids = tmdids,
+                                //    type = "notice",//评测参加通知
+                                //    priority = "normal",
+                                //    school = info.school,
+                                //    scope = info.scope,
+                                //    //data = new { }.ToJsonString()
+                                //    body = new Body { sid = info.id, scode = info.code, spk = info.pk, biztype = "exam-join" }
+
+                                //};
+                                //var messageBlob = new ServiceBusMessage(notice.ToJsonString());
+                                //messageBlob.ApplicationProperties.Add("name", "Notice");
+                                //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageBlob);
+                                #endregion
+                                if (examClassResults.Count == 0)
+                                {
+
                                     foreach (string cla in classes)
                                     {
                                         int m = 0;
@@ -331,183 +337,184 @@ namespace TEAMModelFunction
                                             await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(result, new Azure.Cosmos.PartitionKey($"{result.code}"));
                                         }
                                     }
+
+
                                 }
-                                catch (Exception ex)
+                                else
                                 {
-                                    await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going初始化异常{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
-                                }
-                                finally {
-                                    // 发送信息通知
-                                    var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
-                                    messageEnd.ApplicationProperties.Add("name", "Exam");
-                                    if (records.Count > 0)
-                                    {
-                                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                                        await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
-                                        records[0].sequenceNumber = end;
-                                        await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
-                                        //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
-                                    }
-                                    else
+                                    //处理单科结算时科目与试卷信息匹配的问题
+                                    int gno = 0;
+                                    foreach (ExamSubject subject in info.subjects)
                                     {
-                                        long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
-                                        ChangeRecord changeRecord = new ChangeRecord
+                                        if (subject.classCount == classes.Count)
                                         {
-                                            RowKey = input.Id,
-                                            PartitionKey = "going",
-                                            sequenceNumber = end,
-                                            msgId = messageEnd.MessageId
-                                        };
-                                        await _azureStorage.Save<ChangeRecord>(changeRecord);
-                                        //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
+                                            await createClassResultAsync(info, examClassResults, subject, gno, _azureCosmos, _dingDing, _azureStorage);
+                                        }
+                                        gno++;
                                     }
-                                }                               
+                                }
                             }
-                            else
+                            catch (Exception e)
                             {
-                                //处理单科结算时科目与试卷信息匹配的问题
-                                int gno = 0;
-                                foreach (ExamSubject subject in info.subjects)
+                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
+                            }
+                            finally
+                            {
+                                // 发送信息通知
+                                var messageEnd = new ServiceBusMessage(new { id = input.Id, progress = "finish", code = code }.ToJsonString());
+                                messageEnd.ApplicationProperties.Add("name", "Exam");
+                                if (records.Count > 0)
+                                {
+                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
+                                    await _serviceBus.GetServiceBusClient().cancelMessage(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), records[0].sequenceNumber);
+                                    records[0].sequenceNumber = end;
+                                    await _azureStorage.SaveOrUpdate<ChangeRecord>(records[0]);
+                                    //await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(record, record.id, new Azure.Cosmos.PartitionKey($"{record.code}"));
+                                }
+                                else
                                 {
-                                    if (subject.classCount == classes.Count)
+                                    long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageEnd, DateTimeOffset.FromUnixTimeMilliseconds(etime));
+                                    //string pk = String.Format("{0}{1}{2}", info.code, "-", "going");
+                                    ChangeRecord changeRecord = new ChangeRecord
                                     {
-                                        await createClassResultAsync(info, examClassResults, subject, gno, _azureCosmos, _dingDing, _azureStorage);
-                                    }
-                                    gno++;
+                                        RowKey = input.Id,
+                                        PartitionKey = PartitionKey,
+                                        sequenceNumber = end,
+                                        msgId = messageEnd.MessageId
+                                    };
+                                    await _azureStorage.Save<ChangeRecord>(changeRecord);
+                                    //await client.GetContainer(Constant.TEAMModelOS, "Common").CreateItemAsync(changeRecord, new Azure.Cosmos.PartitionKey($"{changeRecord.code}"));
                                 }
                             }
-                        }
-                        catch (Exception e)
-                        {
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测going状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
-                        }
-                        break;
-                    case "finish":
-                        int fno = 0;
-                        try
-                        {
-                            foreach (ExamSubject subject in info.subjects)
+                            break;
+                        case "finish":
+                            int fno = 0;
+                            try
                             {
-                                await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos, _dingDing, _azureStorage);
-                                fno++;
-                            }
+                                foreach (ExamSubject subject in info.subjects)
+                                {
+                                    await createClassResultAsync(info, examClassResults, subject, fno, _azureCosmos, _dingDing, _azureStorage);
+                                    fno++;
+                                }
 
-                            //计算单次考试简易统计信息
-                            List<ExamResult> examResults = new List<ExamResult>();
-                            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamResult>(
-                                               queryText: $"select value(c) from c where c.examId  = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}") }))
-                            {
-                                examResults.Add(item);
-                            }
-                            List<Task<ItemResponse<ExamClassResult>>> tasks = new List<Task<ItemResponse<ExamClassResult>>>();
-                            //结算单科单班的标准差和平均分
-                            foreach (ExamClassResult classResult in examClassResults)
-                            {
-                                //标记单科单班总得分
-                                double subScore = 0;
-                                //标准差
-                                double sPowSum = 0;
-                                var scount = classResult.studentIds.Count;
-                                foreach (List<double> sc in classResult.studentScores)
+                                //计算单次考试简易统计信息
+                                List<ExamResult> examResults = new List<ExamResult>();
+                                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamResult>(
+                                                   queryText: $"select value(c) from c where c.examId  = '{info.id}'", requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}") }))
+                                {
+                                    examResults.Add(item);
+                                }
+                                List<Task<ItemResponse<ExamClassResult>>> tasks = new List<Task<ItemResponse<ExamClassResult>>>();
+                                //结算单科单班的标准差和平均分
+                                foreach (ExamClassResult classResult in examClassResults)
                                 {
-                                    List<double> newSc = new List<double>();
-                                    foreach (double ssc in sc)
+                                    //标记单科单班总得分
+                                    double subScore = 0;
+                                    //标准差
+                                    double sPowSum = 0;
+                                    var scount = classResult.studentIds.Count;
+                                    foreach (List<double> sc in classResult.studentScores)
                                     {
-                                        if (ssc == -1)
-                                        {
-                                            newSc.Add(0);
-                                        }
-                                        else
+                                        List<double> newSc = new List<double>();
+                                        foreach (double ssc in sc)
                                         {
-                                            newSc.Add(ssc);
+                                            if (ssc == -1)
+                                            {
+                                                newSc.Add(0);
+                                            }
+                                            else
+                                            {
+                                                newSc.Add(ssc);
+                                            }
                                         }
+                                        subScore += newSc.Sum();
                                     }
-                                    subScore += newSc.Sum();
-                                }
-                                foreach (string sid in classResult.studentIds)
-                                {
-                                    double ssc = classResult.studentScores[classResult.studentIds.IndexOf(sid)].Sum();
-                                    sPowSum += Math.Pow(ssc - scount > 0 ? Math.Round(subScore * 1.0 / scount, 2) : 0, 2);
+                                    foreach (string sid in classResult.studentIds)
+                                    {
+                                        double ssc = classResult.studentScores[classResult.studentIds.IndexOf(sid)].Sum();
+                                        sPowSum += Math.Pow(ssc - scount > 0 ? Math.Round(subScore * 1.0 / scount, 2) : 0, 2);
 
+                                    }
+                                    classResult.standard = Math.Round(scount > 0 ? Math.Pow(sPowSum / scount, 0.5) : 0, 2);
+                                    classResult.average = scount > 0 ? Math.Round(subScore / scount, 2) : 0;
+                                    classResult.progress = true;
+                                    tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}")));
                                 }
-                                classResult.standard = Math.Round(scount > 0 ? Math.Pow(sPowSum / scount, 0.5) : 0, 2);
-                                classResult.average = scount > 0 ? Math.Round(subScore / scount, 2) : 0;
-                                classResult.progress = true;
-                                tasks.Add(client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(classResult, classResult.id, new Azure.Cosmos.PartitionKey($"{classResult.code}")));
-                            }
-                            await Task.WhenAll(tasks);
-                            //记录某次考试所有学生得分总分
-                            double score = 0;
-                            double allScore = 0;
-                            int stuCount = 0;
-                            //标准差
-                            double powSum = 0;
-                            List<string> losStu = new List<string>();
-                            //先与第一个值取并集
-                            if (examResults.Count > 0)
-                            {
-                                losStu = losStu.Union(examResults[0].lostStus).ToList();
-                                foreach (ExamResult examResult in examResults)
+                                await Task.WhenAll(tasks);
+                                //记录某次考试所有学生得分总分
+                                double score = 0;
+                                double allScore = 0;
+                                int stuCount = 0;
+                                //标准差
+                                double powSum = 0;
+                                List<string> losStu = new List<string>();
+                                //先与第一个值取并集
+                                if (examResults.Count > 0)
                                 {
-                                    if (info.id == examResult.examId)
+                                    losStu = losStu.Union(examResults[0].lostStus).ToList();
+                                    foreach (ExamResult examResult in examResults)
                                     {
-                                        foreach (List<double> sc in examResult.studentScores)
+                                        if (info.id == examResult.examId)
                                         {
-                                            score += sc.Sum();
+                                            foreach (List<double> sc in examResult.studentScores)
+                                            {
+                                                score += sc.Sum();
+                                            }
+                                            stuCount = examResult.studentIds.Count;
                                         }
-                                        stuCount = examResult.studentIds.Count;
+                                        //powSum += Math.Pow(score - examResult.studentIds.Count > 0 ? Math.Round(score * 1.0 / examResult.studentIds.Count, 2) : 0, 2);
+                                        //取交集
+                                        losStu = losStu.Intersect(examResult.lostStus).ToList();
                                     }
-                                    //powSum += Math.Pow(score - examResult.studentIds.Count > 0 ? Math.Round(score * 1.0 / examResult.studentIds.Count, 2) : 0, 2);
-                                    //取交集
-                                    losStu = losStu.Intersect(examResult.lostStus).ToList();
                                 }
-                            }
-                            double NewsRateScore = stuCount > 0 ? Math.Round(score * 1.0 / stuCount, 2) : 0;
-                            foreach (PaperSimple simple in info.papers)
-                            {
-                                allScore += simple.point.Sum();
-                            }
-                            //计算全科标准差
-                            foreach (string id in examResults[0].studentIds)
-                            {
-                                double sc = 0;
-                                foreach (ExamResult result in examResults)
+                                double NewsRateScore = stuCount > 0 ? Math.Round(score * 1.0 / stuCount, 2) : 0;
+                                foreach (PaperSimple simple in info.papers)
                                 {
-                                    sc += result.studentScores[result.studentIds.IndexOf(id)].Sum();
+                                    allScore += simple.point.Sum();
                                 }
-                                powSum += Math.Pow(sc - NewsRateScore, 2);
-                            }
-                            info.standard = Math.Round(examResults[0].studentIds.Count > 0 ? Math.Pow(powSum / examResults[0].studentIds.Count, 0.5) : 0, 2);
-                            double NewsRate = allScore > 0 ? Math.Round(NewsRateScore / allScore * 100, 2) : 0;
-                            info.lostStu = losStu;
-                            /*//补充历史数据的容器名称
-                            if (string.IsNullOrEmpty(info.cn)) {
-                                if (info.scope.Equals("school"))
+                                //计算全科标准差
+                                foreach (string id in examResults[0].studentIds)
                                 {
-                                    info.cn = info.school;
+                                    double sc = 0;
+                                    foreach (ExamResult result in examResults)
+                                    {
+                                        sc += result.studentScores[result.studentIds.IndexOf(id)].Sum();
+                                    }
+                                    powSum += Math.Pow(sc - NewsRateScore, 2);
                                 }
-                                else {
-                                    info.cn = info.creatorId;
+                                info.standard = Math.Round(examResults[0].studentIds.Count > 0 ? Math.Pow(powSum / examResults[0].studentIds.Count, 0.5) : 0, 2);
+                                double NewsRate = allScore > 0 ? Math.Round(NewsRateScore / allScore * 100, 2) : 0;
+                                info.lostStu = losStu;
+                                /*//补充历史数据的容器名称
+                                if (string.IsNullOrEmpty(info.cn)) {
+                                    if (info.scope.Equals("school"))
+                                    {
+                                        info.cn = info.school;
+                                    }
+                                    else {
+                                        info.cn = info.creatorId;
+                                    }
+                                }*/
+                                //判断均分是否发生变化,便于实时的更新评测基本信息
+                                if (info.sRate != NewsRate || info.average != NewsRateScore)
+                                {
+                                    info.sRate = NewsRate;
+                                    info.average = NewsRateScore;
+                                    await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
                                 }
-                            }*/
-                            //判断均分是否发生变化,便于实时的更新评测基本信息
-                            if (info.sRate != NewsRate || info.average != NewsRateScore)
+                            }
+                            catch (Exception e)
                             {
-                                info.sRate = NewsRate;
-                                info.average = NewsRateScore;
-                                await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync<ExamInfo>(info, info.id, new Azure.Cosmos.PartitionKey(info.code));
+                                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测finish状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
                             }
-                        }
-                        catch (Exception e)
-                        {
-                            await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测finish状态异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
-                        }
-                        break;
+                            break;
+                    }
                 }
+
             }
             catch (Exception e)
             {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-{info.id}-评测结算异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-评测结算异常{e.Message}\n{e.StackTrace}", GroupNames.成都开发測試群組);
             }
 
         }
@@ -528,7 +535,7 @@ namespace TEAMModelFunction
                 //确定低分组 最高分数
                 //scores.Sort((s1, s2) => { return s1.CompareTo(s2); });
                 double rhlCount = Math.Ceiling(scores.Count * 0.73);
-                double rhl = rhlCount > 0 ? scores[int.Parse(rhlCount.ToString("0"))-1] : 0;
+                double rhl = rhlCount > 0 ? scores[int.Parse(rhlCount.ToString("0")) - 1] : 0;
                 //存放高分组学生ID
                 List<string> phId = new List<string>();
                 List<string> plId = new List<string>();
@@ -703,13 +710,13 @@ namespace TEAMModelFunction
                 int phcount = 0;
                 int plcount = 0;
                 //存放并去重知识点
-                List<int> knowledgeName = new List<int>();
-                knowledgeName.Add(1);
+                List<int> knowledgeName = new List<int>() { 1,2,3,4,5,6};
+/*                knowledgeName.Add(1);
                 knowledgeName.Add(2);
                 knowledgeName.Add(3);
                 knowledgeName.Add(4);
                 knowledgeName.Add(5);
-                knowledgeName.Add(6);
+                knowledgeName.Add(6);*/
                 foreach (ExamClassResult classResult in classResults)
                 {
                     if (classResult.subjectId.Equals(subject.id))
@@ -961,6 +968,6 @@ namespace TEAMModelFunction
 
             await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, "Common").UpsertItemAsync(result, new Azure.Cosmos.PartitionKey($"ExamResult-{info.id}"));
 
-        }       
+        }
     }
 }

+ 5 - 3
TEAMModelFunction/TriggerExamLite.cs

@@ -39,9 +39,11 @@ namespace TEAMModelFunction
                 }
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修评测活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
                 ExamLite lite = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamLite>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", lite.progress } });
+                
                 if (lite != null)
                 {
+                    string PartitionKey = string.Format("{0}{1}{2}", lite.code, "-", lite.progress);
+                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
                     switch (lite.progress)
                     {
                         case "pending":
@@ -60,7 +62,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "pending",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = start,
                                     msgId = messageWork.MessageId
                                 };
@@ -113,7 +115,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "going",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = end,
                                     msgId = messageWorkEnd.MessageId
                                 };

+ 6 - 4
TEAMModelFunction/TriggerWork.cs

@@ -14,7 +14,7 @@ using TEAMModelOS.SDK.Models.Service;
 
 namespace TEAMModelFunction
 {
-    public static class TriggerWork
+    public static class TriggerHomework
     {
         public static async void Trigger(AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing,
                     CosmosClient client, Document input, TriggerData tdata, AzureRedisFactory _azureRedis)
@@ -40,9 +40,11 @@ namespace TEAMModelFunction
                 }
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}作业活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
                 Homework work = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Homework>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", work.progress } });
+                
                 if (work != null)
                 {
+                    string PartitionKey = string.Format("{0}{1}{2}", work.code, "-", work.progress);
+                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
                     switch (work.progress)
                     {
                         case "pending":
@@ -61,7 +63,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "pending",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = start,
                                     msgId = messageWork.MessageId
                                 };
@@ -171,7 +173,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "going",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = end,
                                     msgId = messageWorkEnd.MessageId
                                 };

+ 6 - 5
TEAMModelFunction/TriggerStudy.cs

@@ -39,10 +39,11 @@ namespace TEAMModelFunction
                 }
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
                 Study study = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Study>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", study.progress } });
+                
                 if (study != null)
                 {
-
+                    string PartitionKey = string.Format("{0}{1}{2}", study.code, "-", study.progress);
+                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
                     switch (study.progress)
                     {
                         case "pending":
@@ -61,7 +62,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "pending",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = start,
                                     msgId = messageWork.MessageId
                                 };
@@ -114,7 +115,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "going",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = end,
                                     msgId = messageWorkEnd.MessageId
                                 };
@@ -129,7 +130,7 @@ namespace TEAMModelFunction
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动异常{ex.Message}{ex.StackTrace}", GroupNames.成都开发測試群組);
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}研修活动异常{ex.Message}{ex.StackTrace}{tdata.ToJsonString()}{input}", GroupNames.成都开发測試群組);
             }
 
         }

+ 5 - 3
TEAMModelFunction/TriggerSurvey.cs

@@ -48,9 +48,11 @@ namespace TEAMModelFunction
                     blobcntr = tdata.creatorId;
                 }
                 Survey survey = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Survey>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", survey.progress } });
+                
                 if (survey != null)
                 {
+                    string PartitionKey = string.Format("{0}{1}{2}", survey.code, "-", survey.progress);
+                    List<ChangeRecord> changeRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
                     switch (survey.progress)
                     {
                         case "pending":
@@ -69,7 +71,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "pending",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = start,
                                     msgId = messageSurvey.MessageId
                                 };
@@ -203,7 +205,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "going",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = end,
                                     msgId = messageSurveyEnd.MessageId
                                 };

+ 5 - 3
TEAMModelFunction/TriggerVote.cs

@@ -48,9 +48,11 @@ namespace TEAMModelFunction
                 }
                 await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}投票活动【{tdata.name}-{tdata.id}-ttl={tdata.ttl}】正在操作", GroupNames.成都开发測試群組);
                 Vote vote = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(input.Id, new Azure.Cosmos.PartitionKey($"{tdata.code}"));
-                List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", vote.progress } });
+                
                 if (vote != null)
                 {
+                    string PartitionKey = string.Format("{0}{1}{2}", vote.code, "-", vote.progress);
+                    List<ChangeRecord> voteRecords = await _azureStorage.FindListByDict<ChangeRecord>(new Dictionary<string, object>() { { "RowKey", input.Id }, { "PartitionKey", PartitionKey } });
                     switch (vote.progress)
                     {
                         case "pending":
@@ -69,7 +71,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "pending",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = start,
                                     msgId = messageVote.MessageId
                                 };
@@ -212,7 +214,7 @@ namespace TEAMModelFunction
                                 ChangeRecord changeRecord = new ChangeRecord
                                 {
                                     RowKey = input.Id,
-                                    PartitionKey = "going",
+                                    PartitionKey = PartitionKey,
                                     sequenceNumber = end,
                                     msgId = messageVoteEnd.MessageId
                                 };

+ 1 - 0
TEAMModelFunction/local.settings.json

@@ -12,6 +12,7 @@
     "Azure:Redis:ConnectionString": "106.12.23.251:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240",
     "Azure:ServiceBus:ActiveTask": "dep-active-task",
     "Azure:ServiceBus:NoticeTask": "dep-notice-task",
+    "Azure:ServiceBus:ItemCondQueue": "dep-itemcond",
     "Option:Location": "China-Dep",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet"
   }  

+ 0 - 32
TEAMModelOS.SDK/Context/Configuration/BaseConfigModel.cs

@@ -1,32 +0,0 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace TEAMModelOS.SDK.Context.Configuration
-{
-    public class BaseConfigModel
-    {
-        public static IConfiguration Configuration { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-
-        public static string ContentRootPath { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-
-        public static string WebRootPath { get; set; }
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="config"></param>
-        /// <param name="contentRootPath"></param>
-        /// <param name="webRootPath"></param>
-        public static void SetBaseConfig(IConfiguration config, string contentRootPath, string webRootPath)
-        {
-            Configuration = config;
-            ContentRootPath = contentRootPath;
-            WebRootPath = webRootPath;
-        }
-    }
-}

+ 4 - 4
TEAMModelOS.SDK/Context/Constant/Constant.cs

@@ -8,9 +8,9 @@ namespace TEAMModelOS.SDK.DI
     {
         public static readonly List<string> BlobPrefix = new List<string> { "exam", "vote", "survey", "item", "paper", "syllabus", "records", "doc", "image", "res", "video", "audio", "other", "thum", "train", "temp", "jyzx" };
         public static readonly List<string> ContentPrefix = new List<string> { "doc", "image", "res", "video", "audio", "other"};
-        public static string TEAMModelOS = "TEAMModelOS";
-        public static string ScopeTeacher = "teacher";
-        public static string ScopeTmdUser = "tmduser";
-        public static string ScopeStudent = "student";
+        public static readonly string TEAMModelOS = "TEAMModelOS";
+        public static readonly string ScopeTeacher = "teacher";
+        public static readonly string ScopeTmdUser = "tmduser";
+        public static readonly string ScopeStudent = "student";
     }
 }

+ 57 - 0
TEAMModelOS.SDK/DI/CoreAPI/CoreAPIHttpService.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.Extension;
+
+
+namespace TEAMModelOS.SDK.Models.Service
+{
+    public class CoreAPIHttpService
+    {
+        private readonly HttpClient _httpClient;
+        public CoreAPIHttpService(HttpClient httpClient)
+        {
+            _httpClient = httpClient;
+        }
+        /// <summary>
+        ///  隐式登录
+        /// </summary>
+        /// <param name="clientID"></param>
+        /// <param name="clientSecret"></param>
+        /// <param name="location"></param>
+        /// <param name="url"></param>
+        /// <param name="data"></param>
+        /// <returns></returns>
+        public async Task<(int code ,string content)> Implicit(string clientID, string clientSecret, string location, string url,Dictionary<string,string> data)
+        {
+            if (location.Contains("China"))
+            {
+                location = "China";
+            }
+            else if (location.Contains("Global"))
+            {
+                location = "Global";
+            }
+            var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location);
+            _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}");
+            HttpResponseMessage responseMessage = await _httpClient.PostAsJsonAsync(url, data);
+            if (responseMessage.StatusCode == HttpStatusCode.OK)
+            {
+                string content=await responseMessage.Content.ReadAsStringAsync();
+                return (200,content);
+            }
+            else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
+            {
+                return (401,null);
+            }
+            else
+            {
+                return (500,null);
+            }
+        }
+    } 
+}

+ 93 - 0
TEAMModelOS.SDK/Helper/Common/StringHelper/PingYinHelper.cs

@@ -0,0 +1,93 @@
+using Microsoft.International.Converters.PinYinConverter;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NUnit.Framework.Internal;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Helper.Common.StringHelper
+{
+   public static class PingYinHelper
+    {
+        /// <summary>
+        /// 汉字转全拼
+        /// </summary>
+        /// <param name="strChinese"></param>
+        /// <returns></returns>
+        public static string ConvertToAllSpell(string strChinese)
+        {
+            try
+            {
+                if (strChinese.Length != 0)
+                {
+                    StringBuilder fullSpell = new StringBuilder();
+                    for (int i = 0; i < strChinese.Length; i++)
+                    {
+                        var chr = strChinese[i];
+                        fullSpell.Append(GetSpell(chr));
+                    }
+
+                    return fullSpell.ToString().ToLower();
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("全拼转化出错!" + e.Message);
+            }
+
+            return string.Empty;
+        }
+
+        /// <summary>
+        /// 汉字转首字母
+        /// </summary>
+        /// <param name="strChinese"></param>
+        /// <returns></returns>
+        public static string GetFirstSpell(string strChinese)
+        {
+            //NPinyin.Pinyin.GetInitials(strChinese)  有Bug  洺无法识别
+            //return NPinyin.Pinyin.GetInitials(strChinese);
+
+            try
+            {
+                if (strChinese.Length != 0)
+                {
+                    StringBuilder fullSpell = new StringBuilder();
+                    for (int i = 0; i < strChinese.Length; i++)
+                    {
+                        var chr = strChinese[i];
+                        fullSpell.Append(GetSpell(chr)[0]);
+                    }
+
+                    return fullSpell.ToString().ToLower();
+                }
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine("首字母转化出错!" + e.Message);
+            }
+
+            return string.Empty;
+        }
+
+        private static string GetSpell(char chr)
+        {
+            var coverchr = NPinyin.Pinyin.GetPinyin(chr);
+
+            bool isChineses = ChineseChar.IsValidChar(coverchr[0]);
+            if (isChineses)
+            {
+                ChineseChar chineseChar = new ChineseChar(coverchr[0]);
+                foreach (string value in chineseChar.Pinyins)
+                {
+                    if (!string.IsNullOrEmpty(value))
+                    {
+                        return value.Remove(value.Length - 1, 1);
+                    }
+                }
+            }
+            return coverchr;
+
+        }
+    }
+}

+ 2 - 2
TEAMModelOS.SDK/Helper/Security/Md5Hash/Md5Hash.cs

@@ -1,9 +1,9 @@
-using System;
+using System;
 using System.IO;
 using System.Security.Cryptography;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Helper.Security.Md5Hash
+namespace TEAMModelOS.SDK
 {
     public  class Md5Hash
     {

+ 41 - 0
TEAMModelOS.SDK/Models/Cosmos/BI/DeptNode.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.BI
+{
+    /// <summary>
+    /// 所有部门信息
+    /// </summary>
+    public class DeptNode: CosmosEntity
+    {
+        public List<DeptInfo> depts { get; set; }
+    }
+
+    /// <summary>
+    /// 单个部门信息
+    /// </summary>
+    public class DeptInfo
+    {
+
+        [Required(ErrorMessage = "{0} 必须填写")]
+        public long id { get; set; }
+
+        /// <summary>
+        /// 父级
+        /// </summary>
+        [Required(ErrorMessage = "{0} 必须填写")]
+        public long pid { get; set; }
+
+        /// <summary>
+        /// 部门名称
+        /// </summary>
+        public string name { get; set; }
+
+        /// <summary>
+        /// 用户列表
+        /// </summary>
+        public List<string> users { get; set; }
+    }
+}

+ 3 - 3
TEAMModelOS.SDK/Models/Cosmos/BI/DingDingUser.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.Text;
 
@@ -25,8 +25,8 @@ namespace TEAMModelOS.SDK.Models.Cosmos.BI
         public string deptPositionListTitle { get; set; }
         public string hiredDate { get; set; }
         public bool active { get; set; }
-        public List<rolelist> roleList { get; set; }
-        public class rolelist
+        public List<Role> roles { get; set; }
+        public class Role
         {
             public string id { get; set; }
             public string name { get; set; }

+ 40 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/ActivityRecord.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+
+namespace TEAMModelOS.SDK.Models.Cosmos.Common
+{
+    class ActivityRecord : CosmosEntity
+    {
+        /// <summary>
+        /// 源数据的发布层级 类型 school  teacher
+        /// </summary>
+        public string owner { get; set; }
+        /// <summary>
+        /// 源数据的 code
+        /// </summary>
+        public string scode { get; set; }
+        public string type { get; set; }
+        //评测模式
+        public string source { get; set; }
+        public string name { get; set; }
+        public long startTime { get; set; }
+        public long endTime { get; set; }
+        public string scope { get; set; }
+        public string school { get; set; }
+        public string creatorId { get; set; }
+        public List<string> subjects { get; set; }
+        public string blob { get; set; }
+        public string recordUrl { get; set; }
+        public List<string> classIds { get; set; } = new List<string>();
+
+        public long createTime { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+        /// <summary>
+        /// 任务完成状态,-1 未参与,0,未完成, 1已完成
+        /// </summary>
+        public int taskStatus { get; set; } = -1;
+        //写入投票记录,评测作答记录等,自行定义相关规范
+        public List<JsonElement> extParam { get; set; } = new List<JsonElement>();
+    }
+}

+ 68 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/GroupList.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models
+{
+    public class GroupList : CosmosEntity
+    {
+        public GroupList()
+        {
+            pk = "GroupList";
+        }
+        public string name { get; set; }
+        //标记该名单唯一code
+        public string no { get; set; }
+        public string periodId { get; set; }
+        //课程id,需要标记则标记
+        //public string courseId { get; set; }
+        public string scope { get; set; }
+        public string school { get; set; }
+        public string creatorId { get; set; }
+        /// <summary>
+        ///教学班teach ,行政班(学生搜寻classId动态返回)class ,教研组research,学科组(学科搜寻动态返回)subject,好友friend,管理manage,群组group等
+        /// </summary>
+        public string type { get; set; } = "teach";
+        public int year { get; set; }
+        /// <summary>
+        /// 醍摩豆id成员数量
+        /// </summary>
+        public int tcount { get; set; }
+        /// <summary>
+        /// 校内账号成员数量
+        /// </summary>
+        public int scount { get; set; }
+        public List<Member> members { get; set; } = new List<Member>();
+
+    }
+    public class Member
+    {
+        /// <summary>
+        /// 账号id
+        /// </summary>
+        public string id { get; set; }
+        //学生所在的学校
+        public string code { get; set; }
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string name { get; set; }
+        /// <summary>
+        ///类型 1 tmdid,2 student
+        /// </summary>
+        public int type { get; set; }
+        /// <summary>
+        /// 头像
+        /// </summary>
+        public string picture { get; set; }
+        /// <summary>
+        ///座号
+        /// </summary>
+        public string no { get; set; }
+        /// <summary>
+        /// IRS WebIRS编号。
+        /// </summary>
+        public string irs { get; set; }
+        public string tag { get; set; }
+    }
+}

+ 43 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/GroupChange.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models
+{
+    public class GroupChange
+    { /// <summary>
+      /// 醍摩豆学生名单加入的成员
+      /// </summary>
+        public List<Member> tmdjoin { get; set; } = new List<Member>();
+        /// <summary>
+        /// 醍摩豆学生名单离开的成员
+        /// </summary>
+        public List<Member> tmdleave { get; set; } = new List<Member>();
+        /// <summary>
+        /// 学校学生名单加入的成员
+        /// </summary>
+        public List<Member> stujoin { get; set; } = new List<Member>();
+        /// <summary>
+        /// 学校学生名单离开的成员
+        /// </summary>
+        public List<Member> stuleave { get; set; } = new List<Member>();
+
+        /// <summary>
+        /// 学校教师名单加入的成员
+        /// </summary>
+        public List<Member> tchjoin { get; set; } = new List<Member>();
+        /// <summary>
+        /// 学校教师名单离开的成员
+        /// </summary>
+        public List<Member> tchleave { get; set; } = new List<Member>();
+        public string listid { get; set; }
+        /// <summary>
+        /// 分区
+        /// </summary>
+        public string scope { get; set; }
+        public string originCode { get; set; }
+        public string school { get; set; }
+        public string creatorId { get; set; }
+        public string type { get; set; }
+    }
+}

+ 2 - 5
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/ListChange.cs

@@ -2,7 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 
-namespace TEAMModelOS.SDK.Models.Cosmos.Common
+namespace TEAMModelOS.SDK.Models
 {
     public class ListChange
     {
@@ -40,9 +40,6 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         public string school { get; set; }
         public string creatorId { get; set; }
         public string type { get; set; }
-        /// <summary>
-        /// 当状态码大于等于0则表示正常操作,只有当状态码=-1的时候
-        /// </summary>
-        public int listStatus { get; set; } = 1;
+       
     }
 }

+ 0 - 45
TEAMModelOS.SDK/Models/Cosmos/Common/JoinList.cs

@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.SDK.Models.Cosmos.Common
-{
-
-    /*
-     * {
-            "id": "28936",
-            "code": "JoinList-hbcn",
-            "school": [
-                "schoolClassid1"
-            ],
-            "teacher": [
-                "stulistGUID"
-            ]
-        },
-        {
-            "id": "tmdid",
-            "code": "JoinList-tmdid",
-            "school": [
-                "schoolClassid1"
-            ],
-            "teacher": [
-                "schoolClassid1"
-            ]
-        }
-     */
-
-    /// <summary>
-    /// 暂时不使用
-    /// 学生已经加入的名单列表
-    /// 分学校创建的学生名单和教师创建的私人名单
-    /// </summary>
-    public class JoinList : CosmosEntity
-    {
-        public JoinList()
-        {
-            pk = "JoinList";
-        }
-        public List<string> school { get; set; } = new List<string>();
-        public List<string> teacher { get; set; } = new List<string>();
-    }
-}

+ 1 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/MQActivity.cs

@@ -24,6 +24,7 @@ namespace TEAMModelOS.SDK.Models
         public string blob { get; set; }
         public long startTime { get; set; }
         public long endTime { get; set; }
+        public string source { get; set; }
 
     }
     public class Sub { 

+ 7 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Notice.cs

@@ -30,9 +30,16 @@ namespace TEAMModelOS.SDK.Models
         /// 结束时间
         /// </summary>
         public long endTime { get; set; }
+        /// <summary>
+        /// 结束时间
+        /// </summary>
+        public bool autoDelete { get; set; } = false;
+
         /// <summary>
         /// school, course,class
         /// </summary>
         public string type { get; set; }
+        public List<string> classes { get; set; } = new List<string>();
+        public List<Attachment> attachments { get; set; } = new List<Attachment>();
     }
 }

+ 1 - 9
TEAMModelOS.SDK/Models/Cosmos/Common/Scoring.cs

@@ -71,15 +71,7 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
 
             }
         }
-        public int isArb { get {
-                if (flag)
-                {
-                    return 0;
-                }
-                else {
-                    return 1;
-                }
-            } }
+        public int isArb { get; set; } = 0;
 
     }
     public class Info { 

+ 26 - 7
TEAMModelOS.SDK/Models/Cosmos/Common/SheetConfig.cs

@@ -90,18 +90,37 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public List<ConfigContent> contents { get; set; }
     }
+    //public class ConfigContent
+    //{
+    //    public int index { get; set; }
+    //    public int count { get; set; }
+    //    public int type { get; set; }
+    //    public int x { get; set; }
+    //    public int y { get; set; }
+    //    public int width { get; set; }
+    //    public int height { get; set; }
+    //    public int pageNum { get; set; }
+    //    public int vblockCount { get; set; }
+    //    public int hblockCount { get; set; }
+    //    public int id { get; set; }        
+    //}
     public class ConfigContent
     {
         public int index { get; set; }
         public int count { get; set; }
         public int type { get; set; }
-        public int x { get; set; }
-        public int y { get; set; }
-        public int width { get; set; }
-        public int height { get; set; }
         public int pageNum { get; set; }
-        public int vblockCount { get; set; }
-        public int hblockCount { get; set; }
-        public int id { get; set; }        
+        public List<Pos> pos { get; set; } = new List<Pos>();
+        public List<Point> points { get; set; } = new List<Point>();
+    }
+    public  class Pos
+    {
+        public double x { get; set; }
+        public double y { get; set; }
+    }
+    public class Point { 
+        public string ans { get; set; }
+        public int row { get; set; }
+        public List<Pos> pos { get; set; } = new List<Pos>();
     }
 }

+ 5 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/StuActivity.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Text.Json;
 
 namespace TEAMModelOS.SDK.Models
 {
@@ -47,6 +48,8 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string scode { get; set; }
         public string type { get; set; }
+        //评测模式
+        public string source { get; set; }
         public string name { get; set; }
         public long startTime { get; set; }
         public long endTime { get; set; }
@@ -63,6 +66,7 @@ namespace TEAMModelOS.SDK.Models
         /// 任务完成状态,-1 未参与,0,未完成, 1已完成
         /// </summary>
         public int taskStatus { get; set; } = -1;
-        //写入投票记录
+        //写入投票记录,评测作答记录等,自行定义相关规范
+        public List<JsonElement> extParam { get; set; } = new List<JsonElement>();
     }
 }

+ 5 - 1
TEAMModelOS.SDK/Models/Cosmos/Research/Ability.cs

@@ -71,7 +71,11 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         ///选修false  必修true
         /// </summary>
-        public bool compulsory { get; set; } =false;
+        public bool? compulsory { get; set; }
+        /// <summary>
+        ///默认未设置0 必修1 通识2 选修3
+        /// </summary>
+        public int currency { get; set; }
         public string standard { get; set; }
         public List<string> uncountIds { get; set; } = new List<string>();
     }

+ 6 - 0
TEAMModelOS.SDK/Models/Cosmos/School/ExamInfo.cs

@@ -105,6 +105,10 @@ namespace TEAMModelOS.SDK.Models
         public double standard { get; set; }
         //记录该评测内容下blob大小
         public long? size { get; set; } = 0;
+       //进线比列
+        public int income { get; set; } = 0;
+        //踩线比列
+        public int touch { get; set; } = 0;
         //容器名称 container name
         //public string cn { get; set; }
     }
@@ -134,6 +138,8 @@ namespace TEAMModelOS.SDK.Models
         public List<int> field { get; set; } = new List<int>();
         public  string  sheet { get; set; }        //public long sequenceNumber { get; set; }
         public string sheetNo { get; set; }        //public long sequenceNumber { get; set; }
+        //记录试卷作答时间
+        public int time { get; set; } = 0;
 
         //public List<Dictionary<string, int>> record { get; set; } = new List<Dictionary<string, int>>();
 

+ 3 - 3
TEAMModelOS.SDK/Models/Cosmos/School/Knowledge.cs

@@ -17,7 +17,7 @@ namespace TEAMModelOS.SDK.Models
         }
         [Required(ErrorMessage = "owner 必须设置")]
         public string owner { get; set; }
-        [Required(ErrorMessage = "scope 必须设置")]
+        
         public string scope { get; set; }
         /// <summary>
         /// 学段id
@@ -32,11 +32,11 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         /// 知识点
         /// </summary>
-        public List<string> points { get; set; }
+        public List<string> points { get; set; } = new List<string>();
         /// <summary>
         /// 知识块
         /// </summary>
-        public List<Block> blocks { get; set; }
+        public List<Block> blocks { get; set; } = new List<Block>();
 
     }
 

+ 42 - 37
TEAMModelOS.SDK/Models/Cosmos/School/Paper.cs

@@ -64,6 +64,7 @@ namespace TEAMModelOS.SDK.Models
         public string sheetNo { get; set; }
         //记录试卷大小
         public long? size { get; set; } = 0;
+
         
         /// <summary>
         /// type:{
@@ -94,41 +95,45 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public List<MarkConfig> scoring { get; set; }
         /// <summary>
-       /* /// 题目集合
-        /// </summary>
-        public List<string> itemids { get; set; }*/
-    }
-    /// <summary>
-    /// 阅卷规则
-    /// </summary>
-    public class MarkConfig
-    {
-        /// <summary>
-        /// 作答
-        /// </summary>
-        public List<string> ans { get; set; }
-        /// <summary>
-        /// 题目类型
-        /// </summary>
-        public string type { get; set; }
-        /// <summary>
-        /// 多选漏选指定得分
-        /// </summary>
-        public double? score { get; set; } = 0;
-    }
-    /*
-    public class ScoreItem
-    {
-        public ScoreItem()
-        {
-          item = new List<int>();
-        }
-        public double score { get; set; }
-        public List<int> item { get; set; }
+        /* /// 题目集合
+         /// </summary>
+         public List<string> itemids { get; set; }*/
+        /// <summary>
+        ///试卷标签
+        /// </summary>
+        public List<string> tags { get; set; } = new List<string>();
+     }
+     /// <summary>
+     /// 阅卷规则
+     /// </summary>
+     public class MarkConfig
+     {
+         /// <summary>
+         /// 作答
+         /// </summary>
+         public List<string> ans { get; set; }
+         /// <summary>
+         /// 题目类型
+         /// </summary>
+         public string type { get; set; }
+         /// <summary>
+         /// 多选漏选指定得分
+         /// </summary>
+         public double? score { get; set; } = 0;
+     }
+     /*
+     public class ScoreItem
+     {
+         public ScoreItem()
+         {
+           item = new List<int>();
+         }
+         public double score { get; set; }
+         public List<int> item { get; set; }
+     }
+     public class ScoreCount{
+
+         public double score { get; set; }
+         public int count { get; set; }
+     }*/
     }
-    public class ScoreCount{
-         
-        public double score { get; set; }
-        public int count { get; set; }
-    }*/
-}

+ 91 - 1
TEAMModelOS.SDK/Models/Cosmos/School/SchoolProduct.cs

@@ -8,7 +8,97 @@ using TEAMModelOS.SDK.Context.Attributes.Azure;
 using TEAMModelOS.SDK.DI;
 
 namespace TEAMModelOS.SDK.Models
-{    
+{
+    public class SchoolProductCommon : CosmosEntity
+    {
+        public SchoolProductCommon()
+        {
+            pk = "Product";
+        }
+        public string dataType { get; set; }
+        public string prodCode { get; set; }
+    }
+    public class SchoolProductSerial : SchoolProductCommon
+    {
+        public string serial { get; set; }
+        public List<deviceBound> deviceBound { get; set; }
+        public int clientQty { get; set; }
+        public long regDate { get; set; }
+        public long startDate { get; set; }
+        public long endDate { get; set; }
+        public int deviceMax { get; set; }
+        public object aprule { get; set; }
+        public string expireStatus { get; set; }
+        public int status { get; set; }
+    }
+    public class SchoolProductService : SchoolProductCommon
+    {
+        public long startDate { get; set; }
+        public long endDate { get; set; }
+        public int number { get; set; }
+        public string unit { get; set; }
+    }
+    public class SchoolProductHard : SchoolProductCommon
+    {
+        public string model { get; set; }
+        public string serial { get; set; }
+    }
+
+    public class SchoolProductSum
+    {
+        public SchoolProductSum()
+        {
+            pk = "ProductSum";
+            code = "ProductSum";
+            prodinfo = new List<SchoolProductSumProdInfo>();
+            serial = new List<SchoolProductSumData>();
+            service = new List<SchoolProductSumData>();
+            hard = new List<SchoolProductSumDataHard>();
+        }
+        public string pk { get; set; }
+        public string code { get; set; }
+        public string id { get; set; }
+        public List<SchoolProductSumProdInfo> prodinfo { get; set; }
+        public List<SchoolProductSumData> serial { get; set; }
+        public List<SchoolProductSumData> service { get; set; }
+        public List<SchoolProductSumDataHard> hard { get; set; }
+        //public Aclassone aclassone { get; set; } //¬O§_¿W¥ß¥X¨Ó¡A¥¼©w
+    }
+    public class SchoolProductSumProdInfo
+    {
+        public string prodCode { get; set; }
+        public string prodName { get; set; }
+        public string dataType { get; set; }
+        public ServiceType serviceType { get; set; }
+    }
+
+    public enum ServiceType
+    {
+        number = 0,
+        module = 1,
+        space = 2
+    }
+
+    public class SchoolProductSumData
+    {
+        public SchoolProductSumData()
+        {
+            ids = new List<string>();
+        }
+        public string prodCode { get; set; }
+        public List<string> ids { get; set; }
+        public int avaliable { get; set; }
+    }
+
+    public class SchoolProductSumDataHard : SchoolProductSumData
+    {
+        public string model { get; set; }
+    }
+
+
+    /////////////////////////////////////////////////////////
+
+
     public class SchoolProduct : CosmosEntity
     {        
         public SchoolProduct()

+ 11 - 1
TEAMModelOS.SDK/Models/Cosmos/School/StandardFile.cs

@@ -6,7 +6,9 @@ namespace TEAMModelOS.SDK.Models
 {
     public class StandardFile : CosmosEntity
     {
-        //id为区域编码,pk='StandardFile',code="StandardFile"
+        /// <summary>
+        /// id为区域编码,pk='StandardFile',code="StandardFile"
+        /// </summary>
         public StandardFile()
         {
             pk = "StandardFile";
@@ -52,5 +54,13 @@ namespace TEAMModelOS.SDK.Models
         /// 文件类型
         /// </summary>
         public string type { get; set; }
+        /// <summary>
+        /// 发布机构
+        /// </summary>
+        public string org { get; set; }
+        /// <summary>
+        /// 报告人/作者
+        /// </summary>
+        public string author { get; set; }
     }
 }

+ 7 - 0
TEAMModelOS.SDK/Models/Cosmos/Student/Student.cs

@@ -24,5 +24,12 @@ namespace TEAMModelOS.SDK.Models
         public string groupId { get; set; }
         public string groupName { get; set; }
         public string periodId { get; set; }
+        /// <summary>
+        /// 性别 m( male,男) f (female 女)  n(secret 保密) 
+        /// </summary>
+        public string gender { get; set; }
+        //补充留级信息
+        //0在校,1留级,2退学 3毕业
+        public int status { get; set; } = 0;
     }
 }

+ 2 - 0
TEAMModelOS.SDK/Models/Cosmos/Teacher/CorrectTask.cs

@@ -47,5 +47,7 @@ namespace TEAMModelOS.SDK.Models
         public int model { get; set; }
         public long createTime { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
         public string progress { get; set; }
+        //评测类型
+        public string source { get; set; }
     }
 }

+ 238 - 1
TEAMModelOS.SDK/Models/Cosmos/Teacher/Teacher.cs

@@ -11,14 +11,19 @@ namespace TEAMModelOS.SDK.Models
         public string picture { get; set; }
         public int size { get; set; }
         public string defaultSchool { get; set; }
-        public List<TeacherSchool> schools { get; set; }= new List<TeacherSchool>();
+        public List<TeacherSchool> schools { get; set; } = new List<TeacherSchool>();
         public List<TeacherArea> areas { get; set; } = new List<TeacherArea>();
+        public List<ThirdBind> binds { get; set; } = new List<ThirdBind>();
+        public List<DingDingBind> ddbinds { get; set; } = new List<DingDingBind>();
+
         public class TeacherSchool
         {
             public string schoolId { get; set; }
             public string name { get; set; }
             public string status { get; set; }
             public long time { get; set; }
+            public string picture { get; set; }
+            public string areaId { get; set; }
         }
         public class TeacherArea
         {
@@ -26,5 +31,237 @@ namespace TEAMModelOS.SDK.Models
             public string name { get; set; }
             public string status { get; set; }
         }
+        public class ThirdBind
+        {
+            /// <summary>
+            /// scsyxpt 四川省研修平台
+            /// </summary>
+            public string type { get; set; }
+            /// <summary>
+            /// 用户来源
+            /// </summary>
+            public string source { get; set; }
+
+            public string userid { get; set; }
+            public HashSet<string> pxid { get; set; } = new HashSet<string>();
+
+        }
+
+        public class DingDingBind
+        {
+
+            /// <summary>
+            /// 绑定类型  ddteammodel
+            /// </summary>
+            public string type { get; set; }
+
+            /// <summary>
+            /// 是否激活
+            /// </summary>
+            public string active { get; set; }
+
+            /// <summary>
+            /// 是否管理员
+            /// </summary>
+            public bool admin { get; set; }
+
+            /// <summary>
+            /// 头像
+            /// </summary>
+            public string avatar { get; set; }
+
+            /// <summary>
+            /// 是否老板
+            /// </summary>
+            public bool boss { get; set; }
+
+            /// <summary>
+            /// 所属部门id列表
+            /// </summary>
+            public List<long> deptIdList { get; set; }
+
+            /// <summary>
+            /// 员工在对应的部门中的排序
+            /// </summary>
+            public List<DeptOrderDomain> deptOrderList { get; set; }
+
+            /// <summary>
+            /// 任职信息
+            /// </summary>
+            public List<DeptPositionDomain> deptPositionList { get; set; }
+
+            /// <summary>
+            /// 员工工号
+            /// </summary>
+            public string jobNumber { get; set; }
+
+            /// <summary>
+            /// 员工在对应的部门中是否领导。
+            /// </summary>
+            public List<DeptLeaderDomain> leaderInDept { get; set; }
+
+            /// <summary>
+            /// 主管的ID,仅限企业内部开发调用
+            /// </summary>
+            public string managerUserid { get; set; }
+
+            /// <summary>
+            /// 手机号
+            /// </summary>
+            public string mobile { get; set; }
+
+            /// <summary>
+            /// 角色列表
+            /// </summary>
+            public List<UserRoleDomain> roleList { get; set; }
+
+            /// <summary>
+            /// 是否高管
+            /// </summary>
+            public bool senior { get; set; }
+
+            /// <summary>
+            /// 职位名称
+            /// </summary>
+            public string title { get; set; }
+
+            /// <summary>
+            /// 关联信息
+            /// </summary>
+            public UnionEmpExtDomain unionEmpExt { get; set; }
+
+            /// <summary>
+            /// 钉钉用户名
+            /// </summary>
+            public string name { get; set; }
+
+
+            /// <summary>
+            /// 钉钉unionid
+            /// </summary>
+            public string unionid { get; set; }
+
+            /// <summary>
+            /// 钉钉ID
+            /// </summary>
+            public string userid { get; set; }
+        }
+
+        /// <summary>
+        /// 员工在对应的部门中的排序的数据结构
+        /// </summary>
+        public class DeptOrderDomain 
+        {
+            /// <summary>
+            /// 部门id
+            /// </summary>
+            public long deptId { get; set; }
+
+            /// <summary>
+            /// 员工在部门中的排序。
+            /// </summary>
+            public long order { get; set; }
+        }
+
+        /// <summary>
+        /// 任职信息数据结构
+        /// </summary>
+        public class DeptPositionDomain 
+        {
+            /// <summary>
+            /// 部门ID
+            /// </summary>
+            public long deptId { get; set; }
+
+            /// <summary>
+            /// 是否是主任职
+            /// </summary>
+            public bool isMain { get; set; }
+
+            /// <summary>
+            /// 部门内职位
+            /// </summary>
+            public string title { get; set; }
+
+            /// <summary>
+            /// 部门内工作地
+            /// </summary>
+            public string workPlace { get; set; }
+        }
+
+        /// <summary>
+        /// 员工在对应的部门中是否领导 数据结构
+        /// </summary>
+        public class DeptLeaderDomain 
+        {
+            /// <summary>
+            /// 部门id
+            /// </summary>
+            public long deptId { get; set; }
+
+            /// <summary>
+            /// 是否领导
+            /// </summary>
+            public bool leader { get; set; }
+        }
+
+        /// <summary>
+        /// 角色列表 数据结构
+        /// </summary>
+        public class UserRoleDomain 
+        {
+            /// <summary>
+            /// 角色组名称
+            /// </summary>
+            public string groupName { get; set; }
+
+            /// <summary>
+            /// 角色id
+            /// </summary>
+            public long id { get; set; }
+
+            /// <summary>
+            /// 角色名称
+            /// </summary>
+            public string name { get; set; }
+        }
+
+        /// <summary>
+        /// 关联信息 数据结构
+        /// </summary>
+        public class UnionEmpExtDomain
+        {
+            /// <summary>
+            /// 企业ID
+            /// </summary>
+            public string corpId { get; set; }
+
+            /// <summary>
+            /// 关联映射关系
+            /// </summary>
+            public List<UnionEmpMapVoDomain> unionEmpMapList{get;set;}
+
+            /// <summary>
+            /// 员工id
+            /// </summary>
+            public string userid { get; set; }
+        }
+
+        /// <summary>
+        /// 关联映射关系
+        /// </summary>
+        public class UnionEmpMapVoDomain
+        {
+            /// <summary>
+            /// 企业id
+            /// </summary>
+            public string corpId { get; set; }
+
+            /// <summary>
+            /// 用户id
+            /// </summary>
+            public string userid { get; set; }
+        }
+
     }
 }

+ 14 - 0
TEAMModelOS.SDK/Models/Dtos/ItemCondDto.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.SDK.Models
+{
+    public  class ItemCondDto
+    {
+  
+        public string key { get; set; }
+        public string filed { get; set; }
+        public string scope { get; set; }
+    }
+}

+ 9 - 1
TEAMModelOS.SDK/Models/Service/ExamService.cs

@@ -44,9 +44,17 @@ namespace TEAMModelOS.SDK.Models.Service
                 trExam.scope = "school";
                 long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                 trExam.createTime = now;
-
+                if (trExam.startTime > now)
+                {
+                    trExam.progress = "pending";
+                }
+                else
+                {
+                    trExam.progress = "going";
+                }
                 if (string.IsNullOrEmpty(trExam.id))
                 {
+
                     trExam.id = Guid.NewGuid().ToString();
                     await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(trExam, new PartitionKey($"{trExam.code}"));
                 }

+ 770 - 0
TEAMModelOS.SDK/Models/Service/GroupListService.cs

@@ -0,0 +1,770 @@
+using Azure.Cosmos;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models.Cosmos.Common;
+using HTEXLib.COMM.Helpers;
+using System.Linq;
+using System.Text;
+using System.Text.Json;
+using TEAMModelOS.Models;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Extensions.Configuration;
+
+namespace TEAMModelOS.SDK.Models.Service
+{
+    public class GroupListService
+    {
+        public static async Task<(int status, GroupList stuList)> CodeJoinList(CosmosClient client, string _stuListNo, string userid, string name, string no, int type, string picture, string school)
+        {
+            var queryNo = $"SELECT  value(c)  FROM c where  c.no ='{_stuListNo}'";
+            (int status, GroupList stuList) data = (-1, null);
+            if (!string.IsNullOrEmpty(school))
+            {
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: queryNo,
+                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
+                {
+                    data = JoinList(item, userid, name, no, type, picture, school);
+                    break;
+                }
+            }
+            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<GroupList>(queryText: queryNo,
+                          requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList") }))
+            {
+                data = JoinList(item, userid, name, no, type, picture, school);
+                break;
+            }
+            return data;
+        }
+        public static (int status, GroupList stuList) JoinList(GroupList stuList, string userid, string name, string no, int type, string picture, string school)
+        {
+            int status = -1;
+            if (string.IsNullOrEmpty($"{userid}"))
+            {
+                //加入学生或醍摩豆ID为空
+                status = 1;
+            }
+            else
+            {
+                if (type == 1)
+                {
+                    var student = stuList.members.Find(x => x.type == 1 && x.id.Equals(userid));
+                    if (student != null)
+                    {
+                        //重复加入
+                        status = 2;
+                    }
+                    else
+                    {
+                        status = 0;
+                        stuList.members.Add(new Member { id = userid, name = name, no = no, picture = picture, type = type });
+                    }
+                }
+                else if (type == 2)
+                {
+                    var student = stuList.members.Find(x => x.type == 2 && x.id.Equals(userid) && x.code.Equals(school));
+                    if (student != null)
+                    {
+                        //重复加入
+                        status = 2;
+                    }
+                    else
+                    {
+                        status = 0;
+                        stuList.members.Add(new Member { id = userid, code = school, name = name, no = no, picture = picture, type = type });
+                    }
+                }
+            }
+            return (status, stuList);
+        }
+
+        public static async Task<GroupList> UpsertList(GroupList list, AzureCosmosFactory _azureCosmos, AzureStorageFactory _azureStorage, IConfiguration _configuration, AzureServiceBusFactory _serviceBus)
+        {
+            bool isnew = false;
+            var client = _azureCosmos.GetCosmosClient();
+            if (string.IsNullOrEmpty(list.id))
+            {
+                list.id = Guid.NewGuid().ToString();
+                isnew = true;
+            }
+            string tbname = list.scope.Equals("private") ? "Teacher" : "School";
+            list.tcount = list.members.Where(x => x.type == 1).Count();
+            list.scount = list.members.Where(x => x.type == 2).Count();
+            await client.GetContainer(Constant.TEAMModelOS, tbname).UpsertItemAsync(list, new PartitionKey(list.code));
+            //学生名单,教研组会触发活动中间表刷新
+            if (list.type.Equals("teach") || list.type.Equals("research"))
+            {
+                GroupChange change = new GroupChange()
+                {
+                    type = list.type,
+                    listid = list.id,
+                    scope = list.scope,
+                    originCode = list.school,
+                    school = list.school,
+                    creatorId = list.creatorId
+                };
+                GroupList oldList = null;
+                if (!isnew)
+                {
+                    try
+                    {
+                        oldList = await client.GetContainer(Constant.TEAMModelOS, tbname).ReadItemAsync<GroupList>(list.id, new PartitionKey(list.code));
+                    }
+                    catch (CosmosException)
+                    {
+                        oldList = null;
+                    }
+                }
+                if (list.members.IsNotEmpty() && (oldList == null || !oldList.members.IsNotEmpty()))
+                {
+                    //加入的
+                    var tmdids = list.members.FindAll(x => x.type == 1);
+                    if (tmdids.IsNotEmpty())
+                    {
+                        if (list.type.Equals("research"))
+                        {
+                            change.tchjoin.AddRange(tmdids);
+                        }
+                        else
+                        {
+                            change.tmdjoin.AddRange(tmdids);
+                        }
+                    }
+                    var stuids = list.members.FindAll(x => x.type == 2);
+                    if (stuids.IsNotEmpty())
+                    {
+                        change.stujoin.AddRange(stuids);
+                    }
+                }
+                else
+                {
+                    if (list.members.IsNotEmpty())
+                    {
+                        var tmdids = list.members.FindAll(x => x.type == 1);
+                        var oldtmdids = oldList.members.FindAll(x => x.type == 1);
+
+                        //取各自的差集
+                        //新=》旧差集,表示新增
+                        var jointmdid = tmdids.Select(x => x.id).Except(oldtmdids.Select(y => y.id)).ToList();
+                        //旧=》新差集,表示离开
+                        var leavetmdid = oldtmdids.Select(x => x.id).Except(tmdids.Select(y => y.id)).ToList();
+
+                        if (list.type.Equals("research"))
+                        {
+                            change.tchjoin.AddRange(tmdids.Where(x => jointmdid.Exists(y => y.Equals(x.id))));
+                            change.tchleave.AddRange(oldtmdids.Where(x => leavetmdid.Exists(y => y.Equals(x.id))));
+                        }
+                        else
+                        {
+                            change.tmdjoin.AddRange(tmdids.Where(x => jointmdid.Exists(y => y.Equals(x.id))));
+                            change.tmdleave.AddRange(oldtmdids.Where(x => leavetmdid.Exists(y => y.Equals(x.id))));
+                        }
+                        var stuids = list.members.FindAll(x => x.type == 2);
+                        var oldstuids = oldList.members.FindAll(x => x.type == 2);
+
+                        var joinstudent = stuids.Select(x => (x.id, x.code)).Except(oldstuids.Select(y => (y.id, y.code)), new CompareIdCode()).ToList();
+                        var leavestudent = oldstuids.Select(x => (x.id, x.code)).Except(stuids.Select(y => (y.id, y.code)), new CompareIdCode()).ToList();
+
+                        change.stujoin.AddRange(stuids.Where(x => joinstudent.Exists(y => y.id.Equals(x.id) && y.code.Equals(x.code))));
+                        change.stuleave.AddRange(oldstuids.Where(x => leavestudent.Exists(y => y.id.Equals(x.id) && y.code.Equals(x.code))));
+                    }
+                    else
+                    {
+                        //离开的
+                        var tmdids = oldList.members.FindAll(x => x.type == 1);
+                        if (tmdids.IsNotEmpty())
+                        {
+                            if (list.type.Equals("research"))
+                            {
+                                change.tchleave.AddRange(tmdids);
+                            }
+                            else
+                            {
+                                change.tmdleave.AddRange(tmdids);
+                            }
+                        }
+                        var stuids = oldList.members.FindAll(x => x.type == 2);
+                        if (stuids.IsNotEmpty())
+                        {
+                            change.stuleave.AddRange(stuids);
+                        }
+                    }
+                }
+                if (change.tmdjoin.Count != 0 || change.tmdleave.Count != 0 || change.stujoin.Count != 0 || change.stuleave.Count != 0
+                    || change.tchjoin.Count != 0 || change.tchleave.Count != 0)
+                {
+                    var messageChange = new ServiceBusMessage(change.ToJsonString());
+                    messageChange.ApplicationProperties.Add("name", "GroupChange");
+                    var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
+                    await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageChange);
+                }
+            }
+            return list;
+        }
+        public static async Task<GroupList> CheckListNo(GroupList list, AzureCosmosFactory _azureCosmos, DingDing _dingDing, Option _option)
+        {
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                if (string.IsNullOrEmpty(list.no))
+                {
+                    list.no = $"{Utils.CreatSaltString(6, "0123456789")}";
+                    for (int i = 0; i < 10; i++)
+                    {
+                        List<string> noStus = new List<string>();
+                        var queryNo = $"SELECT  c.no  FROM c where  c.no ='{list.no}'";
+                        if (list.scope.Equals("school"))
+                        {
+                            await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: queryNo,
+                                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"{list.code}") }))
+                            {
+                                using var jsonNo = await JsonDocument.ParseAsync(item.ContentStream);
+                                if (jsonNo.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                                {
+                                    var accounts = jsonNo.RootElement.GetProperty("Documents").EnumerateArray();
+                                    while (accounts.MoveNext())
+                                    {
+                                        JsonElement account = accounts.Current;
+                                        noStus.Add(account.GetProperty("no").GetString());
+                                    }
+                                }
+                            }
+                        }
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryStreamIterator(queryText: queryNo,
+                                requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey("GroupList") }))
+                        {
+                            using var jsonNo = await JsonDocument.ParseAsync(item.ContentStream);
+                            if (jsonNo.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                            {
+                                var accounts = jsonNo.RootElement.GetProperty("Documents").EnumerateArray();
+                                while (accounts.MoveNext())
+                                {
+                                    JsonElement account = accounts.Current;
+                                    noStus.Add(account.GetProperty("no").GetString());
+                                }
+                            }
+                        }
+                        if (noStus.Count == 0)
+                        {
+                            break;
+                        }
+                        else
+                        {
+                            if (i == 9)
+                            {
+                                string msg = $"OS,{_option.Location},school/course/upsert-list()\n 编号生成异常,重复生成次数超过10次";
+                                await _dingDing.SendBotMsg(msg, GroupNames.醍摩豆服務運維群組);
+                                throw new Exception(msg);
+                            }
+                            else
+                            {
+                                list.no = $"{Utils.CreatSaltString(6, "0123456789")}";
+                            }
+                        }
+                    }
+                }
+
+            }
+            catch (Exception ex)
+            {
+
+            }
+            return list;
+        }
+        public static async Task<List<GroupList>> GetStutmdidListids(CosmosClient client, DingDing _dingDing, List<string> classes, string school)
+        {
+            List<GroupList> groupLists = null;
+            if (classes.Count == 1 && classes.First().Equals("default") && !string.IsNullOrEmpty(school))
+            {
+                //默认的教研组
+                List<Member> members = new List<Member>();
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<TmdInfo>(queryText: $"SELECT  value(c) FROM c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school}") }))
+                {
+                    Member member = new Member
+                    {
+                        id = item.id,
+                        name = item.name,
+                        picture = item.picture,
+                        type = 1,
+                    };
+                    members.Add(member);
+                }
+                GroupList groupList = new GroupList
+                {
+                    id = "default",
+                    name = "default",
+                    code = $"GroupList-{school}",
+                    school = school,
+                    scope = "school",
+                    type = "research",
+                    members = members
+                };
+                groupLists = new List<GroupList> { groupList };
+            }
+            else
+            {
+                Dictionary<string, List<GroupList>> groups = new Dictionary<string, List<GroupList>>();
+                List<Student> students = new List<Student>();
+                string sql = string.Join(",", classes.Select(x => $"'{x}'"));
+                if (!string.IsNullOrEmpty(school))
+                {
+                    List<GroupList> schoolList = new List<GroupList>();
+
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<GroupList>(queryText: $"select value(c) from c where c.id in ({sql})",
+                            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList-{school}") }))
+                    {
+                        schoolList.Add(item);
+                    }
+                    if (schoolList.IsNotEmpty())
+                    {
+                        groups.Add("School", schoolList);
+                    }
+                    //取差集,减少二次搜寻
+                    classes = classes.Except(schoolList.Select(y => y.id)).ToList();
+                    if (classes.IsNotEmpty())
+                    {
+                        sql = string.Join(",", classes.Select(x => $"'{x}'"));
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: $"select value(c) from c where c.classId in ({sql})",
+                            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Base-{school}") }))
+                        {
+                            students.Add(item);
+                        }
+                        //取差集,减少二次搜寻
+                        classes = classes.Except(students.Select(y => y.classId)).ToList();
+                    }
+                }
+                if (classes.IsNotEmpty())
+                {
+                    List<GroupList> privateList = new List<GroupList>();
+                    sql = string.Join(",", classes.Select(x => $"'{x}'"));
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<GroupList>(queryText: $"select value(c) from c where c.id in ({sql})",
+                           requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"GroupList") }))
+                    {
+                        privateList.Add(item);
+                    }
+                    if (privateList.IsNotEmpty())
+                    {
+                        groups.Add("Teacher", privateList);
+                    }
+                }
+                foreach (var item in groups)
+                {
+                    var list = item.Value.GroupBy(x => x.type).Select(y => new { key = y.Key, list = y.ToList() });
+                    foreach (var group in list)
+                    {
+                        await GetGroupListMemberInfo(client, group.key, group.list, item.Key);
+                    }
+                }
+                groupLists = groups.SelectMany(x => x.Value).ToList();
+                if (students.IsNotEmpty())
+                {
+                    List<string> sqlList = students.Select(x => x.classId).ToList();
+                    string insql = string.Join(",", sqlList.Select(x => $"'{x}'"));
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ClassInfo>(queryText: $"select c.id,c.name ,c.periodId  ,c.year from c where c.id in ({insql})",
+                              requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Class-{school}") }))
+                    {
+                        ///行政班(学生搜寻classId动态返回)class
+                        List<Member> members = students.Where(x => x.classId.Equals(item.id)).Select(y => new Member { id = y.id, code = school, name = y.name, type = 2, picture = y.picture, no = y.no }).ToList();
+                        GroupList group = new GroupList
+                        {
+                            id = item.id,
+                            code = $"GroupList-{school}",
+                            name = item.name,
+                            periodId = item.periodId,
+                            scope = "school",
+                            school = school,
+                            type = "class",
+                            year = item.year,
+                            members = members,
+                            scount = members.Count
+                        };
+                        groupLists.Add(group);
+                    }
+                }
+            }
+            return groupLists;
+        }
+
+        public static async Task<(List<GroupList> groups, List<Member> members)> GetGroupListMemberInfo(CosmosClient client, string type, List<GroupList> groups, string groupTbname)
+        {
+
+            var members = groups.SelectMany(y => y.members).ToList();
+            //去重
+            List<Member> tmids = members.FindAll(x => x.type == 1).Where((x, i) => members.FindAll(x => x.type == 1).FindIndex(n => n.id.Equals(x.id)) == i).ToList();
+            List<Member> students = members.FindAll(x => x.type == 2).Where((x, i) => members.FindAll(x => x.type == 2).FindIndex(n => n.id.Equals(x.id) && n.code.Equals(x.code)) == i).ToList();
+            var stu = students.GroupBy(x => x.code).Select(y => new { key = y.Key, list = y.ToList() });
+            List<Student> studentsData = new List<Student>();
+            if (stu != null)
+            {
+                foreach (var item in stu)
+                {
+                    var ids = item.list.Select(x => x.id).ToList();
+                    if (ids.IsNotEmpty())
+                    {
+                        StringBuilder stuSql = new StringBuilder($"SELECT distinct c.name,c.id,c.code,c.picture,c.no FROM c ");
+                        string insql = string.Join(",", ids.Select(x => $"'{x}'"));
+                        stuSql.Append($"c.id in ({insql})");
+                        await foreach (var student in client.GetContainer(Constant.TEAMModelOS, "Student").GetItemQueryIterator<Student>(queryText: stuSql.ToString(),
+                            requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-{item.key}") }))
+                        {
+                            studentsData.Add(student);
+                        }
+                    }
+                }
+            }
+            List<TmdUser> tmdsData = new List<TmdUser>();
+            if (tmids.IsNotEmpty())
+            {
+                string memberTbname = "";
+                //可能会出现在两种表中
+                if ($"{type}".Equals("teach") || $"{type}".Equals("research") || $"{type}".Equals("group")
+                    || $"{type}".Equals("friend") || $"{type}".Equals("manage") || $"{type}".Equals("subject"))
+                {
+                    StringBuilder tmdidSql = new StringBuilder($"SELECT distinct c.name,c.id,c.picture FROM c ");
+                    string insql = string.Join(",", tmids.Select(x => $"'{x.id}'"));
+                    tmdidSql.Append($" where  c.id in ({insql})");
+                    memberTbname = "Teacher";
+                    await foreach (var tmd in client.GetContainer(Constant.TEAMModelOS, memberTbname).GetItemQueryIterator<TmdUser>(queryText: tmdidSql.ToString(),
+                            requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
+                    {
+                        tmdsData.Add(tmd);
+                    }
+                }
+                if ($"{type}".Equals("teach") || $"{type}".Equals("friend") || $"{type}".Equals("group"))
+                {
+                    //取差集,减少二次搜寻
+                    var tmdidexp = tmids.Select(x => x.id).Except(tmdsData.Select(y => y.id)).ToList();
+                    if (tmdidexp.IsNotEmpty())
+                    {
+                        StringBuilder tmdidSql = new StringBuilder($"SELECT distinct c.name,c.id,c.picture FROM c ");
+                        string insql = string.Join(",", tmdidexp.Select(x => $"'{x}'"));
+                        tmdidSql.Append($" where  c.id in ({insql})");
+
+                        memberTbname = "Student";
+                        await foreach (var tmd in client.GetContainer(Constant.TEAMModelOS, memberTbname).GetItemQueryIterator<TmdUser>(queryText: tmdidSql.ToString(),
+                                requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
+                        {
+                            tmdsData.Add(tmd);
+                        }
+                    }
+                }
+                //去重
+                tmdsData = tmdsData.Where((x, i) => tmdsData.FindIndex(n => n.id.Equals(x.id)) == i).ToList();
+            }
+            HashSet<GroupList> changes = new HashSet<GroupList>();
+            var unexist_tmdid = tmids.Select(x => x.id).Except(tmdsData.Select(y => y.id)).ToList();
+            groups.ForEach(x =>
+            {
+                int item = x.members.RemoveAll(y => unexist_tmdid.Contains(y.id) && y.type == 1);
+                if (item > 0)
+                {
+                    changes.Add(x);
+                }
+            });
+            var unexist_student = students.Select(x => (x.id, x.code)).Except(studentsData.Select(y => (y.id, y.code)), new CompareIdCode()).ToList();
+            groups.ForEach(x =>
+            {
+                int item = x.members.RemoveAll(y => y.type == 2 && unexist_student.Exists(x => x.id.Equals(y.id) && x.code.Equals(y.code)));
+                if (item > 0)
+                {
+                    changes.Add(x);
+                }
+            });
+            if (changes.Count > 0 && !string.IsNullOrEmpty(groupTbname))
+            {
+                foreach (var change in changes)
+                {
+                    change.tcount = change.members.Where(x => x.type == 1).Count();
+                    change.scount = change.members.Where(x => x.type == 2).Count();
+                    await client.GetContainer(Constant.TEAMModelOS, groupTbname).ReplaceItemAsync(change, change.id, new PartitionKey(change.code));
+                }
+            }
+            tmids.ForEach(x =>
+            {
+                var user = tmdsData.Find(y => y.id.Equals(x.id));
+                x.name = user?.name;
+                x.picture = user?.picture;
+            });
+            students.ForEach(x =>
+            {
+                var student = studentsData.Find(y => y.id.Equals(x.id) && y.code.Equals(x.code));
+                x.name = student?.name;
+                x.picture = student?.picture;
+                x.no = student?.no;
+            });
+            var mbs = tmids;
+            mbs.AddRange(students);
+            return (groups, mbs);
+        }
+
+        public static async Task FixActivity(CosmosClient client, DingDing _dingDing, GroupChange groupChange, string type)
+        {
+            try
+            {
+                var query = $"SELECT distinct c.owner, c.id,c.code, c.classes,c.stuLists,c.subjects,c.progress,c.scope,c.startTime,c.school,c.creatorId,c.name,c.pk ,c.endTime   FROM c  where  c.pk='{type}' " +
+                    $" and (( array_contains(c.classes,'{groupChange.listid}')) or ( array_contains(c.stuLists,'{groupChange.listid}'))or ( array_contains(c.tchLists,'{groupChange.listid}')))";
+                //$"and A1 in('{groupChange.listid}') ";
+                List<MQActivity> datas = new List<MQActivity>();
+                if (groupChange.scope.Equals("school", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(groupChange.school))
+                {
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<MQActivity>(queryText: query,
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"{type}-{groupChange.school}") }))
+                    {
+                        datas.Add(item);
+                    }
+                    ///还要处理该学校每个老师发布的班级的
+                    List<SchoolTeacher> teachers = new List<SchoolTeacher>();
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<SchoolTeacher>(queryText: $"SELECT c.id, c.name FROM c",
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{groupChange.school}") }))
+                    {
+                        teachers.Add(item);
+                    }
+                    foreach (var techer in teachers)
+                    {
+                        var queryTech = $"SELECT distinct c.owner, c.id,c.code, c.classes,c.stuLists,c.subjects,c.progress,c.scope,c.startTime,c.school,c.creatorId,c.name,c.pk ,c.endTime   FROM c " +
+                            $" where c.school='{groupChange.school}'   and   c.pk='{type}'" +
+                            $" and (( array_contains(c.classes,'{groupChange.listid}')) or ( array_contains(c.stuLists,'{groupChange.listid}')))";
+                        //  $" and A1 in('{groupChange.listid}') ";
+                        await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<MQActivity>(queryText: queryTech,
+                            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"{type}-{techer.id}") }))
+                        {
+                            datas.Add(item);
+                        }
+                    }
+                }
+                if (groupChange.scope.Equals("private", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(groupChange.creatorId))
+                {
+                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<MQActivity>(queryText: query,
+                        requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"{type}-{groupChange.creatorId}") }))
+                    {
+                        datas.Add(item);
+                    }
+                }
+                long nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+                foreach (MQActivity activity in datas)
+                {
+                    //已经完结的不再允许加入,还未开始的。
+                    if (string.IsNullOrEmpty(activity.progress)|| activity.progress.Equals("finish") || activity.progress.Equals("pending"))
+                    {
+                        continue;
+                    }
+                    List<string> classes = ExamService.getClasses(activity.classes, activity.stuLists);
+                    //stujoin新加入名单的
+                    foreach (Member member in groupChange.stujoin)
+                    {
+                        var stucourse = new StuActivity
+                        {
+                            id = activity.id,
+                            scode = activity.code,
+                            name = activity.name,
+                            code = $"Activity-{member.code.Replace("Base-", "")}-{member.id}",
+                            scope = activity.scope,
+                            school = activity.school,
+                            creatorId = activity.creatorId,
+                            pk = "Activity",
+                            type = type,
+                            subjects = activity.pk.ToLower().Equals("exam") && activity.subjects.IsNotEmpty() ? new List<string>() { activity.subjects[0].id } : new List<string>() { "" },
+                            startTime = activity.startTime,
+                            endTime = activity.endTime,
+                            blob = activity.blob,
+                            owner = activity.owner,
+                            createTime = nowtime,
+                            taskStatus = -1,
+                            classIds = classes
+                        };
+                        await client.GetContainer(Constant.TEAMModelOS, "Student").UpsertItemAsync(stucourse, new PartitionKey(stucourse.code));
+                    }
+
+                    //tmdjoin新加入的
+                    foreach (Member member in groupChange.tmdjoin)
+                    {
+                        var stucourse = new StuActivity
+                        {
+                            id = activity.id,
+                            scode = activity.code,
+                            name = activity.name,
+                            code = $"Activity-{member.id}",
+                            scope = activity.scope,
+                            school = activity.school,
+                            creatorId = activity.creatorId,
+                            pk = "Activity",
+                            type = type,
+                            subjects = activity.pk.ToLower().Equals("exam") && activity.subjects.IsNotEmpty() ? new List<string>() { activity.subjects[0].id } : new List<string>() { "" },
+                            startTime = activity.startTime,
+                            endTime = activity.endTime,
+                            blob = activity.blob,
+                            owner = activity.owner,
+                            createTime = nowtime,
+                            taskStatus = -1,
+                            classIds = classes
+                        };
+                        await client.GetContainer(Constant.TEAMModelOS, "Student").UpsertItemAsync(stucourse, new PartitionKey(stucourse.code));
+                    }
+                    //tchjoin新加入的
+                    foreach (Member member in groupChange.tchjoin)
+                    {
+                        var stucourse = new StuActivity
+                        {
+                            id = activity.id,
+                            scode = activity.code,
+                            name = activity.name,
+                            code = $"Activity-{member.id}",
+                            scope = activity.scope,
+                            school = activity.school,
+                            creatorId = activity.creatorId,
+                            pk = "Activity",
+                            type = type,
+                            subjects = activity.pk.ToLower().Equals("exam") && activity.subjects.IsNotEmpty() ? new List<string>() { activity.subjects[0].id } : new List<string>() { "" },
+                            startTime = activity.startTime,
+                            endTime = activity.endTime,
+                            blob = activity.blob,
+                            owner = activity.owner,
+                            createTime = nowtime,
+                            taskStatus = -1,
+                            classIds = classes
+                        };
+                        await client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync(stucourse, new PartitionKey(stucourse.code));
+                    }
+                    foreach (Member member in groupChange.stuleave)
+                    {
+                        try
+                        {
+
+                            await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<StuActivity>(activity.id, new PartitionKey($"Activity-{member.code.Replace("Base-", "")}-{member.id}"));
+                        }
+                        catch (CosmosException)
+                        {
+                            continue;
+                            // 继续执行 删除失败
+                        }
+                    }
+                    foreach (Member member in groupChange.tmdleave)
+                    {
+                        try
+                        {
+
+                            await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemAsync<StuActivity>(activity.id, new PartitionKey($"Activity-{member.id}"));
+                        }
+                        catch (CosmosException)
+                        {
+                            continue;
+                            // 继续执行 删除失败
+                        }
+                    }
+                    foreach (Member member in groupChange.tchleave)
+                    {
+                        try
+                        {
+                            await client.GetContainer(Constant.TEAMModelOS, "Teacher").DeleteItemAsync<StuActivity>(activity.id, new PartitionKey($"Activity-{member.id}"));
+                        }
+                        catch (CosmosException)
+                        {
+                            continue;
+                            // 继续执行 删除失败
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-StuListService-FixActivity\n{ex.Message}{ex.StackTrace}{groupChange.ToJsonString()}{type}", GroupNames.醍摩豆服務運維群組);
+            }
+        }
+        public static async Task FixStuCourse(CosmosClient client, DingDing _dingDing, GroupChange groupChange)
+        {
+            //1.查找学校或教师的课程是否包含该名单的课程。
+            var query = $"select distinct c.code,c.id,c.no,c.name,c.scope, c.creatorId,c.school from c join A0 in c.schedule where A0.stulist = '{groupChange.listid}'";
+            List<Course> courses = new List<Course>();
+            if (groupChange.scope.Equals("school") && !string.IsNullOrEmpty(groupChange.school))
+            {
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<Course>(queryText: query,
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Course-{groupChange.school}") }))
+                {
+                    courses.Add(item);
+                }
+            }
+            if (groupChange.scope.Equals("private") && !string.IsNullOrEmpty(groupChange.creatorId))
+            {
+                await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<Course>(queryText: query,
+                    requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Course-{groupChange.creatorId}") }))
+                {
+                    courses.Add(item);
+                }
+            }
+            long nowtime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+            // await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-StuListService-FixStuCourse\n名单发生变更 需要处理的课程\n{courses.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
+            //2.获取课程的id 并尝试添加或移除对应的学生课程记录StuCourse。
+            foreach (var course in courses)
+            {
+                //学生新加入名单的
+                foreach (Member member in groupChange.stujoin)
+                {
+                    var stucourse = new StuCourse
+                    {
+                        id = course.id,
+                        scode = course.code,
+                        name = course.name,
+                        code = $"StuCourse-{member.code.Replace("Base-", "")}-{member.id}",
+                        scope = course.scope,
+                        school = course.school,
+                        creatorId = course.creatorId,
+                        pk = "StuCourse",
+                        stulist = new List<string> { groupChange.listid },
+                        createTime = nowtime
+                    };
+                    // await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-StuListService-FixStuCourse\n名单发生变更 新建课程中间表\n{stucourse.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
+                    await client.GetContainer(Constant.TEAMModelOS, "Student").UpsertItemAsync(stucourse, new PartitionKey(stucourse.code));
+                }
+                //tmd新加入的
+                foreach (Member member in groupChange.tmdjoin)
+                {
+                    var stucourse = new StuCourse
+                    {
+                        id = course.id,
+                        scode = course.code,
+                        name = course.name,
+                        code = $"StuCourse-{member.id}",
+                        scope = course.scope,
+                        school = course.school,
+                        creatorId = course.creatorId,
+                        pk = "StuCourse",
+                        stulist = new List<string> { groupChange.listid },
+                        createTime = nowtime
+                    };
+                    // await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-StuListService-FixStuCourse\n名单发生变更 新建课程中间表\n{stucourse.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
+                    await client.GetContainer(Constant.TEAMModelOS, "Student").UpsertItemAsync(stucourse, new PartitionKey(stucourse.code));
+                }
+                //移除名单的。 在点击相关的课程,再去二次校验是否存在,不存在则再去删除。
+                foreach (var delStu in groupChange.stuleave)
+                {
+                    await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemStreamAsync(course.id, new PartitionKey($"StuCourse-{delStu.code.Replace("Base-", "")}-{delStu.id}"));
+                }
+                foreach (var delTmd in groupChange.tmdleave)
+                {
+                    await client.GetContainer(Constant.TEAMModelOS, "Student").DeleteItemStreamAsync(course.id, new PartitionKey($"StuCourse-{delTmd}"));
+                }
+            }
+        }
+    }
+    public class CompareIdCode : IEqualityComparer<(string id, string code)>
+    {
+        public bool Equals((string id, string code) x, (string id, string code) y)
+        {
+            return x.id.Equals(y.id) && x.code.Equals(y.code);
+        }
+
+        public int GetHashCode((string id, string code) obj)
+        {
+            if (obj.id != null && obj.code != null)
+            {
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+    }
+}

+ 29 - 6
TEAMModelOS.SDK/Models/Service/HomeworkService.cs

@@ -1,15 +1,19 @@
 using Azure.Cosmos;
+using Azure.Messaging.ServiceBus;
+using Microsoft.Extensions.Configuration;
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Text.Json;
 using System.Threading.Tasks;
 using TEAMModelOS.SDK.DI;
+using TEAMModelOS.SDK.Extension;
 
 namespace TEAMModelOS.SDK.Models.Service
 {
-	public static class HomeworkService
-	{
-        public static async Task<string> saveMoreAsync(CosmosClient client, DingDing _dingDing, Homework work)
+    public static class HomeworkService
+    {
+        public static async Task<string> saveMoreAsync(CosmosClient client, DingDing _dingDing, Homework work, AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, IConfiguration _configuration)
         {
             try
             {
@@ -17,14 +21,33 @@ namespace TEAMModelOS.SDK.Models.Service
                 work.code = "Homework-" + work.school;
                 long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                 work.createTime = now;
+                var messageBlob = new ServiceBusMessage();
+                string blobcntr = null;
+                blobcntr = work.school;
+                work.size = await _azureStorage.GetBlobContainerClient(work.school).GetBlobsSize($"homework/{work.id}");
+                messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "insert", root = $"homework/{work.id}", name = $"{work.school}" }.ToJsonString());
 
+                messageBlob.ApplicationProperties.Add("name", "BlobRoot");
+                var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
+                await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
+                work.recordUrl = $"/homework/{work.id}/record.json";
+                var cods = new { records = new List<string>(), userids = new List<string>(), question = new List<QuestionRecord>() };
+                await _azureStorage.UploadFileByContainer(blobcntr, cods.ToJsonString(), "homework", $"{work.id}/record.json");
+                work.id = Guid.NewGuid().ToString();
                 if (string.IsNullOrEmpty(work.id))
-                {
-                    work.id = Guid.NewGuid().ToString();
+                {                   
+                    if (work.startTime > now)
+                    {
+                        work.progress = "pending";
+                    }
+                    else
+                    {
+                        work.progress = "going";
+                    }
                     await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(work, new PartitionKey($"{work.code}"));
                 }
                 else
-                {
+                {                   
                     await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(work, new PartitionKey($"{work.code}"));
                 }
                 return work.id;

+ 4 - 4
TEAMModelOS.SDK/Models/Service/ItemService.cs

@@ -56,7 +56,7 @@ namespace TEAMModelOS.Services.Common
                 //检查两个对象是否是同一条记录
                 if (newItem != null && odlItem == null)
                 {
-                    string newKey = $"{newItem.creator}";
+                    string newKey = $"{newItem.code}".Replace("Item-", "");
                     List<string> grade = new List<string> { newKey };
                     UpdateItemCond(cond, true, newKey, grade, newItem.type, newItem.level, newItem.field.HasValue ? newItem.field.Value : 0, newItem);
                 }
@@ -66,18 +66,18 @@ namespace TEAMModelOS.Services.Common
                     if (newItem.id == odlItem.id && newItem.code == odlItem.code)
                     {
                         //先增加
-                        string newKey = $"{newItem.creator}";
+                        string newKey = $"{newItem.code}".Replace("Item-","");
                         List<string> newGrade = new List<string> { newKey };
                         UpdateItemCond(cond, true, newKey, newGrade, newItem.type, newItem.level, newItem.field.HasValue ? newItem.field.Value : 0, newItem);
                         //后变更删除
-                        string oldKey = $"{odlItem.creator}";
+                        string oldKey = $"{odlItem.code}".Replace("Item-", "");
                         List<string> oldGrade = new List<string> { oldKey };
                         UpdateItemCond(cond, false, oldKey, oldGrade, odlItem.type, odlItem.level, odlItem.field.HasValue ? odlItem.field.Value : 0, newItem);
                     }
                 }
                 else if (newItem == null && odlItem != null)
                 {
-                    string oldKey = $"{odlItem.creator}";
+                    string oldKey = $"{odlItem.code}".Replace("Item-", "");
                     List<string> oldGrade = new List<string> { oldKey };
                     UpdateItemCond(cond, false, oldKey, oldGrade, odlItem.type, odlItem.level, odlItem.field.HasValue ? odlItem.field.Value : 0, null);
                 }

+ 25 - 19
TEAMModelOS.SDK/Models/Service/NotificationService.cs

@@ -17,25 +17,31 @@ namespace TEAMModelOS.SDK.Models.Service
             _httpClient = httpClient;
         }
         public    async Task<int> SendNotification(string clientID, string clientSecret, string location, string url, Notification notification) {
-            if (location.Contains("China")) {
-                location = "China";
-            }
-            else if (location.Contains("Global"))
-            {
-                location = "Global";
-            }
-            var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location);
-            _httpClient.DefaultRequestHeaders.Add("Authorization",$"Bearer {token.AccessToken}" );
-            HttpResponseMessage responseMessage = await _httpClient.PostAsJsonAsync(url, notification);
-            if (responseMessage.StatusCode == HttpStatusCode.OK)
-            {
-                return 200;
-            }
-            else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
-            {
-                return 401;
-            }
-            else {
+            try {
+                if (location.Contains("China"))
+                {
+                    location = "China";
+                }
+                else if (location.Contains("Global"))
+                {
+                    location = "Global";
+                }
+                var token = await CoreTokenExtensions.CreateAccessToken(clientID, clientSecret, location);
+                _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.AccessToken}");
+                HttpResponseMessage responseMessage = await _httpClient.PostAsJsonAsync(url, notification);
+                if (responseMessage.StatusCode == HttpStatusCode.OK)
+                {
+                    return 200;
+                }
+                else if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
+                {
+                    return 401;
+                }
+                else
+                {
+                    return 500;
+                }
+            } catch (Exception ) {
                 return 500;
             }
         }

+ 1 - 1
TEAMModelOS.SDK/Models/Service/StuListService.cs

@@ -63,7 +63,7 @@ namespace TEAMModelFunction
                 foreach (MQActivity activity in datas)
                 {
                     //已经完结的不再允许加入
-                    if (activity.progress.Equals("finish") || activity.progress.Equals("pending"))
+                    if (string.IsNullOrEmpty(activity.progress)|| activity.progress.Equals("finish") || activity.progress.Equals("pending"))
                     {
                         continue;
                     }

+ 8 - 0
TEAMModelOS.SDK/Models/Service/SurveyService.cs

@@ -21,6 +21,14 @@ namespace TEAMModelOS.SDK.Models.Service
                 if (string.IsNullOrEmpty(survey.id))
                 {
                     survey.id = Guid.NewGuid().ToString();
+                    if (survey.startTime > now)
+                    {
+                        survey.progress = "pending";
+                    }
+                    else
+                    {
+                        survey.progress = "going";
+                    }
                     await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(survey, new PartitionKey($"{survey.code}"));
                 }
                 else

+ 2 - 0
TEAMModelOS.SDK/Models/Service/TriggerStuActivity.cs

@@ -46,6 +46,7 @@ namespace TEAMModelOS.SDK
                             scode = activity.code,
                             name = activity.name,
                             code = $"Activity-{tmdid.id}",
+                            source = activity.source,
                             scope = activity.scope,
                             school = activity.school,
                             creatorId = activity.creatorId,
@@ -74,6 +75,7 @@ namespace TEAMModelOS.SDK
                             name = activity.name,
                             code = $"Activity-{activity.school}-{student.id}",
                             scope = activity.scope,
+                            source = activity.source,
                             school = activity.school,
                             creatorId = activity.creatorId,
                             pk = "Activity",

+ 0 - 36
TEAMModelOS.SDK/Models/Table/KnowledgeBlock.cs

@@ -1,36 +0,0 @@
-using Microsoft.Azure.Cosmos.Table;
-using System.ComponentModel.DataAnnotations;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-
-namespace TEAMModelOS.SDK.Models
-{
-    [TableName(Name = "SyllabusKnowledgeBlock")]
-    //
-    public class KnowledgeBlock : TableEntity
-    {
-        /// <summary>
-        /// 名称
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string Name { get; set; }
-        
-        /// <summary>
-        /// 上级ID
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string Pid { get; set; } = "root";
-        /// <summary>
-        /// 学科
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string SubjectCode { get; set; }
-        /// <summary>
-        /// 建议学段
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string AdvicePeriodCode { get; set; }
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public int Order { get; set; }
-
-    }
-}

+ 0 - 42
TEAMModelOS.SDK/Models/Table/KnowledgeBlockPoint.cs

@@ -1,42 +0,0 @@
-using Microsoft.Azure.Cosmos.Table;
-using System.ComponentModel.DataAnnotations;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-
-namespace TEAMModelOS.SDK.Models
-{
-    [TableName(Name = "SyllabusKnowledgeBlockPoint")]
-    //
-    public class KnowledgeBlockPoint : TableEntity
-    {
-        //public string Id { get; set; }
-        public string PointId { get; set; }
-        /// <summary>
-        /// 原始名称
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string Name { get; set; }
-        /// <summary>
-        /// 别名
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string Alias { get; set; }
-        /// <summary>
-        /// 知识块ID
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string BlockId { get; set; }
-        /// <summary>
-        /// 建议学段
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string AdvicePeriodCode { get; set; }
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public int Order { get; set; }
-        /// <summary>
-        /// 学科
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string SubjectCode { get; set; }
-
-    }
-}

+ 0 - 44
TEAMModelOS.SDK/Models/Table/KnowledgePoint.cs

@@ -1,44 +0,0 @@
-using Microsoft.Azure.Cosmos.Table;
-using System.ComponentModel.DataAnnotations;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-
-namespace TEAMModelOS.SDK.Models
-{
-    /// <summary>
-    /// 知识点
-    /// </summary>
-    [TableName(Name = "SyllabusKnowledgePoint")]
-    //
-    public class KnowledgePoint : TableEntity
-    {
-        //public string Id { get; set; }
-        public string PointId { get; set; }
-        /// <summary>
-        /// 原始名称
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string Name { get; set; }
-        /// <summary>
-        /// 别名
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string Alias { get; set; }
-        /// <summary>
-        /// 知识块ID
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string BlockId { get; set; }
-        /// <summary>
-        /// 建议学段
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string AdvicePeriodCode { get; set; }
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public int Order { get; set; }
-        /// <summary>
-        /// 学科
-        /// </summary>
-        [Required(ErrorMessage = "{0} 必须填写")]
-        public string SubjectCode { get; set; }
-    }
-}

+ 41 - 0
TEAMModelOS.SDK/Models/Cosmos/Api/OpenApi.cs

@@ -49,6 +49,28 @@ namespace TEAMModelOS.SDK.Models
         /// r,w,d,l
         /// </summary>
         public string type { get; set; }
+        /// <summary>
+        /// minute  分钟,表示按分钟限流,多少分钟内只能访问多少次,
+        /// hour    小时,表示按小时限流,多少小时内只能访问多少次,
+        /// day     天数,表示按天数限流,多少天数内只能访问多少次,
+        /// </summary>
+        public string policy { get; set; }
+        /// <summary>
+        /// policy 策略,分钟,小时,天数对应的时长
+        /// </summary>
+        public int duration { get; set; }
+        /// <summary>
+        /// policy 策略,分钟,小时,天数对应的时长(duration) 可以访问的次数
+        /// </summary>
+        public int times { get; set; }
+        /// <summary>
+        /// 是否免费调用
+        /// </summary>
+        ///public bool free { get; set; }
+        /// <summary>
+        /// 每次调用花费多少钱
+        /// </summary>
+        ///public decimal cost { get; set; }
     }
     [TableName(Name = "OpenApi")]
     public class Webhook : TableEntity
@@ -97,6 +119,7 @@ namespace TEAMModelOS.SDK.Models
         /// 授权信息
         /// </summary>
         public List<int> auths { get; set; } = new List<int>();
+        public List<ApiInfo> apiInfos { get; set; } = new List<ApiInfo>();
         public List<int> webhooks { get; set; } = new List<int>();
         /// <summary>
         /// 学校编码
@@ -118,9 +141,27 @@ namespace TEAMModelOS.SDK.Models
         /// 0禁用,1正常,2 token封禁
         /// </summary>
         public int status { get; set; }
+
         public OpenApp()
         {
             pk = "OpenApp";
         }
     }
+    public class ApiInfo {
+        /// <summary>
+        /// minute  分钟,表示按分钟限流,多少分钟内只能访问多少次,
+        /// hour    小时,表示按小时限流,多少小时内只能访问多少次,
+        /// day     天数,表示按天数限流,多少天数内只能访问多少次,
+        /// </summary>
+        public string policy { get; set; }
+        /// <summary>
+        /// policy 策略,分钟,小时,天数对应的时长
+        /// </summary>
+        public int duration { get; set; }
+        /// <summary>
+        /// policy 策略,分钟,小时,天数对应的时长(duration) 可以访问的次数
+        /// </summary>
+        public int times { get; set; }
+        public int auth { get; set; }
+    }
 }

+ 0 - 19
TEAMModelOS.SDK/Models/Table/ResourceReference.cs

@@ -1,19 +0,0 @@
-using Microsoft.Azure.Cosmos.Table;
-using System;
-using System.Collections.Generic;
-using System.Text;
-using TEAMModelOS.SDK.Context.Attributes.Azure;
-
-namespace TEAMModelOS.SDK.Models
-{
-    [TableName(Name = "CoreResourceReference")]
-    public class ResourceReference : TableEntity
-    {
-        public string ResourceId { get; set; }
-        public string ResourceType { get; set; }
-        public string ReferenceId { get; set; }
-        public string ReferenceType { get; set; }
-        public long CreateTime { get; set; }
-
-    }
-}

+ 0 - 14
TEAMModelOS.SDK/Models/Table/tmdInfo.cs

@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace TEAMModelOS.SDK.Models.Table
-{
-
-    public class tmdInfo
-    {
-        public string tmdId { get; set; }
-        public List<double> tScore { get; set; } = new List<double>();
-        public string mark { get; set; }
-    }
-}

+ 6 - 2
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -11,7 +11,7 @@
 
 
   <ItemGroup>
-    <PackageReference Include="HTEXLib" Version="5.2109.6" />
+    <PackageReference Include="HTEXLib" Version="5.2111.41" />
     <PackageReference Include="AspectCore.Extensions.Reflection" Version="2.2.0" />
     <PackageReference Include="Azure.Cosmos" Version="4.0.0-preview3" />
     <PackageReference Include="Azure.Identity" Version="1.4.0" />
@@ -20,17 +20,21 @@
     <PackageReference Include="Azure.Storage.Blobs.Batch" Version="12.6.0" />
     <PackageReference Include="Azure.Storage.Queues" Version="12.6.1" />
     <PackageReference Include="ClouDASLibx" Version="1.2.7" />
-    <PackageReference Include="DocumentFormat.OpenXml" Version="2.12.3" />
+    <PackageReference Include="DocumentFormat.OpenXml" Version="2.13.1" />
     <PackageReference Include="HtmlAgilityPack" Version="1.11.32" />
     <PackageReference Include="Lib.AspNetCore.ServerSentEvents" Version="6.0.0" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.10" />
     <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
     <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="5.0.4" />
     <PackageReference Include="Microsoft.Identity.Client" Version="4.32.1" />
+    <PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
+    <PackageReference Include="NUnit" Version="3.13.2" />
+    <PackageReference Include="PinYinConverterCore" Version="1.0.2" />
     <PackageReference Include="StackExchange.Redis" Version="2.2.4" />
     <PackageReference Include="SvgNet" Version="2.1.1" />
     <PackageReference Include="System.Drawing.Common" Version="5.0.2" />
     <PackageReference Include="Microsoft.Azure.Cosmos.Table" Version="2.0.0-preview" />
     <PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
+    <PackageReference Include="NPinyin.Core" Version="3.0.0" />
   </ItemGroup>
 </Project>

+ 2 - 1
TEAMModelOS/ClientApp/package.json

@@ -21,7 +21,7 @@
 		"@vue/eslint-config-standard": "^4.0.0",
 		"animate.css": "^3.7.2",
 		"apexcharts": "^3.26.1",
-		"axios": "^0.21.1",
+		"axios": "^0.21.4",
 		"bcryptjs": "^2.4.3",
 		"core-js": "^3.1.2",
 		"d3": "^5.9.2",
@@ -38,6 +38,7 @@
 		"i18next": "^20.3.1",
 		"imports-loader": "^0.8.0",
 		"increase-memory-limit": "^1.0.7",
+		"js-md5": "^0.7.3",
 		"js-sha1": "^0.6.0",
 		"json-markup": "^1.1.3",
 		"jsonpath": "^1.1.1",

+ 5 - 1
TEAMModelOS/ClientApp/src/api/ability.js

@@ -164,5 +164,9 @@ export default {
 	//获取校级统计数据
 	getSchoolData(data){
 		return post('/research/get-school-statistics',data)
-	}
+	},
+	// 更新能力点的选修必修
+	upsertCurrency(data){
+		return post('/research/ability/upsert-currency',data)
+	},
 }

+ 31 - 13
TEAMModelOS/ClientApp/src/api/evaluation.js

@@ -1,20 +1,38 @@
-import { fetch, post } from '@/api/http'
+import {
+	fetch,
+	post
+} from '@/api/http'
 
 export default {
-    /* 获取条件筛选数量*/
-	getFilterCount: function (data) {        
-        return post('/item/cond-count', data)
-    },
+	/* 获取条件筛选数量*/
+	getFilterCount: function(data) {
+		return post('/item/cond-count', data)
+	},
 	/* 保存答题卡 */
-	upsertSheet: function (data) {        
-        return post('/sheet-config/upsert', data)
-    },
+	upsertSheet: function(data) {
+		return post('/sheet-config/upsert', data)
+	},
 	/* 查询答题卡 */
-	findSheet: function (data) {
-	    return post('/sheet-config/find', data)
+	findSheet: function(data) {
+		return post('/sheet-config/find', data)
 	},
 	/* 删除答题卡 */
-	deleteSheet: function (data) {
-	    return post('/sheet-config/delete', data)
-	}
+	deleteSheet: function(data) {
+		return post('/sheet-config/delete', data)
+	},
+	/* 批量保存试题 */
+	upsertAll: function(data) {
+		return post('/item/upsert-all', data)
+	},
+	checkTools: function(data) {
+		return post({
+			url: 'http://localhost:59995',
+			method: 'post',
+			timeout: 1000,
+			data
+		})
+	},
+	getBase64ByTools: function(data) {
+		return post('http://localhost:59995/getimage', data)
+	},
 }

+ 14 - 3
TEAMModelOS/ClientApp/src/api/http.js

@@ -8,15 +8,24 @@ const NO_ACCESS_API = [
     '/oauth2/login',
     '/oauth2/token',
     '/service/sandsms/pin',
+    '/service/sandmail/pin',
     '/teacher/init/get-school-list',
     '/student/login',
     '/area/lang',
-    '/common/study/sign-in'
+    '/common/study/sign-in',
+	'/tmduser/init/get-tmduser-info',
+    'third/sso/opt-tmdid-bind',
+    '/sc/bind'
 ]
 const NO_AUTH_API = [
     '/teacher/init/get-teacher-info',
     '/teacher/init/get-school-info',
-    '/stulist/scan-code-join-list'
+    '/stulist/scan-code-join-list',
+	'/tmduser/init/get-tmduser-info'
+]
+
+const NO_WARNING = [
+	'http://localhost:59995/'
 ]
 
 let refreshing = false
@@ -116,7 +125,9 @@ axios.interceptors.response.use(
     },
     error => {
 		if(!error.response){
-			Message.error(app.$t('http.error'))
+			if(!NO_WARNING.includes(error.config.url)){
+				Message.error(app.$t('http.error'))
+			}
 		}else if (error.response && error.response.status === 401) {
             localStorage.clear()
             window.location.href = window.location.origin + '/login'

+ 5 - 0
TEAMModelOS/ClientApp/src/api/knowledge.js

@@ -15,4 +15,9 @@ export default {
     DeleteSchoolPoint: function(data) {
         return post('/knowledge/delete', data)
     },
+	// 删除知识点知识块
+    SavePoints: function(data) {
+        return post('/knowledges/item-import', data)
+    },
+	
 }

+ 4 - 0
TEAMModelOS/ClientApp/src/api/login.js

@@ -50,6 +50,9 @@ export default {
 	studLoginbyIES: function(data) {
 		return post('/student/login', data)
 	},
+	studLoginbyTmdId: function(data) {
+		return post('/tmduser/init/get-tmduser-info', data)
+	},
 	// 固定登入流程
 	loginIES: function(item, schoolcode) {
 		return new Promise(async (resolve, reject) => {
@@ -96,6 +99,7 @@ export default {
 			info.toArea = areas.length && !joinSchools.length
 
 			if (defaultschool) {
+				console.error(defaultschool)
 				// 取得使用者的在該學校的設定檔
 				await this.getTeacherSchoolInfo({
 					id_token: id_token,

+ 12 - 0
TEAMModelOS/ClientApp/src/api/mark.js

@@ -53,5 +53,17 @@ export default {
      * */
      feedbackErr: function (data) {
         return post('/common/exam/fd-err', data)
+    },
+    /**
+     * 查询仲裁卷
+     * */
+     findArb: function (data) {
+        return post('/common/exam/find-arb', data)
+    },
+    /**
+     * 仲裁打分API
+     * */
+     saveArb: function (data) {
+        return post('/common/exam/save-arb', data)
     }
 }

+ 0 - 0
TEAMModelOS/ClientApp/src/api/schoolSetting.js


Some files were not shown because too many files changed in this diff