Browse Source

Merge branch 'develop3.0' of http://106.12.23.251:10080/TEAMMODEL/TEAMModelOS into develop3.0

CrazyIter 4 năm trước cách đây
mục cha
commit
75897bf803
30 tập tin đã thay đổi với 876 bổ sung499 xóa
  1. 2 0
      TEAMModelOS.Service/Models/SchoolInfo/School.cs
  2. 5 2
      TEAMModelOS/ClientApp/src/access/index.js
  3. 1 1
      TEAMModelOS/ClientApp/src/api/login.js
  4. 3 11
      TEAMModelOS/ClientApp/src/api/schoolList.js
  5. 5 1
      TEAMModelOS/ClientApp/src/api/uploadFile.js
  6. 54 14
      TEAMModelOS/ClientApp/src/common/BaseMock.vue
  7. 0 0
      TEAMModelOS/ClientApp/src/components/learnactivity/ProgressHistogram.less
  8. 6 2
      TEAMModelOS/ClientApp/src/filters/http.js
  9. 3 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/login.js
  10. 3 2
      TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolList.js
  11. 3 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/login.js
  12. 3 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolList.js
  13. 3 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/login.js
  14. 3 2
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolList.js
  15. 4 6
      TEAMModelOS/ClientApp/src/mock/index.js
  16. 1 1
      TEAMModelOS/ClientApp/src/router/routes.js
  17. 1 0
      TEAMModelOS/ClientApp/src/service/User.js
  18. 1 0
      TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.less
  19. 14 3
      TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.vue
  20. 4 328
      TEAMModelOS/ClientApp/src/view/login/Index.vue
  21. 123 0
      TEAMModelOS/ClientApp/src/view/login/components/SignIn.less
  22. 359 0
      TEAMModelOS/ClientApp/src/view/login/components/SignIn.vue
  23. 91 67
      TEAMModelOS/ClientApp/src/view/schoolList/Index.vue
  24. 5 5
      TEAMModelOS/ClientApp/src/view/selflearning/LearnProgress.vue
  25. 67 31
      TEAMModelOS/ClientApp/src/view/selfstudy/ActivityInfo.vue
  26. 3 3
      TEAMModelOS/ClientApp/src/view/selfstudy/LearnProgress.vue
  27. 8 8
      TEAMModelOS/ClientApp/src/components/learnactivity/ProgressHistogram.vue
  28. 97 0
      TEAMModelOS/ClientApp/src/view/selfstudy/ProgressPie.vue
  29. 3 6
      TEAMModelOS/ClientApp/src/view/selfstudy/SelfLearn.vue
  30. 1 1
      TEAMModelOS/Controllers/School/SchoolController.cs

+ 2 - 0
TEAMModelOS.Service/Models/SchoolInfo/School.cs

@@ -34,6 +34,8 @@ namespace TEAMModelOS.Service.Models
         /// 课程计划表
         /// </summary>
         public List<TimeTable> timetable { get; set; }
+        public string address{ get; set; }
+        public string picture { get; set; }
 
     }
 

+ 5 - 2
TEAMModelOS/ClientApp/src/access/index.js

@@ -31,10 +31,13 @@ LoginMiddleware.handleExtend = function(next, ...arg) {
     userInfo = JSON.parse(decodeURIComponent(localStorage.userInfo,"utf-8"))
   }
   
