index.vue 7.79 KB
<template>
  <view class="login-page">
    <!-- 纯CSS渐变动效背景(替代粒子动画,兼容所有版本) -->
    <view class="bg-animation"></view>

    <!-- 登录表单区域(悬浮层) -->
    <view class="login-form">
      <!-- 登录标题(简约大气) -->
      <view class="login-title">园林登录</view>

      <!-- 账号输入框 -->
      <view class="form-item">
        <up-input
            v-model="form.account"
            placeholder="请输入登录账号"
            border="surround"
            clearable
            input-align="left"
            :disabled="isLoading"
            @blur="checkAccount"
            :custom-style="{
            backgroundColor: 'rgba(255, 255, 255, 0.9)',
            borderColor: '#e5e7eb'
          }"
        >
          <template #prefix>
            <up-icon name="account" color="#6b7280" size="20"></up-icon>
          </template>
        </up-input>
        <!-- 账号错误提示 -->
        <view class="error-tip" v-if="error.account">{{ error.account }}</view>
      </view>

      <!-- 密码输入框(移除查看密码功能) -->
      <view class="form-item">
        <up-input
            v-model="form.password"
            placeholder="请输入登录密码"
            border="surround"
            clearable
            input-align="left"
            type="password"
            :disabled="isLoading"
            @blur="checkPassword"
            :custom-style="{
            backgroundColor: 'rgba(255, 255, 255, 0.9)',
            borderColor: '#e5e7eb'
          }"
        >
          <template #prefix>
            <up-icon name="lock" color="#6b7280" size="20"></up-icon>
          </template>
        </up-input>
        <!-- 密码错误提示 -->
        <view class="error-tip" v-if="error.password">{{ error.password }}</view>
      </view>

      <!-- 登录按钮 -->
      <up-button
          class="login-btn"
          type="primary"
          size="large"
          :loading="isLoading"
          @click="handleLogin"
          :custom-style="{
          backgroundColor: '#3b82f6',
          borderColor: '#3b82f6',
          borderRadius: '44rpx',
          height: '88rpx',
          lineHeight: '88rpx',
          fontSize: '32rpx'
        }"
      >
        登录
      </up-button>
    </view>
  </view>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import { useUserStore } from '@/pinia/user';
import globalConfig from '@/common/config/global';

// 表单数据
const form = reactive({
  account: '', // 账号
  password: '' // 密码
});

// 状态管理
const isLoading = ref(false);
const error = reactive({
  account: '',
  password: ''
});

// 实例化 Pinia 用户仓库
const userStore = useUserStore();

// 页面加载时初始化
onMounted(() => {
  // 检查登录态
  checkLoginStatus();
});

// 检查登录状态
const checkLoginStatus = () => {
  try {
    // 已登录则直接跳首页
    if (userStore.isLogin) {
      uni.switchTab({
        url: globalConfig.router.tabBarList[1].path,
        fail: () => {
          // 非tabBar页面用redirectTo
          uni.redirectTo({ url: '/pages/workbench/index' });
        }
      });
      return;
    }
  } catch (err) {
    console.warn('检查登录状态失败:', err);
  }
};

// 校验账号
const checkAccount = () => {
  if (!form.account) {
    error.account = '请输入登录账号';
  } else if (!/^[a-zA-Z0-9_-]{4,16}$/.test(form.account)) {
    error.account = '账号格式错误(4-16位字母/数字/下划线)';
  } else {
    error.account = '';
  }
};

// 校验密码
const checkPassword = () => {
  if (!form.password) {
    error.password = '请输入登录密码';
  } else if (form.password.length < 6) {
    error.password = '密码长度不能少于6位';
  } else {
    error.password = '';
  }
};

// 表单整体校验
const validateForm = () => {
  checkAccount();
  checkPassword();
  return !error.account && !error.password;
};

