Selaa lähdekoodia

Merge branch 'develop' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop

upon 1 vuosi sitten
vanhempi
commit
b3906863c3
61 muutettua tiedostoa jossa 4558 lisäystä ja 1148 poistoa
  1. 2 0
      .gitignore
  2. 8 0
      TEAMModelBI/ClientApp/src/api/index.js
  3. 2 0
      TEAMModelBI/ClientApp/src/main.js
  4. 1 0
      TEAMModelBI/ClientApp/src/static/country.json
  5. 5 1
      TEAMModelBI/ClientApp/src/store/index.js
  6. 80 0
      TEAMModelBI/ClientApp/src/store/module/config.js
  7. 19 3
      TEAMModelBI/ClientApp/src/view/common/aside.vue
  8. 27 5
      TEAMModelBI/ClientApp/src/view/issueCoupons/crteadCoupon.vue
  9. 5 7
      TEAMModelBI/ClientApp/src/view/issueCoupons/index.vue
  10. 57 36
      TEAMModelBI/ClientApp/src/view/userInquire/index.vue
  11. 304 0
      TEAMModelBI/ClientApp/src/view/userInquire/updCodeW.vue
  12. 124 0
      TEAMModelBI/Controllers/BISchool/BatchSchoolController.cs
  13. 3 1
      TEAMModelBI/Controllers/BITmid/TmidController.cs
  14. 3 3
      TEAMModelBI/TEAMModelBI.csproj
  15. 3 3
      TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj
  16. 1791 0
      TEAMModelOS.SDK/Helper/Common/JsonHelper/JsonParser.cs
  17. 59 8
      TEAMModelOS.SDK/Models/Cosmos/Common/Activity.cs
  18. 7 1
      TEAMModelOS.SDK/Models/Cosmos/Common/GroupList.cs
  19. 41 0
      TEAMModelOS.SDK/Models/Cosmos/Common/IotTeachingData.cs
  20. 1 0
      TEAMModelOS.SDK/Models/Cosmos/School/Elegant.cs
  21. 35 2
      TEAMModelOS.SDK/Models/Service/BI/BIProdAnalysis.cs
  22. 35 10
      TEAMModelOS.SDK/Models/Service/Common/ActivityService.cs
  23. 3 3
      TEAMModelOS.SDK/TEAMModelOS.SDK.csproj
  24. 2 0
      TEAMModelOS.sln
  25. 1 1
      TEAMModelOS/ClientApp/package.json
  26. 4 4
      TEAMModelOS/ClientApp/public/lang/zh-TW.js
  27. 25 44
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  28. 4 2
      TEAMModelOS/ClientApp/src/components/public/frontEndMain/Index.vue
  29. 3 0
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScatter.vue
  30. 3 0
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseTestScatter.vue
  31. 2 1
      TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue
  32. 1 1
      TEAMModelOS/ClientApp/src/view/Home.vue
  33. 4 4
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaIndex.vue
  34. 840 779
      TEAMModelOS/ClientApp/src/view/areaMgmt/AreaLayout.vue
  35. 16 18
      TEAMModelOS/ClientApp/src/view/art/AreaArt.vue
  36. 10 2
      TEAMModelOS/ClientApp/src/view/artexam/AcQuos.vue
  37. 3 1
      TEAMModelOS/ClientApp/src/view/elegant/BaseElegantCloud.vue
  38. 76 71
      TEAMModelOS/ClientApp/src/view/elegant/BaseElegantDash.vue
  39. 24 11
      TEAMModelOS/ClientApp/src/view/elegant/Elegant.vue
  40. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseCreateChild.vue
  41. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/components/BasePoints.vue
  42. 1 1
      TEAMModelOS/ClientApp/src/view/evaluation/components/BaseRepair.vue
  43. 1 1
      TEAMModelOS/ClientApp/src/view/iot/areaiot.vue
  44. 2 2
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.vue
  45. 19 2
      TEAMModelOS/ClientApp/src/view/login/page/Student.less
  46. 10 7
      TEAMModelOS/ClientApp/src/view/login/page/Student.vue
  47. 1 1
      TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue
  48. 95 24
      TEAMModelOS/ClientApp/src/view/signupActivity/infoComponent/skContent.vue
  49. 4 5
      TEAMModelOS/ClientApp/src/view/student-web/AppNew.vue
  50. 42 1
      TEAMModelOS/Controllers/Client/HiTAControlller.cs
  51. 479 51
      TEAMModelOS/Controllers/Common/ActivityController.cs
  52. 3 2
      TEAMModelOS/Controllers/Common/ExamController.cs
  53. 31 4
      TEAMModelOS/Controllers/School/ElegantController.cs
  54. 29 6
      TEAMModelOS/Controllers/School/SchoolController.cs
  55. 1 1
      TEAMModelOS/Controllers/Student/StudentController.cs
  56. 172 8
      TEAMModelOS/Controllers/XTest/FixDataController.cs
  57. 3 0
      TEAMModelOS/Controllers/XTest/FixLessonRecordController.cs
  58. 23 2
      TEAMModelOS/Controllers/XTest/TestController.cs
  59. 5 4
      TEAMModelOS/TEAMModelOS.csproj
  60. 1 1
      TEAMModelOS/appsettings.Development.json
  61. 1 1
      TEAMModelOS/appsettings.json

+ 2 - 0
.gitignore

@@ -267,3 +267,5 @@ TEAMModelOS.FunctionV4/Properties/ServiceDependencies/TEAMModel-Test - Zip Deplo
 TEAMModelOS.FunctionV4/Properties/ServiceDependencies/teammodelfunction-rc - Zip Deploy/
 /TEAMModelOS.FunctionV4/Properties/serviceDependencies.teammodelfunction-rc - Zip Deploy.json
 /TEAMModelOS/.local-chromium
+
+TEAMModelBI/Properties/ServiceDependencies/teammodelbi-RC - Web Deploy/profile.arm.json

+ 8 - 0
TEAMModelBI/ClientApp/src/api/index.js

@@ -219,6 +219,14 @@ export default {
     getallSchool(data) {
         return post('/batchschool/get-allscinfo', data)
     },
+    //透過位置取得學校資料
+    getSchooBasicInfo(data) {
+        return post('/batchschool/get-school-basic-info', data)
+    },
+    //弱歸戶
+    updUserSchoolW(data) {
+        return post('/batchschool/upd-user-schoolw', data)
+    },    
 
     //首页dashboard数据接口
     //获取各城市的学校数量(bar)

+ 2 - 0
TEAMModelBI/ClientApp/src/main.js

@@ -18,6 +18,8 @@ import PersonalPhoto from './components/public/personalPhoto/index.vue'
 import zhCn from "element-plus/lib/locale/lang/zh-cn";
 import 'dayjs/locale/zh-cn';
 
+store.dispatch('config/checkSrvAdr');// 檢查現在站的位置
+
 const app = createApp(App)
 app.config.globalProperties.$api = axios
 app.config.globalProperties.$access = inspect

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 0
TEAMModelBI/ClientApp/src/static/country.json


+ 5 - 1
TEAMModelBI/ClientApp/src/store/index.js

@@ -1,4 +1,6 @@
 import { createStore } from 'vuex'
+import config from './module/config'
+
 export default createStore({
     state: {
         organizationData: [], //组织架构数据
@@ -113,5 +115,7 @@ export default createStore({
     },
     actions: {},
     getters: {},
-    modules: {}
+    modules: {
+        config
+    }
 })

+ 80 - 0
TEAMModelBI/ClientApp/src/store/module/config.js

@@ -0,0 +1,80 @@
+export default {
+    namespaced: true,
+    state: {
+        srvAdr: '', // 伺服器位置 China, Global
+        srvAdrType: '', // 正式站 product 測試站 test
+        China: {
+            srvAdr: 'China',
+            domainUrl: [
+                {
+                    station: 'product',
+                    url: 'https://bi.teammodel.cn'
+                },
+                {
+                    station: 'rc',
+                    url: 'https://bi-rc.teammodel.cn'
+                },
+            ]
+        },
+        Global: {
+            srvAdr: 'Global',
+            domainUrl: [
+                {
+                    station: 'product',
+                    url: 'https://bi.teammodel.net'
+                },
+                {
+                    station: 'rc',
+                    url: 'https://bi-rc.teammodel.net'
+                },
+            ]
+        }
+    },
+    getters: {
+        getSrvAdr: state => state.srvAdr,
+    },
+    mutations: {
+        setSrvAdr(state, data) {
+            state.srvAdr = data
+        },
+        setSrvAdrType(state, data) {
+            state.srvAdrType = data
+        }
+    },
+    actions: {
+        checkSrvAdr(context) {
+            let domainUrl = window.location.hostname
+
+            let domainUrlArray = []
+
+            context.state.China.domainUrl.forEach(function (item) {
+                item.srvAdr = 'China'
+                domainUrlArray.push(item)
+            })
+            context.state.Global.domainUrl.forEach(function (item) {
+                item.srvAdr = 'Global'
+                domainUrlArray.push(item)
+            })
+
+            let stationSetting = domainUrlArray.find(function (item) {
+                return item.url.indexOf(domainUrl) >= 0
+            })
+
+            if (!stationSetting) {
+                stationSetting = {}
+                stationSetting.station = 'test'
+                stationSetting.srvAdr = 'Global'
+            }
+            context.commit('setSrvAdr', stationSetting.srvAdr)
+            context.commit('setSrvAdrType', stationSetting.station)
+
+            localStorage.setItem('srvAdr', stationSetting.srvAdr)
+            localStorage.setItem('station', stationSetting.station)
+
+        },
+        setSrvAdr(context, param) {
+            localStorage.setItem('srvAdr', param)
+            context.commit('setSrvAdr', param)
+        }
+    }
+}

+ 19 - 3
TEAMModelBI/ClientApp/src/view/common/aside.vue

@@ -42,7 +42,7 @@
 //基础菜单
 
 import { Location, Document, Menu as IconMenu, Setting } from '@element-plus/icons'
-import { getCurrentInstance, ref, watch, onMounted, reactive, toRefs } from 'vue'
+import { getCurrentInstance, ref, watch, onMounted, reactive, toRefs, computed } from 'vue'
 import { useStore } from 'vuex'
 import { useRouter } from 'vue-router'
 import router from '@/router/index.js'
@@ -55,6 +55,9 @@ export default {
     IconMenu,
   },
   setup () {
+    const store = useStore()
+    const srvType = computed(() => store.getters["config/getSrvAdr"]);
+    
     console.log('调用了一次这个页面')
     let { proxy } = getCurrentInstance()
     let menuWidth = ref('64px')
@@ -134,7 +137,7 @@ export default {
             sort: 7,
           },
           {
-            name: '用户查询',
+            name: '用户相關',
             router: '/home/userinquire',
             icon: '#icon-a-97-yonghuchaxun',
             permission: [],
@@ -156,6 +159,7 @@ export default {
             permission: [],
             isShow: true,
             sort: 6,
+            srvType: 'Global'
           },
         ],
       },
@@ -318,8 +322,8 @@ export default {
       },
     ]
     const isCollapse = ref(true)
-    const store = useStore()
     const shenfen = ref('admin')
+
     //路由
     const routers = useRouter()
     let indexMenu = reactive({ currentRoutePath: routers.currentRoute.value.path })
@@ -400,6 +404,18 @@ export default {
           }
         }
       }
+
+      // 新增功能限制
+      for (let i in menuList.value) {
+        let menuChild = menuList.value[i]
+        for (let y in menuChild.child) {
+          let menuSrvType = menuChild.child[y].srvType
+          if(menuSrvType && menuSrvType != srvType.value){
+            menuChild.child.splice(y, 1)
+          }
+        }
+      }
+
       console.log(menuList.value, result, '菜单')
       //router内容
       let nowUrl = routers.currentRoute.value.path

+ 27 - 5
TEAMModelBI/ClientApp/src/view/issueCoupons/crteadCoupon.vue

@@ -1,5 +1,6 @@
 <template>
     <div style="position: relative;">
+        <!-- 隱藏按鈕 -->
         <div style="width: 100px; height:100px;position: absolute;right: 0;z-index: 10;" @click="showClick()"></div>
         <el-form ref="ruleFormRef" :model="crtCouponForm" :rules="rules" label-width="120px">
             <el-form-item label="發券位置" prop="srvAdr">
@@ -45,11 +46,11 @@
             </el-form-item>
             <el-form-item v-if="detailSettingFlag" label="規則" prop="rule">
                 <div style="max-height: 330px;overflow: scroll;">
-                    <div v-for="(rule, rIndex) in crtCouponForm.rule" style="display: flex;flex-direction: row;align-items: center;margin-bottom: 5px;">
+                    <div v-for="(rule, rIndex) in crtCouponForm.rule" class="ruleBox">
                         <el-button :icon="Plus" circle @click="addRule(rIndex)" style="margin-right: 5px;"/>
-                        <div style="text-align: left;border: 1px solid #dcdfe6;padding: 6px 11px;border-radius: 5px;margin-right: 5px;">
+                        <div class="rule">
                             條件:
-                            <div style="min-height: 36px;max-width: 550px;border: 1px solid #e4e7ed;padding: 1px 11px;border-radius: 5px;background-color: #f5f7fa;">{{ translateRule(rule.q) }}</div>
+                            <div class="ruleStr">{{ translateRule(rule.q) }}</div>
                             <div v-for="(item, index) in rule.q" style="text-align:left;">
                                 <el-button-group style="margin-right: 5px;">
                                     <el-button :icon="Plus" @click="addCondition(rIndex, index)" />
@@ -170,7 +171,6 @@ const maxTakerFlag = ref(false)
 const consolidationFlag = ref(false)
 const loading = ref(false)
 const couponResult = ref('')
