赞
踩
界面如下:
<template> <view class="container"> <input v-model="username" placeholder="用户名" /> <input v-model="password" type="password" placeholder="密码" /> <button @click="handleLogin">登录</button> <text v-if="errorMessage" class="error">{{ errorMessage }}</text> <view class="link"> <text>没有帐号?</text> <button @click="goreg">注册</button> </view> </view> </template> <script> import { mapActions } from 'vuex'; export default { data() { return { username: '', password: '', errorMessage: '' }; }, methods: { ...mapActions(['login', 'fetchUser']), validateInput() { const usernameRegex = /^[a-zA-Z0-9]{6,12}$/; const passwordRegex = /^[a-zA-Z0-9]{6,12}$/; if (!usernameRegex.test(this.username)) { this.errorMessage = '用户名必须是6到12位的字母或数字'; return false; } if (!passwordRegex.test(this.password)) { this.errorMessage = '密码必须是6到12位的字母或数字'; return false; } return true; }, async handleLogin() { if (!this.validateInput()) { return; } try { //用户名 6~12位 密码 6~12位 console.log('Attempting login...'); await this.login({ username: this.username, password: this.password }); } catch (error) { this.errorMessage = '登陆失败'; } }, goreg() { uni.navigateTo({ url: '/pages/index/register' }); } }, async mounted() { const token = uni.getStorageSync('token'); if (token) { try { // Attempt to fetch user data with the token await this.fetchUser(); // Redirect to the friends page if the user is authenticated uni.redirectTo({ url: '/pages/index/friends' }); } catch (error) { console.error('Failed to fetch user:', error); this.errorMessage = '自动登录失败,请重新登录'; } } } }; </script> <style> .container { padding: 20px; } input { display: block; margin: 10px 0; } button { display: block; margin: 10px 0; } .error { color: red; } .link { margin-top: 20px; text-align: center; } .link button { background-color: #007aff; color: white; border: none; padding: 10px; border-radius: 5px; } </style>
注册页:
<template> <view class="container"> <input v-model="username" placeholder="用户名" /> <input v-model="password" type="password" placeholder="密码" /> <button @click="register">注册</button> <text v-if="errorMessage" class="error">{{ errorMessage }}</text> <view class="link"> <text>已有帐号?</text> <button @click="goToLogin">登录</button> </view> </view> </template> <script> import config from '@/config/config.js'; export default { data() { return { username: '', password: '', errorMessage: '' }; }, methods: { validateInput() { const usernameRegex = /^[a-zA-Z0-9]{6,12}$/; const passwordRegex = /^[a-zA-Z0-9]{6,12}$/; if (!usernameRegex.test(this.username)) { this.errorMessage = '用户名必须是6到12位的字母或数字'; return false; } if (!passwordRegex.test(this.password)) { this.errorMessage = '密码必须是6到12位的字母或数字'; return false; } return true; }, async register() { if (!this.validateInput()) { return; } try { const [error, response] = await uni.request({ url: config.apiBaseUrl + '/register', method: 'POST', data: { username: this.username, password: this.password } }); if (response.data.success) { uni.navigateTo({ url: '/pages/index/login' }); this.errorMessage = ''; // 清除任何以前的错误消息 } else { this.errorMessage = response.data.error; } } catch (error) { console.error(error); this.errorMessage = '发生错误'; } }, goToLogin() { uni.navigateTo({ url: '/pages/index/login' }); } } }; </script> <style> .container { padding: 20px; } input { display: block; margin: 10px 0; } button { display: block; margin: 10px 0; } .error { color: red; } .link { margin-top: 20px; text-align: center; } .link button { display: block; background-color: #007aff; color: white; border: none; padding: 10px; border-radius: 5px; } </style>
在store加入index.js:
import Vue from 'vue'; import Vuex from 'vuex'; import config from '@/config/config.js'; Vue.use(Vuex); export default new Vuex.Store({ state: { token: uni.getStorageSync('token') || '', // 从本地存储中获取 token user: null, // 用户信息 friends: [], // 好友列表 groups: [], lastMessages: {}, // 新增状态,用于存储最后一条消息 hasMoreFriends: true // 新增状态用于跟踪是否有更多好友 }, mutations: { SET_TOKEN(state, token) { state.token = token; uni.setStorageSync('token', token); // 保存到本地存储 }, CLEAR_TOKEN(state) { state.token = ''; uni.removeStorageSync('token'); // 从本地存储中删除 }, SET_USER(state, user) { state.user = user; }, SET_FRIENDS(state, { friends, hasMoreFriends }) { state.friends = friends; state.hasMoreFriends = hasMoreFriends; }, SET_GROUPS(state, groups) { state.groups = groups; }, SET_LAST_MESSAGE(state, { id, message }) { Vue.set(state.lastMessages, id, message); // 动态设置最后一条消息 } }, actions: { async fetchGroups({ commit }) { const token = uni.getStorageSync('token'); const [error, response] = await uni.request({ url: `${config.apiBaseUrl}/groups`, method: 'GET', header: { 'Authorization': `Bearer ${token}` } }); if (!error && response.data.code == 0) { commit('SET_GROUPS', response.data.data); } logoutpub(response, commit); }, async createGroup({ state }, { name, description, avatar_url }) { try { const token = uni.getStorageSync('token'); const [error, response] = await uni.request({ url: `${config.apiBaseUrl}/groups`, method: 'POST', header: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, data: { name, description, avatar_url } }); logoutpub(response, commit); return response.data; } catch (error) { throw error; } }, async login({ commit }, { username, password }) { try { const [error, response] = await uni.request({ url: `${config.apiBaseUrl}/login`, method: 'POST', data: { username, password } }); if (error) { throw new Error(`Request failed with error: ${error}`); } response.data = response.data.data; if (response.data.token) { commit('SET_TOKEN', response.data.token); uni.redirectTo({ url: '/pages/index/friends' }); } else { throw new Error('Invalid credentials'); } } catch (error) { console.error('Login error:', error); throw error; } }, async fetchUser({ commit }) { const token = uni.getStorageSync('token'); if (!token) return; try { const [error, response] = await uni.request({ url: `${config.apiBaseUrl}/user`, method: 'GET', header: { 'Authorization': `Bearer ${token}` } }); logoutpub(response, commit); if (error) { throw new Error(`Request failed with error: ${error}`); } if (response.statusCode === 200) { const userData = response.data.data || response.data; commit('SET_USER', userData); } else { throw new Error('Failed to fetch user data'); } } catch (error) { console.error('Failed to fetch user:', error); } }, async fetchFriends({ commit }, { page = 1, perPage = 20 }) { const token = uni.getStorageSync('token'); if (!token) return; try { const [error, response] = await uni.request({ url: `${config.apiBaseUrl}/friends`, method: 'GET', header: { 'Authorization': `Bearer ${token}` }, data: { page, perPage } }); console.log("friends",response) logoutpub(response, commit); if (error) { throw new Error(`Request failed with error: ${error}`); } if (response.data) { commit('SET_FRIENDS', { friends: response.data.data, hasMoreFriends: response.data.hasMoreFriends }); } } catch (error) { console.error(error); } }, async handleNewMessage({ commit }, { id, message }) { try { // 假设这是接收消息的逻辑 commit('SET_LAST_MESSAGE', { id, message }); } catch (error) { console.error('Failed to handle new message:', error); } }, logout({ commit }) { commit('CLEAR_TOKEN'); commit('SET_USER', null); commit('SET_FRIENDS', { friends: [], hasMoreFriends: true }); uni.redirectTo({ url: '/pages/index/login' // 跳转到登录页面 }); } } }); // Helper function for handling token expiration function logoutpub(response, commit) { if (response.data && response.data.code === -1 && response.data.message === 'expire') { commit('CLEAR_TOKEN'); commit('SET_USER', null); commit('SET_FRIENDS', { friends: [], hasMoreFriends: true }); uni.redirectTo({ url: '/pages/index/login' // 跳转到登录页面 }); } }
在config创建config.js:
const config = {
apiBaseUrl: 'http://localhost:3000'
};
export default config;
用户登陆后进入到friends页。
界面代码为:
<template> <view class="friends-container"> <view v-if="!isLoggedIn" class="not-logged-in"> <text>您尚未登录。请先登录以查看好友列表。</text> <button @click="goToLogin">去登录</button> </view> <view> <view v-if="friends.length === 0"> <text>您还没有添加任何好友。</text> <uni-list> <uni-list-chat :avatar-circle="true" title="增加好友/群" note="输入用户帐号或群号" :avatar="'../../static/addfriend.png'" showArrow link @click="gotadd()"></uni-list-chat> </uni-list> </view> <view v-if="friends.length > 0"> <uni-list> <uni-list-chat :avatar-circle="true" title="增加好友/群" note="输入用户帐号或群号" :avatar="'../../static/addfriend.png'" showArrow link @click="gotadd()"></uni-list-chat> </uni-list> <uni-list> <uni-list-chat v-for="(friend, index) in friends" :key="index" :title="friend.type === 'group' ? ('[群]'+friend.group.name) : friend.user.username" :avatar-circle="true" :avatar="friend.type === 'group' ? friend.group.avatar_url : friend.user.avatar_url" :note="friend.message || '暂无信息'" :time="friend.time" badge-position="left" badge-text="188" showArrow link @click="toChat(friend)" ></uni-list-chat> </uni-list> </view> <button @click="loadMoreFriends" v-if="hasMoreFriends">加载更多</button> </view> <uni-popup ref="popupBag" type="center"> <view class="bagDetail"> <view class="title flex align-center justify-content-between"> <view class="flex-sub">添加好友</view> <view class="close-button" style="font-size: 22px;" @tap="closepopupBag">×</view> </view> <uni-list :border="true"> <uni-list-item title="增加好友或群" note="请输入正确的帐号或群号" badge-position="right" badge-text="dot" link @tap="goaddurl"></uni-list-item> <uni-list-item title="创建自己的群" note="群号创建后不能修改" badge-position="right" badge-text="dot" link @tap="gogroupurl"></uni-list-item> </uni-list> </view> </uni-popup> <button @click="myself()">我的信息</button> </view> </template> <script> import { mapState, mapActions } from 'vuex'; import io from 'socket.io-client'; import config from '@/config/config.js'; export default { data() { return { page: 1, perPage: 20, loading: false, hasMoreFriends: false, message:'', friendlist:[] }; }, computed: { ...mapState(['friends', 'token', 'lastMessages']), isLoggedIn() { return !!this.token; }, }, methods: { ...mapActions(['fetchFriends']), async getmsg() { this.socket.on('message', (msg) => { this.friends.forEach((friend, index) => { if (friend.id == msg.group_name) { this.$set(this.friends, index, { ...friend, message: msg.content,type:msg.type }); } }); }); }, async loadFriends() { if (!this.isLoggedIn) return; this.loading = true; try { await this.fetchFriends({ page: this.page, perPage: this.perPage }); this.page++; } catch (error) { console.error('Failed to load friends:', error); this.loading = false; } finally { this.loading = false; } }, toChat(item) { console.log(":::::item.type::::",item.type) if(item.type=='user'){ uni.navigateTo({ url: '/pages/index/chat?id=' + item.id + '&type=' + item.type + '&tid='+item.group_friend_id }); }else{ uni.navigateTo({ url: '/pages/index/chat?id=' + "g_"+item.group_friend_id + '&type=' + item.type + '&tid='+item.group_friend_id }); } }, loadMoreFriends() { this.page++; this.loadFriends(); }, goToLogin() { uni.navigateTo({ url: '/pages/index/login' }); }, gotadd() { this.$refs.popupBag.open(); }, goaddurl() { this.closepopupBag(); uni.navigateTo({ url: '/pages/index/addfriend' }); }, gogroupurl() { this.closepopupBag(); uni.navigateTo({ url: '/pages/index/addgroup' }); }, myself() { uni.navigateTo({ url: '/pages/index/profile' }); }, closepopupBag() { this.$refs.popupBag.close(); }, getLastMessage(id) { console.log('Getting last message for ID:', id); return this.lastMessages && this.lastMessages[id] ? this.lastMessages[id] : '暂无信息'; } }, mounted() { if (this.isLoggedIn) { this.loadFriends(); } this.socket = io('http://127.0.0.1:3000'); this.socket.on('connect', () => { console.log('Socket connected:', this.socket.id); }); this.socket.on('disconnect', () => { console.log('Socket disconnected'); }); this.getmsg(); } }; </script> <style> .container { padding: 20px; } .bagDetail { padding:10px; width: 100%; height: 30%; position: fixed; background-color: #ffffff; left: 0; display: flex; flex-direction: column; } #messages { height: 300px; overflow-y: scroll; border: 1px solid #ccc; margin-bottom: 10px; } input { display: block; margin: 10px 0; } button { display: block; margin: 10px 0; } .user-list { margin-top: 20px; border: 1px solid #ccc; padding: 10px; } .title { display: flex; justify-content: space-between; align-items: center; width: 100%; padding: 10px; } .close-button { font-size: 22px; cursor: pointer; } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。