Selaa lähdekoodia

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

liqk 3 vuotta sitten
vanhempi
commit
ef6323585d

+ 0 - 8
TEAMModelOS.SDK/Helper/Common/ReflectorExtensions/ReflectorExtensions.cs

@@ -53,14 +53,6 @@ namespace TEAMModelOS.SDK.Helper.Common.ReflectorExtensions
                 foreach (var model in ScanModel)
                 {
                     Assembly assembly = Assembly.LoadFrom(currentDirectory + "\\" + model + ".dll");
-                    var TypeInModelS = assembly.GetTypes().SelectMany(x => x.GetMethods()).GroupBy(z=>z.Name).ToList();
-                    TypeInModelS.ForEach(x => {
-                        if (x.Key.Equals("GetTeacherInfo"))
-                        {
-                            var at = x.ToList().SelectMany(z => z.GetCustomAttributes()).Where(m=>m.GetType().Equals(attr));
-                            string ke = x.Key;
-                        }
-                    });
                     var  TypeInModel = assembly.GetTypes().Select(x => x.GetMethods()).SelectMany(y => y).Select(z=>z.GetCustomAttribute(attr,true)).Where(n=>n!=null);
                     attributes.AddRange(TypeInModel);
                 }

+ 6 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/BaseItem.cs

@@ -59,5 +59,11 @@ namespace TEAMModelOS.SDK.Models
         /// //选项数量
         /// </summary>
         public int opts { get; set; }
+
+        /// <summary>
+        /// 来源 0.(学校,个人)文档导入 1.(学校,个人)自建 3.学科网
+        /// </summary>
+        public int source { get; set; }
+        public string tag { get; set; }
     }
 }

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

@@ -15,5 +15,9 @@ export default {
     xkwAuthorize: function (data) {
         return post('/xkw/authorize', data)
     },
+    /* 获取学科网的试题集合 */
+    getXkwItems: function (data) {
+        return post('/xkw/get-paper-items', data)
+    },
 
 }

+ 9 - 0
TEAMModelOS/ClientApp/src/router/routes.js

@@ -441,6 +441,15 @@ export const routes = [{
 				activeName: 'schoolBank'
 			},
 		},
+		{
+			path: 'xkwPage',
+			name: 'xkwPage',
+			// component: resolve => require(['@/view/answersheet/index.vue'], resolve),
+			component: resolve => require(['@/view/evaluation/index/XkwPage.vue'], resolve),
+			meta: {
+				activeName: 'schoolBank'
+			},
+		},
 		{
 			path: 'testPaper',
 			name: 'testPaper',

+ 16 - 2
TEAMModelOS/ClientApp/src/view/evaluation/bank/index.vue

@@ -31,9 +31,9 @@
               <Icon type="md-hand" size="16" />
               <span>{{ $t('evaluation.index.manualCreate') }}</span>
             </span>
-            <span @click="goCreatePaper('import',true)" class="bank-tools-btn">
+            <span @click="goXkwPick()" class="bank-tools-btn">
               <Icon type="ios-send" size="16" />
-              <span>学科网组卷</span>
+              <span>{{ $t('evaluation.xkwMode') }}</span>
             </span>
           </div>
         </div>
@@ -170,6 +170,20 @@ export default {
       })
     },
 
+    goXkwPick() {
+      this.$api.auth.xkwOauth({
+        module: 'ezj',
+        agree: 1
+      }).then(res => {
+        this.$router.push({
+          name: 'xkwPage',
+          params: {
+            iframeSrc: res.redirect,
+          }
+        })
+      })
+    },
+
     /** 前往组卷页面 */
     goCreatePaper(type, isXkwMode) {
       if (isXkwMode) {

+ 60 - 19
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -83,12 +83,8 @@
                 <TabPane :label="evaluationInfo.item.length ? $t('evaluation.paperList.tab3') : $t('evaluation.paperList.tab4')" name="import" v-if="evaluationInfo.createType == 'import' && !isXkwMode" :index="3" tab="createTest">
                   <BaseImport @importFinish="onImportFinish"></BaseImport>
                 </TabPane>
-                <!-- 学科网 -->
-                <TabPane :label="$t('evaluation.xkwMode')" name="import" v-if="isXkwMode" :index="4" tab="createTest">
-                  <iframe id="xkwIframe" :src="iframeSrc" frameborder="0" width="100%" height="100%"></iframe>
-                </TabPane>
                 <!-- 预览试卷 -->
-                <TabPane :label="$t('evaluation.paperList.tab5')" name="preview" :index="5" tab="createTest">
+                <TabPane :label="$t('evaluation.paperList.tab5')" name="preview" :index="4" tab="createTest">
                   <vuescroll ref="paperRef" @handle-scroll="handleScroll">
                     <TestPaper v-if="!examAnalysisStatus" :paper="evaluationInfo" :class="examAnalysisStatus ? '':'animated fadeIn'" ref="testPaper" @onViewModelChange="onViewModelChange" :isPreviewItems="!isGeneratePaper">
                     </TestPaper>
@@ -118,6 +114,7 @@ export default {
   },
   data() {
     return {
+      isLoadingXkw: false,
       isXkwMode: false,
       iframeSrc: '',
       tags: [], //试卷标签
@@ -174,13 +171,24 @@ export default {
     }
   },
   async created() {
-    /* 查询当前是否有保存的组卷方式,如果已经保存则直接读取,优先读取传过来的参数 */
-    // let curCreateType = localStorage.getItem('curCreateType')
-    this.evaluationInfo.createType = this.$route.params.type || 'edit'
-    this.isXkwMode = this.$route.params.isXkwMode
-    this.iframeSrc = this.isXkwMode ? this.$route.params.iframeSrc : ''
-    this.setActiveTab(this.evaluationInfo.createType)
-    localStorage.setItem('curCreateType', this.evaluationInfo.createType)
+    let xkwItems = null
+    if (this.$route.query.paperid && this.$route.query.openid) {
+      this.isXkwMode = true
+      this.isLoadingXkw = true
+      xkwItems = await this.getXkwItems()
+      this.isLoading = false
+      this.isLoadingXkw = false
+    }
+    if (xkwItems) {
+      this.evaluationInfo.createType = 'import'
+      this.activeTab = 'preview'
+      this.renderXkwPaperItems(xkwItems)
+    } else {
+      this.evaluationInfo.createType = this.$route.params.type || 'manual'
+      this.setActiveTab(this.evaluationInfo.createType)
+      localStorage.setItem('curCreateType', this.evaluationInfo.createType)
+    }
+
     this.evaluationInfo.type = this.$route.name === 'newSchoolPaper' ? 'school' : 'private'
     this.evaluationInfo.scope = this.evaluationInfo.type
     if (this.$route.params.isFromItemBank) {
@@ -194,15 +202,48 @@ export default {
       this.isGeneratePaper = true
       this.curMode = 'paper'
     }
-
-    // this.getSchoolBaseInfo().then(res => {
-    // 	if (!res) return
-    // 	this.schoolInfo = res
-    // 	this.onPeriodChange(0)
-    // })
     sessionStorage.setItem('isSave', 0)
   },
   methods: {
+    /* 获取学科网的数据 */
+    getXkwItems() {
+      return new Promise((r, j) => {
+        this.isLoading = true
+        this.$api.auth.getXkwItems(this.$route.query).then(res => {
+          if (res.itemInfos) {
+            r(res)
+          } else {
+            j(null)
+          }
+        }).catch(err => {
+          j(null)
+        })
+      })
+    },
+    /* 渲染学科网选择的试题内容 */
+    renderXkwPaperItems(res) {
+      if (!res.error) {
+        this.onImportFinish({
+          list: res.itemInfos,
+        })
+        let curPeriodName = this.schoolInfo.period[this.evaluationInfo.paperPeriod].name
+        let curSubjectName = this.subjectList[this.evaluationInfo.paperSubject].name
+        if (curPeriodName !== res.periodName) {
+          this.$Notice.info({
+            title: '温馨提示',
+            desc: '题目来源学段与当前所选试题学段不一致,建议您进行调整!',
+            duration: 10
+          });
+        }
+        if (curSubjectName !== res.subjectName) {
+          this.$Notice.info({
+            title: '温馨提示',
+            desc: '题目来源科目与当前所选试题科目不一致,建议您进行调整!',
+            duration: 10
+          });
+        }
+      }
+    },
     /* 学段切换 */
     onPeriodChange(val) {
       this.gradeList = this.schoolInfo.period[val].grades
@@ -1600,7 +1641,7 @@ export default {
                   size: 18
                 }
               }),
-              h('div', this.$t('evaluation.saving'))
+              h('div', this.isLoadingXkw ? 'Loading' : this.$t('evaluation.saving'))
             ])
           }
         });