-const defaultTime = new Date().setTime(new Date().getTime() + (60*60*1000))
 const shortcuts = [
     {
         text: '一個月後',
@@ -715,7 +715,6 @@ const submitForm = formEl => {
             }
             
             await proxy.$api.crtCoupon(data).then((res) => {
-                console.log(res)
                 couponResult.value = '' // 先清空
                 if(res.coupons){
                     res.coupons.forEach(e=>{
@@ -832,6 +831,29 @@ const copyDocument = (data) => {
 </script>
 
 <style scoped>
+.ruleBox{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 5px;
+}
+
+.ruleBox .rule{
+    text-align: left;
+    border: 1px solid #dcdfe6;
+    padding: 6px 11px;
+    border-radius: 5px;
+    margin-right: 5px;
+}
+
+.ruleBox .rule .ruleStr{
+    min-height: 36px;
+    max-width: 550px;
+    border: 1px solid #e4e7ed;
+    padding: 1px 11px;
+    border-radius: 5px;
+    background-color: #f5f7fa;
+}
 .coupons {
     box-shadow: 0px 3px 2px 2px #E0E0E0;
     border-radius: 10px;

+ 5 - 7
TEAMModelBI/ClientApp/src/view/issueCoupons/index.vue

@@ -1,11 +1,9 @@
 <template>
-    <div >
-      <el-tabs type="border-card">
-        <el-tab-pane label="建立優惠券"><CrteadCoupon /></el-tab-pane>
-      <el-tab-pane label="優惠券歸戶"><ConsolidationCoupon /></el-tab-pane>
-      <el-tab-pane label="通知"><Notice /></el-tab-pane>
-    </el-tabs>
-  </div>
+  <el-tabs type="border-card">
+      <el-tab-pane label="建立優惠券"><CrteadCoupon /></el-tab-pane>
+    <el-tab-pane label="優惠券歸戶"><ConsolidationCoupon /></el-tab-pane>
+    <el-tab-pane label="通知"><Notice /></el-tab-pane>
+  </el-tabs>
 </template>
 <script>
 import CrteadCoupon from './crteadCoupon.vue'

+ 57 - 36
TEAMModelBI/ClientApp/src/view/userInquire/index.vue

@@ -1,51 +1,59 @@
 <template>
-    <div class="inquirebox" v-if="pageShow ==='default'">
+    <div class="inquirebox" >
         <div class="inquire-title">
             <p>TEAM Model 智慧教育</p>
         </div>
-        <div class="searchbox" v-loading="searchLoading" element-loading-text="数据搜索中...">
-            <div class="searchbox-title">
-                <p>用户查询</p>
-            </div>
-            <el-divider border-style="dashed" />
-            <div class="searchbox-item">
-                <el-input v-model="searchvalue" placeholder="输入手机号码/醍摩豆账号 进行搜索" class="input-with-select">
-                <template #prepend>
-                    <el-select v-model="selecttypes" placeholder="Select" style="width: 120px">
-                    <el-option label="精准查询" value="precise" />
-                    <!-- <el-option label="批量查询/操作" value="batch" /> -->
-                    </el-select>
-                </template>
-                <template #append>
-                    <el-button :icon="Search" @click="seachSole()"/>
-                </template>
-                </el-input>
-            </div>
-            <div class="recordbox" v-if="selecttypes==='precise'">
-                <p>搜索记录:</p>
-                <div class="recordbox-item">
-                    <el-tag v-for="tag in searchRecordsArr"  class="mx-1" closable type="''"  effect="light" @close="deleteLog(tag)" @click="searchvalue=tag">
-                        {{ tag }}
-                    </el-tag>
+        <el-tabs v-if="pageShow ==='default'" style="width: 100%;height:100%;" type="card" class="demo-tabs">
+            <el-tab-pane label="用户查询" style="padding: 1%;display: flex;justify-content: center;">
+                <div class="searchbox" v-loading="searchLoading" element-loading-text="数据搜索中...">
+                    <div class="searchbox-title">
+                        <p>用户查询</p>
+                    </div>
+                    <el-divider border-style="dashed" />
+                    <div class="searchbox-item">
+                        <el-input v-model="searchvalue" placeholder="输入手机号码/醍摩豆账号 进行搜索" class="input-with-select">
+                        <template #prepend>
+                            <el-select v-model="selecttypes" placeholder="Select" style="width: 120px">
+                            <el-option label="精准查询" value="precise" />
+                            <!-- <el-option label="批量查询/操作" value="batch" /> -->
+                            </el-select>
+                        </template>
+                        <template #append>
+                            <el-button :icon="Search" @click="seachSole()"/>
+                        </template>
+                        </el-input>
+                    </div>
+                    <div class="recordbox" v-if="selecttypes==='precise'">
+                        <p>搜索记录:</p>
+                        <div class="recordbox-item">
+                            <el-tag v-for="tag in searchRecordsArr"  class="mx-1" closable type="''"  effect="light" @close="deleteLog(tag)" @click="searchvalue=tag">
+                                {{ tag }}
+                            </el-tag>
+                        </div>
+                        <div class="dele-all" v-show="searchRecordsArr.length >0">
+                            <el-icon size="14" @click="deleAllsearch"><Delete /></el-icon>
+                        </div>
+                    </div>
+                    <div class="recordbox" v-else="selecttypes ==='batch'">
+                        <p>搜索结果:</p>
+                    </div>
                 </div>
-                <div class="dele-all" v-show="searchRecordsArr.length >0">
-                    <el-icon size="14" @click="deleAllsearch"><Delete /></el-icon>
-                </div>
-            </div>
-            <div class="recordbox" v-else="selecttypes ==='batch'">
-                <p>搜索结果:</p>
-            </div>
+            </el-tab-pane>
+            <el-tab-pane label="弱歸戶" style="padding: 1%">
+                <UpdCodeW />
+            </el-tab-pane>
+        </el-tabs>
+        <div class="inquirebox-details" v-else-if="pageShow ==='details'">
+            <Detailsbox :searchdata="searchResult" @parentClick="backClicks"></Detailsbox>
         </div>
     </div>
-    <div class="inquirebox-details" v-else-if="pageShow ==='details'">
-        <Detailsbox :searchdata="searchResult" @parentClick="backClicks"></Detailsbox>
-    </div>
 </template>
 <script setup>
 import { ref, getCurrentInstance, watch, h, nextTick,provide } from 'vue'
 import { ElMessage, ElLoading } from 'element-plus'
 import { Search,Delete } from '@element-plus/icons'
 import Detailsbox from './details.vue'
+import UpdCodeW from './updCodeW.vue'
 import {useRoute} from "vue-router"
 import { useStore } from 'vuex'
 let { proxy } = getCurrentInstance()
@@ -170,9 +178,10 @@ function deleAllsearch(){
     align-items: center;
     justify-content: center;
     position: relative;
+    /* height: 86vh; */
 }
 .searchbox{
-    width:60%;
+    width: 40vw;
     height:50vh;
     background-color: #fff;
     z-index:999;
@@ -238,4 +247,16 @@ function deleAllsearch(){
     top:1%;
     right:5%;
 }
+</style>
+<style>
+.demo-tabs .el-tabs__item.is-active{
+    color: #333333;
+    font-weight: bold;
+    font-size: 17px;
+}
+.demo-tabs .el-tabs__item.is-active{
+    border-bottom-color: #fff !important;
+    border-bottom-width: 3px;
+    background-color: #ffffffad;
+}
 </style>

+ 304 - 0
TEAMModelBI/ClientApp/src/view/userInquire/updCodeW.vue

@@ -0,0 +1,304 @@
+<template>
+    <div class="updCodeWBox" v-loading="loading" :element-loading-text="loadingStr">
+        <!-- <div class="updCodeWBox-title">
+            <p>弱歸戶</p>
+        </div>
+        <el-divider border-style="dashed" /> -->
+        <div style="line-height: 1px;height: 100%;overflow: auto;">
+            <div style="margin-bottom: 10px;">
+                <h3>區域</h3>
+                <el-radio-group class="radioSty" v-model="countryId" @change="cIdChange">
+                    <el-radio label="CN" size="large"  border>大陆地区</el-radio>
+                    <el-radio label="TW" size="large" border>臺灣地區</el-radio>
+                </el-radio-group>
+            </div>
+            
+            <div style="margin-bottom: 10px;" v-if="provinceIdData != null">
+                <h3>省/直轄市</h3>
+                <el-radio-group class="radioSty" v-model="provinceId" @change="pIdChange">
+                    <el-radio size="large" :label="p.provinceId"  border v-for="p in provinceIdData">{{ p.provinceName }}</el-radio>
+                </el-radio-group>
+            </div>
+
+            <div style="margin-bottom: 10px;" v-if="cityIdData != null">
+                <h3>市/界</h3>
+                <el-radio-group class="radioSty" v-model="cityId">
+                    <el-radio size="large" :label="c.cityId"  border v-for="c in cityIdData" @click="searchSchool(c.cityId)">{{ c.cityName }}</el-radio>
+                </el-radio-group>
+            </div>
+
+            <div style="margin-bottom: 10px;margin-top: 70px;">
+                <div style="display: flex;justify-content: center;align-items: center;">
+                    <span style="font-weight: bold;font-size: 23px;margin-right: 5px;">搜尋</span>
+                    <el-input v-model="wordFilter" placeholder="請填入簡碼或學校名稱" style="width: 500px;"/>
+                </div>
+                <el-table :data="showData" stripe style="width: 100%" >
+                    <el-table-column prop="code" label="代碼"  />
+                    <el-table-column prop="shortCode" label="簡碼"  />
+                    <el-table-column prop="name" label="學校名稱"  />
+                    <el-table-column label="">
+                        <template #default="scope">
+                            <el-button type="primary" size="small" @click="handleUpdSchoolW(scope.row.id, scope.row.name, scope.row.shortCode)">歸戶</el-button>
+                        </template>
+                    </el-table-column>
+                </el-table>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup>
+import country from '@/static/country.json'
+import { h, reactive, ref, computed, getCurrentInstance, markRaw } from 'vue'
+import { SuccessFilled, Warning } from '@element-plus/icons'
+import { ElMessageBox, ElMessage, ElInput, ElForm, ElFormItem } from 'element-plus'
+let { proxy } = getCurrentInstance()
+
+const loading = ref(false)
+const countryId = ref(null)
+const provinceId = ref(null)
+const provinceIdData = ref(null)
+const cityId = ref(null)
+const cityIdData = ref(null)
+const tableData = ref([])
+const wordFilter = ref('')
+const loadingStr = ref('')
+
+const cIdChange = (cId) => {
+    cityId.value = null
+    provinceId.value = null
+    provinceIdData.value = null
+    cityIdData.value = null
+    switch(cId){
+        case 'TW':
+            cityIdData.value = country.filter(function(c){
+                return c.countryId == cId && c.lang == 'zh-tw' && c.areaType == 'y'
+            })
+        break;
+        case 'CN':
+            provinceIdData.value = country.filter(function(c){
+                return c.countryId == cId && c.lang == 'zh-cn' && c.areaType == 'p'
+            })
+        break;
+    }
+}
+
+const pIdChange = (provinceId) =>{
+    cityId.value = null
+    cityIdData.value = null
+    let lang = ''
+    switch(countryId.value){
+        case 'TW':
+            lang = 'zh-tw'
+        break;
+        case 'CN':
+            lang = 'zh-cn'
+        break;
+    }
+
+    cityIdData.value = country.filter(function(c){
+        return c.provinceId == provinceId && c.lang == lang && c.areaType == 'y'
+    })
+}
+
+const searchSchool = async (cityId) =>{
+    let data = {
+        countryId: countryId.value,
+        cityId: cityId,
+        fullData: true
+    }
+
+    if(provinceId.value != null) {
+        data.provinceId = provinceId.value
+    }
+    wordFilter.value = ''
+    loadingStr.value = '搜索學校中...'
+    loading.value = true
+
+    await proxy.$api.getSchooBasicInfo(data).then((res) => {
+        tableData.value = res
+    }).catch(e=>{
+        ElMessage.error('搜尋失敗')
+    }).finally(() => {
+        loading.value = false
+    })
+}
+
+const showData = computed({
+    get(){
+        if(wordFilter.value != ''){
+            let result = []
+            console.log(wordFilter.value, 'wordFilter.value')
+            tableData.value.forEach((f)=>{
+                if(f.name.indexOf(wordFilter.value) >= 0){
+                    result.push(f)
+                } else if(f.shortCode && f.shortCode.indexOf(wordFilter.value) >= 0){
+                    result.push(f)
+                }
+            })
+            return result
+        } else {
+            return tableData.value
+        }
+    }
+})
+
+const handleUpdSchoolW = async (schDocId, schName, shortCode) =>{
+    const iDsCount = ref(0)
+    // 檢查array 內容是否重複
+    function isArrayRep(array){
+        var result = new Set();
+        var repeat = new Set();
+        array.forEach(item => {
+            result.has(item) ? repeat.add(item) : result.add(item);
+        })
+        // console.log(result); // {1, 2, "a", 3, "b"}
+        // console.log(repeat); // {1, "a"}
+        // console.log(repeat.size)
+        if(repeat.size != 0){
+            return true
+        } else {
+            return false
+        }
+    }
+    // 規則檢查: iDs
+    const checkIds = (value) => {
+        let isErr = false
+        if(!value) {
+            isErr = true
+            return "請填入要歸戶的醍摩豆ID"
+        } else if(value && !/^[0-9\n]+$/.test(value)){
+            isErr = true
+            return "只能輸入醍摩豆ID與換行"
+        } else if(value && isArrayRep(value.split('\n'))){
+            isErr = true
+            return "醍摩豆ID有重複"
+        } else if(value){
+            let errIds = []
+            let tmp = value.split('\n')
+            tmp.forEach(e=> {
+                if(e.length != 10) {
+                    errIds.push(e)
+                } else {
+                    let now = Math.floor(new Date().getTime() / 1000)
+                    let orgId = parseInt(e)
+                    if(parseInt(e.substring(0, 1)) >= 6){
+                        orgId -= 5000000000
+                    }
+
+                    if(orgId > now){
+                        errIds.push(e)
+                    }
+                }
+            })
+
+            if(errIds.length > 0){
+                // console.log(errIds, 'errIds')
+                isErr = true
+                return "請檢查醍摩豆ID是否符合格式或有空格"
+            }
+        }
+
+        if(!isErr && value != ''){
+            let tArray = value.split('\n')
+            iDsCount.value = tArray.length
+        } else {
+            iDsCount.value = 0
+        }
+
+        return true
+    }
+
+    if(!shortCode){
+        ElMessageBox.alert('此學校目前沒有簡碼', `***${schName}***`,
+            {
+                type: 'warning',
+                icon: markRaw(Warning),
+            }
+        )
+        // 中斷
+        return 
+    }
+
+    ElMessageBox.prompt(
+        '請填入要歸戶的醍摩豆ID', `歸戶至 ${schName} - ${shortCode}`, {
+            confirmButtonText: '歸戶',
+            cancelButtonText: '取消',
+            inputType: 'textarea',
+            inputValidator: checkIds,
+            customClass: 'prompClass',
+            roundButton: true,
+            closeOnClickModal: false
+        }
+    ).then(({value})=>{
+        let showStr = value.replaceAll('\n', ', ')
+        ElMessageBox.confirm(
+            `確認要歸戶以下的醍摩豆ID嗎?\n${showStr} \n\n 總共 ${iDsCount.value} 位`,
+            `歸戶至 ${schName}  - ${shortCode}`,
+            {
+                confirmButtonText: '確認',
+                cancelButtonText: '先不要',
+                type: 'info',
+                customClass: 'confirmClass'
+            }
+        ).then(async ()=>{
+            let reqData = {
+                schoolDocId: schDocId,
+                ids: value.split('\n')
+            }
+            
+            loadingStr.value = '弱歸戶...'
+            loading.value = true
+
+            await proxy.$api.updUserSchoolW(reqData).then((res) => {
+                ElMessageBox.alert('成功', '弱歸戶成功',
+                    {
+                        type: 'info',
+                        icon: markRaw(SuccessFilled),
+                    }
+                )
+            }).catch(e=>{
+                ElMessage.error('搜尋失敗')
+            }).finally(() => {
+                loading.value = false
+            })
+        })
+    })
+}
+</script>
+<style>
+.prompClass textarea{
+    min-height: 220px!important;
+}
+.confirmClass p{
+    white-space: pre-line;
+}
+.radioSty .el-radio__input{
+    display: none;
+}
+.radioSty .el-radio__label{
+    font-weight: bold;
+    font-size: 15px!important;
+}
+.radioSty .el-radio{
+    margin-right: 10px;
+}
+</style>
+<style scoped>
+.updCodeWBox{
+    width: 100%;
+    height: 82vh;
+    background-color: #fff;
+    z-index:999;
+    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3);
+    border-radius: 10px;
+    padding: 1%;
+    text-align: left;
+}
+.updCodeWBox-title{
+    line-height: 40px;
+    font-size:24px;
+    font-weight: bold;
+    color:#7b84a9;
+    text-align: center;
+}
+</style>

+ 124 - 0
TEAMModelBI/Controllers/BISchool/BatchSchoolController.cs

@@ -39,6 +39,9 @@ using HTEXLib;
 using TEAMModelOS.SDK.Models.Service.BI;
 using TEAMModelOS.SDK.Models.Cosmos.BI.BISchool;
 using DocumentFormat.OpenXml.Vml.Office;
+using System.Net.Http.Headers;
+using System.Text.Encodings.Web;
+using System.ComponentModel.DataAnnotations;
 
 namespace TEAMModelBI.Controllers.BISchool
 {
@@ -1779,6 +1782,112 @@ namespace TEAMModelBI.Controllers.BISchool
             return Ok(new { state = RespondCode.Ok, error });
         }
 
+        /// <summary>
+        /// 根據地理位置搜尋學校基本訊息
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("get-school-basic-info")]
+        public async Task<IActionResult> GetSchoolBasicInfo(SchoolDataRequest request)
+        {
+            try
+            {
+                string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/SchoolData", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    string jsonStr = await response.Content.ReadAsStringAsync();
+                    var options1 = new JsonSerializerOptions
+                    {
+                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+                    };
+
+                    
+                    return Ok(jsonStr.ToObject<JsonElement>());
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
+
+        /// <summary>
+        /// 弱歸戶
+        /// </summary>
+        /// <param name="GenerateCouponRequest"></param>
+        /// <returns></returns>
+        //[AuthToken(Roles = "admin,rdc,assist,sales")]
+        [HttpPost("upd-user-schoolw")]
+        public async Task<IActionResult> UpdUserSchoolW(UpdateUserSchoolCodeWRequest request)
+        {
+            try
+            {
+                string url = _configuration.GetValue<string>("HaBookAuth:CoreAPI");
+                string AccessToken = await getCoreAccessToken();
+                var client = _http.CreateClient();
+                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+                HttpResponseMessage response = await client.PostAsJsonAsync($"{url}/Service/UpdateUserSchoolCodeW", request);
+                if (response.StatusCode == HttpStatusCode.OK)
+                {
+                    string jsonStr = await response.Content.ReadAsStringAsync();
+                    var options1 = new JsonSerializerOptions
+                    {
+                        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+                    };
+
+
+                    return Ok(jsonStr.ToObject<JsonElement>());
+                }
+                else
+                {
+                    return BadRequest();
+                }
+            }
+            catch (Exception ex)
+            {
+                return BadRequest();
+            }
+        }
+
+        private async Task<string> getCoreAccessToken()
+        {
+            string AccessToken = "";
+            try
+            {
+                string Url = _configuration.GetValue<string>("HaBookAuth:CoreAPI") + "/oauth2/token";
+                string GrantType = "device";
+                string ClientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
+                string Secret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
+                var content = new { grant_type = GrantType, client_id = ClientID, client_secret = Secret };
+                var response = await _http.CreateClient().PostAsJsonAsync($"{Url}", content);
+                if (response.IsSuccessStatusCode)
+                {
+                    string responseBody = response.Content.ReadAsStringAsync().Result;
+                    using (JsonDocument document = JsonDocument.Parse(responseBody.ToString()))
+                    {
+                        if (document.RootElement.TryGetProperty("access_token", out JsonElement AccessTokenObj))
+                        {
+                            AccessToken = AccessTokenObj.ToString();
+                        }
+                    }
+                }
+                return AccessToken;
+            }
+            catch (Exception ex)
+            {
+                return AccessToken;
+            }
+        }
+
         #region   预设学校基础信息 多语言
 
         /// <summary>
@@ -2017,5 +2126,20 @@ namespace TEAMModelBI.Controllers.BISchool
             public string name { get; set; }
             public List<string> mobiles { get; set; }
         }
+
+        public record SchoolDataRequest
+        (
+            string countryId,
+            string provinceId,
+            string cityId,
+            string shortCode,
+            bool fullData = false
+        );
+
+        public record UpdateUserSchoolCodeWRequest
+        (
+            [Required] List<string> ids,
+            [Required] string schoolDocId
+        );
     }
 }

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 1
TEAMModelBI/Controllers/BITmid/TmidController.cs


+ 3 - 3
TEAMModelBI/TEAMModelBI.csproj

@@ -65,9 +65,9 @@
 		<SpaRoot>ClientApp\</SpaRoot>
 		<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
 		<UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-		<Version>5.2401.3</Version>
-		<AssemblyVersion>5.2401.3.1</AssemblyVersion>
-		<FileVersion>5.2401.3.1</FileVersion>
+		<Version>5.2401.10</Version>
+		<AssemblyVersion>5.2401.10.1</AssemblyVersion>
+		<FileVersion>5.2401.10.1</FileVersion>
 		<Description>TEAMModelBI(BI)</Description>
 		<PackageReleaseNotes>BI版本说明版本切换标记2022000908</PackageReleaseNotes>
 		<PackageId>TEAMModelBI</PackageId>

+ 3 - 3
TEAMModelOS.FunctionV4/TEAMModelOS.FunctionV4.csproj

@@ -5,9 +5,9 @@
 		<OutputType>Exe</OutputType>
 		<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
 		<SignAssembly>true</SignAssembly>
-		<Version>5.2401.3</Version>
-		<AssemblyVersion>5.2401.3.1</AssemblyVersion>
-		<FileVersion>5.2401.3.1</FileVersion>
+		<Version>5.2401.10</Version>
+		<AssemblyVersion>5.2401.10.1</AssemblyVersion>
+		<FileVersion>5.2401.10.1</FileVersion>
 		<PackageId>TEAMModelOS.FunctionV4</PackageId>
 		<Authors>teammodel</Authors>
 		<Company>醍摩豆(成都)信息技术有限公司</Company>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1791 - 0
TEAMModelOS.SDK/Helper/Common/JsonHelper/JsonParser.cs


+ 59 - 8
TEAMModelOS.SDK/Models/Cosmos/Common/Activity.cs

@@ -113,6 +113,7 @@ namespace TEAMModelOS.SDK.Models
     }
     public class ActivityDto : Activity
     {
+        public string url { get; set; }
         public string sas { get; set; }
     }
     /// <summary>
@@ -150,6 +151,7 @@ namespace TEAMModelOS.SDK.Models
     public class ActivityWebsiteDto : ActivityWebsite
     {
         public string sas { get; set; }
+        public string url { get; set; }
         public ActivityWebsiteDto() { }
         public ActivityWebsiteDto(ActivityWebsite website) {
             this.allowPublic = website.allowPublic;
@@ -282,7 +284,7 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         /// 0未进入专家评审阶段,1已经进入专家评审阶段。
         /// </summary>
-        public int reviewStatus {  get; set; }
+        public int reviewStatus { get; set; }
         /// <summary>
         ///  //default 默认,评审规则
         /// </summary>
@@ -538,7 +540,7 @@ namespace TEAMModelOS.SDK.Models
         public string expertPicture { get; set; }
         public string expertName { get; set; }
         public string expertId { get; set; }
-        public IEnumerable<string> periodSubjects { get; set; }= new List<string>();
+        public IEnumerable<string> periodSubjects { get; set; } = new List<string>();
     }
 
     public class ExpertSubject {
@@ -680,6 +682,17 @@ namespace TEAMModelOS.SDK.Models
         /// 掩饰分数 -1未评分
         /// </summary>
         public double maskScore { get; set; } = -1;
+
+        //public List<ExpertUploadScore> expertScore { get; set; } = new List<ExpertUploadScore>();
+    }
+
+    public class ExpertUploadScore { 
+        public string id { get; set; }
+        public string name { get; set; }
+        public double score { get; set; }
+        public string nickname { get; set; }
+        public string picture { get; set; }
+        public List<RuleConfig> detailScore { get; set; } = new List<RuleConfig>();
     }
     /// <summary>
     /// Teacher表
@@ -687,17 +700,33 @@ namespace TEAMModelOS.SDK.Models
     /// </summary>
     public class ActivityExpertTask : CosmosEntity
     {
-        public  string name { get; set; }
+        public string name { get; set; }
         public string picture { get; set; }
         public string tmdname { get; set; }
-
+        public string activityId { get; set; }
         //id  专家id ,
         //code  ActivityExpertTask-活动id
         /// <summary>
         /// 专家在优课评选中的评审任务
         /// </summary>
-        public List<ExpertContestTask>  contestTasks{ get; set; }
+
+        public List<ExpertContestTask> contestTasks { get; set; }
+
+    }
+    public class ActivityExpertDto
+    {
+        public string activityId { get; set; }
+        public string activityName { get; set; }
+        public long stime { get; set; }
+        public long etime { get; set; }
+        public int taskCount { get; set; }
+        public int completeCount { get; set; }
+        public List<ExpertContestTask> contestTasks { get; set; } = new List<ExpertContestTask>();
+        public string sas { get; set; }
+        public string url {  get; set; }
     }
+
+
     [Serializable]
     public class ExpertContestTaskDto : ExpertContestTask
     {
@@ -707,13 +736,15 @@ namespace TEAMModelOS.SDK.Models
         public string expertId { get; set; }
         public string periodSubjectKey { get; set; }
         /// <summary>
-        /// 0,默认未分配,1已经匹配,2学段未选择,3学科未选择,4 学段或学科未选择,5未上传,6学科或学段不匹配,7未匹配到符合的专家
+        /// 0,默认未分配,1已经匹配,2学段未选择,3学科未选择,4 学段或学科未选择,5未上传,6学科或学段不匹配,7未匹配到符合的专家,8分配次数不足
         /// </summary>
         public int available { get; set; }
         /// <summary>
         /// 第几轮
         /// </summary>
         public int turn { get; set; }
+        public string activityId { get; set; }
+
         public T DeepCopy<T>() where T : ExpertContestTaskDto
         {
             string jsonString = JsonSerializer.Serialize(this);
@@ -773,9 +804,29 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public string teamCipherContest { get; set; }
         public int reviewContestAssignCount { get; set; }
-        public List<IdNameCode> reviewContestExperts { get; set; } = new List<IdNameCode>();
+        public List<ExpertUploadScore> reviewContestExperts { get; set; } = new List<ExpertUploadScore>();
+    }
+    //作品评审结果
+    public class ContestUploadData
+    {
+        public string id { get; set; }
+        public string name { get; set; }
+        public string code { get; set; }
+        public int count { get; set; }
+        public int status { get; set; }
+        public double score { get; set; }
+        public List<RuleConfig> detailScore { get; set; } = new List<RuleConfig>();
+    }
+
+    public class ReviewScoreData
+    {
+        public double score { get; set; } = -1;
+        public List<RuleConfigTree> detailScore { get; set; } = new List<RuleConfigTree>();
+        public string uploadId { get; set; }
     }
 
+    
+
     /// <summary>
     /// 专家在优课评选模块的任务分配
     /// </summary>
@@ -850,7 +901,7 @@ namespace TEAMModelOS.SDK.Models
         /// </summary>
         public int teacherCount { get; set; } = -1;
 
-        public List<IdCodeCount> uploads { get; set; } = new List<IdCodeCount>();
+        public List<ContestUploadData> uploads { get; set; } = new List<ContestUploadData>();
 
     }
 

+ 7 - 1
TEAMModelOS.SDK/Models/Cosmos/Common/GroupList.cs

@@ -487,7 +487,13 @@ namespace TEAMModelOS.SDK.Models
         public string stulist { get; set; }
         public string teacherId { get; set; }
     }
-    
+    public record IdCodeNameCount
+    {
+        public string id { get; set; }
+        public string code { get; set; }
+        public string name { get; set; }
+        public int count { get; set; }
+    }
     public class IdNameCode
     {
         public string id { get; set; }

+ 41 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/IotTeachingData.cs

@@ -141,6 +141,38 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         /// T課堂 0:false 1:true
         /// </summary>
         public string tlesson { get; set; }
+        /// <summary>
+        /// 課堂中課堂中使用記分板 0:false 1:true
+        /// </summary>
+        public string useScoreBoard { get; set; }
+        /// <summary>
+        /// 學習參與度指數
+        /// </summary>
+        public int learnParticipation { get; set; }
+        /// <summary>
+        /// 是否計算學習參與度 (學習參與度指數>0:true ==0:false)
+        /// </summary>
+        public string learnParticipationCnt { get; set; }
+        /// <summary>
+        /// 協作任務數
+        /// </summary>
+        public int coopMission { get; set; }
+        /// <summary>
+        /// 協作作品數
+        /// </summary>
+        public int coopWork { get; set; }
+        /// <summary>
+        /// 協作總貢獻度
+        /// </summary>
+        public int coopContributionT { get; set; }
+        /// <summary>
+        /// 互評活動次數
+        /// </summary>
+        public int peerAct { get; set; }
+        /// <summary>
+        /// 互評學生參與總次數
+        /// </summary>
+        public int peerStuParticipationT { get; set; }
     }
 
     /// <summary>
@@ -194,5 +226,14 @@ namespace TEAMModelOS.SDK.Models.Cosmos.Common
         public int useIes5Test { get; set; } //課堂中有使用IES5測驗模式
         public int usePaperTest { get; set; } //課堂中有使用紙本測驗模式
         public int useExcelTest { get; set; } //課堂中有使用Excel測驗模式
+        public int useScoreBoard { get; set; } //課堂中使用記分板
+        public int learnParticipationCnt { get; set; } //學習參與度次數
+        public long learnParticipationT { get; set; } //學習參與度指數(總和)
+        public decimal learnParticipation { get; set; } //學習參與度指數(平均)
+        public int coopMission { get; set; } //協作任務數
+        public int coopWork { get; set; } //協作作品數
+        public long coopContributionT { get; set; } //協作總貢獻度
+        public int peerAct { get; set; } //互評活動次數
+        public long peerStuParticipationT { get; set; } //互評學生參與總次數
     }
 }

+ 1 - 0
TEAMModelOS.SDK/Models/Cosmos/School/Elegant.cs

@@ -45,6 +45,7 @@ namespace TEAMModelOS.SDK.Models
         /// school, course,class
         /// </summary>
         public string type { get; set; }
+        public string periodId { get; set; }
         public List<string> classes { get; set; } = new List<string>();
      
         public List<Attachment> attachments { get; set; } = new List<Attachment>();

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 35 - 2
TEAMModelOS.SDK/Models/Service/BI/BIProdAnalysis.cs


+ 35 - 10
TEAMModelOS.SDK/Models/Service/Common/ActivityService.cs

@@ -58,7 +58,8 @@ namespace TEAMModelOS.SDK
                         tmdid=z.tmdid,
                         score=z.score,
                         status=z.status,
-                        detailScore=z.detailScore
+                        detailScore=z.detailScore,
+                        activityId=contest.id
                     }));
                 }
                 //处理已经分配完成(taskCount)的作品
