Bladeren bron

添加登录

yangg 1 jaar geleden
bovenliggende
commit
764d22f70b
6 gewijzigde bestanden met toevoegingen van 246 en 38 verwijderingen
  1. 1 0
      package.json
  2. 73 0
      src/composables/AliyunAfs.js
  3. 9 1
      src/locales/zh.json
  4. 5 4
      src/utils/request.js
  5. 153 33
      src/views/auth/boxed-signin.vue
  6. 5 0
      yarn.lock

+ 1 - 0
package.json

@@ -42,6 +42,7 @@
     "sweetalert2": "^11.5.1",
     "swiper": "^8.4.4",
     "tippy.vue": "^3.2.1",
+    "uuid": "^10.0.0",
     "vant": "^4.9.0",
     "vue": "^3.2.37",
     "vue-clipboard3": "^2.0.0",

+ 73 - 0
src/composables/AliyunAfs.js

@@ -0,0 +1,73 @@
+function loadJs(url, callback) {
+  return new Promise((resolve, reject) => {
+    const script = document.createElement('script')
+    script.async = true
+    script.addEventListener('load', () => {
+      callback()
+    })
+    script.addEventListener('error', () => {
+      reject(new Error(`Error loading ${url}`))
+    })
+    script.src = url
+    document.head.appendChild(script)
+  })
+}
+
+export default function(id, scene, appkey, callback) {
+  return {
+    nc: null,
+    init() {
+      var self = this
+
+      function call() {
+        self.show()
+      }
+
+      loadJs('//g.alicdn.com/sd/ncpc/nc.js', call)
+    },
+
+    show() {
+      let nc_token = ['CF_APP_1', (new Date()).getTime(), Math.random()].join(':')
+
+      let NC_Opt = {
+        // 声明滑动验证需要渲染的目标元素ID。
+        renderTo: id,
+        // 应用类型标识。它和使用场景标识(scene字段)一起决定了滑动验证的业务场景与后端对应使用的策略模型。您可以在人机验证控制台的配置管理页签找到对应的appkey字段值,请务必正确填写。
+        appkey: appkey,
+        // 使用场景标识。它和应用类型标识(appkey字段)一起决定了滑动验证的业务场景与后端对应使用的策略模型。您可以在人机验证控制台的配置管理页签找到对应的scene值,请务必正确填写。
+        scene: scene,
+        // 滑动验证码的主键,请勿将该字段定义为固定值。确保每个用户每次打开页面时,其token值都是不同的。系统默认的格式为:”您的appkey”+”时间戳”+”随机数”。
+        token: nc_token,
+        // 滑动条的宽度。
+        customWidth: '100%',
+        // 业务键字段,可为空。为便于线上问题的排查,建议您按照线上问题定位文档中推荐的方法配置该字段值。
+        trans: {},
+        // 语言。PC端Web页面场景默认支持18国语言,详细配置方法请参见自定义文案与多语言文档。
+        language: 'cn',
+        // 是否启用。一般情况,保持默认值(true)即可。
+        isEnabled: true,
+        // 内部网络请求的超时时间。一般情况建议保持默认值(3000ms)。
+        timeout: 3000,
+        // 允许服务器超时重复次数,默认5次。超过重复次数后将触发报错。
+        times: 5,
+        // 前端滑动验证通过时会触发该回调参数。您可以在该回调参数中将请求标识(token)、会话ID(sessionid)、签名串(sig)字段记录下来,随业务请求一同发送至您的服务端调用验签。
+        callback: function(data) {
+          data.nc_token = nc_token
+          callback(data)
+        }
+      }
+      this.nc = new noCaptcha(NC_Opt) // eslint-disable-line
+      // 用于自定义文案。详细配置方法请参见自定义文案与多语言文档。
+      this.nc.upLang('cn', {
+        _startTEXT: '请按住滑块,拖动到最右边',
+        _yesTEXT: '验证通过',
+        _error300: '哎呀,出错了,点击<a href=\"javascript:__nc.reset()\">刷新</a>再来一次',
+        _errorNetwork: '网络不给力,请<a href=\"javascript:__nc.reset()\">点击刷新</a>'
+      })
+    },
+
+    reload() {
+      this.nc.reload()
+    }
+  }
+}