-  // if (token && userAccess && userInfo) {
   if (userAccess && userInfo) {
     if(!userInfo.schoolCode && toNextPath !== '/schoolList'){
-      window.location.href = '/schoolList'
+      if(userAccess.roles.indexOf('student') >= 0){
+        window.location.href = '/home'
+      } else {
+        window.location.href = '/schoolList'
+      }
     } else if(toNextPath === '/login' && userAccess.isLogin){
       window.location.href = '/home'
     } else {

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

@@ -1,11 +1,11 @@
 import { post, corePost } from '@/filters/http'
 import config from '@/store/module/config'
 import jwtDecode from 'jwt-decode'
-var srvAdr = localStorage.getItem('srvAdr')
 
 export default {
   Verification: function(item)   {
     return new Promise((resolve) => {
+      let srvAdr = localStorage.getItem('srvAdr')
       let url = config.state[srvAdr].coreAPIUrl
       let nonceStr = 'habook'  // 檢查項目
       let data = {

+ 3 - 11
TEAMModelOS/ClientApp/src/api/schoolList.js

@@ -1,16 +1,8 @@
-import { fetch, post } from '@/filters/http'
-import mockTools from '@/mock'
+import { post } from '@/filters/http'
 export default {
-  // ¥Ó½Ð¥[¤J¾Ç®Õ
-  // data¿é¤J¨Ò: { schoolCode: 'ABCD', userinfo: {'id':'123', 'mail':'123@123.com.tw', 'name':'123','picture': 'http://123/123.png'} }
+  // �ӽХ[�J�Ǯ�
+  // data��J��: { schoolCode: 'ABCD', userinfo: {'id':'123', 'mail':'123@123.com.tw', 'name':'123','picture': 'http://123/123.png'} }
   Join: function(data) {
     return post('/api/SchoolUser/AddSchoolUserSingle', data)
   },
-  List: function() {
-    // return fetch('http://test.com/schoolList')
-    return new Promise((resolve) => {
-      let res = {data: mockTools.data.schoolList}
-      resolve(res)
-    })
-  },  
 }

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

@@ -3,8 +3,12 @@ export default {
     getBlobSAS: function(data) {
         return post('/api/File/getBlobSAS', data)
     },
+    //最开始使用的blob授权API
     getContainerSAS: function(data) {
         return post('/api/File/getContainerSAS', data)
+    },
+    //调整之后的blob授权API
+    blobSasRCW: function (data) {
+        return post('/api/blob/blobSasRCW', data)
     }
-
 }

+ 54 - 14
TEAMModelOS/ClientApp/src/common/BaseMock.vue

@@ -30,9 +30,10 @@
 				isLoading: false,
 				acType: 0,
                 acId: '5ed79799-4e2d-471e-a484-deedb81a8ad7',
-				orderLearnId:'b910aed3-c981-40c7-9753-edebb803999e'
+                orderLearnId: 'b910aed3-c981-40c7-9753-edebb803999e',
+				unitId:'c223e06a-7ee7-4d09-b5b9-d8c7debdcf26'
 			};
-		},
+		}, 
 		created() {},
 		methods: {
 			onMock() {
@@ -51,10 +52,12 @@
 						case 3:
 							this.doMockEvaluation(this.acId)
 							break
-						case 4:
+                        case 4:
+                            this.acId = this.orderLearnId
 							this.doMockSelfLearning(this.acId)
                             break	
-						case 5:
+                        case 5:
+                            this.acId = this.unitId
 							this.doMockSelfLearning(this.acId)
 							break	
 						default:
@@ -161,21 +164,15 @@
                 let acInfo = null
                 if (this.acType == 4) {
                     acInfo = await this.findOrderLearn()
-                    console.log('acInfo')
-                    console.log(acInfo)
                     if (acInfo) {
                         let taskes = await this.findTask()
-                        console.log('task:')
-                        console.log(taskes)
                         let classes = taskes.map((item) => {
                             return item.code
                         })
                         let students = await this.getStudentList(classes)
-                        console.log('students')
-                        console.log(students)
                         for (let item of students) {
                             let rdItem = {
-                                id: this.orderLearnId,
+                                id: this.acId,
                                 code: item.code,
                                 steps: []
                             }
@@ -213,6 +210,49 @@
                     }
                 } else if (this.acType == 5) {
                     acInfo = await this.findUnit()
+                    let taskes = await this.findTask()
+                    let classes = taskes.map((item) => {
+                        return item.code
+                    })
+                    let students = await this.getStudentList(classes)
+                    for (let item of students) {
+                        let radom = this.$jsFn.getBtwRandom(0, 2)
+                        console.log('random:' + radom)
+                        if (radom) {
+                            let rdItem = {
+                                id: this.acId,
+                                code: item.code,
+                                steps: []
+                            }
+                            let aswItem = {
+                                index: 0,
+                                answer: []
+                            }
+                            acInfo[0].item.forEach((question, i) => {
+                                let stItem = {
+                                    index: i,
+                                    ans: this.randomAnswer(question),
+                                    count: this.$jsFn.getBtwRandom(0, 5)
+                                }
+                                aswItem.answer.push(stItem)
+                            })
+                            rdItem.steps.push(aswItem)
+                            result.push(rdItem)
+                        }
+                    }
+                    console.log(result)
+                    this.$api.learnActivity.upsertRecord(result).then(
+                        (res) => {
+                            if (!res.error && res.result.data) {
+                                this.$Message.success('学习数据模拟成功!')
+                            } else {
+                                this.$Message.error('学习数据模拟失败!')
+                            }
+                        },
+                        (err) => {
+                            this.$Message.error('学习数据模拟失败!')
+                        }
+                    )
                 }
                 this.isLoading = false
 
@@ -373,7 +413,7 @@
             async findTask() {
                 return new Promise((r, j) => {
                     this.$api.learnActivity.findTask({
-                        id: this.orderLearnId
+                        id: this.acId
                     }).then(
                         (res) => {
                             if (!res.error && res.result.data) {
@@ -394,7 +434,7 @@
             async findOrderLearn() {
                 return new Promise((r, j) => {
                     let requestData = {
-                        id: this.orderLearnId
+                        id: this.acId
                     }
                     this.$api.learnActivity.FindOrderLearn(requestData).then(
                         res => {
@@ -416,7 +456,7 @@
             async findUnit() {
                 return new Promise((r, j) => {
                     let requestData = {
-                        id: this.acId
+                        id: this.unitId
                     }
                     this.$api.learnActivity.FindUnit(requestData).then(
                         res => {

+ 0 - 0
TEAMModelOS/ClientApp/src/components/learnactivity/ProgressHistogram.less


+ 6 - 2
TEAMModelOS/ClientApp/src/filters/http.js

@@ -3,7 +3,6 @@ import { Message } from 'view-design'
 import router from '@/router/index'
 import config from '@/store/module/config'
 
-var srvAdr = localStorage.getItem('srvAdr')
 axios.defaults.timeout = 30000 // 设置超时时长
 axios.defaults.baseURL = ''
 let refreshing = false
@@ -15,7 +14,8 @@ axios.interceptors.request.use(
 
         // 呼叫API先偵測是否超過一小時,有則回到登入頁
         let webEndTime = localStorage.getItem('webEndTime')
-        if(isProduction && webEndTime){
+        let access_token = localStorage.getItem('access_token')
+        if(isProduction && access_token && webEndTime){
             let time_now = new Date().getTime()
             if(time_now > webEndTime){
                 let login_schooCode = localStorage.getItem('login_schooCode')
@@ -109,6 +109,8 @@ axios.interceptors.response.use(
 // }
 /**检测token是否快过期 */
 function checkToken() {
+    if(!localStorage.getItem('expires_in') || localStorage.getItem('expires_in') == undefined) return false
+
     var nowTime = new Date();
     var offset = nowTime.getTimezoneOffset() / 60
     let cT = Date.parse(nowTime)
@@ -128,7 +130,9 @@ function checkToken() {
 /**刷新token */
 async function refreshToken() {
     refreshing = true
+    let srvAdr = localStorage.getItem('srvAdr')
     let url = config.state[srvAdr].coreAPIUrl
+    console.log(srvAdr)
 
     await axios.post(url + '/oauth2/token', {
         "grant_type": "refresh_token",

+ 3 - 1
TEAMModelOS/ClientApp/src/locale/lang/en-US/login.js

@@ -37,5 +37,7 @@ export default {
         google: 'Google',
         wechat: 'WeChat',
     },
-
+    apiError:{
+        text1: '您的 帳號 或 密碼 不正確'
+    }
 }

+ 3 - 2
TEAMModelOS/ClientApp/src/locale/lang/en-US/schoolList.js

@@ -1,7 +1,7 @@
 export default {
     title1: 'Apply to join school',
     placeholder:{
-        search: 'Please enter the school short code, school code or school name to search ...',
+        search: 'Please enter the school short code, address or school name to search ...',
         area: 'Area',
         province: 'Province',
         city: 'City'
@@ -16,6 +16,7 @@ export default {
         area: 'Area',
         PRVN: 'PRVN',
         shortCode: 'Short code',
-        code: 'Code'
+        code: 'Code',
+        address: 'Address'
     }
 }

+ 3 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/login.js

@@ -37,5 +37,7 @@ export default {
         google: 'Google',
         wechat: 'WeChat',
     },
-
+    apiError:{
+        text1:'您的帐号或密码不正确'
+    }
 }

+ 3 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/schoolList.js

@@ -1,7 +1,7 @@
 export default {
     title1: '申请加入学校',
     placeholder:{
-        search: '请输入学校简码、学校代码或校名称进行检索...',
+        search: '请输入学校简码,地址或校名进行检索...',
         area: '地区别',
         province: '省分',
         city: '县市'
@@ -16,6 +16,7 @@ export default {
         area: '地区别',
         PRVN: '省县市',
         shortCode: '简码',
-        code: '代码'
+        code: '代码',
+        address: '位置'
     }
 }

+ 3 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/login.js

@@ -37,5 +37,7 @@ export default {
         google: 'Google',
         wechat: 'WeChat',
     },
-
+    apiError:{
+        text1: '您的 帳號 或 密碼 不正確'
+    }
 }

+ 3 - 2
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/schoolList.js

@@ -1,7 +1,7 @@
 export default {
     title1: '申請加入學校',
     placeholder:{
-        search: '請輸入學校簡碼、學校代碼或校名稱進行檢索...',
+        search: '請輸入學校簡碼、地址或校名稱進行檢索...',
         area: '地區別',
         province: '省分',
         city: '縣市'
@@ -16,6 +16,7 @@ export default {
         area: '地區別',
         PRVN: '省縣市',
         shortCode: '簡碼',
-        code: '代碼'
+        code: '代碼',
+        address: '位置'
     }
 }

+ 4 - 6
TEAMModelOS/ClientApp/src/mock/index.js

@@ -104,12 +104,10 @@ export default {
       'biology|60-120': 60
     }],
     "schoolList|50": [{
-      'avatar': '@dataImage("100x100")',
-      'name': '@ctitle(10,20)',
-      'area|1': ['大陸', '國際'],
-      'PRVN|1': ['新疆 / 伊犁', '臺灣 / 台北', '北京 / 北京'],
-      'shortCode': '@word(5, 10)',
-      'code': /\d{10,10}/
+      'picture': '@dataImage("100x100")',
+      'schoolName': '@ctitle(10,20)',
+      'schoolCode': '@word(5, 10)',
+      'address': '@ctitle(20,40)'
     }],
     "teacherList|50": [{
       'id':  /[a-z]{2}[A-Z]{2}[0-9]/,

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

@@ -25,7 +25,7 @@ export const routes = [
             name: 'schoolList',
             path: '/',
             meta: {
-            middleware: ['login']
+                middleware: ['login']
             },
             component: resolve => require(['@/view/schoolList/Index.vue'], resolve),
         }

+ 1 - 0
TEAMModelOS/ClientApp/src/service/User.js

@@ -71,6 +71,7 @@ export class User {
           localStorage.removeItem('user_details')
           localStorage.removeItem('access_token')
           localStorage.removeItem('expires_in')
+          localStorage.removeItem('id_token')          
 
           // 重置登录状态
           User.$access.reset();

+ 1 - 0
TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.less

@@ -8,6 +8,7 @@
         font-weight: bold;
         vertical-align: middle;
         text-align: center;
+		cursor: pointer;
     }
 
     .paper-subTitle {

+ 14 - 3
TEAMModelOS/ClientApp/src/view/evaluation/index/TestPaper.vue

@@ -27,10 +27,10 @@
 
 					<!-- 试卷头部信息 -->
 					<div class="paper-header flex-col-center">
-						<p class="paper-title" v-if="!isShowTools">{{paperInfo.name}}</p>
-						<Tooltip content="点击可编辑修改主标题" placement="right" v-else >
+						<p class="paper-title" @click="isSetPaperName = true">{{paperInfo.name}}</p>
+						<!-- <Tooltip content="点击可编辑修改主标题" placement="right" v-else >
 							<p class="paper-title" contenteditable="true" @blur="titleChange($event)">{{paperInfo.name}}</p>
-						</Tooltip>
+						</Tooltip> -->
 					</div>
 					<!-- 题目类型及列表 -->
 					<BaseExerciseList :paper="paperInfo" @dataUpdate="onListUpdate" ref="exList" :isShowTools="isShowTools"
@@ -78,6 +78,16 @@
 				<Button type="primary" @click="onSetScore">确定</Button>
 			</div>
 		</Modal>
+		
+		<!-- 设置试卷标题 -->
+		<Modal v-model="isSetPaperName" title="设置试卷名称" width="400px" class="related-point-modal" style="z-index:99999">
+			<span>试卷名称</span>
+			<Input v-model="paperInfo.name" style="margin:20px 0"></Input>
+			<div slot="footer">
+				<Button type="text" @click="isSetPaperName = false">取消</Button>
+				<Button type="primary" @click="isSetPaperName = false">确定</Button>
+			</div>
+		</Modal>
 
 		<!-- 设置阅卷规则 -->
 		<!-- <Modal v-model="isSetRules" title="设置阅卷规则" width="400px" class="related-point-modal rules-modal" style="z-index:99999">
@@ -144,6 +154,7 @@
 		data() {
 			return {
 				isAllOpen: false,
+				isSetPaperName:false,
 				isSetScore: false,
 				isSetRules: false,
 				isShowSave: false,

+ 4 - 328
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -98,125 +98,7 @@
       </Dropdown>
     </div>
     <div class="login-body">
-      <div class="loginDiv">
-        <div class="loginBox">
-          <div class="title">
-            <div class="logo">
-              <img  width="15" height="15" src="@/assets/icon/tmd_account.svg">
-            </div>
-            <h4 class="text">
-              {{ qrloginFlag ? $t('login.title.QRLogin'): $t('login.title.IDLogin') }}
-            </h4>
-            <Tooltip class="tooltip" placement="right-end" :transfer="true" max-width="200">
-                <img src="@/assets/icon/icon_info.svg" width="15" height="15">
-                <div slot="content">
-                  <p style="font-size: 12px;">{{ $t('login.tooltip.text1') }}</p>
-                </div>
-            </Tooltip>
-          </div>
-          <h4 class="subTitle">
-            {{ qrloginFlag ? $t('login.subTitle.QRLogin') : $t('login.subTitle.IDLogin')}}
-          </h4>
-
-          <template v-if="!qrloginFlag">
-            <Form class="loginForm" ref="loginForm" :model="loginForm" :rules="loginRule" @keydown.enter.native="loginSubmit('loginForm')" :show-message="false">
-              <FormItem class="formItem" prop="id" >
-                <Input v-model="loginForm.id" :placeholder="$t('login.placeholder.id')"/>
-              </FormItem>
-              <FormItem class="formItem"  prop="pass">
-                <Input  type="password" v-model="loginForm.pass" :placeholder="$t('login.placeholder.psw')" >
-                  <Icon size="24" v-show="!loading && loginFormEnter" @click="loginSubmit('loginForm')" type="md-arrow-forward" slot="suffix" />
-                  <div v-show="loading" class="demo-spin-col" slot="suffix">
-                    <Spin>
-                      <Icon type="ios-loading" size=18 class="demo-spin-icon-load"></Icon>
-                    </Spin>
-                  </div>
-                </Input>
-              </FormItem>
-              <div class="errlable">{{ loginErrText }}</div>
-            </Form>
-
-            <div class="extra">
-              <div class="qrlogin">
-                <div class="logo">
-                  <img  width="15" height="15" src="@/assets/icon/icon_qrcode.svg">
-                </div>
-                <a @click="chgLoginType()">{{ $t('login.link.QRLogin') }}</a>
-              </div>
-              <div class="link">
-                <a>{{ $t('login.link.regist') }}</a> | <a>{{ $t('login.link.forgetPsw') }}</a>
-              </div>
-            </div>
-
-            <div class="communyLoging">
-              <div class="description">{{ $t('login.communy.title')}}</div>
-              <div class="links">
-                <div class="icon">
-                  <img  src="@/assets/icon/icon_fb.svg">
-                  <span>{{ $t('login.communy.fb')}}</span>
-                </div>
-                <div class="icon">
-                  <img  src="@/assets/icon/icon_google.svg">
-                  <span>{{ $t('login.communy.google')}}</span>
-                </div>
-                <div class="icon">
-                  <img  src="@/assets/icon/icon_wechat.svg">
-                  <span>{{ $t('login.communy.wechat')}}</span>
-                </div>
-              </div>
-            </div>
-          </template>
-          <template v-else>
-            <div class="qrloginMode">
-              <img class="qrcode" src="@/assets/image/demoQRCode.jpg">
-              <div class="links">
-                <div class="icon-a">
-                  <img src="@/assets/icon/icon_account.svg">
-                  <a @click="chgLoginType()">{{ $t('login.link.IDLogin') }}</a>
-                </div>
-                <a > {{ $t('login.link.regist') }}</a>
-              </div>
-            </div>
-          </template>
-
-        </div>
-
-        <div class="loginBox">
-          <div class="title">
-            <div class="logo">
-              <img  width="15" height="15" src="@/assets/icon/tmd_account.svg">
-            </div>
-            <h4 class="text">{{ $t('login.title.schoolLogin') }}</h4>
-            <Tooltip class="tooltip" placement="right-end" :transfer="true" max-width="200">
-                <img src="@/assets/icon/icon_info.svg" width="15" height="15">
-                <div slot="content">
-                  <p style="font-size: 12px;">{{ $t('login.tooltip.text2') }}</p>
-                </div>
-            </Tooltip>
-          </div>
-          <h4 class="subTitle">{{ $t('login.subTitle.schoolLogin') }}</h4>
-          <Form class="loginForm">
-            <FormItem class="formItem" style="margin-bottom: 15px;" >
-              <Select v-model="schoolForm.schoolCode" :placeholder="$t('login.placeholder.schoolMenu')" filterable clearable >
-                <template v-for="(item, index) in data3" >
-                  <OptionGroup :label="item.area" :key="index">
-                    <Option v-for="school in item.schools" :key="school.id" :value="school.id">{{ school.name }}</Option>
-                  </OptionGroup>
-                </template>
-              </Select>
-            </FormItem>
-            <FormItem class="formItem" prop="id" >
-              <Input v-model="schoolForm.id" :placeholder="$t('login.placeholder.schoolID')"/>
-            </FormItem>
-            <FormItem class="formItem"  prop="pass">
-              <Input  type="password" v-model="schoolForm.pass" :placeholder="$t('login.placeholder.schoolPsw')" >
-                <Icon v-show="schoolFormEnter" @click="login()" type="md-arrow-forward" slot="suffix" />
-              </Input>
-            </FormItem>
-            <div class="errlable">{{ schoolErrText }}</div>
-          </Form>
-        </div>
-      </div>
+        <SignIn/> <!-- 登入模組 -->
     </div>
     <div class="login-footer">
       <h5 style="position: absolute;bottom:0;width: 100%;padding: 7px;color: #515a6e;">&copy; HABOOL Group 2019</h5>
@@ -225,137 +107,17 @@
 </template>
 
 <script>
-import { User } from '@/service/User'
 import { mapState, mapGetters } from 'vuex'
+import SignIn from '@/view/login/components/SignIn.vue'
 
 export default {
-  data() {
-    const validatePass = (rule, value, callback) => {
-      if (value === '') {
-          callback(new Error());
-          this.loginErrText = this.$t('error.required')
-      } else if (value.search(/^\+/) == 0) {
-          callback(new Error());
-          this.loginErrText = this.$t('error.format.default')
-      } else {
-        if(value.indexOf('@') >=0){ //是否為Email
-            var emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
-            if(value.search(emailRule)!= -1){
-                callback();
-                this.loginErrText = ''
-            } else {
-                callback(new Error());
-                this.loginErrText = this.$t('error.format.email')
-            }
-        } else {
-          callback();
-          this.loginErrText = ''
-        }
-        //都不是就是HabookID
-      }
-    };
-    const validatePasswordCheck = (rule, value, callback) => {
-        if (value === '') {
-            callback(new Error());
-            this.loginErrText = this.$t('error.required')
-        }
-        else {
-            callback();
-            this.loginErrText = ''
-        }
-    };    
-    return {
-      qrloginFlag: false,
-      identity: 0,
-      single: '',
-      loginForm: {
-          id: '',
-          pass: '',
-      },
-      loginRule: {
-          id: [
-              { validator: validatePass, trigger: 'blur' },
-          ],
-          pass: [
-              { validator: validatePasswordCheck, trigger: 'blur' },
-          ]
-      },
-      schoolForm: {
-        schoolCode: '',
-        id: '',
-        pass: ''
-      },
-      loginErrText: '',
-      schoolErrText: '',
-      data3: [
-          {
-              area: '四川省',
-              schools: [
-                {
-                  id: 'DFGDFG',
-                  name: '成都市鹽道街小學',
-                },
-                {
-                  id: 'QWERRR',
-                  name: '四川師範大學附屬實驗學校',
-                },
-                {
-                  id: 'ERTRE',
-                  name: '成都市和平街小學',
-                },
-                {
-                  id: 'ERTRE1',
-                  name: '成都師範銀都紫藤小學',
-                },
-                {
-                  id: 'ERTRE2',
-                  name: '成都市錦江區駙馬小學校',
-                }
-              ]
-          },
-          {
-              area: '湖北省',
-              schools: [
-                {
-                  id: 'ERTRE3',
-                  name: '武漢市第三十中學',
-                },
-                {
-                  id: 'ERTRE4',
-                  name: '武漢市漢鐵寄宿初級中學',
-                },
-                {
-                  id: 'ERTRE5',
-                  name: '武漢市江岸區新建小學',
-                }
-              ]
-          },
-      ],
-      loading: false
-    }
+  components:{
+    SignIn
   },
   computed: {
     ...mapState({
       config: state => state.config
     }),
-    ...mapGetters({
-        loginSchooCode: 'user/getLoginSchooCode',
-    }),
-    userAccess() { return this.$access.getExtendInfo('userAccess');},
-    userInfo() { return this.$access.getExtendInfo('userInfo');},
-    loginFormEnter: function(){
-      let flag = false
-      if(this.loginForm.id && this.loginForm.pass) flag = true
-      return flag
-    },
-    schoolFormEnter: function(){
-      let flag = false
-      if(this.schoolForm.schoolCode && this.schoolForm.id && this.schoolForm.pass) flag = true
-      return flag
-    }
-  },
-  created() {
-    // if(localStorage.getItem('roleCode')) this.setUser(localStorage.getItem('roleCode'))
   },
   methods: {
     chgLoginType: function(){
@@ -368,95 +130,9 @@ export default {
           window.open(this.config[val].domainUrl);
         } else {
           this.$store.dispatch('config/setSrvAdr', val)
-          console.log(this.config)
         }
       }
     },
-    loginSubmit: function(name){
-      this.$refs[name].validate( async(valid) => {
-        if (valid) {
-          this.loading = true
-          let result;
-          let id = this.loginForm.id
-
-          if(id.indexOf(0) == 0) id = id.substr(1)
-
-          // 呼叫Azure是否帳號正確
-          await this.$api.login.Verification({id: id, pass: this.loginForm.pass}).then(res => {
-            this.loading = false
-            result = res
-          })
-
-          if(result.error){
-            this.loginErrText = this.$t('你的 帳號 或 密碼 不正確')
-          } else {
-            let t_Data = this.$jwtDecode(result.id_token)
-            let id_token = result.id_token
-
-            // 設定idToken 和 保存時間
-            localStorage.setItem("access_token", result.access_token)
-            localStorage.setItem("expires_in", result.expires_in)
-
-            // 取得大雲裡面使用者的資訊
-            await this.$api.login.getSingleSchoolUser({ id: t_Data.sub }).then( res => { 
-              result = []
-              if(res.result.data.length != 0){
-                result = res.result.data
-              }
-            })
-            // 整理符合登入的內容
-            let userDetails = result.filter(function(item){
-              return parseInt(item.joinStatus) == 1
-            })
-            // 沒有符合的學校
-            if(userDetails.length === 0){
-              let userAccess = {
-                id: t_Data.sub,
-                role: [],
-                authority: [],
-                picture: t_Data.picture ? t_Data.picture : ''
-              }
-
-              User.login(userAccess).then(res => {
-                if(res) {
-                  // 沒有加入過任何一間大雲學校,直接到選擇學校頁面
-                  this.$router.push({ name: 'schoolList' })
-                }
-              })
-            } else {
-              // 設定user詳細資訊
-              this.$store.dispatch('user/setUserDetails', userDetails)
-
-              let _this = this
-              let loginSchoolData = userDetails.filter(function(item){
-                return item.schoolCode == _this.loginSchooCode
-              })
-
-              // 檢查登入過的痕跡
-              if(loginSchoolData.length === 0){
-                // 以第一筆登入
-                let firstSchoolInfo =  userDetails[0]
-                // 設定此瀏覽器的學校簡碼
-                this.$store.dispatch('user/setSchoolCode', firstSchoolInfo.schoolCode)
-
-                // 設定權限並登入
-                User.login(firstSchoolInfo).then(res => {
-                  if(res) {
-                    this.$router.push({ path: '/home' })
-                  }
-                })
-              } else {
-                User.login(loginSchoolData[0]).then(res => {
-                  if(res) {
-                    this.$router.push({ path: '/home' })
-                  }
-                })
-              }
-            }
-          }
-        }
-      })
-    }
   }
 }
 </script>

+ 123 - 0
TEAMModelOS/ClientApp/src/view/login/components/SignIn.less

@@ -0,0 +1,123 @@
+.loginDiv{
+    width: 800px;
+    display: flex;
+    // align-items: center;
+    justify-content: space-between;
+    .loginBox{
+        width: 300px;
+        height: 310px;
+        .title{
+            display: flex;
+            align-items: center;
+            // align-content: center !important;
+            margin-bottom: 5px;
+            .logo{
+                margin-right: 5px;
+                height: 15px;
+            }
+            .text{
+                margin-right: 15px;
+                color: #ffffff;
+                font-size: ;
+            }
+            .tooltip{
+                height: 15px;
+            }
+        }
+        .subTitle{
+            font-size: 12px;
+            color: #d1d1d3;
+            margin-bottom: 25px;
+        }
+        .loginForm{
+            margin-bottom: 10px;
+            .formItem{
+                margin: 0;
+            }
+            .errlable{
+                text-align: right;
+                color: #f22613;
+                font-size: 12px;
+                margin-top: 3px;
+                height: 12px;
+            }
+        }
+        .extra{
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            margin-bottom: 30px;
+            .qrlogin{
+                display: flex;
+                align-items: center;
+                .logo{
+                    margin-right: 5px;
+                    height: 15px;
+                }
+                a{
+                    font-size: 12px;
+                    color: #668fbc;
+                    text-decoration: underline;
+                }
+            }
+            .link{
+                a{
+                    font-size: 12px;
+                    color: #668fbc;
+                    text-decoration: underline;
+                }
+            }
+        }
+        .communyLoging{
+            .description{
+                text-align: center;
+                font-size: 12px;
+                color: #d1d1d3;
+                margin-bottom: 20px;
+                letter-spacing: 1.5px;
+            }
+            .links{
+                display: flex;
+                align-items: center;
+                justify-content: space-around;
+                .icon{
+                    display: flex;
+                    align-items: center;
+                    flex-direction: column;
+                    img{
+                        width: 35px;
+                    }
+                    span{
+                        font-size: 12px;
+                        color: #d1d1d3;
+                    }
+                }
+            }
+        }
+        .qrloginMode{
+            .qrcode{
+                width: 100%;
+                display: block;
+                margin-bottom: 10px;
+            }
+            .links{
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                .icon-a{
+                    display: flex;
+                    align-items: center;
+                    img{
+                        margin-right: 3px;
+                        width: 15px;
+                        height: 15px;
+                    }
+                }
+                a{
+                    font-size: 12px;
+                    color: #668fbc;
+                }
+            }
+        }
+    }
+}

+ 359 - 0
TEAMModelOS/ClientApp/src/view/login/components/SignIn.vue

@@ -0,0 +1,359 @@
+<style lang="less" scoped>
+  @import './SignIn.less';
+</style>
+
+<template>
+    <div class="loginDiv">
+        <div class="loginBox">
+          <div class="title">
+            <div class="logo">
+              <img  width="15" height="15" src="@/assets/icon/tmd_account.svg">
+            </div>
+            <h4 class="text">
+              {{ qrloginFlag ? $t('login.title.QRLogin'): $t('login.title.IDLogin') }}
+            </h4>
+            <Tooltip class="tooltip" placement="right-end" :transfer="true" max-width="200">
+                <img src="@/assets/icon/icon_info.svg" width="15" height="15">
+                <div slot="content">
+                  <p style="font-size: 12px;">{{ $t('login.tooltip.text1') }}</p>
+                </div>
+            </Tooltip>
+          </div>
+          <h4 class="subTitle">
+            {{ qrloginFlag ? $t('login.subTitle.QRLogin') : $t('login.subTitle.IDLogin')}}
+          </h4>
+
+          <template v-if="!qrloginFlag">
+            <Form class="loginForm" ref="loginForm" :model="loginForm" :rules="loginRule" @keydown.enter.native="loginSubmit('loginForm')" :show-message="false">
+              <FormItem class="formItem" prop="id" >
+                <Input v-model="loginForm.id" :placeholder="$t('login.placeholder.id')"/>
+              </FormItem>
+              <FormItem class="formItem"  prop="pass">
+                <Input  type="password" v-model="loginForm.pass" :placeholder="$t('login.placeholder.psw')" >
+                  <Icon size="24" v-show="!loading && loginFormEnter" @click="loginSubmit('loginForm')" type="md-arrow-forward" slot="suffix" />
+                  <div v-show="loading" class="demo-spin-col" slot="suffix">
+                    <Spin>
+                      <Icon type="ios-loading" size=18 class="demo-spin-icon-load"></Icon>
+                    </Spin>
+                  </div>
+                </Input>
+              </FormItem>
+              <div class="errlable">{{ loginErrText }}</div>
+            </Form>
+
+            <div class="extra">
+              <div class="qrlogin">
+                <div class="logo">
+                  <img  width="15" height="15" src="@/assets/icon/icon_qrcode.svg">
+                </div>
+                <a @click="chgLoginType()">{{ $t('login.link.QRLogin') }}</a>
+              </div>
+              <div class="link">
+                <a>{{ $t('login.link.regist') }}</a> | <a>{{ $t('login.link.forgetPsw') }}</a>
+              </div>
+            </div>
+
+            <div class="communyLoging">
+              <div class="description">{{ $t('login.communy.title')}}</div>
+              <div class="links">
+                <div class="icon">
+                  <img  src="@/assets/icon/icon_fb.svg">
+                  <span>{{ $t('login.communy.fb')}}</span>
+                </div>
+                <div class="icon">
+                  <img  src="@/assets/icon/icon_google.svg">
+                  <span>{{ $t('login.communy.google')}}</span>
+                </div>
+                <div class="icon">
+                  <img  src="@/assets/icon/icon_wechat.svg">
+                  <span>{{ $t('login.communy.wechat')}}</span>
+                </div>
+              </div>
+            </div>
+          </template>
+          <template v-else>
+            <div class="qrloginMode">
+              <img class="qrcode" src="@/assets/image/demoQRCode.jpg">
+              <div class="links">
+                <div class="icon-a">
+                  <img src="@/assets/icon/icon_account.svg">
+                  <a @click="chgLoginType()">{{ $t('login.link.IDLogin') }}</a>
+                </div>
+                <a > {{ $t('login.link.regist') }}</a>
+              </div>
+            </div>
+          </template>
+        </div>
+
+        <div class="loginBox">
+          <div class="title">
+            <div class="logo">
+              <img  width="15" height="15" src="@/assets/icon/tmd_account.svg">
+            </div>
+            <h4 class="text">{{ $t('login.title.schoolLogin') }}</h4>
+            <Tooltip class="tooltip" placement="right-end" :transfer="true" max-width="200">
+                <img src="@/assets/icon/icon_info.svg" width="15" height="15">
+                <div slot="content">
+                  <p style="font-size: 12px;">{{ $t('login.tooltip.text2') }}</p>
+                </div>
+            </Tooltip>
+          </div>
+          <h4 class="subTitle">{{ $t('login.subTitle.schoolLogin') }}</h4>
+          <Form class="loginForm">
+            <FormItem class="formItem" style="margin-bottom: 15px;" >
+              <Select v-model="schoolForm.schoolCode" :placeholder="$t('login.placeholder.schoolMenu')" filterable clearable >
+                <template v-for="(item, index) in data3" >
+                  <OptionGroup :label="item.area" :key="index">
+                    <Option v-for="school in item.schools" :key="school.id" :value="school.id">{{ school.name }}</Option>
+                  </OptionGroup>
+                </template>
+              </Select>
+            </FormItem>
+            <FormItem class="formItem" prop="id" >
+              <Input v-model="schoolForm.id" :placeholder="$t('login.placeholder.schoolID')"/>
+            </FormItem>
+            <FormItem class="formItem"  prop="pass">
+              <Input  type="password" v-model="schoolForm.pass" :placeholder="$t('login.placeholder.schoolPsw')" >
+                <Icon v-show="schoolFormEnter" @click="login()" type="md-arrow-forward" slot="suffix" />
+              </Input>
+            </FormItem>
+            <div class="errlable">{{ schoolErrText }}</div>
+          </Form>
+        </div>
+    </div>
+</template>
+<script>
+import { User } from '@/service/User'
+import { mapState, mapGetters } from 'vuex'
+
+export default {
+  data() {
+    const validatePass = (rule, value, callback) => {
+      if (value === '') {
+          callback(new Error());
+          this.loginErrText = this.$t('error.required')
+      } else if (value.search(/^\+/) == 0) {
+          callback(new Error());
+          this.loginErrText = this.$t('error.format.default')
+      } else {
+        if(value.indexOf('@') >=0){ //是否為Email
+            var emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
+            if(value.search(emailRule)!= -1){
+                callback();
+                this.loginErrText = ''
+            } else {
+                callback(new Error());
+                this.loginErrText = this.$t('error.format.email')
+            }
+        } else {
+          callback();
+          this.loginErrText = ''
+        }
+        //都不是就是HabookID
+      }
+    };
+    const validatePasswordCheck = (rule, value, callback) => {
+        if (value === '') {
+            callback(new Error());
+            this.loginErrText = this.$t('error.required')
+        }
+        else {
+            callback();
+            this.loginErrText = ''
+        }
+    };    
+    return {
+      qrloginFlag: false,
+      loginForm: {
+          id: '',
+          pass: '',
+      },
+      loginRule: {
+          id: [
+              { validator: validatePass, trigger: 'blur' },
+          ],
+          pass: [
+              { validator: validatePasswordCheck, trigger: 'blur' },
+          ]
+      },
+      schoolForm: {
+        schoolCode: '',
+        id: '',
+        pass: ''
+      },
+      loginErrText: '',
+      schoolErrText: '',
+      data3: [
+          {
+              area: '四川省',
+              schools: [
+                {
+                  id: 'DFGDFG',
+                  name: '成都市鹽道街小學',
+                },
+                {
+                  id: 'QWERRR',
+                  name: '四川師範大學附屬實驗學校',
+                },
+                {
+                  id: 'ERTRE',
+                  name: '成都市和平街小學',
+                },
+                {
+                  id: 'ERTRE1',
+                  name: '成都師範銀都紫藤小學',
+                },
+                {
+                  id: 'ERTRE2',
+                  name: '成都市錦江區駙馬小學校',
+                }
+              ]
+          },
+          {
+              area: '湖北省',
+              schools: [
+                {
+                  id: 'ERTRE3',
+                  name: '武漢市第三十中學',
+                },
+                {
+                  id: 'ERTRE4',
+                  name: '武漢市漢鐵寄宿初級中學',
+                },
+                {
+                  id: 'ERTRE5',
+                  name: '武漢市江岸區新建小學',
+                }
+              ]
+          },
+      ],
+      loading: false
+    }
+  },
+  computed: {
+    ...mapState({
+      config: state => state.config
+    }),
+    ...mapGetters({
+        loginSchooCode: 'user/getLoginSchooCode',
+    }),
+    userAccess() { return this.$access.getExtendInfo('userAccess');},
+    userInfo() { return this.$access.getExtendInfo('userInfo');},
+    loginFormEnter: function(){
+      let flag = false
+      if(this.loginForm.id && this.loginForm.pass) flag = true
+      return flag
+    },
+    schoolFormEnter: function(){
+      let flag = false
+      if(this.schoolForm.schoolCode && this.schoolForm.id && this.schoolForm.pass) flag = true
+      return flag
+    }
+  },
+  created() {
+    // if(localStorage.getItem('roleCode')) this.setUser(localStorage.getItem('roleCode'))
+  },
+  methods: {
+    chgLoginType: function(){
+      this.qrloginFlag = !this.qrloginFlag
+    },
+    chgSerType: function(val){
+      if(this.config.srvAdr != val){
+        let isProduction = process.env.NODE_ENV == 'development' ? false : true
+        if(isProduction){
+          window.open(this.config[val].domainUrl);
+        } else {
+          this.$store.dispatch('config/setSrvAdr', val)
+          console.log(this.config)
+        }
+      }
+    },
+    loginSubmit: function(name){
+      this.$refs[name].validate( async(valid) => {
+        if (valid) {
+          this.loading = true
+          let result;
+          let id = this.loginForm.id
+
+          if(id.indexOf(0) == 0) id = id.substr(1)
+
+          // 呼叫Azure是否帳號正確
+          await this.$api.login.Verification({id: id, pass: this.loginForm.pass}).then(res => {
+            this.loading = false
+            result = res
+          })
+
+          if(result.error){
+            this.loginErrText = this.$t('login.apiError.text1')
+          } else {
+            let t_Data = this.$jwtDecode(result.id_token)
+            let id_token = result.id_token
+
+            // 設定Token 和 保存時間
+            localStorage.setItem("id_token", result.id_token)
+            localStorage.setItem("access_token", result.access_token)
+            localStorage.setItem("expires_in", result.expires_in)
+
+            // 取得大雲裡面使用者的資訊
+            await this.$api.login.getSingleSchoolUser({ id: t_Data.sub }).then( res => { 
+              result = []
+              if(res.result.data.length != 0){
+                result = res.result.data
+              }
+            })
+            // 整理符合登入的內容
+            let userDetails = result.filter(function(item){
+              return parseInt(item.joinStatus) == 1
+            })
+            // 沒有符合的學校
+            if(userDetails.length === 0){
+              let userAccess = {
+                id: t_Data.sub,
+                role: [],
+                authority: [],
+                picture: t_Data.picture ? t_Data.picture : ''
+              }
+
+              User.login(userAccess).then(res => {
+                if(res) {
+                  // 沒有加入過任何一間大雲學校,直接到選擇學校頁面
+                  this.$router.push({ name: 'schoolList' })
+                }
+              })
+            } else {
+              // 設定user詳細資訊
+              this.$store.dispatch('user/setUserDetails', userDetails)
+
+              let _this = this
+              let loginSchoolData = userDetails.filter(function(item){
+                return item.schoolCode == _this.loginSchooCode
+              })
+
+              // 檢查登入過的痕跡
+              if(loginSchoolData.length === 0){
+                // 以第一筆登入
+                let firstSchoolInfo =  userDetails[0]
+                // 設定此瀏覽器的學校簡碼
+                this.$store.dispatch('user/setSchoolCode', firstSchoolInfo.schoolCode)
+
+                // 設定權限並登入
+                User.login(firstSchoolInfo).then(res => {
+                  if(res) {
+                    this.$router.push({ path: '/home' })
+                  }
+                })
+              } else {
+                User.login(loginSchoolData[0]).then(res => {
+                  if(res) {
+                    this.$router.push({ path: '/home' })
+                  }
+                })
+              }
+            }
+          }
+        }
+      })
+    }
+  }
+}
+</script>

+ 91 - 67
TEAMModelOS/ClientApp/src/view/schoolList/Index.vue

@@ -7,11 +7,11 @@
         <div class="title">
             <h1>{{ $t('schoolList.title1')}}</h1>
         </div>
-        <Row class="filterBox" type="flex" justify="center" :gutter="16">
+        <Row class="filterBox" type="flex" :gutter="16">
             <Col span="11">
                 <Input v-model="filterText" class="search" suffix="ios-search" :placeholder="$t('schoolList.placeholder.search')" />
             </Col>
-            <Col span="3">
+            <!-- <Col span="3">
                 <Select class="select" v-model="area" :placeholder="$t('schoolList.placeholder.area')" clearable>
                     <Option v-for="item in areaList" :value="item.value" :key="item.value" >{{ item.label }}</Option>
                 </Select>
@@ -25,18 +25,18 @@
                 <Select class="select" v-model="city" :placeholder="$t('schoolList.placeholder.city')" clearable>
                     <Option v-for="item in cityList" :value="item.value" :key="item.value">{{ item.label }}</Option>
                 </Select>
-            </Col>
+            </Col> -->
         </Row>                  
         <span class="tableBox">
             <Table height="550" class="vue-table scrollstyle" :columns="columns" :data="filteredRows">
-                <template slot-scope="{ row }" slot="avatar">
-                    <img :src="row.avatar" width="30" style="border-radius: 15px;border 1px #fff;">
+                <template slot-scope="{ row }" slot="picture">
+                    <img :src="row.picture" width="30" style="border-radius: 15px;border 1px #fff;">
                 </template>
-                <template slot-scope="{ row }" slot="shortCode">
+                <template slot-scope="{ row }" slot="schoolCode">
                     <span>{{ row.shortCode |  upper}}</span>
                 </template>
                 <template slot-scope="{ row }" slot="action">                
-                    <Button v-if="applySchool.indexOf(row.shortCode) <= 0" class="appButton application" size="small" @click="applicationSchool(row.shortCode)">{{ $t('schoolList.btn.apply') }}</Button> 
+                    <Button v-if="applySchool.indexOf(row.schoolCode) <= 0" class="appButton application" size="small" @click="applicationSchool(row.schoolCode)">{{ $t('schoolList.btn.apply') }}</Button> 
                     <Button v-else class="verifyButton" size="small" disabled>{{ $t('schoolList.btn.pending') }}</Button>
                 </template>
             </Table>
@@ -55,33 +55,42 @@ export default {
         columns: [
             {
                 title: ' ',
-                slot: 'avatar',
+                slot: 'picture',
                 width: 150,
                 align: 'center'
             },
             {
                 title: this.$t('schoolList.columns.name'),
-                key: 'name'
+                key: 'schoolName'
             },
+            // {
+            //     title: this.$t('schoolList.columns.area'),
+            //     width: 150,
+            //     key: 'area'
+            // },
+            // {
+            //     title: this.$t('schoolList.columns.PRVN'),
+            //     width: 150,
+            //     key: 'PRVN'
+            // },
+            // {
+            //     title: this.$t('schoolList.columns.shortCode'),
+            //     width: 150,
+            //     slot: 'shortCode',
+            // },
+            // {
+            //     title: this.$t('schoolList.columns.code'),
+            //     width: 150,
+            //     key: 'code'
+            // },
             {
-                title: this.$t('schoolList.columns.area'),
-                width: 150,
-                key: 'area'
-            },
-            {
-                title: this.$t('schoolList.columns.PRVN'),
-                width: 150,
-                key: 'PRVN'
+                title: this.$t('schoolList.columns.address'),
+                key: 'address'
             },
             {
                 title: this.$t('schoolList.columns.shortCode'),
                 width: 150,
-                slot: 'shortCode',
-            },
-            {
-                title: this.$t('schoolList.columns.code'),
-                width: 150,
-                key: 'code'
+                key: 'schoolCode'
             },
             {
                 title: ' ',
@@ -95,44 +104,44 @@ export default {
         area: '',
         province: '',
         city: '',
-        areaList: [
-            {
-                value: '國際',
-                label: '國際'
-            },
-            {
-                value: '大陸',
-                label: '大陸'
-            }            
-        ],
-        provinceList:[
-            {
-                value: '臺灣',
-                label: '臺灣'
-            },
-            {
-                value: '北京',
-                label: '北京'
-            },
-            {
-                value: '新疆',
-                label: '新疆'
-            },
-        ],
-        cityList: [
-            {
-                value: '北京',
-                label: '北京'
-            },
-            {
-                value: '伊犁',
-                label: '伊犁'
-            },
-            {
-                value: '台北',
-                label: '台北'
-            },
-        ],        
+        // areaList: [
+        //     {
+        //         value: '國際',
+        //         label: '國際'
+        //     },
+        //     {
+        //         value: '大陸',
+        //         label: '大陸'
+        //     }            
+        // ],
+        // provinceList:[
+        //     {
+        //         value: '臺灣',
+        //         label: '臺灣'
+        //     },
+        //     {
+        //         value: '北京',
+        //         label: '北京'
+        //     },
+        //     {
+        //         value: '新疆',
+        //         label: '新疆'
+        //     },
+        // ],
+        // cityList: [
+        //     {
+        //         value: '北京',
+        //         label: '北京'
+        //     },
+        //     {
+        //         value: '伊犁',
+        //         label: '伊犁'
+        //     },
+        //     {
+        //         value: '台北',
+        //         label: '台北'
+        //     },
+        // ],        
         filterText: ''
     }
 
@@ -206,17 +215,32 @@ export default {
     }
     },
     created() {
-        this.$api.schoolList.List().then(res => {
-            this.schoolList = res.data
+    // 取得所有學校資料
+       this.$api.GetAllSchoolBaesInfo({}).then(
+            res => {
+                this.schoolList = res.result.data
+            console.log(res.result.data, 'res.result.data');
         })
+        console.log(this.userInfo)
     },
     methods: {
         applicationSchool: function(schoolCode){
-            // this.$api.schoolList.Join({id: this.userInfo.TEAMModelId, schoolCode: schoolCode}).then(result => {
-                
-                // this.$store.dispatch('user/setUserDetails', userDetails)
+
+            // 待前端 token 出來在打算
+            // // 基本資料構成 start--
+            // let inputInfo = { 
+            //     'id': this.userInfo.id,
+            //     'name': this.userInfo.name,
+            //     'picture': this.userInfo.picture,
+            // };
+            // //以下是前端可得的資料--end--
+            // inputInfo.joinStatus = 3; //請追加「加入狀態」  3:申請中
+            // let data = { schoolCode: schoolCode, userinfo: userinfo };
+            // this.$api.schoolList.Join(data).then(
+            //     res => {
+            //         console.log('userJoinSchoolTest data:');
+            //         console.log(res.result.data);
             // })
-            alert('API向後端申請')
         },
         logout(){
             User.logout()

+ 5 - 5
TEAMModelOS/ClientApp/src/view/selflearning/LearnProgress.vue

@@ -5,7 +5,7 @@
                 <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:15px;">活动进度概览</p>
                 <div class="whole-progress-wrap">
                     <div class="progress-histogram-wrap" style="margin:auto;">
-                        <ProgressHistogram @clickStep="clickStep"></ProgressHistogram>
+                        <!--<ProgressHistogram @clickStep="clickStep"></ProgressHistogram>-->
                     </div>
                 </div>
                 <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:50px;margin-bottom:30px;">
@@ -54,11 +54,11 @@
     </div>
 </template>
 <script>
-    import ProgressHistogram from '@/components/learnactivity/ProgressHistogram.vue'
+    //import ProgressHistogram from '@/components/learnactivity/ProgressHistogram.vue'
     export default {
-        components: {
-            ProgressHistogram
-        },
+        //components: {
+        //    ProgressHistogram
+        //},
         data() {
             return {
                 pageSize: 10,

+ 67 - 31
TEAMModelOS/ClientApp/src/view/selfstudy/ActivityInfo.vue

@@ -42,18 +42,19 @@
                                     <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:15px;">活动进度概览</p>
                                     <div class="whole-progress-wrap">
                                         <div class="progress-histogram-wrap" style="margin:auto;">
-                                            <ProgressHistogram :countData="countData" @clickStep="clickStep"></ProgressHistogram>
+                                            <ProgressBar v-if="learnContent.pk == 'LearnProcess' && learnContent.steps.length > 1" :countData="countData" @clickStep="clickStep"></ProgressBar>
+                                            <ProgressPie v-else :pieData="pieData"></ProgressPie>
                                         </div>
                                     </div>
                                     <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:50px;margin-bottom:30px;">
                                         学生进度概览
                                     </p>
-                                    <div class="learn-progress-filter dark-iview-select">
+                                    <!--<div class="learn-progress-filter dark-iview-select">
                                         <span class="filter-label">搜学生:</span>
                                         <Select v-model="curStudent" filterable style="display: inline-block;width: 200px;" size="small">
                                             <Option v-for="item in classList[curClassIndex].students" :value="item.studentId" :key="item.value">{{ item.name }}</Option>
                                         </Select>
-                                    </div>
+                                    </div>-->
                                     <Table :columns="studentColumns" :data="showRecord" :show-header="true" style="margin:0px 25px;" no-data-text="此班暂无学生">
                                         <template slot-scope="{ row, index }" slot="isComplete">
                                             <Icon size="20" type="md-checkmark" color="aqua" v-if="row.isComplete == 1" />
@@ -130,20 +131,22 @@
     </div>
 </template>
 <script>
-    import ProgressHistogram from '@/components/learnactivity/ProgressHistogram.vue'
+    import ProgressBar from './ProgressBar.vue'
+    import ProgressPie from './ProgressPie.vue'
     import Loading from '@/common/Loading.vue'
     import AnswerDetail from './AnswerDetail.vue'
     import AnswerRecord from './AnswerRecord.vue'
 
     export default {
         components: {
-            AnswerDetail,AnswerRecord,Loading,ProgressHistogram
+            AnswerDetail,AnswerRecord,Loading,ProgressBar,ProgressPie
         },
         props: {
             learnContent: {
                 default: () => {
                     return {
-                        id:''
+                        id: '',
+                        pk:''
                     }
                 },
                 type: Object
@@ -245,22 +248,21 @@
             confirmRevoke() {
                 let requestData = {
                     id: this.learnContent.id,
-                    pk: this.classList[this.curClassIndex]
+                    pk: this.classList[this.curClassIndex].classroomCode
                 }
-                console.log(this.classList)
-                //this.$api.learnActivity.deleteTask(requestData).then(
-                //    (res) => {
-                //        if (!res.error) {
-                //            this.$Message.success('撤销成功!')
-                //            console.log()
-                //        } else {
-                //            this.$Message.error('API error!')
-                //        }
-                //    },
-                //    (err) => {
-                //        this.$Message.error('API error!')
-                //    }
-                //)
+                this.$api.learnActivity.deleteTask(requestData).then(
+                    (res) => {
+                        if (!res.error) {
+                            this.$Message.success('撤销成功!')
+                            this.classList[this.curClassIndex][this.learnContent.id] = undefined
+                        } else {
+                            this.$Message.error('API error!')
+                        }
+                    },
+                    (err) => {
+                        this.$Message.error('API error!')
+                    }
+                )
             },
             /**
              * 确认分享学习内容
@@ -304,6 +306,16 @@
             goToAnswer() {
                 this.showAnswer = true
             },
+            /**
+             *检测是否首次访问学生数据 
+             * */
+            checkFindRecord() {
+                if (this.classList[this.curClassIndex][this.learnContent.id] && !this.classList[this.curClassIndex][this.learnContent.id].record) {
+                    this.findRecord()
+                } else {
+                    this.getPageData()
+                }
+            },
             /**
              * 获取学生学习数据
              * */
@@ -368,8 +380,13 @@
                             steps: []
                         })
                     }
-                    this.$set(this.classList[this.curClassIndex][this.learnContent.id], 'record', record)
-                    this.getPageData()
+                    if (this.classList[this.curClassIndex][this.learnContent.id]) {
+                        this.$set(this.classList[this.curClassIndex][this.learnContent.id], 'record', record)
+                        this.getPageData()
+                    } else {
+                        this.showRecord = []
+                    }
+                    
                     this.isLoading = false
                 }
                 
@@ -400,7 +417,8 @@
                         }
                     )
                 } else {
-                    this.getPageData()
+                    this.checkFindRecord()
+                    
                     setTimeout(() => {
                         this.isLoading = false
                     },800)
@@ -438,15 +456,33 @@
                         seriesData: seriesData,
                         studentCount: studentCount
                     }
-                } else {
-                    let labels = [this.learnContent.name]
-                    return {
-                        xAxisData: labels,
-                        seriesData: [42],
-                        studentCount: 50
-                    }
                 }
+                //else {
+                //    let labels = [this.learnContent.name]
+                //    return {
+                //        xAxisData: labels,
+                //        seriesData: [42],
+                //        studentCount: 50
+                //    }
+                //}
             },
+            pieData() {
+                if (this.learnContent.pk == 'LearnUnit' || this.learnContent.steps.length < 2 ) {
+                    if (this.classList.length > 0) {
+                        if (this.classList[this.curClassIndex].students && this.classList[this.curClassIndex][this.learnContent.id].record) {
+                            let studentCount = this.classList[this.curClassIndex].students.length
+                            let completed = 0
+                            for (let item of this.classList[this.curClassIndex][this.learnContent.id].record) {
+                                if (item.steps.length > 0) {
+                                    completed++
+                                }
+                            }
+                            return [completed == 0 ? undefined : completed, studentCount - completed == 0 ? undefined : studentCount - completed]
+                        }
+                    } 
+                }
+                return [0,0]
+            }
         },
         created() {
           

+ 3 - 3
TEAMModelOS/ClientApp/src/view/selfstudy/LearnProgress.vue

@@ -5,7 +5,7 @@
                 <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:15px;">活动进度概览</p>
                 <div class="whole-progress-wrap">
                     <div class="progress-histogram-wrap" style="margin:auto;">
-                        <ProgressHistogram :countData="countData" @clickStep="clickStep"></ProgressHistogram>
+                        <!--<ProgressHistogram :countData="countData" @clickStep="clickStep"></ProgressHistogram>-->
                     </div>
                 </div>
                 <p style="color:#EEEEEE;padding-left:15px;font-size:16px;margin-top:50px;margin-bottom:30px;">
@@ -50,10 +50,10 @@
     </div>
 </template>
 <script>
-    import ProgressHistogram from '@/components/learnactivity/ProgressHistogram.vue'
+    //import ProgressHistogram from '@/view/learnactivity/ProgressHistogram.vue'
     export default {
         components: {
-            ProgressHistogram
+            //ProgressHistogram
         },
         data() {
             return {

+ 8 - 8
TEAMModelOS/ClientApp/src/components/learnactivity/ProgressHistogram.vue

@@ -1,5 +1,5 @@
 <template>
-    <div id="progress-histogram"></div>
+    <div id="progress-bar"></div>
 </template>
 <script>
     export default {
@@ -18,7 +18,7 @@
         data() {
             return {
                 dataIndex: 1,
-                progressHistogram: undefined,
+                progressBar: undefined,
                 option: {
                     legend: {
                         data: [
@@ -94,9 +94,9 @@
             }
         },
         mounted() {
-            this.progressHistogram = this.$echarts.init(document.getElementById('progress-histogram'))
-            this.progressHistogram.setOption(this.option)
-            this.progressHistogram.on('click', (params) => {
+            this.progressBar = this.$echarts.init(document.getElementById('progress-bar'))
+            this.progressBar.setOption(this.option)
+            this.progressBar.on('click', (params) => {
                 this.$emit('clickStep', params)
             })
         },
@@ -110,7 +110,7 @@
                         for (let item of this.countData.seriesData) {
                             this.option.series[1].data.push(this.countData.studentCount - item == 0 ? undefined : this.countData.studentCount - item)
                         }
-                        this.progressHistogram.setOption(this.option)
+                        this.progressBar.setOption(this.option)
                     })
                 },
                 deep: true,
@@ -120,10 +120,10 @@
     }
 </script>
 <style scoped lang="less">
-    @import "./ProgressHistogram.less";
+
 </style>
 <style>
-    #progress-histogram {
+    #progress-bar {
         width:100%;
         height:100%;
     }

+ 97 - 0
TEAMModelOS/ClientApp/src/view/selfstudy/ProgressPie.vue

@@ -0,0 +1,97 @@
+<template>
+    <div id="progress-pie"></div>
+</template>
+<script>
+    export default {
+        props: {
+            pieData: {
+                type: Array,
+                default: () => {
+                    return [0,0]
+                }
+            }
+        },
+        data() {
+            return {
+                progressPie: undefined,
+                option: {
+                    tooltip: {
+                        trigger: 'item',
+                        formatter: '{b} : {c} ({d}%)'
+                    },
+                    legend: {
+                        data: [
+                            {
+                                name: '已完成',
+                                textStyle: {
+                                    color:'white'
+                                }
+                            },
+                            {
+                                name: '未完成',
+                                textStyle: {
+                                    color:'white'
+                                }
+                            }
+                        ]
+                    },
+                    series: [
+                        {
+                            hoverOffset:5, 
+                            type: 'pie',
+                            radius: '65%',
+                            center: ['50%', '60%'],
+                            selectedMode: 'single',
+                            data: [
+                                {
+                                    value: 0,
+                                    name: '已完成',
+                                    itemStyle: {
+                                        color:'#69EFEF'
+                                    }
+                                },
+                                {
+                                    value: 0,
+                                    name: '未完成',
+                                    itemStyle: {
+                                        color:'#AAAAAA'
+                                    }
+                                }
+                            ]
+                        }
+                    ]
+                }
+            }
+        },
+        mounted() {
+            this.progressPie = this.$echarts.init(document.getElementById('progress-pie'))
+            this.progressPie.setOption(this.option)
+        },
+        watch: {
+            pieData: {
+                handler(n, o) {
+                    this.$nextTick(() => {
+                        if (!this.progressPie) {
+                            this.progressPie = this.$echarts.init(document.getElementById('progress-pie'))
+                        }
+                        console.log(this.pieData)
+                        this.option.series[0].data[0].value = this.pieData[0]
+                        this.option.series[0].data[1].value = this.pieData[1]
+                        this.progressPie.setOption(this.option)
+                    })
+                },
+                deep: true,
+                immediate: true
+            }
+        }
+    }
+</script>
+<style scoped lang="less">
+    #progress-pie {
+        width: 100%;
+        height: 100%;
+    }
+</style>
+<style>
+    
+</style>

+ 3 - 6
TEAMModelOS/ClientApp/src/view/selfstudy/SelfLearn.vue

@@ -21,7 +21,7 @@
         </div>
         <div class="order-learn-main">
             <div class="main-bar-wrap">
-                <span :class="currentTabIndex == 1 ? 'main-header-tab line-bottom line-bottom-active':'main-header-tab line-bottom'" @click="selectTab(1)">分享对象</span>
+                <span :class="currentTabIndex == 1 ? 'main-header-tab line-bottom line-bottom-active':'main-header-tab line-bottom'" @click="selectTab(1)">学习数据</span>
                 <span :class="currentTabIndex == 0 ? 'main-header-tab line-bottom line-bottom-active':'main-header-tab line-bottom'" @click="selectTab(0)">学习内容</span>
             </div>
             <div class="order-learn-main-body dark-iview-split" v-if="listType == 'order' && orderLearnList[currentLearnIndex]">
@@ -50,8 +50,6 @@
     </div>
 </template>
 <script>
-    
-    import Loading from '@/common/Loading.vue'
     import QuestionList from '@/components/learnactivity/QuestionList.vue'
     import ContentFileList from '@/components/learnactivity/ContentFileList.vue'
     import OrderLearnList from './OrderLearnList.vue'
@@ -62,7 +60,7 @@
     
     export default {
         components: {
-             QuestionList, ContentFileList, Loading, OrderLearnList, UnitList,OrderLearnInfo,UnitInfo,ActivityInfo
+             QuestionList, ContentFileList, OrderLearnList, UnitList,OrderLearnInfo,UnitInfo,ActivityInfo
         },
         data() {
             return {
@@ -265,7 +263,6 @@
                             if (res.error == null) {
                                 this.classList = res.result.data
                                 this.findTask()
-                                console.log('selfLearn')
                                 setTimeout(() => {
                                     this.$refs['activityInfo'].getClassroomStudent()
                                 },1000)
@@ -313,7 +310,7 @@
                 } else {
                     this.currentUnitIndex = index
                 }
-
+                this.$refs['activityInfo'].checkFindRecord()
             },
             /**
              * 查询编序式教材列表

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

@@ -86,7 +86,7 @@ namespace TEAMModelOS.Controllers
         public async Task<BaseJosnRPCResponse> GetAllSchoolBaesInfo(JosnRPCRequest<Dictionary<string, object>> request)
         {
             JsonRPCResponseBuilder builder = JsonRPCResponseBuilder.custom();
-            List<School> sc = await _cosmosrepository.FindSQL<School>("SELECT c.id, c.schoolCode, c.schoolName FROM c WHERE c.pk='School'");
+            List<School> sc = await _cosmosrepository.FindSQL<School>("SELECT c.id, c.schoolCode, c.schoolName, c.address, c.picture FROM c WHERE c.pk='School'");
             return builder.Data(sc).build();
         }
     }