@@ -91,13 +92,13 @@ namespace TEAMModelOS.SDK
                     List<IdNameCode> members = team.Select(z => new IdNameCode { id = z.id, code = z.schoolId, picture = z.tmdPicture, nickname = z.tmdName, name = z.contest?.enrollInfos?.Find(e => e.code.Equals("name")).val }).ToList();
                     //队长的报名信息
                     var leader = leaders?.First();
-                    string name = leader.contest?.teamName;
-                    var period = leader.contest?.enrollInfos?.Find(z => z.code.Equals("period"));
-                    var subject = leader.contest?.enrollInfos?.Find(z => z.code.Equals("subject"));
+                    string name = leader?.contest?.teamName;
+                    var period = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("period"));
+                    var subject = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("subject"));
                     string uploadId = string.Empty;
                     if (string.IsNullOrEmpty(name))
                     {
-                        name = $"{leader.contest?.enrollInfos?.Find(z => z.code.Equals("name"))?.val}({team.Count})";
+                        name = $"{leader?.contest?.enrollInfos?.Find(z => z.code.Equals("name"))?.val}({team.Count})";
                     }
                     int count = 0;
                     int available = -1;
@@ -105,11 +106,11 @@ namespace TEAMModelOS.SDK
                     if (checkResult.available == 0)
                     {
 
-                        if (leader.upload != null && leader.upload.sokrates.IsNotEmpty())
+                        if (leader?.upload != null && leader.upload.sokrates.IsNotEmpty())
                         {
                             count += leader.upload.sokrates.Count;
                         }
-                        if (leader.upload != null && leader.upload.files.IsNotEmpty())
+                        if (leader?.upload != null && leader.upload.files.IsNotEmpty())
                         {
                             count += leader.upload.files.Count;
                         }
@@ -120,7 +121,7 @@ namespace TEAMModelOS.SDK
                         }
                         else
                         {
-                            uploadId = leader.upload?.uploadId;
+                            uploadId = leader?.upload?.uploadId;
                             available = checkResult.available;
                         }
                     }
@@ -149,7 +150,8 @@ namespace TEAMModelOS.SDK
                             periodSubjectKey = checkResult.periodSubjectKey,
                             period = period?.val,
                             subject = subject?.val,
-                            available = available
+                            available = available,
+                            activityId=contest.id,
                         });
                     }
                     else
@@ -159,6 +161,7 @@ namespace TEAMModelOS.SDK
                         expertContestTask.count = count;
                         expertContestTask.members = members;
                         expertContestTask.periodSubjectKey = checkResult.periodSubjectKey;
+                        expertContestTask.activityId=contest?.id;
                     }
                 }
                 else
@@ -228,7 +231,8 @@ namespace TEAMModelOS.SDK
                             periodSubjectKey = checkResult.periodSubjectKey,
                             period = period?.val,
                             subject = subject?.val,
-                            available = available
+                            available = available,
+                            activityId = contest?.id,
                         });
                     }
                     else
@@ -237,6 +241,7 @@ namespace TEAMModelOS.SDK
                         expertContestTask.name = name;
                         expertContestTask.count = count;
                         expertContestTask.periodSubjectKey = checkResult.periodSubjectKey;
+                        expertContestTask.activityId=contest?.id;
                     }
                 }
             }
@@ -247,6 +252,23 @@ namespace TEAMModelOS.SDK
             if (invalids.IsNotEmpty()) {
                 invalids.AddRange(data.assignmentsInvalid);
             }
+            List<ExpertContestTaskDto> okTask = new List<ExpertContestTaskDto>();
+            okTask.AddRange(data.assignmentsAdd);
+            okTask.AddRange(worksDB);
+            var groups= okTask.GroupBy(z => z.uploadId).Select(x => new { key = x.Key, list = x.ToList() });
+            foreach (var item in groups) {
+                if (item.list.Count()<taskCount) {
+
+                    ExpertContestTaskDto taskDto=  item.list.First().ToJsonString().ToObject<ExpertContestTaskDto>();
+                    taskDto.expertName=null;
+                    taskDto.expertId=null;
+                    taskDto.expertPicture=null;
+                    taskDto.expertTmdname=null;
+                    //,8分配次数不足
+                    taskDto.available=8;
+                    invalids.Add(taskDto);
+                }
+            }
             return (data.assignmentsAdd, invalids, worksDB);
         }
         public static (int available, string periodSubjectKey) CheckPeriodSubject(string distribute , EnrollInfo period, EnrollInfo subject, HashSet<string> periodSubjectKeys) {
@@ -446,6 +468,7 @@ namespace TEAMModelOS.SDK
             result.list.ForEach(z => {
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                 z.sas=blob_sas;
+                z.url=blob_uri;
             });
             return result.list.OrderByDescending(z => z.stime);
         }
@@ -541,6 +564,7 @@ namespace TEAMModelOS.SDK
             {
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                 z.sas=blob_sas;
+                z.url = blob_uri;
             });
 
             return activities;
@@ -623,6 +647,7 @@ namespace TEAMModelOS.SDK
             {
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read);
                 z.sas=blob_sas;
+                z.url=blob_uri;
             });
             if (activities.IsNotEmpty())
             {

+ 3 - 3
TEAMModelOS.SDK/TEAMModelOS.SDK.csproj

@@ -2,9 +2,9 @@
 
   <PropertyGroup>
     <TargetFramework>net6.0</TargetFramework>
-    <Version>5.2401.3</Version>
-    <AssemblyVersion>5.2401.3.1</AssemblyVersion>
-    <FileVersion>5.2401.3.1</FileVersion>
+    <Version>5.2401.10</Version>
+    <AssemblyVersion>5.2401.10.1</AssemblyVersion>
+    <FileVersion>5.2401.10.1</FileVersion>
     <PackageReleaseNotes>发版</PackageReleaseNotes>
   </PropertyGroup>
 

+ 2 - 0
TEAMModelOS.sln

@@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelBI", "TEAMModelBI\
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TEAMModelOS.TEST", "TEAMModelOS.TEST\TEAMModelOS.TEST.csproj", "{335938F6-8418-497A-AB41-CDD006FB8FD6}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TEAMModelContest", "TEAMModelContest", "{43694D93-19B4-4AF6-8A37-2B2073E7014C}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU

+ 1 - 1
TEAMModelOS/ClientApp/package.json

@@ -83,7 +83,7 @@
     "vuex": "^3.0.1",
     "vuex-oidc": "^3.3.0",
     "vuex-router-sync": "^5.0.0",
-    "wangeditor": "4.4.1",
+    "wangeditor": "^4.4.1",
     "webpack": "^4.46.0",
     "xlsx": "^0.17.1"
   },

+ 4 - 4
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -7851,7 +7851,7 @@ const LANG_ZH_TW = {
     },
     activity: {
         scoreWord: {
-            only: '按评审分数',
+            only: '按評審分數',
             avg: '按平均分',
             top: '按最高分',
             rmLowAvg: '去掉最低分的平均分',
@@ -7860,9 +7860,9 @@ const LANG_ZH_TW = {
         },
         distributeWord: {
             none: '不需要匹配',
-            period: '只匹配段',
-            subject: '只匹配科',
-            periodAndSubject: '同时匹配学科和学段',
+            period: '只匹配段',
+            subject: '只匹配科',
+            periodAndSubject: '同时匹配學科和學段',
         },
     },
 

+ 25 - 44
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -134,6 +134,7 @@
 	export default {
 		data() {
 			return {
+				isQingYangArea:false,
 				version: "",
 				edition: "",
 				updateModal: false,
@@ -387,7 +388,7 @@
 					});
 			},
 			menuClick(menu) {
-				console.error(menu)
+				console.error(menu);
 				if (menu.router == "#") {
 					if (menu.to === "privSokrate") {
 						this.toPrivSokrate();
@@ -424,7 +425,7 @@
 				return ["collapse-icon", this.isCollapsed ? "rotate-icon" : ""];
 			},
 			// isDev(){
-			// 	return 
+			// 	return
 			// },
 			schoolStatusInfo() {
 				if (this.isCollapsed) {
@@ -455,8 +456,8 @@
 			isGlobalSite() {
 				return this.$store.state.config.srvAdr !== "China";
 			},
-			isQingYangArea() {
-				return sessionStorage.getItem("areaId") && sessionStorage.getItem("areaId") === "7a51072f-b329-4e74-99e0-ba0407ba8926";
+			curPeriod(){
+				return this.$store.state.user.curPeriod
 			},
 			/* 是否开启课堂记录管理开关 */
 			isOpenLessonRecord() {
@@ -719,42 +720,17 @@
 					? isZhiYinVersion
 						? this.zySchoolMenu
 						: [
-								//iot (10.20 应台湾要求 调整 顺序 1.iot 2.教学看板)
-								// {
-								// 	icon: "iconfont icon-wulianwang",
-								// 	name: this.$t("system.menu.iotBoard"),
-								// 	router: "/schooliot",
-								// 	tag: "",
-								// 	role: "admin",
-								// 	permission: "dashboard-read",
-								// 	menuName: "TeacherDashboard",
-								// 	child: [],
-                                //     //isShow: this.isGlobalSite
-								// 	isShow:true,
-								// },
-								// 教学看板(国际站单独)
-								// {
-								// 	icon: "iconfont icon-data-count",
-								// 	name: this.$t("system.menu.techDash"),
-								// 	router: "/researchDashboard",
-								// 	tag: "",
-								// 	role: "admin",
-								// 	permission: "dashboard-read",
-								// 	menuName: "TeacherDashboard",
-								// 	child: [],
-								// 	isShow: this.isGlobalSite,
-								// },
 								// 数据中心
 								{
 									icon: "iconfont icon-data-count",
-									name: this.$t('researchCenter.dashboard.dashCenter'),
+									name: this.$t("researchCenter.dashboard.dashCenter"),
 									router: "/dashCenter",
 									tag: "",
 									role: "admin",
 									permission: "dashboard-read",
 									menuName: "dashCenter",
 									child: [],
-									isShow: this.IES5Menu,
+									isShow: this.IES5Menu
 								},
 								// 学校管理
 								{
@@ -1147,7 +1123,7 @@
 											role: "admin",
 											permission: "art-upd",
 											menuName: "ArtAssessment",
-											isShow: true
+											isShow: !this.isQingYangArea
 										}
 									],
 									isShow: this.hasArtProd
@@ -1164,7 +1140,7 @@
 									isShow: false,
 									child: [
 										// 校园风采
-										
+
 										{
 											icon: "iconfont icon-basic-setting",
 											name: this.$t("system.menu.judgeSettings"),
@@ -1179,7 +1155,7 @@
 										},
 										{
 											icon: "iconfont icon-basic-setting",
-											name: '评价管理',
+											name: "评价管理",
 											router: "/appraiseMgt",
 											tag: "",
 											role: "admin",
@@ -1187,7 +1163,7 @@
 											permission: "",
 											menuName: "appraiseMgt",
 											child: [],
-											isShow: window.location.host.includes("test.teammodel.cn") || this.$store.state.config.srvAdrType != 'product'
+											isShow: window.location.host.includes("test.teammodel.cn") || this.$store.state.config.srvAdrType != "product"
 										}
 									]
 								},
@@ -1247,7 +1223,7 @@
 									router: "#",
 									to: "schoolSokrate",
 									tag: "",
-									child:[],
+									child: [],
 									role: "admin",
 									permission: "research-read|research-upd",
 									menuName: "schoolSokrate",
@@ -1280,7 +1256,7 @@
 								// 活动报名
 								{
 									icon: "iconfont icon-yishu",
-									name: '活动平台',
+									name: "活动平台",
 									router: "/home/activityManage",
 									tag: "",
 									role: "admin",
@@ -1288,9 +1264,9 @@
 									child: [],
 									menuName: "activityManage",
 									// menuName: 'myCourse',
-									isShow: false,
-								},
-						  	]
+									isShow: false
+								}
+						  ]
 					: [];
 				return data;
 			},
@@ -1468,7 +1444,7 @@
 									// }
 								]
 							},