+ 9 - 1
src/locales/zh.json

@@ -124,5 +124,13 @@
     "coming_soon_boxed": "即将推出盒装",
     "coming_soon_cover": "即将推出封面",
     "contact_us_boxed": "联系我们 盒装",
-    "contact_us_cover": "联系我们封面"
+    "contact_us_cover": "联系我们封面",
+    "logIn": "登录",
+    "username": "请输入管理员名称",
+    "password": "请输入管理员密码",
+    "validcode": "请输入图片验证码",
+    "val_username": "请输入管理员名称",
+    "val_password": "请输入管理员密码",
+    "val_validcode": "请输入图片验证码",
+    "val_form": "表单填写有误,请检查!"
 }

+ 5 - 4
src/utils/request.js

@@ -48,8 +48,8 @@ service.interceptors.request.use(config => {
   if (accessToken) {
     config.headers['Authorization'] = accessToken
   }
-  // 如果是上传接口,不限制超时时间
-  if (config.url === `${api.admin}/uploaders`) {
+  // 如果是上传接口,不限制超时时间${api.admin}
+  if (config.url === `http://192.168.8.107:9999/uploaders`) {
     config.timeout = 0
   }
   return config
@@ -88,10 +88,11 @@ service.interceptors.response.use(
  * @param target
  */
 const closeLoading = (target) => {
-  if (!target.config.ElLoading) return true
+  console.log(target);
+  if (!target.config.loading) return true
   return new Promise((resolve, reject) => {
     setTimeout(() => {
-      target.config.ElLoading.close()
+      target.config.loading.close()
       resolve()
     }, 200)
   })

+ 153 - 33
src/views/auth/boxed-signin.vue

@@ -26,7 +26,6 @@
                             </h1>
                             <p class="text-base font-bold leading-normal text-white-dark">欢迎登录V3StudioApp</p>
                         </div>
-                        {{ $t('dashboard') }}
                         <!--  <form class="space-y-5 dark:text-white" @submit.prevent="router.push('/')">
                             <div>
                                 <label for="Email">请输入账号</label>
@@ -59,38 +58,41 @@
                                 登录
                             </button>
                         </form> -->
-                       <!--  <el-form :model="loginForm" :rules="loginRules" ref="loginForm" class="login-input">
+                        <el-form :model="loginForm" ref="loginFormRef" class="login-input">
                             <el-form-item prop="username">
                                 <el-input v-model="loginForm.username" :placeholder="$t('username')" autofocus
                                     clearable>
-                                    <svg-icon #prefix class="el-input__icon" icon-class="user" />
+                                    <template v-slot:prefix>
+                                        <svg-icon class="el-input__icon" icon-class="user" />
+                                    </template>
                                 </el-input>
                             </el-form-item>
                             <el-form-item prop="password">
-                                <el-input v-model="loginForm.password" type="password" autocompete="off"
+                                <el-input v-model="loginForm.password" type="password" autocomplete="off"
                                     :placeholder="$t('password')" :minlength="6" :maxlength="20" clearable>
-                                    <svg-icon slot="prefix" class="el-input__icon" icon-class="password" />
+                                    <template v-slot:prefix>
+                                        <svg-icon class="el-input__icon" icon-class="password" />
+                                    </template>
                                 </el-input>
                             </el-form-item>
-                            <div style="margin-bottom: 20px" v-if="validateInFO.validator_type === 'ALIYUN'">
-                                <div id="pc-valid" class="nc-container"></div>
-                            </div>
-                            <el-form-item prop="validcode" v-else-if="validateInFO.validator_type === 'IMAGE'">
-                                <el-input v-model="loginForm.validcode" :placeholder="$t('validcode')"
-                                    :maxlength="4" clearable>
-                                    <template slot="append">
+                            <el-form-item prop="validcode" v-if="validateInFO.validator_type === 'IMAGE'">
+                                <el-input v-model="loginForm.validcode" :placeholder="$t('validcode')" :maxlength="4"
+                                    clearable>
+                                    <template v-slot:append>
                                         <img class="login-validcode-img" :src="validcodeImg" @click="changeValidcode">
                                     </template>
                                 </el-input>
                             </el-form-item>
-                            <div v-else></div>
+                            <div v-else-if="validateInFO.validator_type === 'ALIYUN'" style="margin-bottom: 20px">
+                                <div id="pc-valid" class="nc-container"></div>
+                            </div>
                             <el-form-item>
                                 <el-button type="primary" :loading="loading" :disabled="!accountAfsSuccess" class="btn"
-                                    @click="submitLogin">{{
-                                        $t('logIn') }}</el-button>
+                                    @click="submitLogin(loginFormRef)">
+                                    {{ $t('logIn') }}
+                                </el-button>
                             </el-form-item>
-                        </el-form> -->
-
+                        </el-form>
                         <!-- 新用户注册账号--暂不开放 -->
                         <!-- <div class="relative my-7 text-center md:mb-9">
                             <span class="absolute inset-x-0 top-1/2 h-px w-full -translate-y-1/2 bg-white-light dark:bg-white-dark"></span>
@@ -112,45 +114,65 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { computed, reactive, ref } from 'vue';
+import { computed, onMounted, reactive, ref } from 'vue';
+import Vue from 'vue'
 import { useI18n } from 'vue-i18n';
 import appSetting from '@/app-setting';
 import { useAppStore } from '@/stores/index';
-import { useRouter } from 'vue-router';
+import { useRouter, useRoute } from 'vue-router';
 import { useMeta } from '@/composables/use-meta';
+import Storage from '@/utils/storage'
+import * as API_common from '@/api/common'
+import { v4 as uuidv4 } from "uuid";
+import AliyunAfs from '@/composables/AliyunAfs'
+import type { FormInstance } from 'element-plus'
 
-/* import IconCaretDown from '@/components/icon/icon-caret-down.vue';
-import IconMail from '@/components/icon/icon-mail.vue';
-import IconLockDots from '@/components/icon/icon-lock-dots.vue';
-import IconInstagram from '@/components/icon/icon-instagram.vue';
-import IconFacebookCircle from '@/components/icon/icon-facebook-circle.vue';
-import IconTwitter from '@/components/icon/icon-twitter.vue';
-import IconGoogle from '@/components/icon/icon-google.vue'; */
 
-const loginForm: any = reactive({
+const loading: any = ref(false)
+const loginForm = reactive({
     username: '',
     password: '',
     scene: 'LOGIN',
     validcode: ''
-})
-const loginRules = reactive({
+});
+const { t } = useI18n();
+/* const loginRules = reactive({
     username: [
-        { required: true, message: $t('val_username'), trigger: 'blur' }
+        { required: true, message: t('val_username'), trigger: 'blur' }
     ],
     password: [
-        { required: true, message: $t('val_password'), trigger: 'blur' }
+        { required: true, message: t('val_password'), trigger: 'blur' }
     ],
     validcode: [
-        { required: true, message: $t('val_validcode'), trigger: 'blur' }
+        { required: true, message: t('val_validcode'), trigger: 'blur' }
     ]
+}); */
+// 验证信息
+const validateInFO: any = ref({})
+let validcodeImg: any = ref('')
+let uuid: any = ref(Storage.getItem('admin_uuid'))
+// 阿里云验证条实例
+let afs: any = ref(null)
+// 当滑动验证成功之后返回的参数
+const afsParam: any = ref({
+    c_sessionid: '',
+    sig: '',
+    nc_token: ''
 })
+// 阿里云滑动验证是否通过 && 如果不是 阿里云验证则直接设置为 true
+const accountAfsSuccess: any = ref(false)
+// 是否为加盟商登录
+const is_franchise: any = ref(false)
+const loginFormRef = ref<FormInstance>()
+
 
 useMeta({ title: 'Login Boxed' });
 const router = useRouter();
-
+const route = useRoute()
 const store = useAppStore();
 // multi language
 const i18n = reactive(useI18n());
+console.log(i18n);
 const changeLanguage = (item: any) => {
     i18n.locale = item.code;
     appSetting.toggleLanguage(item);
@@ -158,4 +180,102 @@ const changeLanguage = (item: any) => {
 const currentFlag = computed(() => {
     return `/assets/images/flags/${i18n.locale.toUpperCase()}.svg`;
 });
+
+onMounted(() => {
+    const uuids = Storage.getItem('admin_uuid')
+    if (uuids) {
+        uuid = uuids
+    } else {
+        const _uuid = uuidv4()
+        uuid = _uuid
+        Storage.setItem('admin_uuid', _uuid, { expires: 30 })
+    }
+    changeValidcode();
+    API_common.getValidator().then(res => {
+        validateInFO.value = res
+        const { validator_type, aliyun_afs } = res
+        if (validator_type === 'ALIYUN') {
+            //afs = new AliyunAfs('#pc-valid', aliyun_afs.scene, aliyun_afs.app_key, initCaptcha)
+            afs.init()
+        } else {
+            accountAfsSuccess.value = true
+        }
+    })
+});
+
+/** 阿里云滑动验证 通过后的回调函数 **/
+const initCaptcha = (data) => {
+    afsParam.c_sessionid = data.csessionid
+    afsParam.sig = data.sig
+    afsParam.nc_token = data.nc_token
+    accountAfsSuccess.value = true
+}
+
+/** 更换图片验证码 */
+const changeValidcode = () => {
+    validcodeImg = API_common.getValidateCodeUrl('LOGIN', uuid)
+    console.log(validcodeImg);
+}
+const MixinClone = (obj) => {
+    return JSON.parse(JSON.stringify(obj))
+}
+
+/** 登录处理 */
+const dispatchLoginAction = (params) => {
+    loading = true
+    return new Promise((resolve, reject) => {
+        useAppStore.dispatch('loginAction', params).then((res) => {
+            loading = false
+            if (res && api.adminWS) {
+                try {
+                    const WS = new WebSocket(api.adminWS, res.access_token)
+                    Vue.prototype.$WS = WS
+                } catch (error) {
+                    console.log('websocket 实例化失败:', error)
+                }
+            }
+            const forward = route.query.forward
+            console.log(forward);
+            let query = JSON.parse(JSON.stringify(route.query))
+
+            //delete query.forward
+            router.push({ path: '/', query }).catch(() => { })//forward ||
+        }).catch(() => {
+            loading = false
+            reject()
+        })
+    })
+}
+
+const submitLogin = (formEl: FormInstance | undefined) => {
+    if (!accountAfsSuccess) return
+    if (afs) {
+        const params = MixinClone(loginForm)
+        params.c_sessionid = afsParam.c_sessionid
+        params.sig = afsParam.sig
+        params.nc_token = afsParam.nc_token
+        delete params.validcode
+        delete params.scene
+        dispatchLoginAction(params).catch(() => {
+            // this.afs.reload()
+            accountAfsSuccess.value = false
+        })
+    } else {
+        formEl.validate((valid) => {
+            if (valid) {
+                const params = MixinClone(loginForm)
+                params.uuid = uuid
+                params.captcha = params.validcode
+                delete params.validcode
+                dispatchLoginAction(params).catch(() => {
+                    changeValidcode()
+                })
+            } else {
+                //this.$message.error(this.translateKey('val_form'))
+                return false
+            }
+        })
+    }
+}
+
 </script>

+ 5 - 0
yarn.lock

@@ -3201,6 +3201,11 @@ util@^0.10.3:
   dependencies:
     inherits "2.0.3"
 
+uuid@^10.0.0:
+  version "10.0.0"
+  resolved "https://registry.npmmirror.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294"
+  integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==
+
 vant@^4.9.0:
   version "4.9.1"
   resolved "https://registry.npmmirror.com/vant/-/vant-4.9.1.tgz#d042702b0d14da987e4b17e46e4297dabb5fae01"