Pārlūkot izejas kodu

Merge branch 'develop5.0-tmd' of http://106.12.23.251:10000/TEAMMODEL/TEAMModelOS into develop5.0-tmd

CrazyIter_Bin 4 gadi atpakaļ
vecāks
revīzija
1a6e49d104
23 mainītis faili ar 1290 papildinājumiem un 730 dzēšanām
  1. 1 1
      TEAMModelOS/ClientApp/src/api/syllabus.js
  2. 26 3
      TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html
  3. 7 3
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css
  4. 1 1
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js
  5. 7 0
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json
  6. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf
  7. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff
  8. BIN
      TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2
  9. 11 1
      TEAMModelOS/ClientApp/src/common/BaseLayout.vue
  10. 1 1
      TEAMModelOS/ClientApp/src/common/BaseNotification.vue
  11. 405 347
      TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue
  12. 24 0
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.less
  13. 332 15
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue
  14. 9 6
      TEAMModelOS/ClientApp/src/components/syllabus/InviteTeacher.vue
  15. 1 0
      TEAMModelOS/ClientApp/src/css/dark-iview-poptip.less
  16. 18 0
      TEAMModelOS/ClientApp/src/router/routes.js
  17. 2 0
      TEAMModelOS/ClientApp/src/utils/blobTool.js
  18. 8 6
      TEAMModelOS/ClientApp/src/utils/evTools.js
  19. 21 12
      TEAMModelOS/ClientApp/src/view/Home.vue
  20. 4 2
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  21. 157 154
      TEAMModelOS/ClientApp/src/view/settings/Index.vue
  22. 235 178
      TEAMModelOS/ClientApp/src/view/syllabus/Syllabus.vue
  23. 20 0
      TEAMModelOS/ClientApp/src/view/user/UserCenter.vue

+ 1 - 1
TEAMModelOS/ClientApp/src/api/syllabus.js