-							
+
 							// 个人研修
 							{
 								icon: "iconfont icon-train",
@@ -1565,8 +1541,7 @@
                 isShow: true
             }, */
 								]
-							},
-							
+							}
 					  ];
 				return data;
 			}
@@ -1621,7 +1596,13 @@
 				handler(n, o) {
 					this.getSystemLevel();
 				}
-			}
+			},
+			curPeriod:{
+				immediate: true,
+				handler(n,o){
+					this.isQingYangArea = sessionStorage.getItem("areaId") && sessionStorage.getItem("areaId") === "7a51072f-b329-4e74-99e0-ba0407ba8926";
+				}
+			},
 		}
 	};
 </script>

+ 4 - 2
TEAMModelOS/ClientApp/src/components/public/frontEndMain/Index.vue

@@ -90,8 +90,8 @@
 <template>
     <div id="login" :class="[isShowZY ? 'login zylogin':'login']" :style="{backgroundImage:bgImg}">
         <div class="login-mark" v-show="isShowTMD">
-            <img height="42" src="@/assets/login/ies5_logo_2.svg">
-            <span class="login-title">
+            <img height="30" src="@/assets/login/ies5_logo_2.svg">
+            <span class="login-title" v-if="!queryCode">
                 {{$t('system.title')}}
             </span>
         </div>