+ 26 - 0
TEAMModelOS/ClientApp/src/view/evaluation/index/XkwPage.vue

@@ -0,0 +1,26 @@
+<template>
+  <div class="xkw-iframe-container">
+    <iframe id="xkwIframe" :src="iframeSrc" frameborder="0" width="100%" height="100%"></iframe>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      iframeSrc: ""
+    }
+  },
+  created() {
+    this.iframeSrc = this.$route.params.iframeSrc
+  }
+}
+</script>
+
+<style>
+.xkw-iframe-container {
+  width: 100%;
+  height: calc(100vh - 60px);
+  overflow: hidden;
+}
+</style>

+ 11 - 7
TEAMModelOS/ClientApp/src/view/homework/ManageHomeWork.vue

@@ -46,8 +46,12 @@
                       <Tooltip placement="bottom" theme="light" transfer>
                         <Icon type="ios-paper-plane" size="24" color="#70b1e7" />
                         <div slot="content" class="ac-share-tooltip">
-                          <p class="link-item" @click="$tools.doCopyAcLink('notice',item)"><Icon type="ios-notifications" size="18"/>{{ $t('vote.copyNotice') }}</p>
-                          <p class="link-item" @click="$tools.doCopyAcLink('link',item)"><Icon type="ios-link" size="18"/>{{ $t('vote.copyLinkUrl') }}</p>
+                          <p class="link-item" @click="$tools.doCopyAcLink('notice',item)">
+                            <Icon type="ios-notifications" size="18" />{{ $t('vote.copyNotice') }}
+                          </p>
+                          <p class="link-item" @click="$tools.doCopyAcLink('link',item)">
+                            <Icon type="ios-link" size="18" />{{ $t('vote.copyLinkUrl') }}
+                          </p>
                         </div>
                       </Tooltip>
                     </span>
@@ -430,7 +434,7 @@ export default {
       })
     },
     /** 新增作业 */
