Commit d719f549 by pangchong

feat: 登录完成

parent bc35c6f9
...@@ -8,17 +8,19 @@ export const getGifCaptchaApi = (data, config) => { ...@@ -8,17 +8,19 @@ export const getGifCaptchaApi = (data, config) => {
config config
}) })
} }
export const getUserCallStateApi = (data) => { export const getUserCallStateApi = (data, config) => {
return http({ return http({
method: 'POST', method: 'POST',
url: '/call/getUserCallState', url: '/call/getUserCallState',
data, data,
config
}) })
} }
export const loginApi = (data) => { export const loginApi = (data, config) => {
return http({ return http({
method: 'POST', method: 'POST',
url: '/user/login', url: '/user/login',
data, data,
config
}) })
} }
import { createSSRApp } from 'vue' import { createSSRApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import pinia from './store' import pinia from './store'
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)
app.use(pinia) app.use(pinia)
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
"tabBar": { "tabBar": {
"color": "#1D2129", "color": "#1D2129",
"selectedColor": "#0E42D2", "selectedColor": "#0E42D2",
"borderStyle": "#E7E7E7", "borderStyle": "black",
"iconWidth": "24px", "iconWidth": "24px",
"backgroundColor": "#fff", "backgroundColor": "#fff",
"list": [ "list": [
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
</uni-forms-item> </uni-forms-item>
<uni-forms-item label="验证码" name="verifyCode"> <uni-forms-item label="验证码" name="verifyCode">
<view class="verify-code"> <view class="verify-code">
<uni-easyinput type="text" v-model="loginForm.password" placeholder="请输入验证码" /> <uni-easyinput type="text" v-model="loginForm.verifyCode" placeholder="请输入验证码" />
<image :src="loginCode" mode="scaleToFill" v-if="loginCode" /> <image :src="loginCode" mode="scaleToFill" v-if="loginCode" />
</view> </view>
</uni-forms-item> </uni-forms-item>
...@@ -20,9 +20,10 @@ ...@@ -20,9 +20,10 @@
</template> </template>
<script setup> <script setup>
import { reactive, ref, watch } from 'vue' import { reactive, ref, toRaw, watch } from 'vue'
import { getGifCaptchaApi } from '@/api/user' import { getGifCaptchaApi, loginApi } from '@/api/user'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import message from '@/utils/message'
//表单数据 //表单数据
const loginForm = reactive({ const loginForm = reactive({
...@@ -47,6 +48,14 @@ const rules = reactive({ ...@@ -47,6 +48,14 @@ const rules = reactive({
errorMessage: '请输入密码' errorMessage: '请输入密码'
} }
] ]
},
verifyCode: {
rules: [
{
required: true,
errorMessage: '请输入验证码'
}
]
} }
}) })
//获取验证码 //获取验证码
...@@ -55,9 +64,9 @@ const getGifCaptcha = async () => { ...@@ -55,9 +64,9 @@ const getGifCaptcha = async () => {
const params = { const params = {
username: loginForm.username username: loginForm.username
} }
const blob = await getGifCaptchaApi(params, { blob: true }) const res = await getGifCaptchaApi(params, { arraybuffer: true })
if (blob) { if (res) {
loginCode.value = URL.createObjectURL(blob) loginCode.value = 'data:image/png;base64,' + uni.arrayBufferToBase64(res)
} }
} }
watch( watch(
...@@ -72,6 +81,15 @@ watch( ...@@ -72,6 +81,15 @@ watch(
const loginFormRef = ref() const loginFormRef = ref()
const handleLogin = async () => { const handleLogin = async () => {
await loginFormRef.value?.validate() await loginFormRef.value?.validate()
const res = await loginApi(toRaw(loginForm), { loading: '登陆中...' })
if (res.code == 200) {
//跳转工作台
uni.switchTab({
url: '/pages/panel/index'
})
} else {
message.error(res.message)
}
} }
</script> </script>
...@@ -87,6 +105,11 @@ const handleLogin = async () => { ...@@ -87,6 +105,11 @@ const handleLogin = async () => {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
image {
margin-left: 10rpx;
width: 200rpx;
height: 70rpx;
}
} }
.login-btn { .login-btn {
margin-top: 50rpx; margin-top: 50rpx;
......
...@@ -14,10 +14,46 @@ import useUserStore from '@/store/modules/user' ...@@ -14,10 +14,46 @@ import useUserStore from '@/store/modules/user'
const baseURL = 'https://hna-platform.anyremote.cn' const baseURL = 'https://hna-platform.anyremote.cn'
class ServiceLoading {
constructor() {
this.count = 0
}
open(loading) {
if (this.count < 0) {
this.count = 0
}
if (loading || loading === '') {
let loadingText = '加载中'
if (typeof loading === 'string' && loading !== '') {
loadingText = loading
}
this.count++
uni.showLoading({
title: loadingText
});
}
}
close() {
this.count--
if (this.count <= 0) {
uni.hideLoading();
}
}
}
const serviceLoading = new ServiceLoading()
// 添加拦截器 // 添加拦截器
const httpInterceptor = { const httpInterceptor = {
// 拦截前触发 // 拦截前触发
invoke(options) { invoke(options) {
//responseType
if (options.config?.arraybuffer) {
options.responseType = 'arraybuffer'
}
//loading
const loading = options.config?.loading
serviceLoading.open(loading)
//重组提交数据
if (options.data) { if (options.data) {
options.data = { options.data = {
...options.data, ...options.data,
...@@ -26,18 +62,18 @@ const httpInterceptor = { ...@@ -26,18 +62,18 @@ const httpInterceptor = {
realUserId: '21' realUserId: '21'
} }
} }
// 1. 非 http 开头需拼接地址 // 非 http 开头需拼接地址
if (!options.url.startsWith('http')) { if (!options.url.startsWith('http')) {
options.url = baseURL + options.url options.url = baseURL + options.url
} }
// 2. 请求超时, 默认 60s // 请求超时, 默认 60s
options.timeout = 10000 options.timeout = 10000
// 3. 添加小程序端请求头标识 // 添加小程序端请求头标识
options.header = { options.header = {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
...options.header, ...options.header,
} }
// 4. 添加 token 请求头标识 // 添加 token 请求头标识
const userStore = useUserStore() const userStore = useUserStore()
if (userStore.token) { if (userStore.token) {
options.header.Authorization = `Bearer ${userStore.token}` options.header.Authorization = `Bearer ${userStore.token}`
...@@ -67,14 +103,11 @@ export const http = (options) => { ...@@ -67,14 +103,11 @@ export const http = (options) => {
...options, ...options,
// 响应成功 // 响应成功
success(res) { success(res) {
serviceLoading.close()
// 状态码 2xx, axios 就是这样设计的 // 状态码 2xx, axios 就是这样设计的
if (res.statusCode >= 200 && res.statusCode < 300) { if (res.statusCode >= 200 && res.statusCode < 300) {
// 2.1 提取核心数据 res.data // 2.1 提取核心数据 res.data
if (options.config?.blob) {
resolve(res.data?.blob())
} else {
resolve(res.data) resolve(res.data)
}
} else if (res.statusCode === 401) { } else if (res.statusCode === 401) {
// 401错误 -> 清理用户信息,跳转到登录页 // 401错误 -> 清理用户信息,跳转到登录页
const userStore = useUserStore() const userStore = useUserStore()
...@@ -85,6 +118,7 @@ export const http = (options) => { ...@@ -85,6 +118,7 @@ export const http = (options) => {
// 其他错误 -> 根据后端错误信息轻提示 // 其他错误 -> 根据后端错误信息轻提示
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
mask: true,
title: res.data.msg || '请求错误', title: res.data.msg || '请求错误',
}) })
reject(res) reject(res)
...@@ -92,6 +126,7 @@ export const http = (options) => { ...@@ -92,6 +126,7 @@ export const http = (options) => {
}, },
// 响应失败 // 响应失败
fail(err) { fail(err) {
serviceLoading.close()
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
title: '网络错误,换个网络试试', title: '网络错误,换个网络试试',
......
// utils/message.js
export default {
// 成功提示
success(options) {
uni.showToast({
title: options.title || '操作成功',
icon: 'success',
duration: 2000,
...options
});
},
// 错误提示
error(options) {
uni.showToast({
title: options.title || '操作失败',
icon: 'none',
duration: 2000,
...options
});
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment