231 lines
5.2 KiB
Vue
Raw Normal View History

2025-10-15 16:03:42 +08:00
<script lang="ts" setup>
2025-10-31 11:29:01 +08:00
import { getUserInfo, loginAPI } from '@/api/login'
2025-10-15 16:03:42 +08:00
import { useAppStore } from '@/store'
2026-01-28 15:55:55 +08:00
import { getImageFullPath } from '@/utils'
2025-10-15 16:03:42 +08:00
import CacheManager from '@/utils/CacheManager'
2026-02-26 09:39:10 +08:00
const { VITE_APP_TITLE } = import.meta.env
2025-10-15 16:03:42 +08:00
definePage({
// 使用 type: "home" 属性设置首页其他页面不需要设置默认为page
type: 'home',
style: {
navigationStyle: 'custom',
},
})
const appStore = useAppStore()
// 获取标题名称
const TITLE_NAME = import.meta.env.VITE_APP_TITLE
// 显示密码
const showMm = ref(false)
// 登录表单数据
const formData = reactive({
2025-12-19 17:18:47 +08:00
username: '',
password: '',
2025-10-15 16:03:42 +08:00
})
2026-01-28 15:55:55 +08:00
const formRef = ref<any>(null)
2025-10-15 16:03:42 +08:00
// 是否在登录
const isLogin = ref(false)
const notifyRef = ref<any>(null)
2026-01-28 15:55:55 +08:00
const rules = {
username: [
{
required: true,
message: '请输入用户名',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur',
},
],
}
const labelStyles = computed(() => {
return {
fontFamily: 'PingFangSC-Medium',
fontSize: '34rpx',
color: '#000000',
fontWeight: 500,
}
})
const InputPlaceholderStyle = computed(() => {
return {
fontFamily: 'PingFangSC-Medium',
fontSize: '28rpx',
color: '#999999',
fontWeight: 400,
}
})
const inputCustomStyle = computed(() => {
return {
backgroundColor: '#F5F8FF',
}
})
2025-10-15 16:03:42 +08:00
/**
* 登录
*/
async function login() {
2026-01-28 15:55:55 +08:00
const status = await formRef.value.validate()
if (!status) {
2025-12-19 17:18:47 +08:00
return
}
2026-01-28 15:55:55 +08:00
2025-10-15 16:03:42 +08:00
isLogin.value = true
2026-01-14 17:31:26 +08:00
uni.showLoading({
title: '登录中...',
mask: true,
})
2025-10-15 16:03:42 +08:00
try {
const token = await loginAPI(formData)
CacheManager.set('token', token)
isLogin.value = false
2025-10-31 11:29:01 +08:00
const userInfo = await getUserInfo()
appStore.setUserInfo(userInfo) // 获取字典数据
2025-10-15 16:03:42 +08:00
appStore.setDictData() // 获取字典数据
2026-01-14 17:31:26 +08:00
setTimeout(() => {
2026-01-28 15:55:55 +08:00
uni.hideLoading()
2026-01-14 17:31:26 +08:00
appStore.loginJump()
}, 800)
2025-10-15 16:03:42 +08:00
}
catch (e) {
isLogin.value = false
2026-01-14 17:31:26 +08:00
uni.hideLoading()
2025-10-15 16:03:42 +08:00
notifyRef.value?.show({ safeAreaInsetTop: true, type: 'error', message: (e as Error).message || '登录失败,请稍后再试' })
}
}
2026-02-26 09:39:10 +08:00
onShareAppMessage(() => {
return {
title: `欢迎使用${VITE_APP_TITLE}`,
path: '/pages/login/login',
}
})
2025-10-15 16:03:42 +08:00
</script>
<template>
2026-01-28 15:55:55 +08:00
<view class="container">
<!-- logo -->
<view class="img_container">
<uv-image :src="getImageFullPath('DENGLU_LOGO_IMAGE')" mode="widthFix" width="100%" />
</view>
<!-- 登录语 -->
<view class="login_text">
<view class="">
2025-10-15 16:03:42 +08:00
您好
</view>
2026-01-28 15:55:55 +08:00
<view>欢迎使用{{ TITLE_NAME }}</view>
2025-10-15 16:03:42 +08:00
</view>
2026-01-28 15:55:55 +08:00
<!-- 登录表单 -->
<view class="login_form">
<uv-form
ref="formRef"
label-position="top"
:model="formData"
label-width="150"
:label-style="labelStyles"
:rules="rules"
>
<uv-form-item label="账号" prop="username">
<uv-input
v-model="formData.username"
placeholder="请输入账号"
:placeholder-style="InputPlaceholderStyle"
clearable
:custom-style="inputCustomStyle"
border="none"
/>
</uv-form-item>
<uv-form-item label="密码" prop="password">
<uv-input
v-model="formData.password"
placeholder="请输入密码"
:password="!showMm"
:placeholder-style="InputPlaceholderStyle"
:custom-style="inputCustomStyle"
border="none"
>
<template #suffix>
<uv-icon name="eye" size="20" :color="showMm ? '#36acf6' : '#CCCCCC'" @click="showMm = !showMm" />
</template>
</uv-input>
</uv-form-item>
</uv-form>
<!-- 登录按钮 -->
<view class="btn_bar">
<uv-button
type="primary"
text="登录"
loading-text="正在登录中..."
:loading="isLogin"
:custom-style="{
backgroundImage: `linear-gradient(135deg, #1089FF 0%, #0F5BFF 100%)`,
borderRadius: '50rpx',
height: '100rpx',
width: '100%',
}"
:custom-text-style="{
fontSize: '34rpx',
fontFamily: 'PingFangSC-Medium',
}"
@click="login"
/>
2025-10-15 16:03:42 +08:00
</view>
</view>
2026-01-28 15:55:55 +08:00
2025-10-15 16:03:42 +08:00
<uv-notify ref="notifyRef" />
</view>
</template>
<style lang="scss" scoped>
2026-01-28 15:55:55 +08:00
.container {
2025-10-15 16:03:42 +08:00
width: 100%;
2026-01-28 15:55:55 +08:00
.img_container {
position: fixed;
top: 0;
2025-10-15 16:03:42 +08:00
width: 100%;
2026-01-28 15:55:55 +08:00
z-index: -1;
2025-10-15 16:03:42 +08:00
}
2026-01-28 15:55:55 +08:00
.login_text {
position: fixed;
left: 40rpx;
top: 210rpx;
font-family: PingFangSC-Medium;
font-size: 36rpx;
color: #ffffff;
letter-spacing: 0;
line-height: 70rpx;
text-shadow: 0 2px 8px #708eae;
font-weight: 500;
}
2025-10-15 16:03:42 +08:00
2026-01-28 15:55:55 +08:00
.login_form {
position: fixed;
padding: 80rpx 60rpx 0 60rpx;
width: calc(100% - 120rpx);
z-index: 2;
left: 0;
bottom: 0;
top: 448rpx;
background-color: white;
border-radius: 48rpx 48rpx 0 0;
2025-10-15 16:03:42 +08:00
.btn_bar {
2026-01-28 15:55:55 +08:00
position: relative;
transform: translateY(100rpx);
2025-10-15 16:03:42 +08:00
}
}
}
2026-01-28 15:55:55 +08:00
::v-deep .uv-input__content {
padding: 0 25rpx;
height: 80rpx !important;
2025-10-15 16:03:42 +08:00
}
</style>