Parcourir la source

Merge branch 'develop' into TPE/develop

jeff il y a 1 an
Parent
commit
7c11d065cb

+ 4 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Activity.cs

@@ -85,6 +85,7 @@ namespace TEAMModelOS.SDK.Models
         /// 0未发布,1已发布,2.已结束
         /// </summary>
         public int publish { get; set; }
+        public string sas { get; set; }
     }
 
 
@@ -478,6 +479,9 @@ namespace TEAMModelOS.SDK.Models
     
     public class ActivityExpert : CosmosEntity
     {
+        /// <summary>
+        /// 活动id
+        /// </summary>
         public ActivityExpert() {
             pk="ActivityExpert";
             code="ActivityExpert";

+ 3 - 1
TEAMModelOS.SDK/Models/Service/Common/ActivityService.cs

@@ -1,4 +1,5 @@
-using HTEXLib.COMM.Helpers;
+using Azure.Storage.Blobs.Models;
+using HTEXLib.COMM.Helpers;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -7,6 +8,7 @@ using System.Threading.Tasks;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models;
+using TEAMModelOS.Services;
 
 namespace TEAMModelOS.SDK
 {

+ 2 - 3
TEAMModelOS.SDK/Models/Service/Common/TeacherService.cs

@@ -30,9 +30,10 @@ namespace TEAMModelOS.Services
 {
     public static class TeacherService
     {
-        public static async Task<TeacherInfo> TeacherInfoLite(AzureCosmosFactory _azureCosmos, Teacher teacher, string name, string picture, string id,
+        public static async Task<TeacherInfo> TeacherInfoLite(AzureCosmosFactory _azureCosmos,  string name, string picture, string id,
            AzureStorageFactory _azureStorage, Option _option, AzureRedisFactory _azureRedis, string ip, HttpTrigger _httpTrigger, string lang)
         {
+            Teacher teacher = null;
             string defaultschool = null;
             //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等),學校數據另外API處理,多校切換時不同
             var client = _azureCosmos.GetCosmosClient();
@@ -179,7 +180,6 @@ namespace TEAMModelOS.Services
             List<string> roles = new List<string>() { "teacher" };
            
             //換取AuthToken,提供給前端
-            var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, Website: "IES", scope: Constant.ScopeTeacher, standard: "", roles: roles.ToArray(), expire: 1);
 
             //用户在线记录
             try
@@ -194,7 +194,6 @@ namespace TEAMModelOS.Services
             var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
             return new TeacherInfo
             {
-                auth_token = auth_token,
                 blob_uri = blob_uri,
                 blob_sas = blob_sas,
                 defaultschool = defaultschool,

+ 2 - 1
TEAMModelOS/ClientApp/src/boot-app.js

@@ -21,7 +21,7 @@ import jwtDecode from 'jwt-decode'
 import GLOBAL from '@/static/Global.js'
 import echarts from 'echarts'
 import vuescroll from 'vuescroll/dist/vuescroll-native'
-import { Tree, Cascader } from 'element-ui' // 按需引入element Tree组件
+import { Tree, Cascader, Switch } from 'element-ui' // 按需引入element Tree组件
 import 'element-ui/lib/theme-chalk/tree.css'
 import 'element-ui/lib/theme-chalk/icon.css'
 import animated from 'animate.css'
@@ -82,6 +82,7 @@ Vue.use(commonComponents)
 Vue.use(evaluationComponents)
 Vue.use(Tree)
 Vue.use(Cascader)
+Vue.use(Switch)
 // 定义全局日志组件
 Vue.use(VueLogger, {
     isEnabled: true,

+ 1 - 1
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1940,7 +1940,7 @@ export const routes = [{
             name: 'areaActivitySet',
             component: () => import('@/view/signupActivity/setActivity.vue'),
             meta: {
-                activeName: 'areaActivityManage',
+                activeName: 'areaActivitySet',
             }
         }
     ]

+ 1 - 2
TEAMModelOS/ClientApp/src/view/signupActivity/createActivity.vue

@@ -56,9 +56,8 @@
                                 <Icon type="md-alert" color="#ffad16" size="18" />
                                 不选学校则表示所有学校都可参加该活动
                             </p>
-                            <p>
+                            <p v-show="(createData.scope === 'public' && selSchools.length) || createData.scope != 'public'">
                                 <Icon type="ios-alert-outline" color="#ffad16" size="18" />
-                                <!-- <Icon type="ios-alert" color="#ffad16" size="18" /> -->
                                 发布活动后,需学校先确认参与活动,老师才可报名参与
                             </p>
                         </FormItem>

+ 65 - 55
TEAMModelOS/ClientApp/src/view/signupActivity/infoGoing.vue

@@ -12,6 +12,9 @@
                     </span>
                     {{ actInfo.name }}
                 </p>
+                <div class="btn-box">
+                    <Button type="warning" size="small">删除</Button>
+                </div>
                 <!-- <div class="btn-box">
                     <Steps :current="2" size="small">
                         <Step title="报名"></Step>
@@ -37,10 +40,13 @@
                             <p>承办:
                                 <span v-for="(item, index) in actInfo.cb" :key="index" style="margin-right: 10px;">{{ item }}</span>
                             </p>
-                            <p v-if="actInfo.scope === 'area' && isArea">学校:
-                                <span>
+                            <p v-if="actInfo.scope != 'school' && isArea">学校:
+                                <span v-if="actInfo.invitedSchools.length">
                                     <span v-for="item in actInfo.invitedSchools" :key="item.id" style="margin-right: 10px;">{{ item.name }}</span>
                                 </span>
+                                <span v-else>
+                                    所有学校
+                                </span>
                             </p>
                             <p v-else-if="actInfo.scope === 'school'">
                                 老师:
@@ -131,61 +137,63 @@
                                     </Table>
                                 </div>
                             </div>
-                            <div class="data-box">
-                                <div class="module-title">评审管理</div>
-                                <div class="module-data">
-                                    <div class="tab-header">
-                                        <Button @click="processShow = true">添加评审专家</Button>
-                                        <Button style="margin-left: 20px;" @click="workPro = true">自动分配评审作品</Button>
-                                        <Button style="float: right;" @click="ruleDrawer = true">评审规则</Button>
-                                    </div>
-                                    <Table :columns="processColumns" :data="processList">
-                                        <template #process="{}">
-                                            <Progress :percent="25" :stroke-width="10" />
-                                        </template>
-                                        <template #actions="{row, index}">
-                                            <Button type="error" size="small" @click="deleteApplica(row, index, 'process')">删除</Button>
-                                        </template>
-                                    </Table>
-                                </div>
-                            </div>
-                            <div class="data-box">
-                                <div class="module-title">成绩统计</div>
-                                <div class="module-data">
-                                    <div class="tab-header">
-                                        <div v-show="!awardsing">
-                                            <Button @click="setAwards()">设置奖项</Button>
-                                            <Button @click="openAch()" style="margin-left: 20px;">公示成绩</Button>
-                                        </div>
-                                        <div v-show="awardsing">
-                                            <Button @click="awardsShow = true">批量设置</Button>
-                                            <Button @click="awardTypes()" style="margin-left: 20px;">取消</Button>
+                            <template v-if="actInfo.scope === 'area' && isArea">
+                                <div class="data-box">
+                                    <div class="module-title">评审管理</div>
+                                    <div class="module-data">
+                                        <div class="tab-header">
+                                            <Button @click="processShow = true">添加评审专家</Button>
+                                            <Button style="margin-left: 20px;" @click="workPro = true">自动分配评审作品</Button>
+                                            <Button style="float: right;" @click="ruleDrawer = true">评审规则</Button>
                                         </div>
+                                        <Table :columns="processColumns" :data="processList">
+                                            <template #process="{}">
+                                                <Progress :percent="25" :stroke-width="10" />
+                                            </template>
+                                            <template #actions="{row, index}">
+                                                <Button type="error" size="small" @click="deleteApplica(row, index, 'process')">删除</Button>
+                                            </template>
+                                        </Table>
                                     </div>
-                                    <Table :columns="scoreColumns" :data="scoreList" height="600">
-                                        <template #score1="{row}">
-                                            <div v-show="!row.edit">
-                                                <span>{{ row.score1 }}</span>
-                                                <Icon type="md-nutrition" @click="row.edit = true" />
-                                            </div>
-                                            <div v-show="row.edit">
-                                                <InputNumber :min="0" v-model="row.score1" />
-                                                <Icon type="md-checkmark-circle" @click="row.edit = false" />
-                                                <Icon type="md-close-circle" @click="row.edit = false" />
+                                </div>
+                                <div class="data-box">
+                                    <div class="module-title">成绩统计</div>
+                                    <div class="module-data">
+                                        <div class="tab-header">
+                                            <div v-show="!awardsing">
+                                                <Button @click="setAwards()">设置奖项</Button>
+                                                <Button @click="openAch()" style="margin-left: 20px;">公示成绩</Button>
                                             </div>
-                                        </template>
-                                        <template #awards="{row}">
-                                            <span v-if="!awardsing">{{ row.awards ? row.awards : '-' }}</span>
-                                            <div v-else>
-                                                <Select v-model="row.awards" style="width:200px" :transfer="true">
-                                                    <Option v-for="item in awardsList" :value="item.value" :key="item.value">{{ item.label }}</Option>
-                                                </Select>
-                                                <Icon type="md-add-circle" @click="addAward = true" />
+                                            <div v-show="awardsing">
+                                                <Button @click="awardsShow = true">批量设置</Button>
+                                                <Button @click="awardTypes()" style="margin-left: 20px;">取消</Button>
                                             </div>
-                                        </template>
-                                    </Table>
+                                        </div>
+                                        <Table :columns="scoreColumns" :data="scoreList" height="600">
+                                            <template #score1="{row}">
+                                                <div v-show="!row.edit">
+                                                    <span>{{ row.score1 }}</span>
+                                                    <Icon type="md-nutrition" @click="row.edit = true" />
+                                                </div>
+                                                <div v-show="row.edit">
+                                                    <InputNumber :min="0" v-model="row.score1" />
+                                                    <Icon type="md-checkmark-circle" @click="row.edit = false" />
+                                                    <Icon type="md-close-circle" @click="row.edit = false" />
+                                                </div>
+                                            </template>
+                                            <template #awards="{row}">
+                                                <span v-if="!awardsing">{{ row.awards ? row.awards : '-' }}</span>
+                                                <div v-else>
+                                                    <Select v-model="row.awards" style="width:200px" :transfer="true">
+                                                        <Option v-for="item in awardsList" :value="item.value" :key="item.value">{{ item.label }}</Option>
+                                                    </Select>
+                                                    <Icon type="md-add-circle" @click="addAward = true" />
+                                                </div>
+                                            </template>
+                                        </Table>
+                                    </div>
                                 </div>
-                            </div>
+                            </template>
                         </div>
                     </vuescroll>
                 </TabPane>
@@ -589,11 +597,11 @@ export default {
             this.sasData.sas = this.$store.state.user.userProfile.areas.find(item => {
                 return item.areaId === this.actInfo.owner
             }).sas
+            this.getInviteTea()
         } else {
             this.sasData.sas = this.$store.state.user.schoolProfile.blob_sas
         }
         this.getActInfo()
-        this.getInviteTea()
     },
     computed: {
         actInfo() {
@@ -728,9 +736,11 @@ export default {
         }
         .btn-box {
             position: absolute;
-            top: 12px;
+            /* top: 12px;
             right: 5px;
-            width: 320px;
+            width: 320px; */
+            top: 0;
+            right: 20px;
         }
     }
 

+ 148 - 81
TEAMModelOS/ClientApp/src/view/signupActivity/infoReleased.vue

@@ -1,6 +1,6 @@
 <template>
-    <div>
-        <div v-if="actInfo">
+    <div class="info-released">
+        <div v-if="actInfo" style="height: 100%;">
             <div class="info-header">
                 <div @click="$router.go(-1)">
                     <Icon type="ios-arrow-back" />
@@ -12,9 +12,15 @@
                     </span>
                     {{ actInfo.name }}
                 </p>
-                <div class="btn-box">
-                    <Button type="success" size="small" @click="publishNow()">立即发布</Button>
-                    <Button type="primary" size="small">修改</Button>
+                <div class="btn-box" v-if="actInfo.needConfirmed || !actInfo.publish">
+                    <template v-if="!actInfo.needConfirmed">
+                        <Button type="success" size="small" @click="publishNow()">立即发布</Button>
+                        <Button type="primary" size="small">修改</Button>
+                    </template>
+                    <template v-else>
+                        <Button type="success" size="small" @click="confirmedJoin(1)">加入</Button>
+                        <!-- <Button type="primary" size="small" @click="confirmedJoin(0)">退出</Button> -->
+                    </template>
                 </div>
             </div>
             <div class="info-box">
@@ -49,7 +55,7 @@
                                 <span v-for="(item, index) in actInfo.cb" :key="index" style="margin-right: 10px;">{{ item }}</span>
                             </span>
                         </div>
-                        <div v-if="actInfo.scope === 'area' && isArea">
+                        <div v-if="actInfo.scope != 'school' && isArea">
                             <span>学校:</span>
                             <span>
                                 <span v-for="item in actInfo.invitedSchools" :key="item.id">{{ item.name }}</span>
@@ -210,13 +216,19 @@ export default {
                     label: '学科',
                 },
             ],
-            ruleInfo: undefined,
+            ruleInfo: {
+                name: '',
+                desc: '',
+                trees: [],
+            },
             ruleDrawer: false,
         }
     },
     created () {
         if(this.actInfo) {
             this.getActInfo()
+        } else {
+            this.$router.go(-1)
         }
     },
     computed: {
@@ -278,101 +290,156 @@ export default {
                 }
             })
         },
+        confirmedJoin(type) {
+            this.$Modal.confirm({
+                // title: '删除专家',
+                content: `确认加入本次活动吗?`,
+                onOk: () => {
+                    let params = {
+                        grant_type: 'school-confirm',
+                        activityId: this.actInfo.id,
+                        confirm: type
+                    }
+                    this.$api.areaActivity.manageAct(params).then(res => {
+                        if(res.code === 200) {
+                            this.actInfo.needConfirmed = 0
+                        }
+                    })
+                }
+            })
+        },
     }
 
 }
 </script>
 
 <style lang="less" scoped>
-.info-header {
-    height: 45px;
-    line-height: 45px;
-    box-shadow: 0px 2px 5px #e9e9e9;
-    padding-left: 10px;
-    text-align: center;
-    position: relative;
+.info-released {
+    height: 100%;
+    .info-header {
+        height: 45px;
+        line-height: 45px;
+        box-shadow: 0px 2px 5px #e9e9e9;
+        padding-left: 10px;
+        text-align: center;
+        position: relative;
 
-    &>div:first-of-type{
-        /* display: inline-block;
-        float: left; */
-        cursor: pointer;
-        position: absolute;
-        top: 0;
-        left: 10px;
+        &>div:first-of-type{
+            /* display: inline-block;
+            float: left; */
+            cursor: pointer;
+            position: absolute;
+            top: 0;
+            left: 10px;
+        }
+        .title{
+            font-size: 18px;
+            font-weight: bold;
+            margin-right: 7%;
+            .type-box{
+                background-color: #a8a8a8;
+                font-size: 15px;
+                font-weight: normal;
+                color: #fff;
+                padding: 3px 6px;
+                border-radius: 5px;
+                margin-right: 5px;
+            }
+        }
+        .btn-box {
+            position: absolute;
+            top: 0;
+            right: 5px;
+            .ivu-btn {
+                margin-right: 10px;
+            }
+        }
     }
-    .title{
-        font-size: 18px;
-        font-weight: bold;
-        margin-right: 7%;
-        .type-box{
-            background-color: #a8a8a8;
-            font-size: 15px;
-            font-weight: normal;
+    .info-box {
+        display: flex;
+        height: 100%;
+
+        .time-border {
+            background-color: #319be7;
+            border-radius: 5px;
+            padding: 2px 10px;
             color: #fff;
-            padding: 3px 6px;
+            font-weight: 100;
+        }
+
+        .info-border {
+            background-color: #8cb553;
             border-radius: 5px;
+            padding: 2px 10px;
+            color: #fff;
             margin-right: 5px;
         }
-    }
-    .btn-box {
-        position: absolute;
-        top: 0;
-        right: 5px;
-        .ivu-btn {
-            margin-right: 10px;
-        }
-    }
-}
-.info-box {
-    display: flex;
 
-    .time-border {
-        background-color: #319be7;
-        border-radius: 5px;
-        padding: 2px 10px;
-        color: #fff;
-        font-weight: 100;
-    }
+        .activity-info {
+            width: 40%;
+            height: 100%;
+            margin: 10px 20px;
+            margin-right: 30px;
+            img {
+                /* width: 100%;
+                min-height: 300px; */
+                width: auto;
+                height: 300px;
+            }
+            &>div {
+                margin: 10px 0;
+                font-size: 16px;
+            }
+        }
 
-    .info-border {
-        background-color: #8cb553;
-        border-radius: 5px;
-        padding: 2px 10px;
-        color: #fff;
-        margin-right: 5px;
-    }
+        .check-module {
+            width: 60%;
+            .sk-title{
+                background-color: #eaeaea;
+                padding: 10px;
+                margin-bottom: 10px;
+                margin-top: 25px;
+                font-weight: bold;
+                border-radius: 10px;
 
-    .activity-info {
-        width: 40%;
-        margin: 10px 20px;
-        margin-right: 30px;
-        img {
-            width: 100%;
-        }
-        &>div {
-            margin: 10px 0;
-            font-size: 16px;
+                &>span:first-child {
+                    margin-right: 15px;
+                }
+            }
+            .sk-info{
+                // padding: 0 10px;
+                &>p {
+                    margin: 10px;
+                }
+            }
         }
     }
+    .create-form {
+        margin: 30px 30px 30px 10px;
+        // height: 100%;
 
-    .check-module {
-        width: 60%;
-        .sk-title{
-            background-color: #eaeaea;
-            padding: 10px;
-            margin-bottom: 10px;
-            margin-top: 25px;
-            font-weight: bold;
-            border-radius: 10px;
+        .tab-check{
+            margin-bottom: 15px;
 
-            &>span:first-child {
-                margin-right: 15px;
+            .file-box {
+                display: flex;
+                & >label{
+                    width: 100px;
+
+                }
             }
         }
-        .sk-info{
-            // padding: 0 10px;
-            &>p {
-                margin: 10px;
+
+        .unit-box {
+            position: relative;
+            .ivu-icon-md-add-circle {
+                position: absolute;
+                top: 6px;
+                right: 0;
+            }
+            .ivu-icon{
+                margin-left: 10px;
+                cursor: pointer;
             }
         }
     }

+ 35 - 16
TEAMModelOS/ClientApp/src/view/signupActivity/processActivity.vue

@@ -4,6 +4,7 @@
             <RadioGroup v-model="processType" type="button" button-style="solid">
                 <Radio :label="-1">全部</Radio>
                 <Radio :label="0">未发布</Radio>
+                <Radio :label="3" v-if="!isArea">未确认</Radio>
                 <Radio :label="1">进行中</Radio>
                 <Radio :label="2">已结束</Radio>
             </RadioGroup>
@@ -29,9 +30,14 @@
                         <p>主办:{{ item.zb.length }}</p>
                         <!-- <p>简介:{{ item.jianjie }}</p> -->
                         <div class="process-type">
-                            <span v-show="!item.publish" style="color: #ec8130;">待发布</span>
-                            <span v-show="item.publish === 1" style="color: #1e9a1e;">进行中</span>
-                            <span v-show="item.publish === 2" style="color: #696969;">已结束</span>
+                            <template v-if="item.needConfirmed">
+                                <span style="color: #305cec;">待确认</span>
+                            </template>
+                            <template v-else>
+                                <span v-show="!item.publish" style="color: #ec8130;">待发布</span>
+                                <span v-show="item.publish === 1" style="color: #1e9a1e;">进行中</span>
+                                <span v-show="item.publish === 2" style="color: #696969;">已结束</span>
+                            </template>
                         </div>
                     </div>
                 </div>
@@ -62,9 +68,14 @@ export default {
             handler(n, o) {
                 if(n === -1) {
                     this.activityListShow = this.activityList
+                } else if(n != 3) {
+                    this.activityListShow = this.activityList.filter(item => {
+                        return item.publish === n && !item.needConfirmed
+                        // return n ? (n === 1 ? item.publish === 1 : item.publish === 2) : item.publish === 0
+                    })
                 } else {
                     this.activityListShow = this.activityList.filter(item => {
-                        return n ? (n === 1 ? item.publish === 1 : item.publish === 2) : item.publish === 0
+                        return item.needConfirmed
                     })
                 }
             },
@@ -82,20 +93,27 @@ export default {
             this.$api.areaActivity.manageAct(params).then(res => {
                 if(res.activities) {
                     let sasData = {sas: ''}
-                    if(this.isArea) {
+                    /* if(this.isArea) {
                         sasData.sas = this.$store.state.user.userProfile.areas.find(item => {
                             return item.areaId === params.areaId
                         }).sas
                     } else {
                         sasData.sas = this.$store.state.user.schoolProfile.blob_sas
-                    }
+                    } */
                     this.activityList = res.activities.map(item => {
+                        console.log(item.sas);
                         item.startTime = this.$tools.formatTime(item.stime, 'yyyy-MM-dd')
                         item.endTime = this.$tools.formatTime(item.etime, 'yyyy-MM-dd')
-                        item.poster = !item.poster ? require('@/assets/image/no-poster-cn1.png') : `${item.poster}?${sasData.sas}`
+                        item.poster = !item.poster ? require('@/assets/image/no-poster-cn1.png') : `${item.poster}?${item.sas}`
                         item.attachment.forEach(attach => {
-                            attach.url = `${attach.url}?${sasData.sas}`
+                            attach.url = `${attach.url}?${item.sas}`
                         })
+                        // 校级确认参加: confirmedSchools[0].status = 0(没确认)/1(已确认)
+                        // 区级都需要确认,公开只有选择了学校才需确认
+                        if(!this.isArea && ((item.scope === 'public' && item.invitedSchools.length) || item.scope === 'area')) {
+                            item.needConfirmed = !item.confirmedSchools[0].status
+                            // item.confirmed = item.confirmedSchools[0].status
+                        }
                         return item
                     })
                     this.activityListShow = this.activityList
@@ -103,14 +121,8 @@ export default {
             })
         },
         goInfo(data) {
-            if(data.publish) {
-                this.$router.push({
-                    name: this.isArea ? 'areaInfoActivity' : 'infoActivity',
-                    params: {
-                        info: data
-                    }
-                })
-            } else {
+            // 待确认页面 === 待发布页面
+            if(!data.publish || data.needConfirmed) {
                 this.$router.push(
                 {
                     name: this.isArea ? 'areaInfoProcess' : 'infoProcess',
@@ -118,6 +130,13 @@ export default {
                         info: data
                     },
                 })
+            } else {
+                this.$router.push({
+                    name: this.isArea ? 'areaInfoActivity' : 'infoActivity',
+                    params: {
+                        info: data
+                    }
+                })
             }
         },
         createActivity() {

+ 177 - 21
TEAMModelOS/ClientApp/src/view/signupActivity/setActivity.vue

@@ -2,21 +2,71 @@
     <div class="setting">
         <Tabs v-model="activeName">
             <TabPane label="分站管理" name="subs">
-                <Form :model="formItem" :label-width="120" style="width: 98%;">
-                    <FormItem label="授权单位/组织">
-                        <Input v-model="formItem.unit" placeholder="请输入..." :disabled="!editType"></Input>
-                    </FormItem>
-                    <FormItem label="分站代码">
-                        <Input v-model="formItem.code" placeholder="请输入..." :disabled="!editType"></Input>
-                    </FormItem>
-                    <FormItem label="分站路由">
-                        <Input v-model="formItem.route" placeholder="请输入..." disabled></Input>
-                    </FormItem>
-                    <FormItem>
-                        <Button @click="editType = true" v-show="!editType">更改</Button>
-                        <Button type="primary" @click="editType = false" v-show="editType">保存</Button>
-                    </FormItem>
-                </Form>
+                <!-- 醍摩豆学区可以查看所有区级路由 -->
+                <div v-if="isTMD" style="margin-bottom: 50px;">
+                    <Table :columns="websiteColumn" :data="websiteList" class="banner-set">
+                        <template #route="{row}">
+                            <span v-if="row.route">/{{ row.route }}</span>
+                            <span v-else>-</span>
+                        </template>
+                        <!-- <template #code="{row}">
+                            <p v-if="row.isEdit">
+                                <Input v-model="row.code" placeholder="default size" />
+                                <span>
+                                    <Icon size="20" color="#78ba20" type="md-checkmark-circle" />
+                                    <Icon size="20" color="#8f8f8f" type="md-close-circle" />
+                                </span>
+                            </p>
+                            <span v-else>{{ row.code }}</span>
+                        </template> -->
+                        <template #name="{row}">
+                            <div v-if="row.isEdit" class="website-name-edit">
+                                <Input v-model="row.name" placeholder="default size" style="width: 80%" />
+                                <!-- <div>
+                                    <Icon size="20" color="#78ba20" type="md-checkmark-circle" />
+                                    <Icon size="20" color="#8f8f8f" type="md-close-circle" />
+                                </div> -->
+                            </div>
+                            <span v-else>
+                                {{ row.name }}
+                                <Icon type="md-contact" v-if="areaId === row.id" />
+                            </span>
+                        </template>
+                        <template #allowPublic="{row}">
+                            <el-switch v-model="row.allowPublic" :disabled="!row.isEdit || areaId === row.id" active-text="允许" inactive-text="禁止" :active-value="1" :inactive-value="0" active-color="#13ce66" />
+                        </template>
+                        <template #action="{row, index}">
+                            <div v-if="!row.isEdit">
+                                <Button type="primary" size="small" @click="row.isEdit = true">编辑</Button>
+                                <!-- <Button type="error" size="small">删除</Button> -->
+                            </div>
+                            <div v-else>
+                                <Button type="success" size="small" @click="saveWebsit(row, true)" style="margin-right: 10px;">保存</Button>
+                                <Button size="small" @click="cancelEdit(row, index)" class="cancel-edit">取消</Button>
+                            </div>
+                        </template>
+                    </Table>
+                </div>
+                <template v-else>
+                    <Form :model="websitInfo" :label-width="120" style="width: 98%;" v-if="websitInfo">
+                        <FormItem label="授权单位/组织">
+                            <Input v-model="websitInfo.name" placeholder="请输入..." :disabled="!editType"></Input>
+                        </FormItem>
+                        <!-- <FormItem label="分站代码">
+                            <Input v-model="websitInfo.code" placeholder="请输入..." :disabled="!editType"></Input>
+                        </FormItem> -->
+                        <FormItem label="分站路由">
+                            <Input v-model="websitInfo.route" placeholder="暂无路由" disabled></Input>
+                        </FormItem>
+                        <FormItem>
+                            <Button @click="editType = true" v-show="!editType">更改</Button>
+                            <div v-show="editType">
+                                <Button type="primary" @click="saveWebsit(websitInfo, false)">保存</Button>
+                                <Button @click="cancelInfo()" class="cancel-edit">取消</Button>
+                            </div>
+                        </FormItem>
+                    </Form>
+                </template>
             </TabPane>
             <TabPane label="首页管理" name="homepage">
                 <Button @click="bannerShow = true">新增</Button>
@@ -33,7 +83,7 @@
                     <template #image="{row}">
                         <img :src="row.image" alt="">
                     </template>
-                    <template #action="{row}">
+                    <template #action="{}">
                         <Button type="error" size="small">删除</Button>
                     </template>
                 </Table>
@@ -53,11 +103,42 @@ export default {
     data () {
         return {
             activeName: 'subs',
-            formItem: {
-                unit: '醍摩豆(成都)信息技术有限公司',
-                code: 'TMD',
-                route: '/TeamModel',
-            },
+            websitInitial: undefined,
+            websitInfo: undefined,
+            websiteColumn: [
+                {
+                    title: '分站路由',
+                    slot: 'route',
+                    align: 'center',
+                },
+                /* {
+                    title: '分站代码',
+                    slot: 'code',
+                    align: 'center',
+                    // width: '100',
+                }, */
+                {
+                    title: '授权单位/组织',
+                    slot: 'name',
+                    align: 'center',
+                    // width: '200',
+                },
+                {
+                    title: '发布公开活动',
+                    slot: 'allowPublic',
+                    align: 'center',
+                    // width: '100',
+                },
+                {
+                    title: '操作',
+                    slot: 'action',
+                    width: '300',
+                    align: 'center',
+                }
+            ],
+            websiteInitial: [], //未被操作的数据
+            websiteList: [], //页面展示的数据
+
             columns: [
                 {
                     title: '活动名称',
@@ -126,7 +207,67 @@ export default {
             awardsSel: [],
         }
     },
+    computed: {
+        isTMD() { //是醍摩豆智慧学区
+            return sessionStorage.getItem('areaId') === '02944f32-f534-3397-ea56-e6f1fc6c3714'
+        },
+        areaId() {
+            return sessionStorage.getItem('areaId')
+        },
+    },
+    created () {
+        this.getWebsite()
+    },
     methods: {
+        getWebsite() {
+            let params = {
+                grant_type: 'list',
+                websiteId: this.areaId
+            }
+            this.$api.areaActivity.websiteManage(params).then(res => {
+                if(res.code === 200) {
+                    if(!this.isTMD) {
+                        this.websitInfo = res.websites[0]
+                        this.websitInitial = this._.cloneDeep(this.websitInfo)
+                    } else {
+                        this.websiteList = res.websites.map(item => {
+                            item.isEdit = false
+                            return item
+                        })
+                        this.websiteInitial = this._.cloneDeep(this.websiteList)
+                    }
+                }
+            })
+        },
+        saveWebsit(row, isTable) {
+            let params = {
+                grant_type: 'update',
+                areaId: this.areaId,
+                website: row,
+            }
+            this.$api.areaActivity.websiteManage(params).then(res => {
+                if(res.code === 200) {
+                    this.$Message.success('更新成功')
+                    if(isTable) {
+                        row.isEdit = false
+                    } else {
+                        this.editType = false
+                    }
+                } else {
+                    this.$Message.warning('更新失败')
+                }
+            })
+        },
+        cancelEdit(row, index) {
+            row.name = this.websiteInitial[index].name
+            row.allowPublic = this.websiteInitial[index].allowPublic
+            row.isEdit = false
+        },
+        cancelInfo() {
+            this.websitInfo.name = this.websitInitial.name
+            this.websitInfo.allowPublic = this.websitInitial.allowPublic
+            this.editType = false
+        },
         addBanner() {
             this.bannnerdata.push(this.awardsList[this.awardsSel])
         },
@@ -143,6 +284,21 @@ export default {
         text-align: center;
         padding: 5px 0;
     }
+    .website-name-edit {
+        display: flex;
+        align-items: center;
+        .ivu-icon {
+            margin-left: 10px;
+        }
+    }
+    .cancel-edit {
+        background-color: #959595;
+        border-color: #959595;
+        color: #fff;
+        &:hover {
+            border-color: #959595;
+        }
+    }
 }
 </style>
 <style lang="less">

+ 90 - 6
TEAMModelOS/Controllers/Common/ActivityController.cs

@@ -33,6 +33,10 @@ using TEAMModelOS.SDK.Models.Service;
 using DocumentFormat.OpenXml.Office2010.Excel;
 using TEAMModelOS.Services;
 using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
+using Azure.Storage.Sas;
+using DocumentFormat.OpenXml.Bibliography;
+using System.Runtime.Intrinsics.X86;
+using Microsoft.IdentityModel.Tokens;
 
 namespace TEAMModelOS.Controllers
 {
@@ -543,6 +547,10 @@ namespace TEAMModelOS.Controllers
                             }
                             string sql = $"select value c from c where c.owner='{_areaId}' {yearSql}  ";
                             var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Activity>(sql, "Activity");
+                            result.list.ForEach(z => {
+                                var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner,  BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
+                                z.sas=blob_sas;
+                            });
                             return Ok(new { activities = result.list.OrderByDescending(z => z.stime) });
                         }
                     //校级活动列表
@@ -628,6 +636,10 @@ namespace TEAMModelOS.Controllers
                                     var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Activity>(sqlSchool, "Activity");
                                     activities.AddRange(resultSchool.list);
                                 }
+                                activities.ForEach(z => {
+                                    var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
+                                    z.sas=blob_sas;
+                                });
                                 return Ok(new { activities = activities.OrderByDescending(z => z.stime) });
                             }
                             break;
@@ -670,7 +682,7 @@ namespace TEAMModelOS.Controllers
 
                                 if (!string.IsNullOrWhiteSpace(schoolIdIn))
                                 {   //部分学校
-                                    string sqlSchool = $"select value c from c join i in c.confirmedSchools  where c.scope='public' and c.joinMode='enroll'  and (c.publish=1 or c.publish=2 )  and s.status=1 {yearSql}  {schoolIdIn}  ";
+                                    string sqlSchool = $"select value c from c join i in c.confirmedSchools  where c.scope='public' and c.joinMode='enroll'  and (c.publish=1 or c.publish=2 )  and i.status=1 {yearSql}  {schoolIdIn}  ";
                                     var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Activity>(sqlSchool, "Activity");
                                     activities.AddRange(resultSchool.list);
                                 }
@@ -686,7 +698,7 @@ namespace TEAMModelOS.Controllers
                             //获取所有区级的
                             if (!string.IsNullOrWhiteSpace(areaOwnerIn) && !string.IsNullOrEmpty(schoolIdIn)) {
                                 
-                                string sqlOpen = $"select value c from c join i  in c.confirmedSchools where c.scope='area'  and c.joinMode='enroll' and (c.publish=1 or c.publish=2 ) and s.status=1 {yearSql}  {areaOwnerIn}   {schoolIdIn} ";
+                                string sqlOpen = $"select value c from c join i  in c.confirmedSchools where c.scope='area'  and c.joinMode='enroll' and (c.publish=1 or c.publish=2 ) and i.status=1 {yearSql}  {areaOwnerIn}   {schoolIdIn} ";
                                 var resultOpen = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Activity>(sqlOpen, "Activity");
                                 activities.AddRange(resultOpen.list);
                             }
@@ -698,6 +710,11 @@ namespace TEAMModelOS.Controllers
                                 var resultSchool = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Common).GetList<Activity>(sqlSchool, "Activity");
                                 activities.AddRange(resultSchool.list);
                             }
+
+                            activities.ForEach(z => {
+                                var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(z.owner,  BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
+                                z.sas=blob_sas;
+                            });
                             return Ok(new { activities = activities.OrderByDescending(z => z.stime) });
                         }
                     //读取优课评选模块及评审规则
@@ -1028,9 +1045,7 @@ namespace TEAMModelOS.Controllers
                 jwt.Payload.TryGetValue("lang", out object _jwtlang);
                 head_lang = !string.IsNullOrWhiteSpace($"{_jwtlang}") ? $"{_jwtlang}" : head_lang;
             }
-            Teacher teacher = null;
-            teacherInfo = await TeacherService.TeacherInfo(_azureCosmos, teacher, $"{name}", $"{picture}", tmdid, _azureStorage, _option, _azureRedis, ip, _httpTrigger, head_lang);
-
+            teacherInfo = await TeacherService.TeacherInfoLite(_azureCosmos,  $"{name}", $"{picture}", tmdid, _azureStorage, _option, _azureRedis, ip, _httpTrigger, head_lang);
             string sql = $"select value c from c where c.route='{_route}'";
             var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).GetList<ActivityWebsite>(sql, "ActivityWebsite");
             ActivityWebsite website = null;
@@ -1046,10 +1061,79 @@ namespace TEAMModelOS.Controllers
 
                 }
             }
+            List<string > roles= new List<string>() { "teacher" };
+
+            CoreUser coreUser = await _coreAPIHttpService.GetUserInfo(new Dictionary<string, string> { { "key", teacherInfo.teacher.id } }, _option.Location, _configuration);
+            string sqlExpert = $"select value c from c join e in c.experts   where e.id='{teacherInfo.teacher.id}'";
+            if (!string.IsNullOrWhiteSpace(coreUser.mobile)) {
+                sqlExpert=$"  or  e.mobile='{coreUser.mobile}' ";
+
+            }
+            var resultActivityExpert = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).GetList<ActivityExpert>(sqlExpert, "ActivityExpert",pageSize:1);
 
-            return Ok(new { website, code =200, teacher});
+            if (resultActivityExpert.list.IsNotEmpty()) {
+                roles.Add("expert");
+            }
+            var payload = new JwtPayload {
+                { JwtRegisteredClaimNames.Iss, _option.HostName }, //發行者
+                { JwtRegisteredClaimNames.Sub, teacherInfo.teacher.id }, // 用戶ID                  
+                { JwtRegisteredClaimNames.Exp,DateTimeOffset.UtcNow.AddHours(2).ToUnixTimeSeconds()},  // 到期的時間,必須為數字
+                { "name",name}, // 用戶的顯示名稱
+                { "picture",picture}, // 用戶頭像
+                { "roles", roles}, // 登入者的角色,角色類型 (Admin、Teacher、Student) 
+                { JwtRegisteredClaimNames.Website,website.route},
+            };
+            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_option.JwtSecretKey));
+            var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
+            var header = new JwtHeader(signingCredentials);
+            var secToken = new JwtSecurityToken(header, payload);
+            // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
+            var tokenHandler = new JwtSecurityTokenHandler();
+            var serializeToken = tokenHandler.WriteToken(secToken);
+            return Ok(new { website, code =200,token =serializeToken, schools= teacherInfo.teacher.schools.Where(z=>z.status.Equals("join"))});
         }
 
+
+      
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        [ProducesDefaultResponseType]
+        [HttpPost("get-website")]
+        public async Task<IActionResult> GetWebsite(JsonElement request) {
+            if (!request.TryGetProperty("route", out JsonElement _route)) return BadRequest();
+            string sql = $"select value c from c where c.route='{_route}'";
+            var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).GetList<ActivityWebsite>(sql, "ActivityWebsite");
+            ActivityWebsite website = null;
+            if (result.list.Count>1)
+            {
+                return Ok(new { code = 1, msg = "路由匹配多个区校" });
+            }
+            else
+            {
+                if (result.list.Count==1)
+                {
+                    website= result.list[0];
+                }
+            }
+            if (website!= null)
+            {
+                List<ActivityWebsite> websites = new List<ActivityWebsite>();
+                if (website.route.Equals("teammodel") )
+                {
+                    string sqlAll = $"select value c from c where IS_DEFINED(c.route) = true  and c.route<> null  and  c.route<>'' ";
+                    var resultAll = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.Normal).GetList<ActivityWebsite>(sqlAll, "ActivityWebsite");
+                    websites=resultAll.list;
+                }
+                return Ok(new { code = 200, website ,websites });
+            }
+            else {
+                return Ok(new { code = 2, msg = "未匹配分站" }) ;
+            }
+          
+        }
         /// <summary>
         /// portal站的
         /// </summary>

+ 32 - 32
TEAMModelOS/appsettings.Development.json

@@ -22,48 +22,48 @@
   },
   "Azure": {
     // 测试站数据库
-    //"Storage": {
-    //  "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
-    //},
-    //"Cosmos": {
-    //  "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
-    //},
-    //"Redis": {
-    //  "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
-    //},
-    //"ServiceBus": {
-    //  "ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
-    //  "ActiveTask": "dep-active-task",
-    //  "ItemCondQueue": "dep-itemcond",
-    //  "GenPdfQueue": "dep-genpdf"
-    //},
-    //"SignalR": {
-    //  "ConnectionString": "Endpoint=https://channel.service.signalr.net;AccessKey=KrblW06tuA4a/GyqRPDU0ynFFmAWxbAvyJihHclSXbQ=;Version=1.0;"
-    //}
-    // 正式站数据库
     "Storage": {
-      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn"
+      "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodeltest;AccountKey=O2W2vadCqexDxWO+px+QK7y1sHwsYj8f/WwKLdOdG5RwHgW/Dupz9dDUb4c1gi6ojzQaRpFUeAAmOu4N9E+37A==;EndpointSuffix=core.chinacloudapi.cn"
     },
     "Cosmos": {
-      "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"
+      "ConnectionString": "AccountEndpoint=https://cdhabookdep-free.documents.azure.cn:443/;AccountKey=JTUVk92Gjsx17L0xqxn0X4wX2thDPMKiw4daeTyV1HzPb6JmBeHdtFY1MF1jdctW1ofgzqkDMFOtcqS46by31A==;"
     },
     "Redis": {
-      "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False"
+      "ConnectionString": "52.130.252.100:6379,password=habook,ssl=false,abortConnect=False,writeBuffer=10240"
     },
     "ServiceBus": {
-      "ConnectionString": "Endpoint=sb://coreiotservicebuscnpro.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=llRPBMDJG9w1Nnifj+pGhV0g4H2REcq0PjvX2qqpcOg=",
-      "ActiveTask": "active-task",
-      "ItemCondQueue": "itemcond",
-      "GenPdfQueue": "genpdf"
+      "ConnectionString": "Endpoint=sb://teammodelos.servicebus.chinacloudapi.cn/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=Sy4h4EQ8zP+7w/lOLi1X3tGord/7ShFHimHs1vC50Dc=",
+      "ActiveTask": "dep-active-task",
+      "ItemCondQueue": "dep-itemcond",
+      "GenPdfQueue": "dep-genpdf"
     },
     "SignalR": {
-      "ConnectionString": "Endpoint=https://channel.signalr.azure.cn;AccessKey=AtcB7JYFNUbUXb1rGxa3PVksQ2X5YSv3JOHZR9J88tw=;Version=1.0;"
-    },
-    "Speech": {
-      "SubscriptionKey": "a4f5f4e2e2e54c6e8b0a4a0b4a0a4a0b",
-      "Region": "chinanorth3",
-      "Endpoint": "https://chinanorth3.api.cognitive.azure.cn/sts/v1.0/issuetoken"
+      "ConnectionString": "Endpoint=https://channel.service.signalr.net;AccessKey=KrblW06tuA4a/GyqRPDU0ynFFmAWxbAvyJihHclSXbQ=;Version=1.0;"
     }
+    // 正式站数据库
+    //"Storage": {
+    //  "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=teammodelos;AccountKey=Dl04mfZ9hE9cdPVO1UtqTUQYN/kz/dD/p1nGvSq4tUu/4WhiKcNRVdY9tbe8620nPXo/RaXxs+1F9sVrWRo0bg==;EndpointSuffix=core.chinacloudapi.cn"
+    //},
+    //"Cosmos": {
+    //  "ConnectionString": "AccountEndpoint=https://teammodelos.documents.azure.cn:443/;AccountKey=clF73GwPECfP1lKZTCvs8gLMMyCZig1HODFbhDUsarsAURO7TcOjVz6ZFfPqr1HzYrfjCXpMuVD5TlEG5bFGGg==;"
+    //},
+    //"Redis": {
+    //  "ConnectionString": "CoreRedisCN.redis.cache.chinacloudapi.cn:6380,password=LyJWP1ORJdv+poXWofAF97lhCEQPg1wXWqvtzXGXQuE=,ssl=True,abortConnect=False"
+    //},
+    //"ServiceBus": {
+    //  "ConnectionString": "Endpoint=sb://coreiotservicebuscnpro.servicebus.chinacloudapi.cn/;SharedAccessKeyName=TEAMModelOS;SharedAccessKey=llRPBMDJG9w1Nnifj+pGhV0g4H2REcq0PjvX2qqpcOg=",
+    //  "ActiveTask": "active-task",
+    //  "ItemCondQueue": "itemcond",
+    //  "GenPdfQueue": "genpdf"
+    //},
+    //"SignalR": {
+    //  "ConnectionString": "Endpoint=https://channel.signalr.azure.cn;AccessKey=AtcB7JYFNUbUXb1rGxa3PVksQ2X5YSv3JOHZR9J88tw=;Version=1.0;"
+    //},
+    //"Speech": {
+    //  "SubscriptionKey": "a4f5f4e2e2e54c6e8b0a4a0b4a0a4a0b",
+    //  "Region": "chinanorth3",
+    //  "Endpoint": "https://chinanorth3.api.cognitive.azure.cn/sts/v1.0/issuetoken"
+    //}
   },
   "HaBookAuth": {
     "CoreId": {