2025-09-16

This commit is contained in:
2025-09-16 16:05:34 +08:00
parent 178bd0d1e9
commit 4df905f3cf
570 changed files with 352745 additions and 97 deletions

View File

@@ -13,18 +13,18 @@
<u-form :model="userLogin.userForm" ref="userLoginRef" :border-bottom="false" :error-type="['message']"
label-width="0">
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/user.png" prop="username">
<u-input v-model="userLogin.userForm.username" placeholder="请输入用户名或手机号"
<u-input v-model="userLogin.userForm.username" placeholder="请输入用户名或手机号" type="number" maxlength="11"
placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Lock.png" prop="password">
<u-input type="password" v-model="userLogin.userForm.password" placeholder="请输入密码"
<u-input type="password" v-model="userLogin.userForm.password" placeholder="请输入密码" maxlength="20"
placeholder-style="color: #737373;" />
</u-form-item>
<u-form-item :left-icon-style="inputIcon" left-icon="../../static/icon/Globe.png" prop="captcha">
<u-input v-model="userLogin.userForm.captcha" placeholder="请输入验证码"
<u-input v-model="userLogin.userForm.captcha" placeholder="请输入验证码" maxlength="4"
placeholder-style="color: #737373;" />
<template v-slot:right>
<image class="captcha-img" :src="captcha" mode=""></image>
<image @click="loadCaptcha" class="captcha-img" :src="captcha" mode=""></image>
</template>
</u-form-item>
<view class="reflash" @click="reflash">
@@ -51,6 +51,7 @@
import { onMounted, reactive, ref } from 'vue';
import { onLoad, onReady } from '@dcloudio/uni-app';
import { captchaAPI } from '@/api/captcha.js';
import { authAPI } from '../../api/auth';
// 表单图标样式
const inputIcon = {
@@ -60,6 +61,7 @@
// 登录表单
const captcha = ref()
const captchaId = ref()
const userLoginRef = ref()
const userLogin = reactive({
userForm: {
@@ -74,6 +76,11 @@
required: true,
message: '请输入用户名或手机号',
trigger: ['change']
},
{
pattern: /^1[3-9]\d{9}$/,
message: '请输入正确的手机号格式',
trigger: ['blur']
}
],
password: [
@@ -83,13 +90,17 @@
trigger: ['change']
}
],
code: [
{
required: true,
message: '请输入验证码',
trigger: ['change']
}
]
captcha: [{
required: true,
message: '请输入验证码',
trigger: ['blur']
},
{
min: 4,
max: 4,
message: '验证码长度为4位',
trigger: 'blur'
}],
}
})
@@ -100,6 +111,7 @@
onMounted(() => {
loadCaptcha()
loadCache()
})
// 刷新
@@ -112,14 +124,80 @@
const loadCaptcha = () => {
captchaAPI.generate().then(res => {
captcha.value = res.data.image
captchaId.value = res.data.captchaId
})
}
const loadCache = () =>{
let is_rember = uni.getStorageSync("rember")
if(is_rember){
userLogin.userForm.is_rember = true
let data = JSON.parse(is_rember)
userLogin.userForm.username = data.username
userLogin.userForm.password = data.password
}
}
// 登录处理
const submit = () => {
userLoginRef.value.validate((valid : any) => {
if (valid) {
console.log('验证通过');
// 登录逻辑
const loginData = {
username: userLogin.userForm.username,
password: userLogin.userForm.password,
captchaId: captchaId.value,
captchaText: userLogin.userForm.captcha
}
authAPI.login(loginData).then(response => {
console.log('登录结果', response);
if (response.success) {
// 激活用户
uni.setStorageSync("token", response.token)
if (userLogin.userForm.is_rember) {
uni.setStorageSync("rember", {
username: userLogin.userForm.username,
password: userLogin.userForm.password,
})
}
uni.showToast({
title: '登录成功',
icon: 'success',
success() {
setTimeout(() => {
uni.switchTab({
url: '/pages/home/index'
})
}, 1000)
}
})
} else if (response.token) {
// 未激活用户
uni.setStorageSync("token", response.token)
if (userLogin.userForm.is_rember) {
uni.setStorageSync("rember", JSON.stringify({
username: userLogin.userForm.username,
password: userLogin.userForm.password,
}))
}
uni.showToast({
title: '登录成功',
icon: 'success',
success() {
setTimeout(() => {
uni.switchTab({
url: '/pages/home/index'
})
}, 1000)
}
})
}
}).catch((err) => {
setTimeout(() => {
userLogin.userForm.captcha = ''
loadCaptcha()
}, 1000)
})
}
});
}

