瀏覽代碼

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

CrazyIter 4 年之前
父節點
當前提交
1233a39bb9
共有 28 個文件被更改,包括 1388 次插入799 次删除
  1. 38 2
      TEAMModelOS/ClientApp/src/api/index.js
  2. 52 0
      TEAMModelOS/ClientApp/src/api/regist.js
  3. 2 20
      TEAMModelOS/ClientApp/src/components/learnactivity/GradeList.vue
  4. 7 3
      TEAMModelOS/ClientApp/src/components/learnactivity/ReviewPaperList.vue
  5. 0 0
      TEAMModelOS/ClientApp/src/components/public/ClassList.vue
  6. 69 0
      TEAMModelOS/ClientApp/src/components/public/countryCode/Index.vue
  7. 50 0
      TEAMModelOS/ClientApp/src/components/public/frontEndMain/Index.less
  8. 116 0
      TEAMModelOS/ClientApp/src/components/public/frontEndMain/Index.vue
  9. 1 3
      TEAMModelOS/ClientApp/src/filters/http.js
  10. 18 1
      TEAMModelOS/ClientApp/src/locale/lang/en-US/error.js
  11. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/index.js
  12. 27 0
      TEAMModelOS/ClientApp/src/locale/lang/en-US/regist.js
  13. 18 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/error.js
  14. 2 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/index.js
  15. 26 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-CN/regist.js
  16. 18 1
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/error.js
  17. 2 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/index.js
  18. 27 0
      TEAMModelOS/ClientApp/src/locale/lang/zh-TW/regist.js
  19. 33 15
      TEAMModelOS/ClientApp/src/router/routes.js
  20. 60 8
      TEAMModelOS/ClientApp/src/store/module/config.js
  21. 1 0
      TEAMModelOS/ClientApp/src/utils/countryCodeData.js
  22. 10 7
      TEAMModelOS/ClientApp/src/view/learnactivity/ManageEvaluation.vue
  23. 102 152
      TEAMModelOS/ClientApp/src/view/login/Index.less
  24. 343 103
      TEAMModelOS/ClientApp/src/view/login/Index.vue
  25. 0 123
      TEAMModelOS/ClientApp/src/view/login/components/SignIn.less
  26. 0 359
      TEAMModelOS/ClientApp/src/view/login/components/SignIn.vue
  27. 12 0
      TEAMModelOS/ClientApp/src/view/regist/Index.less
  28. 352 0
      TEAMModelOS/ClientApp/src/view/regist/Index.vue

+ 38 - 2
TEAMModelOS/ClientApp/src/api/index.js

@@ -1,4 +1,5 @@
-import { fetch, post } from '@/filters/http'
+import { fetch, post, corePost } from '@/filters/http'
+import config from '@/store/module/config'
 import ClassMgmt from './classMgmt'
 import talMgmt from './talMgmt'
 // import cloudApi from '../store/api/index'
@@ -18,6 +19,7 @@ import questionnaire from './questionnaire'
 import teachMgmt from './teachMgmt'
 import schoolUser from './schoolUser'
 import accessToken from './accessToken'
+import regist from './regist'
 export default {
     accessToken,
     learnActivity,
@@ -38,6 +40,7 @@ export default {
     schoolList,
     teachMgmt,
     schoolUser,
+    regist,
     // 获取登录跳转链接
     getLoginLink: function (data) {
         return post('api/login/login', data)
@@ -153,6 +156,39 @@ export default {
             let srvAdd = 'China'
             resolve(srvAdd)
         })
-    }
+    },
+
+    /**
+     * 發送驗證簡訊
+     * @param {String} applyType - 寄信類型(email, phone)
+     * @param {String} to - 寄信位置
+     * @param {String} lang - 要傳送的語言代碼,請用標準zh-CN、zh-TW、en-US
+     * @param {Boolean} hasUser - true,代表必須存在用戶,才能發送,false,代表用戶必須不存在,才能發送
+     * @param {Number} country - 手機區碼,無須+號(有phone為必填)
+     */
+    SendPinCode: function(item) {
+        return new Promise((resolve) => {
+            let srvAdr = localStorage.getItem('srvAdr')
+            let url = config.state[srvAdr].coreAPIUrl
+            
+            let data = {
+                'to': item.to.toString(),
+                'lang': item.lang,
+                'HasUser': item.hasUser,
+            }
+
+            if(item.applyType == 'phone'){
+                data.country= item.country.toString()
+                url += '/service/sandsms/pin'
+            } else {
+                url += '/service/sandmail/pin'
+            }
+            corePost(url, data).then( res => {
+                resolve(res)
+            },err => {
+                console.log(err)
+            })
+        })
+    },
 
 }

+ 52 - 0
TEAMModelOS/ClientApp/src/api/regist.js

@@ -0,0 +1,52 @@
+import { corePost } from '@/filters/http'
+import config from '@/store/module/config'
+import jwtDecode from 'jwt-decode'
+
+export default {
+
+    /**
+     * 註冊帳號
+     * @param {String} applyType - 寄信類型(email, phone)
+     * @param {String} name - 姓名
+     * @param {String} account - 驗證帳號
+     * @param {Stringn} pw - 密碼
+     * @param {String} country - 手機區碼,無須+號(有phone為必填)
+     * @param {String} pinCode - 驗證碼
+     */
+    crtAccount: function(item)   {
+        return new Promise((resolve) => {
+          let srvAdr = localStorage.getItem('srvAdr')
+          let url = config.state[srvAdr].coreAPIUrl
+          let nonceStr = 'habook'  // 檢查項目
+          let data = {
+            "grant_type": "create",
+            'client_id': config.state[srvAdr].clientID,
+            'nonce': nonceStr,
+            "name" : item.name,
+            "password": item.pw,
+            "pin_code": item.pinCode.toString()
+          }
+
+          if(item.applyType == 'phone'){
+              data.account = '+' + item.country + '-' + item.account
+          } else {
+            data.account = item.account
+          }
+
+          corePost(url+'/oauth2/login', data).then( res => {
+            if(res.error){
+              resolve(res)
+            } else {
+              let t_data = jwtDecode(res.id_token)
+              if(nonceStr === t_data.nonce){
+                resolve(res)
+              } else {
+                resolve({error: 'nonce'})
+              }
+            }
+          },err => {
+            console.log(err)
+          })
+        })
+      },
+}