@@ -29,7 +29,7 @@ export default {
 	    return post('/teacher/share/view-share', data)
 	},
 	ShareAgree:function(data) {
-	    return post('/teacher/share/agree', data)
+	    return post('/teacher/share/agree-share', data)
 	},
 	// 查找知识块数量
 	FindBlockCount: function (data) {

+ 26 - 3
TEAMModelOS/ClientApp/src/assets/iconfont/demo_index.html

@@ -54,6 +54,12 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe6c3;</span>
+                <div class="name">开放</div>
+                <div class="code-name">&amp;#xe6c3;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe718;</span>
                 <div class="name">在籍学生</div>
@@ -810,9 +816,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1623427872430') format('woff2'),
-       url('iconfont.woff?t=1623427872430') format('woff'),
-       url('iconfont.ttf?t=1623427872430') format('truetype');
+  src: url('iconfont.woff2?t=1624327216353') format('woff2'),
+       url('iconfont.woff?t=1624327216353') format('woff'),
+       url('iconfont.ttf?t=1624327216353') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -838,6 +844,15 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont icon-open"></span>
+            <div class="name">
+              开放
+            </div>
+            <div class="code-name">.icon-open
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont icon-student1"></span>
             <div class="name">
@@ -1972,6 +1987,14 @@
       <div class="content symbol">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-open"></use>
+                </svg>
+                <div class="name">开放</div>
+                <div class="code-name">#icon-open</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-student1"></use>

+ 7 - 3
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 2000444 */
-  src: url('iconfont.woff2?t=1623427872430') format('woff2'),
-       url('iconfont.woff?t=1623427872430') format('woff'),
-       url('iconfont.ttf?t=1623427872430') format('truetype');
+  src: url('iconfont.woff2?t=1624327216353') format('woff2'),
+       url('iconfont.woff?t=1624327216353') format('woff'),
+       url('iconfont.ttf?t=1624327216353') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-open:before {
+  content: "\e6c3";
+}
+
 .icon-student1:before {
   content: "\e718";
 }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.js


+ 7 - 0
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.json

@@ -5,6 +5,13 @@
   "css_prefix_text": "icon-",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "20587121",
+      "name": "开放",
+      "font_class": "open",
+      "unicode": "e6c3",
+      "unicode_decimal": 59075
+    },
     {
       "icon_id": "8827519",
       "name": "在籍学生",

BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.ttf


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff


BIN
TEAMModelOS/ClientApp/src/assets/iconfont/iconfont.woff2


+ 11 - 1
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -335,7 +335,17 @@ export default {
                     menuName: 'totalIndex',
                     child: []
                 },
-
+                //开放平台
+                {
+                    icon: 'iconfont icon-open',
+                    name: this.$t('settings.setting_title3'),
+                    router: '/home/OpenPlat',
+                    tag: '',
+                    role: 'admin',
+                    permission: '',
+                    menuName: 'OpenPlat',
+                    child: []
+                }
             ] : []
             this.teacherMenu = [
                 // 我的班级

+ 1 - 1
TEAMModelOS/ClientApp/src/common/BaseNotification.vue

@@ -1,6 +1,6 @@
 <template>
 	<div class="base-notification">
-		<Poptip :title="$t('utils.newNotice')" class="dark-iview-poptip">
+		<Poptip :title="$t('utils.newNotice')" class="dark-iview-poptip" placement="bottom">
 			<Badge :count="msgArr.length">
 				<Icon type="md-notifications" />
 			</Badge>

+ 405 - 347
TEAMModelOS/ClientApp/src/common/BaseUserPoptip.vue

@@ -1,28 +1,50 @@
 <template>
-	<div class="base-user-center">
-		<div style="display: flex;">
-			<div class="base-user-info">
-				<p class="base-user-name">{{ userInfo.username }}</p>
-				<!-- <p class="base-user-post">教务主任</p> -->
-				<Dropdown @on-click="onRoleSelect">
-					<a href="javascript:void(0)" class="base-user-post">
-						{{ getRoleName(curRole) }}
-						<Icon type="ios-arrow-down"></Icon>
-					</a>
-					<DropdownMenu slot="list">
-						<DropdownItem v-if="curRole != 'teacher' && curRole != 'admin'" name="teacher">{{ $t('utils.teacher') }}</DropdownItem>
-						<DropdownItem v-if="curRole != 'student'" name="student">{{ $t('utils.student') }}</DropdownItem>
-						<!-- <DropdownItem  name="student">學生</DropdownItem> -->
-					</DropdownMenu>
-				</Dropdown>
-			</div>
-			<Poptip class="dark-iview-poptip" @on-popper-show="doRefresh()">
-				<!-- <img :src="user.picture" /> -->
+    <div class="base-user-center">
+        <div style="display: flex;">
+            <div class="base-user-info">
+                <!-- <p class="base-user-name" style="margin-top:6px">{{ userInfo.username }}</p> -->
+                <!-- <Dropdown @on-click="onRoleSelect">
+                    <a href="javascript:void(0)" class="base-user-post">
+                        {{ getRoleName(curRole) }}
+                        <Icon type="ios-arrow-down"></Icon>
+                    </a>
+                    <DropdownMenu slot="list">
+                        <DropdownItem v-if="curRole != 'teacher' && curRole != 'admin'" name="teacher">{{ $t('utils.teacher') }}</DropdownItem>
+                        <DropdownItem v-if="curRole != 'student'" name="student">{{ $t('utils.student') }}</DropdownItem>
+                    </DropdownMenu>
+                </Dropdown> -->
+            </div>
+            <Dropdown placement="bottom-end">
+                <PersonalPhoto style="cursor: pointer;" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor" />
+                <DropdownMenu slot="list" class="user-center-wrap">
+                    <DropdownItem class="user-info-wrap" @click.native="toUserCenter()">
+                        <p>{{userInfo.username}}</p>
+                        <p class="user-id">{{`ID: ${user.id}`}}</p>
+                        <Icon class="user-info-arrow" type="ios-arrow-forward" color="#1cc0f3" />
+                    </DropdownItem>
+                    <DropdownItem class="drop-item" style="margin-top:8px" @click.native="onRoleSelect('student')">
+                        <Icon type="md-swap" class="drop-item-icon" />
+                        切换为学生
+                    </DropdownItem>
+                    <DropdownItem class="drop-item" @click.native="toSettings('1')">
+                        <Icon custom="iconfont icon-school" class="drop-item-icon" />
+                        学校管理
+                    </DropdownItem>
+                    <DropdownItem class="drop-item" @click.native="toSettings('0')">
+                        <Icon type="ios-settings" class="drop-item-icon" />
+                        系统设置
+                    </DropdownItem>
+                    <DropdownItem divided @click.native="onQuit">
+                        <Icon type="md-power" class="drop-item-icon" />
+                        {{$t('utils.logout')}}
+                    </DropdownItem>
+                </DropdownMenu>
+            </Dropdown>
+            <!-- <Poptip class="dark-iview-poptip" @on-popper-show="doRefresh()">
 				<PersonalPhoto style="cursor: pointer;" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor"/>
 
 				<div slot="content" class="user-center">
 					<div class="user-info">
-						<!-- <img :src="user.picture" />     border: 2px solid #fff;-->
 						<PersonalPhoto :width="'70px'" :height="'70px'" :fontSize="'1.50rem'" :name="userInfo.username" :picture="user.picture" :color="userInfo.nameColor"/>
 
 						<span class="user-info-username">{{ userInfo.username }}</span>
@@ -72,359 +94,395 @@
 					</div>
 					<div class="btn-logout" @click="onQuit">{{ $t('utils.logout') }}</div>
 				</div>
-			</Poptip>
-		</div>
-	</div>
+			</Poptip> -->
+        </div>
+    </div>
 </template>
 
 <script>
-    import BlobTool from '@/utils/blobTool.js';
-	import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
-	export default {
-		data() {
-			return {
-				curRole: '',
-				userInfo: {
-					username: '',
-					account: '',
-					role: '',
-					courseNum: 0,
-					activityNum: 0,
-					classNum: 0,
-					nameColor: '',
-				},
-				user: {},
-                sizeInfo: {
-                    total: 0,   //所有
-                    image: 0,   //内容模块图片
-                    res: 0,     //内容模块教材
-                    video: 0,   //内容模块视频
-                    audio: 0,   //内容模块音频
-                    doc: 0,     //内容模块文档
-                    other: 0,   //内容模块其他文件
-                    data: 0      //除了内容模块之外的文件
-                }
-			}
-		},
-		created() {
-            this.doRefresh()
-		},
-		methods: {
-			doRefresh(){
-				this.user = JSON.parse(decodeURIComponent(localStorage.userInfo, "utf-8"));
-				let user_profile = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
-				if(this.user.roles.length){
-					this.curRole = this.user.roles[0]
-				}
-				this.userInfo.username = this.user.name
-				this.userInfo.nameColor = this.randomColor()
-				this.userInfo.courseNum = user_profile.courses.length
-				this.getSize()
-			},
-			//获取Blob空间信息
-			getSize() {
-                BlobTool.getSizeByServe(this.$store.state.userInfo.TEAMModelId).then(
-                    res => {
-                        this.sizeInfo = res
-                    },
-                    err => {
-                        this.$Message.error(this.$t('utils.caclErrorL'))
-                    }
-                )
-			},
-            //计算空间占比
-            getPercent(size) {
-                if (this.sizeInfo.total > this.$GLOBAL.PRIVATE_SPACE) {
-                    return '0%'
-                } else {
-                    let p = (size * 100 / this.$GLOBAL.PRIVATE_SPACE)
-					p = p > 1 ? p.toFixed(2) : p > 0 ? 1 : 0
-                    return p + '%'
-                }
+import BlobTool from '@/utils/blobTool.js';
+import PersonalPhoto from '@/components/public/personalPhoto/Index.vue'
+export default {
+    data() {
+        return {
+            curRole: '',
+            userInfo: {
+                username: '',
+                account: '',
+                role: '',
+                courseNum: 0,
+                activityNum: 0,
+                classNum: 0,
+                nameColor: '',
             },
-			onRoleSelect(val){
-				if(localStorage.getItem('identity') != val){
-					this.curRole = val
-					let path = val === 'student' ? '/studentWeb' : '/home'
-					localStorage.setItem('identity', val)
-					this.$router.push({ path: path })					
-				}
-			},
-			onQuit() {
-				this.$emit('logout')
-			},
-			randomColor: function(){
-				let r = Math.floor(Math.random()*255);
-				let g = Math.floor(Math.random()*255);
-				let b = Math.floor(Math.random()*255);
-				return 'rgba('+ r +','+ g +','+ b +',0.8)';
-			},
-		},
-
-		computed: {
-            
-			getSizeVal() {
-				return val => {
-					return this.$tools.bytesToSize(val)
-				}
-			},
-			getRoleName() {
-				return val => {
-					return val === 'student' ? this.$t('utils.student') : this.$t('utils.teacher')
-				}
-			}
-		},
-    	components:{
-			PersonalPhoto
-		}
-	}
+            user: {},
+            sizeInfo: {
+                total: 0,   //所有
+                image: 0,   //内容模块图片
+                res: 0,     //内容模块教材
+                video: 0,   //内容模块视频
+                audio: 0,   //内容模块音频
+                doc: 0,     //内容模块文档
+                other: 0,   //内容模块其他文件
+                data: 0      //除了内容模块之外的文件
+            }
+        }
+    },
+    created() {
+        this.doRefresh()
+    },
+    methods: {
+        // 这里可以携带参数,直接跳转到对应的tab
+        toSettings(tab) {
+            this.$router.push({
+                path: '/home/settings',
+                query: { tab }
+            })
+        },
+		// 这里可以携带参数,直接跳转到对应的tab
+        toUserCenter() {
+            this.$router.push({
+                name: 'userCenter'
+            })
+        },
+        doRefresh() {
+            this.user = JSON.parse(decodeURIComponent(localStorage.userInfo, "utf-8"));
+            let user_profile = JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8"));
+            if (this.user.roles.length) {
+                this.curRole = this.user.roles[0]
+            }
+            this.userInfo.username = this.user.name
+            this.userInfo.nameColor = this.randomColor()
+            this.userInfo.courseNum = user_profile.courses.length
+            this.getSize()
+        },
+        //获取Blob空间信息
+        getSize() {
+            BlobTool.getSizeByServe(this.$store.state.userInfo.TEAMModelId).then(
+                res => {
+                    this.sizeInfo = res
+                },
+                err => {
+                    this.$Message.error(this.$t('utils.caclErrorL'))
+                }
+            )
+        },
+        //计算空间占比
+        getPercent(size) {
+            if (this.sizeInfo.total > this.$GLOBAL.PRIVATE_SPACE) {
+                return '0%'
+            } else {
+                let p = (size * 100 / this.$GLOBAL.PRIVATE_SPACE)
+                p = p > 1 ? p.toFixed(2) : p > 0 ? 1 : 0
+                return p + '%'
+            }
+        },
+        onRoleSelect(val) {
+            if (localStorage.getItem('identity') != val) {
+                this.curRole = val
+                let path = val === 'student' ? '/studentWeb' : '/home'
+                localStorage.setItem('identity', val)
+                this.$router.push({ path: path })
+            }
+        },
+        onQuit() {
+            this.$emit('logout')
+        },
+        randomColor: function () {
+            let r = Math.floor(Math.random() * 255);
+            let g = Math.floor(Math.random() * 255);
+            let b = Math.floor(Math.random() * 255);
+            return 'rgba(' + r + ',' + g + ',' + b + ',0.8)';
+        },
+    },
+
+    computed: {
+
+        getSizeVal() {
+            return val => {
+                return this.$tools.bytesToSize(val)
+            }
+        },
+        getRoleName() {
+            return val => {
+                return val === 'student' ? this.$t('utils.student') : this.$t('utils.teacher')
+            }
+        }
+    },
+    components: {
+        PersonalPhoto
+    }
+}
 </script>
 <style scoped>
-    .user-storage-distribution {
-		overflow:hidden;
-	}
-    .user-storage-text span {
-		margin-right:20px;
-		display:inline-block;
-	}
-    .storage-full {
-        background-color: red;
-    }
-
-    .storage-data {
-        background-color: #F8C006;
+.drop-item-icon {
+    margin-right: 5px;
+}
+.drop-item {
+    padding: 10px 16px;
+}
+.user-info-arrow {
+    float: right;
+    margin-top: -25px;
+}
+.user-info-wrap {
+    /* background: #608f94; */
+    padding: 12px 16px;
+    box-shadow: 0px 2px 5px #eee;
+}
+.user-id {
+    color: rgb(174 176 178);
+    margin-top: 5px;
+    font-size: 12px;
+}
+.user-center-wrap {
+    min-width: 200px;
+    border-radius: 6px;
+    overflow: hidden;
+}
+.user-storage-distribution {
+    overflow: hidden;
+}
+.user-storage-text span {
+    margin-right: 20px;
+    display: inline-block;
+}
+.storage-full {
+    background-color: red;
+}
+
+.storage-data {
+    background-color: #f8c006;
+}
+
+.storage-image {
+    background-color: #45c84a;
+}
+
+.storage-video {
+    background-color: #8e2bdd;
+}
+
+.storage-audio {
+    background-color: #e1027b;
+}
+
+.storage-doc {
+    background-color: #03c0c2;
+}
+
+.storage-res {
+    background-color: #1ffcc5;
+}
+
+.storage-other {
+    background-color: #e87b22;
+}
+
+.text-data {
+    color: #f8c006;
+}
+
+.text-image {
+    color: #45c84a;
+}
+
+.text-video {
+    color: #8e2bdd;
+}
+
+.text-audio {
+    color: #e1027b;
+}
+
+.text-doc {
+    color: #03c0c2;
+}
+
+.text-res {
+    color: #1ffcc5;
+}
+
+.text-other {
+    color: #e87b22;
+}
+</style>
+<style lang="less">
+.base-user-center .ivu-select-dropdown {
+    padding: 0px 0px 5px 0px;
+    border-radius: 7px;
+}
+.base-user-center {
+    .base-user-info {
+        margin-right: 20px;
+        text-align: right;
+
+        .base-user-name {
+            font-weight: bold;
+            color: #b2b5b4;
+        }
+
+        .base-user-post {
+            color: #686b6b;
+        }
     }
 
-    .storage-image {
-        background-color: #45C84A;
+    img {
+        width: 40px;
+        border-radius: 50%;
+        border: 2px solid #dddddd;
+        cursor: pointer;
     }
 
-    .storage-video {
-        background-color: #8E2BDD;
+    .ivu-dropdown-item {
+        text-align: left;
     }
 
-    .storage-audio {
-        background-color: #E1027B;
+    .ivu-poptip-popper {
+        width: 460px !important;
     }
 
-    .storage-doc {
-        background-color: #03C0C2;
+    .ivu-poptip-popper {
+        left: -400px !important;
+        padding: 0;
     }
 
-    .storage-res {
-        background-color: #1FFCC5;
+    .ivu-poptip-title {
+        display: none;
     }
 
-    .storage-other {
-        background-color: #E87B22;
+    .ivu-poptip-arrow {
+        left: 90% !important;
     }
 
-    .text-data {
-        color: #F8C006;
-    }
+    .user-center {
+        height: 620px;
+        padding-top: 30px;
+
+        .user-info {
+            .fl-col-center;
+
+            img {
+                width: 70px;
+                border: 2px solid #fff;
+            }
+
+            &-username {
+                margin: 10px 0;
+                font-size: 18px;
+                font-weight: bold;
+                letter-spacing: 0.6px;
+                color: #1cc0f3;
+            }
+
+            &-account {
+                color: #a5a5a5;
+            }
+
+            &-btn {
+                background: #1cc0f3;
+                padding: 5px 60px;
+                color: #fff;
+                margin-top: 20px;
+                border-radius: 5px;
+                cursor: pointer;
+            }
+        }
+
+        .user-nums {
+            display: flex;
+            justify-content: space-around;
+            padding-top: 60px;
+
+            &-item {
+                .fl-col-center;
+
+                span {
+                    &:first-child {
+                        font-size: 34px;
+                        font-weight: bold;
+                        color: #fff;
+                    }
 
-    .text-image {
-        color: #45C84A;
-    }
+                    &:last-child {
+                        font-size: 14px;
+                        color: #1cc0f3;
+                    }
+                }
+            }
+        }
+
+        .user-storage {
+            padding-top: 50px;
+
+            p {
+                text-align: center;
+                color: #a5a5a5;
+                font-size: 12px;
+            }
+
+            &-distribution {
+                margin: 15px 0;
+                height: 10px;
+                width: 100%;
+                border-radius: 50px;
+                background-color: #888888;
+                display: flex;
+
+                span {
+                    display: inline-block;
+                    width: 50px;
+                    height: 10px;
+                }
 
-    .text-video {
-        color: #8E2BDD;
-    }
+                &-green {
+                    border-radius: 5px 0 0 5px;
+                    background-color: #00d523;
+                }
 
-    .text-audio {
-        color: #E1027B;
-    }
+                &-orange {
+                    background-color: #e87b22;
+                }
 
-    .text-doc {
-        color: #03C0C2;
-    }
+                &-red {
+                    background-color: #ff40bc;
+                }
 
-    .text-res {
-        color: #1FFCC5;
+                &-blue {
+                    background-color: #1fccd5;
+                }
+            }
+
+            &-text {
+                margin-top: 10px;
+                font-size: 12px;
+                font-weight: bold;
+                white-space: normal;
+                /*display: flex;
+					flex-wrap: wrap;
+					justify-content: space-around;*/
+            }
+        }
+
+        .btn-logout {
+            .fl-col-center;
+            background: #1cc0f3;
+            padding: 6px 0;
+            color: #fff;
+            width: 60%;
+            margin-left: 20%;
+            margin-top: 40px;
+            border-radius: 5px;
+            font-size: 16px;
+            cursor: pointer;
+        }
     }
 
-    .text-other {
-        color: #E87B22;
+    .fl-col-center {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
     }
-</style>
-<style lang="less">
-	.base-user-center {
-		.base-user-info {
-			margin-right: 20px;
-			text-align: right;
-
-			.base-user-name {
-				font-weight: bold;
-				color: #b2b5b4;
-			}
-
-			.base-user-post {
-				color: #686b6b;
-			}
-		}
-
-
-		img {
-			width: 40px;
-			border-radius: 50%;
-			border: 2px solid #dddddd;
-			cursor: pointer;
-		}
-		
-		.ivu-dropdown-item{
-			text-align: left;
-		}
-
-		.ivu-poptip-popper {
-			width: 460px !important;
-		}
-
-		.ivu-poptip-popper {
-			left: -400px !important;
-			padding: 0;
-		}
-
-		.ivu-poptip-title {
-			display: none;
-		}
-
-		.ivu-poptip-arrow {
-			left: 90% !important;
-		}
-
-		.user-center {
-			height: 620px;
-			padding-top: 30px;
-
-			.user-info {
-				.fl-col-center;
-
-				img {
-					width: 70px;
-					border: 2px solid #fff;
-				}
-
-				&-username {
-					margin: 10px 0;
-					font-size: 18px;
-					font-weight: bold;
-					letter-spacing: .6px;
-					color: #1CC0F3;
-				}
-
-				&-account {
-					color: #a5a5a5;
-				}
-
-				&-btn {
-					background: #1CC0F3;
-					padding: 5px 60px;
-					color: #fff;
-					margin-top: 20px;
-					border-radius: 5px;
-					cursor: pointer;
-				}
-
-			}
-
-
-			.user-nums {
-				display: flex;
-				justify-content: space-around;
-				padding-top: 60px;
-
-				&-item {
-					.fl-col-center;
-
-					span {
-
-						&:first-child {
-							font-size: 34px;
-							font-weight: bold;
-							color: #fff
-						}
-
-						&:last-child {
-							font-size: 14px;
-							color: #1CC0F3
-						}
-					}
-
-					;
-				}
-			}
-
-			.user-storage {
-				padding-top: 50px;
-
-				p {
-					text-align: center;
-					color: #a5a5a5;
-					font-size: 12px;
-				}
-
-				&-distribution {
-					margin: 15px 0;
-					height: 10px;
-					width: 100%;
-					border-radius: 50px;
-					background-color: #888888;
-					display: flex;
-
-					span {
-						display: inline-block;
-						width: 50px;
-						height: 10px;
-					}
-
-					&-green {
-						border-radius: 5px 0 0 5px;
-						background-color: #00D523;
-					}
-
-					&-orange {
-						background-color: #e87b22;
-					}
-
-					&-red {
-						background-color: #ff40bc;
-					}
-
-					&-blue {
-						background-color: #1fccd5;
-					}
-				}
-
-				&-text {
-					margin-top: 10px;
-					font-size: 12px;
-					font-weight: bold;
-					white-space:normal;
-					/*display: flex;
-					flex-wrap: wrap;
-					justify-content: space-around;*/
-				}
-			}
-
-			.btn-logout {
-				.fl-col-center;
-				background: #1CC0F3;
-				padding: 6px 0;
-				color: #fff;
-				width: 60%;
-				margin-left: 20%;
-				margin-top: 40px;
-				border-radius: 5px;
-				font-size: 16px;
-				cursor: pointer;
-			}
-		}
-
-		.fl-col-center {
-			display: flex;
-			flex-direction: column;
-			align-items: center;
-			justify-content: center;
-		}
-	}
+}
 </style>

+ 24 - 0
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.less

@@ -72,6 +72,24 @@
 /* 修改iview Modal样式 */
 .tree-modal {
 	font-family: 'NotoSerif', '微软正黑体', 'Microsoft JhengHei UI', 'Microsoft JhengHei', Sans-serif;
+	
+	
+	
+	.ivu-input::-webkit-input-placeholder {
+		color: #808080;
+	}
+	
+	.ivu-select-single .ivu-select-selection {
+		background: #575757;
+		color: #fbfbfb;
+		border-color: transparent;
+		height: 35px;
+		margin-left: 15px;
+	}
+	
+	.ivu-select-single .ivu-select-arrow {
+		color: #fbfbfb;
+	}
   .ivu-modal-content {
     background: #3c3c3c;
     overflow: hidden;
@@ -103,6 +121,12 @@
       margin: 30px 0;
       font-size: 14px;
     }
+	.node-name{
+		font-size: 16px;
+		font-weight: bold;
+		color: #00fec1;
+		margin-left: 10px;
+	}
     .ivu-input {
       background: #575757;
       border-color: transparent;

+ 332 - 15
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue

@@ -12,8 +12,10 @@
 						<Icon type="md-git-compare" color="#00c38d" :title="$t('syllabus.tree.hasCoEdit')" v-if="hasEditAuth(data) && isSchool" />
 					</span>
 					<span class="custom-tree-tools" v-if="inShareView && isFirstLevel(data)">
+						<Icon type="md-copy" style="margin-right: 5px;" size="16" />
+						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;" @click="onCopyChapter(data)">复制该章节</span>
 						<Icon type="ios-remove-circle-outline" style="margin-right: 5px;" size="16" />
-						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;">忽略该章节</span>
+						<span style="color: #9f9f9f;font-size: 12px;margin-right: 20px;"  @click="onIgnoreShare(data)">忽略该章节</span>
 					</span>
 					<span class="custom-tree-tools" v-if="((hasEditAuth(data) || $access.can('admin.*|Syllabus_Edit')) && !inShareView)">
 						<Icon type="md-create" size="16" :title="$t('syllabus.tree.edit')" @click="onEditItem(node,data,$event)" />
@@ -38,11 +40,26 @@
 			<Button @click="onSubmitNode" class="modal-btn"
 				style="width: 88%;margin-left: 6%;margin-bottom: 20px;">{{ $t('syllabus.tree.confirm') }}</Button>
 		</Modal>
+		
+		<!-- 新增或者编辑弹窗 -->
+		<Modal v-model="chapterCopyModal" width="500" footer-hide class="tree-modal add-volume-modal choose-content-modal">
+			<div class="modal-header" slot="header">复制节点</div>
+			<div class="modal-content">
+				<p class="node-title">当前章节: <span class="node-name">{{ curChapter.title }}</span></p>
+				<p class="node-title" style="display: inline-block;">目标册别:</p>
+				<Select v-model="copyTargetVolume" style="width: 300px;">
+					<Option v-for="(item,index) in volumeList" :value="index" :key="index">{{item.name}}</Option>
+				</Select>
+			</div>
+			<Button @click="doCopyChapter" :loading="isCopyBtnLoading" class="modal-btn"
+				style="width: 88%;margin-left: 6%;margin-bottom: 20px;">{{ $t('syllabus.tree.confirm') }}</Button>
+		</Modal>
 	</div>
 </template>
 
 <script>
 	import '@/utils/Math.uuid'
+	import BlobTool from '@/utils/blobTool.js'
 	import BaseResource from '@/view/syllabus/newSyllabus/operation/BaseResource'
 	import BaseKnowledge from '@/view/syllabus/newSyllabus/operation/BaseKnowledge'
 	import BaseQuestionList from '@/common/BaseQuestionList'
@@ -65,9 +82,12 @@
 				},
 				isEditOrAdd: false,
 				isLoading: false,
+				isCopyBtnLoading:false,
 				isRelatedContent: false,
 				isShowContent: false,
+				chapterCopyModal:false,
 				isEditItem: false,
+				copyTargetVolume:0,
 				contentIndex: '1',
 				currentVolume: null,
 				currentEditData: null,
@@ -76,6 +96,10 @@
 				currentItems: [],
 				curNode: null,
 				curData:null,
+				curChapter:{
+					id: null,
+					title: '',
+				},
 				nodeInfo: {
 					id: null,
 					title: '',
@@ -94,7 +118,8 @@
 					rnodes:[]
 				},
 				isSchool: false,
-				flatArr:[]
+				flatArr:[],
+				flatRNodes:[],
 			}
 		},
 		created() {
@@ -109,11 +134,9 @@
 					node:node
 				})
 			},
-
 			doShare(data) {
 				this.$emit('doShare', data)
 			},
-			
 			/* 禁止一级节点往下级进行拖拽 */
 			allowDrop(draggingNode, dropNode, dropType) {
 				if (draggingNode.level === dropNode.level) {
@@ -150,7 +173,298 @@
 				this.$parent.hasModify = true
 
 			},
-
+			/* 忽略某个章节的分享 */
+			onIgnoreShare(data){
+				this.$Modal.confirm({
+					title: this.$t('syllabus.tree.removeTitle'),
+					content: '确认忽略该章节吗?',
+					onOk: () => {
+						this.$api.syllabus.ShareAgree({
+							"code": this.$store.state.userInfo.TEAMModelId,
+							"id": data.id,
+							"type": "share",
+							"opt": "ignore"
+						}).then(res => {
+							if(res.status === 200){
+								this.$Message.success('操作成功!')
+								this.$parent.getShareVolumeList()
+							}
+						})
+					}
+				})
+			},
+			/* 复制章节到课纲 */
+			onCopyChapter(data){
+				if(this.volumeList.length){
+					this.curChapter = data
+					this.chapterCopyModal = true
+				}else{
+					this.$Message.warning('请先创建您的个人课纲!')
+				}
+			},
+			/* 复制章节的业务逻辑 */
+			async doCopyChapter(){
+				let targetVolume = this.volumeList[this.copyTargetVolume]
+				let allRNodes = this.getAllRNodes(JSON.parse(JSON.stringify(this.curChapter)))
+				let hasItemOrPaper = allRNodes.filter(i => i.type === 'item' || i.type === 'paper').length > 0
+				this.flatRNodes = allRNodes
+				this.isCopyBtnLoading = true
+				this.curChapter.auth = []
+				this.curChapter.pid = targetVolume.id
+				// 在复制章节过程中 如果章节节点以及子节点有关联试题试卷 则需要询问用户是否进行入库操作
+				if(hasItemOrPaper){
+					this.$Modal.confirm({
+						title: '提示',
+						content: '该章节中有关联试题试卷信息,是否需要同步到您的个人试题试卷库?',
+						okText: '同步并复制',
+						cancelText: '不需要',
+						onOk: async () => {
+							let copyResult = await this.doCopyResources(allRNodes,true)
+							console.log('复制后的回调',copyResult)
+							this.sendCopyApi(targetVolume)
+						},
+						onCancel: async () => {
+							let copyResult = await this.doCopyResources(allRNodes,false)
+							console.log('复制后的回调',copyResult)
+							this.sendCopyApi(targetVolume)
+						}
+					})
+				}else{
+					let copyResult = await this.doCopyResources(allRNodes,false)
+					this.sendCopyApi(targetVolume)
+				}
+			},
+			/* 发送复制章节到个人课纲的请求API */
+			sendCopyApi(targetVolume){
+				console.log(JSON.stringify(this.flatRNodes))
+				let upsertParams = [{
+					id: this.curChapter.id,
+					volumeId: targetVolume.id,
+					scope: targetVolume.scope,
+					trees: [this.refreshCopyChapter(this.curChapter)]
+				}]
+				this.$api.syllabus.UpsertTree(upsertParams).then((res) => {
+					if (!res.error && res) {
+						this.$Message.success("复制成功");
+						this.chapterCopyModal = false
+					} else {
+						this.$Message.error("获取数据失败");
+					}
+				}).catch(e => {
+					this.$Message.error(e);
+				}).finally(() => {
+					this.isCopyBtnLoading = false
+				})
+			},
+			/* 将复制的节点内的创建信息、code等更新为当前用户 */
+			refreshCopyChapter(chapterNode){
+				console.log(this.flatRNodes);
+				let myId = this.$store.state.userInfo.TEAMModelId
+				const fn = (source)=>{
+					source.creatorId = myId
+					if(source.rnodes.length){
+						source.rnodes.forEach(i => {
+							i.cntr = myId
+							i.code = i.code.split('-').length > 1 ? i.code.split('-')[0] + '-' + myId : myId
+							i.link = this.flatRNodes.find(j => j.id === i.id).link
+						})
+					}
+					if(source.children.length){
+						source.creatorId = myId
+						source.children.forEach(i => {
+							fn(i)
+						})
+					}
+				}
+				fn(chapterNode)
+				return chapterNode
+			},
+			/* 复制节点到个人课纲 需要把关联的内容全部拷贝到个人的BLOB容器内 */
+			doCopyResources(rnodes,needSave){
+				return new Promise((r,j) => {
+					let promiseArr = []
+					let tmdId = this.$store.state.userInfo.TEAMModelId
+					console.log(JSON.stringify(this.flatRNodes));
+					rnodes.forEach((file,fileIndex) => {
+						let copyFile = JSON.parse(JSON.stringify(file))
+						if(copyFile.type === 'item'){
+							promiseArr.push(this.copyItemToBlob(copyFile,needSave))
+							// 如果不入库 则需要修改资源的link地址
+							if(!needSave){
+								this.flatRNodes[fileIndex].link = '/syllabus/' + rnodes[fileIndex].id + '/' + rnodes[fileIndex].id + '.json'
+							}
+						}else if(copyFile.type === 'paper'){
+							promiseArr.push(this.copyPaperToBlob(copyFile,needSave))
+							// 如果不入库 则需要修改资源的link地址
+							if(!needSave){
+								this.flatRNodes[fileIndex].link = rnodes[fileIndex].link.replace('paper','syllabus')
+							}
+						}else{
+							promiseArr.push(this.copyFileToBlob(copyFile))
+						}
+						this.flatRNodes[fileIndex].code = this.flatRNodes[fileIndex].code.includes('-') ? this.flatRNodes[fileIndex].code.split('-')[0] + '-' +  tmdId : tmdId
+						this.flatRNodes[fileIndex].cntr = tmdId
+					})
+					Promise.all(promiseArr).then(result => {
+						r(result)
+						console.log(result)
+					}).catch(err =>{
+						j(err)
+					})
+				})
+			},
+			/* 根据醍摩豆ID获取对应BLOB个人容器授权信息 */
+			getBlobPrivateSas(tmdId){
+				return new Promise((r,j) => {
+					this.$api.blob.blobSasR({
+						name:tmdId,
+						role:'teacher'
+					}).then(res => {
+						if(!res.error){
+							r(res)
+						}
+					})
+				})
+			},
+			/* 复制试题到当前用户BLOB */
+			copyItemToBlob(resourceItem,needSave){
+				// console.log(JSON.stringify(rnodes))
+				return new Promise(async (r, j) => {
+					let toPath = needSave ? `item/${resourceItem.id}/` : `syllabus/${resourceItem.id}/`
+					// 是否入库 来决定保存的路径
+					let fromPath = `item/${resourceItem.id}`
+					// 试题的拥有者也就是复制的来源容器
+					let myId = this.$store.state.userInfo.TEAMModelId
+					let fileOwner = resourceItem.code.replace('Item-','')
+					let privateSas = await this.getBlobPrivateSas(fileOwner)
+					let privateBlobTool = new BlobTool(privateSas.url, privateSas.name, '?' + privateSas.sas,'private')
+					// 拿到试题的完整数据 方便保存到COSMOS
+					const itemJsonFile = await this.$evTools.getFullItemByTmdId(fileOwner, resourceItem.link)
+					let file = new File([JSON.stringify(itemJsonFile)],resourceItem.id + ".json", {type: "",});
+					console.log(itemJsonFile);
+					// 先把对应试题目录下的全部复制到校本BLOB 然后再更新添加学段科目等字段后的题目Json文件
+					this.$parent.containerClient.copyFolder(toPath,fromPath,privateBlobTool).then(async res => {
+						try{
+							itemJsonFile.blob = '/' + toPath + resourceItem.id + '.json'
+							itemJsonFile.code = myId
+							itemJsonFile.scope = resourceItem.scope
+							this.$parent.saveExercise(itemJsonFile).then(result => {
+								console.log(result)
+								r(result)
+							})
+						}catch(e){
+							j(e)
+						}
+					}).catch(err => {
+						j(err)
+					})
+				})
+			},
+			/* 根据关联的试卷资源获取数据库的试卷信息 方便复制的入库问题 */
+			getCosmosPaper(paperResourceItem){
+				console.log(JSON.stringify(paperResourceItem))
+				return new Promise((r,j) => {
+					this.$api.learnActivity.FindExamPaper({
+						id:paperResourceItem.id,
+						code:paperResourceItem.code.replace('Paper-',''),
+						scope:paperResourceItem.scope
+					}).then(res => {
+						if(!res.error && res.papers.length){
+							r(res.papers[0])
+						}
+					}).catch(e => {
+						j(e)
+					})
+				})
+			},
+			/* 保存复制的试卷到cosmos */
+			async savePaperToCosmos(paperResourceItem){
+				console.log(JSON.stringify(paperResourceItem))
+				let cosmosPaper = await this.getCosmosPaper(paperResourceItem)
+				cosmosPaper.code = this.$store.state.userInfo.TEAMModelId
+				cosmosPaper.scope = 'pravite'
+				return new Promise(async (r,j) => {
+					let params = {
+						paper: cosmosPaper,
+						option: 'insert'
+					}
+					//  保存试卷到cosmos
+					this.$api.learnActivity.SaveExamPaper(params).then(
+						res => {
+							if (res.error == null) {
+								r(res)
+							} else {
+								r(res.error)
+							}
+						},
+						err => {
+							j(err)
+						}
+					)
+				})
+			},
+			/* 复制试题到当前用户BLOB */
+			copyPaperToBlob(resourceItem,needSave){
+				return new Promise(async (r, j) => {
+					let toPath = needSave ? `paper/${resourceItem.title}/` : `syllabus/${resourceItem.title}/`
+					// 是否入库 来决定保存的路径
+					let fromPath = `paper/${resourceItem.title}`
+					// 试题的拥有者也就是复制的来源容器
+					let myId = this.$store.state.userInfo.TEAMModelId
+					let fileOwner = JSON.parse(JSON.stringify(resourceItem.code)).replace('Paper-','')
+					let privateSas = await this.getBlobPrivateSas(fileOwner)
+					let privateBlobTool = new BlobTool(privateSas.url, privateSas.name, '?' + privateSas.sas,'private')
+					// 拿到试题的完整数据 方便保存到COSMOS
+					const paperJsonFile = await this.$evTools.getFullPaperByTmdId(fileOwner, resourceItem.link)
+					// let file = new File([JSON.stringify(paperJsonFile)],resourceItem.id + ".json", {type: "",});
+					// 先把对应试题目录下的全部复制到校本BLOB 然后再更新添加学段科目等字段后的题目Json文件
+					this.$parent.containerClient.copyFolder(toPath,fromPath,privateBlobTool).then(async res => {
+						try{
+							console.log(JSON.stringify(resourceItem))
+							this.savePaperToCosmos(resourceItem).then(result => {
+								console.log(result)
+								r(result)
+							})
+						}catch(e){
+							j(e)
+						}
+					}).catch(err => {
+						j(err)
+					})
+				})
+			},
+			/* 复制内容文件到当前用户BLOB */
+			copyFileToBlob(resourceItem){
+				return new Promise(async (r, j) => {
+					// 试题的拥有者也就是复制的来源容器
+					let fileOwner = resourceItem.code.replace('Paper-','')
+					let privateSas = await this.$evTools.getBlobPrivateSas(fileOwner)
+					let fullLink = 	this.$evTools.getBlobHost() + '/' + fileOwner + resourceItem.link
+					console.log(fullLink)
+					// 拿到试题的完整数据 方便保存到COSMOS
+					this.$parent.containerClient.copyBlob('syllabus/' + resourceItem.title, fullLink, privateSas).then(res => {
+						r(200)
+					}).catch(err => {
+						console.log(err)
+						j(err)
+					})
+				})
+			},
+			/* 获取章节下所有的资源节点 */
+			getAllRNodes(chapterNode){
+				let result = []
+				const fn = (source)=>{
+					result.push(...source.rnodes)
+					if(source.children.length){
+						console.log(JSON.stringify(source.children[0].rnodes));
+						source.children.forEach(i => {
+							fn(i)
+						})
+					}
+				}
+				fn(chapterNode)
+				return result
+			},
 			// 删除节点操作
 			remove(node, data) {
 				let isFirstLevel = this.isFirstLevel(data)
@@ -173,6 +487,10 @@
 										this.$parent.modifyIdArr  = this.$parent.modifyIdArr.filter(i => i !== data.id)
 									}
 									children.splice(index, 1)
+									this.$nextTick().then(() => {
+										const firstNode = document.querySelector('.el-tree-node')
+										firstNode.click();
+									})
 									this.$Message.success(this.$t('syllabus.tree.removeSucTip'))
 								} else {
 									this.$Message.warning(res.error);
@@ -189,7 +507,6 @@
 					}
 				})
 			},
-
 			// 点击添加展开弹窗
 			onAddNode(node,data, e) {
 				e.stopPropagation() // 防止点击事件穿透到父层
@@ -201,7 +518,6 @@
 				this.nodeInfo.title = ''
 				this.curNode = node
 			},
-
 			// 编辑节点操作
 			onEditItem(node, data, e) {
 				e.stopPropagation() // 防止点击事件穿透到父层
@@ -213,7 +529,6 @@
 				this.nodeInfo.id = node.data.id
 				this.curNode = node
 			},
-			
 			/* 根据节点获取它所在的章节信息 */
 			getChapterByNode(node){
 				console.log(node)
@@ -223,7 +538,6 @@
 					return this.getChapterByNode(node.parent)
 				}
 			},
-
 			// 提交编辑或者新增
 			onSubmitNode() {
 				if (!this.nodeInfo.title) {
@@ -253,7 +567,6 @@
 				this.$emit('addModifyId',this.getChapterIdById(this.curData.id))
 				this.$Message.success(this.isEditItem ? this.$t('syllabus.tree.editSucTip') : this.$t('syllabus.tree.addSucTip'))
 			},
-			
 			/* 获取整个树的章节与子节点归属 */
 			getAllChild(arr){
 				let result = []
@@ -265,7 +578,6 @@
 				})
 				this.flatArr = result
 			},
-			
 			/* 递归拉平所有children */
 			flatChildren(children){
 				let result = []
@@ -280,14 +592,13 @@
 				fn(children)
 				return result
 			},
-			
 			/* 根据某个节点ID换取它对应的章节ID */
 			getChapterIdById(id){
 				if(this.flatArr.map(i => i.chapterId).includes(id)){
 					return id
 				}else{
 					let targetChapter = this.flatArr.find(i => i.children.includes(id))
-					return targetChapter.chapterId
+					return targetChapter ? targetChapter.chapterId : 0
 				}
 			}
 
@@ -317,6 +628,10 @@
 			},
 			inShareView(){
 				return !this.isSchool && this.$parent.activeTab === 'fromShare'
+			},
+			volumeList(){
+				console.log(this.$parent)
+				return this.$parent.myVolumeList
 			}
 		},
 		watch: {
@@ -335,13 +650,15 @@
 					})
 				},
 				immediate: true,