View File

@@ -1,12 +1,222 @@
<template>
<Tabbar></Tabbar>
<view class="message-container">
<!-- 固定背景的容器 -->
<view class="background-container"></view>
<!-- 可滚动的内容区域 -->
<view class="content-container" :style="'height:'+height+'px'">
<view class="message-title">
容讯聊天室
</view>
<u-row class="message-search">
<u-col span="9">
<u-search placeholder="点击查询项目" v-model="keyword" :show-action="false"></u-search>
</u-col>
<u-col class="collection" span="3">
<image class="collection-icon" src="/static/icon/Bookmark.png" mode=""></image>
<view class="collection-text">
我的收藏
</view>
</u-col>
</u-row>
<view class="menu-list">
<view class="menu-item" v-for="(item,index) in menuList" @click="handleMenuChange(index)">
<view class="menu-title">{{item.name + '(' + item.count +')'}}
</view>
<image class="menu-icon"
:src="currentMenu==index?'/static/icon/Chevron down.png':'/static/icon/Chevron right Menu.png'"
mode=""></image>
</view>
</view>
<view class="program-list">
<view class="program-item" v-for="item in programList">
{{item.programName}}
</view>
</view>
</view>
<Tabbar id="tabbarId"></Tabbar>
</view>
</template>
<script setup lang="ts">
import { ref, computed, getCurrentInstance } from 'vue';
import {
onReady
} from '@dcloudio/uni-app';
import { onReady as onUniReady } from '@dcloudio/uni-app';
const instance = getCurrentInstance();
const height = ref(0)
const loadHeight = () => {
uni.getSystemInfo({
success(res) {
let screenHeight = res.screenHeight
uni.createSelectorQuery().in(instance.proxy).select("#tabbarId").boundingClientRect((data : any) => {
height.value = screenHeight - data.height
}).exec()
}
})
}
// 搜索
const keyword = ref('')
// 小菜单切换
const menuList = ref([{
name: '全部',
count: 5
}, {
name: '已投资',
count: 5
}, {
name: '未读',
count: 0
}, {
name: '不感兴趣',
count: 5
}])
// 当前小菜单
const currentMenu = ref(0)
// 切换小菜单
const handleMenuChange = (val) => {
currentMenu.value = val
}
// 项目
const programList = ref([])
const mockData = () => {
for (var i = 0; i < 20; i++) {
programList.value.push({
programName: "test" + i
})
}
}
onUniReady(() => {
loadHeight()
// 模拟数据
mockData()
})
</script>
<style>
<style lang="scss" scoped>
.message-container {
width: 100%;
position: fixed;
top: 0;
left: 0;
height: 100%;
overflow: hidden;
/* 防止容器本身滚动 */
</style>
/* 固定背景 */
.background-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, #2F75F9 0%, #F0F3FF 34.13%);
z-index: 1;
/* 确保背景在内容下方 */
}
/* 内容滚动区域 */
.content-container {
position: relative;
z-index: 2;
/* 确保内容在背景上方 */
width: 100%;
overflow-y: scroll;
height: 100%;
padding: 32rpx;
.message-title {
margin-top: 40rpx;
text-align: center;
font-family: SF Pro;
font-weight: 700;
font-style: Bold;
font-size: 40rpx;
leading-trim: NONE;
line-height: 48rpx;
letter-spacing: 0%;
color: #FFFFFF;
}
.message-search {
margin-top: 20rpx;
.collection {
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
.collection-icon {
width: 48rpx;
height: 48rpx;
}
.collection-text {
font-family: SF Pro;
font-weight: 30;
font-style: Expanded Ultralight;
font-size: 24rpx;
leading-trim: NONE;
line-height: 26px;
letter-spacing: 0%;
color: #FFFFFF;
}
}
}
.menu-list {
margin-top: 20rpx;
display: flex;
justify-content: space-around;
.menu-item {
display: flex;
align-items: center;
.menu-title {
font-family: SF Pro;
font-weight: 30;
font-style: Expanded Ultralight;
font-size: 24rpx;
leading-trim: NONE;
line-height: 42rpx;
letter-spacing: 0%;
color: #000;
}
.menu-icon {
width: 22rpx;
height: 22rpx;
}
}
}
.program-list {
margin-top: 10rpx;
.program-item {
// border: 1px solid #000;
padding: 20rpx 10px;
background-color: #FFFFFF;
border-radius: 10rpx;
margin-bottom: 10rpx;
}
}
}
}
</style>

