feat:新增登录页面与相关功能,移除自动登录,对接用户反馈功能

This commit is contained in:
2025-10-08 02:29:48 +08:00
parent 0ec86fba8e
commit 8560ff778e
10 changed files with 317 additions and 35 deletions
+62 -19
View File
@@ -1,6 +1,6 @@
<template>
<view class="feedback-container">
<form>
<!-- <form> -->
<!-- 问题类型选择 -->
<view class="type-section">
<view class="section-title">问题类型</view>
@@ -21,7 +21,7 @@
</view>
<!-- 图片上传 -->
<!-- <view class="upload-section">
<!-- <view class="upload-section">
<view class="section-title">图片上传选填</view>
<view class="upload-grid">
<view class="upload-item" v-for="(img, index) in images" :key="index">
@@ -46,7 +46,7 @@
<view class="submit-section">
<view class="submit-btn" @click="submitFeedback">提交反馈</view>
</view>
</form>
<!-- </form> -->
</view>
</template>
@@ -55,10 +55,11 @@
ref
} from 'vue'
import {
URL
URL,
appid
} from '../../config/url'
import {
addUserFeedback
uploadOssResource
} from '../../config/user'
// 响应式数据
@@ -78,8 +79,25 @@
const chooseImage = () => {
uni.chooseImage({
count: 3 - images.value.length,
success: (res) => {
images.value = [...images.value, ...res.tempFilePaths]
success: async (res) => {
const toUpload = res.tempFilePaths || []
for (const localPath of toUpload) {
// 先追加本地预览,再上传并替换为远程URL
images.value.push(localPath)
try {
const remoteUrl = await uploadOssResource(localPath)
const idx = images.value.indexOf(localPath)
if (idx !== -1) {
images.value.splice(idx, 1, remoteUrl)
}
} catch (e) {
const idx = images.value.indexOf(localPath)
if (idx !== -1) {
images.value.splice(idx, 1)
}
uni.showToast({ title: '图片上传失败', icon: 'none' })
}
}
}
})
}
@@ -126,18 +144,43 @@
phone: contact.value,
// images: images.value
}
const res = await addUserFeedback(feedbackData);
if (res.code == 200) {
uni.showToast({
title: '反馈成功',
icon: 'success'
})
} else {
uni.showToast({
title: '反馈失败',
icon: 'none'
})
}
uni.request({
url: `${apiUrl}/app/feedback/add`,
method: 'POST',
data: feedbackData,
header: {
'Content-Type': 'application/json',
'appid': appid,
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
},
dataType: 'json',
success: (res) => {
// 兼容后端返回 { code: 200 } 或 HTTP 200 情况
if ((res.statusCode === 200) && ((res.data && res.data.code === 200) || res.data === true || res.data?.success === true)) {
uni.showToast({
title: '反馈成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack();
}, 1500);
return
}
uni.showToast({
title: (res.data && (res.data.msg || res.data.message)) || '反馈失败',
icon: 'none'
})
},
fail: (err) => {
console.error('feedback request failed:', err)
uni.showToast({
title: '网络错误,请稍后重试',
icon: 'none'
})
}
})
}
</script>
+18 -3
View File
@@ -128,6 +128,18 @@
</template>
<script setup>
const redirectToLogin = () => {
try {
const pages = getCurrentPages()
const current = pages && pages.length ? pages[pages.length - 1] : null
const route = current && current.route ? ('/' + current.route) : '/pages/index/index'
const query = current && current.options ? Object.keys(current.options).map(k => `${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
uni.reLaunch({ url: `/pages/login/index?redirect=${redirect}` })
} catch (e) {
uni.reLaunch({ url: '/pages/login/index' })
}
}
import {
ref,
computed,
@@ -318,7 +330,8 @@
const loadPositions = async () => {
try {
if (!uni.getStorageSync('token')) {
await wxLogin()
redirectToLogin()
return
}
const res = await uni.request({
@@ -387,7 +400,8 @@
const loadPositionsByCenter = async (center) => {
try {
if (!uni.getStorageSync('token')) {
await wxLogin()
redirectToLogin()
return
}
// 使用原有接口获取所有场地
@@ -511,7 +525,8 @@
}
if (!uni.getStorageSync('token')) {
await wxLogin()
redirectToLogin()
return
}
// 检查是否有使用中的订单
+150
View File
@@ -0,0 +1,150 @@
<template>
<view class="login-container">
<view class="logo">
<image src="/static/logo.png" mode="aspectFit" />
<text class="app-name">共享风扇</text>
</view>
<view class="title">登录您的账号</view>
<view class="subtitle">为保障使用体验请先完成登录</view>
<!-- 微信一键手机号快捷登录推荐 -->
<button class="btn primary" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
手机号快捷登录
</button>
<!-- 仅微信登录不授权手机号时使用 -->
<button class="btn outline" @click="onWeChatLogin">仅微信登录</button>
<view class="tips">登录即表示同意用户协议隐私政策</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { wxLogin, getUserPhoneNumber, getUserInfo } from '../../util/index.js'
const redirect = ref('/pages/index/index')
const navigateAfterLogin = async () => {
try {
// 可选:刷新一次用户信息
await getUserInfo().catch(() => {})
} catch (e) {}
// 读取跳转路径(支持 tabBar 页面)
const target = '/pages/index/index'
const tabPages = ['/pages/index/index', '/pages/my/index']
if (tabPages.includes(target)) {
uni.switchTab({ url: target })
return
}
uni.reLaunch({ url: target })
}
const onWeChatLogin = async () => {
try {
await wxLogin()
uni.showToast({ title: '登录成功', icon: 'success' })
await navigateAfterLogin()
} catch (error) {
uni.showToast({ title: error.message || '登录失败', icon: 'none' })
}
}
const onGetPhoneNumber = async (e) => {
if (!e || e.detail.errMsg !== 'getPhoneNumber:ok') {
uni.showToast({ title: '已取消手机号授权', icon: 'none' })
return
}
try {
// 先微信登录,获取 token
await wxLogin()
// 再用微信返回的临时 code 换取手机号
await getUserPhoneNumber(e.detail.code)
uni.showToast({ title: '登录成功', icon: 'success' })
await navigateAfterLogin()
} catch (error) {
uni.showToast({ title: error.message || '登录失败', icon: 'none' })
}
}
onLoad((opts) => {
if (opts && opts.redirect) {
try {
redirect.value = decodeURIComponent(opts.redirect)
} catch (_) {}
}
})
</script>
<style lang="scss" scoped>
.login-container {
min-height: 100vh;
background: #f8f8f8;
padding: 80rpx 40rpx 40rpx;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
.logo {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 60rpx;
image {
width: 160rpx;
height: 160rpx;
margin-bottom: 16rpx;
}
.app-name {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
.title {
font-size: 40rpx;
font-weight: 600;
color: #222;
margin-bottom: 12rpx;
}
.subtitle {
font-size: 26rpx;
color: #888;
margin-bottom: 60rpx;
}
.btn {
width: 100%;
height: 96rpx;
border-radius: 48rpx;
font-size: 32rpx;
margin-bottom: 24rpx;
}
.primary {
background: #1976D2;
color: #fff;
}
.outline {
background: #fff;
color: #1976D2;
border: 2rpx solid #1976D2;
}
.tips {
margin-top: 24rpx;
font-size: 22rpx;
color: #999;
}
}
</style>
+15 -2
View File
@@ -149,8 +149,8 @@
try {
const token = uni.getStorageSync('token');
if (!token) {
await wxLogin();
return;
redirectToLogin()
return
}
const res = await getUserInfo();
@@ -183,6 +183,19 @@
}
};
const redirectToLogin = () => {
try {
const pages = getCurrentPages()
const current = pages && pages.length ? pages[pages.length - 1] : null
const route = current && current.route ? ('/' + current.route) : '/pages/index/index'
const query = current && current.options ? Object.keys(current.options).map(k => `${k}=${encodeURIComponent(current.options[k])}`).join('&') : ''
const redirect = encodeURIComponent(query ? `${route}?${query}` : route)
uni.reLaunch({ url: `/pages/login/index?redirect=${redirect}` })
} catch (e) {
uni.reLaunch({ url: '/pages/login/index' })
}
}
// 导航到指定页面
const navigateTo = (url) => {
uni.navigateTo({