逻辑优化

This commit is contained in:
18631081161 2026-01-18 18:13:01 +08:00
parent 4ab93debc7
commit 93f7b104c8
12 changed files with 187 additions and 20 deletions

View File

@ -14,7 +14,14 @@ import { getToken } from '../utils/storage'
*/
export async function getSessions() {
const response = await get('/chat/sessions')
return response
// 统一返回格式
if (response && response.code === 0) {
return {
success: true,
data: Array.isArray(response.data) ? response.data : (response.data?.list || [])
}
}
return { success: false, data: [] }
}
/**
@ -105,8 +112,11 @@ export async function getUnreadCount() {
*/
export async function uploadVoice(filePath) {
return new Promise((resolve, reject) => {
// 简化 URL 拼接
const uploadUrl = `${config.API_BASE_URL}/upload/voice`
uni.uploadFile({
url: config.API_BASE_URL.replace('/api/app', '') + '/api/app/upload/voice',
url: uploadUrl,
filePath: filePath,
name: 'file',
header: {
@ -114,18 +124,22 @@ export async function uploadVoice(filePath) {
},
success: (res) => {
if (res.statusCode === 200) {
const data = JSON.parse(res.data)
if (data.code === 0) {
resolve(data)
} else {
reject(new Error(data.message || '上传失败'))
try {
const data = JSON.parse(res.data)
if (data.code === 0) {
resolve(data)
} else {
reject(new Error(data.message || '上传失败'))
}
} catch (e) {
reject(new Error('解析响应失败'))
}
} else {
reject(new Error('上传失败'))
reject(new Error(`上传失败: ${res.statusCode}`))
}
},
fail: (err) => {
reject(err)
reject(new Error(err.errMsg || '网络错误'))
}
})
})

View File

@ -21,7 +21,7 @@ const ENV = {
}
// 当前环境 - 开发时使用 development打包时改为 production
const CURRENT_ENV = 'production'
const CURRENT_ENV = 'development'
// 导出配置
export const config = {

View File

@ -229,7 +229,10 @@
<!-- 消息状态 -->
<view v-if="message.isMine && message.messageType === MessageType.TEXT" class="message-status">
<text v-if="message.status === MessageStatus.SENDING" class="status sending">发送中</text>
<text v-else-if="message.status === MessageStatus.FAILED" class="status failed">发送失败</text>
<view v-else-if="message.status === MessageStatus.FAILED" class="status-failed-wrapper">
<text class="status failed">发送失败</text>
<text class="retry-btn" @click="handleRetryMessage(message)">重试</text>
</view>
</view>
</view>
@ -530,6 +533,36 @@ const handleSendMessage = async () => {
}
}
//
const handleRetryMessage = async (message) => {
if (message.status !== MessageStatus.FAILED) return
message.status = MessageStatus.SENDING
try {
const res = await sendMessage({
sessionId: sessionId.value,
receiverId: targetUserId.value,
messageType: message.messageType,
content: message.content
})
if (res && res.code === 0) {
message.status = MessageStatus.SENT
if (res.data?.messageId) {
message.id = res.data.messageId
}
uni.showToast({ title: '发送成功', icon: 'success' })
} else {
message.status = MessageStatus.FAILED
uni.showToast({ title: '发送失败', icon: 'none' })
}
} catch (error) {
message.status = MessageStatus.FAILED
uni.showToast({ title: '发送失败', icon: 'none' })
}
}
//
const handleSwitchInputMode = () => {
inputMode.value = inputMode.value === 'text' ? 'voice' : 'text'
@ -1444,6 +1477,18 @@ onUnmounted(() => {
color: #ff5252;
}
}
.status-failed-wrapper {
display: flex;
align-items: center;
gap: 12rpx;
}
.retry-btn {
font-size: 22rpx;
color: #1890ff;
text-decoration: underline;
}
}
}

View File

@ -215,7 +215,8 @@
if (res && res.code === 0) {
configStore.setHomeConfig({
banners: res.data?.banners || [],
kingKongs: res.data?.kingKongs || []
kingKongs: res.data?.kingKongs || [],
defaultAvatar: res.data?.defaultAvatar || ''
})
}
} catch (error) {

View File

@ -122,12 +122,12 @@ export default {
//
const handleUserAgreement = () => {
uni.showToast({ title: '功能开发中', icon: 'none' })
uni.navigateTo({ url: '/pages/agreement/index?type=user' })
}
//
const handlePrivacyPolicy = () => {
uni.showToast({ title: '功能开发中', icon: 'none' })
uni.navigateTo({ url: '/pages/agreement/index?type=privacy' })
}
onMounted(() => {

View File

@ -93,6 +93,7 @@ import { useUserStore } from '@/store/user.js'
import { useConfigStore } from '@/store/config.js'
import { getMemberInfo } from '@/api/member.js'
import { createOrder } from '@/api/order.js'
import { getFullImageUrl } from '@/utils/image.js'
import Loading from '@/components/Loading/index.vue'
export default {
@ -181,7 +182,7 @@ export default {
const userInfo = computed(() => ({
userId: userStore.userId,
nickname: userStore.nickname,
avatar: userStore.avatar,
avatar: getFullImageUrl(userStore.avatar),
isMember: userStore.isMember,
memberLevel: userStore.memberLevel
}))

View File

@ -108,7 +108,19 @@
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else-if="!pageLoading && !userStore.isLoggedIn">
<image src="/static/ic_empty.png" mode="aspectFit" class="empty-icon" />
<text class="empty-text">登录后查看消息</text>
<button class="login-btn" @click="handleLogin">立即登录</button>
</view>
<!-- 无聊天记录 -->
<view class="empty-state" v-else-if="!pageLoading && sessions.length === 0">
<image src="/static/ic_empty.png" mode="aspectFit" class="empty-icon" />
<text class="empty-text">暂无聊天记录</text>
<text class="empty-tip">去首页看看心仪的对象吧</text>
</view>
</view>
</scroll-view>
</view>
@ -273,6 +285,11 @@ export default {
})
}
//
const handleLogin = () => {
uni.navigateTo({ url: '/pages/login/index' })
}
onMounted(() => {
getSystemInfo()
initPage()
@ -289,10 +306,12 @@ export default {
sessions,
interactCounts,
defaultAvatar,
userStore,
formatTime,
navigateTo,
handleSessionClick,
handleRefresh,
handleLogin,
initPage,
loadInteractCounts,
loadSessions
@ -591,4 +610,47 @@ export default {
}
}
}
//
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 40rpx;
.empty-icon {
width: 200rpx;
height: 200rpx;
margin-bottom: 32rpx;
opacity: 0.6;
}
.empty-text {
font-size: 32rpx;
color: #666;
margin-bottom: 16rpx;
}
.empty-tip {
font-size: 26rpx;
color: #999;
}
.login-btn {
margin-top: 32rpx;
width: 240rpx;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(135deg, #FFBDC2 0%, #FF8A93 100%);
border-radius: 40rpx;
font-size: 30rpx;
color: #fff;
border: none;
&::after {
border: none;
}
}
}
</style>

View File

@ -596,9 +596,19 @@ const getSystemInfo = () => {
})
}
//
//
const handleBack = () => {
uni.navigateBack()
uni.showModal({
title: '提示',
content: '确定要离开吗?已填写的内容将不会保存',
confirmText: '离开',
cancelText: '继续填写',
success: (res) => {
if (res.confirm) {
uni.navigateBack()
}
}
})
}
//
@ -1332,6 +1342,26 @@ onMounted(() => {
})
</script>
<script>
// script
export default {
onBackPress() {
uni.showModal({
title: '提示',
content: '确定要离开吗?已填写的内容将不会保存',
confirmText: '离开',
cancelText: '继续填写',
success: (res) => {
if (res.confirm) {
uni.navigateBack()
}
}
})
return true // true
}
}
</script>
<style lang="scss" scoped>
.profile-edit-page {
min-height: 100vh;

View File

@ -133,7 +133,7 @@ export default {
// 使
const uploadRes = await new Promise((resolve, reject) => {
uni.uploadFile({
url: `${API_BASE_URL}/upload`,
url: `${API_BASE_URL}/api/app/upload/image`,
filePath: tempFilePath,
name: 'file',
header: {

View File

@ -54,9 +54,13 @@ class SignalRClient {
return new Promise((resolve, reject) => {
try {
// 构建 WebSocket URL
// API_BASE_URL: http://localhost:5000/api/app 或 https://xxx.com/api/app
// Hub URL: ws://localhost:5000/hubs/chat 或 wss://xxx.com/hubs/chat
let baseUrl = config.API_BASE_URL
// 移除 /api/app 后缀,获取服务器根地址
const serverUrl = baseUrl.replace(/\/api\/app$/, '')
// 将 http/https 替换为 ws/wss
const wsUrl = baseUrl.replace(/^http/, 'ws').replace('/api/app', '') + '/hubs/chat'
const wsUrl = serverUrl.replace(/^http/, 'ws') + '/hubs/chat'
console.log('[SignalR] 正在连接:', wsUrl)

View File

@ -51,6 +51,11 @@ public class HomeConfigResponse
/// 金刚位列表
/// </summary>
public List<KingKongResponse> KingKongs { get; set; } = new();
/// <summary>
/// 默认头像URL
/// </summary>
public string? DefaultAvatar { get; set; }
}
/// <summary>

View File

@ -13,6 +13,7 @@ public class ConfigService : IConfigService
private readonly IRepository<Banner> _bannerRepository;
private readonly IRepository<KingKong> _kingKongRepository;
private readonly IRepository<PopupConfig> _popupConfigRepository;
private readonly ISystemConfigService _systemConfigService;
private readonly ILogger<ConfigService> _logger;
/// <summary>
@ -29,11 +30,13 @@ public class ConfigService : IConfigService
IRepository<Banner> bannerRepository,
IRepository<KingKong> kingKongRepository,
IRepository<PopupConfig> popupConfigRepository,
ISystemConfigService systemConfigService,
ILogger<ConfigService> logger)
{
_bannerRepository = bannerRepository;
_kingKongRepository = kingKongRepository;
_popupConfigRepository = popupConfigRepository;
_systemConfigService = systemConfigService;
_logger = logger;
}
@ -42,11 +45,13 @@ public class ConfigService : IConfigService
{
var banners = await GetBannersAsync();
var kingKongs = await GetKingKongsAsync();
var defaultAvatar = await _systemConfigService.GetDefaultAvatarAsync();
return new HomeConfigResponse
{
Banners = banners,
KingKongs = kingKongs
KingKongs = kingKongs,
DefaultAvatar = defaultAvatar
};
}