-				deep:true
+				// deep:true
 			},
 			// 监听课纲数据变化
 			volume: {
 				handler: function(n, o) {
 					this.volume = n
-				}
+					
+				},
+				immediate: true
 			}
 		}
 	}

+ 9 - 6
TEAMModelOS/ClientApp/src/components/syllabus/InviteTeacher.vue

@@ -182,8 +182,8 @@
 						this.nodeInfo.auth.push({
 							tmdid:val.id,
 							tmdname:val.name,
-							share:false,
-							coedit:true
+							aggre:0,
+							type:'coedit'
 						})
 					}else{
 						this.nodeInfo.auth.splice(this.nodeInfo.auth.map(i => i.tmdid).indexOf(val.id),1)
@@ -193,6 +193,10 @@
 			/* 分享课纲操作 */
 			doShare(){
 				let val = this.curTeacher
+				if(this.nodeInfo.auth.map(i => i.tmdid).includes(val.id)){
+					this.$Message.warning('该章节已分享给当前教师!请勿重复分享!')
+					return
+				}
 				this.isShareLoading = true
 				this.sendShareApi(val.id,val.name,true,true).then(res => {
 					setTimeout(() => {
@@ -200,8 +204,8 @@
 						this.nodeInfo.auth.push({
 							tmdid:val.id,
 							tmdname:val.name,
-							share:true,
-							coedit:false
+							aggre:0,
+							type:'share'
 						})
 						this.isShareLoading = false
 						this.curTeacher = null
@@ -237,8 +241,7 @@
 								"tmdname": toName
 							}
 						],
-						"coedit": !isShare,
-						"share": isShare,
+						"type": isShare ? 'share' : 'coedit',
 						"issuer": this.$store.state.userInfo.TEAMModelId,
 						"opt": isAdd ? 'add' : 'del',
 						"syllabusId": this.nodeInfo.id,

+ 1 - 0
TEAMModelOS/ClientApp/src/css/dark-iview-poptip.less

@@ -26,6 +26,7 @@
 	}
 	
 	.ivu-poptip-arrow{
+		left: 62% !important;
 		top:-10px !important;
 		border-width: 0 10px 10px !important;
 		border-bottom-color: #3b3b3b !important;

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

@@ -660,6 +660,24 @@ export const routes = [
 				activeName: 'settings'
 			}
 		},
+		//设置
+		{
+			path: 'OpenPlat',
+			name: 'OpenPlat',
+			component: resolve => require(['@/view/settings/OpenMgmt2.vue'], resolve),
+			meta: {
+				activeName: 'OpenPlat'
+			}
+		},
+		//设置
+		{
+			path: 'userCenter',
+			name: 'userCenter',
+			component: resolve => require(['@/view/user/UserCenter.vue'], resolve),
+			meta: {
+				
+			}
+		},
 		//课堂记录
 		{
 			path: 'classRecord',

+ 2 - 0
TEAMModelOS/ClientApp/src/utils/blobTool.js

@@ -496,6 +496,7 @@ export default class BlobTool {
      * @param {boolean} handleSize 是否内部处理blobsize
      */
     copyFolder(targetFolder, sourceFolder, blobTool, handleSize = true) {
+		console.log(...arguments);
         return new Promise(async (r, j) => {
             let blobs = undefined
             let sasString = ''
@@ -510,6 +511,7 @@ export default class BlobTool {
                 }, false)
                 sasString = this.sasString
             }
+			console.log(blobs);
             //上传之前检查文件夹大小
             let beforeSize = 0
             let cont = ''

+ 8 - 6
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -34,7 +34,7 @@ export default {
 					gradeIds:item.gradeIds,
 					subjectId:item.subjectId,
 					children:item.children || [],
-					scope:item.scope,
+					// scope:item.scope,
 					score: item.score||0,
 					blankCount: item.blankCount||1,
 					repair:item.repair,
@@ -52,13 +52,13 @@ export default {
 		})
 	},
 	/* 获取保存在COSMOS里面的试题格式 */
-	createCosmosItem(item){
+	createCosmosItem(item,scope,code){
 		return new Promise((r,j) => {
 			let cosmosItem  = {
 				id:item.id,
 				pid:item.pid || null,
-				code:item.code,
-				scope:item.scope,
+				code:code || item.code,
+				scope:scope || item.scope,
 				score:item.score||0,
 				type:item.type,
 				objective:this.getItemType(item.type),
@@ -84,8 +84,8 @@ export default {
 			let paperItem  = {
 				id:paper.id,
 				name:paper.name,
-				code:paper.code,
-				scope:paper.scope,
+				// code:paper.code,
+				// scope:paper.scope,
 				multipleRule:paper.multipleRule,
 				slides:slides,
 				points:paper.points,
@@ -136,6 +136,7 @@ export default {
 			jsonData.exercise.code = tmdId
 			jsonData.exercise.option = jsonData.item[0].option
 			jsonData.exercise.id = jsonData.id
+			jsonData.exercise.scope = 'private'
 			jsonData.exercise.pid = jsonData.pid
 			jsonData.exercise = await this.doAddHost(jsonData.exercise,null,tmdId)
 			r(jsonData.exercise)
@@ -183,6 +184,7 @@ export default {
 							jsonData.exercise.createTime = list[i].createTime || 0
 							jsonData.exercise.blob = list[i].blob
 							jsonData.exercise.code = list[i].code
+							jsonData.exercise.scope = list[i].scope
 							jsonData.exercise.option = jsonData.item[0].option
 							jsonData.exercise.id = list[i].id
 							jsonData.exercise.pid = jsonData.pid

+ 21 - 12
TEAMModelOS/ClientApp/src/view/Home.vue

@@ -4,9 +4,10 @@
         <BaseLayout>
             <!-- 头部右侧个人中心部分 -->
             <div class="header-right-box fl-around" slot="header-content">
-                <Icon custom="iconfont icon-home" :color="routerName == 'homePage' ? '#1CC0F3':'#d0d0d0'" @click="toHome" />
+                <Icon style="display:block" custom="iconfont icon-home" :color="routerName == 'homePage' ? '#1CC0F3':'#d0d0d0'" @click="toHome" />
                 <BaseNotification :msgs="msgs"></BaseNotification>
-                <Icon type="ios-settings" :color="routerName == 'settings' ? '#1CC0F3':'#d0d0d0'" @click="toSettings" />
+                <span class="header-split"></span>
+                <!-- <Icon type="ios-settings" :color="routerName == 'settings' ? '#1CC0F3':'#d0d0d0'" @click="toSettings" /> -->
                 <!-- 问题答疑页面暂未开发 暂时注释 -->
                 <!-- <Icon type="md-help-circle" :color="routerName == 'feedback' ? '#1CC0F3':'#d0d0d0'" @click="toFeedback"/> -->
                 <BaseUserPoptip @logout="basicMenu('quit')"></BaseUserPoptip>
@@ -28,7 +29,7 @@ export default {
     components: {},
     data() {
         return {
-			msgs:[],
+            msgs: [],
             isShowMock: false,
             isOpenDrawer: false,
             routerName: '',
@@ -58,14 +59,14 @@ export default {
                 schoolCode: this.$GLOBAL.DEFAULT_SCHOOL_CODE
             })
         }
-		
-		this.$api.service.getNotification({
-			"from":"ies5:" + user_profile.defaultschool || user_profile.schools[0].schoolId,
-			"receiver": user.id
-		}).then(res => {
-			console.log('端外通知',res)
-			this.msgs = res.msgs
-		})
+
+        this.$api.service.getNotification({
+            "from": "ies5:" + user_profile.defaultschool || user_profile.schools[0].schoolId,
+            "receiver": user.id
+        }).then(res => {
+            console.log('端外通知', res)
+            this.msgs = res.msgs
+        })
 
 
     },
@@ -128,11 +129,19 @@ export default {
 </script>
 
 <style scoped>
+.header-split {
+    display: block;
+    width: 1px;
+    background: #797979;
+    height: 30px;
+}
 .header-right-box {
-    width: 400px;
+    width: 240px;
     margin: 12px;
     line-height: 1.5;
     float: right;
+    height: 45px;
+    margin-right: 20px;
 }
 
 .header-right-box .ivu-icon {

+ 4 - 2
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -321,9 +321,11 @@
 			async getAutoQuestions(questions) {
 				let autoQuestions = await this.$evTools.getFullItem(questions)
 				let arr = autoQuestions
+				// 拿到题目后 根据试卷总分给所有题目进行平均分配
 				let scoreArr = this.averageTotalScore(this.evaluationInfo.score, arr.length)
 				arr.forEach((i, index) => {
 					i.score = scoreArr[index] || 0
+					// 如果是综合题 则需要进行子题的分数平均分配
 					if(i.type === 'compose' && i.children.length){
 						let childrenScoreArr = this.averageTotalScore(i.score, i.children.length)
 						i.children.forEach((child,childIndex) => {
@@ -343,9 +345,11 @@
 			getSelectedQuestion(data) {
 				console.log(data)
 				let arr = data.questions
+				// 拿到题目后 根据试卷总分给所有题目进行平均分配
 				let scoreArr = this.averageTotalScore(this.evaluationInfo.score, arr.length)
 				arr.forEach((i, index) => {
 					i.score = scoreArr[index] || 0
+					// 如果是综合题 则需要进行子题的分数平均分配
 					if(i.type === 'compose' && i.children.length){
 						let childrenScoreArr = this.averageTotalScore(i.score, i.children.length)
 						i.children.forEach((child,childIndex) => {
@@ -364,8 +368,6 @@
 				} else {
 					this.evaluationInfo.item = arr
 				}
-				console.log('手动挑题返回')
-				console.log(arr)
 			},
 			
 			/* 根据总分给出固定长度的平均分配数组 */

+ 157 - 154
TEAMModelOS/ClientApp/src/view/settings/Index.vue

@@ -2,8 +2,8 @@
     <div class="settings-container">
         <div class="settings-header">
             <span :class="['settings-header-item',activeTab === '1' ?  'active-item' : '']" @click="onTabChange('1')">{{ $t('settings.setting_title1')}}</span>
-			<span :class="['settings-header-item',activeTab === '0' ?  'active-item' : '']" @click="onTabChange('0')">{{ $t('settings.setting_title2')}}</span>
-			<span :class="['settings-header-item',activeTab === '2' ?  'active-item' : '']" @click="onTabChange('2')">{{ $t('settings.setting_title3')}}</span>
+            <span :class="['settings-header-item',activeTab === '0' ?  'active-item' : '']" @click="onTabChange('0')">{{ $t('settings.setting_title2')}}</span>
+            <!-- <span :class="['settings-header-item',activeTab === '2' ?  'active-item' : '']" @click="onTabChange('2')">{{ $t('settings.setting_title3')}}</span> -->
         </div>
 
         <div class="settings-body">
@@ -38,148 +38,157 @@
                         </RadioGroup>
                     </span>
                 </div>
-				<div class="normal-settings-item">
-				    <span class="item-title">{{ $t('settings.logoSetting')}}</span>
-				    <span class="item-description">{{ $t('settings.logoTips')}}</span>
-				    <span class="item-content">
-				        <RadioGroup v-model="cloudSetting.logoStatus" @on-change="onLogoStatusChange">
-				            <Radio label="open">{{ $t('settings.logoOpen')}}</Radio>
-				            <Radio label="close">{{ $t('settings.logoHide')}}</Radio>
-				        </RadioGroup>
-				    </span>
-				</div>
+                <div class="normal-settings-item">
+                    <span class="item-title">{{ $t('settings.logoSetting')}}</span>
+                    <span class="item-description">{{ $t('settings.logoTips')}}</span>
+                    <span class="item-content">
+                        <RadioGroup v-model="cloudSetting.logoStatus" @on-change="onLogoStatusChange">
+                            <Radio label="open">{{ $t('settings.logoOpen')}}</Radio>
+                            <Radio label="close">{{ $t('settings.logoHide')}}</Radio>
+                        </RadioGroup>
+                    </span>
+                </div>
                 <div class="normal-settings-item">
                     <!-- <Button @click="saveSetting">保存变更</Button> -->
                 </div>
             </div>
             <SchoolMgmt v-if="activeTab === '1'" class="animated fadeIn"></SchoolMgmt>
             <!-- <OpenMgmt v-if="activeTab === '2'" class="animated fadeIn"></OpenMgmt> -->
-            <OpenMgmt2 v-if="activeTab === '2'" class="animated fadeIn"></OpenMgmt2>
+            <!-- 换成独立菜单了 -->
+            <!-- <OpenMgmt2 v-if="activeTab === '2'" class="animated fadeIn"></OpenMgmt2> -->
         </div>
     </div>
 </template>
 
 <script>
-    //import "@/css/less-variable.less"
-    import SchoolMgmt from './SchoolMgmt.vue'
-    import OpenMgmt from './OpenMgmt.vue'
-    import OpenMgmt2 from './OpenMgmt2.vue';
-    export default {
-        components: {
-            SchoolMgmt,
-            OpenMgmt,
-            OpenMgmt2
-        },
-        data() {
-            return {
-                activeTab: '1',
-                activeTheme: '0',
+//import "@/css/less-variable.less"
+import SchoolMgmt from './SchoolMgmt.vue'
+import OpenMgmt from './OpenMgmt.vue'
+// import OpenMgmt2 from './OpenMgmt2.vue';
+export default {
+    components: {
+        SchoolMgmt,
+        OpenMgmt,
+        // OpenMgmt2
+    },
+    data() {
+        return {
+            activeTab: '1',
+            activeTheme: '0',
+            menuStatus: 'open',
+            curLang: 'zh-cn',
+            isHomeworkLang: true,
+            cloudSetting: {
+                curLang: localStorage.getItem('local'),
+                curTheme: 'dark',
+                isSystemLang: true,
                 menuStatus: 'open',
-                curLang: 'zh-cn',
-                isHomeworkLang: true,
-                cloudSetting: {
-                    curLang: localStorage.getItem('local'),
-                    curTheme: 'dark',
-                    isSystemLang: true,
-                    menuStatus: 'open',
-					logoStatus: 'open'
-                }
+                logoStatus: 'open'
             }
+        }
+    },
+    created() {
+        if (localStorage.getItem('cloudSetting')) {
+            this.cloudSetting = JSON.parse(localStorage.getItem('cloudSetting'))
+        }
+    },
+    methods: {
+
+        onSelectLang(val) {
+            localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
+            this.$store.commit("setLanguage", val);
         },
-        created() {
-            if (localStorage.getItem('cloudSetting')) {
-                this.cloudSetting = JSON.parse(localStorage.getItem('cloudSetting'))
-            }
+
+        onMenuStatusChange(val) {
+            localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
         },
-        methods: {
-			
-			onSelectLang(val){
-				localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
-				this.$store.commit("setLanguage", val);
-			},
-			
-			onMenuStatusChange(val){
-				localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
-			},
-			
-			onLogoStatusChange(val){
-				localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
-				this.$EventBus.$emit('onLogoStatusChange',val)
-			},
 
-            /* 一般设置与学校管理切换 */
-            onTabChange(index) {
-                this.activeTab = index
-            },
+        onLogoStatusChange(val) {
+            localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
+            this.$EventBus.$emit('onLogoStatusChange', val)
+        },
 
-            /* 主题切换 */
-            onThemeChange(index) {
-                this.cloudSetting.curTheme = index
-                //this.$less.modifyVars({  // 调用 `less.modifyVars` 方法来改变变量值'
-                //    '@border-color': '#000',
-                //    '@header-bg': 'white',
-                //})
-                //    .then(() => {
-                //        console.log('修改成功');
-                //    });
-                localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
-                if (index == 'dark') {
-                    let url =  '/theme/dark-theme.css'
-                    var link = document.getElementById('theme') ? document.getElementById('theme') : document.createElement('link');
-                    if (document.getElementById('theme')) {
-                        link.href = url;
-                    } else {
-                        var head = document.getElementsByTagName('head')[0];
-                        link.type = 'text/css';
-                        link.rel = 'stylesheet';
-                        link.id = 'theme';
-                        link.href = url;
-                        head.appendChild(link);
-                    }
+        /* 一般设置与学校管理切换 */
+        onTabChange(index) {
+            this.activeTab = index
+        },
+
+        /* 主题切换 */
+        onThemeChange(index) {
+            this.cloudSetting.curTheme = index
+            //this.$less.modifyVars({  // 调用 `less.modifyVars` 方法来改变变量值'
+            //    '@border-color': '#000',
+            //    '@header-bg': 'white',
+            //})
+            //    .then(() => {
+            //        console.log('修改成功');
+            //    });
+            localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
+            if (index == 'dark') {
+                let url = '/theme/dark-theme.css'
+                var link = document.getElementById('theme') ? document.getElementById('theme') : document.createElement('link');
+                if (document.getElementById('theme')) {
+                    link.href = url;
                 } else {
-                    let url = '/theme/light-theme.css'
-                    var link = document.getElementById('theme') ? document.getElementById('theme') : document.createElement('link');
-                    if (document.getElementById('theme')) {
-                        link.href = url;
-                    } else {
-                        var head = document.getElementsByTagName('head')[0];
-                        link.type = 'text/css';
-                        link.rel = 'stylesheet';
-                        link.id = 'theme';
-                        link.href = url;
-                        head.appendChild(link);
-                    }
+                    var head = document.getElementsByTagName('head')[0];
+                    link.type = 'text/css';
+                    link.rel = 'stylesheet';
+                    link.id = 'theme';
+                    link.href = url;
+                    head.appendChild(link);
+                }
+            } else {
+                let url = '/theme/light-theme.css'
+                var link = document.getElementById('theme') ? document.getElementById('theme') : document.createElement('link');
+                if (document.getElementById('theme')) {
+                    link.href = url;
+                } else {
+                    var head = document.getElementsByTagName('head')[0];
+                    link.type = 'text/css';
+                    link.rel = 'stylesheet';
+                    link.id = 'theme';
+                    link.href = url;
+                    head.appendChild(link);
                 }
-            },
-			
-			onTips(){
-				this.$Message.warning('换肤功能即将上线')
-			},
-
-            /* 保存设置 */
-            saveSetting() {
-                this.$Modal.confirm({
-                    title: '提示',
-                    content: '设置保存成功,刷新后即可生效,是否前往?',
-                    onOk: () => {
-                        localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
-                        location.reload()
-                    }
-                })
             }
+        },
+
+        onTips() {
+            this.$Message.warning('换肤功能即将上线')
+        },
+
+        /* 保存设置 */
+        saveSetting() {
+            this.$Modal.confirm({
+                title: '提示',
+                content: '设置保存成功,刷新后即可生效,是否前往?',
+                onOk: () => {
+                    localStorage.setItem('cloudSetting', JSON.stringify(this.cloudSetting))
+                    location.reload()
+                }
+            })
         }
-    }
+    },
+    watch: {
+        $route: {
+            handler: function (val, oldVal) {
+                let routeData = this.$route.query
+                this.activeTab = routeData.tab || this.activeTab
+            },
+            // 深度观察监听
+            deep: true
+        }
+    },
+}
 </script>
 
 <style lang="less" scoped>
-    @import "./Index.less";
+@import "./Index.less";
 </style>
 
 <style lang="less">
-    .settings-container {
-        .ivu-select-selection
-
-    {
+.settings-container {
+    .ivu-select-selection {
         background: transparent;
         border-color: #363738;
         color: #a6a6a6;
@@ -208,24 +217,21 @@
         border-color: #4d4d4d;
         border-width: 1px;
         margin-right: 5px;
-        &::after
-
-    {
-        content: '';
-        display: block;
-        width: 10px;
-        height: 16px;
-        border-right: #ffffff solid 3px;
-        border-bottom: #ffffff solid 3px;
-        transform: rotate(35deg);
-        position: absolute;
-        top: -4px;
-        left: 4px;
-        border-radius: 0;
-        background-color: transparent;
-        border-color: #0094FF;
-    }
-
+        &::after {
+            content: "";
+            display: block;
+            width: 10px;
+            height: 16px;
+            border-right: #ffffff solid 3px;
+            border-bottom: #ffffff solid 3px;
+            transform: rotate(35deg);
+            position: absolute;
+            top: -4px;
+            left: 4px;
+            border-radius: 0;
+            background-color: transparent;
+            border-color: #0094ff;
+        }
     }
 
     .ivu-checkbox-inner {
@@ -246,24 +252,21 @@
         border-color: #4d4d4d;
         border-width: 1px;
         margin-right: 5px;
-        &::after
-
-    {
-        content: '';
-        display: block;
-        width: 10px;
-        height: 16px;
-        border-right: #ffffff solid 3px;
-        border-bottom: #ffffff solid 3px;
-        transform: rotate(35deg);
-        position: absolute;
-        top: -4px;
-        left: 4px;
-        border-radius: 0;
-        background-color: transparent;
-        border-color: #0094FF;
-    }
-
-    }
+        &::after {
+            content: "";
+            display: block;
+            width: 10px;
+            height: 16px;
+            border-right: #ffffff solid 3px;
+            border-bottom: #ffffff solid 3px;
+            transform: rotate(35deg);
+            position: absolute;
+            top: -4px;
+            left: 4px;
+            border-radius: 0;
+            background-color: transparent;
+            border-color: #0094ff;
+        }
     }
+}
 </style>

+ 235 - 178
TEAMModelOS/ClientApp/src/view/syllabus/Syllabus.vue

@@ -53,10 +53,10 @@
 								<span>{{ getSemesterName(volume.semesterId) }}</span>
 							</p>
 							<p class="volume-item-info" v-if="inShareView">
-								<span  style="display: flex;align-items: center;">
+								<!-- <span  style="display: flex;align-items: center;">
 									<Icon type="ios-remove-circle-outline" style="font-weight: bold;margin-right: 5px;"/>
 									忽略该分享
-								</span>
+								</span> -->
 								<!-- <span class="volume-btn-agree" @click="onAgreeShare(volume,'agree')">
 									<Icon type="md-checkmark-circle-outline" size="20" color="#27c684" />
 									<span>接受</span>
@@ -91,7 +91,7 @@
 					<span class="syllabus-content-header-tools">
 						<!-- <Icon type="md-add" @click="onAddResource" v-if="curNode.id"/> -->
 						<Dropdown @on-click="onAddResource"
-							v-if="curNode.id && (hasSyllabusAuth || hasEditAuth(curNode))">
+							v-if="curNode.id && (hasSyllabusAuth || hasEditAuth(curNode)) && !inShareView">
 							<a href="javascript:void(0)" style="color: #ddd;">
 								添加资源
 								<Icon type="ios-arrow-down"></Icon>
@@ -127,7 +127,7 @@
 							<img src="../../assets/source/zip.png" v-else-if="item.type === 'res'" />
 							<img src="../../assets/source/image.png" v-else-if="item.type === 'thum'" />
 							<img src="../../assets/source/unknow.png" v-else="item.type === 'other'" />
-							<span v-html="getSimpleText(item.title)" style="max-width: 70%;"></span>
+							<span v-html="item.title" style="max-width: 70%;"></span>
 							<div class="node-resource-tools">
 								<div class="node-resource-tool" @click="onPreview(item)">
 									<Icon type="md-eye" />
@@ -242,18 +242,18 @@
 		<div v-if="previewStatus" class="image-viewer">
 			<div style="width:fit-content;position:relative;margin:auto;">
 				<Icon type="md-close" class="close-icon" @click="previewStatus = false" />
-				<video v-if="previewFile.type == 'video'" id="previewVideo" :src="previewFile.link[0]" width="870"
+				<video v-if="previewFile.type == 'video'" id="previewVideo" :src="previewFile.link" width="870"
 					controls="controls" style="max-height: 800px;">
 					{{$t('teachContent.tips8')}}
 				</video>
 				<audio v-else-if="previewFile.type == 'audio'" controls>
-					<source :src="previewFile.link[0]">
+					<source :src="previewFile.link">
 					{{$t('teachContent.notAudio')}}
 				</audio>
-				<img v-else-if="previewFile.type == 'image'" :src="previewFile.link[0]"
+				<img v-else-if="previewFile.type == 'image'" :src="previewFile.link"
 					style="border-radius: 5px;max-height: 800px;max-width:870px;" />
-				<!-- <embed v-else-if="previewFile.type == 'doc'" :src="previewFile.link[0]" width="870" height="720" /> -->
-				<iframe v-else :src="'https://view.officeapps.live.com/op/view.aspx?src=' + previewFile.link[0]"
+				<!-- <embed v-else-if="previewFile.type == 'doc'" :src="previewFile.link" width="870" height="720" /> -->
+				<iframe v-else :src="'https://view.officeapps.live.com/op/view.aspx?src=' + previewFile.link"
 					width='870' height='700' frameborder='1'></iframe>
 			</div>
 		</div>
@@ -307,6 +307,7 @@
 				semesterList: [],
 				volumeList: [],
 				originVolumeList: [],
+				myVolumeList:[],
 				questionList: [],
 				allChapterIds: [],
 				schoolInfo: null,
@@ -346,7 +347,8 @@
 					"rnodes": []
 				},
 				modifyIdArr: [],
-				flatArr: []
+				flatArr: [],
+				isSaveSyllabus:false,
 			}
 		},
 		created() {
@@ -378,9 +380,15 @@
 				});
 			},
 			/* 提取富文本内容中的文本 */
-			getSimpleText(html) {
-				html = html || '';
-				return html.replace(/<[^>]+>/g, ""); //去掉所有的html标记
+			async getItemSimpleText(item) {
+				try{
+					let sas = await this.$evTools.getBlobPrivateSas(item.cntr)
+					let indexJsonFile = await this.$tools.getFile(this.$evTools.getBlobHost() + '/' + item.cntr + item.link  + sas)
+					let itemJson = JSON.parse(indexJsonFile)
+					return itemJson.item[0].question.replace(/<[^>]+>/g, "") //去掉所有的html标记
+				}catch(e){
+					this.$Message.error(e)
+				}
 			},
 			/* 切换学段的操作 */
 			onPeriodChange(val) {
@@ -398,12 +406,22 @@
 			/* 切换个人创建的课纲和他人分享的课纲 */
 			onChangeSyllabusTab(type) {
 				this.activeTab = type
-				type === 'fromCreate' ? this.getVolumeList() : this.getShareVolumeList()
+				this.treeOrigin = []
+				this.curNode = {
+					id: '',
+					rnodes: []
+				}
+				this.hasModify = false
+				type === 'fromCreate' ? this.getVolumeList(true) : this.getShareVolumeList(true)
 			},
 			/* 获取册别列表 */
-			getVolumeList() {
+			getVolumeList(needRefresh) {
 				this.isLoading = true
 				this.treeOrigin = []
+				this.curNode = {
+					id: '',
+					rnodes: []
+				}
 				let findParams = {
 					"periodId": this.isSchool ? this.periodList[this.currentPeriodIndex].id : '',
 					"subjectId": this.isSchool ? this.subjectList[this.activeSubjectIndex].id : '',
@@ -417,9 +435,10 @@
 						this.isLoading = false
 						this.volumeList = res.volumes.reverse()
 						this.originVolumeList = JSON.parse(JSON.stringify(this.volumeList))
+						this.myVolumeList = JSON.parse(JSON.stringify(this.volumeList))
 						let activeIndex = this.isEditVolume ? this.activeVolumeIndex : 0
 						// this.isEditVolume = false
-						res.volumes.length && this.onVolumeClick(res.volumes[activeIndex], activeIndex)
+						res.volumes.length && this.onVolumeClick(res.volumes[activeIndex], activeIndex, needRefresh)
 					} else {
 						this.$Message.warning(res.error);
 					}
@@ -428,7 +447,7 @@
 				})
 			},
 			/* 获取分享来的册别列表 */
-			getShareVolumeList() {
+			getShareVolumeList(needRefresh) {
 				this.$api.syllabus.FindShare({
 					"code": this.$store.state.userInfo.TEAMModelId,
 					"type": "share"
@@ -448,10 +467,10 @@
 									status: 1
 								}
 							})
-							this.volumeList = shareList
+							this.volumeList = shareList.reverse()
 							this.originVolumeList = JSON.parse(JSON.stringify(this.volumeList))
 							let activeIndex = this.isEditVolume ? this.activeVolumeIndex : 0
-							shareList.length && this.onVolumeClick(shareList[activeIndex], activeIndex)
+							shareList.length && this.onVolumeClick(shareList[activeIndex], activeIndex, needRefresh)
 						} else {
 							this.volumeList = []
 							this.originVolumeList = []
@@ -466,18 +485,12 @@
 			},
 			/* 是否接受分享的课纲 */
 			onAgreeShare(volume,type){
-				// this.$api.syllabus.ShareAgree({
-				// 	code:volume.code,
-				// 	id:volume.id,
-				// 	agree:type === 'agree' ? 3 : 4
-				// }).then(res => {
-					
-				// })
+				console.log(volume)
 			},
 			/* 点击某个册别 */
-			onVolumeClick(volume, volumeIndex) {
+			onVolumeClick(volume, volumeIndex, needRefresh) {
 				console.log(volume)
-				if (!volume || (volume.id === this.curVolume.id && !this.isEditVolume)) return
+				if (!volume || (volume.id === this.curVolume.id && !this.isEditVolume && !needRefresh)) return
 				this.isLoading = true
 				this.curVolume = volume
 				this.allChapterIds = volume.syllabusIds || []
@@ -497,7 +510,7 @@
 			},
 			/* 复制副本 */
 			doCopyVolume(){
-				
+				console.log('xxx')
 			},
 			/* 搜索册别 */
 			doSearchVolume() {
@@ -639,7 +652,7 @@
 			},
 			/* 存储变更保存最新课纲数据 */
 			onSaveSyllabus() {
-				this.isEditVolume = true
+				this.isSaveSyllabus = true
 				// 拿到有修改变动的章节ID集合
 				let modifyIdArr = [...new Set(this.modifyIdArr)].filter(i => i !== this.curVolume.id)
 				console.log(modifyIdArr)
@@ -669,8 +682,21 @@
 			/* 点击某个节点 */
 			onNodeClick(data) {
 				this.curChapter = this.getChapterByNode(data.node)
-				console.log(this.curChapter)
-				this.curNode = data.data
+				// 如果当前节点有关联试题资源 则需要去拿到试题完整信息 来给title赋值 保证为最新数据
+				if(data.data.rnodes.length){
+					let itemNodeArr = data.data.rnodes.filter(i => i.type === 'item')
+					if(itemNodeArr.length){
+						itemNodeArr.forEach(async item => {
+							item.title = await this.getItemSimpleText(item)
+							this.curNode = data.data
+						})
+					}else{
+						this.curNode = data.data
+					}
+				}else{
+					this.curNode = data.data
+				}
+				console.log('当前点击节点数据 ==== ',data.data.title,data.data.rnodes)
 			},
 			/* 根据节点获取它所在的章节信息 */
 			getChapterByNode(node) {
@@ -696,7 +722,7 @@
 					code: this.curCode,
 					scope: this.curScope,
 					id: this.$tools.guid(),
-					link: [this.curLink.url],
+					link: this.curLink.url,
 					title: this.curLink.name,
 					type: 'link',
 					ctnr: ''
@@ -729,7 +755,7 @@
 						code: this.curCode,
 						scope: this.curScope,
 						id: this.$tools.guid(),
-						link: [file.url],
+						link: file.url,
 						title: file.name,
 						type: file.type,
 						cntr: this.curCode
@@ -763,12 +789,12 @@
 										title: file.name,
 										id: this.$tools.guid(),
 										code: this.curCode,
-										scope: file.scope,
-										cntr: file.scope === 'school' ? this
+										scope: this.isSchool ? 'school' : 'private',
+										cntr: this.isSchool ? this
 											.$store.state.userInfo.schoolCode :
 											this.$store.state
 											.userInfo.TEAMModelId,
-										link: [file.url]
+										link: `/syllabus/${file.name}`
 									})
 									r2(200)
 
@@ -789,11 +815,13 @@
 
 			},
 			/* 保存单个试题 */
-			saveExercise(item) {
+			saveExercise(item,scope) {
+				console.log(item)
+				console.log(scope)
 				return new Promise(async (r, j) => {
 					let cosmosItem = await this.$editorTools.transBase64Src(item)
 					this.$api.newEvaluation.SaveSingleExercise({
-						itemInfo: await this.$evTools.createCosmosItem(cosmosItem),
+						itemInfo: await this.$evTools.createCosmosItem(cosmosItem,scope),
 						option: "insert",
 					}).then((res) => {
 						r(res)
@@ -832,58 +860,67 @@
 			},
 			/* 获取关联的试题数据 */
 			onSelectQuestion(val) {
-				let list = this.$refs.chooseContentRef.$refs.exListRef.selectItems
-				if (!list.length) return
-				let curResourceArr = this.$refs.treeRef.curData.rnodes
-				// 拿到关联的个人试题
-				let privateItems = list.filter(i => i.scope === 'private')
-				// 如果是在校本课纲关联的个人试题 则需要进行入库操作
-				if (this.isSchool && privateItems.length) {
-					let promiseArr = []
-					// 个人试题入库前需要补充必要的学段科目年级信息
-					privateItems.forEach(pItem => {
-						pItem.periodId = this.periodList[this.currentPeriodIndex].id
-						pItem.subjectId = this.subjectList[this.activeSubjectIndex].id
-						pItem.gradeIds = [this.curVolume.gradeId + '']
-						pItem.scope = 'school'
-						pItem.code = this.$store.state.userInfo.schoolCode
-						promiseArr.push(this.saveItemToSchoolBlob(pItem))
-					})
-					Promise.all(promiseArr).then(result => {
+				return new Promise((r,j) => {
+					let list = this.$refs.chooseContentRef.$refs.exListRef.selectItems
+					console.log('xxxxx',list)
+					if (!list.length) {
+						r(200)
+					}else{
+						let curResourceArr = this.$refs.treeRef.curData.rnodes
+						// 拿到关联的个人试题
+						let privateItems = list.filter(i => i.scope === 'private')
+						// 如果是在校本课纲关联的个人试题 则需要进行入库操作
+						if (this.isSchool && privateItems.length) {
+							let promiseArr = []
+							// 个人试题入库前需要补充必要的学段科目年级信息
+							privateItems.forEach(pItem => {
+								pItem.periodId = this.periodList[this.currentPeriodIndex].id
+								pItem.subjectId = this.subjectList[this.activeSubjectIndex].id
+								pItem.gradeIds = [this.curVolume.gradeId + '']
+								pItem.scope = 'school'
+								pItem.code = this.$store.state.userInfo.schoolCode
+								promiseArr.push(this.saveItemToSchoolBlob(pItem))
+							})
+							Promise.all(promiseArr).then(result => {
+								list.forEach(i => {
+									if (!curResourceArr.filter(j => j.type === 'item').map(k => k.id).includes(i
+											.id)) {
+										curResourceArr.push({
+											type: 'item',
+											title: i.question,
+											id: i.id,
+											code: 'Item-' + this.$store.state.userInfo.schoolCode,
+											scope: 'school',
+											cntr: this.$store.state.userInfo.schoolCode,
+											link: i.blob
+										})
+									}
+								})
+								r(200)
+							}).catch(err => {
+								this.$Message.error(err)
+							})
+						} else {
 						list.forEach(i => {
-							if (!curResourceArr.filter(j => j.type === 'item').map(k => k.id).includes(i
-									.id)) {
+							if (!curResourceArr.filter(j => j.type === 'item').map(k => k.id).includes(i.id)) {
 								curResourceArr.push({
 									type: 'item',
 									title: i.question,
 									id: i.id,
-									code: 'Item-' + this.$store.state.userInfo.schoolCode,
-									scope: 'school',
-									cntr: this.$store.state.userInfo.schoolCode,
-									link: [i.blob]
+									code: i.code,
+									scope: i.scope,
+									cntr: i.scope === 'school' ? this.$store.state.userInfo.schoolCode : this
+										.$store.state
+										.userInfo.TEAMModelId,
+									link: i.blob
 								})
 							}
 						})
-					}).catch(err => {
-						this.$Message.error(err)
-					})
-				} else {
-					list.forEach(i => {
-						if (!curResourceArr.filter(j => j.type === 'item').map(k => k.id).includes(i.id)) {
-							curResourceArr.push({
-								type: 'item',
-								title: i.question,
-								id: i.id,
-								code: i.code,
-								scope: i.scope,
-								cntr: i.scope === 'school' ? this.$store.state.userInfo.schoolCode : this
-									.$store.state
-									.userInfo.TEAMModelId,
-								link: [i.blob]
-							})
-						}
-					})
-				}
+						r(200)
+					}
+					}
+				})
+				
 
 			},
 			/* 判断试卷名称是否已存在校本库中 */
@@ -957,108 +994,113 @@
 			onSelectPaper() {
 				return new Promise(async (r,j) => {
 					let list = this.$refs.chooseContentRef.$refs.paperListRef.checkedPaperList
-					if (!list.length) return
-					let curResourceArr = this.$refs.treeRef.curData.rnodes
-					// 拿到关联的个人试卷
-					let privatePapers = list.filter(i => i.scope === 'private')
-					let privateSas = await this.$tools.getPrivateSas()
-					// 如果是在校本课纲关联的个人试卷 则需要进行入库操作
-					if (this.isSchool && privatePapers.length) {
-						let schoolPaperList = await this.getSchoolPaperList()
-						console.log(privatePapers)
-						let promiseArr = []
-						privatePapers.forEach(async paper => {
-							if(schoolPaperList.map(i => i.name).includes(paper.name)){
-								this.$Modal.confirm({
-									title: '提示',
-									content: '校本试卷库中已存在名称为' + paper.name + '的试卷,是否继续操作覆盖原试卷?',
-									onOk: async () => {
-										// 继续进行操作完成试卷覆盖
-										// 拿到试卷的index.json 先完善学段科目年级信息后 去进行上传覆盖操作
-										let indexJsonFile = await this.$tools.getFile(this.$evTools.getBlobHost() + '/' + paper.code.replace('Paper-','') + paper.blob + '/index.json' + privateSas.sas)
-										let paperIndexJson = JSON.parse(indexJsonFile)
-										paperIndexJson.periodId = this.periodList[this.currentPeriodIndex].id
-										paperIndexJson.subjectId = this.subjectList[this.activeSubjectIndex].id
-										paperIndexJson.subjectName = this.subjectList[this.activeSubjectIndex].name
-										paperIndexJson.gradeIds = [this.curVolume.gradeId + '']
-										paperIndexJson.scope = 'school'
-										paperIndexJson.code = this.$store.state.userInfo.schoolCode
-										console.log(paperIndexJson)
-										promiseArr.push(this.savePaperToSchoolBlob(paperIndexJson,paper.scoring,true))
-									},
-									onCancel: () => {
-										// 取消则无法关联当前试卷到节点
-										curResourceArr.splice(curResourceArr.map(i => i.id).indexOf(paper.id),1)
+					if (!list.length) {
+						r(200)
+					}else{
+						let curResourceArr = this.$refs.treeRef.curData.rnodes
+						// 拿到关联的个人试卷
+						let privatePapers = list.filter(i => i.scope === 'private')
+						let privateSas = await this.$tools.getPrivateSas()
+						// 如果是在校本课纲关联的个人试卷 则需要进行入库操作
+						if (this.isSchool && privatePapers.length) {
+							let schoolPaperList = await this.getSchoolPaperList()
+							console.log(privatePapers)
+							let promiseArr = []
+							privatePapers.forEach(async paper => {
+								if(schoolPaperList.map(i => i.name).includes(paper.name)){
+									this.$Modal.confirm({
+										title: '提示',
+										content: '校本试卷库中已存在名称为' + paper.name + '的试卷,是否继续操作覆盖原试卷?',
+										onOk: async () => {
+											// 继续进行操作完成试卷覆盖
+											// 拿到试卷的index.json 先完善学段科目年级信息后 去进行上传覆盖操作
+											let indexJsonFile = await this.$tools.getFile(this.$evTools.getBlobHost() + '/' + paper.code.replace('Paper-','') + paper.blob + '/index.json' + privateSas.sas)
+											let paperIndexJson = JSON.parse(indexJsonFile)
+											paperIndexJson.periodId = this.periodList[this.currentPeriodIndex].id
+											paperIndexJson.subjectId = this.subjectList[this.activeSubjectIndex].id
+											paperIndexJson.subjectName = this.subjectList[this.activeSubjectIndex].name
+											paperIndexJson.gradeIds = [this.curVolume.gradeId + '']
+											paperIndexJson.scope = 'school'
+											paperIndexJson.code = this.$store.state.userInfo.schoolCode
+											console.log(paperIndexJson)
+											promiseArr.push(this.savePaperToSchoolBlob(paperIndexJson,paper.scoring,true))
+										},
+										onCancel: () => {
+											// 取消则无法关联当前试卷到节点
+											curResourceArr.splice(curResourceArr.map(i => i.id).indexOf(paper.id),1)
+										}
+									})
+								}else{
+									// 拿到试卷的index.json 先完善学段科目年级信息后 去进行上传覆盖操作
+									let indexJsonFile = await this.$tools.getFile(this.$evTools.getBlobHost() + '/' + paper.code.replace('Paper-','') + paper.blob + '/index.json' + privateSas.sas)
+									let paperIndexJson = JSON.parse(indexJsonFile)
+									paperIndexJson.periodId = this.periodList[this.currentPeriodIndex].id
+									paperIndexJson.subjectId = this.subjectList[this.activeSubjectIndex].id
+									paperIndexJson.subjectName = this.subjectList[this.activeSubjectIndex].name
+									paperIndexJson.gradeIds = [this.curVolume.gradeId + '']
+									paperIndexJson.scope = 'school'
+									paperIndexJson.code = this.$store.state.userInfo.schoolCode
+									console.log(paperIndexJson)
+									promiseArr.push(this.savePaperToSchoolBlob(paperIndexJson,paper.scoring))
+								}
+								
+							})
+							Promise.all(promiseArr).then(result => {
+								console.log(result)
+								list.forEach(i => {
+									if (!curResourceArr.filter(j => j.type === 'paper').map(k => k.id).includes(i.id)) {
+										curResourceArr.push({
+											type: 'paper',
+											title: i.name,
+											id: i.id,
+											code: 'Paper-' + this.$store.state.userInfo.schoolCode,
+											scope: 'school',
+											cntr:this.$store.state.userInfo.schoolCode,
+											link: i.blob
+										})
 									}
 								})
-							}else{
-								// 拿到试卷的index.json 先完善学段科目年级信息后 去进行上传覆盖操作
-								let indexJsonFile = await this.$tools.getFile(this.$evTools.getBlobHost() + '/' + paper.code.replace('Paper-','') + paper.blob + '/index.json' + privateSas.sas)
-								let paperIndexJson = JSON.parse(indexJsonFile)
-								paperIndexJson.periodId = this.periodList[this.currentPeriodIndex].id
-								paperIndexJson.subjectId = this.subjectList[this.activeSubjectIndex].id
-								paperIndexJson.subjectName = this.subjectList[this.activeSubjectIndex].name
-								paperIndexJson.gradeIds = [this.curVolume.gradeId + '']
-								paperIndexJson.scope = 'school'
-								paperIndexJson.code = this.$store.state.userInfo.schoolCode
-								console.log(paperIndexJson)
-								promiseArr.push(this.savePaperToSchoolBlob(paperIndexJson,paper.scoring))
-							}
-							
-						})
-						Promise.all(promiseArr).then(result => {
-							console.log(result)
+								r(200)
+							}).catch(err => {
+								j(err)
+							})
+						}else{
 							list.forEach(i => {
 								if (!curResourceArr.filter(j => j.type === 'paper').map(k => k.id).includes(i.id)) {
 									curResourceArr.push({
 										type: 'paper',
 										title: i.name,
 										id: i.id,
-										code: 'Paper-' + this.$store.state.userInfo.schoolCode,
-										scope: 'school',
-										cntr:this.$store.state.userInfo.schoolCode,
-										link: [i.blob]
+										code: i.code,
+										scope: i.scope,
+										cntr: i.scope === 'school' ? this.$store.state.userInfo.schoolCode : this
+											.$store.state
+											.userInfo.TEAMModelId,
+										link: i.blob
 									})
 								}
 							})
 							r(200)
-						})
-					}else{
-						list.forEach(i => {
-							if (!curResourceArr.filter(j => j.type === 'paper').map(k => k.id).includes(i.id)) {
-								curResourceArr.push({
-									type: 'paper',
-									title: i.name,
-									id: i.id,
-									code: i.code,
-									scope: i.scope,
-									cntr: i.scope === 'school' ? this.$store.state.userInfo.schoolCode : this
-										.$store.state
-										.userInfo.TEAMModelId,
-									link: [i.blob]
-								})
-							}
-						})
-						r(200)
+						}
 					}
+					
 				})
 				
 			},
 			/* 点击确认 去获取关联的内容数据、试题试卷数据 */
 			onRelateContent() {
 				this.isRelateLoading = true
-				let curResourceArr = this.$refs.treeRef.curData.rnodes
-				this.onSelectFile().then(res => {
-					this.onSelectQuestion()
-					this.onSelectPaper().then(result => {
-						setTimeout(() => {
-							this.isRelateLoading = false
-							this.isRelateContentModal = false
-							this.hasModify = true
-							this.modifyIdArr.push(this.curChapter.data.id)
-						},500)
-					})
+				Promise.all([this.onSelectFile(),this.onSelectQuestion(),this.onSelectPaper()]).then(result => {
+					console.log(result)
+					setTimeout(() => {
+						this.isRelateLoading = false
+						this.isRelateContentModal = false
+						this.hasModify = true
+						this.modifyIdArr.push(this.curChapter.data.id)
+					},500)
 				}).catch(err => {
+					console.log(err)
+					this.isRelateLoading = false
 					this.$Message.error(err)
 				})
 			},
@@ -1075,14 +1117,14 @@
 						// 如果不是当前用户自己的试题 则需要去获取他人BLOB内部的试题JSON文件
 						if (tmdId !== this.$store.state.userInfo.TEAMModelId) {
 							this.isFullList = 'true'
-							let fullItemJson = await this.$evTools.getFullItemByTmdId(tmdId, item.link[0])
+							let fullItemJson = await this.$evTools.getFullItemByTmdId(tmdId, item.link)
 							this.questionList = [fullItemJson]
 						} else {
 							this.isFullList = null
 							this.questionList = [{
 								code: item.code,
 								id: item.id,
-								blob: item.link[0],
+								blob: item.link,
 								scope: item.scope
 							}]
 						}
@@ -1097,13 +1139,13 @@
 						// 如果不是当前用户自己的试题 则需要去获取他人BLOB内部的试卷JSON文件
 						if (paperTmdId !== this.$store.state.userInfo.TEAMModelId) {
 							this.isFullList = 'true'
-							fullPaper = await this.$evTools.getFullPaperByTmdId(paperTmdId, item.link[0])
+							fullPaper = await this.$evTools.getFullPaperByTmdId(paperTmdId, item.link)
 						} else {
 							this.isFullList = null
 							let paper = {
 								code: item.code,
 								id: item.id,
-								blob: item.link[0],
+								blob: item.link,
 								scope: item.scope,
 							}
 							fullPaper = await this.$evTools.getFullPaper(paper)
@@ -1116,22 +1158,35 @@
 						this.isPreviewPaper = true
 						break;
 					case 'link':
-						window.open(item.link[0]);
+						window.open(item.link);
 						break;
 					case 'doc':
 						let copyLink = JSON.parse(JSON.stringify(item.link))
-
+						let docSas = ''
+						if (item.code !== this.$store.state.userInfo.TEAMModelId){
+							docSas = await this.$evTools.getBlobPrivateSas(item.code)
+						}else{
+							docSas = sasObj.sas
+						}
+						let fullLink = 	this.$evTools.getBlobHost() + '/' + item.cntr + item.link  + docSas
+						console.log(fullLink)
 						if (this.getSuffix(item.title) === 'pdf') {
-							this.openPdf(item.link[0] + sasObj.sas, item.title)
-							// window.open(item.link[0]+ sasObj.sas);
+							this.openPdf(fullLink, item.title)
 						} else {
 							this.previewFile = JSON.parse(JSON.stringify(item))
-							this.previewFile.link[0] = escape(copyLink[0] + sasObj.sas)
+							this.previewFile.link = escape(fullLink)
 							this.previewStatus = true
 						}
 						break;
 					default:
-						item.link[0] = item.link[0] + sasObj.sas
+						let fileTmdId = item.code.replace('Item-', '')
+						let sas = ''
+						if (fileTmdId !== this.$store.state.userInfo.TEAMModelId){
+							sas = await this.$evTools.getBlobPrivateSas(fileTmdId)
+						}else{
+							sas = sasObj.sas
+						}
+						item.link = item.link + sas
 						this.previewFile = item
 						this.previewStatus = true
 						break;
@@ -1199,6 +1254,8 @@
 			handleSubmit() {
 				return new Promise((r, j) => {
 					this.isAddLoading = true
+					console.log(this.addVolumeForm)
+					console.log(this.curVolume)
 					let addVolumeParams = {
 						"code": this.curCode,
 						"periodId": this.isSchool ? this.periodList[this.currentPeriodIndex].id : null,
@@ -1212,11 +1269,12 @@
 						"scope": this.curScope,
 						"syllabusIds": []
 					}
-					if (this.isEditVolume && this.curVolume) {
+					if ((this.isEditVolume && this.curVolume) || this.isSaveSyllabus) {
 						addVolumeParams.id = this.curVolume.id
-						addVolumeParams.name = this.curVolume.name
+						// addVolumeParams.name = this.curVolume.name
 						addVolumeParams.syllabusIds = this.allChapterIds || []
 						addVolumeParams.creatorId = this.curVolume.creatorId
+						this.isSaveSyllabus = false
 					}
 					// 发送新增或者编辑册别请求
 					this.$api.syllabus.SaveOrUpdateVolume(addVolumeParams).then(res => {
@@ -1295,7 +1353,6 @@
 			curScope() {
 				return this.isSchool ? "school" : "private"
 			},
-
 			getSuffix() {
 				return name => {
 					return name.substr(name.lastIndexOf(".") + 1)

+ 20 - 0
TEAMModelOS/ClientApp/src/view/user/UserCenter.vue

@@ -0,0 +1,20 @@
+<template>
+    <div class="user-center-container">
+        <h1 style="color:white;text-align:center;margin-top:120px;color:#AAA">账号信息</h1>
+    </div>
+</template>
+<script>
+export default {
+    data(){
+        return{
+
+        }
+    }
+}
+</script>
+<style lang="less" scoped>
+
+</style>
+<style lang="less">
+
+</style>