소스 검색

二维码

Xiao_123 1 년 전
부모
커밋
894f61fa03

+ 9 - 0
.env.development

@@ -0,0 +1,9 @@
+NODE_ENV = 'development'
+
+VUE_APP_MODE = 'development'
+
+VITE_APP_TITLE = 门墩儿招聘
+
+VUE_APP_BASE_API = 'http://192.168.3.86:83/op/base'
+
+TENANTCODE = ''

+ 1 - 1
index.html

@@ -5,7 +5,7 @@
   <meta charset="UTF-8" />
   <link rel="icon" href="/favicon.ico" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-  <title>Welcome to Vuetify 3</title>
+  <title>%VITE_APP_TITLE%</title>
 </head>
 
 <body>

+ 2 - 4
src/plugins/vuetify.js

@@ -18,10 +18,8 @@ const myCustomLightTheme = {
   colors: {
     background: '#FFFFFF',
     surface: '#FFFFFF',
-    primary: '#6200EE',
-    'primary-darken-1': '#3700B3',
-    secondary: '#03DAC6',
-    'secondary-darken-1': '#018786',
+    primary: '#00897B',
+    secondary: '#26A69A',
     error: '#B00020',
     info: '#2196F3',
     success: '#4CAF50',

+ 14 - 0
src/utils/auth.js

@@ -0,0 +1,14 @@
+// 获取token
+export const getToken = () => {
+  return localStorage.getItem('access_token')
+}
+
+// 设置token
+export const setToken = (token) => {
+  return localStorage.setItem('access_token', token)
+}
+
+// 清除token
+export const deleteToken = () => {
+  return localStorage.removeItem('access_token')
+}

+ 2 - 2
src/utils/code.js

@@ -1,10 +1,10 @@
 import Cookies from 'js-cookie'
 
-export function getCodeTime() {
+export const getCodeTime = () => {
   return Cookies.get('codeTime')
 }
 
-export function setCodeTime(value) {
+export const setCodeTime = (value) => {
   return Cookies.set('codeTime',value)
 }
 

+ 17 - 0
src/utils/index.js

@@ -0,0 +1,17 @@
+export const blobToJson = (blob) => {
+  return new Promise((resolve, reject) => {
+    const reader = new FileReader()
+
+    reader.onload = function (event) {
+      const jsonString = event.target.result
+      const jsonObject = JSON.parse(jsonString)
+      resolve(jsonObject)
+    }
+
+    reader.onerror = function (error) {
+      reject(error)
+    }
+
+    reader.readAsText(blob)
+  })
+}

+ 118 - 0
src/utils/request.js

@@ -0,0 +1,118 @@
+import axios from 'axios'
+import { blobToJson } from '@/utils'
+import { getToken } from '@/utils/auth'
+import qs from 'qs'
+
+// create an axios instance
+const service = axios.create({
+  baseURL: import.meta.env.VUE_APP_BASE_API,
+  timeout: 120000 // request timeout
+})
+
+// request interceptor
+// 发送请求拦截器
+service.interceptors.request.use(
+  config => {
+    if (getToken()) {
+      config.headers.token = getToken()
+    }
+    config.headers.token = getToken()
+    return config
+  },
+  error => {
+    console.error(error)
+    return Promise.reject(error)
+  }
+)
+
+// 请求返回之后的拦截器
+service.interceptors.response.use(
+  async response => {
+    const res = response.data
+
+    if (response.request.responseType === 'blob') {
+      // 返回的文件流当报错时转化成json
+      if (response.headers['content-type'] === 'application/json') {
+        try {
+          const result = await blobToJson(res)
+          return Promise.reject(result.msg)
+        } catch (error) {
+          return Promise.reject(error)
+        }
+      }
+      const name = response.headers['content-disposition']
+      return {
+        data: res,
+        name: name ? decodeURI(name.replace('attachment;filename=', '')) : '未命名'
+      }
+    }
+
+    if ([50008, 50012, 50014, 402000, 401].includes(res.code)) {
+      // 登录过期
+      return Promise.reject(res.msg)
+    }
+    // 登录验证码过期
+    if (res.code === 60902) {
+      return Promise.reject(res)
+    }
+    if (res.code !== 20000) {
+      if (res.data) {
+        return Promise.reject(res)
+      }
+      return Promise.reject(res.msg)
+    }
+    return res
+  },
+  error => {
+    console.error(error)
+    return Promise.reject(error)
+  }
+)
+
+// 请求方法
+const http = {
+  post (url, params) {
+    return service.post(url, params, {
+      transformRequest: [(params) => {
+        return JSON.stringify(params)
+      }],
+      headers: {
+        'Content-Type': 'application/json'
+      }
+    })
+  },
+  get (url, params) {
+    return service.get(url, {
+      params: params,
+      paramsSerializer: (params) => {
+        return qs.stringify(params)
+      }
+    })
+  },
+  formData (url, params) {
+    return service.post(url, params, {
+      timeout: 600000,
+      headers: {
+        'Content-Type': 'application/x-www-form-urlencoded'
+      }
+    })
+  },
+  upload (url, params) {
+    return service.post(url, params, {
+      timeout: 600000,
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      }
+    })
+  },
+  download (url, params) {
+    return service.post(url, params, {
+      timeout: 10000,
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      responseType: 'blob'
+    })
+  }
+}
+export default http

+ 19 - 3
src/views/login/components/password.vue

@@ -1,7 +1,16 @@
 <template>
   <v-form @submit.prevent>
-    <v-text-field placeholder="请输入账户" color="#00897B" variant="outlined" density="compact" prepend-inner-icon="mdi-account-outline" :rules="[v=> !!v || '请输入账户']"></v-text-field>
-    <v-text-field 
+    <v-text-field
+      v-model="loginData.query.username"
+      placeholder="请输入账户" 
+      color="#00897B" 
+      variant="outlined" 
+      density="compact" 
+      prepend-inner-icon="mdi-account-outline" 
+      :rules="[v=> !!v || '请输入账户']"
+    ></v-text-field>
+    <v-text-field
+      v-model="loginData.query.passwod"
       placeholder="请输入密码" 
       variant="outlined" 
       density="compact"
@@ -16,7 +25,14 @@
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { ref, reactive } from 'vue'
 defineOptions({ name: 'passowrd-form' })
 const passwordType = ref(false)
+
+const loginData = reactive({
+  query: {
+    username: '',
+    passwod: ''
+  }
+})
 </script>

+ 23 - 11
src/views/login/components/phone.vue

@@ -1,17 +1,17 @@
 <template>
   <div>
-    <v-form>
-      <v-text-field placeholder="请输入手机号" color="#00897B" variant="outlined" density="compact" :rules="phoneRules">
+    <v-form @submit.prevent>
+      <v-text-field v-model="loginData.query.phone" placeholder="请输入手机号" color="#00897B" variant="outlined" density="compact" :rules="phoneRules">
         <template v-slot:prepend-inner>
           <span class="d-flex">
             <v-icon icon="mdi-cellphone" size="20"></v-icon>
             <span class="d-flex" id="menu-activator">
-              <span class="phone-number">+86</span>
+              <span class="phone-number">{{ currentAear }}</span>
               <v-icon size="20">mdi-chevron-down</v-icon>
             </span>
             <v-menu activator="#menu-activator">
               <v-list>
-                <v-list-item v-for="(item, index) in items" :key="index" :value="index">
+                <v-list-item v-for="(item, index) in items" :key="index" :value="index" @click="handleChangeCurrentAear">
                   <v-list-item-title>{{ item.title }}</v-list-item-title>
                 </v-list-item>
               </v-list>
@@ -19,7 +19,7 @@
           </span>
         </template>
       </v-text-field>
-      <v-text-field placeholder="请输入验证码" color="#00897B" variant="outlined" density="compact" prepend-inner-icon="mdi-security" :rules="[v=> !!v || '请填写验证码']">
+      <v-text-field v-model="loginData.query.code" placeholder="请输入验证码" color="#00897B" variant="outlined" density="compact" prepend-inner-icon="mdi-security" :rules="[v=> !!v || '请填写验证码']">
         <template #append-inner>
           <span v-if="showCode" class="login-code" @click="handleCode">获取验证码</span>
           <span v-else class="disable">重新获取{{ count }}s</span>
@@ -30,7 +30,7 @@
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { ref, reactive } from 'vue'
 import { setCodeTime } from '@/utils/code'
 defineOptions({ name: 'phone-index' })
 const phoneRules = ref([
@@ -39,17 +39,21 @@ const phoneRules = ref([
     return '请输入手机号'
   },
   value => {
-    if (value?.length <= 10) return true
+    if (value?.length <= 11) return true
     return 'Name must be less than 10 characters.'
   }
 ])
 // 手机号区域
+const currentAear = ref('中国大陆')
 const items = [
-  { title: 'Click Me' },
-  { title: 'Click Me' },
-  { title: 'Click Me' },
-  { title: 'Click Me 2' }
+  { title: '中国大陆', value: '86' },
+  { title: '中国香港', value: '852' },
+  { title: '中国澳门', value: '853' },
+  { title: '西班牙', value: '34' }
 ]
+const handleChangeCurrentAear = (e) => {
+  currentAear.value = e.target.innerText
+}
 
 // 获取验证码
 const showCode = ref(true)
@@ -80,6 +84,13 @@ const autoTimer = () => {
   setTime()
 }
 autoTimer()
+
+const loginData = reactive({
+  query: {
+    phone: '',
+    code: ''
+  }
+})
 </script>
 
 <style lang="scss" scoped>
@@ -96,5 +107,6 @@ autoTimer()
 }
 ::v-deep .phone-number {
   font-size: 12px;
+  width: 50px;
 }
 </style>

+ 15 - 0
src/views/login/components/qrCode.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    <v-img
+      :width="289"
+      cover
+      aspect-ratio="16/9"
+      src="https://minio.citupro.com/dev/static/csqrcode.jpg"
+      style="height: 200px;"
+    ></v-img>
+  </div>
+</template>
+
+<script setup>
+defineOptions({ name: 'qr-code' })
+</script>

+ 24 - 8
src/views/login/index.vue

@@ -5,33 +5,40 @@
         <div class="left">
           <div ref="phone" :class="['left-qrCode', {'phone-switch': isPhone}]" @click="handlePhone">
             <div class="switch-tip">
-              {{ isPhone ? '验证码登录/注册' : '微信扫码快速登录' }}
+              {{ isPhone ? '短信、密码登录/注册' : '微信扫码快速登录' }}
             </div>
           </div>
         </div>
-        <div class="right mr-2 mt-3">
+        <div class="right mr-2 mt-3" v-if="showClose">
           <v-icon color="grey" size="30">mdi-close</v-icon>
         </div>
       </div>
       <div class="login-content-box mt-2">
-        <div class="login-tab">
+        <div v-if="!isPhone" class="login-tab">
           <v-tabs v-model="tab" align-tabs="center" color="#00897B">
             <v-tab :value="1">短信登录</v-tab>
             <v-tab :value="2">密码登录</v-tab>
           </v-tabs>
           <v-window v-model="tab" class="mt-7">
             <v-window-item :value="1">
-              <phoneFrom></phoneFrom>
+              <!-- 验证码登录 -->
+              <phoneFrom ref="phoneRef"></phoneFrom>
             </v-window-item>
             <v-window-item :value="2">
-              <passwordFrom></passwordFrom>
+              <!-- 账号密码登录 -->
+              <passwordFrom ref="passRef"></passwordFrom>
             </v-window-item>
           </v-window>
         </div>
-        <v-btn color="#00897B" class="white--text mt-2" min-width="298">登录/注册</v-btn>
+        <div v-else>
+          <!-- 微信扫码登录 -->
+          <qr-code></qr-code>
+        </div>
+        <v-btn color="primary" class="white--text mt-2" min-width="298" @click="handleLogin">登录/注册</v-btn>
         <div class="login-tips mt-3">
           登录/注册即代表您同意 
-          <span class="color">[用户协议及隐私政策]</span>
+          <span class="color" style="cursor: pointer;">[用户协议]</span>
+          <span class="color" style="cursor: pointer;">[隐私政策]</span>
         </div>
       </div>
     </div>
@@ -42,6 +49,7 @@
 import { ref } from 'vue'
 import passwordFrom from './components/password.vue'
 import phoneFrom from './components/phone.vue'
+import qrCode from './components/qrCode.vue'
 defineOptions({ name: 'login-index' })
 const phone = ref()
 let isPhone = ref(false)
@@ -50,6 +58,13 @@ const handlePhone = () => {
   phone.value.style.backgroundPosition = isPhone.value ? '0 -80px' : '0 0'
 }
 const tab = ref(1)
+
+const showClose = ref(false)
+
+const phoneRef = ref()
+const passRef = ref()
+const handleLogin = () => {
+}
 </script>
 
 <style lang="scss" scoped>
@@ -73,6 +88,7 @@ const tab = ref(1)
   display: flex;
   justify-content: space-between;
   align-items: center;
+  height: 40px;
 }
 .login-content-box {
   padding: 0 50px;
@@ -87,7 +103,7 @@ const tab = ref(1)
   width: 40px;
   height: 40px;
   cursor: pointer;
-  background: url(https://img.bosszhipin.com/static/file/2022/4dwjcdpfje1667186848239.png) 0 0/40px auto no-repeat;
+  background: url('https://img.bosszhipin.com/static/file/2022/4dwjcdpfje1667186848239.png') 0 0/40px auto no-repeat;
 }
 .left-qrCode:hover {
   background-position: 0 -40px !important;

+ 4 - 4
vite.config.mjs

@@ -19,10 +19,10 @@ export default defineConfig({
     Components(),
     ViteFonts({
       google: {
-        families: [{
-          name: 'Roboto',
-          styles: 'wght@100;300;400;500;700;900',
-        }],
+        // families: [{
+        //   name: 'Roboto',
+        //   styles: 'wght@100;300;400;500;700;900',
+        // }],
       },
     }),
   ],