+ 2 - 20
TEAMModelOS/ClientApp/src/components/learnactivity/GradeList.vue

@@ -32,7 +32,6 @@
 
 <script>
     import ReviewPaper from '../learnactivity/ReviewPaper.vue'
-    //import Loading from '@/common/Loading.vue'
     export default {
         components: {
             ReviewPaper,
@@ -54,7 +53,6 @@
                 this.studentData = this.$Mock.data.studentList[0].studentScore
                 let filterData = this.studentData
                 if (this.inputData) {
-                    // 可以客制調整
                     filterData = this.studentData.filter(res => {
                         let a = res.name
                         return (a.indexOf(this.inputData) >= 0)
@@ -65,9 +63,7 @@
         },
         methods: {
             //获取单个学生作答数据
-            getStudentInfo(data,index) {
-                console.log(data)
-                console.log(index)
+            getStudentInfo(data, index) {
                 this.selectIndex = index
             },
             //获取学生测验数据
@@ -75,7 +71,6 @@
                 let requestData = {}
                 let datas = this.$Mock.data.studentList
                 console.log(datas)
-                //this.studentList = datas[0].studentScore
                 requestData.examCode = "632dd8b3-c48c-4ee5-8448-7e539f764272"
                 requestData.id = "c3da2274-94ab-4cf1-92d8-dd30e8532aaf"
                 if (requestData.id !== undefined) {
@@ -99,9 +94,6 @@
                             } else {
                                 this.$Message.error('API ERROR!')
                             }
-                        },
-                        err => {
-
                         }
                     )
                 }
@@ -118,30 +110,20 @@
                             res => {
                                 if (res.error == null) {
                                     this.paperInfo = res.result.data[0]
-                                    console.log(this.dataInfo)
                                     let data = res.result.data[0].item
                                     this.paperInfo.item = []
-                                    let types = ["Single", "Multiple", "Judge"]
                                     for (let i = 0; i < data.length; i++) {
-                                        if (!(types.includes(data[i].type))) {
-                                            this.paperInfo.item.push(data[i])
-                                        }
+                                        this.paperInfo.item.push(data[i])
                                     }
                                     this.examAnalysisStatus = true
-                                    console.log('111111111111')
-                                    console.log(this.paperInfo)
                                 } else {
                                     this.$Message.error('API ERROR!')
                                 }
-                            },
-                            err => {
-
                             }
                         )
                     }
                 }
             }
-
         },
         mounted() {
             this.getStudentData()

+ 7 - 3
TEAMModelOS/ClientApp/src/components/learnactivity/ReviewPaperList.vue

@@ -35,7 +35,7 @@
 						<div class="item-explain-details">
 							<!-- 问答题答案 -->
 							<div v-if="item.type === 'Subjective'">
-								<span v-for="(answer,index) in item.answer" :key="index" v-html="item.answer.length ? answer : '未设置答案'"></span>
+								<span v-for="(answer,index) in item.answer" :key="index"  v-html="item.answer.length ? answer : '未设置答案'"></span>
 							</div>
 							<!-- 填空题答案 -->
 							<div v-else-if="item.type === 'Complete'">
@@ -50,7 +50,7 @@
 					</div>
 					<div style="margin-top:20px">
 						<span>【题 目 分 数】:</span>
-						<Input v-model="value" placeholder="请为此题打分..." style="width: 300px" />
+						<Input  @on-change="inputScore(item)" placeholder="请为此题打分..." style="width: 300px" />
 					</div>
 					<transition name="slide">
 						<!-- <div v-show="collapseList.indexOf(exerciseList.indexOf(item)) > -1" class="toggle-area"> -->
@@ -201,7 +201,10 @@
 				this.exerciseList = this.originData.slice(start, end)
 				this.pageScrollTo(0)
 			},
