2026-03-11 11:15:33 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="login-page">
|
|
|
|
|
|
<!-- 装饰背景 -->
|
|
|
|
|
|
<view class="bg-decoration">
|
|
|
|
|
|
<view class="circle circle-1"></view>
|
|
|
|
|
|
<view class="circle circle-2"></view>
|
|
|
|
|
|
<view class="circle circle-3"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 主内容区 -->
|
|
|
|
|
|
<view class="login-container">
|
|
|
|
|
|
<!-- Logo 和标题 -->
|
|
|
|
|
|
<view class="header-section">
|
|
|
|
|
|
<view class="logo-wrapper">
|
|
|
|
|
|
<image class="logo" src="/static/image/car.png" mode="aspectFit"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="app-name">二手车采集</text>
|
|
|
|
|
|
<text class="app-desc">欢迎登录,二手车采集平台</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 登录卡片 -->
|
|
|
|
|
|
<view class="login-card">
|
|
|
|
|
|
<!-- 登录方式切换 -->
|
|
|
|
|
|
<view class="tab-bar">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="tab-item"
|
|
|
|
|
|
:class="{ active: loginType === 'password' }"
|
|
|
|
|
|
@tap="switchLoginType('password')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<text class="tab-text">账号登录</text>
|
|
|
|
|
|
<view class="tab-line" v-if="loginType === 'password'"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="tab-item"
|
|
|
|
|
|
:class="{ active: loginType === 'feishu' }"
|
|
|
|
|
|
@tap="switchLoginType('feishu')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<text class="tab-text">飞书登录</text>
|
|
|
|
|
|
<view class="tab-line" v-if="loginType === 'feishu'"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 账号密码登录表单 -->
|
|
|
|
|
|
<view v-if="loginType === 'password'" class="form-section">
|
|
|
|
|
|
<!-- 账号输入框 -->
|
|
|
|
|
|
<view class="input-group">
|
|
|
|
|
|
<view class="input-wrapper">
|
|
|
|
|
|
<uni-icons type="person" size="20" color="#999"></uni-icons>
|
|
|
|
|
|
<input
|
|
|
|
|
|
class="input-field"
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
placeholder="请输入账号/手机号"
|
|
|
|
|
|
v-model="formData.account"
|
|
|
|
|
|
placeholder-class="input-placeholder"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 密码输入框 -->
|
|
|
|
|
|
<view class="input-group">
|
|
|
|
|
|
<view class="input-wrapper">
|
|
|
|
|
|
<uni-icons type="locked" size="20" color="#999"></uni-icons>
|
|
|
|
|
|
<input
|
2026-03-12 16:47:27 +08:00
|
|
|
|
class="input-field uni-input-input"
|
2026-03-11 11:15:33 +08:00
|
|
|
|
:type="showPassword ? 'text' : 'password'"
|
|
|
|
|
|
placeholder="请输入密码"
|
|
|
|
|
|
v-model="formData.password"
|
|
|
|
|
|
placeholder-class="input-placeholder"
|
2026-03-12 16:47:27 +08:00
|
|
|
|
step="" enterkeyhint="done" autocomplete="off"
|
2026-03-11 11:15:33 +08:00
|
|
|
|
/>
|
|
|
|
|
|
<uni-icons
|
|
|
|
|
|
:type="showPassword ? 'eye' : 'eye-slash'"
|
|
|
|
|
|
size="20"
|
|
|
|
|
|
:color="showPassword ? '#2E6CF6' : '#999'"
|
|
|
|
|
|
@tap="togglePassword"
|
|
|
|
|
|
></uni-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 记住密码和忘记密码 -->
|
|
|
|
|
|
<!-- <view class="form-options">
|
|
|
|
|
|
<view class="remember-me" @tap="toggleRemember">
|
|
|
|
|
|
<view class="checkbox" :class="{ checked: rememberMe }">
|
|
|
|
|
|
<uni-icons v-if="rememberMe" type="checkmarkempty" size="14" color="#fff"></uni-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="option-text">记住密码</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="forget-pwd" @tap="goToForgetPwd">忘记密码?</text>
|
|
|
|
|
|
</view> -->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 登录按钮 -->
|
|
|
|
|
|
<view class="login-btn" :class="{ loading: isLoading }" @tap="handlePasswordLogin">
|
|
|
|
|
|
<text class="btn-text">{{ isLoading ? '登录中...' : '登录' }}</text>
|
|
|
|
|
|
<uni-icons v-if="isLoading" type="spinner-cycle" size="18" color="#fff"></uni-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 飞书登录 -->
|
|
|
|
|
|
<view v-else class="feishu-section">
|
|
|
|
|
|
<!-- 公司选择 -->
|
|
|
|
|
|
<view class="input-group">
|
|
|
|
|
|
<view class="input-wrapper" style="display: flex;align-items: center;gap: 10px;">
|
|
|
|
|
|
<uni-icons type="home" size="20" color="#999"></uni-icons>
|
|
|
|
|
|
<picker
|
|
|
|
|
|
mode="selector"
|
|
|
|
|
|
:range="companyList"
|
|
|
|
|
|
range-key="name"
|
|
|
|
|
|
:value="selectedCompanyIndex"
|
|
|
|
|
|
@change="onCompanyChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-input">
|
|
|
|
|
|
<text class="picker-text" :class="{ placeholder: !selectedCompany }">
|
|
|
|
|
|
{{ selectedCompany ? selectedCompany.name : '请选择公司' }}
|
|
|
|
|
|
</text>
|
|
|
|
|
|
<uni-icons type="arrowdown" size="14" color="#999"></uni-icons>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 飞书内环境:自动登录 -->
|
|
|
|
|
|
<view v-if="isInFeishu && selectedCompany" class="feishu-auto-login">
|
|
|
|
|
|
<view class="feishu-loading">
|
|
|
|
|
|
<uni-icons type="spinner-cycle" size="40" color="#2E6CF6"></uni-icons>
|
|
|
|
|
|
<text class="loading-text">正在跳转飞书授权...</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 非飞书环境:显示二维码 -->
|
|
|
|
|
|
<view v-else-if="!isInFeishu && selectedCompany" class="feishu-qrcode-section">
|
|
|
|
|
|
<view class="qrcode-container" id="feishu_qrcode_container">
|
|
|
|
|
|
<view v-if="sdkLoadFailed" class="sdk-error">
|
|
|
|
|
|
<text class="error-text">二维码加载失败</text>
|
|
|
|
|
|
<view class="retry-btn" @tap="reloadFeishuSDK">
|
|
|
|
|
|
<text>点击重试</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<text class="qrcode-tip">请使用飞书App扫码登录</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 未选择公司 -->
|
|
|
|
|
|
<view v-else class="feishu-content">
|
|
|
|
|
|
<text class="feishu-desc">请先选择公司</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部提示 -->
|
|
|
|
|
|
<!-- <view class="footer-tip">
|
|
|
|
|
|
<text class="tip-text">登录即表示同意</text>
|
|
|
|
|
|
<text class="link-text">《用户协议》</text>
|
|
|
|
|
|
<text class="tip-text">和</text>
|
|
|
|
|
|
<text class="link-text">《隐私政策》</text>
|
|
|
|
|
|
</view> -->
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { request } from '@/api/apiT.js'
|
|
|
|
|
|
import { saveRoles } from '@/common/role.js'
|
|
|
|
|
|
import { getVisibleTabBar } from '@/common/tabbar.js'
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
loginType: 'password', // password | feishu
|
|
|
|
|
|
isLoading: false,
|
|
|
|
|
|
showPassword: false,
|
|
|
|
|
|
rememberMe: false,
|
|
|
|
|
|
fsappid: '',
|
|
|
|
|
|
// 公司相关
|
|
|
|
|
|
companyList: [],
|
|
|
|
|
|
selectedCompany: null,
|
|
|
|
|
|
selectedCompanyIndex: -1,
|
|
|
|
|
|
feishuConfig: null,
|
|
|
|
|
|
// 是否在飞书内环境
|
|
|
|
|
|
isInFeishu: false,
|
|
|
|
|
|
// SDK加载状态
|
|
|
|
|
|
sdkLoadFailed: false,
|
|
|
|
|
|
formData: {
|
|
|
|
|
|
account: '',
|
|
|
|
|
|
password: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onLoad(options) {
|
|
|
|
|
|
// 检测是否在飞书内环境
|
|
|
|
|
|
this.isInFeishu = /Lark|Feishu/i.test(navigator.userAgent || '')
|
|
|
|
|
|
|
|
|
|
|
|
// 获取飞书 appid
|
|
|
|
|
|
this.fsappid = options.appid || '';
|
|
|
|
|
|
uni.setStorageSync('fsappid', this.fsappid);
|
|
|
|
|
|
|
|
|
|
|
|
// 保存登录成功后的回跳地址
|
|
|
|
|
|
const redirect = options.redirect || options.r || ''
|
|
|
|
|
|
if (redirect) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
uni.setStorageSync('post_login_redirect', decodeURIComponent(redirect))
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
uni.setStorageSync('post_login_redirect', redirect)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载记住的密码
|
|
|
|
|
|
this.loadRememberedPassword();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取公司列表
|
|
|
|
|
|
this.getCompanyList();
|
|
|
|
|
|
|
|
|
|
|
|
// 检查URL参数中的公司ID
|
|
|
|
|
|
const companyId = options.corp_id
|
|
|
|
|
|
if (companyId) {
|
|
|
|
|
|
this.selectCompanyById(Number(companyId))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
// 检查SDK初始状态(延迟1秒后检查)
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
console.log('[飞书登录] 页面加载后SDK状态检查:', {
|
|
|
|
|
|
typeofQRLogin: typeof window.QRLogin,
|
|
|
|
|
|
typeofQRLoginGlobal: typeof QRLogin,
|
|
|
|
|
|
hasWindow: typeof window !== 'undefined',
|
|
|
|
|
|
windowKeys: Object.keys(window).filter(k => k.includes('QR') || k.includes('Lark'))
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 检查脚本标签是否存在
|
|
|
|
|
|
const scripts = document.querySelectorAll('script')
|
|
|
|
|
|
const feishuScript = Array.from(scripts).find(s => s.src && s.src.includes('feishu'))
|
|
|
|
|
|
console.log('[飞书登录] 飞书SDK脚本标签:', {
|
|
|
|
|
|
found: !!feishuScript,
|
|
|
|
|
|
src: feishuScript?.src,
|
|
|
|
|
|
loaded: feishuScript?.onload ? 'has onload' : 'no onload',
|
|
|
|
|
|
error: feishuScript?.onerror ? 'has onerror' : 'no onerror',
|
|
|
|
|
|
readyState: feishuScript?.readyState
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 如果SDK没加载,尝试动态加载
|
|
|
|
|
|
if (typeof window.QRLogin === 'undefined') {
|
|
|
|
|
|
console.log('[飞书登录] SDK未加载,尝试动态加载...')
|
|
|
|
|
|
this.loadFeishuSDKScript()
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 切换登录方式
|
|
|
|
|
|
switchLoginType(type) {
|
|
|
|
|
|
this.loginType = type
|
|
|
|
|
|
// 切换时清空二维码容器
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
const container = document.getElementById('feishu_qrcode_container')
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
container.innerHTML = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 切换密码显示
|
|
|
|
|
|
togglePassword() {
|
|
|
|
|
|
this.showPassword = !this.showPassword
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 切换记住密码
|
|
|
|
|
|
toggleRemember() {
|
|
|
|
|
|
this.rememberMe = !this.rememberMe
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 加载记住的密码
|
|
|
|
|
|
loadRememberedPassword() {
|
|
|
|
|
|
const remembered = uni.getStorageSync('remembered_password')
|
|
|
|
|
|
if (remembered) {
|
|
|
|
|
|
this.formData.account = remembered.account || ''
|
|
|
|
|
|
this.formData.password = remembered.password || ''
|
|
|
|
|
|
this.rememberMe = true
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 保存记住的密码
|
|
|
|
|
|
saveRememberedPassword() {
|
|
|
|
|
|
if (this.rememberMe) {
|
|
|
|
|
|
uni.setStorageSync('remembered_password', {
|
|
|
|
|
|
account: this.formData.account,
|
|
|
|
|
|
password: this.formData.password
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.removeStorageSync('remembered_password')
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 验证表单
|
|
|
|
|
|
validateForm() {
|
|
|
|
|
|
if (!this.formData.account) {
|
|
|
|
|
|
uni.showToast({ title: '请输入账号/手机号', icon: 'none' })
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!this.formData.password) {
|
|
|
|
|
|
uni.showToast({ title: '请输入密码', icon: 'none' })
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.formData.password.length < 6) {
|
|
|
|
|
|
uni.showToast({ title: '密码长度不能少于6位', icon: 'none' })
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 账号密码登录
|
|
|
|
|
|
async handlePasswordLogin() {
|
|
|
|
|
|
if (!this.validateForm()) return
|
|
|
|
|
|
if (this.isLoading) return
|
|
|
|
|
|
|
|
|
|
|
|
this.isLoading = true
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await request({
|
|
|
|
|
|
url: 'common/auth/login',
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
loginType: 'upwd', // 账号密码登录
|
|
|
|
|
|
data: {
|
|
|
|
|
|
account: this.formData.account,
|
|
|
|
|
|
password: this.formData.password
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if (res.data.code === 200) {
|
|
|
|
|
|
const data = res.data.data
|
|
|
|
|
|
|
|
|
|
|
|
// 保存登录类型
|
|
|
|
|
|
uni.setStorageSync('loginType', 'upwd')
|
|
|
|
|
|
|
|
|
|
|
|
// 统一使用 union_id 作为 token(与PC端保持一致)
|
|
|
|
|
|
const token = data.union_id || data.token
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
uni.setStorageSync('token', token)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理用户信息
|
|
|
|
|
|
const userInfo = {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
token: token
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.setStorageSync('userInfo', userInfo)
|
|
|
|
|
|
|
|
|
|
|
|
// 处理角色信息(统一使用 role.js 工具)
|
|
|
|
|
|
saveRoles(data.role, data.role_wp)
|
|
|
|
|
|
|
2026-03-12 16:47:27 +08:00
|
|
|
|
// 通知自定义 TabBar 刷新
|
|
|
|
|
|
uni.$emit && uni.$emit('userRoleChanged')
|
|
|
|
|
|
|
2026-03-11 11:15:33 +08:00
|
|
|
|
// 保存记住的密码
|
|
|
|
|
|
this.saveRememberedPassword()
|
|
|
|
|
|
|
|
|
|
|
|
uni.showToast({ title: '登录成功', icon: 'success' })
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.goToRedirect()
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({ title: res.data.message || '登录失败', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('[password login] error:', err)
|
|
|
|
|
|
uni.showToast({ title: err.message || '登录失败,请稍后重试', icon: 'none' })
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
this.isLoading = false
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 公司相关方法 ==========
|
|
|
|
|
|
// 获取公司列表
|
|
|
|
|
|
async getCompanyList() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await request({
|
|
|
|
|
|
url: 'common/preset/corps',
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
if (res.data.code === 200) {
|
|
|
|
|
|
this.companyList = res.data.data || []
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('[getCompanyList] error:', err)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 公司选择变更
|
|
|
|
|
|
onCompanyChange(e) {
|
|
|
|
|
|
const index = e.detail.value
|
|
|
|
|
|
this.selectedCompanyIndex = index
|
|
|
|
|
|
this.selectedCompany = this.companyList[index]
|
|
|
|
|
|
|
|
|
|
|
|
if (this.selectedCompany) {
|
|
|
|
|
|
// 保存公司信息
|
|
|
|
|
|
uni.setStorageSync('companyId', this.selectedCompany.id)
|
|
|
|
|
|
uni.setStorageSync('companyAbbr', this.selectedCompany.abbr || '')
|
|
|
|
|
|
|
|
|
|
|
|
// 构建飞书配置
|
|
|
|
|
|
this.feishuConfig = {
|
|
|
|
|
|
...this.selectedCompany,
|
|
|
|
|
|
app_id: this.selectedCompany.app_id,
|
|
|
|
|
|
r_url: this.selectedCompany.m_url,
|
|
|
|
|
|
state: this.selectedCompany.state || 'xinyouhe'
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.setStorageSync('fsappid', this.selectedCompany.app_id);
|
|
|
|
|
|
// 保存 app_id 供回调页面使用
|
|
|
|
|
|
if (this.feishuConfig.app_id) {
|
|
|
|
|
|
uni.setStorageSync('fsappid', this.feishuConfig.app_id)
|
|
|
|
|
|
this.fsappid = this.feishuConfig.app_id
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化飞书登录
|
|
|
|
|
|
this.initFeishuLogin()
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 通过ID选择公司
|
|
|
|
|
|
selectCompanyById(companyId) {
|
|
|
|
|
|
const index = this.companyList.findIndex(c => c.id === companyId)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
this.onCompanyChange({ detail: { value: index } })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化飞书登录
|
|
|
|
|
|
async initFeishuLogin() {
|
|
|
|
|
|
if (!this.selectedCompany || !this.feishuConfig) return
|
|
|
|
|
|
|
|
|
|
|
|
if (this.isInFeishu) {
|
|
|
|
|
|
// 飞书内环境,自动跳转授权
|
|
|
|
|
|
await this.handleFeishuLogin()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 普通浏览器环境,显示二维码
|
|
|
|
|
|
await this.loadFeishuQRCode()
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 加载飞书二维码
|
|
|
|
|
|
async loadFeishuQRCode() {
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
console.log('[飞书登录] 开始加载二维码')
|
|
|
|
|
|
this.sdkLoadFailed = false
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 等待SDK加载完成(已在index.html中预加载)
|
|
|
|
|
|
await this.waitForFeishuSDK()
|
|
|
|
|
|
console.log('[飞书登录] SDK加载完成')
|
|
|
|
|
|
|
|
|
|
|
|
await this.$nextTick()
|
|
|
|
|
|
|
|
|
|
|
|
const container = document.getElementById('feishu_qrcode_container')
|
|
|
|
|
|
console.log('[飞书登录] 容器:', container)
|
|
|
|
|
|
if (!container) {
|
|
|
|
|
|
uni.showToast({ title: '二维码容器未找到', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = ''
|
|
|
|
|
|
|
|
|
|
|
|
const { app_id, r_url, state } = this.feishuConfig
|
|
|
|
|
|
console.log('[飞书登录] 飞书配置:', { app_id, r_url, state })
|
|
|
|
|
|
|
|
|
|
|
|
if (!app_id || !r_url || !state) {
|
|
|
|
|
|
uni.showToast({ title: '飞书配置不完整', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// URL编码
|
|
|
|
|
|
const encodedRedirectUri = encodeURIComponent(r_url)
|
|
|
|
|
|
|
|
|
|
|
|
const gotoUrl = `https://passport.feishu.cn/suite/passport/oauth/authorize?client_id=${app_id}&redirect_uri=${encodedRedirectUri}&response_type=code&state=${state}`
|
|
|
|
|
|
|
|
|
|
|
|
// 检查SDK是否加载
|
|
|
|
|
|
if (typeof window.QRLogin === 'undefined') {
|
|
|
|
|
|
console.error('[飞书登录] QRLogin 未定义')
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
uni.showToast({ title: '飞书SDK未加载,请点击重试', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('[飞书登录] 开始生成二维码, gotoUrl:', gotoUrl)
|
|
|
|
|
|
|
|
|
|
|
|
// 生成二维码(使用 window.QRLogin)
|
|
|
|
|
|
const QRLoginObj = window.QRLogin({
|
|
|
|
|
|
id: 'feishu_qrcode_container',
|
|
|
|
|
|
goto: gotoUrl,
|
|
|
|
|
|
width: '200',
|
|
|
|
|
|
height: '200',
|
|
|
|
|
|
style: 'width:270px;height:270px;border:none'
|
|
|
|
|
|
})
|
|
|
|
|
|
console.log('[飞书登录] 二维码生成成功:', QRLoginObj)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听扫码消息
|
|
|
|
|
|
const handleMessage = (event) => {
|
|
|
|
|
|
console.log('[飞书登录] 收到消息:', event)
|
|
|
|
|
|
if (
|
|
|
|
|
|
QRLoginObj.matchOrigin &&
|
|
|
|
|
|
QRLoginObj.matchData &&
|
|
|
|
|
|
QRLoginObj.matchOrigin(event.origin) &&
|
|
|
|
|
|
QRLoginObj.matchData(event.data)
|
|
|
|
|
|
) {
|
|
|
|
|
|
const loginTmpCode = event.data.tmp_code
|
|
|
|
|
|
console.log('[飞书登录] 扫码成功,跳转授权')
|
|
|
|
|
|
window.location.href = `${gotoUrl}&tmp_code=${loginTmpCode}`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener('message', handleMessage, false)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[飞书登录] 加载二维码失败:', error)
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
uni.showToast({ title: error.message || '二维码加载失败,请重试', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 重新加载飞书SDK
|
|
|
|
|
|
reloadFeishuSDK() {
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
console.log('[飞书登录] 手动重新加载SDK')
|
|
|
|
|
|
this.sdkLoadFailed = false
|
|
|
|
|
|
this.loadFeishuSDKScript()
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 动态加载飞书SDK脚本
|
|
|
|
|
|
loadFeishuSDKScript() {
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
// 检查是否已经加载过
|
|
|
|
|
|
if (typeof window.QRLogin === 'function') {
|
|
|
|
|
|
console.log('[飞书登录] SDK已加载,无需重复加载')
|
|
|
|
|
|
if (this.selectedCompany && !this.isInFeishu) {
|
|
|
|
|
|
this.loadFeishuQRCode()
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已有正在加载的脚本
|
|
|
|
|
|
const existingScript = document.querySelector('script[data-feishu-sdk]')
|
|
|
|
|
|
if (existingScript) {
|
|
|
|
|
|
console.log('[飞书登录] SDK脚本已在加载中')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('[飞书登录] 开始动态加载SDK脚本...')
|
|
|
|
|
|
const script = document.createElement('script')
|
|
|
|
|
|
script.setAttribute('data-feishu-sdk', 'true')
|
|
|
|
|
|
script.src = 'https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js'
|
|
|
|
|
|
script.crossOrigin = 'anonymous'
|
|
|
|
|
|
|
|
|
|
|
|
script.onload = () => {
|
|
|
|
|
|
console.log('[飞书登录] ✅ SDK脚本加载成功')
|
|
|
|
|
|
console.log('[飞书登录] QRLogin类型:', typeof window.QRLogin)
|
|
|
|
|
|
if (typeof window.QRLogin === 'function') {
|
|
|
|
|
|
console.log('[飞书登录] SDK已准备就绪')
|
|
|
|
|
|
// 如果已选择公司且在非飞书环境,加载二维码
|
|
|
|
|
|
if (this.selectedCompany && !this.isInFeishu) {
|
|
|
|
|
|
this.loadFeishuQRCode()
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.error('[飞书登录] ⚠️ 脚本加载成功但QRLogin未定义')
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
script.onerror = (event) => {
|
|
|
|
|
|
console.error('[飞书登录] ❌ SDK脚本加载失败:', event)
|
|
|
|
|
|
console.error('[飞书登录] 脚本URL:', script.src)
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
uni.showToast({ title: 'SDK加载失败,请检查网络', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
script.onabort = () => {
|
|
|
|
|
|
console.error('[飞书登录] ❌ SDK脚本加载被中断')
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到head而不是body
|
|
|
|
|
|
document.head.appendChild(script)
|
|
|
|
|
|
console.log('[飞书登录] SDK脚本标签已添加到head')
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 等待飞书SDK加载完成(带超时)
|
|
|
|
|
|
async waitForFeishuSDK() {
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
const startTime = Date.now()
|
|
|
|
|
|
const timeoutMs = 15000 // 15秒超时
|
|
|
|
|
|
|
|
|
|
|
|
const timeout = setTimeout(() => {
|
|
|
|
|
|
const elapsed = Date.now() - startTime
|
|
|
|
|
|
console.error('[飞书登录] SDK加载超时,等待时间:', elapsed, 'ms')
|
|
|
|
|
|
console.log('[飞书登录] 当前window上的属性:', Object.keys(window).filter(k => k.includes('QR') || k.includes('qr') || k.includes('Lark')))
|
|
|
|
|
|
console.log('[飞书登录] window.QRLogin类型:', typeof window.QRLogin)
|
|
|
|
|
|
console.log('[飞书登录] QRLogin类型:', typeof QRLogin)
|
|
|
|
|
|
// 检查是否有网络错误
|
|
|
|
|
|
if (typeof window.QRLogin === 'undefined') {
|
|
|
|
|
|
console.error('[飞书登录] 请检查网络连接或是否被浏览器扩展阻止')
|
|
|
|
|
|
}
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
uni.showToast({ title: '飞书SDK加载超时,请点击重试', icon: 'none' })
|
|
|
|
|
|
reject(new Error('飞书SDK加载超时,请刷新页面重试'))
|
|
|
|
|
|
}, timeoutMs)
|
|
|
|
|
|
|
|
|
|
|
|
let count = 0
|
|
|
|
|
|
const checkInterval = 200 // 每200ms检查一次
|
|
|
|
|
|
const maxCount = Math.ceil(timeoutMs / checkInterval)
|
|
|
|
|
|
|
|
|
|
|
|
const check = () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
count++
|
|
|
|
|
|
const elapsed = Date.now() - startTime
|
|
|
|
|
|
|
|
|
|
|
|
// 每1秒打印一次详细日志
|
|
|
|
|
|
if (count % 5 === 0) {
|
|
|
|
|
|
console.log(`[飞书登录] SDK检测 ${count}/${maxCount}, 已等待: ${elapsed}ms, window.QRLogin: ${typeof window.QRLogin}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查全局对象 window.QRLogin
|
|
|
|
|
|
if (typeof window.QRLogin === 'function') {
|
|
|
|
|
|
clearTimeout(timeout)
|
|
|
|
|
|
console.log('[飞书登录] SDK加载成功,总耗时:', elapsed, 'ms')
|
|
|
|
|
|
resolve(true)
|
|
|
|
|
|
} else if (elapsed >= timeoutMs) {
|
|
|
|
|
|
clearTimeout(timeout)
|
|
|
|
|
|
reject(new Error('SDK加载超时'))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setTimeout(check, checkInterval)
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('[飞书登录] 检查过程出错:', err)
|
|
|
|
|
|
clearTimeout(timeout)
|
|
|
|
|
|
this.sdkLoadFailed = true
|
|
|
|
|
|
reject(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 立即开始检查
|
|
|
|
|
|
check()
|
|
|
|
|
|
})
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 飞书登录(飞书内环境)
|
|
|
|
|
|
async handleFeishuLogin() {
|
|
|
|
|
|
if (!this.feishuConfig) {
|
|
|
|
|
|
uni.showToast({ title: '请先选择公司', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log('[飞书内登录] 请求参数:', {
|
|
|
|
|
|
app_id: this.feishuConfig.app_id,
|
|
|
|
|
|
config: this.feishuConfig
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const res = await request({
|
|
|
|
|
|
url: 'common/auth/feishu/scope',
|
|
|
|
|
|
method: 'get',
|
|
|
|
|
|
loginType: 'feishu',
|
|
|
|
|
|
data: {
|
|
|
|
|
|
app_id: this.feishuConfig.app_id,
|
|
|
|
|
|
is_pc:0
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
console.log('[飞书内登录] 接口返回:', res)
|
|
|
|
|
|
|
|
|
|
|
|
const auth_url = res?.data?.data?.auth_url
|
|
|
|
|
|
if (!auth_url) {
|
|
|
|
|
|
console.error('[飞书内登录] 返回数据结构:', res)
|
|
|
|
|
|
throw new Error('未获取到授权地址')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// H5 环境跳转飞书授权
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
window.location.replace(auth_url)
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('[feishu login] error:', err)
|
|
|
|
|
|
uni.showToast({ title: err?.message || '跳转失败,请稍后重试', icon: 'none' })
|
|
|
|
|
|
this.isLoading = false
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 忘记密码
|
|
|
|
|
|
goToForgetPwd() {
|
|
|
|
|
|
uni.navigateTo({ url: '/pages/index/forget-password' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到目标页面(根据角色TabBar显示规则)
|
|
|
|
|
|
goToRedirect() {
|
|
|
|
|
|
// 获取用户可见的TabBar列表
|
|
|
|
|
|
const visibleTabs = getVisibleTabBar()
|
|
|
|
|
|
// 检查是否包含首页Tab
|
|
|
|
|
|
const hasIndexTab = visibleTabs.some(tab => tab.pagePath === 'pages/index/index')
|
|
|
|
|
|
// 默认跳转目标:有首页进入首页,否则进入我的页面
|
|
|
|
|
|
const defaultTarget = hasIndexTab ? '/pages/index/index' : '/pages/index/mine'
|
|
|
|
|
|
// 优先使用存储的跳转地址
|
|
|
|
|
|
const target = uni.getStorageSync('post_login_redirect') || defaultTarget
|
|
|
|
|
|
uni.removeStorageSync('post_login_redirect')
|
|
|
|
|
|
uni.reLaunch({ url: target })
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.login-page {
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
background: linear-gradient(180deg, #FF972F 0%, #FF8A2C 25%, #FFF4E8 50%, #F4F6F8 100%);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 装饰背景 */
|
|
|
|
|
|
.bg-decoration {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
height: 50vh;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.circle {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.15);
|
|
|
|
|
|
animation: float 6s ease-in-out infinite;
|
|
|
|
|
|
|
|
|
|
|
|
&.circle-1 {
|
|
|
|
|
|
width: 400rpx;
|
|
|
|
|
|
height: 400rpx;
|
|
|
|
|
|
top: -150rpx;
|
|
|
|
|
|
left: -100rpx;
|
|
|
|
|
|
animation-delay: 0s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.circle-2 {
|
|
|
|
|
|
width: 300rpx;
|
|
|
|
|
|
height: 300rpx;
|
|
|
|
|
|
top: -80rpx;
|
|
|
|
|
|
right: -80rpx;
|
|
|
|
|
|
animation-delay: 1s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.circle-3 {
|
|
|
|
|
|
width: 200rpx;
|
|
|
|
|
|
height: 200rpx;
|
|
|
|
|
|
top: 100rpx;
|
|
|
|
|
|
right: 100rpx;
|
|
|
|
|
|
animation-delay: 2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes float {
|
|
|
|
|
|
0%, 100% {
|
|
|
|
|
|
transform: translateY(0) scale(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
50% {
|
|
|
|
|
|
transform: translateY(-20rpx) scale(1.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 主容器 */
|
|
|
|
|
|
.login-container {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
padding: 40rpx 32rpx;
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 头部区域 */
|
|
|
|
|
|
.header-section {
|
|
|
|
|
|
padding-top: 80rpx;
|
|
|
|
|
|
padding-bottom: 40rpx;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
|
|
|
|
|
|
.logo-wrapper {
|
|
|
|
|
|
width: 140rpx;
|
|
|
|
|
|
height: 140rpx;
|
|
|
|
|
|
margin: 0 auto 24rpx;
|
|
|
|
|
|
// background: rgba(255, 255, 255, 0.95);
|
|
|
|
|
|
border-radius: 32rpx;
|
|
|
|
|
|
box-shadow: 0 8rpx 32rpx rgba(255, 151, 47, 0.25);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.logo {
|
|
|
|
|
|
width: 100rpx;
|
|
|
|
|
|
height: 100rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.app-name {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: #1f2937;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.app-desc {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 登录卡片 */
|
|
|
|
|
|
.login-card {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.95);
|
|
|
|
|
|
border-radius: 32rpx;
|
|
|
|
|
|
padding: 40rpx 32rpx;
|
|
|
|
|
|
box-shadow: 0 16rpx 48rpx rgba(255, 151, 47, 0.12);
|
|
|
|
|
|
backdrop-filter: blur(20px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Tab 切换 */
|
|
|
|
|
|
.tab-bar {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
// background: #e5e7eb;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tab-item {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 20rpx 0;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
.tab-text {
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tab-line {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
|
height: 6rpx;
|
|
|
|
|
|
background: #FF972F;
|
|
|
|
|
|
border-radius: 3rpx;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.active .tab-text {
|
|
|
|
|
|
color: #FF972F;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表单区域 */
|
|
|
|
|
|
.form-section {
|
|
|
|
|
|
.input-group {
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.input-wrapper {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 24rpx 28rpx;
|
|
|
|
|
|
background: #F8F9FB;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
border: 2rpx solid transparent;
|
|
|
|
|
|
transition: all 0.3s;
|
2026-03-12 16:47:27 +08:00
|
|
|
|
|
2026-03-11 11:15:33 +08:00
|
|
|
|
.input-field {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
margin: 0 16rpx;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #1f2937;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
background: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.input-placeholder {
|
|
|
|
|
|
color: #9CA3AF;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-options {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.remember-me {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.checkbox {
|
|
|
|
|
|
width: 36rpx;
|
|
|
|
|
|
height: 36rpx;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
border: 2rpx solid #d1d5db;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin-right: 12rpx;
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
|
|
|
|
|
|
&.checked {
|
|
|
|
|
|
background: #FF972F;
|
|
|
|
|
|
border-color: #FF972F;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.option-text {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.forget-pwd {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #FF972F;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 飞书登录区域 */
|
|
|
|
|
|
.feishu-section {
|
|
|
|
|
|
padding: 20rpx 0;
|
|
|
|
|
|
|
|
|
|
|
|
.feishu-content {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 40rpx 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.feishu-icon-wrapper {
|
|
|
|
|
|
width: 120rpx;
|
|
|
|
|
|
height: 120rpx;
|
|
|
|
|
|
margin: 0 auto 24rpx;
|
|
|
|
|
|
background: linear-gradient(135deg, #FF972F 0%, #FF8A2C 100%);
|
|
|
|
|
|
border-radius: 28rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
box-shadow: 0 12rpx 32rpx rgba(255, 151, 47, 0.3);
|
|
|
|
|
|
|
|
|
|
|
|
.feishu-logo {
|
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.feishu-title {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #1f2937;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.feishu-desc {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 登录按钮 */
|
|
|
|
|
|
.login-btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
|
background: linear-gradient(135deg, #FF972F 0%, #FF8A2C 100%);
|
|
|
|
|
|
border-radius: 24rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 12rpx;
|
|
|
|
|
|
box-shadow: 0 12rpx 32rpx rgba(255, 151, 47, 0.35);
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
transform: scale(0.98);
|
|
|
|
|
|
box-shadow: 0 8rpx 24rpx rgba(255, 151, 47, 0.25);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.loading {
|
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// &.feishu-btn {
|
|
|
|
|
|
// background: linear-gradient(135deg, #3370FF 0%, #2956CC 100%);
|
|
|
|
|
|
// box-shadow: 0 12rpx 32rpx rgba(51, 112, 255, 0.35);
|
|
|
|
|
|
|
|
|
|
|
|
// &:active {
|
|
|
|
|
|
// box-shadow: 0 8rpx 24rpx rgba(51, 112, 255, 0.25);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
.btn-text {
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 底部提示 */
|
|
|
|
|
|
.footer-tip {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding-top: 32rpx;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.tip-text {
|
|
|
|
|
|
color: #9CA3AF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.link-text {
|
|
|
|
|
|
color: #FF972F;
|
|
|
|
|
|
margin: 0 4rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 飞书登录新增样式 */
|
|
|
|
|
|
/* 公司选择下拉框 */
|
|
|
|
|
|
.picker-input {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
min-height: 88rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.picker-text {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
|
|
|
|
|
|
&.placeholder {
|
|
|
|
|
|
color: #9CA3AF;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 飞书内环境自动登录 */
|
|
|
|
|
|
.feishu-auto-login {
|
|
|
|
|
|
padding: 60rpx 40rpx;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
|
|
|
|
|
|
.feishu-loading {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 24rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.loading-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #2E6CF6;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 飞书二维码区域 */
|
|
|
|
|
|
.feishu-qrcode-section{
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|