Merge pull request 'feature-nxdev' (#42) from feature-nxdev into main
Reviewed-on: #42
This commit is contained in:
commit
f565e9d8a3
@ -53,6 +53,7 @@ namespace IM_API.Controllers
|
||||
return Ok(res);
|
||||
}
|
||||
[HttpPost]
|
||||
[ProducesResponseType(typeof(BaseResponse<LoginDto>),StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Refresh(RefreshDto dto)
|
||||
{
|
||||
(bool ok,int userId) = await _refreshTokenService.ValidateRefreshTokenAsync(dto.refreshToken);
|
||||
|
||||
@ -53,8 +53,8 @@ namespace IM_API.Services
|
||||
if (json.IsNullOrEmpty) return (false,-1);
|
||||
try
|
||||
{
|
||||
var doc = JsonConvert.DeserializeObject<JsonElement>(json);
|
||||
var userId = doc.GetProperty("UserId").GetInt32();
|
||||
using var doc = JsonDocument.Parse(json.ToString());
|
||||
var userId = doc.RootElement.GetProperty("UserId").GetInt32();
|
||||
return (true,userId);
|
||||
}
|
||||
catch
|
||||
|
||||
@ -2,10 +2,15 @@ import axios from 'axios'
|
||||
import { useMessage } from '@/components/messages/useAlert';
|
||||
import router from '@/router';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { authService } from './auth';
|
||||
|
||||
const message = useMessage();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
let waitqueue = [];
|
||||
let isRefreshing = false;
|
||||
const authURL = ['/auth/login', '/auth/register', '/auth/refresh'];
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api', // 从环境变量中读取基础 URL
|
||||
timeout: 10000,
|
||||
@ -31,16 +36,50 @@ api.interceptors.response.use(
|
||||
response => {
|
||||
return response.data;
|
||||
},
|
||||
err => {
|
||||
if (err.response) {
|
||||
switch (err.response.status) {
|
||||
async err => {
|
||||
const { config, response } = err;
|
||||
if (response) {
|
||||
switch (response.status) {
|
||||
case 401:
|
||||
if (authURL.some(x => config.url.includes(x))) {
|
||||
authStore.logout();
|
||||
message.error('未登录,请登录后操作。');
|
||||
router.push('/auth/login')
|
||||
break;
|
||||
}
|
||||
if (config._retry) {
|
||||
break;
|
||||
}
|
||||
|
||||
config._retry = true;
|
||||
// 已经在刷新 → 排队
|
||||
if (isRefreshing) {
|
||||
return new Promise(resolve => {
|
||||
waitqueue.push(token => {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
resolve(api(config))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
isRefreshing = true;
|
||||
const refreshToken = authStore.refreshToken;
|
||||
console.log(authStore)
|
||||
if (refreshToken != null && refreshToken != '') {
|
||||
const res = await authService.refresh(refreshToken)
|
||||
authStore.setLoginInfo(res.data.token, res.data.refreshToken, res.data.userInfo)
|
||||
waitqueue.forEach(cb => cb(authStore.token));
|
||||
waitqueue = [];
|
||||
config.headers.Authorization = `Bearer ${authStore.token}`
|
||||
return api(config)
|
||||
}
|
||||
authStore.logout();
|
||||
message.error('未登录,请登录后操作。');
|
||||
router.push('/auth/login')
|
||||
break;
|
||||
case 400:
|
||||
if (err.response.data && err.response.data.code == 1003) {
|
||||
message.error(err.response.data.message);
|
||||
if (response.data && response.data.code == 1003) {
|
||||
message.error(response.data.message);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@ -13,5 +13,11 @@ export const authService = {
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
register: (data) => request.post('/auth/register', data)
|
||||
register: (data) => request.post('/auth/register', data),
|
||||
/**
|
||||
* 刷新用户凭证
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
refresh: (refreshToken) => request.post('/auth/refresh', { refreshToken })
|
||||
}
|
||||
@ -4,10 +4,10 @@ import { defineStore } from 'pinia'
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const token = ref(localStorage.getItem('user_token') || '');
|
||||
const refreshToken = ref(localStorage.getItem('refresh_token') || '');
|
||||
const userInfo = ref(localStorage.getItem('user_info') || '');
|
||||
const userInfo = ref(JSON.parse(localStorage.getItem('user_info')) || {});
|
||||
|
||||
//判断是否已登录
|
||||
const isLoggedIn = computed(() => !!token.value);
|
||||
const isLoggedIn = computed(() => !!refreshToken.value);
|
||||
|
||||
/**
|
||||
* 登录成功保存状态
|
||||
@ -15,12 +15,13 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
* @param {*} user 用户信息
|
||||
*/
|
||||
function setLoginInfo(newToken, newRefreshToken, user) {
|
||||
console.log(`设置凭证:\ntoken:${newToken}\nrefreshToken:${newRefreshToken}`)
|
||||
token.value = newToken;
|
||||
refreshToken.value = newRefreshToken
|
||||
userInfo.value = user;
|
||||
localStorage.setItem('user_token', newToken);
|
||||
localStorage.setItem('refresh_token', refreshToken)
|
||||
localStorage.setItem('user_info', user)
|
||||
localStorage.setItem('refresh_token', newRefreshToken)
|
||||
localStorage.setItem('user_info', JSON.stringify(user))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,10 +30,11 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
function logout() {
|
||||
token.value = '';
|
||||
userInfo.value = null;
|
||||
refreshToken.value = ''
|
||||
localStorage.removeItem('user_token');
|
||||
localStorage.removeItem('refresh_token')
|
||||
localStorage.removeItem('user_info')
|
||||
}
|
||||
|
||||
return { token, userInfo, isLoggedIn, setLoginInfo, logout };
|
||||
return { token, refreshToken, userInfo, isLoggedIn, setLoginInfo, logout };
|
||||
})
|
||||
|
||||
@ -30,9 +30,9 @@
|
||||
class="list-item"
|
||||
:class="{active: activeContactId === c.id}"
|
||||
@click="activeContactId = c.id">
|
||||
<img :src="c.avatar" class="avatar-std" />
|
||||
<img :src="c.userInfo.avatar" class="avatar-std" />
|
||||
<div class="info">
|
||||
<div class="name">{{ c.name }}</div>
|
||||
<div class="name">{{ c.remarkName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -43,21 +43,21 @@
|
||||
<header class="profile-header">
|
||||
<div class="text-info">
|
||||
<h2 class="display-name">
|
||||
{{ currentContact.name }}
|
||||
<span :class="['gender-tag', currentContact.gender]">
|
||||
{{ currentContact.gender === 'm' ? '♂' : '♀' }}
|
||||
{{ currentContact.remarkName }}
|
||||
<span :class="['gender-tag', 'm']">
|
||||
{{ '♂' }}
|
||||
</span>
|
||||
</h2>
|
||||
<p class="sub-text">微信号:{{ currentContact.wxid }}</p>
|
||||
<p class="sub-text">地区:{{ currentContact.region }}</p>
|
||||
<p class="sub-text">账号:{{ currentContact.userInfo.username }}</p>
|
||||
<p class="sub-text">地区:{{ '未知' }}</p>
|
||||
</div>
|
||||
<img :src="currentContact.avatar" class="big-avatar" />
|
||||
<img :src="currentContact.userInfo.avatar" class="big-avatar" />
|
||||
</header>
|
||||
|
||||
<div class="profile-body">
|
||||
<div class="info-row">
|
||||
<span class="label">备注名</span>
|
||||
<span class="value">{{ currentContact.alias || '未设置' }}</span>
|
||||
<span class="label">昵称</span>
|
||||
<span class="value">{{ currentContact.userInfo.nickName }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">个性签名</span>
|
||||
@ -65,7 +65,7 @@
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">来源</span>
|
||||
<span class="value">通过搜索微信号添加</span>
|
||||
<span class="value">通过搜索账号添加</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -91,20 +91,24 @@ import { friendService } from '@/services/friend'
|
||||
const searchQuery = ref('')
|
||||
const activeContactId = ref(null)
|
||||
|
||||
const contacts1 = ref([]);
|
||||
const contacts = ref([]);
|
||||
|
||||
// 模拟联系人数据
|
||||
const contacts = ref([
|
||||
{ id: 1, name: '南浔', wxid: 'nan_xun_99', region: '浙江 杭州', avatar: 'https://i.pravatar.cc/40?1', gender: 'f', signature: '山有木兮木有枝', alias: '南酱' },
|
||||
{ id: 102, name: '老张', wxid: 'zhang_boss', region: '广东 深圳', avatar: 'https://i.pravatar.cc/40?10', gender: 'm', signature: '搞钱要紧', alias: '张总' },
|
||||
{ id: 103, name: 'UI小王', wxid: 'wang_design', region: '上海 黄浦', avatar: 'https://i.pravatar.cc/40?5', gender: 'f', signature: '不改了,真的不改了', alias: '' },
|
||||
{ id: 104, name: '测试组长', wxid: 'test_pro', region: '北京', avatar: 'https://i.pravatar.cc/40?8', gender: 'm', signature: 'Bug 哪里跑', alias: '铁面人' }
|
||||
])
|
||||
|
||||
const filteredContacts = computed(() => {
|
||||
return contacts.value.filter(c =>
|
||||
c.name.includes(searchQuery.value) || c.wxid.includes(searchQuery.value)
|
||||
)
|
||||
const searchKey = searchQuery.value.toString().trim();
|
||||
if(!searchKey){
|
||||
return contacts.value;
|
||||
}
|
||||
|
||||
|
||||
return contacts.value.filter(c => {
|
||||
if (!c) return false
|
||||
|
||||
const remark = c.remarkName || ''
|
||||
const username = c.userInfo.username || ''
|
||||
|
||||
return remark.includes(searchKey) || username.includes(searchKey)
|
||||
})
|
||||
})
|
||||
|
||||
const currentContact = computed(() => {
|
||||
@ -121,15 +125,14 @@ function handleGoToChat() {
|
||||
|
||||
const loadContactList = async (page = 1,limit = 100) => {
|
||||
const res = await friendService.getFriendList(page,limit);
|
||||
contacts1.value = res.data;
|
||||
contacts.value = res.data;
|
||||
console.log(contacts.value)
|
||||
}
|
||||
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
await loadContactList();
|
||||
const contacts = await friendService.getFriendList();
|
||||
console.log(contacts)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user