View File

@@ -1,12 +1,26 @@
<template>
<view class="my-container">
<u-button @click="loginOut">退出登录</u-button>
</view>
<Tabbar></Tabbar>
</template>
<script setup lang="ts">
const loginOut = () => {
uni.removeStorageSync("token")
uni.redirectTo({
url: '/pages/login/login'
})
}
</script>
<style>
</style>
<style scoped lang="scss">
.my-container {
}
</style>

View File

@@ -0,0 +1,73 @@
<template>
<view class="message-container">
<!-- 固定背景的容器 -->
<view class="background-container"></view>
<!-- 可滚动的内容区域 -->
<view class="content-container" :style="'height:'+height+'px'">
</view>
<Tabbar id="tabbarId"></Tabbar>
</view>
</template>
<script setup lang="ts">
import { ref, computed, getCurrentInstance } from 'vue';
import {
onReady
} from '@dcloudio/uni-app';
import { onReady as onUniReady } from '@dcloudio/uni-app';
const instance = getCurrentInstance();
const height = ref(0)
const loadHeight = () => {
uni.getSystemInfo({
success(res) {
let screenHeight = res.screenHeight
uni.createSelectorQuery().in(instance.proxy).select("#tabbarId").boundingClientRect((data : any) => {
height.value = screenHeight - data.height
}).exec()
}
})
}
onUniReady(() => {
loadHeight()
})
</script>
<style lang="scss" scoped>
.message-container {
width: 100%;
position: fixed;
top: 0;
left: 0;
height: 100%;
overflow: hidden;
/* 防止容器本身滚动 */
/* 固定背景 */
.background-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, #2F75F9 0%, #F0F3FF 34.13%);
z-index: 1;
/* 确保背景在内容下方 */
}
/* 内容滚动区域 */
.content-container {
position: relative;
z-index: 2;
/* 确保内容在背景上方 */
width: 100%;
overflow-y: scroll;
height: 100%;
padding: 32rpx;
}
}
</style>

View File