// 登录处理
const handleLogin = async () => {
  if (!validateForm()) return;

  isLoading.value = true;

  try {
    await userStore.login({
      username: form.account,
      password: form.password
    });

    uni.showToast({ title: '登录成功', icon: 'success', duration: 1500 });

    // 登录成功后跳转首页
    setTimeout(() => {
      uni.switchTab({
        url: globalConfig.router.tabBarList[1].path,
        fail: (err) => {
          console.warn('tabBar跳转失败,切换为普通跳转:', err);
          uni.redirectTo({ url: '/pages/workbench/index' });
        }
      });
    }, 1500);
  } catch (err) {
    console.error('登录失败详情:', err);
    const errorMsg =
        err.message === '网络异常,请稍后重试'
            ? '网络异常,请稍后重试'
            : err.message || '登录失败,请检查账号密码';
    uni.showToast({
      title: errorMsg,
      icon: 'none',
      duration: 2000
    });
  } finally {
    isLoading.value = false;
  }
};
</script>

<style scoped lang="scss">
// 核心布局
.login-page {
  min-height: 100vh;
  position: relative;
  padding: 40rpx 30rpx;
  box-sizing: border-box;
  overflow: hidden; // 隐藏动效溢出

  // 适配小程序安全区
  /* #ifdef MP-WEIXIN */
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
  /* #endif */
}

// 纯CSS渐变动效背景(替代粒子,兼容所有版本)
.bg-animation {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  // 基础渐变底色
  background: linear-gradient(120deg, #f0f9ff 0%, #e6f7ff 100%);
  // 伪粒子动效(多个透明渐变圆缓慢移动)
  &::before,
  &::after {
    content: '';
    position: absolute;
    border-radius: 50%;
    background: rgba(59, 130, 246, 0.05);
    animation: float 20s infinite linear;
  }

  &::before {
    width: 600rpx;
    height: 600rpx;
    top: -200rpx;
    left: -200rpx;
  }

  &::after {
    width: 800rpx;
    height: 800rpx;
    bottom: -300rpx;
    right: -300rpx;
    animation-delay: -10s; // 错开动画时间
  }

  // 额外小动效点(模拟粒子)
  & > view {
    position: absolute;
    width: 400rpx;
    height: 400rpx;
    border-radius: 50%;
    background: rgba(59, 130, 246, 0.03);
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    animation: float 15s infinite linear reverse;
  }
}

// 浮动动画(模拟粒子运动)
@keyframes float {
  0% {
    transform: translate(0, 0) rotate(0deg);
  }
  25% {
    transform: translate(50rpx, 30rpx) rotate(90deg);
  }
  50% {
    transform: translate(0, 60rpx) rotate(180deg);
  }
  75% {
    transform: translate(-50rpx, 30rpx) rotate(270deg);
  }
  100% {
    transform: translate(0, 0) rotate(360deg);
  }
}

// 登录表单(悬浮层)
.login-form {
  position: relative;
  z-index: 10;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 60rpx 40rpx;
  border-radius: 16rpx;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
  max-width: 600rpx;
  margin: 0 auto;
  margin-top: 100rpx;

  // 登录标题
  .login-title {
    font-size: 36rpx;
    font-weight: 600;
    color: #111827;
    text-align: center;
    margin-bottom: 40rpx;
    letter-spacing: 2rpx;
  }
}

// 表单项
.form-item {
  margin-bottom: 30rpx;
  position: relative;

  // 错误提示
  .error-tip {
    font-size: 24rpx;
    color: #ef4444;
    margin-top: 10rpx;
    line-height: 1.2;
    padding-left: 10rpx;
  }
}

// 登录按钮
.login-btn {
  width: 100%;
  margin-top: 20rpx;

  // 按钮点击反馈
  &:active {
    transform: scale(0.98);
    transition: transform 0.1s ease;
  }
}

// 覆盖uview默认样式
:deep(.up-input) {
  border-radius: 8rpx !important;
  height: 80rpx !important;
  line-height: 80rpx !important;
}

:deep(.up-input__prefix) {
  margin-right: 15rpx !important;
}

:deep(.up-button__loading) {
  color: #fff !important;
}
</style>