#
zhou zhou
8 天以前 da05dcffeabcb3c460e45666a4804f4ea5a4145a
pages/login/login.vue
@@ -1,437 +1,673 @@
<template>
   <view class="bodyView">
      <view>
         <u-navbar
            :fixed="true"
            :title="$t('page.login')"
            rightIcon="setting"
            left-icon=""
            :placeholder="true"
            @rightClick="openSettings"
         ></u-navbar>
      </view>
      <view class="topView">
         <image src="/static/img/login_top.png" mode="aspectFill">
         </image>
         <u--image
            width="100%"
            src="/static/img/login_top.png"
            mode="aspectFill"
         ></u--image>
      </view>
      <view class="logoView">
         <image src="/static/img/newLogo.png" mode="aspectFit">
         </image>
         <image
            src="/static/img/newLogo.png"
            mode="aspectFit"
         ></image>
      </view>
      <view class="bottomView">
         <view class="itemView" style="margin-bottom: 40px;">
            <view class="helloText">{{$t('index.hello')}}</view>
            <view class="introText">{{$t('index.intro')}}</view>
         <view
            class="itemView"
            style="margin-bottom: 20px"
         >
            <view class="helloText">{{ $t('index.hello') }}</view>
            <view class="introText">{{ $t('index.intro') }}</view>
         </view>
         <view class="itemView">
            <view class="textType3">{{$t('login.user')}}:</view>
            <u-input clearable class="" v-model="user.userName" focus :placeholder="$t('login.inputUser')" />
            <text class="textType3">{{ $t('login.user') }}:</text>
            <u-input
               clearable
               class=""
               v-model="user.userName"
               focus
               :placeholder="$t('login.inputUser')"
            />
         </view>
         <view class="itemView">
            <view class="textType3">{{$t('login.pwd')}}:</view>
            <text class="textType3">{{ $t('login.pwd') }}:</text>
            <u-input :password="showPassword" v-model="user.password" :placeholder="$t('login.inputPwd')"
               suffixIcon="map-fill" suffixIconStyle="color: #909399">
            <u-input
               :password="showPassword"
               v-model="user.password"
               :placeholder="$t('login.inputPwd')"
               suffixIcon="map-fill"
               suffixIconStyle="color: #909399"
            >
               <template slot="suffix">
                  <u-icon :name="pwdIcon" @click="changePassword"></u-icon>
                  <u-icon
                     :name="pwdIcon"
                     @click="changePassword"
                  ></u-icon>
               </template>
            </u-input>
         </view>
         <view class="langAndRemView">
            <view class="check">
               <view>
                  <view>{{$t('login.remPwd')}}</view>
                  <text>{{ $t('login.remPwd') }}</text>
               </view>
               <view>
                  <u-switch space="2" size="20" v-model="remberPassword" activeColor="#f9ae3d"
                     inactiveColor="rgb(230, 230, 230)">
                  </u-switch>
                  <!-- <switch :checked='remberPassword' color="#FFCC33" style="transform:scale(0.7)"
                     @change="remberChange" /> -->
                  <u-switch
                     space="2"
                     size="20"
                     v-model="remberPassword"
                     activeColor="#f9ae3d"
                     inactiveColor="rgb(230, 230, 230)"
                  ></u-switch>
               </view>
            </view>
            <view class="langView">
               <!-- 语言选择下拉菜单 -->
               <view class="language-dropdown">
                  <view class="selected-language" @click="toggleLanguageDropdown">
                     <text>{{getCurrentLanguageText()}}</text>
                     <u-icon name="list" size="14" color="#707070"></u-icon>
                  <view
                     class="selected-language"
                     @click="toggleLanguageDropdown"
                  >
                     <text>{{ getCurrentLanguageText() }}</text>
                     <u-icon
                        name="list"
                        size="14"
                        color="#707070"
                     ></u-icon>
                  </view>
                  <view class="language-options" v-if="showLanguageDropdown">
                     <view class="language-option" v-for="(item, index) in locales" :key="index"
                        @click="onLocaleChange(item)">
                        <text>{{item.text}}</text>
                        <u-icon name="checkbox-mark" color="#007AFF"
                           v-if="item.code == applicationLocale"></u-icon>
                  <view
                     class="language-options"
                     v-if="showLanguageDropdown"
                  >
                     <view
                        class="language-option"
                        v-for="(item, index) in locales"
                        :key="index"
                        @click="onLocaleChange(item)"
                     >
                        <text>{{ item.text }}</text>
                        <u-icon
                           name="checkbox-mark"
                           color="#007AFF"
                           v-if="item.code == applicationLocale"
                        ></u-icon>
                     </view>
                  </view>
               </view>
            </view>
         </view>
         <view class="itemView">
            <u-button class="loadingButton" @click="onLogin()" :loading="loading">{{btnText}}</u-button>
            <u-button
               class="loadingButton"
               @click="onLogin()"
               :loading="loading"
            >
               {{ btnText }}
            </u-button>
         </view>
      </view>
      <u-popup
         :show="showAuth"
         @close="showAuth = false"
         mode="center"
         :round="14"
         :customStyle="{ width: '500rpx' }"
      >
         <view class="settings-popup">
            <view class="settings-title">
               <text class="settings-title-text">
                  {{ $t('settings.authTitle') || '身份验证' }}
               </text>
            </view>
            <view class="settings-item">
               <u-input
                  v-model="authPassword"
                  type="password"
                  border="surround"
                  :placeholder="
                     $t('settings.inputAuthPwd') || '请输入管理员密码'
                  "
               />
            </view>
            <view class="settings-buttons">
               <u-button
                  size="medium"
                  @click="showAuth = false"
               >
                  {{ $t('common.cancel') || '取消' }}
               </u-button>
               <view style="width: 20px"></view>
               <u-button
                  size="medium"
                  type="primary"
                  @click="checkAuth"
               >
                  {{ $t('common.confirm') || '确认' }}
               </u-button>
            </view>
         </view>
      </u-popup>
      <u-popup
         :show="showSettings"
         @close="showSettings = false"
         mode="center"
         :round="14"
         :closeOnClickOverlay="false"
         :customStyle="{ width: '600rpx' }"
      >
         <view class="settings-popup">
            <view class="settings-title">
               <text class="settings-title-text">
                  {{ $t('settings.title') || '设置' }}
               </text>
            </view>
            <view class="settings-item">
               <text class="settings-label">
                  {{ $t('settings.ip') || 'IP地址' }}:
               </text>
               <u-input
                  v-model="settings.ip"
                  border="surround"
               />
            </view>
            <view class="settings-item">
               <text class="settings-label">
                  {{ $t('settings.port') || '端口' }}:
               </text>
               <u-input
                  v-model="settings.port"
                  border="surround"
               />
            </view>
            <view class="settings-item">
               <text class="settings-label">
                  {{ $t('settings.project') || '项目名' }}:
               </text>
               <u-input
                  v-model="settings.project"
                  border="surround"
               />
            </view>
            <view class="settings-buttons">
               <u-button
                  size="medium"
                  @click="showSettings = false"
               >
                  {{ $t('common.cancel') || '取消' }}
               </u-button>
               <view style="width: 20px"></view>
               <u-button
                  size="medium"
                  type="primary"
                  @click="saveSettings"
               >
                  {{ $t('common.confirm') || '确认' }}
               </u-button>
            </view>
         </view>
      </u-popup>
      <u-toast ref="uToast"></u-toast>
   </view>
