<template> <view id="login-container" class="login-container"> <image class="bgImage" :src="useStore.loginBg" v-if="useStore.loginBg" /> <view class="middle"> <view class="middle-top"> <image class="logo" mode="heightFix" :src="useStore.loginLogo" v-if="useStore.loginLogo" /> <text class="title" :style="{ color: useStore.loginBg ? '#FFFFFF' : '#000000' }" v-if="useStore.loginTitle">{{ useStore.loginTitle }}</text> </view> <view class="middle-content"> <text class="title" :style="{ color: useStore.loginBg ? '#FFFFFF' : '#000000' }">请登录</text> <!-- #ifdef APP-PLUS || MP-WEIXIN --> <view class="prompt" v-if="!linkUrl">首次账号登录请先配置服务器</view> <view class="setting" @tap="goSeverConfig"> 配置服务器 </view> <!--#endif--> </view> <view class="middle-input" v-if="switchText == '验证码登录'"> <u-input v-model="phone" prefixIcon="phone" placeholder="请输入手机号" :maxlength="11" /> <u-input v-model="verify" prefixIcon="email" placeholder="请输入验证码" :maxlength="6"> <template #suffix> <button class="verify" @click="getVerifyCode">{{ !useStore.codeTime ? "获取验证码" : useStore.codeTime + "s" }}</button> </template> </u-input> </view> <view class="middle-input" v-if="switchText == '账号密码登录'"> <u-input type="text" v-model="username" prefixIcon="account" placeholder="请输入账号" /> <u-input v-model="password" prefixIcon="lock" placeholder="请输入密码" :password="isPassword"> <template #suffix> <text :class="!isPassword ? 'iconfont oaIcon-eye' : 'iconfont oaIcon-eye-close'" @click="isPassword = !isPassword"></text> </template> </u-input> </view> <button class="middle-submit" @click="submitRes">登 录</button> <!-- #ifdef APP-PLUS || MP-WEIXIN || H5 --> <view class="middle-switch" v-if="proxy.$common.isVisible()"> <text class="switch-loginMethod" @click="switchMode(1)">{{ switchText === "验证码登录" ? "账号密码登录" : "验证码登录" }}</text> <view style="margin: auto"></view> <text class="switch-register" @click="switchMode(2)">注册账号</text> </view> <!--#endif--> <!-- #ifdef APP-PLUS || MP-WEIXIN --> <view class="middle-agreed text-center"> <u-checkbox shape="circle" inactiveColor="#0081ff" size="13" :usedAlone="true" :checked="uChecked" @change="uCheckedChange"></u-checkbox> <!-- <text>登录即已代表阅读并同意</text> --> <text>我已阅读并同意</text> <text @click="handleUserAgrement" class="text-blue">用户协议</text> <text>和</text> <text @click="handlePrivacy" class="text-blue">隐私政策</text> </view> <!--#endif--> </view> <view class="bottom"> <div class="title">{{ useStore.loginBottomTitle }}</div> </view> </view> <u-modal :show="modalShow" title="用户协议及隐私政策" :confirmText="'同意'" :cancelText="'不同意'" :zoom="false" :showCancelButton="true" @confirm="(uChecked = true), (modalShow = false)" @cancel="modalShow = false" > <view class="slot-content"> <view> 您在使用我们的服务时,我们可能会收集和使用您的相关信息。我们希望通过本 <text class="text-blue underline">《用户协议及隐私政策》</text> 向您说明,在使用我们的服务时,我们如何收集、使用、 储存和分享这些信息,以及我们为您提供的访问、更新、控制和保护这些信息的方式。本 <text @click="handleUserAgrement" class="text-blue underline">《用户协议</text> <text class="text-blue">及</text> <text @click="handlePrivacy" class="text-blue underline">隐私政策》</text>,希望您仔细阅读,充分理解协议中的内容后再点击同意。 </view> </view> </u-modal> </template> <script setup> /*----------------------------------依赖引入-----------------------------------*/ import { onLoad, onShow, onHide, onLaunch, onReady } from "@dcloudio/uni-app"; import { reactive, getCurrentInstance, toRefs, inject, nextTick } from "vue"; /*----------------------------------接口引入-----------------------------------*/ /*----------------------------------组件引入-----------------------------------*/ /*----------------------------------store引入-----------------------------------*/ import { useStores, commonStores } from "@/store/modules/index"; /*----------------------------------公共方法引入-----------------------------------*/ import config from "@/config"; import { storageSystem } from "@/utils/storage"; /*----------------------------------公共变量-----------------------------------*/ const { proxy } = getCurrentInstance(); const useStore = useStores(); const commonStore = commonStores(); /*----------------------------------变量声明-----------------------------------*/ const state = reactive({ /** login数据 */ phone: undefined, verify: undefined, switchText: "验证码登录", username: undefined, password: undefined, isPassword: true, /** 服务器配置数据 */ linkUrl: uni.getStorageSync("serveUrl"), /** 用户隐私协议数据 */ uChecked: false, modalShow: false, }); const { phone, verify, switchText, username, password, isPassword, linkUrl, uChecked, modalShow } = toRefs(state); /** * @跳转服务器配置 */ function goSeverConfig() { proxy.$tab.navigateTo("/pages/serveConfigSelect"); } /** * @登录方式切换 */ function switchMode(value) { if (value == 1) { switchText.value = switchText.value == "验证码登录" ? "账号密码登录" : "验证码登录"; } else if (value == 2) { proxy.$tab.navigateTo("/pages/register"); } } /** * @点击发送验证码 */ function getVerifyCode() { //#ifdef APP-PLUS || MP-WEIXIN if (!uni.getStorageSync("serveUrl")) { proxy.$modal.msg("首次账号登录请先配置服务器"); return; } //#endif verify.value = undefined; useStore.GetCodeImg({ phone: phone.value, success: (res) => { proxy.$modal.msgSuccess("发送成功"); }, }); } /** * @初始化 */ function init() { useStore.SetInterval("codeTime"); //调用倒计时定时器 //#ifdef H5 useStore.GetWxOpenId(1); //调用获取微信公众号openId if (window.location.host) { linkUrl.value = window.location.host; // linkUrl.value = "172.16.120.165:13200"; // linkUrl.value = "localhost:81"; useStore.GetMobileTenantConfig({ url: linkUrl.value }); } //#endif //#ifdef APP-PLUS || MP-WEIXIN if (uni.getStorageSync("serveUrl")) { linkUrl.value = uni.getStorageSync("serveUrl"); // linkUrl.value = "localhost:81"; useStore.GetMobileTenantConfig({ url: linkUrl.value }); } else { uni.setStorageSync("serveUrl", "manager.usky.cn"); commonStore.setServeList("manager.usky.cn", ""); linkUrl.value = uni.getStorageSync("serveUrl"); // linkUrl.value = "localhost:81"; useStore.GetMobileTenantConfig({ url: linkUrl.value }); } //#endif } /** 点击提交按钮 */ function submitRes() { //#ifdef APP-PLUS || MP-WEIXIN if (!uni.getStorageSync("serveUrl")) { proxy.$modal.msg("首次登录请先进行服务器配置"); return; } if (!uChecked.value) { modalShow.value = true; return; } //#endif if (switchText.value == "验证码登录") { if (!phone.value) { proxy.$modal.msg("请输入手机号"); return; } if (!/^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$/.test(phone.value)) { proxy.$modal.msg("请输入正确的手机号"); return; } if (!verify.value) { proxy.$modal.msg("请输入验证码"); return; } login({ phone: phone.value, verify: verify.value, tenantId: useStore.tenantId, cids: proxy.$settingStore.pushClientId || undefined, type: proxy.$common.isWechatMp() ? "wx" : "app", openId: useStore.wxOpenId || undefined, }); } else { if (!username.value) { proxy.$modal.msg("请输入账户"); return; } if (!password.value) { proxy.$modal.msg("请输入密码"); return; } login({ username: username.value, password: password.value, tenantId: useStore.tenantId, cids: proxy.$settingStore.pushClientId || undefined, type: proxy.$common.isWechatMp() ? "wx" : "app", openId: useStore.wxOpenId || undefined, }); } } /** 获取登录数据 */ function login(data) { proxy.$modal.loading("登录中,请耐心等待..."); useStore.Login(data).then(() => { /** 获取用户信息 */ proxy.$modal.closeLoading(); useStore.GetInfo().then((res) => { proxy.$tab.reLaunch("/pages/index"); proxy.$settingStore.initThemeColor(storageSystem.get("themeColor")); //初始化默认主题 }); }); } // 复选框chage事件 function uCheckedChange(e) { uChecked.value = e; } // 用户协议 function handleUserAgrement() { let site = config.appInfo.agreements[0]; proxy.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`); } // 隐私协议 function handlePrivacy() { let site = config.appInfo.agreements[1]; proxy.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`); } onShow(() => { nextTick(() => { init(); }); }); onLoad((options) => {}); </script> <style lang="scss" scoped> .login-container { position: fixed; top: 0; left: 0; right: 0; bottom: 0; display: flex; width: 100%; height: 100vh; background-color: $uni-bg-color; .bgImage { position: fixed; top: 0; left: 0; right: 0; z-index: 0; width: 100%; height: 100%; } .middle { position: relative; z-index: 1; width: 100%; padding: 0 30px; margin: auto; margin-top: 30%; &-top { display: flex; align-items: center; justify-content: center; margin-bottom: 60px; .logo { height: 40px; width: auto; margin-right: 10px; } .title { font-size: 20px; color: #000; max-width: 50%; // white-space: nowrap; // overflow: hidden; //超出的文本隐藏 // text-overflow: ellipsis; //溢出用省略号显示 } } &-content { display: flex; position: relative; margin: 30px 0 30px 0; .title { margin: auto auto auto 0; color: #000; font-size: 18px; } .setting { color: #2a98ff; margin: auto 0; } .prompt { position: absolute; top: -35px; right: 0px; background-color: #2a98ff; text-align: center; line-height: 25px; display: inline-block; color: #fff; padding: 3px 5px; border-radius: 3px; &::after { content: ""; position: absolute; border: 5px solid transparent; transform: rotate(90deg); right: 5px; bottom: -9px; border-left-color: #2a98ff; } } } // 登录页-服务器配置样式 开始 &-input { :deep(.u-input) { height: 45px; border: 0 !important; border-radius: 8px; margin-bottom: 15px; padding: 5px 12px !important; background-color: #f5f6fa !important; } :deep(.input-placeholder) { color: #c0c4cc !important; } :deep(.uni-input-wrapper) { font-size: 16px; } :deep(.u-icon__icon) { font-size: 24px !important; line-height: 24px !important; color: gray !important; } :deep(.iconfont) { color: gray !important; } :deep(:-webkit-autofill) { caret-color: #000; // 设置光标颜色 // -webkit-text-fill-color: gray !important; -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; background-color: transparent; background-image: none; transition: background-color 50000s ease-in-out 0s; //背景色透明 生效时长 过渡效果 启用时延迟的时间 } } &-switch { width: 100%; display: flex; margin-top: 20px; color: #96a6b5; &-loginMethod { display: block; } &-register { display: block; } } &-submit { height: 45px; line-height: 45px; border-radius: 24px; background: #2a98ff; color: #fff; border: 0px; } &-agreed { color: #96a6b5; margin-top: 30px; display: flex; flex-wrap: wrap; justify-content: center; > uni-view { margin: auto 0; } > uni-text { margin: auto 0; } // animation: roundRule 0.5s linear infinite; } @keyframes roundRule { 0% { transform: translateX(0); } 50% { transform: translateX(-5px); } 100% { transform: translateX(0); } } } .bottom { position: fixed; width: 100%; bottom: 20px; .title { text-align: center; color: #96a6b5; font-size: 14px; } } } </style>