-    async goToCreate() {
+    async goToCreate(classInfo) {
       let hasNoSaveVote = this.voteList.filter(i => !i.id).length
       let isFull = await this.$tools.isBlobContainerFull(this.getCurScope)
       if (hasNoSaveVote) {
@@ -441,9 +445,9 @@ export default {
         let defaultVote = {
           name: this.$t('homework.defaultName'),
           code: this.$store.state.userInfo.TEAMModelId,
-          classes: [],
-          stuLists: [],
-          targets: [],
+          classes: classInfo && classInfo.classId ? [classInfo.classId] : [],
+          stuLists: classInfo && classInfo.stulist ? [classInfo.stulist] : [],
+          targets: [classInfo.classId || classInfo.stulist],
           endTime: new Date(new Date().toLocaleDateString()).getTime() + 2 * 24 * 60 * 60 * 1000 - 1,
           startTime: null,
           description: '',
@@ -531,7 +535,7 @@ export default {
             this.isFromRecord = Boolean(this.routerAc)
             if (this.$route.params.isAdd && !this.quickCreateFinish) {
               // 如果是从我的课程新建活动 跳转过来
-              this.goToCreate()
+              this.goToCreate(this.$route.params.classInfo)
               this.quickCreateFinish = true
             } else {
               this.onVoteClick(queryVote, queryIndex, false)

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1266 - 1304
TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.vue


+ 136 - 135
TEAMModelOS/ClientApp/src/view/mycourse/homework/Homework.vue

@@ -1,151 +1,152 @@
 <template>
-    <div class="hw-container">
-        <div class="ac-action-wrap">
-            <span class="action-item" @click="onCreateAc">
-                <Icon type="md-add" />
-                {{$t('cusMgt.cusTab9')}}
-            </span>
-        </div>
-        <vuescroll>
-            <div class="hw-item" v-for="(item,index) in hwList" :key="index" @click="toAcDetail(index)">
-                <Icon custom="iconfont icon-hw" class="list-icon" />
-                <div class="exam-info-wrap">
-                    <h3 class="exam-name">
-                        {{item.name}}
-                    </h3>
-                    <p class="exam-detail-wrap">
-                        <!-- 学校|个人 -->
-                        <Tag color="blue">
-                            {{ item.owner == 'school' ? $t('cusMgt.school') : $t('cusMgt.private') }}
-                        </Tag>
-                        <!-- 活动进度状态 -->
-                        <Tag :color="item.progress == 'going' ? 'success' : 'warning'">
-                            {{ item.progText }}
-                        </Tag>
-                        <Tag>
-                            <Icon type="md-time" size="16" />
-                            {{$jsFn.timeFormat(item.startTime)}}
-                        </Tag>
-                    </p>
-                </div>
-                <div class="item-action-wrap">
-                    <span style="float:right;margin-right:20px">
-                        <!-- 修改名称 -->
-                        <Icon v-show="item.owner === 'teacher'" type="md-create" style="right:80px" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
-                        <!-- 删除记录 -->
-                        <Icon v-show="item.owner === 'teacher'" type="md-trash" style="right:50px" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
-                        <!-- 收藏 -->
-                        <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" style="right:20px" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
-                    </span>
-                </div>
-            </div>
-            <EmptyData v-show="!hwList.length" :top="150"></EmptyData>
-        </vuescroll>
+  <div class="hw-container">
+    <div class="ac-action-wrap">
+      <span class="action-item" @click="onCreateAc">
+        <Icon type="md-add" />
+        {{$t('cusMgt.cusTab9')}}
+      </span>
     </div>
+    <vuescroll>
+      <div class="hw-item" v-for="(item,index) in hwList" :key="index" @click="toAcDetail(index)">
+        <Icon custom="iconfont icon-hw" class="list-icon" />
+        <div class="exam-info-wrap">
+          <h3 class="exam-name">
+            {{item.name}}
+          </h3>
+          <p class="exam-detail-wrap">
+            <!-- 学校|个人 -->
+            <Tag color="blue">
+              {{ item.owner == 'school' ? $t('cusMgt.school') : $t('cusMgt.private') }}
+            </Tag>
+            <!-- 活动进度状态 -->
+            <Tag :color="item.progress == 'going' ? 'success' : 'warning'">
+              {{ item.progText }}
+            </Tag>
+            <Tag>
+              <Icon type="md-time" size="16" />
+              {{$jsFn.timeFormat(item.startTime)}}
+            </Tag>
+          </p>
+        </div>
+        <div class="item-action-wrap">
+          <span style="float:right;margin-right:20px">
+            <!-- 修改名称 -->
+            <Icon v-show="item.owner === 'teacher'" type="md-create" style="right:80px" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
+            <!-- 删除记录 -->
+            <Icon v-show="item.owner === 'teacher'" type="md-trash" style="right:50px" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
+            <!-- 收藏 -->
+            <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" style="right:20px" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
+          </span>
+        </div>
+      </div>
+      <EmptyData v-show="!hwList.length" :top="150"></EmptyData>
+    </vuescroll>
+  </div>
 </template>
 <script>
 export default {
-    props: {
-        classInfo: {
-            type: Object,
-            default: () => {
-                return {}
-            }
-        }
+  props: {
+    classInfo: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data() {
+    return {
+      fIds: [],
+      hwList: []
+    }
+  },
+  methods: {
+    /* 新建活动 跳转活动创建页面 */
+    async onCreateAc() {
+      let isFull = await this.$tools.isBlobContainerFull('private')
+      if (isFull) {
+        this.$Message.warning(this.$t('vote.fullTip'))
+      } else {
+        this.$router.push({
+          name: 'manageHomeWork',
+          params: {
+            isAdd: true,
+            classInfo: this.classInfo
+          }
+        })
+      }
+    },
+    isFavorite(id) {
+      return this.fIds.includes(id)
     },
-    data() {
-        return {
-            fIds: [],
-            hwList: []
+    toAcDetail(index) {
+      this.$router.push({
+        name: 'manageHomeWork',
+        params: {
+          ac: this.hwList[index]
         }
+      })
     },
-    methods: {
-        /* 新建活动 跳转活动创建页面 */
-        async onCreateAc() {
-            let isFull = await this.$tools.isBlobContainerFull('private')
-            if (isFull) {
-                this.$Message.warning(this.$t('vote.fullTip'))
-            } else {
-                this.$router.push({
-                    name: 'manageHomeWork',
-                    params: {
-                        isAdd: true
-                    }
-                })
-            }
-        },
-        isFavorite(id) {
-            return this.fIds.includes(id)
-        },
-        toAcDetail(index) {
-            this.$router.push({
-                name: 'manageHomeWork',
-                params: {
-                    ac: this.hwList[index]
-                }
+    getStatusInfo(progress) {
+      let info = {}
+      if (progress == 'pending') {
+        info.progText = this.$t('learnActivity.mgtScEv.pending')
+        info.progColor = '#2d8cf0'
+      } else if (progress == 'going') {
+        info.progText = this.$t('learnActivity.mgtScEv.going')
+        info.progColor = '#19be6b'
+      } else if (progress == 'finish') {
+        info.progText = this.$t('learnActivity.mgtScEv.finish')
+        info.progColor = '#515a6e'
+      }
+      return info
+    },
+    //获取活动列表
+    findTchAc(classId) {
+      this.examList = []
+      this.isShowGrade = false
+      this.isLoading = true
+      let requestData = {
+        school: this.$store.state.userInfo.schoolCode,
+        classes: [classId],
+        userid: this.$store.state.userInfo.TEAMModelId,
+        pk: 'Homework'
+      }
+      this.$api.courseMgmt.findTchAc(requestData).then(
+        res => {
+          if (!res.error) {
+            res.datas.forEach(item => {
+              let statusInfo = this.getStatusInfo(item.progress)
+              item.progText = statusInfo.progText
+              item.progColor = statusInfo.progColor
             })
-        },
-        getStatusInfo(progress) {
-            let info = {}
-            if (progress == 'pending') {
-                info.progText = this.$t('learnActivity.mgtScEv.pending')
-                info.progColor = '#2d8cf0'
-            } else if (progress == 'going') {
-                info.progText = this.$t('learnActivity.mgtScEv.going')
-                info.progColor = '#19be6b'
-            } else if (progress == 'finish') {
-                info.progText = this.$t('learnActivity.mgtScEv.finish')
-                info.progColor = '#515a6e'
-            }
-            return info
-        },
-        //获取活动列表
-        findTchAc(classId) {
-            this.examList = []
-            this.isShowGrade = false
-            this.isLoading = true
-            let requestData = {
-                school: this.$store.state.userInfo.schoolCode,
-                classes: [classId],
-                userid: this.$store.state.userInfo.TEAMModelId,
-                pk: 'Homework'
-            }
-            this.$api.courseMgmt.findTchAc(requestData).then(
-                res => {
-                    if (!res.error) {
-                        res.datas.forEach(item => {
-                            let statusInfo = this.getStatusInfo(item.progress)
-                            item.progText = statusInfo.progText
-                            item.progColor = statusInfo.progColor
-                        })
-                        res.datas.sort((a, b) => {
-                            return a.startTime - b.startTime > 0 ? -1 : 1
-                        })
-                        this.hwList = res.datas
-                    }
-                },
-                err => {
-                    // this.$Message.error('API error')
-                }
-            ).finally(() => {
-                this.isLoading = false
+            res.datas.sort((a, b) => {
+              return a.startTime - b.startTime > 0 ? -1 : 1
             })
+            this.hwList = res.datas
+          }
         },
+        err => {
+          // this.$Message.error('API error')
+        }
+      ).finally(() => {
+        this.isLoading = false
+      })
     },
-    watch: {
-        classInfo: {
-            deep: true,
-            immediate: true,
-            handler(n, o) {
-                console.log(n)
-                if (n && (n.classId || n.stulist)) {
-                    this.findTchAc(n.classId || n.stulist)
-                } else {
-                    this.hwList = []
-                }
-            }
+  },
+  watch: {
+    classInfo: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        console.log(n)
+        if (n && (n.classId || n.stulist)) {
+          this.findTchAc(n.classId || n.stulist)
+        } else {
+          this.hwList = []
         }
+      }
     }
+  }
 }
 </script>
 <style lang="less" scoped>
@@ -153,6 +154,6 @@ export default {
 </style>
 <style lang="less">
 .hw-container .ivu-list-item:hover {
-    background: var(--active-item-start);
+  background: var(--active-item-start);
 }
 </style>

+ 137 - 136
TEAMModelOS/ClientApp/src/view/mycourse/survey/Survey.vue

@@ -1,152 +1,153 @@
 <template>
-    <div class="hw-container">
-        <div class="ac-action-wrap">
-            <span class="action-item" @click="onCreateAc">
-                <Icon type="md-add" />
-                {{$t('cusMgt.cusTab11')}}
-            </span>
-        </div>
-        <vuescroll>
-            <div class="survey-item" v-for="(item,index) in surveyList" :key="index" @click="toAcDetail(index)">
-                <Icon custom="iconfont icon-vote" class="list-icon" />
-                <div class="exam-info-wrap">
-                    <h3 class="exam-name">
-                        {{item.name}}
-                    </h3>
-                    <p class="exam-detail-wrap">
-                        <!-- 学校|个人 -->
-                        <Tag color="blue">
-                            {{ item.owner == 'school' ? $t('cusMgt.school') : $t('cusMgt.private') }}
-                        </Tag>
-                        <!-- 活动进度状态 -->
-                        <Tag :color="item.progress == 'going' ? 'success' : 'warning'">
-                            {{ item.progText }}
-                        </Tag>
-                        <Tag>
-                            <Icon type="md-time" size="16" />
-                            {{$jsFn.timeFormat(item.startTime)}}
-                        </Tag>
-                    </p>
-                </div>
-                <div class="item-action-wrap">
-                    <span style="float:right;margin-right:20px">
-                        <!-- 修改评测名称 -->
-                        <Icon v-show="item.owner === 'teacher'" type="md-create" style="right:80px" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
-                        <!-- 删除记录 -->
-                        <Icon v-show="item.owner === 'teacher'" type="md-trash" style="right:50px" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
-                        <!-- 收藏 -->
-                        <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" style="right:20px" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
-                    </span>
-                </div>
-            </div>
-            <EmptyData v-show="!surveyList.length" :top="150"></EmptyData>
-        </vuescroll>
+  <div class="hw-container">
+    <div class="ac-action-wrap">
+      <span class="action-item" @click="onCreateAc">
+        <Icon type="md-add" />
+        {{$t('cusMgt.cusTab11')}}
+      </span>
     </div>
+    <vuescroll>
+      <div class="survey-item" v-for="(item,index) in surveyList" :key="index" @click="toAcDetail(index)">
+        <Icon custom="iconfont icon-vote" class="list-icon" />
+        <div class="exam-info-wrap">
+          <h3 class="exam-name">
+            {{item.name}}
+          </h3>
+          <p class="exam-detail-wrap">
+            <!-- 学校|个人 -->
+            <Tag color="blue">
+              {{ item.owner == 'school' ? $t('cusMgt.school') : $t('cusMgt.private') }}
+            </Tag>
+            <!-- 活动进度状态 -->
+            <Tag :color="item.progress == 'going' ? 'success' : 'warning'">
+              {{ item.progText }}
+            </Tag>
+            <Tag>
+              <Icon type="md-time" size="16" />
+              {{$jsFn.timeFormat(item.startTime)}}
+            </Tag>
+          </p>
+        </div>
+        <div class="item-action-wrap">
+          <span style="float:right;margin-right:20px">
+            <!-- 修改评测名称 -->
+            <Icon v-show="item.owner === 'teacher'" type="md-create" style="right:80px" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
+            <!-- 删除记录 -->
+            <Icon v-show="item.owner === 'teacher'" type="md-trash" style="right:50px" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
+            <!-- 收藏 -->
+            <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" style="right:20px" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
+          </span>
+        </div>
+      </div>
+      <EmptyData v-show="!surveyList.length" :top="150"></EmptyData>
+    </vuescroll>
+  </div>
 </template>
 <script>
 export default {
-    props: {
-        classInfo: {
-            type: Object,
-            default: () => {
-                return {}
-            }
-        }
+  props: {
+    classInfo: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data() {
+    return {
+      fIds: [],
+      surveyList: []
+    }
+  },
+  methods: {
+    /* 新建活动 跳转活动创建页面 */
+    async onCreateAc() {
+      let isFull = await this.$tools.isBlobContainerFull('private')
+      if (isFull) {
+        this.$Message.warning(this.$t('vote.fullTip'))
+      } else {
+        this.$router.push({
+          name: 'personalSurvey',
+          params: {
+            isAdd: true,
+            classInfo: this.classInfo
+          }
+        })
+      }
+    },
+    isFavorite(id) {
+      return this.fIds.includes(id)
     },
-    data() {
-        return {
-            fIds: [],
-            surveyList: []
+    toAcDetail(index) {
+      let owner = this.surveyList[index].owner
+      this.$router.push({
+        name: owner == 'school' ? 'manageQuestionnaire' : 'personalSurvey',
+        params: {
+          ac: this.surveyList[index]
         }
+      })
     },
-    methods: {
-        /* 新建活动 跳转活动创建页面 */
-        async onCreateAc() {
-            let isFull = await this.$tools.isBlobContainerFull('private')
-            if (isFull) {
-                this.$Message.warning(this.$t('vote.fullTip'))
-            } else {
-                this.$router.push({
-                    name: 'personalSurvey',
-                    params: {
-                        isAdd: true
-                    }
-                })
-            }
-        },
-        isFavorite(id) {
-            return this.fIds.includes(id)
-        },
-        toAcDetail(index) {
-            let owner = this.surveyList[index].owner
-            this.$router.push({
-                name: owner == 'school' ? 'manageQuestionnaire' : 'personalSurvey',
-                params: {
-                    ac: this.surveyList[index]
-                }
+    getStatusInfo(progress) {
+      let info = {}
+      if (progress == 'pending') {
+        info.progText = this.$t('learnActivity.mgtScEv.pending')
+        info.progColor = '#2d8cf0'
+      } else if (progress == 'going') {
+        info.progText = this.$t('learnActivity.mgtScEv.going')
+        info.progColor = '#19be6b'
+      } else if (progress == 'finish') {
+        info.progText = this.$t('learnActivity.mgtScEv.finish')
+        info.progColor = '#515a6e'
+      }
+      return info
+    },
+    //获取活动列表
+    findTchAc(classId) {
+      this.examList = []
+      this.isShowGrade = false
+      this.isLoading = true
+      let requestData = {
+        school: this.$store.state.userInfo.schoolCode,
+        classes: [classId],
+        userid: this.$store.state.userInfo.TEAMModelId,
+        pk: 'Survey'
+      }
+      this.$api.courseMgmt.findTchAc(requestData).then(
+        res => {
+          if (!res.error) {
+            res.datas.forEach(item => {
+              let statusInfo = this.getStatusInfo(item.progress)
+              item.progText = statusInfo.progText
+              item.progColor = statusInfo.progColor
             })
-        },
-        getStatusInfo(progress) {
-            let info = {}
-            if (progress == 'pending') {
-                info.progText = this.$t('learnActivity.mgtScEv.pending')
-                info.progColor = '#2d8cf0'
-            } else if (progress == 'going') {
-                info.progText = this.$t('learnActivity.mgtScEv.going')
-                info.progColor = '#19be6b'
-            } else if (progress == 'finish') {
-                info.progText = this.$t('learnActivity.mgtScEv.finish')
-                info.progColor = '#515a6e'
-            }
-            return info
-        },
-        //获取活动列表
-        findTchAc(classId) {
-            this.examList = []
-            this.isShowGrade = false
-            this.isLoading = true
-            let requestData = {
-                school: this.$store.state.userInfo.schoolCode,
-                classes: [classId],
-                userid: this.$store.state.userInfo.TEAMModelId,
-                pk: 'Survey'
-            }
-            this.$api.courseMgmt.findTchAc(requestData).then(
-                res => {
-                    if (!res.error) {
-                        res.datas.forEach(item => {
-                            let statusInfo = this.getStatusInfo(item.progress)
-                            item.progText = statusInfo.progText
-                            item.progColor = statusInfo.progColor
-                        })
-                        res.datas.sort((a, b) => {
-                            return a.startTime - b.startTime > 0 ? -1 : 1
-                        })
-                        this.surveyList = res.datas
-                    }
-                },
-                err => {
-                    // this.$Message.error('API error')
-                }
-            ).finally(() => {
-                this.isLoading = false
+            res.datas.sort((a, b) => {
+              return a.startTime - b.startTime > 0 ? -1 : 1
             })
+            this.surveyList = res.datas
+          }
         },
+        err => {
+          // this.$Message.error('API error')
+        }
+      ).finally(() => {
+        this.isLoading = false
+      })
     },
-    watch: {
-        classInfo: {
-            deep: true,
-            immediate: true,
-            handler(n, o) {
-                console.log(n)
-                if (n && (n.classId || n.stulist)) {
-                    this.findTchAc(n.classId || n.stulist)
-                } else {
-                    this.surveyList = []
-                }
-            }
+  },
+  watch: {
+    classInfo: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        console.log(n)
+        if (n && (n.classId || n.stulist)) {
+          this.findTchAc(n.classId || n.stulist)
+        } else {
+          this.surveyList = []
         }
+      }
     }
+  }
 }
 </script>
 <style lang="less" scoped>
@@ -154,6 +155,6 @@ export default {
 </style>
 <style lang="less">
 .hw-container .ivu-list-item:hover {
-    background: var(--active-item-start);
+  background: var(--active-item-start);
 }
 </style>

+ 136 - 135
TEAMModelOS/ClientApp/src/view/mycourse/vote/Vote.vue

@@ -1,151 +1,152 @@
 <template>
-    <div class="hw-container">
-        <div class="ac-action-wrap">
-            <span class="action-item" @click="onCreateAc">
-                <Icon type="md-add" />
-                {{$t('cusMgt.cusTab12')}}
-            </span>
-        </div>
-        <vuescroll>
-            <div class="vote-item" v-for="(item,index) in voteList" :key="index" @click="toAcDetail(index)">
-                <Icon custom="iconfont icon-vote" class="list-icon" />
-                <div class="exam-info-wrap">
-                    <h3 class="exam-name">
-                        {{item.name}}
-                    </h3>
-                    <p class="exam-detail-wrap">
-                        <!-- 学校|个人 -->
-                        <Tag color="blue">
-                            {{ item.owner == 'school' ? $t('cusMgt.school') : $t('cusMgt.private') }}
-                        </Tag>
-                        <!-- 活动进度状态 -->
-                        <Tag :color="item.progress == 'going' ? 'success' : 'warning'">
-                            {{ item.progText }}
-                        </Tag>
-                        <Tag>
-                            <Icon type="md-time" size="16" />
-                            {{$jsFn.timeFormat(item.startTime)}}
-                        </Tag>
-                    </p>
-                </div>
-                <div class="item-action-wrap">
-                    <span style="float:right;margin-right:20px">
-                        <!-- 修改评测名称 -->
-                        <Icon v-show="item.owner === 'teacher'" type="md-create" style="right:80px" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
-                        <!-- 删除记录 -->
-                        <Icon v-show="item.owner === 'teacher'" type="md-trash" style="right:50px" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
-                        <!-- 收藏 -->
-                        <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" style="right:20px" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
-                    </span>
-                </div>
-            </div>
-            <EmptyData v-show="!voteList.length" :top="150"></EmptyData>
-        </vuescroll>
+  <div class="hw-container">
+    <div class="ac-action-wrap">
+      <span class="action-item" @click="onCreateAc">
+        <Icon type="md-add" />
+        {{$t('cusMgt.cusTab12')}}
+      </span>
     </div>
+    <vuescroll>
+      <div class="vote-item" v-for="(item,index) in voteList" :key="index" @click="toAcDetail(index)">
+        <Icon custom="iconfont icon-vote" class="list-icon" />
+        <div class="exam-info-wrap">
+          <h3 class="exam-name">
+            {{item.name}}
+          </h3>
+          <p class="exam-detail-wrap">
+            <!-- 学校|个人 -->
+            <Tag color="blue">
+              {{ item.owner == 'school' ? $t('cusMgt.school') : $t('cusMgt.private') }}
+            </Tag>
+            <!-- 活动进度状态 -->
+            <Tag :color="item.progress == 'going' ? 'success' : 'warning'">
+              {{ item.progText }}
+            </Tag>
+            <Tag>
+              <Icon type="md-time" size="16" />
+              {{$jsFn.timeFormat(item.startTime)}}
+            </Tag>
+          </p>
+        </div>
+        <div class="item-action-wrap">
+          <span style="float:right;margin-right:20px">
+            <!-- 修改评测名称 -->
+            <Icon v-show="item.owner === 'teacher'" type="md-create" style="right:80px" class="common-item-icon" @click.stop="editEvName(index)" :title="$t('learnActivity.mgtScEv.edName')" />
+            <!-- 删除记录 -->
+            <Icon v-show="item.owner === 'teacher'" type="md-trash" style="right:50px" class="common-item-icon" @click.stop="delEv(item)" :title="$t('cusMgt.delRcd')" />
+            <!-- 收藏 -->
+            <Icon :type="isFavorite(item.id) ? 'md-heart':'md-heart-outline'" style="right:20px" :class="['common-item-icon',isFavorite(item.id) ? 'heart-active':'']" @click.stop="toggleFavorite(item)" :title="isFavorite(item.id) ? $t('cusMgt.unfvt') : $t('cusMgt.fvt')" />
+          </span>
+        </div>
+      </div>
+      <EmptyData v-show="!voteList.length" :top="150"></EmptyData>
+    </vuescroll>
+  </div>
 </template>
 <script>
 export default {
-    props: {
-        classInfo: {
-            type: Object,
-            default: () => {
-                return {}
-            }
-        }
+  props: {
+    classInfo: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data() {
+    return {
+      fIds: [],
+      voteList: []
+    }
+  },
+  methods: {
+    /* 新建活动 跳转活动创建页面 */
+    async onCreateAc() {
+      let isFull = await this.$tools.isBlobContainerFull('private')
+      if (isFull) {
+        this.$Message.warning(this.$t('vote.fullTip'))
+      } else {
+        this.$router.push({
+          name: 'personalVote',
+          params: {
+            isAdd: true,
+            classInfo: this.classInfo
+          }
+        })
+      }
+    },
+    isFavorite(id) {
+      return this.fIds.includes(id)
     },
-    data() {
-        return {
-            fIds: [],
-            voteList: []
+    toAcDetail(index) {
+      this.$router.push({
+        name: 'personalVote',
+        params: {
+          ac: this.voteList[index]
         }
+      })
     },
-    methods: {
-        /* 新建活动 跳转活动创建页面 */
-        async onCreateAc() {
-            let isFull = await this.$tools.isBlobContainerFull('private')
-            if (isFull) {
-                this.$Message.warning(this.$t('vote.fullTip'))
-            } else {
-                this.$router.push({
-                    name: 'personalVote',
-                    params: {
-                        isAdd: true
-                    }
-                })
-            }
-        },
-        isFavorite(id) {
-            return this.fIds.includes(id)
-        },
-        toAcDetail(index) {
-            this.$router.push({
-                name: 'personalVote',
-                params: {
-                    ac: this.voteList[index]
-                }
+    getStatusInfo(progress) {
+      let info = {}
+      if (progress == 'pending') {
+        info.progText = this.$t('learnActivity.mgtScEv.pending')
+        info.progColor = '#2d8cf0'
+      } else if (progress == 'going') {
+        info.progText = this.$t('learnActivity.mgtScEv.going')
+        info.progColor = '#19be6b'
+      } else if (progress == 'finish') {
+        info.progText = this.$t('learnActivity.mgtScEv.finish')
+        info.progColor = '#515a6e'
+      }
+      return info
+    },
+    //获取活动列表
+    findTchAc(classId) {
+      this.examList = []
+      this.isShowGrade = false
+      this.isLoading = true
+      let requestData = {
+        school: this.$store.state.userInfo.schoolCode,
+        classes: [classId],
+        userid: this.$store.state.userInfo.TEAMModelId,
+        pk: 'Vote'
+      }
+      this.$api.courseMgmt.findTchAc(requestData).then(
+        res => {
+          if (!res.error) {
+            res.datas.forEach(item => {
+              let statusInfo = this.getStatusInfo(item.progress)
+              item.progText = statusInfo.progText
+              item.progColor = statusInfo.progColor
             })
-        },
-        getStatusInfo(progress) {
-            let info = {}
-            if (progress == 'pending') {
-                info.progText = this.$t('learnActivity.mgtScEv.pending')
-                info.progColor = '#2d8cf0'
-            } else if (progress == 'going') {
-                info.progText = this.$t('learnActivity.mgtScEv.going')
-                info.progColor = '#19be6b'
-            } else if (progress == 'finish') {
-                info.progText = this.$t('learnActivity.mgtScEv.finish')
-                info.progColor = '#515a6e'
-            }
-            return info
-        },
-        //获取活动列表
-        findTchAc(classId) {
-            this.examList = []
-            this.isShowGrade = false
-            this.isLoading = true
-            let requestData = {
-                school: this.$store.state.userInfo.schoolCode,
-                classes: [classId],
-                userid: this.$store.state.userInfo.TEAMModelId,
-                pk: 'Vote'
-            }
-            this.$api.courseMgmt.findTchAc(requestData).then(
-                res => {
-                    if (!res.error) {
-                        res.datas.forEach(item => {
-                            let statusInfo = this.getStatusInfo(item.progress)
-                            item.progText = statusInfo.progText
-                            item.progColor = statusInfo.progColor
-                        })
-                        res.datas.sort((a, b) => {
-                            return a.startTime - b.startTime > 0 ? -1 : 1
-                        })
-                        this.voteList = res.datas
-                    }
-                },
-                err => {
-                    // this.$Message.error('API error')
-                }
-            ).finally(() => {
-                this.isLoading = false
+            res.datas.sort((a, b) => {
+              return a.startTime - b.startTime > 0 ? -1 : 1
             })
+            this.voteList = res.datas
+          }
         },
+        err => {
+          // this.$Message.error('API error')
+        }
+      ).finally(() => {
+        this.isLoading = false
+      })
     },
-    watch: {
-        classInfo: {
-            deep: true,
-            immediate: true,
-            handler(n, o) {
-                console.log(n)
-                if (n && (n.classId || n.stulist)) {
-                    this.findTchAc(n.classId || n.stulist)
-                } else {
-                    this.voteList = []
-                }
-            }
+  },
+  watch: {
+    classInfo: {
+      deep: true,
+      immediate: true,
+      handler(n, o) {
+        console.log(n)
+        if (n && (n.classId || n.stulist)) {
+          this.findTchAc(n.classId || n.stulist)
+        } else {
+          this.voteList = []
         }
+      }
     }
+  }
 }
 </script>
 <style lang="less" scoped>
@@ -153,6 +154,6 @@ export default {
 </style>
 <style lang="less">
 .hw-container .ivu-list-item:hover {
-    background: var(--active-item-start);
+  background: var(--active-item-start);
 }
 </style>

+ 12 - 9
TEAMModelOS/ClientApp/src/view/questionnaire/ManageQuestionnaire.vue

@@ -43,8 +43,12 @@
                       <Tooltip placement="bottom" theme="light" transfer>
                         <Icon type="ios-paper-plane" size="24" color="#70b1e7" />
                         <div slot="content" class="ac-share-tooltip">
-                          <p class="link-item" @click="$tools.doCopyAcLink('notice',item)"><Icon type="ios-notifications" size="18"/>{{ $t('vote.copyNotice') }}</p>
-                          <p class="link-item" @click="$tools.doCopyAcLink('link',item)"><Icon type="ios-link" size="18"/>{{ $t('vote.copyLinkUrl') }}</p>
+                          <p class="link-item" @click="$tools.doCopyAcLink('notice',item)">
+                            <Icon type="ios-notifications" size="18" />{{ $t('vote.copyNotice') }}
+                          </p>
+                          <p class="link-item" @click="$tools.doCopyAcLink('link',item)">
+                            <Icon type="ios-link" size="18" />{{ $t('vote.copyLinkUrl') }}
+                          </p>
                         </div>
                       </Tooltip>
                     </span>
@@ -408,7 +412,7 @@ export default {
     },
 
     /** 新增问卷 */
-    async goToCreate() {
+    async goToCreate(classInfo) {
       let hasNoSaveQn = this.qnList.filter(i => !i.id).length
       let isFull = await this.$tools.isBlobContainerFull(this.getCurScope)
       if (hasNoSaveQn) {
@@ -418,9 +422,9 @@ export default {
       } else {
         let defaultQn = {
           name: this.$t('survey.defaultName'),
-          classes: [],
-          stuLists: [],
-          targets: [],
+          classes: classInfo && classInfo.classId ? [classInfo.classId] : [],
+          stuLists: classInfo && classInfo.stulist ? [classInfo.stulist] : [],
+          targets: [classInfo.classId || classInfo.stulist],
           endTime: new Date(new Date().toLocaleDateString()).getTime() + 2 * 24 * 60 * 60 * 1000 - 1,
           startTime: null,
           description: "",
@@ -501,11 +505,10 @@ export default {
             let queryIndex = queryId ? list.indexOf(queryItem) : 0
             if (this.$route.params.isAdd && !this.quickCreateFinish) {
               // 如果是从我的课程新建活动 跳转过来
-              this.goToCreate()
+              this.goToCreate(this.$route.params.classInfo)
               this.quickCreateFinish = true
             } else {
               this.onQnClick(queryItem, queryIndex);
-
             }
             this.isEmptyData = false;
           } else {
@@ -583,7 +586,7 @@ export default {
       });
     },
 
-	/* 确实是否移除未保存的活动 */
+    /* 确实是否移除未保存的活动 */
     doConfirmRemoveUnsaveAc() {
       return new Promise((r, j) => {
         this.$Modal.confirm({

+ 11 - 7
TEAMModelOS/ClientApp/src/view/vote/ManageVote.vue

@@ -53,8 +53,12 @@
                       <Tooltip placement="bottom" theme="light" transfer>
                         <Icon type="ios-paper-plane" size="24" color="#70b1e7" />
                         <div slot="content" class="ac-share-tooltip">
-                          <p class="link-item" @click="$tools.doCopyAcLink('notice',item)"><Icon type="ios-notifications" size="18"/>{{ $t('vote.copyNotice') }}</p>
-                          <p class="link-item" @click="$tools.doCopyAcLink('link',item)"><Icon type="ios-link" size="18"/>{{ $t('vote.copyLinkUrl') }}</p>
+                          <p class="link-item" @click="$tools.doCopyAcLink('notice',item)">
+                            <Icon type="ios-notifications" size="18" />{{ $t('vote.copyNotice') }}
+                          </p>
+                          <p class="link-item" @click="$tools.doCopyAcLink('link',item)">
+                            <Icon type="ios-link" size="18" />{{ $t('vote.copyLinkUrl') }}
+                          </p>
                         </div>
                       </Tooltip>
                     </span>
@@ -399,7 +403,7 @@ export default {
     },
 
     /** 新增投票 */
-    async goToCreate() {
+    async goToCreate(classInfo) {
       let hasNoSaveVote = this.voteList.filter(i => !i.id).length
       let isFull = await this.$tools.isBlobContainerFull(this.getCurScope)
       if (hasNoSaveVote) {
@@ -411,9 +415,9 @@ export default {
           name: this.$t('vote.defaultName'),
           code: this.tabIndex === 0 ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo
             .TEAMModelId,
-          classes: [],
-          stuLists: [],
-          targets: [],
+          classes: classInfo && classInfo.classId ? [classInfo.classId] : [],
+          stuLists: classInfo && classInfo.stulist ? [classInfo.stulist] : [],
+          targets: [classInfo.classId || classInfo.stulist],
           owner: this.isAreaVote ? 'area' : this.isPrivate ? 'teacher' : 'school',
           options: [{
             code: 'A',
@@ -509,7 +513,7 @@ export default {
             this.isFromRecord = Boolean(queryId)
             if (this.$route.params.isAdd && !this.quickCreateFinish) {
               // 如果是从我的课程新建活动 跳转过来
-              this.goToCreate()
+              this.goToCreate(this.$route.params.classInfo)
               this.quickCreateFinish = true
             } else {
               this.onVoteClick(queryVote, queryIndex, false)

+ 2 - 2
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -1425,12 +1425,12 @@ namespace TEAMModelOS.Controllers
             }
             catch (CosmosException ex)
             {
-                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
         }

+ 26 - 8
TEAMModelOS/Controllers/Third/Xkw/Sdk/XkwConstant.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using TEAMModelOS.SDK.Models;
 
 namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
 {
@@ -116,14 +117,14 @@ namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
         public static readonly List<XkwDifficulty> xkwDifficulties = new List<XkwDifficulty>()
         {
             //new XkwDifficulty{ id=17,name="容易",ceiling=0.99,flooring=0.9  },
-            new XkwDifficulty{ id=17,name="容易",ceiling=1.0,flooring=0.9  },
-            new XkwDifficulty{ id=18,name="较易",ceiling=0.9,flooring=0.8  },
-            new XkwDifficulty{ id=19,name="一般",ceiling=0.8,flooring=0.5  },
-            new XkwDifficulty{ id=20,name="较难",ceiling=0.5,flooring=0.3  },
-            new XkwDifficulty{ id=21,name="困难",ceiling=0.3,flooring=0.0  },
+            new XkwDifficulty{ id=17,name="容易",ceiling=1.0,flooring=0.9 ,level=1  },
+            new XkwDifficulty{ id=18,name="较易",ceiling=0.9,flooring=0.8 ,level=2 },
+            new XkwDifficulty{ id=19,name="一般",ceiling=0.8,flooring=0.5 ,level=3 },
+            new XkwDifficulty{ id=20,name="较难",ceiling=0.5,flooring=0.3 ,level=4 },
+            new XkwDifficulty{ id=21,name="困难",ceiling=0.3,flooring=0.0 ,level=5 },
         };
 
-        public static readonly List<XkwQuestionType> xkwQuestionTypees = new List<XkwQuestionType>()
+        public static readonly List<XkwQuestionType> xkwQuestionTypes = new List<XkwQuestionType>()
         {
             new XkwQuestionType{id="0101",name="选择题",objective=true,course_id=1},
             new XkwQuestionType{id="0118",name="互动连线题",objective=false,course_id=1},
@@ -722,6 +723,7 @@ namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
         public string name { get; set; }
         public double ceiling { get; set; }
         public double flooring { get; set; }
+        public int level { get; set; }
     }
     public class XkwDto { 
         public int id { get; set; }
@@ -736,8 +738,24 @@ namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
     /// <summary>
     /// 学科网题目结构
     /// </summary>
-    public class XkwPaper { 
-    
+    public class XkwPaperPart
+    {
+        public List<XkwBody> part_body { get; set; } = new List<XkwBody>();
+    }
+    /// <summary>
+    /// 学科网题目结构
+    /// </summary>
+    public class XkwBody {
+        public List<XkwItem> questions { get; set; } = new List<XkwItem>();
+    }
+
+    public class XkwItemInfo : ItemInfo
+    {
+        public string stemHtml { get; set; }
+        public string answerHtml { get; set; }
+        public string subjectName { get; set; }
+        public string periodName { get; set; }
+        public List<string> gradeNames { get; set; }
     }
     /// <summary>
     /// 学科网题目结构

+ 2 - 1
TEAMModelOS/Controllers/Third/Xkw/XkwOAuth2Controller.cs

@@ -300,7 +300,8 @@ namespace TEAMModelOS.Controllers
                                 domain_port = "kong.sso.com:5001";
                             }
                             OAuth_Xkw_ServiceUrl = OAuth_Xkw_ServiceUrl.Replace("{{iframe}}", HttpUtility.UrlEncode($"https://{domain_port}/home/newSchoolPaper"))
-                                .Replace("{{notice}}", HttpUtility.UrlEncode($"https://{domain_port}/xkw/paper-notice"))
+                                .Replace("{{notice}}", HttpUtility.UrlEncode($"https://{domain_port}/home/newSchoolPaper"))
+                                //.Replace("{{notice}}", HttpUtility.UrlEncode($"https://{domain_port}/xkw/paper-notice"))
                                 .Replace("{{openid}}", openId).Replace("{{target}}", "");
                         }
                     }

+ 215 - 6
TEAMModelOS/Controllers/Third/Xkw/XkwServiceController.cs

@@ -35,6 +35,9 @@ using Microsoft.Extensions.Primitives;
 using System.Net.Http;
 using TEAMModelOS.Controllers.Third.Xkw.Sdk;
 using TEAMModelOS.SDK.Models.Table;
+using System.Text.RegularExpressions;
+using HtmlAgilityPack;
+using TEAMModelOS.SDK.Helper.Security.ShaHash;
 
 namespace TEAMModelOS.Controllers.Third.Xkw
 { 
@@ -62,6 +65,15 @@ namespace TEAMModelOS.Controllers.Third.Xkw
         private readonly HttpTrigger _httpTrigger;
         private readonly IWebHostEnvironment _environment;
         private readonly XkwAPIHttpService _xkwAPIHttpService;
+        /// <summary>
+        /// 全角
+        /// </summary>
+        string[] aza = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
+        /// <summary>
+        /// 半角
+        /// </summary>
+        string[] azh = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
+
         public IConfiguration _configuration { get; set; }
         public XkwServiceController(XkwAPIHttpService xkwAPIHttpService, IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage,
             AzureRedisFactory azureRedis, AzureServiceBusFactory serviceBus, IConfiguration configuration, CoreAPIHttpService coreAPIHttpService, ThirdApisService scsApisService, HttpTrigger httpTrigger)
@@ -109,13 +121,210 @@ namespace TEAMModelOS.Controllers.Third.Xkw
             return Ok(authCode);
         }
 
-        [HttpGet("get-paper-items")]
-        //[Authorize(Roles = "IES")]
-        //[AuthToken(Roles = "teacher,admin,area,student")]
-        public async Task<IActionResult> GetPaperItems([FromQuery] OAuthCode authCode)
+        [HttpPost("get-paper-items")]
+#if DEBUG
+#else
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin,area,student")]
+#endif
+        public async Task<IActionResult> GetPaperItems(JsonElement json)
         {
-            await _dingDing.SendBotMsg($"学科网推送消息:{authCode.ToJsonString()}", GroupNames.成都开发測試群組);
-            return Ok(authCode);
+            if (!json.TryGetProperty("paperid", out JsonElement paperid)) { return BadRequest(); }
+            if (!json.TryGetProperty("openid", out JsonElement openid)) { return BadRequest(); }
+            Dictionary<string, string> dict = new Dictionary<string, string>() { { "id", $"{paperid}" }, { "user_id", $"{openid}" } };
+            var paper = _xkwAPIHttpService.Get<JsonElement>("/xopqbm/zj-saas/users/download-papers/details", dict);
+            List<XkwItem> items = new List<XkwItem>();
+            string ps = paper.ToJsonString();
+            XkwDto course = null ;
+            if (paper.TryGetProperty("code", out JsonElement code) && $"{code}".Equals("2000000"))
+            {
+                
+                    if (paper.TryGetProperty("data", out JsonElement data)  &&  data.TryGetProperty("course_id", out JsonElement course_id)) {
+                    course =  XkwConstant.xkwCourses.Find(x => $"{course_id}".Equals($"{x.id}"));
+                    if (course != null) {
+                        if (data.TryGetProperty("body", out JsonElement body)) {
+                            List<XkwPaperPart> paperParts = body.ToObject<List<XkwPaperPart>>();
+                            items.AddRange(paperParts.SelectMany(x => x.part_body).SelectMany(z=>z.questions));
+                        }
+                    }
+                }
+            }
+            List<XkwItemInfo> itemInfos = new List<XkwItemInfo>();
+            List<XkwDto> xkw_points = new List<XkwDto>();
+            var kpoint_ids=items.SelectMany(x => x.kpoint_ids).ToHashSet();
+            if (kpoint_ids.Any()) {
+                Dictionary<string, string> dict_pointids = new Dictionary<string, string>() { { "ids", String.Join(",", kpoint_ids.Select(x => x)) } };
+                var points = _xkwAPIHttpService.Get<JsonElement>("/xopqbm/knowledge-points", dict_pointids);
+
+                if (points.TryGetProperty("code", out JsonElement pcode) && $"{pcode}".Equals("2000000")) {
+                    if (points.TryGetProperty("data", out JsonElement pdata)) {
+                        xkw_points = pdata.ToObject<List<XkwDto>>();
+                    }
+                }
+            }
+            int index = 1;
+            items.ForEach(x => {
+                //x.kpoint_ids
+                XkwItemInfo itemInfo = new XkwItemInfo
+                {
+                    source = 3,
+                    shaCode = ShaHashHelper.GetSHA1(x.stem),
+                    id = x.id,
+                    order = index,
+                    explain = x.explanation,
+                    subjectName = course?.subject_name,
+                    periodName = course?.stage_name,
+                    // explain = x.explanation.Replace("【分析】", "分析:").Replace("【详解】", "详解:")
+                     
+                };
+                index += 1;
+                //设置默认难度,和默认认知层次
+                itemInfo.field = 1;
+                itemInfo.level = 3;
+                foreach (var difct in XkwConstant.xkwDifficulties) {
+                    if (x.difficulty < difct.ceiling && x.difficulty >= difct.flooring) {
+                        itemInfo.level = difct.level;
+                    }
+                }
+                var grades=    XkwConstant.xkwGrades.FindAll(g => x.grade_ids.Contains(g.id));
+                if (grades.Any()) {
+                    itemInfo.gradeNames = grades.Select(g => g.name).ToList();
+                }
+                if (x.kpoint_ids.Any()) {
+                    var points =  xkw_points.FindAll(p => x.kpoint_ids.Contains(p.id));
+                    if (points.Any()) {
+                        
+                        itemInfo.knowledge.AddRange(points.Select(x => x.name));
+                    }
+                }
+                var type= XkwConstant.xkwQuestionTypes.Find(t => t.id == x.type_id);
+                //判断是否 主客观题
+                if (type != null) {
+                    itemInfo.objective =type.objective;
+                    itemInfo.tag = type.name;
+                }
+                else { 
+                    itemInfo.objective = false; 
+                }
+                //如果是客观题,则需要处理选项和答案。
+                if (itemInfo.objective)
+                {
+                    string classpattern = "class=\"([^\"]*)\"";
+                    string pattern = "<span([^>]{0,})>";
+                    string table_pattern = "<table([^>]{0,})>";
+                    string apattern = "<a([^>]{0,})></a>";
+                    string shtml = x.stem;
+                    //去除class 以及span标签"
+                    shtml = Regex.Replace(shtml, table_pattern, "").Replace("</table>", "").Replace("<tr>", "").Replace("<td>", "").Replace("</td>", "").Replace("</tr>", "");
+                    //shtml = Regex.Replace(shtml, classpattern, "");
+                    //shtml = Regex.Replace(shtml, pattern, "");
+                    //shtml = Regex.Replace(shtml, apattern, "");
+                    //shtml = shtml.Replace(" close=\"\" separators=\" | \">", "");
+                    //shtml = shtml.Replace("\t", " ").Replace("<span>", "").Replace("</span>", "").Replace("dir=\"ltr\"", "");
+                    //处理 标签中包含的空格字符
+
+                    //处理题干
+                    (List<CodeValue> options, string question) = OptionProcess(shtml);
+                    itemInfo.option = options;
+                    itemInfo.opts = options.Count;
+                    itemInfo.question = question;
+
+                    //处理答案
+                    //去除class 以及span标签"
+                    string ahtml = x.answer;
+                    ahtml = Regex.Replace(ahtml, classpattern, "");
+                    ahtml = Regex.Replace(ahtml, pattern, "");
+                    ahtml = Regex.Replace(ahtml, apattern, "");
+                    ahtml = ahtml.Replace(" close=\"\" separators=\" | \">", "");
+                    ahtml = ahtml.Replace("\t", " ").Replace("<span>", "").Replace("</span>", "").Replace("dir=\"ltr\"", "");
+                    HashSet<string> ans = new HashSet<string>();
+                    var anstr = BlankTag(ahtml);
+                    for (int idx = 0; idx < 26; idx++)
+                    {
+                        anstr = anstr.Replace(aza[idx], azh[idx]);
+                    }
+
+                    anstr.Select(s => s.ToString()).ToList().ForEach(x =>
+                    {
+                        ans.Add(x);
+                    });
+                    itemInfo.answerHtml = x.answer;
+                    itemInfo.answer = ans.ToList() ;
+                    if (ans.Count > 1)
+                    {
+                        itemInfo.type = "multiple";
+                    }
+                    else {
+                        itemInfo.type = "single";
+                    }
+                }
+                else {
+                    itemInfo.type = "subjective";
+                    itemInfo.question = x.stem;
+                    itemInfo.answer = new List<string>() { HtmlHelper.DoUselessTag(x.answer.ToString()) };
+                }
+                itemInfos.Add(itemInfo);
+
+
+            });
+            HashSet<string> gradeNames = new HashSet<string>();
+            gradeNames = itemInfos.SelectMany(x => x.gradeNames).ToHashSet();
+           // await _dingDing.SendBotMsg($"学科网推送消息:{authCode.ToJsonString()}", GroupNames.成都开发測試群組);
+            return Ok(new { periodName=course.stage_name, subjectName=course.subject_name, gradeNames, knowledge=xkw_points.Select(x=>x.name), itemInfos, paper });
+        }
+
+        private string BlankTag(string tagHtml)
+        {
+            //去掉标签中的Html
+            HtmlDocument doc = new HtmlDocument();
+            doc.LoadHtml(tagHtml);
+            var tagValue = doc.DocumentNode.InnerText.Replace("{", "").Replace("}", "")
+                        .Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "")
+                        .Replace("&nbsp;", "").Replace("&emsp;", "").Replace("&emsp;", "");
+            // tagValue = Regex.Replace(tagValue, @"\d", "");
+            tagValue = Regex.Replace(tagValue, @"\s", "");
+            return tagValue;
+        }
+
+        public (List<CodeValue> options, string question) OptionProcess(string question) {
+
+            string Options = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+            string[] optionsKeys = Options.Select(s => s.ToString()).ToArray();
+            for (int idx = 0; idx < 26; idx++)
+            {
+                question = question.Replace(aza[idx], azh[idx]);
+            }
+            List<CodeValue> options = new List<CodeValue>();
+            string optsRgex = optionsKeys[0] + "\\s*(\\.|\\.|\\、|\\:|\\:)([\\s\\S]*?).*"; ;
+            string optsHtml = Regex.Match(question, optsRgex).Value;
+            StringBuilder textImg = new StringBuilder();
+            for (int i = 0; i < optionsKeys.Length - 1; i++)
+            {
+                string optRgex = optionsKeys[i] + "\\s*(\\.|\\.|\\、|\\:|\\:)([\\s\\S]*?)" + optionsKeys[i + 1] + "\\s*(\\.|\\.|\\、|\\:|\\:)";
+                string optHtml = Regex.Match(optsHtml, optRgex).Value;
+                if (string.IsNullOrWhiteSpace(optHtml))
+                {
+                    optRgex = optionsKeys[i] + "\\s*(\\.|\\.|\\、|\\:|\\:).*";
+                    optHtml = Regex.Match(optsHtml, optRgex).Value;
+                }
+                if (!string.IsNullOrEmpty(optHtml))
+                {
+                    optHtml = Regex.Replace(optHtml, optionsKeys[i + 1] + "\\s*(\\.|\\.|\\、|\\:|\\:)", "");
+                    optHtml = optHtml.Substring(2, optHtml.Length - 2);
+                    optHtml = HtmlHelper.DoUselessTag(optHtml);
+                    optHtml = optHtml.TrimStart().TrimEnd();
+                    textImg.Append(HtmlHelper.DoTextImg(optHtml));
+                    options.Add(new CodeValue { code = optionsKeys[i], value = optHtml });
+                }
+            }
+            if (!string.IsNullOrWhiteSpace(optsHtml))
+            {
+                return (options, question.Replace(optsHtml, ""));
+            }
+            else
+            {
+                return (new List<CodeValue>(), question);
+            }
         }
     }
 }