-
+			//題目打分
+			inputScore(data) {
+				console.log(data)
+            },
 			pageSizeChange(val) {
 				this.pageSize = val
 				this.pageChange(1)
@@ -366,6 +369,7 @@
 
         .components-el-container .exercise-item .item-explain-details {
             width: 90%;
+			margin-left:15px;
         }
 
         .components-el-container .exercise-item .item-tools-t .ivu-icon {

+ 0 - 0
TEAMModelOS/ClientApp/src/components/public/ClassList.vue


+ 69 - 0
TEAMModelOS/ClientApp/src/components/public/countryCode/Index.vue

@@ -0,0 +1,69 @@
+<template>
+    <div id="countrycode" >
+        <Select v-model="value1" filterable clearable>
+            <Option v-for="item in dataList" :value="item.value">{{ item.label }}</Option>
+        </Select>
+    </div>
+</template>
+
+<script>
+import codeData from '@/utils/countryCodeData.js';
+
+export default {
+    name: 'countrycode',
+    props:['value'],
+    model: {
+        prop: "value", //绑定的值,通过父组件传递
+        event: "update", //自定义时间名    
+    },
+    data() {
+        return {
+            lang: localStorage.getItem('local'),
+            value1:'',
+        }
+    },
+    computed:{
+        dataList(){
+            let data = []
+            let LowerCaseLang = this.lang.toLowerCase()
+            let _this = this
+            Object.keys(codeData).forEach(function(key){
+                let OItem = codeData[key]
+                let lowerCaseCulture = OItem.Culture !='' ? OItem.Culture.toString().toLowerCase() : ''
+                let label;
+                switch (LowerCaseLang) {
+                    case 'zh-tw':
+                        label = '+' + OItem.Code + '(' + OItem.CountryTw + ')'
+                        break;
+                    case 'zh-cn':
+                        label = '+' + OItem.Code + '(' + OItem.CountryCn + ')'
+                        break;                
+                    default:
+                        label = '+' + OItem.Code + '(' + OItem.CountryEn + ')'
+                        break;
+                }
+                data.push({
+                    label: label,
+                    value: OItem.Code
+                })
+
+                if(LowerCaseLang == lowerCaseCulture){
+                    _this.value1 = OItem.Code
+                }
+            })
+            return data
+        }
+    },
+    created:  function () {
+        // console.log(this.dataList)
+    },
+    watch:{
+        value1: function(newVal, oldVal){
+            if(newVal == undefined) newVal = ''
+            this.$emit("update", newVal); //子组件与父组件通讯,告知父组件更新绑定的值
+        }
+    },
+    methods: {
+    }
+}
+</script>

+ 50 - 0
TEAMModelOS/ClientApp/src/components/public/frontEndMain/Index.less

@@ -0,0 +1,50 @@
+.login{
+    width: 100%;
+    height: 100%;
+    background-image: url('../../../assets/image/lgoin_bg.jpg');
+    background-repeat: no-repeat;
+    background-attachment: fixed;
+    background-position: center;
+    background-size: cover;
+    &-mark{
+        position: fixed;
+        left:30px;
+        top:30px;
+    }
+    &-server{
+        position: fixed;
+        right:30px;
+        top:30px;
+        h5 {
+            font-weight: 100;
+            margin-bottom: 5px;
+            color: #ffffff;
+        }
+    }
+    &-body{
+        padding-top: 100px;
+        height: 95%;
+        display: -webkit-flex;
+        display:         flex;
+        -webkit-align-items: center;
+                align-items: center;
+        -webkit-justify-content: center;
+                justify-content: center;
+    }
+    &-footer{
+        height: 5%;
+        text-align: center;
+        position: relative;
+        .footer-title{
+            color: #fefefe;
+        }
+        .link{
+            color: rgb(220, 220, 220);
+            font-size: 1.2em;
+            text-decoration: underline;
+        }
+        .demarcation{
+            color: rgb(220, 220, 220);
+        }
+    }
+}

+ 116 - 0
TEAMModelOS/ClientApp/src/components/public/frontEndMain/Index.vue

@@ -0,0 +1,116 @@
+<style lang="less" scoped>
+  @import './Index.less';
+</style>
+
+<style lang="less">
+    .demo-spin-icon-load{
+        animation: ani-demo-spin 1s linear infinite;
+    }
+    @keyframes ani-demo-spin {
+        from { transform: rotate(0deg);}
+        50%  { transform: rotate(180deg);}
+        to   { transform: rotate(360deg);}
+    }
+.login{
+  &-server{
+    .ivu-select-selection, .ivu-btn{
+      border-radius: 0;
+      background-color: #0d253f;
+      color: #e3e5e8;
+      border: 0;
+      span{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      }
+    }
+    .ivu-select-arrow{
+      font-size: 18px;
+    }
+    .ivu-select-dropdown{
+      background-color: #091529;
+      border-radius: 0;
+    }
+    .ivu-select-item, .ivu-dropdown-item{
+      color: #ffffff;
+      &:hover{
+        background-color:transparent;
+      }
+    }
+    .ivu-select-item-focus{
+      background-color:transparent;
+    }
+  }
+}
+</style>
+
+<template>
+  <div id="login" class="login">
+    <div class="login-mark">
+      <img width="125" src="@/assets/ies5_logo.svg">    
+    </div>
+    <div class="login-server">
+      <h5>{{ $t('login.title.ser') }}</h5>
+      <Dropdown trigger="click" @on-click="chgSerType">
+          <a href="javascript:void(0)">
+            <Button style="width:120px;">
+              
+              <span>
+                {{ $t('login.serAdress.' + config.srvAdr) }}
+              </span>
+
+              <Icon type="ios-arrow-down"></Icon>
+          </Button>
+          </a>
+          <DropdownMenu slot="list" style="width:120px">
+              <DropdownItem name="China" >{{ $t('login.serAdress.China') }}</DropdownItem>
+              <DropdownItem name="Global">{{ $t('login.serAdress.Global') }}</DropdownItem>
+          </DropdownMenu>
+      </Dropdown>
+    </div>
+
+    <div class="login-body">
+        <router-view/>
+    </div>
+
+    <div class="login-footer">
+      <h5 style="position: absolute;bottom:0;width: 100%;padding: 7px;color: #515a6e;">&copy; HABOOL Group 2019</h5>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState, mapGetters } from 'vuex'
+
+export default {
+  data(){
+    return {
+      
+    }
+  },
+  computed: {
+    ...mapState({
+      config: state => state.config
+    }),
+  },
+  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){
+          let toStation = this.config[val].domainUrl.find(function(item){
+            return item.station == localStorage.getItem('station')
+          })
+          window.open(toStation.url);
+          
+        } else {
+          this.$store.dispatch('config/setSrvAdr', val)
+        }
+      }
+    },
+  }
+}
+</script>

+ 1 - 3
TEAMModelOS/ClientApp/src/filters/http.js