@@ -136,6 +136,7 @@ export default {
             version: '',
             isShowTMD: false,
             isShowZY: false,
+            queryCode:''
         }
     },
     computed: {
@@ -164,6 +165,7 @@ export default {
     created() {
         let queryData = this.$route.query
         console.log(this.$route)
+        this.queryCode = queryData.code
         // 統一處理預設登入學校
         this.setLoginSchoolCode()
         this.$api.login.getSystemInfo({}).then(

+ 3 - 0
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScatter.vue

@@ -68,6 +68,9 @@ export default {
         legend: {
           data: [_this.$t('totalAnalysis.sca_text4')]
         },
+        grid:{
+          containLabel:true
+        },
         // toolbox: {
         //    show: true,
         //    right: '70px',

+ 3 - 0
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseTestScatter.vue

@@ -51,6 +51,9 @@ export default {
         legend: {
           data: [_this.$t('totalAnalysis.ta_chart_text1')]
         },
+        grid:{
+          containLabel:true
+        },
         // dataZoom: [{
         // 		show: true,
         // 		type: 'inside',

+ 2 - 1
TEAMModelOS/ClientApp/src/components/student-web/HomeView/HomeView.vue

@@ -920,7 +920,8 @@ export default {
         getAllCourse: {
             handler(n, o) {
                 this.isLoading = true
-                this.allCourseShow = [...n]
+                this.searchCourse()
+                // this.allCourseShow = [...n]
                 if(this.classRecord) {
                     let recordList = [...this.classRecord]
                     this.classRecord = recordList.map(item => {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -436,7 +436,7 @@
 				return host == "zhiyin-test.teammodel.cn";
 			},
 			teacherRoutes(){
-				return  ["/home/course", "/home/taskList/marking", "/home/personalSyllabus", "/home/personalcontent", "/home/evaluation/personalBank", "/ome/privExam", "/home/manageHomeWork", "/home/personalVote", "/home/personalSurvey", "/home/jyHome", "/home/online", "/home/offline", "/home/application", "/home/classMemoir", "/home/discuss"];
+				return  ["/home/homePage", "/home/course", "/home/classRecord", "/home/userCenter", "/home/settings",  "/home/taskList/marking", "/home/personalSyllabus", "/home/personalcontent", "/home/evaluation/personalBank", "/home/privExam", "/home/manageHomeWork", "/home/personalVote", "/home/personalSurvey", "/home/jyHome", "/home/online", "/home/offline", "/home/application", "/home/classMemoir", "/home/discuss"];
 			}
 		},
 		watch: {

+ 4 - 4
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaIndex.vue

@@ -439,8 +439,8 @@ export default {
               color: '#333',
             },
             formatter: function (name) {
-              if (name.length > 6) {
-                name = name.slice(0, 6) + '...';
+              if (name.length > 12) {
+                name = name.slice(0, 12) + '...';
               }
               return name
             },
@@ -486,8 +486,8 @@ export default {
               color: '#333',
             },
             formatter: function (name) {
-              if (name.length > 6) {
-                name = name.slice(0, 6) + '...';
+              if (name.length > 12) {
+                name = name.slice(0, 12) + '...';
               }
               return name
             },

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 840 - 779
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaLayout.vue


+ 16 - 18
TEAMModelOS/ClientApp/src/view/art/AreaArt.vue

@@ -104,7 +104,7 @@
 						</div>
 					</div>
 				</div>
-        <div class="online-train-wrap">
+				<div class="online-train-wrap">
 					<h4 class="block-title">学校艺术特色素材数量统计</h4>
 					<div class="chart-data-wrap">
 						<ArtBar echartsId="artBar" :echartData="artBarData"></ArtBar>
@@ -169,12 +169,12 @@
 			SchoolComp,
 			OccupyCourse,
 			Award,
-      ArtBar,
+			ArtBar,
 			BackToTop
 		},
 		data() {
 			return {
-        artBarData:[],
+				artBarData: [],
 				dashSchoolCode: "",
 				modalTitle: "",
 				dashModal: false,
@@ -331,7 +331,7 @@
 						code: item.code,
 						musicPass: musicPass,
 						drawPass: drawPass,
-            picture:item.picture
+						picture: item.picture
 					};
 				});
 				return data;
@@ -610,19 +610,19 @@
 			},
 			onAcChange() {
 				this.getAreaArtAnalysis();
-        this.$api.elegant
+				this.$api.elegant
 					.findElegantStatistics({
 						scope: "area",
-						code: sessionStorage.getItem("areaId")
+						code: sessionStorage.getItem("areaId"),
+						periodType: this.periodId
 					})
 					.then((res) => {
-						console.log(res);
-            this.artBarData = res.schoolDatas.map(school => {
-              return {
-                name:school.name,
-                count:school.items[1].count
-              }
-            })
+						this.artBarData = res.schoolDatas.map((school) => {
+							return {
+								name: school.name,
+								count: school.items.find(i => i.id === '艺术特色').count
+							};
+						});
 					});
 			},
 			getAreaSchoolList() {
@@ -748,8 +748,6 @@
 				this.modalTitle = school.name + " - 学生风采统计数据";
 				this.dashSchoolCode = school.code;
 				this.dashModal = true;
-
-				
 			},
 			backToTop() {
 				this.$refs["art-dasboard"].scrollTo(
@@ -832,7 +830,7 @@
 			align-items: center;
 			margin-right: 20px;
 			color: #2d8cf0;
-			border:1px solid #2d8cf0;
+			border: 1px solid #2d8cf0;
 			padding: 5px 10px;
 			border-radius: 5px;
 
@@ -880,7 +878,7 @@
 		background: #ffffff;
 		margin-top: 10px;
 		padding: 40px 20px;
-    border-radius: 10px;
+		border-radius: 10px;
 	}
 
 	.block-title {
@@ -962,7 +960,7 @@
 		width: 100%;
 		height: 100%;
 		background: #ededed;
-    // padding: 15px 20px;
+		// padding: 15px 20px;
 
 		.export-box {
 			position: absolute;

+ 10 - 2
TEAMModelOS/ClientApp/src/view/artexam/AcQuos.vue

@@ -208,9 +208,17 @@
 				let fileItem = {
 					file,
 					fileName: file.name
-				};
+				};  
+				function extractNumbers(str) {
+					// 创建一个正则表达式,用于匹配字符串中的数字
+					const regex = /\d+/g;
+					// 使用正则表达式在字符串中查找所有匹配的数字
+					const numbers = str.match(regex);
+					// 如果找到数字,则返回它们,否则返回空数组
+					return numbers || [];
+				}
 				if (this.curClass && this.curClass.members) {
-					let n = file.name.substring(0, file.name.lastIndexOf("."));
+					let n = extractNumbers(file.name.substring(0, file.name.lastIndexOf(".")))[0];
 					let studentInfo = this.curClass.members.find((item) => item.id == n || item.name === n);
 					if (studentInfo) {
 						fileItem.studentName = studentInfo.name;

+ 3 - 1
TEAMModelOS/ClientApp/src/view/elegant/BaseElegantCloud.vue

@@ -46,7 +46,9 @@
         watch: {
             echartData:{
                 handler(n,o){
-                    let keyCounts = this.echartsId === 'cloud1' ? n[1].keyCounts : n[0].keyCounts
+					let cloud1Index = n.findIndex(i => i.id === '艺术特色')
+					let cloud2Index = n.findIndex(i => i.id === '德育风采')
+                    let keyCounts = this.echartsId === 'cloud1' ? n[cloud1Index].keyCounts : n[cloud2Index].keyCounts
                     this.chartOption.series[0].data = keyCounts.map(i => {
                         return {
                             name: i.word,

+ 76 - 71
TEAMModelOS/ClientApp/src/view/elegant/BaseElegantDash.vue

@@ -1,6 +1,6 @@
 <template>
 	<div class="elegant-dash-container">
-        <Spin fix v-if="isLoading"></Spin>
+		<Spin fix v-if="isLoading"></Spin>
 		<!-- <div class="title">
 			<span>数据总览</span>
 			<span class="btn-details" @click="goDetails">数据详情 ></span>
@@ -9,32 +9,32 @@
 			<div class="count-item">
 				<p class="label">全部活动数</p>
 				<p class="value">{{ countArr[0] }}</p>
-                <img src="../../assets/source/folder.png">
+				<img src="../../assets/source/folder.png" />
 			</div>
 			<div class="count-item">
 				<p class="label">德育风采数</p>
 				<p class="value">{{ countArr[1] }}</p>
-                <img src="../../assets/mark/5.png" style="width: 70px">
+				<img src="../../assets/mark/5.png" style="width: 70px" />
 			</div>
 			<div class="count-item">
 				<p class="label">艺术特色数</p>
 				<p class="value">{{ countArr[2] }}</p>
-                <img src="../../assets/mark/7.png" style="width: 70px">
+				<img src="../../assets/mark/7.png" style="width: 70px" />
 			</div>
 			<div class="count-item">
 				<p class="label">图片总数</p>
 				<p class="value">{{ countArr[3] }}</p>
-                <img src="../../assets/source/image.png">
+				<img src="../../assets/source/image.png" />
 			</div>
 			<div class="count-item">
 				<p class="label">视频总数</p>
 				<p class="value">{{ countArr[4] }}</p>
-                <img src="../../assets/source/video.png">
+				<img src="../../assets/source/video.png" />
 			</div>
 			<div class="count-item">
 				<p class="label">文档总数</p>
 				<p class="value">{{ countArr[5] }}</p>
-                <img src="../../assets/source/pdf.png">
+				<img src="../../assets/source/pdf.png" />
 			</div>
 		</div>
 		<div class="chart-wrap">
@@ -46,12 +46,12 @@
 					<BasePie echartsId="pie1" :echartData="artCount"></BasePie>
 				</div>
 			</div>
-            <div class="chart-block" style="margin: 0 1%;width: 26%">
+			<div class="chart-block" style="margin: 0 1%; width: 26%">
 				<div class="chart-title">
 					<p class="title">艺术特色素材文字云</p>
 				</div>
 				<div class="chart-content">
-                    <BaseElegantCloud echartsId="cloud1" :echartData="keyCounts"></BaseElegantCloud>
+					<BaseElegantCloud echartsId="cloud1" :echartData="keyCounts"></BaseElegantCloud>
 				</div>
 			</div>
 			<div class="chart-block chart-right">
@@ -64,7 +64,7 @@
 			</div>
 		</div>
 		<div class="chart-wrap">
-			<div class="chart-block" style="width: 26%;">
+			<div class="chart-block" style="width: 26%">
 				<div class="chart-title">
 					<p class="title">德育风采素材类型</p>
 				</div>
@@ -72,7 +72,7 @@
 					<BasePie echartsId="pie2" :echartData="elegantCount"></BasePie>
 				</div>
 			</div>
-			<div class="chart-block"  style="margin: 0 1%;width: 26%">
+			<div class="chart-block" style="margin: 0 1%; width: 26%">
 				<div class="chart-title">
 					<p class="title">德育风采素材文字云</p>
 				</div>
@@ -126,63 +126,68 @@
 	import BaseUploadLine from "./BaseUploadLine.vue";
 	import BaseElegantCloud from "./BaseElegantCloud.vue";
 	export default {
-		props:['schoolCode'],
+		props: ["schoolCode"],
 		components: {
 			BasePie,
 			BaseBar,
 			BaseUploadLine,
-            BaseElegantCloud
+			BaseElegantCloud
+		},
+		data() {
+			return {
+				isLoading: false,
+				elegantCount: [],
+				artCount: [],
+				keyCounts: [],
+				countArr: [0, 0, 0, 0, 0, 0]
+			};
+		},
+		created() {
+			this.initDash();
 		},
-        data(){
-            return {
-                isLoading:false,
-                elegantCount:[],
-                artCount:[],
-                keyCounts:[],
-                countArr:[0,0,0,0,0,0]
-            }
-        },
-        created(){
-            this.isLoading = true
-            this.$api.elegant.findElegantStatistics({
-                "scope": "school",
-                "code": this.schoolCode || localStorage.getItem("login_schoolCode")
-            })
-            .then((res) => {
-                console.log(res);
-                this.isLoading = false
-                let artItems = ['艺术特色','课程活动','艺术社团','艺术活动',"理想信念","社会责任","行为习惯","演奏", "影视", "舞蹈", "戏剧", "常规活动", "获奖活动"]
-                let elegantItems = ['德育风采',"理想信念","社会责任","行为习惯","读书分享","思想沙龙","文学创作","社会服务","文化交流","思德教育","反思日志","小组合作","行为习惯挑战"]
-                let elegantCount = elegantItems.map(item => {
-                    return {
-                        name:item,
-                        count: res.items.find(i => i.id === item) ? res.items.find(i => i.id === item).count : 0
-                    }
-                })
-                let artCount = artItems.map(item => {
-                    return {
-                        name:item,
-                        count: res.items.find(i => i.id === item) ? res.items.find(i => i.id === item).count : 0
-                    }
-                })
-                this.keyCounts = res.itemKeys
-                this.elegantCount = elegantCount
-                this.artCount = artCount
-                console.error(artCount)
-                this.countArr = [
-                    elegantCount[0].count + artCount[0].count,
-                    elegantCount[0].count,
-                    artCount[0].count,
-                    res.imageCount,
-                    res.videoCount,
-                    res.docCount
-                ]
-            });
-        },
 		methods: {
+			initDash() {
+				this.isLoading = true;
+				this.$api.elegant
+					.findElegantStatistics({
+						scope: "school",
+						code: this.schoolCode || localStorage.getItem("login_schoolCode"),
+						periodId: this.$store.state.user.curPeriod.id
+					})
+					.then((res) => {
+						console.log(res);
+						this.isLoading = false;
+						let artItems = ["艺术特色", "课程活动", "艺术社团", "艺术活动", "理想信念", "社会责任", "行为习惯", "演奏", "影视", "舞蹈", "戏剧", "常规活动", "获奖活动"];
+						let elegantItems = ["德育风采", "理想信念", "社会责任", "行为习惯", "读书分享", "思想沙龙", "文学创作", "社会服务", "文化交流", "思德教育", "反思日志", "小组合作", "行为习惯挑战"];
+						let elegantCount = elegantItems.map((item) => {
+							return {
+								name: item,
+								count: res.items.find((i) => i.id === item) ? res.items.find((i) => i.id === item).count : 0
+							};
+						});
+						let artCount = artItems.map((item) => {
+							return {
+								name: item,
+								count: res.items.find((i) => i.id === item) ? res.items.find((i) => i.id === item).count : 0
+							};
+						});
+						this.keyCounts = res.itemKeys;
+						this.elegantCount = elegantCount;
+						this.artCount = artCount;
+						this.countArr = [elegantCount[0].count + artCount[0].count, elegantCount[0].count, artCount[0].count, res.imageCount, res.videoCount, res.docCount];
+					});
+			},
 			goDetails() {
 				this.$emit("goDetails");
 			}
+		},
+		watch: {
+			"$store.state.user.curSemester": {
+				deep: true,
+				handler(n, old) {
+					this.initDash();
+				}
+			}
 		}
 	};
 </script>
@@ -220,7 +225,7 @@
 				flex-direction: column;
 				justify-content: space-between;
 				padding: 20px;
-                position: relative;
+				position: relative;
 				.label {
 					font-size: 14px;
 					color: #818181;
@@ -232,13 +237,13 @@
 					color: #0d78be;
 					letter-spacing: 1px;
 				}
-                img{
-                    width: 60px;
-                    position: absolute;
-                    bottom: 20px;
-                    right: 20px;
-                    opacity: .3;
-                }
+				img {
+					width: 60px;
+					position: absolute;
+					bottom: 20px;
+					right: 20px;
+					opacity: 0.3;
+				}
 			}
 		}
 		.chart-wrap {
@@ -258,14 +263,14 @@
 
 				.title {
 					font-size: 14px;
-                    display: flex;
-                    align-items: center;
+					display: flex;
+					align-items: center;
 					&::before {
 						content: "";
 						display: inline-block;
 						border: 3px solid #0d78be;
 						border-radius: 4px;
-                        height: 14px;
+						height: 14px;
 						margin-right: 10px;
 					}
 				}
@@ -277,7 +282,7 @@
 			}
 
 			.chart-right {
-                flex:1;
+				flex: 1;
 				// width: 71%;
 				// margin-left: 1%;
 			}

+ 24 - 11
TEAMModelOS/ClientApp/src/view/elegant/Elegant.vue

@@ -4,8 +4,8 @@
 		<div class="elegant-details-box">
 			<div class="container-title">
 				<div style="display: flex; align-items: center">
-					<span>{{isShowDash ? '数据总览' : '数据详情'}}</span>
-					<span class="btn-details" @click="isShowDash = !isShowDash">{{!isShowDash ? '数据总览' : '数据详情'}} ></span>
+					<span>{{ isShowDash ? "数据总览" : "数据详情" }}</span>
+					<span class="btn-details" @click="isShowDash = !isShowDash">{{ !isShowDash ? "数据总览" : "数据详情" }} ></span>
 				</div>
 				<div class="tools">
 					<Button shape="circle" @click="onAddElegant" icon="md-add">添加素材</Button>
@@ -175,7 +175,7 @@
 				isLoading: false,
 				allList: [],
 				typeList: [],
-				filterVal: ['0'],
+				filterVal: ["0"],
 				props: {
 					multiple: false,
 					value: "id",
@@ -317,22 +317,23 @@
 			};
 		},
 		created() {
-			this.typeList = this._.cloneDeep(this.bizTypeData)
+			this.typeList = this._.cloneDeep(this.bizTypeData);
 			this.typeList.unshift({
 				value: "0",
 				label: "全部素材",
-				children:[]
-			})
+				children: []
+			});
 			this.schoolProfile = JSON.parse(decodeURIComponent(localStorage.school_profile || "{}", "utf-8"));
 			this.$api.elegant
 				.findElegants({
 					admin: "1", //表示管理列表,其他则只获取有效的publish
+					periodId: this.$store.state.user.curPeriod.id,
 					stime: null, //可选
 					etime: null //可选
 				})
 				.then((res) => {
 					this.originList = res.elegants.reverse();
-					this.onFilterTypeChange(['0']);
+					this.onFilterTypeChange(["0"]);
 					this.getTargetList();
 				});
 		},
@@ -362,9 +363,9 @@
 				excel.export_array_to_excel(params);
 				this.isLoading = false;
 			},
-			onFilterTypeChange(val,origin) {
-				let lastLabel = origin ? origin[origin.length - 1].label : ''
-				this.elegantList = val.includes('0') ? this._.cloneDeep(this.originList) : this.originList.filter((i) => i.bizType && i.bizType.includes(lastLabel));
+			onFilterTypeChange(val, origin) {
+				let lastLabel = origin ? origin[origin.length - 1].label : "";
+				this.elegantList = val.includes("0") ? this._.cloneDeep(this.originList) : this.originList.filter((i) => i.bizType && i.bizType.includes(lastLabel));
 			},
 			onPreview(file) {
 				let fullLink = this.getFullPath(file.url);
@@ -578,6 +579,7 @@
 					params.type = "school";
 					params.startTime = 111;
 					params.endTime = 222;
+					params.periodId = this.curPeriod.id;
 					this.$api.elegant.upsertElegants(params).then((res) => {
 						if (!res.error) {
 							this.btnLoading = false;
@@ -692,7 +694,18 @@
 			"$store.state.user.curSemester": {
 				deep: true,
 				handler(n, old) {
-					this.getTargetList();
+					this.$api.elegant
+						.findElegants({
+							admin: "1", //表示管理列表,其他则只获取有效的publish
+							periodId: this.$store.state.user.curPeriod.id,
+							stime: null, //可选
+							etime: null //可选
+						})
+						.then((res) => {
+							this.originList = res.elegants.reverse();
+							this.onFilterTypeChange(["0"]);
+							this.getTargetList();
+						});
 				}
 			}
 		}

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseCreateChild.vue

@@ -68,7 +68,7 @@
 		</div>
 
 		<div class="save-wrap display-flex">
-			<Button v-if="!isPaperEnv" type="success" @click="getContent(exersicesType)" :loading="saveLoading">{{ $t('evaluation.newExercise.save') }}</Button>
+			<Button type="success" @click="getContent(exersicesType)" :loading="saveLoading">{{ $t('evaluation.newExercise.save') }}</Button>
 		</div>
 
 		<!-- 选择知识点弹窗 -->

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/components/BasePoints.vue

@@ -256,7 +256,7 @@ export default {
     },
 
     onSearchSchoolChange() {
-      this.schoolPointList = this.originSchoolList.filter(item => item.indexOf(this.searchSchoolPoint) > -1)
+      this.schoolPointList = this.originSchoolList.filter(item => item.toLowerCase().indexOf(this.searchSchoolPoint) > -1)
     },
   },
   mounted() {

+ 1 - 1
TEAMModelOS/ClientApp/src/view/evaluation/components/BaseRepair.vue

@@ -418,7 +418,7 @@
 	}
 
 	.repair-wrap {
-		min-height: 400px;
+		min-height: 200px;
 		padding-bottom: 50px;
 		.image-viewer {
 			background-color: rgba(0, 0, 0, 0.8);

+ 1 - 1
TEAMModelOS/ClientApp/src/view/iot/areaiot.vue

@@ -381,7 +381,7 @@ export default {
      getAreaiots() {
        let schoolcodeArr = []
        this.schoolList.forEach((item) => {schoolcodeArr.push(item.id)})
-       let data = { schoolIds: schoolcodeArr }
+       let data = { areaId: sessionStorage.getItem('areaId'), schoolIds: schoolcodeArr }
        this.$api.iot.getAreaiot(data).then((res) => {
         console.log(res,'area iot back')
           //header基础数据

+ 2 - 2
TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.vue

@@ -1007,13 +1007,13 @@ export default {
 
     // 搜索知识块输入框onchange事件
     onSearchBlockChange() {
-      this.blockList = this.originBlockList.filter(item => item.name.indexOf(this.searchBlock) > -1)
+      this.blockList = this.originBlockList.filter(item => item.name.toLowerCase().indexOf(this.searchBlock) > -1)
       if (this.blockList.length) this.handleBlockTap(0, this.blockList[0])
     },
 
     // 搜索知识点输入框onchange事件
     onSearchPointChange() {
-      this.pointList = this.originPointList.filter(item => item.indexOf(this.searchPoint) > -1)
+      this.pointList = this.originPointList.filter(item => item.toLowerCase().indexOf(this.searchPoint) > -1)
     },
 
     // 清空科目搜索框

+ 19 - 2
TEAMModelOS/ClientApp/src/view/login/page/Student.less

@@ -21,6 +21,23 @@
             
         }
     }
+
+    .query-school-info{
+        position: absolute;
+        top: 40px;
+        left: auto;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 50px;
+        color: #fff;
+        padding-bottom: 20px;
+        margin-bottom: 10px;
+
+        img {
+            margin-right: 15px;
+        }
+    }
 }
 .errlable{
     text-align: right;
@@ -182,7 +199,7 @@
 }
 .left-box {
     padding: 0px 70px;
-    height: 480px;
+    height: 430px;
     display: flex;
     align-items: center;
     justify-content: center;
@@ -194,7 +211,7 @@
     // box-shadow: -2px 0px 15px 0px rgba(75, 113, 136, 0.9);
     display: flex;
     // align-items: center;
-    height: 431px;
+    height: 380px;
     min-width: 600px;
 }
 .student-login-img {

+ 10 - 7
TEAMModelOS/ClientApp/src/view/login/page/Student.vue

@@ -116,10 +116,14 @@
 		<div class="left-box">
 			<!-- 这张图片需要裁剪顶部 -->
 			<img src="@/assets/login/icon_student.svg" class="student-login-img" style="margin-top: -30px" />
-			<p class="client-label">
+			<p class="client-label" v-if="!queryCode">
 				{{ $t("login.stuCli") }}
 			</p>
 		</div>
+		<div class="query-school-info" v-if="queryCode">
+			<img :src="querySchoolInfo.picture" alt="" srcset="" width="60px" />
+			<span>{{ querySchoolInfo.name }}</span>
+		</div>
 		<div class="right-box">
 			<!-- 醍摩豆表单登录 -->
 			<div v-show="!qrloginFlag && !queryCode" class="tmd-login-box">
@@ -229,10 +233,9 @@
 			</div>
 			<!-- 校内账号登录 -->
 			<div class="school-login-box">
-				<div class="school-info" v-if="queryCode">
-					<img :src="querySchoolInfo.picture" alt="" srcset="" width="40px" />
-					<span>{{ querySchoolInfo.name }}</span>
-				</div>
+				<!-- <div class="school-info" v-if="queryCode">
+					{{ $t("login.stuCli") }}
+				</div> -->
 				<p class="teacher-login-title">{{ $t("login.title.schoolLogin") }}</p>
 				<p class="teacher-login-decr">{{ $t("login.subTitle.schoolLogin") }}</p>
 				<Form class="loginForm" ref="studForm" :model="studForm" :rules="studRule" :show-message="false" @keydown.enter.native="loginSubmit('studForm')">
@@ -264,9 +267,9 @@
 					<Checkbox v-model="isRememberForm" style="color: #fff; float: right">{{ $t("login.title.rememberPsw") }}</Checkbox>
 				</Form>
 				<!-- 三方登录 -->
-				<Divider class="login-divider" style="margin-top: 24px">{{ $t("login.communy.title") }}</Divider>
+				<Divider class="login-divider" style="margin-top: 34px">{{ $t("login.communy.title") }}</Divider>
 				<div class="other-login-box" style="margin-top: 0px; display: flex; flex-direction: column; align-items: center">
-					<p style="color: #39d0e4; cursor: pointer" @click="queryCode = null" v-if="queryCode">{{ $t("schoolBaseInfo.goNormalLogin") }}</p>
+					<!-- <p style="color: #39d0e4; cursor: pointer" @click="queryCode = null" v-if="queryCode">{{ $t("schoolBaseInfo.goNormalLogin") }}</p> -->
 					<!-- 教育雲 -->
 					<div class="other-login-item" @click="oauthLogin('educloudtwl')" v-if="srvAdr == 'Global'">
 						<v-icon iconClass="educloudtw" class="icon-educlowudtw"></v-icon>

+ 1 - 1
TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue

@@ -1710,7 +1710,7 @@
 					}
 					this.$api.newCourse.courseManage(params).then((res) => {
 						if(res.courseTasks.length) {
-							this.$Message.success(assistants.length ? this.$t('cusMgt.addCourseMeg4') : this.$t('cusMgt.saveOk'))
+							this.$Message.success(this.$t('cusMgt.saveOk'))
 							this.courseInfo.schedules = this.courseInfo.schedules.map(item => {
 								let infos = res.courseTasks[0].schedules.find(sche => sche.groupId === item.groupId)
 								if(infos) {

+ 95 - 24
TEAMModelOS/ClientApp/src/view/signupActivity/infoComponent/skContent.vue

@@ -34,10 +34,10 @@
                         </div> -->
                     </div>
                     <div style="margin-bottom: 10px;">
-                        <Input placeholder="搜索醍摩豆帐号" style="width: 300px; margin-right: 10px;" />
+                        <Input v-model="tmdID" search @on-search="searchTmd()" placeholder="搜索醍摩豆ID" style="width: 300px; margin-right: 10px;" />
                         <Button type="success" @click="getTeacherList()" v-show="actInfo.joinMode === 'invite' && !isArea">邀请老师</Button>
                     </div>
-                    <Table :columns="applicationColumns" :data="applicationList" stripe row-key="id" height="300">
+                    <Table :columns="applicationColumns" :data="applicationListShow" stripe row-key="id">
                         <template #head="{}">
                             <span> </span>
                         </template>
@@ -62,11 +62,15 @@
                         <template #uploadContestScore="{row}">
                             <span>{{ row.uploadContestScore === -1 ? '-' : row.uploadContestScore }}</span>
                         </template>
-                        <template #action="{row}">
-                            <Button type="success" size="small" style="margin-right: 10px;" @click="getTeaInfo(row)" v-show="row.inviteStatus != -2">查看</Button>
+                        <template #action="{row, index}">
+                            <Button type="info" size="small" style="margin-right: 10px;" @click="getTeaInfo(row)" v-show="row.inviteStatus != -2">查看</Button>
+                            <Button type="success" size="small" style="margin-right: 10px;" @click="manualAssignChange(index)" v-show="row.inviteStatus && row.signContestStatus === 1 && !row.reviewContestAssignCount">分配</Button>
                             <!-- <Button type="error" size="small" @click="deleteApplica(row, index, 'join')">删除</Button> -->
                         </template>
                     </Table>
+                    <div style="text-align: center; margin-top: 10px;">
+                        <Page :current="currentPage" :total="applicationList.length" :page-size="pageSize" :page-size-opts="pageSizeOpts" @on-change="pageChange" @on-page-size-change="pageSizeChange" show-sizer />
+                    </div>
                 </div>
             </div>
             <template v-if="actInfo.scope != 'school' && isArea || actInfo.scope === 'school'">
@@ -95,7 +99,7 @@
                             <Button style="margin-right: 20px;" @click="processShow = true">添加评审专家</Button>
                             <Button @click="allocationWork()">自动分配评审作品</Button>
                             <!-- 根据review reviewStatus为1表示专家可以评审 -->
-                            <Button style="margin-left: 20px;">开始评审</Button>
+                            <Button style="margin-left: 20px;" @click="startReview()">开始评审</Button>
                             <!-- 专家列表中taskCount判断是否已经分配作品 -->
                             <Button style="float: right;" @click="ruleDrawer = true">评审规则</Button>
                         </div>
@@ -210,11 +214,6 @@
         <Modal v-model="processShow" title="邀请评审专家" width="1000" :footer-hide="true">
             <expertImport :actInfo="actInfo" @processList="setProList"></expertImport>
         </Modal>
-        <Modal v-model="awardsShow" title="批量设置奖项">
-            <Select v-model="awardsSel" style="width:200px">
-                <Option v-for="item in awardsList" :value="item.value" :key="item.value">{{ item.label }}</Option>
-            </Select>
-        </Modal>
         <Modal v-model="isAllocation" title="自动分配评审作品" width="1000" :mask-closable="false" :footer-hide="true">
             <Alert type="warning" show-icon>
                 已为专家预分配作品,若无调整,请保存分配结果,作品才会真正分配给专家
@@ -234,6 +233,16 @@
             </Table>
             <Button type="success" long @click="saveAllocationResults()" style="margin-top: 20px;">保存</Button>
         </Modal>
+        <Modal v-model="manualAssign" title="手动分配作品" @on-ok="manualAssignFn()">
+            <RadioGroup v-model="manualAssignId">
+                <Radio v-for="item in processList" :key="item.id" :label="item.id">{{ item.iname }}</Radio>
+            </RadioGroup>
+        </Modal>
+        <Modal v-model="awardsShow" title="批量设置奖项">
+            <Select v-model="awardsSel" style="width:200px">
+                <Option v-for="item in awardsList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+            </Select>
+        </Modal>
         <Modal v-model="addAward" title="新增奖项" @on-ok="addAwardOK()">
             <Input v-model="addAwardWord" placeholder="Enter something..." style="width: 300px" />
         </Modal>
@@ -352,6 +361,7 @@ export default {
                 },
             ],
             applicationList: [],
+            applicationListShow: [],
             processShow: false,
             ruleDrawer: false,
             processColumns: [
@@ -547,20 +557,13 @@ export default {
             alloWorkCloumns: [],
             alloWorkList: [],
             taskKey: null,
-            scoreWord: {
-                only: '按评审分数',
-                avg: '按平均分',
-                top: '按最高分',
-                rmLowAvg: '去掉最低分的平均分',
-                rmTopAvg: '去掉最高分的平均分',
-                rmLowTopAvg: '去掉最高分和最低分的平均分',
-            },
-            distributeWord: {
-                none: '不需要匹配',
-                period: '只匹配学段',
-                subject: '只匹配学科',
-                periodAndSubject: '同时匹配学科和学段',
-            },
+            currentPage: 1,
+            pageSize: 5,
+            pageSizeOpts: [5, 10, 20, 30, 40],
+            tmdID: '',
+            manualAssign: false,
+            manualAssignId: null,
+            proIndex: null,
         }
     },
     computed: {
@@ -591,6 +594,9 @@ export default {
                     this.teacherModal = true
                 }
             })
+        },
+        searchTmd() {
+
         },
         //获取教师学科信息
         getSubjectNames(ids) {
@@ -783,6 +789,15 @@ export default {
                 this.isAllocation = false
             })
         },
+        startReview() {
+            this.$Modal.confirm({
+                title: '开始评审',
+                content: `确认开始评审后,不可删除已邀请的专家,不可调整评审规则,同时专家可以对作品进行评审,是否确认开始评审?`,
+                onOk: () => {
+                    this.$Message.success('已开始评审,未对接口')
+                }
+            })
+        },
         delProInfo(info, index) {
             this.$Modal.confirm({
                 title: '删除专家',
@@ -808,6 +823,7 @@ export default {
                 }
             })
         },
+        // 获取报名老师列表
         actTeaList() {
             let params = {
                 grant_type: 'invited-and-enroll-teachers',
@@ -858,6 +874,8 @@ export default {
                         this.applicationList = lists
                     }
                 }
+            }).finally(() => {
+                this.pageChange(1)
             })
         },
         saveRule(data) {
@@ -867,6 +885,7 @@ export default {
             }
             this.ruleDrawer = false
         },
+        // 查看老师报名信息
         getTeaInfo(data) {
             this.changeLoad(true)
             let params = {
@@ -888,6 +907,58 @@ export default {
                 this.changeLoad(false)
             })
         },
+		// 分页操作
+        pageChange(page) {
+            const startIndex = this.pageSize * (page - 1)
+            const endIndex = this.pageSize * page
+            this.currentPage = page
+            this.applicationListShow = this.applicationList.slice(startIndex, endIndex)
+        },
+        // 页码操作
+        pageSizeChange(val) {
+            this.pageSize = val
+            this.pageChange(1)
+        },
+        manualAssignChange(index) {
+            this.proIndex = index
+            this.manualAssign = true
+        },
+        manualAssignFn(oldId) {
+            if(!oldId && !this.applicationListShow[this.proIndex].uploadContestId) {
+                this.$Message.warning('未上传作品')
+                return
+            }
+            let params = {
+                grant_type: 'allocation-task-manual-save',
+                activityId: this.actInfo.id,
+                uploadId: '',
+                expertId: '',
+                expertIdOld: oldId || '',
+            }
+            if(oldId) {
+                params.uploadId = ''
+                params.expertId = ''
+            } else {
+                params.uploadId = this.applicationListShow[this.proIndex].uploadContestId
+                params.expertId = this.manualAssignId
+            }
+            this.$api.areaActivity.manageAct(params).then(res => {
+                switch (res.code) {
+                    case 2:
+                        this.$Message.warning('评审专家不存在')
+                        break
+                    case 4:
+                        this.$Message.warning('未变更专家')
+                        break
+                    case 200:
+                        this.$Message.success('分配成功')
+                        break
+                    default:
+                        this.$Message.warning('分配失败')
+                        break
+                }
+            })
+        },
 
 
         deleteApplica(data, index, type) {

+ 4 - 5
TEAMModelOS/ClientApp/src/view/student-web/AppNew.vue

@@ -678,11 +678,9 @@ export default {
                         // 没有学校课程,需要添加'基本课程'
                         // 2023.11.10 有未分配的科目也需创建基本课程,里面包含所有未分配的科目
                         if(!adminClass || noCourseSubj.length) {
-                            if(!list.length) {
-                                // 没加入任何课程,仅靠基本课程查看评测等
-                                this.onlySystem = true
-                                this.$store.commit("setOnlySystem", true)
-                            }
+                            // 没加入任何课程,仅靠基本课程查看评测等,为true
+                            this.onlySystem = !list.length ? true : false
+                            this.$store.commit("setOnlySystem", !list.length ? true : false)
                             let admClass = {
                                 id: "",
                                 no: "",
@@ -852,6 +850,7 @@ export default {
             let arr = [];
             for (let i = 0; i <= gradeCount; i++) {
                 for (let j = 0; j < semesterArr.length; j++) {
+                    // 从学生的入学年到现在
                     if(this.userInfo.year <= (oldYear + i)) {
                         // 只展示到当前学期
                         if(Semester.year === (oldYear + i) && Semester.semesterIndex === 1) {

+ 42 - 1
TEAMModelOS/Controllers/Client/HiTAControlller.cs

@@ -128,7 +128,42 @@ namespace TEAMModelOS.Controllers.Client
                 return Ok(new { error = 400, msg = "参数错误" });
             }
         }
+        [ProducesDefaultResponseType]
+        [HttpGet("get-school-knowledge")]
+        public async Task<IActionResult> GetSchoolKnowledge([FromQuery] HiTAJoinSchool join)
+        {
+            return Ok();
+        }
+        [ProducesDefaultResponseType]
+        [HttpGet("get-school-data")]
+        public async Task<IActionResult> GetSchoolData([FromQuery] HiTAJoinSchool join)
+        {
+            IList<IdCodeNameCount> periodSubjects = new List<IdCodeNameCount>(); 
+            School school=  await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(join.school, new PartitionKey("Base"));
+            foreach(var period in school.period) 
+            {
+                foreach (var subject in period.subjects) {
+                    string name = subject.name;
+                    if (school.period.Count>1) {
+                        name=$"{period.name} {subject.name}";    
+                    }
+                    string key =   $"Knowledge:Count:{school.id}-{subject.id}";
+                    int pcount = 0;
+                    var value=  _azureRedis.GetRedisClient(8).HashGet(key,period.id) ;
+                    if (value!=default  && !value.IsNullOrEmpty) {
+                        var json = value.ToString().ToObject<JsonElement>();
+                       
+                        if (json.TryGetProperty("pcount", out JsonElement _pcount)  && int.TryParse($"{_pcount}",out  pcount)) { 
+                            
+                        }
+                    }
+                    periodSubjects.Add(new IdCodeNameCount { id=period.id,code =subject.id,name=name,count = pcount });
+                }
+            }
+            return Ok(new { periodSubjects });
+        }
 
+        
         [ProducesDefaultResponseType]
         [HttpGet("check-login")]
         public async Task<IActionResult> CheckLogin([FromQuery] HiTAJoinSchool join)
@@ -146,7 +181,13 @@ namespace TEAMModelOS.Controllers.Client
                         { "account",id },
                         { "nonce",Guid.NewGuid().ToString()}
                         }, location, _configuration);
-                return Ok(implicit_token);
+                IEnumerable<dynamic> schools= new List<dynamic>();
+                var response =  await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemStreamAsync(id, new PartitionKey("Base"));
+                if (response.Status==200) { 
+                    Teacher teacher= JsonDocument.Parse(response.Content).RootElement.ToObject<Teacher>();
+                     schools= teacher.schools.Where(x=>x.status.Equals("join")).Select(x => new { id = x.schoolId, name = x.name });
+                }
+                return Ok(new { implicit_token ,schools});
             }
             return Ok();
         }

+ 479 - 51
TEAMModelOS/Controllers/Common/ActivityController.cs

@@ -36,6 +36,7 @@ using DocumentFormat.OpenXml.Drawing.Charts;
 using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateApplyForSubjectApplymentRequest.Types;
 using static TEAMModelOS.Controllers.FixDataController;
 using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml.Office2013.Drawing.ChartStyle;
 namespace TEAMModelOS.Controllers
 {
 
@@ -899,6 +900,7 @@ namespace TEAMModelOS.Controllers
                                 TEAMModelOS.SDK.Models.Research research = null;
                                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(activity.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                                 activity.sas=blob_sas;
+                                activity.url=blob_uri;
                                 return Ok(new { code = 200, activity, contest, reviewRule, training, research });
                             }
                             else
@@ -1366,10 +1368,18 @@ namespace TEAMModelOS.Controllers
                                             {
                                                 foreach (var task in item.contestTasks)
                                                 {
-                                                    var teachers = inviteEnrollTeachers.FindAll(z => z.uploadContestId.Equals(task.uploadId));
+                                                    var teachers = inviteEnrollTeachers.FindAll(z => !string.IsNullOrWhiteSpace(z.uploadContestId) && z.uploadContestId.Equals(task.uploadId));
                                                     if (teachers!=null)
                                                     {
-                                                        teachers.ForEach(z => { z.reviewContestAssignCount+=1; z.reviewContestExperts.Add(new IdNameCode { id= item.id, name=item.name, nickname=item.tmdname, picture=item.picture }); });
+                                                        teachers.ForEach(z => { z.reviewContestAssignCount+=1; z.reviewContestExperts.Add(new ExpertUploadScore 
+                                                        {
+                                                            score=task.score,
+                                                            detailScore=task.detailScore,
+                                                            id= item.id,
+                                                            name=item.name,
+                                                            nickname=item.tmdname,
+                                                            picture=item.picture
+                                                        }); });
                                                     }
                                                 }
                                             }
@@ -1757,7 +1767,7 @@ namespace TEAMModelOS.Controllers
                                 {
                                     contest = JsonDocument.Parse(contestResponse.Content).RootElement.ToObject<Contest>();
                                 }
-                                var expertDtos = activityExpert.experts.Select(z => z.ToJsonString().ToObject<ExpertDto>());
+                                List<ExpertDto> expertDtos = activityExpert.experts.Select(z => z.ToJsonString().ToObject<ExpertDto>()).ToList();
                                 long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
                                 //进入评审环节
                                 if (contest.review!= null  && now > contest.review.stime) {
@@ -1769,34 +1779,63 @@ namespace TEAMModelOS.Controllers
                                         {
                                             string taskSql = $"select value c from c where c.id in ({string.Join(",", hasIds.Select(z => $"'{z.id}'"))})";
                                             var taskResults = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(taskSql, $"ActivityExpertTask-{_activityId}");
-                                            foreach (var dto in expertDtos)
-                                            {
-                                                var task = taskResults.list.Find(z => z.id.Equals(dto.id));
-                                                if (task!=null)
+
+                                            foreach (var item in taskResults.list) {
+                                                var dto = expertDtos.Find(z => !string.IsNullOrWhiteSpace(z.id)  &&  z.id.Equals(item.id));
+                                                if (dto!=null  )
                                                 {
-                                                    dto.taskCount =task.contestTasks.Count();
-                                                    dto.teacherCount=task.contestTasks.SelectMany(z => z.members).Count();
-                                                    dto.completeCount=task.contestTasks.Where(z => z.status==1).Count();
-                                                    dto.uploads=  task.contestTasks.Select(z => new IdCodeCount { name = z.name, id=z.uploadId, code=string.Join(",", z.uploadTypes), count=z.count }).ToList();
+                                                    dto.taskCount =item.contestTasks.Count();
+                                                    dto.teacherCount=item.contestTasks.SelectMany(z => z.members).Count();
+                                                    dto.completeCount=item.contestTasks.Where(z => z.status==1).Count();
+                                                    dto.uploads=  item.contestTasks.Select(z => new ContestUploadData { name = z.name, id=z.uploadId, code=string.Join(",", z.uploadTypes), count=z.count,status= z.status,score=z.score, detailScore=z.detailScore }).ToList();
                                                 }
                                             }
                                         }
                                     }
                                 }
-                                
                                 expertTasks.AddRange(expertDtos);
                             }
                             return Ok(new { expertTasks, code = 200 });
                         }
-                    //专家在Protal
-                    case bool when $"{grant_type}".Equals("expert-visible", StringComparison.OrdinalIgnoreCase):
-                        {
-                            break;
-                        }
 
-                    case bool when $"{grant_type}".Equals("analyze-contest", StringComparison.OrdinalIgnoreCase):
+                    case bool when $"{grant_type}".Equals("update-reviewStatus", StringComparison.OrdinalIgnoreCase): 
                         {
-                            break;
+
+                            if (!request.TryGetProperty("activityId", out JsonElement _activityId)) return BadRequest();
+                            if (!request.TryGetProperty("reviewStatus", out JsonElement _reviewStatus)) return BadRequest();
+                            Azure.Response responseContest = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(_activityId.GetString(), new PartitionKey("Contest"));
+                            if (responseContest.Status == 200)
+                            {
+                                long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                                Contest contest = JsonDocument.Parse(responseContest.Content).RootElement.ToObject<Contest>();
+                                if (contest.modules.Contains("review") && contest.review != null)
+                                {
+
+                                    if (now < contest.review.stime || now > contest.review.etime)
+                                    {
+                                        return Ok(new { code = 1, msg = "不在评审时间范围内!" });
+                                    }
+                                }
+                                else
+                                {
+                                    return Ok(new { code = 2, msg = "未配置评审模块!" });
+                                }
+                                if (int.TryParse($"{_reviewStatus}", out int reviewStatus))
+                                {
+                                    contest.review.reviewStatus = reviewStatus;
+                                    await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).UpsertItemAsync(contest, new PartitionKey("Contest"));
+                                    return Ok(new { code = 200, msg = "操作成功!" });
+                                }
+                                else
+                                {
+                                    return Ok(new { code = 4, msg = "评审参数错误!" });
+                                }
+                            }
+                            else {
+                                return Ok(new { code = 3, msg = "活动不存在!" });
+                            }
+                            
+                             
                         }
                     //分配评审作品任务-检查,自动分配
                     case bool when $"{grant_type}".Equals("allocation-task-auto-assign", StringComparison.OrdinalIgnoreCase):
@@ -2033,7 +2072,7 @@ namespace TEAMModelOS.Controllers
                                 if (expertIds != null && expertIds.Count > 0)
                                 {
                                     string taskSQL = $"select value c from c where c.pk='ActivityExpertTask' and c.id in ({string.Join(",", expertIds.Select(z => $"'{z}'"))})";
-                                    List<ExpertContestTaskDto> worksDB = new List<ExpertContestTaskDto>();
+                                  
                                     var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(taskSQL, $"ActivityExpertTask-{_activityId}");
                                     if (result.list.IsNotEmpty())
                                     {
@@ -2041,12 +2080,28 @@ namespace TEAMModelOS.Controllers
                                     }
                                 }
                                 HashSet<ActivityExpertTask> expertTasksChange = new HashSet<ActivityExpertTask>();
+                                Azure.Response responseContest = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(_activityId.GetString(), new PartitionKey("Contest"));
+                                Contest contest = null;
+                                if (responseContest.Status == 200)
+                                {
+                                    long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                                    contest= JsonDocument.Parse(responseContest.Content).RootElement.ToObject<Contest>();
+                                    if (contest.modules.Contains("review") && contest.review != null)
+                                    {
+
+                                        if (now < contest.review.stime || now > contest.review.etime)
+                                        {
+                                            return Ok(new { code = 12, msg = "不在评审时间范围内!" });
+                                        }
+                                    }
+                                }
                                 foreach (var contestTask in contestTasks)
                                 {
                                     ExpertContestTask expertContestTask = contestTask.ToJsonString().ToObject<ExpertContestTask>();
                                     var expertTask = expertTasks.Find(z => z.id.Equals(contestTask.expertId));
                                     if (expertTask != null)
                                     {
+                                       
                                         var task = expertTask.contestTasks.Find(z => z.uploadId.Equals(contestTask.uploadId));
                                         if (task == null)
                                         {
@@ -2062,6 +2117,7 @@ namespace TEAMModelOS.Controllers
                                             id = contestTask.expertId,
                                             code = $"ActivityExpertTask-{_activityId}",
                                             pk = "ActivityExpertTask",
+                                            activityId=_activityId.GetString(),
                                             picture=contestTask.expertPicture,
                                             name=contestTask.expertName,
                                             tmdname=contestTask.expertTmdname,
@@ -2105,7 +2161,9 @@ namespace TEAMModelOS.Controllers
                                         tmdid=z.tmdid,
                                         score=z.score,
                                         status=z.status,
-                                        detailScore=z.detailScore
+                                        detailScore=z.detailScore,
+
+                                        activityId=_activityId.GetString()
                                     }));
                                 }
                                 return Ok(new { code = 200, tasksDb = tasksDb });
@@ -2118,22 +2176,204 @@ namespace TEAMModelOS.Controllers
                             if (!request.TryGetProperty("activityId", out JsonElement _activityId)) return BadRequest();
                             if (!request.TryGetProperty("uploadId", out JsonElement _uploadId)) return BadRequest();
                             if (!request.TryGetProperty("expertId", out JsonElement _expertId)) return BadRequest();
-                         //   if (!request.TryGetProperty("expertId", out JsonElement _expertId)) return BadRequest();
+                            request.TryGetProperty("expertIdOld", out JsonElement _expertIdOld);
                             string sql = $"select value c from c where c.upload.uploadId='{_uploadId}' and c.pk='ActivityEnroll'";
                             var result =  await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityEnroll>(sql, $"ActivityEnroll-{_activityId}");
                             if (result.list.IsNotEmpty())
                             {
+                                ActivityExpertTask expertTask = null;
+
+                                ExpertContestTask contestTask = new ExpertContestTask
+                                {
+                                    uploadId=_uploadId.GetString(),
+
+                                };
+                                string name = string.Empty;
+                                int count = 0;
+                                if (result.list.Count>1)
+                                {
+                                    var leaders = result.list.FindAll(z => z.contest.leader == 1);
+                                    var leader = leaders?.First();
+                                    if (leader!=null)
+                                    {
+                                        name = leader?.contest?.teamName;
+                                        if (string.IsNullOrEmpty(name))
+                                        {
+                                            name = $"{leader?.contest?.enrollInfos?.Find(z => z.code.Equals("name"))?.val}({result.list.Count})";
+                                        }
+                                        if (leader?.upload != null && leader.upload.sokrates.IsNotEmpty())
+                                        {
+                                            count += leader.upload.sokrates.Count;
+                                        }
+                                        if (leader?.upload != null && leader.upload.files.IsNotEmpty())
+                                        {
+                                            count += leader.upload.files.Count;
+                                        }
+                                        List<IdNameCode> members = result.list.Select(z => new IdNameCode { id = z.id, code = z.schoolId, picture = z.tmdPicture, nickname = z.tmdName, name = z.contest?.enrollInfos?.Find(e => e.code.Equals("name")).val }).ToList();
+                                        var period = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("period"));
+                                        var subject = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("subject"));
+                                        contestTask.name= $"{leader?.schoolName}-{name}";
+                                        contestTask.uploadTypes=new List<string> { leader.upload?.type };
+                                        contestTask.count=count;
+                                        contestTask.cipher=leader.contest?.cipher;
+                                        contestTask.type=leader.contest.type;
+                                        contestTask.leader=leader.contest.leader;
+                                        contestTask.members= members;
+                                        contestTask.tmdid=leader.id;
+                                        contestTask.period=period?.val;
+                                        contestTask.subject=subject?.val;
+
+                                    }
+                                    else
+                                    {
+                                        return Ok(new { code = 3, msg = "该队伍没有队长!" });
+                                    }
+                                }
+                                else if (result.list.Count==1)
+                                {
+                                    var leader = result.list[0];
+                                    name = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("name"))?.val;
+                                    if (leader?.upload != null && leader.upload.sokrates.IsNotEmpty())
+                                    {
+                                        count += leader.upload.sokrates.Count;
+                                    }
+                                    if (leader?.upload != null && leader.upload.files.IsNotEmpty())
+                                    {
+                                        count += leader.upload.files.Count;
+                                    }
+                                    var period = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("period"));
+                                    var subject = leader?.contest?.enrollInfos?.Find(z => z.code.Equals("subject"));
+                                    contestTask.name= $"{leader?.schoolName}-{name}";
+                                    contestTask.uploadTypes=new List<string> { leader.upload?.type };
+                                    contestTask.count=count;
+                                    contestTask.type=leader.contest.type;
+                                    contestTask.tmdid=leader.id;
+                                    contestTask.period=period?.val;
+                                    contestTask.subject=subject?.val;
+                                }
+
                                 ActivityExpert activityExpert = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<ActivityExpert>(_activityId.GetString(), new PartitionKey("ActivityExpert"));
                                 Expert expert=  activityExpert.experts.Find(z => !string.IsNullOrWhiteSpace(z.id)  &&   z.id.Equals(_expertId.GetString()));
-                                if (expert!=null) { 
-                                    
-                                }
+                                if (expert!=null) {
+                                    //作品是否有分配过
+                                    string taskSQL = $"select value c from c  join b in c.contestTasks where b.uploadId='{_uploadId}' and c.pk='ActivityExpertTask' " ;
+                                    var resultTask = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(taskSQL, $"ActivityExpertTask-{_activityId}");
+                                    if (resultTask.list.IsNotEmpty())
+                                    {
+                                        if (!string.IsNullOrWhiteSpace($"{_expertIdOld}")) {
+
+                                            if (!expert.id.Equals(_expertIdOld.GetString()))
+                                            {
+                                                //从旧的分配中移除
+                                                var oldTaskExpert = resultTask.list.Find(z => z.id.Equals(_expertIdOld.GetString()));
+                                                if (oldTaskExpert!=null)
+                                                {
+                                                    var changeCount = oldTaskExpert.contestTasks.RemoveAll(z => z.uploadId.Equals(_uploadId.GetString()));
+                                                    if (changeCount>0)
+                                                    {
+                                                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(oldTaskExpert, new PartitionKey(oldTaskExpert.code));
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    return Ok(new { code = 2, msg = "未找到该作品已经分配的专家!" });
+                                                }
+                                            }
+                                            else {
+                                                return Ok(new { code = 4, msg = "作品变更评审专家,调整后的专家不能与已分配的专家相同!" });
+                                            }
+                                        }
+                                        // 除去被调整的专家(oldExpert),(resultTask)可能还有别的专家已分配的,但是不影响该作品继续被分配到新的专家, 可以理解为,作品分配次数+1,
+                                        //作品未被分配的情况、
+                                        string expTaskSQL = $"select value c from c  where c.id='{expert.id}' and c.pk='ActivityExpertTask' ";
+                                        var resultExpTask = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(expTaskSQL, $"ActivityExpertTask-{_activityId}");
+                                      
+                                        if (resultExpTask.list.IsNotEmpty())
+                                        {
+                                            var task = resultExpTask.list[0].contestTasks.Find(z => z.uploadId.Equals(_uploadId.GetString()));
+                                            if (task!=null)
+                                            {
+                                                task=contestTask;
+                                            }
+                                            else
+                                            {
+                                                resultExpTask.list[0].contestTasks.Add(contestTask);
+                                            }
+                                            expertTask=resultExpTask.list[0];
+                                            expertTask.activityId=_activityId.GetString();
+                                        }
+                                        else
+                                        {
+                                            //专家没有任何被分配的作品
+                                             expertTask = new ActivityExpertTask()
+                                            {
+                                                id= expert.id,
+                                                code=$"ActivityExpertTask-{_activityId}",
+                                                pk="ActivityExpertTask",
+                                                ttl=-1,
+                                                activityId=_activityId.GetString(),
+                                                name=expert.iname,
+                                                tmdname=expert.name,
+                                                picture=expert.picture,
+                                                contestTasks= new List<ExpertContestTask> { contestTask }
+                                            };
+                                        }
+                                        if (expertTask!=null) {
+                                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(expertTask, new PartitionKey(expertTask.code));
+                                        }
+                                    }
+                                    else {
+                                        //旧专家,和作品没有匹配的情况,未分配过,不能调整。
+                                        if (!string.IsNullOrWhiteSpace($"{_expertIdOld}"))
+                                        {
+                                            return Ok(new { code = 2, msg = "未找到该作品已经分配的专家!" });
+                                        }
+                                       
+                                        //作品未被分配的情况、
+                                        string expTaskSQL = $"select value c from c  where c.id='{expert.id}' and c.pk='ActivityExpertTask' ";
+                                        var resultExpTask = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(expTaskSQL, $"ActivityExpertTask-{_activityId}");
+                                      
+                                        if (resultExpTask.list.IsNotEmpty())
+                                        {
+                                            var task = resultExpTask.list[0].contestTasks.Find(z => z.uploadId.Equals(_uploadId.GetString()));
+                                            if (task!=null)
+                                            {
+                                                task=contestTask;
+                                            }
+                                            else {
+                                                resultExpTask.list[0].contestTasks.Add(contestTask);
+                                            }
+                                            expertTask=resultExpTask.list[0];
+                                            expertTask.activityId=_activityId.GetString();
+                                        }
+                                        else {
+                                            //专家没有任何被分配的作品
 
+                                            expertTask = new ActivityExpertTask() 
+                                            {
+                                                id= expert.id,
+                                                code=$"ActivityExpertTask-{_activityId}",
+                                                pk="ActivityExpertTask",
+                                                ttl=-1,
+                                                activityId=_activityId.GetString(),
+                                                name=expert.iname,
+                                                tmdname=expert.name,
+                                                picture=expert.picture,
+                                                contestTasks= new List<ExpertContestTask> { contestTask }
+                                            };
+                                        }
+                                        if (expertTask!=null)
+                                        {
+                                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(expertTask, new PartitionKey(expertTask.code));
+                                        }
+                                    }   
+                                }
+                                return Ok(new { code = 200, expertTask });
                             }
                             else {
                                 return Ok(new { code=1,msg ="作品不存在!"});
                             }
-                            break;
+                          
                         }
                 }
             }
@@ -2303,7 +2543,10 @@ namespace TEAMModelOS.Controllers
                     {
                         cnt="02944f32-f534-3397-ea56-e6f1fc6c3714";
                     }
-                    z.sas= _azureStorage.GetBlobContainerSAS(cnt, BlobContainerSasPermissions.Read).sas;
+                    var it = _azureStorage.GetBlobContainerSAS(cnt, BlobContainerSasPermissions.Read);
+                    z.sas= it.sas;
+                    z.url=it.uri;
+
                 });
                 string cnt = website.id;
                 if (website.id.Equals("teammodel"))
@@ -2312,6 +2555,7 @@ namespace TEAMModelOS.Controllers
                 }
                 var blob = _azureStorage.GetBlobContainerSAS(cnt, BlobContainerSasPermissions.Read);
                 website.sas= blob.sas;
+                website.url=blob.uri;
                 string blobUrl = blob.uri;
                 return Ok(new { code = 200, website, websites, blobUrl });
             }
@@ -2371,6 +2615,7 @@ namespace TEAMModelOS.Controllers
                 TEAMModelOS.SDK.Models.Research research = null;
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(activity.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                 activity.sas=blob_sas;
+                activity.url=blob_uri;
                 return Ok(new { code = 200, activity, contest, reviewRule, training, research });
             }
             else
@@ -2421,7 +2666,10 @@ namespace TEAMModelOS.Controllers
                     {
                         cnt="02944f32-f534-3397-ea56-e6f1fc6c3714";
                     }
-                    website.sas= _azureStorage.GetBlobContainerSAS(cnt, BlobContainerSasPermissions.Read).sas;
+                    var blob = _azureStorage.GetBlobContainerSAS(cnt, BlobContainerSasPermissions.Read);
+                    website.sas= blob.sas;
+                    website.url=blob.uri;
+
                     return Ok(new { code = 200, website });
                 }
                 else
@@ -2451,40 +2699,218 @@ namespace TEAMModelOS.Controllers
         {
             (string tmdid, string name, string picture, _) = HttpContext.GetAuthTokenInfo();
             if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
-            if (!request.TryGetProperty("activityId", out JsonElement _activityId)) return BadRequest();
+
             var client = _azureCosmos.GetCosmosClient();
-            Azure.Response response = await client.GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(_activityId.GetString(), new PartitionKey("Activity"));
-            if (response.Status==200)
-            {
-                Activity activity = JsonDocument.Parse(response.Content).RootElement.ToObject<Activity>();
-                if (activity.publish==1)
-                {
-                    switch (true)
+
+            switch (true)
+            { //获取分配的任务
+                case bool when $"{grant_type}".Equals("get-enroll-by-uploadId", StringComparison.OrdinalIgnoreCase):
+                    {
+                        if (!request.TryGetProperty("activityId", out JsonElement _activityId)) return BadRequest();
+                        if (!request.TryGetProperty("uploadId", out JsonElement _uploadId)) return BadRequest();
+                        string enrollSQL = $"select value c from c where c.activityId='{_activityId.GetString()}' and c.upload.uploadId='{_uploadId}' ";
+                        //不是自己的,且学校不为空,则查询指定学校的,否则获取所有报名的数据
+                        var enrollResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityEnroll>(enrollSQL, $"ActivityEnroll-{_activityId}");
+                        EnrollUpload upload = null; 
+                        if (enrollResult.list.IsNotEmpty()) {
+                            upload= enrollResult.list[0].upload;
+                        }
+                        return Ok(new { upload });
+                    }
+                //获取分配的任务
+                case bool when $"{grant_type}".Equals("list-task", StringComparison.OrdinalIgnoreCase):
                     {
-                        //获取分配的任务
-                        case bool when $"{grant_type}".Equals("list-task", StringComparison.OrdinalIgnoreCase):
+                        List<ActivityExpertDto> activities = new List<ActivityExpertDto>();
+                        long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                        //在时间内正在进入评审阶段的活动。
+                        string contestSQL = $"select value c from c where c.review.stime<={now} and c.review.etime>={now} and c.review.reviewStatus=1";
+                        var contestResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Contest>(contestSQL, "Contest");
+                        if (contestResult.list.IsNotEmpty()) 
+                        {
+                            string baseSQL = $"select value c from c where c.id in ({string.Join(",", contestResult.list.Select(z => $"'{z.id}'"))}) ";
+                            var activityResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Activity>(baseSQL, "Activity");
+                            string sql = $"select value c  from c where  c.activityId in ({string.Join(",", contestResult.list.Select(z => $"'{z.id}'"))})  and  c.id='{tmdid}' and  c.pk='ActivityExpertTask'";
+                            var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(sql);
+                            foreach (var item in result.list)
                             {
+                                var contest =  contestResult.list.Find(z => z.id.Equals(item.activityId));
+                                var activity = activityResult.list.Find(z => z.id.Equals(item.activityId));
+                                var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(activity.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
 
-                                break;
+                                activities.Add(new ActivityExpertDto
+                                {
+                                    activityId=item.activityId,
+                                    activityName=activity?.name,
+                                    stime=contest?.review?.stime??0,
+                                    etime=contest?.review?.etime??0,
+                                    taskCount=item.contestTasks.Count(),
+                                    completeCount=item.contestTasks.Where(z => z.status==1).Count(),
+                                    contestTasks=item.contestTasks,
+                                    sas=blob_sas,
+                                    url=blob_uri
+                                }) ;
                             }
-                        ///评分
-                        case bool when $"{grant_type}".Equals("decide-score", StringComparison.OrdinalIgnoreCase):
+                        }
+                        return Ok(new { activities,code=200 });
+                    }
+                ///评分
+                case bool when $"{grant_type}".Equals("decide-score", StringComparison.OrdinalIgnoreCase):
+                    {
+                        if (!request.TryGetProperty("activityId", out JsonElement _activityId)) return BadRequest();
+                        if (!request.TryGetProperty("scoreData", out JsonElement _scoreData)) return BadRequest();
+                        Azure.Response response = await client.GetContainer(Constant.TEAMModelOS, Constant.Common).ReadItemStreamAsync(_activityId.GetString(), new PartitionKey("Contest"));
+                        if (response.Status==200)
+                        {
+                            long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
+                            Contest contest = JsonDocument.Parse(response.Content).RootElement.ToObject<Contest>();
+                            if (contest.review!= null   &&contest.review.stime<now &&contest.review.etime>now)
                             {
-
-                                break;
+                                if (contest.review.reviewStatus==1)
+                                {
+                                    //作品安分配次数,如果分数全部打完成,自动汇算 
+                                    ReviewScoreData scoreData=  _scoreData.ToObject<ReviewScoreData>();
+                                    var ruleResponse=  await client.GetContainer(Constant.TEAMModelOS, Constant.Normal).ReadItemStreamAsync(_activityId.GetString(), new PartitionKey("ReviewRule-disposable"));
+                                    ReviewRule reviewRule = JsonDocument.Parse(ruleResponse.Content).RootElement.ToObject<ReviewRule>();
+                                    if (reviewRule.scoreDetail==1) {
+                                        if (!scoreData.detailScore.IsNotEmpty()) 
+                                        {
+                                            return Ok(new { code = 5, msg = "需要进行细项评分!" });
+                                        }
+                                    }
+                                    if (scoreData.score<0) {
+                                        return Ok(new { code = 6, msg = "分数不能小于0!" });
+                                    }
+                                    if (!string.IsNullOrWhiteSpace(scoreData.uploadId))
+                                    {
+                                        ActivityExpertTask expertTask = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<ActivityExpertTask>(tmdid, new PartitionKey($"ActivityExpertTask-{_activityId}"));
+                                        var task = expertTask.contestTasks.Find(x => x.uploadId.Equals(scoreData.uploadId));
+                                        task.score = scoreData.score;
+                                        task.status=1;
+                                        task.detailScore = ActivityService.TreeToList(scoreData.detailScore, new List<RuleConfig>()) ;
+                                        await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(expertTask, new PartitionKey($"ActivityExpertTask-{_activityId}"));
+                                        //检查作品是否完成评审自动结算
+                                        {
+                                            string sql = $"select distinct  value  c  from c join b in c.contestTasks  where c.activityId='{_activityId}' and b.uploadId='{scoreData.uploadId}'";
+                                            var uploadAllResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityExpertTask>(sql, $"ActivityExpertTask-{_activityId}");
+                                            if (uploadAllResult.list.IsNotEmpty()) 
+                                            {
+                                                var unfinish = uploadAllResult.list.SelectMany(x=>x.contestTasks).Where(z => z.status==0  && z.uploadId.Equals(scoreData.uploadId));
+                                                if (!(unfinish!=null  && unfinish.Count()>0)) {
+                                                    //没有未完成的评审作品自动结算、
+                                                    string enrollSQL =$"select value c from c where c.upload.uploadId='{scoreData.uploadId}'and c.pk ='ActivityEnroll' ";
+                                                    var enrollResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).GetList<ActivityEnroll>(enrollSQL, $"ActivityEnroll-{_activityId}");
+                                                    foreach (var item in enrollResult.list) 
+                                                    {
+                                                        bool change = false;
+                                                        List<ExpertUploadScore> expertScores= new List<ExpertUploadScore>();
+                                                        foreach (var expertScore  in uploadAllResult.list)
+                                                        {
+                                                            var taskScore = expertScore.contestTasks.Find(z => z.uploadId.Equals(item.upload.uploadId));
+                                                            if (taskScore!= null) {
+                                                                expertScores.Add(new ExpertUploadScore {
+                                                                    id= expertScore.id,
+                                                                    name=expertScore.name,
+                                                                    score=taskScore.score,
+                                                                    detailScore=taskScore.detailScore
+                                                                });
+                                                            }
+                                                        }
+                                                        switch (reviewRule.scoreRule) 
+                                                        {
+                                                            case "only":
+                                                                if (expertScores.IsNotEmpty() && expertScores.Count==1) 
+                                                                { 
+                                                                    item.upload.score= expertScores.First().score;
+                                                                    change=true;
+                                                                }
+                                                                break;
+                                                            case "avg":
+                                                                if (expertScores.IsNotEmpty()  && expertScores.Count>=2)
+                                                                {
+                                                                    item.upload.score= expertScores.Average(z => z.score); 
+                                                                    change=true;
+                                                                }
+                                                                break;
+                                                            case "top":
+                                                                if (expertScores.IsNotEmpty() && expertScores.Count>2) {
+                                                                    item.upload.score= expertScores.Max(z => z.score);
+                                                                    change=true;
+                                                                }
+                                                                break;
+                                                            case "rmLowAvg":
+                                                                if (expertScores.IsNotEmpty() && expertScores.Count>=3) 
+                                                                {
+                                                                    expertScores.Remove(expertScores.Min());
+                                                                    if (expertScores.IsNotEmpty()) {
+                                                                        item.upload.score= expertScores.Average(z => z.score);
+                                                                        change=true;
+                                                                    }
+                                                                }
+                                                                break;
+                                                            case "rmTopAvg":
+                                                                if (expertScores.IsNotEmpty() && expertScores.Count>=3)
+                                                                {
+                                                                    expertScores.Remove(expertScores.Max());
+                                                                    if (expertScores.IsNotEmpty())
+                                                                    {
+                                                                        item.upload.score= expertScores.Average(z => z.score);
+                                                                        change=true;
+                                                                    }
+                                                                }
+                                                                break;
+                                                            case "rmLowTopAvg":
+                                                                if (expertScores.IsNotEmpty() && expertScores.Count>=4)
+                                                                {
+                                                                    expertScores.Remove(expertScores.Max());
+                                                                    expertScores.Remove(expertScores.Min());
+                                                                    if (expertScores.IsNotEmpty())
+                                                                    {
+                                                                        item.upload.score= expertScores.Average(z => z.score);
+                                                                        change=true;
+                                                                    }
+                                                                }
+                                                                break;
+                                                        }
+                                                        if (change)
+                                                        {
+                                                            await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).UpsertItemAsync(item, new PartitionKey($"ActivityEnroll-{_activityId}"));
+                                                        }
+                                                      
+                                                    }
+                                                }
+                                            }
+                                        }
+                                        return Ok(new { code = 200, completeCount = expertTask.contestTasks.Where(z => z.status==1).Count(), contestTasks = expertTask.contestTasks });
+                                    }
+                                    else
+                                    {
+                                        return Ok(new { code = 4, msg = "参数错误!" });
+                                    }
+                                }
+                                else
+                                {
+                                    return Ok(new { code = 2, msg = "评审已关闭!" });
+                                }
                             }
+                            else
+                            {
+                                return Ok(new { code = 1, msg = "已过评审时间!" });
+                            }
+                        }
+                        else {
+                            return Ok(new { code = 3, msg = "活动不存在!" });
+                        }
                     }
-                }
             }
             return Ok();
         }
 
-        /// <summary>
-        /// 教师在赛课模块的操作
-        /// </summary>
-        /// <param name="request"></param>
-        /// <returns></returns>
-        [ProducesDefaultResponseType]
+            /// <summary>
+            /// 教师在赛课模块的操作
+            /// </summary>
+            /// <param name="request"></param>
+            /// <returns></returns>
+            [ProducesDefaultResponseType]
         [HttpPost("teacher-contest")]
         [AuthToken(Roles = "teacher")]
 #if !DEBUG
@@ -2526,8 +2952,9 @@ namespace TEAMModelOS.Controllers
                         {
                             if (contest.review!=null)
                             {
-                                if (now>= contest.review?.stime)
+                                if (now>= contest.review?.stime  &&  !$"{grant_type}".Equals("get-enroll", StringComparison.OrdinalIgnoreCase))
                                 {
+                                    //只能查看报名信息
                                     return Ok(new { code = 35, msg = "已到截至日期,不能操作!" });
                                 }
                             }
@@ -3418,6 +3845,7 @@ namespace TEAMModelOS.Controllers
             {
                 var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read);
                 z.sas=blob_sas;
+                z.url=blob_uri;
             });
             return Ok(new { activities, website });
         }

+ 3 - 2
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -4214,7 +4214,7 @@ namespace TEAMModelOS.Controllers
             if (!request.TryGetProperty("errorItems", out JsonElement items)) return BadRequest();
             List<errorItemInfo> errors = items.ToObject<List<errorItemInfo>>();
             var client = _azureCosmos.GetCosmosClient();
-            List<string> ids = errors.Select(c => c.activityId).ToList();
+            List<string> ids = errors.Select(c => c.activityId).Distinct().ToList();
             var queryClass = $"select value(c) from c where c.id in ({string.Join(",", ids.Select(o => $"'{o}'"))}) and c.pk = 'Exam'";
             List<ExamInfo> exams = new();
             await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamInfo>(queryText: queryClass))
@@ -4225,7 +4225,8 @@ namespace TEAMModelOS.Controllers
             if (exams.Count > 0)
             {
                 foreach (errorItemInfo itemInfo in errors) {
-                    ExamInfo info = exams.Where(c => c.id.Equals(itemInfo.activityId)).FirstOrDefault();                   
+                    ExamInfo info = exams.Where(c => c.id.Equals(itemInfo.activityId)).FirstOrDefault(); 
+                    if(info==null) continue; //[Jeff]無法取得評量紀錄報錯bug修正
                     List<ExamSubject> subjects = info.subjects;
                     int index = 0;
                     foreach (ExamSubject subject in subjects)

+ 31 - 4
TEAMModelOS/Controllers/School/ElegantController.cs

@@ -14,6 +14,7 @@ using System.Threading.Tasks;
 using Azure;
 using Azure.Cosmos;
 using Azure.Storage.Sas;
+using DocumentFormat.OpenXml.Drawing.Charts;
 using HTEXLib.COMM.Helpers;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Cryptography.KeyDerivation;
@@ -68,6 +69,8 @@ namespace TEAMModelOS.Controllers
 #endif
         public async Task<IActionResult> Statistics(JsonElement  json)
         {
+            json.TryGetProperty("periodId", out JsonElement _periodId);
+            json.TryGetProperty("periodType", out JsonElement _periodType);
             if (!json.TryGetProperty("scope", out JsonElement _scope))
             {
                 return BadRequest();
@@ -76,16 +79,26 @@ namespace TEAMModelOS.Controllers
             {
                 return BadRequest();
             }
-            List<IdNameCode> schools= new List<IdNameCode>();
+            List<School> schools= new List<School>();
             List<Elegant> elegants = new List<Elegant>();
+            IEnumerable<string> periodIds = new List<string>();
             if ($"{_scope}".Equals("area"))
             {
-                string sql = $"select c.name ,c.picture, c.id  from c where c.areaId ='{_code}'";
-                var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<IdNameCode>(sql, "Base");
+                string sql = $"select value c  from c where c.areaId ='{_code}'";
+                var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<School>(sql, "Base");
                 if (result.list.IsNotEmpty())
                 {
+                    string sqlPeriod = string.Empty;
+                    if (!string.IsNullOrWhiteSpace($"{_periodType}")) {
+                        periodIds = result.list.SelectMany(x => x.period).Where(z => !string.IsNullOrWhiteSpace(z.periodType)  && z.periodType.Equals($"{_periodType}")).Select(x => x.id);
+                        if (periodIds!=null && periodIds.Count()>0)
+                        {
+                            sqlPeriod=$" and c.periodId in ({string.Join(",",periodIds.Select(x=>$"'{x}'"))})";
+                        }
+                    }
+                   
                     schools.AddRange(result.list);
-                    string sqlE = $"select value c from c where c.school in ({string.Join(",", result.list.Select(z => $"'{z.id}'"))}) and c.pk='Elegant' and contains(c.code,'Elegant-')";
+                    string sqlE = $"select value c from c where c.school in ({string.Join(",", result.list.Select(z => $"'{z.id}'"))}) {sqlPeriod} and c.pk='Elegant' and contains(c.code,'Elegant-')";
                     var resultE = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<Elegant>(sqlE);
                     if (resultE.list.IsNotEmpty())
                     {
@@ -96,6 +109,9 @@ namespace TEAMModelOS.Controllers
             else if ($"{_scope}".Equals("school"))
             {
                 string sqlE = $"select value c from c ";
+                if (!string.IsNullOrWhiteSpace($"{_periodId}")) {
+                    sqlE=$"{sqlE}  where c.periodId='{_periodId}'";
+                }
                 var resultE = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<Elegant>(sqlE,$"Elegant-{_code}");
                 if (resultE.list.IsNotEmpty())
                 {
@@ -105,6 +121,17 @@ namespace TEAMModelOS.Controllers
             List<ClassifiedItemSchool > schoolDatas= new List<ClassifiedItemSchool>();
             if (schools.IsNotEmpty()) {
                 foreach (var school in schools) {
+                    if (periodIds.Count()>0) {
+                        bool has = false;
+                        foreach (var period in school.period) {
+                            if (periodIds.Contains(period.id)) {
+                                has=true;
+                            }
+                        }
+                        if (!has) {
+                            continue;
+                        }
+                    }
                     var esSchool = elegants.FindAll(z => z.school.Equals(school.id));
                     List<ClassifiedItem> itemschool = ClassifyHierarchy(esSchool);
                     if (!itemschool.Select(z => z.id).Contains("德育风采"))

+ 29 - 6
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -32,6 +32,7 @@ using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 using TEAMModelOS.SDK.Models.Cosmos.School;
 using TEAMModelOS.SDK.Models.Service.BI;
+using static TEAMModelOS.SDK.Models.Teacher;
 
 namespace TEAMModelOS.Controllers
 {
@@ -2243,11 +2244,32 @@ namespace TEAMModelOS.Controllers
         [ProducesDefaultResponseType]
         [HttpPost("get-area-iot")]
         [Authorize(Roles = "IES")]
-        [AuthToken(Roles = "admin")]
+        [AuthToken(Roles = "admin,teacher")]
         public async Task<IActionResult> getAreaIotData(JsonElement request)
         {
             try
             {
+                //回傳值定義
+                IotStatisticsArea areaIot = new IotStatisticsArea(); //學區IOT統計結果
+                List<IotStatisticsSch> schoolIotResult = new List<IotStatisticsSch>(); //學校IOT統計結果
+                List<ProdAnalysisApiResult> iotData = new List<ProdAnalysisApiResult>(); //IOT資料
+                string err = string.Empty;
+                //取得ID
+                var (tmid, name, _, _school) = HttpContext.GetAuthTokenInfo();
+                if(string.IsNullOrWhiteSpace(tmid)) return BadRequest();
+                Teacher tmidInfo = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Teacher).ReadItemAsync<Teacher>(tmid, new PartitionKey("Base"));
+                //區管理者權限驗證 (有給areaId則驗)
+                string areaId = (request.TryGetProperty("areaId", out JsonElement _areaId)) ? _areaId.GetString() : string.Empty;
+                if(!string.IsNullOrWhiteSpace(areaId))
+                {
+                    TeacherArea hasAreaAdmin = tmidInfo.areas.Where(a => a.areaId.Equals(areaId)).FirstOrDefault();
+                    if(hasAreaAdmin == null || !hasAreaAdmin.status.Equals("join"))
+                    {
+                        err = "Permission denied.";
+                        return Ok(new { err, area = areaIot, school = schoolIotResult, iotData });
+                    }
+                }
+                //學校資料取得
                 if (!request.TryGetProperty("schoolIds", out JsonElement _schoolIds)) return BadRequest();
                 List<string> schoolIds = _schoolIds.ToObject<List<string>>();
                 List<string> periodIds = (request.TryGetProperty("periodIds", out JsonElement _periodIds)) ? _periodIds.ToObject<List<string>>() : new List<string>();
@@ -2279,11 +2301,12 @@ namespace TEAMModelOS.Controllers
                         }
                     }
                 }
-                if (schools.Count.Equals(0)) return BadRequest();
+                if (schools.Count.Equals(0))
+                {
+                    return Ok(new { err, area = areaIot, school = schoolIotResult, iotData });
+                }
                 //取得各校IOT相關統計值
-                IotStatisticsArea areaIot = new IotStatisticsArea(); //學區IOT統計項
                 Dictionary<string, IotStatisticsSch> schIot = new Dictionary<string, IotStatisticsSch>(); //各校IOT統計項
-                List<ProdAnalysisApiResult> iotData = new List<ProdAnalysisApiResult>(); //IOT資料
                 List<string> serialPermitList = new List<string>() { "J223IZ6M", "3222C6D2", "J223IZAM", "J2236ZCX", "3222DNG2", "3222IAVN", "BYJ6LZ6Z" };
                 string serialPermitJsonStr = JsonConvert.SerializeObject(serialPermitList);
                 foreach (School school in schools)
@@ -2429,7 +2452,7 @@ namespace TEAMModelOS.Controllers
                 }
 
                 //輸出整形
-                List<IotStatisticsSch> schoolIotResult = new List<IotStatisticsSch>();
+                
                 foreach (KeyValuePair<string, IotStatisticsSch> schIotItem in schIot)
                 {
                     IotStatisticsSch schIotData = schIotItem.Value;
@@ -2461,7 +2484,7 @@ namespace TEAMModelOS.Controllers
                     areaIot.lTypeDif += schIotData.lTypeDif;
                 }
 
-                return Ok(new { area = areaIot, school = schoolIotResult, iotData });
+                return Ok(new { err, area = areaIot, school = schoolIotResult, iotData });
             }
             catch (Exception ex)
             {

+ 1 - 1
TEAMModelOS/Controllers/Student/StudentController.cs

@@ -1497,7 +1497,7 @@ namespace TEAMModelOS.Controllers
         //學生登入後根據學校規模取得授權數
         private async Task<int> GetStudentAuthNumByScale(string school_code, School school)
         {
-            if ((school.areaId.Equals("7a51072f-b329-4e74-99e0-ba0407ba8926") || school.areaId.Equals("69e3d413-50a1-4f5e-844a-e0f7c9622ea3"))  &&  DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()<1706630400000) {
+            if (!string.IsNullOrWhiteSpace(school.areaId) && (school.areaId.Equals("7a51072f-b329-4e74-99e0-ba0407ba8926") || school.areaId.Equals("69e3d413-50a1-4f5e-844a-e0f7c9622ea3"))  &&  DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()<1706630400000) {
                 return school.scale-5;
             }
             //授权规模数量

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 172 - 8
TEAMModelOS/Controllers/XTest/FixDataController.cs


+ 3 - 0
TEAMModelOS/Controllers/XTest/FixLessonRecordController.cs

@@ -40,6 +40,7 @@ using DocumentFormat.OpenXml.Bibliography;
 using System.Formats.Asn1;
 using Microsoft.Azure.SignalR.Protocol;
 using System.Collections;
+using System.Text.Json.Nodes;
 
 namespace TEAMModelOS.Controllers.XTest
 {
@@ -78,6 +79,8 @@ namespace TEAMModelOS.Controllers.XTest
         [HttpPost("fix-overall-education")]
         public async Task<IActionResult> FixOverallEducation(JsonElement json)
         {
+
+           
             var client = _azureCosmos.GetCosmosClient();
             string sql = " SELECT distinct value(c)  FROM c  where c.pk='OverallEducation' and contains(c.code,'OverallEducation-ydzt-') ";
             List<OverallEducation> overallEducations = new List<OverallEducation>();

+ 23 - 2
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -12,9 +12,12 @@ using DocumentFormat.OpenXml.Drawing.Wordprocessing;
 using DocumentFormat.OpenXml.Office2010.Excel;
 using DocumentFormat.OpenXml.Office2016.Excel;
 using DocumentFormat.OpenXml.Presentation;
+using DocumentFormat.OpenXml.Spreadsheet;
 using DocumentFormat.OpenXml.Wordprocessing;
+using FastJSON;
 using HTEXLib.COMM.Helpers;
 using HTEXLib.Helpers.ShapeHelpers;
+using Json.Path;
 using MathNet.Numerics.Distributions;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
@@ -38,6 +41,7 @@ using System.Runtime.Intrinsics.X86;
 using System.Security.Policy;
 using System.Text;
 using System.Text.Json;
+using System.Text.Json.Nodes;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using System.Web;
@@ -45,11 +49,13 @@ using TEAMModelOS.Controllers.Analysis;
 using TEAMModelOS.Controllers.Core;
 using TEAMModelOS.Controllers.Third.LePei;
 using TEAMModelOS.Filter;
+using TEAMModelOS.Helper.Common.FileHelper;
 using TEAMModelOS.Models;
 using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Helper.Common.DateTimeHelper;
+using TEAMModelOS.SDK.Helper.Common.JsonHelper.JsonPath;
 using TEAMModelOS.SDK.Models;
 using TEAMModelOS.SDK.Models.Cosmos.Common;
 using TEAMModelOS.SDK.Models.Cosmos.OpenEntity;
@@ -99,6 +105,10 @@ namespace TEAMModelOS.Controllers
             _httpTrigger = httpTrigger;
             _azureService=azureService;
         }
+
+
+
+
         /// <summary>
         /// 移除已经废弃的StuCourse 数据
         /// </summary>
@@ -107,10 +117,21 @@ namespace TEAMModelOS.Controllers
         /// <returns></returns>
         [HttpPost("remove-stucourse")]
         [RequestSizeLimit(102_400_000_00)] //最大10000m左右
-        public async Task<IActionResult> RemoveStuCourse([FromForm] IFormFile[] file, [FromForm] string periodId)
+        public async Task<IActionResult> RemoveStuCourse(JsonElement json)
         {
 
-            await BIStats.SetTypeAddStats(_azureCosmos.GetCosmosClient(), _dingDing, "zjaz", "Exam", 1, 0, 0, 1703663934180);
+            JsonNode jsonNode = JsonObject.Parse(json.ToString());
+            var path= JsonPath.Parse("$.groupLists[*].groupList.members[*]");
+            var d = path.Evaluate(jsonNode);
+            JsonPathContext context = new JsonPathContext
+            { ValueSystem = new JsonApiValueSystem() };
+            //解析试卷作答详情
+            var datas = context.SelectNodes(json,
+            "$.groupLists[*].groupList.members[*]").Select(node => node.Value).ToList();
+        
+
+            return Ok(datas);
+
 
             //            var schoolResult = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).GetList<string>("select value c.id from c ", "Base");
             //            if (schoolResult.list.IsNotEmpty()) 

+ 5 - 4
TEAMModelOS/TEAMModelOS.csproj

@@ -7,6 +7,7 @@
     <PackageReference Include="DotNetZip" Version="1.16.0" />
 	<PackageReference Include="DinkToPdf" Version="1.0.8" />
 	<PackageReference Include="EPPlus" Version="6.2.6" />
+	<PackageReference Include="JsonPath.Net" Version="0.7.1" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
 	<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="2.20.0" />
 	<PackageReference Include="System.Security.Cryptography.Algorithms" Version="4.3.1" />
@@ -74,11 +75,11 @@
     <SpaRoot>ClientApp\</SpaRoot>
     <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
     <UserSecretsId>078b5d89-7d90-4f6a-88fc-7d96025990a8</UserSecretsId>
-    <Version>5.2401.3</Version>
-    <AssemblyVersion>5.2401.3.1</AssemblyVersion>
-    <FileVersion>5.2401.3.1</FileVersion>
+    <Version>5.2401.10</Version>
+    <AssemblyVersion>5.2401.10.1</AssemblyVersion>
+    <FileVersion>5.2401.10.1</FileVersion>
     <Description>TEAMModelOS(IES5)</Description>
-    <PackageReleaseNotes>IES版本说明版本切换标记5.2401.3.1</PackageReleaseNotes>
+    <PackageReleaseNotes>IES版本说明版本切换标记5.2401.10.1</PackageReleaseNotes>
     <PackageId>TEAMModelOS</PackageId>
     <Authors>teammodel</Authors>
     <Company>醍摩豆(成都)信息技术有限公司</Company>

+ 1 - 1
TEAMModelOS/appsettings.Development.json

@@ -18,7 +18,7 @@
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction-test.chinacloudsites.cn/api/",
     //"HttpTrigger": "http://localhost:7071/api/"
-    "Version": "5.2401.3.1"
+    "Version": "5.2401.10.1"
   },
   "Azure": {
     // 测试站数据库

+ 1 - 1
TEAMModelOS/appsettings.json

@@ -18,7 +18,7 @@
     "Exp": 86400,
     "IdTokenSalt": "8263692E2213497BB55E74792B7900B4",
     "HttpTrigger": "https://teammodelosfunction.chinacloudsites.cn/api/",
-    "Version": "5.2401.3.1"
+    "Version": "5.2401.10.1"
   },
   "Azure": {
     "Storage": {