| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- <template>
- <view class="login-page">
- <!-- 顶部欢迎语 -->
- <view class="header">
- <text class="hello">HELLO,</text>
- <text class="welcome">欢迎使用研年健康平台</text>
- </view>
- <!-- 表单区域 -->
- <view class="form-area">
- <!-- 手机号输入 -->
- <view class="input-wrapper">
- <image class="input-icon" src="/static/login/phone.png" />
- <input
- class="input-field"
- type="number"
- maxlength="11"
- placeholder="请输入手机号"
- placeholder-class="placeholder-text"
- v-model="phone"
- />
- </view>
- <!-- 验证码输入 -->
- <view class="input-wrapper">
- <image class="input-icon" src="/static/login/pwd.png" />
- <input
- class="input-field code-input"
- type="number"
- maxlength="6"
- placeholder="请输入验证码"
- placeholder-class="placeholder-text"
- v-model="code"
- />
- <text
- class="code-btn"
- :class="[codeBtnDisabled ? 'code-btn-disabled' : '']"
- @click="onGetCode"
- >{{ countdown > 0 ? countdown + 's后重发' : '获取验证码' }}</text>
- </view>
- <!-- 登录按钮 -->
- <view
- class="login-btn"
- :class="[!canLogin ? 'login-btn-disabled' : '']"
- @click="onLogin"
- >
- <text class="login-btn-text" @click="onLogin">登录</text>
- </view>
- </view>
- <!-- 其他登录方式 -->
- <view class="other-login">
- <view class="divider">
- <view class="divider-line"></view>
- <text class="divider-text">其他登录方式</text>
- <view class="divider-line"></view>
- </view>
- <view class="third-party-area">
- <!-- 微信登录 -->
- <view class="third-party-btn" @click="onWechatLogin">
- <image class="third-party-icon" src="/static/login/wechat@2x.png" />
- </view>
- </view>
- <!-- Apple 登录 - 仅iOS显示,符合苹果审核规范 -->
- <view class="apple-section" >
- <view class="apple-login-btn" @click="onAppleLogin">
- <image class="apple-icon" src="/static/login/apple@2x.png" />
- <text class="apple-btn-text">通过 Apple 登录</text>
- </view>
- </view>
- </view>
- <!-- 底部协议 -->
- <view class="footer">
- <view class="agreement-row" @click="onToggleAgreement">
- <view class="checkbox" :class="[agreed ? 'checkbox-checked' : '']">
- <text class="checkbox-icon" v-if="agreed">✓</text>
- </view>
- <text class="agreement-text">登录即代表同意</text>
- <text class="agreement-link" @click.stop="onOpenPrivacy">隐私政策</text>
- <text class="agreement-text">和</text>
- <text class="agreement-link" @click.stop="onOpenTerms">用户协议</text>
- </view>
- </view>
- <!-- 隐私政策弹窗 -->
- <customPopup :isShow="isShowDrawer" @closePop="isShowDrawer=false">
- <view class="boxcontent">
- <view class="rich_header">
- <text class="rich_title">服务协议与隐私政策</text>
- </view>
- <scroll-view class="privateContent" scroll-y="true">
- <view class="contentBox">
- <text class="content-text">感谢您信任并使用研年健康平台!我们深知保护个人隐私信息的重要性,请在使用研年健康平台的服务前,认真阅读我们的</text>
- <view class="linebox">
- <text class="link-text" @click="goWebview(1)">《用户协议》</text>
- <text class="content-text">和</text>
- <text class="link-text" @click="goWebview(2)">《隐私政策》</text>
- </view>
- <text class="content-text">,以帮助您了解我们在收集、使用、存储和共享您个人信息的情况以及您享有的相关权利。</text>
- <text class="content-text"> 请您仔细阅读并作出适当的选择:</text>
- <text class="content-text"> 1.《用户协议》的主要内容包括:协议适用范围、服务内容及形式、软件使用及许可、终端责任安全、用户权利与义务、用户行为规范、知识产权声明、用户信息保护。</text>
- <text class="content-text"> 2.关于《隐私政策》,我们特别向您说明:</text>
- <text class="content-text">(1)根据合法、正当、必要的原则,我们会收集实现产品功能所必要的信息,包括:您在注册帐号时所填写的信息(昵称、手机号码);您的日志信息及设备信息、设备型号;当您选择使用部分服务时,我们将在征求您的同意后获取相关权限。</text>
- </view>
- </scroll-view>
- <view class="rich_btn">
- <text class="btn-disagree" @click="onAgree(0)">不同意</text>
- <text class="btn-agree" @click="onAgree(1)">同意</text>
- </view>
- </view>
- </customPopup>
- <ay-toast ref="ayToast" />
- </view>
- </template>
- <script>
- import customPopup from '@/components/customPopup/customPopup.nvue'
- import ayToast from '@/components/ay-toast/ay-toast.nvue'
- import toast from '@/utils/toast.js'
- import http from '@/utils/http'
- import { sendCode, login } from '@/utils/api/login.js'
- export default {
- components: {
- customPopup,
- ayToast
- },
- data() {
- return {
- phone: '',
- code: '',
- countdown: 0,
- agreed: false,
- isIOS: false,
- countdownTimer: null,
- isShowDrawer: false
- }
- },
- computed: {
- isPhoneValid() {
- return /^1[3-9]\d{9}$/.test(this.phone)
- },
- codeBtnDisabled() {
- return this.countdown > 0 || !this.isPhoneValid
- },
- canLogin() {
- return this.isPhoneValid && this.code.length >= 4 && this.agreed
- }
- },
- watch: {
- isShowDrawer(val) {
- if (val) {
- uni.hideKeyboard()
- }
- }
- },
- onLoad() {
- // 判断平台
- const sysInfo = uni.getSystemInfoSync()
- this.isIOS = sysInfo.platform === 'ios'
- // 读取持久化的隐私政策同意状态
- const agreedFlag = uni.getStorageSync('privacy_agreed')
- if (agreedFlag) {
- this.agreed = true
- }
- },
- onUnload() {
- if (this.countdownTimer) {
- clearInterval(this.countdownTimer)
- this.countdownTimer = null
- }
- },
- methods: {
- // 获取验证码
- async onGetCode() {
- if (this.codeBtnDisabled) return
- if (!this.isPhoneValid) {
- toast.error('请输入正确的手机号')
- return
- }
- try {
- await sendCode(this.phone)
- // 发送成功后开始倒计时
- this.countdown = 60
- this.countdownTimer = setInterval(() => {
- this.countdown--
- if (this.countdown <= 0) {
- clearInterval(this.countdownTimer)
- this.countdownTimer = null
- }
- }, 1000)
- toast.success('验证码已发送')
- } catch (e) {
- // 错误已由 http 层自动 toast 展示
- }
- },
- // 登录
- async onLogin() {
- if (!this.agreed) {
- this.isShowDrawer = true
- return
- }
- if (!this.isPhoneValid) {
- toast.error('请输入正确的手机号')
- return
- }
- if (this.code.length < 4) {
- toast.error('请输入验证码')
- return
- }
- toast.loading('登录中...')
- try {
- const data = await login(this.phone, this.code)
- // 存储 Token
- http.setToken(data.token)
- // 存储用户基本信息
- uni.setStorageSync('user_info', {
- userId: data.userId,
- phone: data.phone,
- nickname: data.nickname,
- avatar: data.avatar,
- appId: data.appId
- })
- // 单独存储各字段(便于页面直接读取)
- uni.setStorageSync('phone', data.phone)
- uni.setStorageSync('nickname', data.nickname || '')
- uni.setStorageSync('avatar', data.avatar || '')
- uni.setStorageSync('appId', data.appId || '')
- toast.hide()
- console.log("登录成功")
- // 跳转首页
- uni.reLaunch({ url:"/pages/device/list/list" })
- } catch (e) {
- toast.hide()
- toast.error(e.message || '登录失败,请稍后重试')
- }
- },
- // 微信登录(暂未实现)
- onWechatLogin() {
- if (!this.agreed) {
- this.isShowDrawer = true
- return
- }
- toast.text('微信登录暂未开放')
- // TODO: 微信登录实现(需绑定手机号)
- },
- // Apple登录(暂未实现)
- onAppleLogin() {
- if (!this.agreed) {
- this.isShowDrawer = true
- return
- }
- toast.text('Apple登录暂未开放')
- // TODO: Apple 登录实现(需绑定手机号)
- },
- // 切换协议勾选
- onToggleAgreement() {
- this.agreed = !this.agreed
- if (this.agreed) {
- uni.setStorageSync('privacy_agreed', true)
- } else {
- uni.removeStorageSync('privacy_agreed')
- }
- },
- // 打开隐私政策/用户协议弹窗
- onOpenPrivacy() {
- this.isShowDrawer = true
- },
- onOpenTerms() {
- this.isShowDrawer = true
- },
- // 弹窗中同意/不同意操作
- onAgree(type) {
- this.isShowDrawer = false
- if (type === 1) {
- this.agreed = true
- uni.setStorageSync('privacy_agreed', true)
- }
- },
- // 跳转webview查看完整协议
- goWebview(id) {
- uni.navigateTo({
- url: '/pages/webview/webview?id=' + id
- })
- }
- }
- }
- </script>
- <style>
- .login-page {
- flex: 1;
- background-color: #ffffff;
- padding-left: 40rpx;
- padding-right: 40rpx;
- padding-top: 160rpx;
- }
- /* 顶部欢迎语 */
- .header {
- margin-bottom: 80rpx;
- }
- .hello {
- font-size: 56rpx;
- font-weight: bold;
- color: #1a9e78;
- margin-bottom: 10rpx;
- }
- .welcome {
- font-size: 40rpx;
- font-weight: bold;
- color: #1a9e78;
- }
- /* 表单区域 */
- .form-area {
- margin-bottom: 60rpx;
- }
- .input-wrapper {
- flex-direction: row;
- align-items: center;
- background-color: #f5f5f5;
- border-radius: 16rpx;
- padding-left: 24rpx;
- padding-right: 24rpx;
- height: 100rpx;
- margin-bottom: 24rpx;
- }
- .input-icon {
- width: 40rpx;
- height: 40rpx;
- margin-right: 16rpx;
- }
- .input-field {
- flex: 1;
- font-size: 30rpx;
- color: #333333;
- height: 100rpx;
- }
- .placeholder-text {
- color: #999999;
- font-size: 30rpx;
- }
- .code-input {
- flex: 1;
- }
- .code-btn {
- font-size: 28rpx;
- color: #1a9e78;
- padding-left: 20rpx;
- }
- .code-btn-disabled {
- color: #cccccc;
- }
- /* 登录按钮 */
- .login-btn {
- height: 96rpx;
- background-color: #7ecdb8;
- border-radius: 48rpx;
- align-items: center;
- justify-content: center;
- margin-top: 20rpx;
- }
- .login-btn-disabled {
- background-color: #c8e6dc;
- }
- .login-btn-text {
- flex: 1;
- font-size: 32rpx;
- color: #ffffff;
- font-weight: bold;
- text-align: center;
- line-height: 96rpx;
- }
- /* 其他登录方式 */
- .other-login {
- flex: 1;
- align-items: center;
- }
- .divider {
- flex-direction: row;
- align-items: center;
- margin-top: 60rpx;
- margin-bottom: 50rpx;
- }
- .divider-line {
- width: 140rpx;
- height: 1px;
- background-color: #e0e0e0;
- }
- .divider-text {
- font-size: 26rpx;
- color: #999999;
- margin-left: 20rpx;
- margin-right: 20rpx;
- }
- /* 第三方登录按钮 */
- .third-party-area {
- flex-direction: row;
- justify-content: center;
- align-items: center;
- margin-bottom: 40rpx;
- }
- .third-party-btn {
- width: 100rpx;
- height: 100rpx;
- border-radius: 50rpx;
- background-color: #f5f5f5;
- align-items: center;
- justify-content: center;
- }
- .third-party-icon {
- width: 56rpx;
- height: 56rpx;
- }
- /* Apple 登录按钮 - 符合苹果HIG规范 */
- .apple-section {
- align-items: center;
- margin-top: 20rpx;
- }
- .apple-login-btn {
- flex-direction: row;
- align-items: center;
- justify-content: center;
- width: 580rpx;
- height: 88rpx;
- background-color: #000000;
- border-radius: 44rpx;
- }
- .apple-icon {
- width: 36rpx;
- height: 36rpx;
- margin-right: 12rpx;
- }
- .apple-btn-text {
- font-size: 30rpx;
- color: #ffffff;
- font-weight: 500;
- }
- /* 底部协议 */
- .footer {
- position: fixed;
- bottom: 60rpx;
- left: 40rpx;
- right: 40rpx;
- }
- .agreement-row {
- flex-direction: row;
- align-items: center;
- justify-content: center;
- }
- .checkbox {
- width: 32rpx;
- height: 32rpx;
- border-radius: 16rpx;
- border-width: 2rpx;
- border-style: solid;
- border-color: #cccccc;
- align-items: center;
- justify-content: center;
- margin-right: 10rpx;
- }
- .checkbox-checked {
- background-color: #1a9e78;
- border-color: #1a9e78;
- }
- .checkbox-icon {
- font-size: 20rpx;
- color: #ffffff;
- }
- .agreement-text {
- font-size: 24rpx;
- color: #999999;
- }
- .agreement-link {
- font-size: 24rpx;
- color: #1a9e78;
- }
- /* 隐私政策弹窗 */
- .boxcontent {
- padding-left: 10rpx;
- padding-right: 10rpx;
- }
- .rich_header {
- align-items: center;
- margin-bottom: 30rpx;
- }
- .rich_title {
- font-size: 34rpx;
- font-weight: bold;
- color: #333333;
- }
- .privateContent {
- height: 500rpx;
- }
- .contentBox {
- padding-left: 10rpx;
- padding-right: 10rpx;
- }
- .content-text {
- font-size: 26rpx;
- color: #666666;
- line-height: 44rpx;
- }
- .linebox {
- flex-direction: row;
- flex-wrap: wrap;
- align-items: center;
- }
- .link-text {
- font-size: 26rpx;
- color: #1a9e78;
- line-height: 44rpx;
- }
- .rich_btn {
- flex-direction: row;
- justify-content: space-between;
- margin-top: 30rpx;
- padding-left: 20rpx;
- padding-right: 20rpx;
- }
- .btn-disagree {
- flex: 1;
- height: 80rpx;
- line-height: 80rpx;
- text-align: center;
- font-size: 30rpx;
- color: #999999;
- background-color: #f5f5f5;
- border-radius: 40rpx;
- margin-right: 20rpx;
- }
- .btn-agree {
- flex: 1;
- height: 80rpx;
- line-height: 80rpx;
- text-align: center;
- font-size: 30rpx;
- color: #ffffff;
- background-color: #1a9e78;
- border-radius: 40rpx;
- margin-left: 20rpx;
- }
- </style>
|