@@ -131,9 +131,11 @@
// 选择省市区
const handleRegion = (e) => {
console.log(e);
userRegister.userRegisterForm.regionLabel = e[0].label + "/" + e[1].label + "/" + e[2].label
userRegister.userRegisterForm.region = e[2].value
userRegister.userRegisterForm.province = e[0].value
userRegister.userRegisterForm.city = e[1].value
userRegister.userRegisterForm.district = e[2].value
userRegister.userRegisterForm.district_id = e[2].value
}
@@ -162,10 +164,11 @@
callback(new Error('密码必须包含字母和数字'));
} else {
// 如果确认密码已输入,重新验证确认密码
if (userRegister.userRegisterForm.confirmPassword) {
userRegisterRef.value?.validateField('confirmPassword');
}
callback();
// if (userRegister.userRegisterForm.confirmPassword && userRegister.userRegisterForm.confirmPassword == userRegister.userRegisterForm.password) {
// return true
// }
// callback(new Error('两次输入的密码不一致'));
return true
}
};
@@ -183,14 +186,17 @@
const userRegisterRef = ref()
const userRegister = reactive({
userRegisterForm: {
username: '13758452159',
phone: '13758452159',
smsCode: 'asrfdv',
region: '',
username: '',
phone: '',
smsCode: '',
province: '',
city: '',
district: '',
district_id: '',
regionLabel: '',
password: 's123456s',
confirmPassword: 's123456s',
captcha: 'vfjs',
password: '',
confirmPassword: '',
captcha: '',
},
rules: {
phone: [{
@@ -238,8 +244,7 @@
max: 4,
message: '验证码长度为4位',
trigger: 'blur'
}
],
}],
}
})
@@ -252,47 +257,54 @@
})
return
}
// 等待表单验证完成
const valid = await userRegisterRef.value.validate();
if (valid) {
console.log(valid);
try {
userRegisterRef.value.validate((valid : any) => {
if (valid) {
// 验证通过后执行的逻辑
console.log('表单验证通过', userRegister.userRegisterForm);
// 提交注册
const registerData = {
username: userRegister.userRegisterForm.phone,
phone: userRegister.userRegisterForm.phone,
province: userRegister.userRegisterForm.province,
city: userRegister.userRegisterForm.city,
district: userRegister.userRegisterForm.district,
district_id: userRegister.userRegisterForm.district_id,
password: userRegister.userRegisterForm.password,
smsCode: userRegister.userRegisterForm.smsCode,
captchaId: captchaId.value,
captchaText: userRegister.userRegisterForm.captcha,
}
authAPI.register(registerData).then(response => {
if (response.success) {
console.log('注册结果', response);
uni.setStorageSync("token", response.token)
uni.setStorageSync("user", response.user)
uni.showToast({
title: '注册成功',
success() {
setTimeout(() => {
uni.switchTab({
url: '/pages/home/index'
})
}, 1000)
}
})
}
}).catch((err) => {
setTimeout(() => {
userRegister.userRegisterForm.captcha = ''
loadCaptcha()
}, 1000)
})
}
});
} catch (error) {
// 验证失败时会进入这里,无需额外处理(表单会自动显示错误信息)
console.log('表单验证失败', error);
}
// userRegisterRef.value.validate((valid : any) => {
// if (valid) {
// // 验证验证码
// captchaAPI.verify({
// captchaId: captchaId.value,
// captchaText: userRegister.userRegisterForm.captcha
// }).then(verifyResponse => {
// console.log(verifyResponse);
// if (!verifyResponse.data.success) {
// uni.showToast({
// title: verifyResponse.data.message || '验证码错误',
// icon: 'error'
// })
// // 重新加载验证码
// loadCaptcha()
// return
// }
// })
// const registerData = {
// username: userRegister.userRegisterForm.phone,
// phone: userRegister.userRegisterForm.phone,
// city: userRegister.userRegisterForm.region,
// password: userRegister.userRegisterForm.password,
// smsCode: userRegister.userRegisterForm.smsCode,
// captchaId: captchaId.value,
// captchaText: userRegister.userRegisterForm.captcha,
// province: userRegister.userRegisterForm.region,
// }
// authAPI.register(registerData).then(response => {
// // 直接注册成功的情况
// // setToken(response.data.token)
// // setUser(response.data.user)
// console.log(response);
// })
// }
// })
}
// 手机验证码
@@ -314,8 +326,22 @@
// 获取手机验证码
const getMsgCode = () => {
// 校验手机号
console.log("发送验证码");
if (msgCodeRef.value.canGetCode) {
console.log("发送验证码");
captchaAPI.smsSend(userRegister.userRegisterForm.phone).then(res => {
const result = res.json();
if (result.success) {
uni.showToast({
title: '验证码发送成功,请查收短信',
icon: 'success'
})
} else {
uni.showToast({
title: result.message || '发送失败,请重试',
icon: 'error'
})
}
})
msgCodeRef.value.start();
} else {
uni.showToast({
@@ -434,7 +460,7 @@
letter-spacing: -2%;
text-align: center;
color: #3781EF;
display: ruby;
}
}