</template>
<script>
   import md5 from '../../static/js/md5.js'
   import {
      request
   } from '../../common/request.js'
   export default {
      data() {
         return {
            showPassword: true,
            loading: false,
            showLanguageDropdown: false,
            loginButton: 'login.login',
            systemLocale: '',
            applicationLocale: '',
            remberPassword: true,
            user: {
               userName: '',
               password: '',
import md5 from '../../static/js/md5.js'
import { login } from './api.js'
export default {
   data() {
      return {
         showPassword: true,
         loading: false,
         showLanguageDropdown: false,
         loginButton: 'login.login',
         systemLocale: '',
         applicationLocale: '',
         remberPassword: true,
         user: {
            userName: '',
            password: ''
         },
         passwordIcon: 'eye-off',
         showSettings: false,
         settings: {
            ip: '',
            port: '',
            project: ''
         },
         showAuth: false,
         authPassword: ''
      }
   },
   computed: {
      locales() {
         return [
            {
               text: this.$t('locale.auto'),
               code: 'auto'
            },
            passwordIcon: 'eye-off'
            {
               text: this.$t('locale.en'),
               code: 'en'
            },
            {
               text: this.$t('locale.zh-hans'),
               code: 'zh-Hans'
            },
            {
               text: this.$t('locale.zh-hant'),
               code: 'zh-Hant'
            },
            {
               text: this.$t('locale.ja'),
               code: 'ja'
            }
         ]
      },
      btnText() {
         return this.$t(this.loginButton)
      },
      pwdIcon() {
         return this.passwordIcon
      }
   },
   onLoad() {
      let systemInfo = uni.getSystemInfoSync()
      this.systemLocale = systemInfo.language
      this.applicationLocale = uni.getLocale()
      this.isAndroid = systemInfo.platform.toLowerCase() === 'android'
      uni.onLocaleChange((e) => {
         this.applicationLocale = e.locale
      })
      this.user = uni.getStorageSync('user')
      if (!this.user) {
         this.user = {
            userName: '',
            password: ''
         }
      }
   },
   methods: {
      openSettings() {
         this.showAuth = true
         this.authPassword = ''
      },
      checkAuth() {
         // Default password: admin or 123456. Ideally from config.
         if (
            this.authPassword === 'admin' ||
            this.authPassword === '123456'
         ) {
            this.showAuth = false
            this.loadSettings()
         } else {
            this.$refs.uToast.show({
               type: 'error',
               message: this.$t('settings.authError') || '密码错误'
            })
         }
      },
      computed: {
         locales() {
            return [{
                  text: this.$t('locale.auto'),
                  code: 'auto'
               }, {
                  text: this.$t('locale.en'),
                  code: 'en'
               },
               {
                  text: this.$t('locale.zh-hans'),
                  code: 'zh-Hans'
               },
               {
                  text: this.$t('locale.zh-hant'),
                  code: 'zh-Hant'
               },
               {
                  text: this.$t('locale.ja'),
                  code: 'ja'
               }
            ]
         },
         btnText() {
            return this.$t(this.loginButton);
         },
         pwdIcon() {
            return this.passwordIcon;
      loadSettings() {
         this.showSettings = true
         let settings = uni.getStorageSync('app_settings')
         if (!settings) {
            settings = {
               ip: '127.0.0.1',
               port: '8080',
               project: 'jshdasrs'
            }
         }
         this.settings = settings
      },
      onLoad() {
         let systemInfo = uni.getSystemInfoSync();
         this.systemLocale = systemInfo.language;
         this.applicationLocale = uni.getLocale();
         this.isAndroid = systemInfo.platform.toLowerCase() === 'android';
         uni.onLocaleChange((e) => {
            this.applicationLocale = e.locale;
      saveSettings() {
         uni.setStorageSync('app_settings', this.settings)
         console.log(this.settings)
         this.showSettings = false
         this.$refs.uToast.show({
            type: 'success',
            message: this.$t('settings.saved') || '设置已保存'
         })
      },
      async onLogin() {
         try {
            const res = await login(
               {
                  username: this.user.userName,
                  password: md5.hex_md5(this.user.password)
               },
               { custom: { catch: true } }
            )
         this.user = uni.getStorageSync('user')
         if (!this.user) {
            this.user = {
               userName: '',
               password: ''
            this.loading = true
            this.loginButton = 'login.loging'
            uni.setStorageSync('token', res.data.accessToken)
            uni.setStorageSync('userData', res.data.username)
            if (this.remberPassword) {
               uni.setStorageSync('user', this.user)
            } else {
               uni.removeStorageSync('user')
            }
            this.goHome()
         } catch (e) {
            // 拦截器已处理 toast
         }
      },
      methods: {
         async onLogin() {
            const {
               code,
               data,
               msg
            } = await request('/login.action', {
               username: this.user.userName,
               password: md5.hex_md5(this.user.password),
            }, 'GET')
            if (code === 200) {
               this.loading = true;
               this.loginButton = 'login.loging';
               uni.setStorageSync('token', data.accessToken);
               uni.setStorageSync('userData', data.username);
               if (this.remberPassword) {
                  uni.setStorageSync('user', this.user);
               } else {
                  uni.removeStorageSync('user');
               }
               this.goHome()
            } else {
               this.$refs.uToast.show({
                  type: 'error',
                  message: "请检查接口连接",
                  position: 'top'
               });
            }
         },
         goHome() {
      goHome() {
         setTimeout(() => {
            this.$refs.uToast.show({
               type: 'success',
               message: '登录成功',
               position: 'top'
            })
            setTimeout(() => {
               this.$refs.uToast.show({
                  type: 'success',
                  message: "登录成功",
                  position: 'top'
               });
               setTimeout(() => {
                  uni.$u.route({
                     url: 'pages/index/index',
                     params: {
                        name: 'lisa'
                     }
                  })
               }, 300)
            }, 700)
         },
         remberChange(e) {
            this.remberPassword = !this.remberPassword
         },
         // 显示/隐藏密码
         changePassword() {
            this.passwordIcon = !this.showPassword ? 'eye-off' : 'eye'
            this.showPassword = !this.showPassword;
         },
         localChange() {
            console.log(this.local)
            if (this.isAndroid) {
               uni.showModal({
                  content: this.$t('index.language-change-confirm'),
                  success: (res) => {
                     if (res.confirm) {
                        uni.setLocale(this.local.value);
                     }
               uni.$u.route({
                  type: 'reLaunch',
                  url: 'pages/home/home',
                  params: {
                     name: 'lisa'
                  }
               })
            } else {
               uni.setLocale(this.local.value);
               this.$i18n.locale = this.local.value;
            }
         },
         // 切换语言下拉菜单显示状态
         toggleLanguageDropdown() {
            this.showLanguageDropdown = !this.showLanguageDropdown;
         },
         // 获取当前选择的语言文本
         getCurrentLanguageText() {
            const currentLocale = this.locales.find(item => item.code === this.applicationLocale);
            return currentLocale ? currentLocale.text : this.$t('locale.auto');
         },
         // 语言选择改变
         onLocaleChange(e) {
            if (this.isAndroid) {
               uni.showModal({
                  content: this.$t('index.language-change-confirm'),
                  success: (res) => {
                     if (res.confirm) {
                        uni.setLocale(e.code);
                        this.showLanguageDropdown = false;
                     }
            }, 300)
         }, 700)
      },
      remberChange(e) {
         this.remberPassword = !this.remberPassword
      },
      // 显示/隐藏密码
      changePassword() {
         this.passwordIcon = !this.showPassword ? 'eye-off' : 'eye'
         this.showPassword = !this.showPassword
      },
      localChange() {
         console.log(this.local)
         if (this.isAndroid) {
            uni.showModal({
               content: this.$t('index.language-change-confirm'),
               success: (res) => {
                  if (res.confirm) {
                     uni.setLocale(this.local.value)
                  }
               })
            } else {
               uni.setLocale(e.code);
               this.$i18n.locale = e.code;
               this.showLanguageDropdown = false;
            }
         },
               }
            })
         } else {
            uni.setLocale(this.local.value)
            this.$i18n.locale = this.local.value
         }
      },
      // 切换语言下拉菜单显示状态
      toggleLanguageDropdown() {
         this.showLanguageDropdown = !this.showLanguageDropdown
      },
      // 获取当前选择的语言文本
      getCurrentLanguageText() {
         const currentLocale = this.locales.find(
            (item) => item.code === this.applicationLocale
         )
         return currentLocale ? currentLocale.text : this.$t('locale.auto')
      },
      // 语言选择改变
      onLocaleChange(e) {
         if (this.isAndroid) {
            uni.showModal({
               content: this.$t('index.language-change-confirm'),
               success: (res) => {
                  if (res.confirm) {
                     uni.setLocale(e.code)
                     this.showLanguageDropdown = false
                  }
               }
            })
         } else {
            uni.setLocale(e.code)
            this.$i18n.locale = e.code
            this.showLanguageDropdown = false
         }
      }
   }
}
</script>
<style lang="scss" scoped>
   .helloText {
      font-family: a2;
      font-size: 20px;
      margin-top: 10px;
      margin-bottom: 5px;
   }
.helloText {
   font-family: a2;
   font-size: 20px;
   margin-top: 10px;
   margin-bottom: 5px;
}
   .introText {
      font-family: a3;
      font-size: 15px;
      color: #ababab;
   }
.introText {
   font-family: a3;
   font-size: 15px;
   color: #ababab;
}
   .textType3 {
      font-family: a4;
   }
.textType3 {
   font-family: a4;
}
   .bodyView {
      display: flex;
      flex-direction: column;
      background-image: url("/static/img/login_backg.png");
      background-repeat: no-repeat;
      background-size: cover;
      background-position: center;
      height: 100vh;
      width: 100%;
   }
.bodyView {
   flex: 1;
   flex-direction: column;
   width: 750rpx;
}
   .topView {
      flex: 7;
   }
.bgImage {
   position: fixed;
   top: 0;
   left: 0;
   bottom: 0;
   right: 0;
}
   .topView image {
      width: 100%;
   }
.topView {
   flex: 7;
}
   .logoView {
      flex: 1;
      display: flex;
      justify-content: flex-end;
      align-items: center;
.topView image {
   width: 100%;
}
   }
.logoView {
   flex: 1;
   display: flex;
   justify-content: flex-end;
   align-items: flex-end;
}
   .logoView image {
      width: 33%;
      height: 50px;
      margin-right: 20px;
   }
.logoView image {
   width: 33%;
   height: 50px;
   margin-right: 20px;
}
   .bottomView {
      flex: 15;
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      align-items: center;
   }
.bottomView {
   flex: 15;
   display: flex;
   flex-direction: column;
   justify-content: flex-start;
   align-items: center;
}
   .itemView {
      width: 90%;
      height: 50px;
      margin-bottom: 30px;
   }
.itemView {
   width: 90%;
   margin-bottom: 5px;
}
   .langAndRemView {
      width: 90%;
      display: flex;
      justify-content: space-between;
      align-items: center;
   }
.langAndRemView {
   width: 90%;
   display: flex;
   flex-direction: row;
   justify-content: space-between;
   align-items: center;
   margin-bottom: 5px;
}
   .langView {
      width: 30%;
   }
.langView {
   width: 30%;
}
   .textImage {
      width: 60%;
      height: 42px;
      object-fit: cover;
      margin-top: 20px;
      margin-bottom: 30px;
   }
.textImage {
   width: 60%;
   height: 42px;
   object-fit: cover;
   margin-top: 20px;
   margin-bottom: 30px;
}
   .input-wrapper {
      /* #ifndef APP-NVUE */
      display: flex;
      /* #endif */
      padding: 8px 13px;
      flex-direction: row;
      flex-wrap: nowrap;
      background-color: #FFFFFF;
      border-radius: 10px;
      height: 45px;
      align-items: center;
      margin-top: 5px;
   }
.input-wrapper {
   /* #ifndef APP-NVUE */
   display: flex;
   /* #endif */
   padding: 8px 13px;
   flex-direction: row;
   flex-wrap: nowrap;
   background-color: #ffffff;
   border-radius: 10px;
   height: 45px;
   align-items: center;
   margin-top: 5px;
}
   .uni-input {
      height: 28px;
      line-height: 28px;
      font-size: 15px;
      padding: 0px;
      flex: 1;
      background-color: #FFFFFF;
.uni-input {
   height: 28px;
   line-height: 28px;
   font-size: 15px;
   padding: 0px;
   flex: 1;
   background-color: #ffffff;
}
   }
.uni-icon {
   font-family: uniicons;
   font-size: 24px;
   font-weight: normal;
   font-style: normal;
   width: 24px;
   height: 24px;
   line-height: 24px;
   color: #999999;
}
   .uni-icon {
      font-family: uniicons;
      font-size: 24px;
      font-weight: normal;
      font-style: normal;
      width: 24px;
      height: 24px;
      line-height: 24px;
      color: #999999;
   }
.uni-eye-active {
   color: #007aff;
}
   .uni-eye-active {
      color: #007AFF;
   }
.eye-icon {
   width: 20px;
   height: 13px;
   margin-left: 5px;
}
   .eye-icon {
      width: 20px;
      height: 13px;
      margin-left: 5px;
   }
.loadingButton {
   background-color: #ffda1e;
   font-family: a1;
}
   .loadingButton {
      background-color: #ffda1e;
      font-family: a1;
   }
.check {
   height: 100%;
   display: flex;
   flex-direction: row;
   font-size: 18px;
   color: #606266;
   justify-content: flex-start;
   align-items: center;
}
   .check {
/* 语言选择下拉菜单 */
.language-dropdown {
   position: relative;
   margin-bottom: 20rpx;
   z-index: 10;
}
      height: 100%;
      display: flex;
      font-size: 18px;
      color: #606266;
      justify-content: flex-start;
      align-items: center;
.selected-language {
   display: flex;
   flex-direction: row;
   justify-content: space-between;
   align-items: center;
   padding: 15rpx 20rpx;
   background-color: #f8f8f8;
   border-radius: 8rpx;
   border: 1px solid #e0e0e0;
}
   }
.language-options {
   position: absolute;
   bottom: 100%;
   left: 0;
   right: 0;
   background-color: #ffffff;
   border-radius: 8rpx;
   box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
   border: 1px solid #e0e0e0;
   margin-bottom: 5rpx;
}
   /* 语言选择下拉菜单 */
   .language-dropdown {
      position: relative;
      margin-bottom: 20rpx;
      z-index: 10;
   }
.language-option {
   display: flex;
   flex-direction: row;
   justify-content: space-between;
   align-items: center;
   padding: 15rpx 20rpx;
   border-bottom: 1px solid #f0f0f0;
}
   .selected-language {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 15rpx 20rpx;
      background-color: #f8f8f8;
      border-radius: 8rpx;
      border: 1px solid #e0e0e0;
   }
.language-option:last-child {
   border-bottom: none;
}
   .language-options {
      position: absolute;
      bottom: 100%;
      left: 0;
      right: 0;
      background-color: #ffffff;
      border-radius: 8rpx;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      border: 1px solid #e0e0e0;
      margin-bottom: 5rpx;
   }
.language-option:active {
   background-color: #f5f5f5;
}
   .language-option {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 15rpx 20rpx;
      border-bottom: 1px solid #f0f0f0;
   }
.settings-popup {
   padding: 20px;
   background-color: #ffffff;
   border-radius: 10px;
   display: flex;
   flex-direction: column;
}
   .language-option:last-child {
      border-bottom: none;
   }
.settings-title {
   margin-bottom: 20px;
   align-items: center;
   justify-content: center;
}
   .language-option:active {
      background-color: #f5f5f5;
   }
</style>
.settings-title-text {
   font-size: 18px;
   font-weight: bold;
}
.settings-item {
   margin-bottom: 15px;
}
.settings-label {
   margin-bottom: 5px;
   font-size: 14px;
   color: #606266;
}
.settings-buttons {
   display: flex;
   flex-direction: row;
   justify-content: center;
   margin-top: 10px;
}
</style>