@@ -212,9 +212,7 @@ export function post(url, params) {
 export function corePost(url, params) {
     return new Promise((resolve, reject) => {
         axios.post(url, params).then(response => {
-            if (response && response.data) {
-                resolve(response.data)
-            }
+            resolve(response.data)
         }, err => {
             reject(err)
             Message.error('数据访问错误!')

+ 18 - 1
TEAMModelOS/ClientApp/src/locale/lang/en-US/error.js

@@ -3,6 +3,23 @@ export default {
     format:{
         default: 'wrong format',
         email: 'Wrong Email format',
+        numeric: 'Only Numbers',
+        pw: 'Password must be 8-30 characters and contain English and numeric.'
     },
-    alphanumeric: 'Only enter English & numbers'
+    alphanumeric: 'Only enter English & numbers.',
+    input:{
+        phone: 'Please enter your Cell Phone',
+        email: 'Please enter your Email',
+        countryCode: 'Please select a country or region.',
+        pwCheck: 'Please confirm your password again.',
+        pwCheckFail: 'The two input passwords do not match!',
+    },
+    coreApi:{
+        error2: {
+            default: 'This mobile number or email has been registered.',
+            phone: 'This mobile number has been registered.',
+            email: 'This mail has been used.'
+        },
+        error3: 'PIN verification failed'
+    }
 }

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/index.js

@@ -13,6 +13,7 @@ import login from './login'
 import error from './error'
 import schoolList from './schoolList'
 import teachermgmt from './teachermgmt'
+import regist from './regist'
 
 export default {
   schoolBaseInfo,
@@ -30,6 +31,7 @@ export default {
   error,
   schoolList,
   teachermgmt,
+  regist,
   test: 'test',
   formConfigP: {
     input: 'Please Enter ',

+ 27 - 0
TEAMModelOS/ClientApp/src/locale/lang/en-US/regist.js

@@ -0,0 +1,27 @@
+export default {
+    title: 'Create Account',
+    form:{
+        text1: 'Verification',
+        text2: 'Cellphone',
+        text3: 'Email',
+        text4: 'Name',
+        text5: 'Password',
+        text6: 'Confirm',
+        text7: 'The verification email may be received in your spam or it may take 5-10 minutes to receive.',
+        text8: 'Registration means that you have read and agreed to the',
+        text9: ' terms of service',
+        text10: ' and',
+        text11: ' privacy policy.',
+        placeholder:{
+            phone: 'Please enter your phone',
+            email: 'Please enter your email',
+            pindCode: 'Please enter pin code'
+        }        
+    },
+    btn:{
+        signUp: 'Regist',
+        sendphone: 'Send code',
+        sendemail: 'Send Mail'
+    }
+  }
+  

+ 18 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/error.js

@@ -3,6 +3,23 @@ export default {
     format:{
         default: '格式错误',
         email: 'Email格式错误',
+        numeric: '只能是数字',
+        pw: '密码长度8-30位,而且要包含英文和数字'
     },
-    alphanumeric: '只能输入英数字'
+    alphanumeric: '只能输入英数字',
+    input:{
+        phone: '请输入手机号码',
+        email: '请输入信箱',
+        countryCode: '请选择地区代码',
+        pwCheck: '请再一次填写密码',
+        pwCheckFail: '与第一次密码不一样',
+    },
+    coreApi:{
+        error2: {
+            default: '该信箱或手机号码已被注册',
+            phone: '此手机已被注册',
+            email: '此信箱已被注册'
+        },
+        error3: '验证PIN码失败'
+    }
 }

+ 2 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/index.js

@@ -13,7 +13,7 @@ import login from './login'
 import error from './error'
 import schoolList from './schoolList'
 import teachermgmt from './teachermgmt'
-
+import regist from './regist'
 export default {
   schoolBaseInfo,
   classMgmt,
@@ -30,6 +30,7 @@ export default {
   error,
   schoolList,
   teachermgmt,
+  regist,
   test: '测试',
   formConfigP: {
     input: '请输入',

+ 26 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-CN/regist.js

@@ -0,0 +1,26 @@
+export default {
+    title: '建立帐号',
+    form:{
+        text1: '认证方式',
+        text2: '手机',
+        text3: '邮箱',
+        text4: '姓名',
+        text5: '密码',
+        text6: '确认密码',
+        text7: '请注意,验证信可能会在您的垃圾邮件或需要5-10分钟才会收到',
+        text8: '注册表示您已经阅读并同意',
+        text9: '服务条款',
+        text10: '及',
+        text11: '隐私权政策',
+        placeholder:{
+            phone: '请输入手机',
+            email: '请输入邮箱',
+            pindCode: '请输入验证码'
+        }
+    },
+    btn:{
+        signUp: '注册',
+        sendphone: '发送验证码',
+        sendemail: '发送验证信'
+    }
+  }

+ 18 - 1
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/error.js

@@ -3,6 +3,23 @@ export default {
     format:{
         default: '格式錯誤',
         email: 'Email格式錯誤',
+        numeric: '只能是數字',
+        pw: '密碼長度8-30位,而且要包含英文和數字'
     },
-    alphanumeric: '只能輸入英數字'
+    alphanumeric: '只能輸入英數字',
+    input:{
+        phone: '請輸入手機號碼',
+        email: '請輸入信箱',
+        countryCode: '請選擇地區代碼',
+        pwCheck: '請再一次填寫密碼',
+        pwCheckFail: '與第一次密碼不一樣',
+    },
+    coreApi:{
+        error2: {
+            default: '該信箱或手機號碼已被註冊',
+            phone: '此手機已被註冊',
+            email: '此信箱已被註冊'
+        },
+        error3: '驗證PIN碼失敗'
+    }
 }

+ 2 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/index.js

@@ -13,6 +13,7 @@ import login from './login'
 import error from './error'
 import schoolList from './schoolList'
 import teachermgmt from './teachermgmt'
+import regist from './regist'
 
 export default {
   schoolBaseInfo,
@@ -30,6 +31,7 @@ export default {
   error,
   schoolList,
   teachermgmt,
+  regist,
   test: '測試',
   formConfigP: {
     input: '請輸入',

+ 27 - 0
TEAMModelOS/ClientApp/src/locale/lang/zh-TW/regist.js

@@ -0,0 +1,27 @@
+export default {
+    title: '建立帳號',
+    form:{
+        text1: '認證方式',
+        text2: '手機',
+        text3: '信箱',
+        text4: '姓名',
+        text5: '密碼',
+        text6: '確認密碼',
+        text7: '請注意,驗證信可能會在您的垃圾郵件或需要5-10分鐘才會收到',
+        text8: '註冊表示您已經閱讀並同意',
+        text9: '服務條款',
+        text10: '及',
+        text11: '隱私權政策',
+        placeholder:{
+            phone: '請輸入手機',
+            email: '請輸入信箱',
+            pindCode: '請輸入驗證碼'
+        }        
+    },
+    btn:{
+        signUp: '註冊',
+        sendphone: '發送驗證碼',
+        sendemail: '發送驗證信'
+    }
+  }
+  

+ 33 - 15
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1,6 +1,6 @@
 import ServerSideLogin from '@/view/serverside/login.vue'
-import Main from '@/components/public/main/index.vue'
 import Home from '@/view/Home.vue'
+import FrontEndMain from '@/components/public/frontEndMain/Index.vue'
 // import HTTP404 from '@/view/404'
 // import { resolve } from 'url'
 
@@ -10,25 +10,43 @@ export const routes = [
     { name: 'index', path: '', redirect: '/home' }, 
     { name: 'selectModule' ,path: '/selectModule' ,redirect: '/home' },
     {
-        name: 'login',
-        path: '/login',
-        meta: {
-        middleware: ['login?']
-        },
-        component: resolve => require(['@/view/login/Index.vue'], resolve),
+        path: '/login', component: FrontEndMain,
+        children: [
+            {
+                name: 'login',
+                path: '/',
+                meta: {
+                    middleware: ['login?']
+                },
+                component: resolve => require(['@/view/login/Index.vue'], resolve)
+            }
+        ]
+    },
+    {
+        path: '/regist', component: FrontEndMain,
+        children: [
+            {
+                name: 'regist',
+                path: '/',
+                meta: {
+                    middleware: ['login?']
+                },
+                component: resolve => require(['@/view/regist/Index.vue'], resolve)
+            }
+        ]
     },
     {
         path: '/schoolList',
         component: Home,
         children:[
-        {
-            name: 'schoolList',
-            path: '/',
-            meta: {
-                middleware: ['login']
-            },
-            component: resolve => require(['@/view/schoolList/Index.vue'], resolve),
-        }
+            {
+                name: 'schoolList',
+                path: '/',
+                meta: {
+                    middleware: ['login']
+                },
+                component: resolve => require(['@/view/schoolList/Index.vue'], resolve),
+            }
         ]
     },
     { name: 'ServerSideLogin', path: '/serverside/login', component: ServerSideLogin },

+ 60 - 8
TEAMModelOS/ClientApp/src/store/module/config.js

@@ -3,17 +3,38 @@ export default {
     namespaced: true,
     state: {
         srvAdr: '', // 伺服器位置 China, Global
+        srvAdrType: '', // 正式站 product 測試站 test
         China: {
+            srvAdr: 'China',
             clientID: 'c7317f88-7cea-4e48-ac57-a16071f7b884',
-            domainUrl: 'https://teammodelos.chinacloudsites.cn',
             accAPIUrl: 'https://account.teammodel.cn',
-            coreAPIUrl: 'https://api2.teammodel.cn'
+            coreAPIUrl: 'https://api2.teammodel.cn',
+            domainUrl: [
+                {
+                    station: 'product' ,
+                    url: 'https://teammodelos.chinacloudsites.cn'
+                },
+                {
+                    station: 'test' ,
+                    url: 'http://teammodelos-test.chinacloudsites.cn'
+                },
+            ]
         },
         Global: {
+            srvAdr: 'Global',
             clientID: '531fecd1-b1a5-469a-93ca-7984e1d392f2',
-            domainUrl: 'https://www.teammodel.net',
             accAPIUrl: 'https://account.teammodel.net',
-            coreAPIUrl: 'https://api2.teammodel.net'
+            coreAPIUrl: 'https://api2.teammodel.net',
+            domainUrl: [
+                {
+                    station: 'product' ,
+                    url: 'https://www.teammodel.net;'
+                },
+                {
+                    station: 'test' ,
+                    url: 'http://teammodelos-test.azurewebsites.net'
+                },
+            ]
         }
     },
     getters:{
@@ -23,17 +44,48 @@ export default {
         setSrvAdr(state, data) {
             state.srvAdr = data
         },
+        setSrvAdrType(state, data) {
+            state.srvAdrType = data
+        },
     },
     actions: {
         checkSrvAdr(context) {
             let srvAdr = localStorage.getItem('srvAdr')
-            if(srvAdr){
+            let station = localStorage.getItem('station')
+
+            if(srvAdr && srvAdr !== 'undefined' && station &&  station !== 'undefined'){
                 context.commit('setSrvAdr', srvAdr)
+                context.commit('setSrvAdrType', station)
             } else {
-                apiTools.GetSrvAdd().then( res => {
-                    localStorage.setItem('srvAdr', res)
-                    context.commit('setSrvAdr', res)
+                let hostname = window.location.hostname
+                let protocol = window.location.protocol
+                let domainUrl = protocol + '//' + hostname
+                let domainUrlArray = []
+
+                context.state.China.domainUrl.forEach(function(item){
+                    item.srvAdr= 'China'
+                    domainUrlArray.push(item)
+                })
+                context.state.Global.domainUrl.forEach(function(item){
+                    item.srvAdr= 'Global'
+                    domainUrlArray.push(item)
+                })
+
+                let stationSetting = domainUrlArray.find(function(item){
+                    return item.url == domainUrl
                 })
+
+                if(!stationSetting){
+                    stationSetting = []
+                    stationSetting.srvAdr = 'China'
+                    stationSetting.station = 'localhost'
+                }
+
+                context.commit('setSrvAdr', stationSetting.srvAdr)
+                context.commit('setSrvAdrType', stationSetting.station)
+
+                localStorage.setItem('srvAdr', stationSetting.srvAdr)
+                localStorage.setItem('station', stationSetting.station)
             }
         },
         setSrvAdr(context, param) {

File diff suppressed because it is too large
+ 1 - 0
TEAMModelOS/ClientApp/src/utils/countryCodeData.js


+ 10 - 7
TEAMModelOS/ClientApp/src/view/learnactivity/ManageEvaluation.vue

@@ -506,6 +506,8 @@
             },
             selectEvaluation(index) {
                 this.avtiveEvaluationIndex = index
+                console.log(index)
+                console.log(this.evaluationList[this.avtiveEvaluationIndex])
                 this.getMyDate(this.evaluationList[this.avtiveEvaluationIndex].startTime, this.evaluationList[this.avtiveEvaluationIndex].endTime)
                 this.findExamPaper()
             },
@@ -524,6 +526,7 @@
                     res => {
                         if (res.error == null) {
                             this.evaluationList = res.result.data
+                            console.log('獲取评测列表')
                             console.log(this.evaluationList)
                             if (this.evaluationList.length > 0) {
                                 this.selectEvaluation(0)
@@ -643,13 +646,13 @@
             }
         },
         mounted() {
-            console.log('sas')
-            console.log(this.$tools.getSas({
-                type: 'blobR',
-                data: {
-                    "name": "HBCN", "role": "student"
-                }
-            }))
+            //console.log('sas')
+            //console.log(this.$tools.getSas({
+            //    type: 'blobR',
+            //    data: {
+            //        "name": "HBCN", "role": "student"
+            //    }
+            //}))
             setTimeout(() => {
                 console.log(this.$tools.getSas({
                     type: 'blobR',

+ 102 - 152
TEAMModelOS/ClientApp/src/view/login/Index.less

@@ -1,173 +1,123 @@
-.login{
-    width: 100%;
-    height: 100%;
-    background-image: url('../../assets/image/lgoin_bg.jpg');
-    background-repeat: no-repeat;
-    background-attachment: fixed;
-    background-position: center;
-    background-size: cover;
-    &-mark{
-        position: fixed;
-        left:30px;
-        top:30px;
-    }
-    &-server{
-        position: fixed;
-        right:30px;
-        top:30px;
-        h5 {
-            font-weight: 100;
+.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;
-            color: #ffffff;
+            .logo{
+                margin-right: 5px;
+                height: 15px;
+            }
+            .text{
+                margin-right: 15px;
+                color: #ffffff;
+                font-size: ;
+            }
+            .tooltip{
+                height: 15px;
+            }
         }
-    }
-    &-body{
-        padding-top: 100px;
-        height: 95%;
-        display: -webkit-flex;
-        display:         flex;
-        -webkit-align-items: center;
-                align-items: center;
-        -webkit-justify-content: center;
-                justify-content: center;
-        .loginDiv{
-            width: 800px;
+        .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;
+            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;
-                    }
+            margin-bottom: 30px;
+            .qrlogin{
+                display: flex;
+                align-items: center;
+                .logo{
+                    margin-right: 5px;
+                    height: 15px;
                 }
-                .subTitle{
+                a{
                     font-size: 12px;
-                    color: #d1d1d3;
-                    margin-bottom: 25px;
+                    color: #668fbc;
+                    text-decoration: underline;
                 }
-                .loginForm{
-                    margin-bottom: 10px;
-                    .formItem{
-                        margin: 0;
-                    }
-                    .errlable{
-                        text-align: right;
-                        color: #f22613;
-                        font-size: 12px;
-                        margin-top: 3px;
-                        height: 12px;
-                    }
+            }
+            .link{
+                a{
+                    font-size: 12px;
+                    color: #668fbc;
+                    text-decoration: underline;
                 }
-                .extra{
+            }
+        }
+        .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;
-                    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;
-                        }
+                    flex-direction: column;
+                    img{
+                        width: 35px;
                     }
-                }
-                .communyLoging{
-                    .description{
-                        text-align: center;
+                    span{
                         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;
-                        }
+            }
+        }
+        .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;
+                }
             }
         }
     }
-    &-footer{
-        height: 5%;
-        text-align: center;
-        position: relative;
-        .footer-title{
-            color: #fefefe;
-        }
-        .link{
-            color: rgb(220, 220, 220);
-            font-size: 1.2em;
-            text-decoration: underline;
-        }
-        .demarcation{
-            color: rgb(220, 220, 220);
-        }
-    }
 }

+ 343 - 103
TEAMModelOS/ClientApp/src/view/login/Index.vue

@@ -3,136 +3,376 @@
 </style>
 
 <style lang="less">
-    .demo-spin-icon-load{
-        animation: ani-demo-spin 1s linear infinite;
-    }
-    @keyframes ani-demo-spin {
-        from { transform: rotate(0deg);}
-        50%  { transform: rotate(180deg);}
-        to   { transform: rotate(360deg);}
+.loginBox{
+  .loginForm{
+    .formItem{
+        input, select{
+            border-radius: 0;
+            font-size: 12px;
+        }
+        .ivu-select-selection{
+          border-radius: 0;
+        }
     }
-.login{
-  &-server{
-    .ivu-select-selection, .ivu-btn{
-      border-radius: 0;
-      background-color: #0d253f;
-      color: #e3e5e8;
-      border: 0;
-      span{
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
+    .schoolAutoComplete{
+      height: 170px;
+      .schoolsBox{
+        border-bottom: 1px solid #e9e9e9;
+        padding: 5px 5px 5px 15px;
+        .area{
+          font-size: 12px;
+          padding: 5px;
+        }
       }
     }
-    .ivu-select-arrow{
-      font-size: 18px;
-    }
     .ivu-select-dropdown{
-      background-color: #091529;
       border-radius: 0;
     }
-    .ivu-select-item, .ivu-dropdown-item{
-      color: #ffffff;
-      &:hover{
-        background-color:transparent;
-      }
-    }
-    .ivu-select-item-focus{
-      background-color:transparent;
-    }
-  }
-  &-body{
-    .loginBox{
-      .loginForm{
-        .formItem{
-            input, select{
-                border-radius: 0;
-                font-size: 12px;
-            }
-            .ivu-select-selection{
-              border-radius: 0;
-            }
-        }
-        .schoolAutoComplete{
-          height: 170px;
-          .schoolsBox{
-            border-bottom: 1px solid #e9e9e9;
-            padding: 5px 5px 5px 15px;
-            .area{
-              font-size: 12px;
-              padding: 5px;
-            }
-          }
-        }
-        .ivu-select-dropdown{
-          border-radius: 0;
-        }
-      }
-    }
   }
 }
 </style>
 
 <template>
-  <div id="login" class="login">
-    <div class="login-mark">
-      <img width="125" src="@/assets/ies5_logo.svg">    
-    </div>
-    <div class="login-server">
-      <h5>{{ $t('login.title.ser') }}</h5>
-      <Dropdown trigger="click" @on-click="chgSerType">
-          <a href="javascript:void(0)">
-            <Button style="width:120px;">
-              
-              <span>
-                {{ $t('login.serAdress.' + config.srvAdr) }}
-              </span>
-
-              <Icon type="ios-arrow-down"></Icon>
-          </Button>
-          </a>
-          <DropdownMenu slot="list" style="width:120px">
-              <DropdownItem name="China" >{{ $t('login.serAdress.China') }}</DropdownItem>
-              <DropdownItem name="Global">{{ $t('login.serAdress.Global') }}</DropdownItem>
-          </DropdownMenu>
-      </Dropdown>
-    </div>
-    <div class="login-body">
-        <SignIn/> <!-- 登入模組 -->
-    </div>
-    <div class="login-footer">
-      <h5 style="position: absolute;bottom:0;width: 100%;padding: 7px;color: #515a6e;">&copy; HABOOL Group 2019</h5>
+    <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">
+                <router-link to="/regist">{{ $t('login.link.regist') }}</router-link> | <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>
-  </div>
 </template>
-
 <script>
+import { User } from '@/service/User'
 import { mapState, mapGetters } from 'vuex'
-import SignIn from '@/view/login/components/SignIn.vue'
 
 export default {
-  components:{
-    SignIn
+  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 = ''
+        }
+      }
+    };
+    const validatePasswordCheck = (rule, value, callback) => {
+      let error = ''
+        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() {
+    
   },
   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)
+    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>
+</script>

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

@@ -1,123 +0,0 @@
-.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;
-                }
-            }
-        }
-    }
-}

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

@@ -1,359 +0,0 @@
-<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>

+ 12 - 0
TEAMModelOS/ClientApp/src/view/regist/Index.less

@@ -0,0 +1,12 @@
+.registDiv{
+    width: 500px;
+    display: flex;
+    justify-content: center;
+    .registForm{
+        width: 400px;
+        .formItem{
+            
+        }
+        
+    }
+}

+ 352 - 0
TEAMModelOS/ClientApp/src/view/regist/Index.vue

@@ -0,0 +1,352 @@
+<style lang="less" scoped>
+  @import './Index.less';
+</style>
+
+<style lang="less">
+  .registBox{
+    .registForm{
+      .formItem{
+          .ivu-form-item-label {
+            color: white;
+          }
+          input, select, button{
+              border-radius: 0;
+              font-size: 12px;
+          }
+          .ivu-btn-primary{
+            background-color: #4d6b9d;
+          }
+          .ivu-select-selection{
+            border-radius: 0;
+          }
+      }
+    }
+  }
+</style>
+
+<template>
+    <div class="registDiv">
+        <div class="registBox">
+          <h3 style="text-align: center;margin-bottom: 5px;font-weight: 100;letter-spacing: 3px;font-size: 20px;color: white;">
+              {{ $t('regist.title') }}
+          </h3>
+          <Form class="registForm" ref="registForm" :model="registForm" :rules="registRules" label-position="top" style="color: white;">
+              <!-- <FormItem class="formItem" style="font-size: 12px; text-align: center;">
+                  <label>{{ $t('醍摩豆ID')}}:</label> {{ teammodelID }}
+              </FormItem> -->
+              <FormItem class="formItem">
+                  <span style="font-size: 14px;font-weight: 500;">{{$t('regist.form.text1')}}</span>
+                  <br/>
+                  <div>
+                      <RadioGroup v-model="applyType">
+                          <Radio label="phone" select>
+                              <span style="font-size: 13px;">{{$t('regist.form.text2')}}</span>
+                          </Radio>
+                          <Radio label="email" >
+                              <span style="font-size: 13px;">{{$t('regist.form.text3')}}</span>
+                          </Radio>
+                      </RadioGroup>
+                  </div>
+                  <span v-if="applyType == 'email' " style="width: 400px;display: block;text-align: center;font-size: 13px;color: rgb(244, 67, 54);">{{ $t('regist.form.text7')}}</span>
+              </FormItem>
+              <FormItem class="formItem" prop="account" >
+                  <Row type="flex" justify="center" align="top">
+                      <Col v-if="applyType == 'phone'" :span="9">
+                          <CountryCode v-model="cCode"/>
+                      </Col>
+                      <Col :span="applyType == 'phone' ? 15 : 24">
+                          <Input :placeholder="$t('regist.form.placeholder.' + applyType)" v-model="registForm.account"></Input>                                                                        
+                      </Col>
+                  </Row>
+              </FormItem>
+              <FormItem class="formItem" prop="pinCode">
+                  <Row type="flex" justify="center" align="top">
+                      <Col :span="9">
+                          <Button  class="radius-right-0" style="font-size:12px; " long type="primary" @click="sendPinCode()" :disabled="countdown || pinCodeSwitch">
+                              {{ sendBtnText }}
+                          </Button>
+                      </Col>
+                      <Col :span="15">
+                          <Input   class="radius-left-0 input-font-size-12" v-model="registForm.pinCode" :placeholder="$t('regist.form.placeholder.pindCode')"></Input>
+                      </Col>
+                  </Row>
+              </FormItem>
+              <FormItem class="formItem"  :label="$t('regist.form.text4')" prop="name">
+                  <Input  v-model="registForm.name" ></Input>
+              </FormItem>
+              <FormItem class="formItem"  :label="$t('regist.form.text5')" prop="pw" >
+                  <Input   type="password" password  v-model="registForm.pw" ></Input>
+              </FormItem>
+              <FormItem class="formItem"  :label="$t('regist.form.text6')" prop="pwCheck" >
+                  <Input   type="password" password v-model="registForm.pwCheck" ></Input>
+              </FormItem>
+              <FormItem class="formItem">
+                  <Checkbox v-model="agreePrivacy" style="font-size: 12px;">
+                      {{ $t('regist.form.text8') }}
+                      <a target="_blank" :href="descriptionURL"><b>{{ $t('regist.form.text9')}}</b></a>
+                      {{ $t('regist.form.text10') }}
+                      <a target="_blank" :href="privacyURL"><b>{{ $t('regist.form.text11')}}</b></a>
+                  </Checkbox>
+              </FormItem>
+              <FormItem class="formItem">
+                  <Button long  type="primary" @click="handleSubmit('registForm')" :disabled="!agreePrivacy" style="margin-top:20px;">
+                      <span>{{ $t('regist.btn.signUp') }}</span>
+                  </Button>
+              </FormItem>
+          </Form>
+        </div>
+    </div>
+</template>
+<script>
+import { User } from '@/service/User'
+import CountryCode from '@/components/public/countryCode/Index.vue'
+import { mapState, mapGetters } from 'vuex'
+
+export default {
+  components:{
+    CountryCode
+  },
+  data() {
+    const validAccount = (rule, value, callback) => {
+      if (value === '') {
+        if(this.applyType == 'phone'){
+          callback(new Error( this.$t('error.input.phone')));
+        } else {
+          callback(new Error( this.$t('error.input.email')));
+        }    
+      } else {
+        switch (this.applyType) {
+          case 'email':
+            let emailRule = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/;
+            if(value.search(emailRule) != -1){
+              callback();
+            } else {
+              callback(new Error( this.$t('error.format.email')));
+            }
+            break;
+          case 'phone':
+            if(this.cCode === '') {
+              callback(new Error( this.$t('error.input.countryCode')));
+            } else if(!(/^[0-9]*$/.test(value))) {
+              callback(new Error( this.$t('error.format.numeric')));
+            } else {
+              callback();
+            }
+            break;
+        }
+      }
+    };
+    const validPW = (rule, value, callback) => {
+      if (!(/^(?=.*[a-zA-Z])(?=.*\d)[\S]{8,30}$/.test(value))) {
+        callback(new Error(this.$t('error.format.pw')));
+      } else {
+        callback();
+      }
+    };
+    const validPWCheck = (rule, value, callback) => {
+      if(value == ''){
+        callback(new Error(this.$t('error.input.pwCheck')));
+      }
+      else if(value != this.registForm.pw){
+        callback(new Error(this.$t('error.input.pwCheckFail')));
+      } else {
+        callback();
+      }
+    };
+    return {
+      applyType: 'phone',
+      cCode:'',
+      teammodelID: '',
+      agreePrivacy: '',
+      sendText: '',
+      lang: localStorage.getItem('local'),
+      countdownSec: 60,
+      verfTime: 0,
+      countdown: false,
+      registForm: {
+          account: '',
+          name: '',
+          pw: '',
+          pwCheck: '',
+          pinCode:''
+      },
+      registRules: {
+        account: [
+          {validator: validAccount , trigger: 'blur' },
+        ],
+        name: [
+          {required: true, message: () => this.$t('error.required') , trigger: 'blur' },
+        ],
+        pw: [
+          {required: true, message: () => this.$t('error.required') , trigger: 'blur' },
+          {validator: validPW , trigger: 'blur' }
+        ],
+        pwCheck: [
+          {required: true, message: () => this.$t('error.required') , trigger: 'blur' },
+          {validator: validPWCheck , trigger: 'blur' }
+        ],
+        pinCode: [
+          {required: true, message: () => this.$t('error.required') , trigger: 'blur' },
+        ],        
+      },
+      loading: false
+    }
+  },
+  computed: {
+    userAccess() { return this.$access.getExtendInfo('userAccess');},
+    userInfo() { return this.$access.getExtendInfo('userInfo');},
+    ...mapState({
+      config: state => state.config
+    }),
+    ...mapGetters({
+        loginSchooCode: 'user/getLoginSchooCode',
+        srvAdr: 'config/getSrvAdr'
+    }),
+    descriptionURL: function () {
+      let domain = 'https://account.habookaclass.biz'
+      let path;
+      if(this.srvAdr == 'China'){
+        domain = 'https://account.teammodel.cn'
+      }
+      switch (this.lang.toLowerCase()) {
+          case 'zh-tw':
+              path =  '/html/description/zh_TW.html'
+              break;
+          case 'zh-cn':
+              path = '/html/description/zh_CN.html'
+              break;
+          case 'en-us':
+              path = '/html/description/en_US.html'
+              break;
+        }
+
+        return domain + path
+    },
+    privacyURL: function () {
+      let domain = 'https://account.habookaclass.biz'
+      let path;
+      if(this.srvAdr == 'China'){
+        domain = 'https://account.teammodel.cn'
+      }
+      switch (this.lang.toLowerCase()) {
+          case 'zh-tw':
+              path = '/html/privacy/zh_TW.html'
+              break;
+          case 'zh-cn':
+              path = '/html/privacy/zh_CN.html'
+              break;
+          case 'en-us':
+              path = '/html/privacy/en_US.html'
+              break;
+      }
+
+      return domain + path
+    },
+    sendBtnText: function(){ // 發送驗證信與驗證碼字串判斷
+        let str = this.$t('regist.btn.send' + this.applyType)
+        let timeStr = ''
+        if(this.countdown) timeStr = '(' + this.verfTime + ')'
+
+        return str + timeStr
+    },
+    pinCodeSwitch: function(){
+      let disabledFlag = false
+      if(this.registForm.account === '') disabledFlag = true
+      if(this.applyType == 'phone' && this.cCode === '') disabledFlag = true
+      return disabledFlag
+    },
+    accFormat: function(){
+      let acc = this.registForm.account
+      if(this.applyType == 'phone' && this.cCode == 886 && acc.indexOf(0) == 0) {
+        acc = acc.substr(1)
+      }
+
+      return acc
+    }
+  },
+  created() {
+    this.verfTime = this.countdownSec;
+    // this.teammodelID = Math.floor(new Date().getTime() / 1000)
+  },
+  methods: {
+    handleSubmit: function(name){
+      this.$refs[name].validate( async(valid) => {
+        if (valid) {
+          let data = {
+            applyType: this.applyType,
+            name: this.registForm.name,
+            account: this.accFormat,
+            pw: this.registForm.pw,
+            country: this.cCode,
+            pinCode: this.registForm.pinCode
+          }
+
+          this.$api.regist.crtAccount(data).then(res => {
+            if(res.error){
+              let text;
+              switch (res.error) {
+                case 2:
+                  text = this.$t('error.coreApi.error2.default')
+                  break;
+                case 3:
+                  text = this.$t('error.coreApi.error3')
+                  break;
+              }
+
+              this.$Message.warning({
+                  content: text,
+                  duration: 7,
+                  closable: true
+              })
+            } else {
+              console.log('登入')
+              console.log(res)
+              // 1. 登入大雲
+              // 2. 檢查是否有學校沒有則跳至schoolList
+              // 3. 有學校是否和login_schollCode 一樣
+              // 4. 沒有一樣預設第一個
+              // 5. 儲存 asscess_token, id_token, expires_in
+              // 6. 登入User.API
+            }
+          })
+        }
+      })
+    },
+    sendPinCode(){
+      let data = {
+        applyType: this.applyType,
+        to: this.accFormat,
+        lang: this.lang,
+        hasUser: false,
+        country: this.cCode
+      }
+      this.$api.SendPinCode(data).then(res => {
+        let errorFlag = false
+        if(res){
+          errorFlag = true
+          this.$Message.warning({
+              content: text = this.$t('error.coreApi.error2.' + this.applyType),
+              duration: 7,
+              closable: true
+          })
+        } 
+
+        if(!errorFlag){
+          this.countdown = true
+          this.reciprocal()
+        }
+      })
+    },
+    reciprocal () { // 調整倒數時間至可控
+        this.verfTime -=1;
+        if(this.verfTime==0){
+          this.countdown = false
+          this.verfTime = this.countdownSec;
+        } else{
+          //每秒執行一次,showTime()
+          setTimeout(this.reciprocal,1000);
+        }
+    },
+  }
+}
+</script>