同步状态
This commit is contained in:
parent
af5ceac9a7
commit
79072bc060
128
miniapp/App.vue
128
miniapp/App.vue
|
|
@ -1,6 +1,129 @@
|
|||
<script>
|
||||
import { useConfigStore } from './store/config.js'
|
||||
import { useUserStore } from './store/user.js'
|
||||
import { useChatStore, MessageType } from './store/chat.js'
|
||||
import signalR from './utils/signalr.js'
|
||||
|
||||
// 交换状态枚举
|
||||
const ExchangeStatus = {
|
||||
PENDING: 0,
|
||||
ACCEPTED: 1,
|
||||
REJECTED: 2
|
||||
}
|
||||
|
||||
// 全局 SignalR 事件处理器引用(用于移除监听)
|
||||
let globalExchangeResponseHandler = null
|
||||
let globalReceiveMessageHandler = null
|
||||
|
||||
/**
|
||||
* 初始化全局 SignalR 连接和事件监听
|
||||
* 用于在用户不在聊天页面时也能接收交换响应等通知
|
||||
*/
|
||||
async function initGlobalSignalR() {
|
||||
const userStore = useUserStore()
|
||||
const chatStore = useChatStore()
|
||||
|
||||
if (!userStore.isLoggedIn) {
|
||||
console.log('[App] 用户未登录,跳过 SignalR 连接')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 连接 SignalR(如果已连接会直接返回)
|
||||
await signalR.connect()
|
||||
console.log('[App] 全局 SignalR 连接成功')
|
||||
|
||||
// 移除旧的监听器(防止重复注册)
|
||||
if (globalExchangeResponseHandler) {
|
||||
signalR.off('ExchangeResponse', globalExchangeResponseHandler)
|
||||
}
|
||||
if (globalReceiveMessageHandler) {
|
||||
signalR.off('ReceiveMessage', globalReceiveMessageHandler)
|
||||
}
|
||||
|
||||
// 全局监听交换响应事件
|
||||
globalExchangeResponseHandler = (message) => {
|
||||
console.log('[App] 全局收到交换响应:', message)
|
||||
|
||||
// 如果当前在对应的聊天页面,由聊天页面处理,这里不重复处理
|
||||
if (message.sessionId && message.sessionId === chatStore.currentSessionId) {
|
||||
console.log('[App] 当前在聊天页面,跳过全局处理')
|
||||
return
|
||||
}
|
||||
|
||||
// 更新 chatStore 中对应会话的消息状态
|
||||
if (message.extraData) {
|
||||
try {
|
||||
const extraData = typeof message.extraData === 'string'
|
||||
? JSON.parse(message.extraData)
|
||||
: message.extraData
|
||||
|
||||
const requestMessageId = extraData.RequestMessageId || extraData.requestMessageId
|
||||
const status = extraData.Status ?? extraData.status ?? ExchangeStatus.PENDING
|
||||
const sessionId = message.sessionId
|
||||
|
||||
console.log('[App] 交换响应详情:', { requestMessageId, status, sessionId })
|
||||
|
||||
// 更新 chatStore 中的消息
|
||||
if (sessionId && chatStore.messagesBySession[sessionId]) {
|
||||
const messages = chatStore.messagesBySession[sessionId]
|
||||
const requestMsg = messages.find(m => m.id === requestMessageId)
|
||||
if (requestMsg) {
|
||||
requestMsg.status = status
|
||||
console.log('[App] 已更新消息状态:', requestMessageId, status)
|
||||
|
||||
// 如果同意了交换,更新交换的数据
|
||||
if (status === ExchangeStatus.ACCEPTED) {
|
||||
if (requestMsg.messageType === MessageType.EXCHANGE_WECHAT) {
|
||||
requestMsg.exchangedContent = extraData.senderWeChat || extraData.receiverWeChat ||
|
||||
extraData.SenderWeChat || extraData.ReceiverWeChat
|
||||
} else if (requestMsg.messageType === MessageType.EXCHANGE_PHOTO) {
|
||||
requestMsg.photos = extraData.senderPhotos || extraData.receiverPhotos ||
|
||||
extraData.SenderPhotos || extraData.ReceiverPhotos
|
||||
requestMsg.photoCount = requestMsg.photos?.length || 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 显示通知提示
|
||||
const isAccepted = status === ExchangeStatus.ACCEPTED
|
||||
const typeText = message.messageType === 5 ? '微信' : '照片'
|
||||
uni.showToast({
|
||||
title: isAccepted ? `对方已同意交换${typeText}` : `对方已拒绝交换${typeText}`,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[App] 解析交换响应数据失败:', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 全局监听新消息事件(用于更新未读数等)
|
||||
globalReceiveMessageHandler = (message) => {
|
||||
console.log('[App] 全局收到新消息:', message)
|
||||
|
||||
// 如果当前在对应的聊天页面,由聊天页面处理,这里不重复处理
|
||||
if (message.sessionId && message.sessionId === chatStore.currentSessionId) {
|
||||
console.log('[App] 当前在聊天页面,跳过全局处理')
|
||||
return
|
||||
}
|
||||
|
||||
// 不在聊天页面时,增加未读数
|
||||
if (message.sessionId) {
|
||||
chatStore.incrementUnreadCount(message.sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
signalR.on('ExchangeResponse', globalExchangeResponseHandler)
|
||||
signalR.on('ReceiveMessage', globalReceiveMessageHandler)
|
||||
|
||||
console.log('[App] 全局 SignalR 事件监听已注册')
|
||||
} catch (err) {
|
||||
console.error('[App] 全局 SignalR 连接失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
|
|
@ -12,9 +135,14 @@
|
|||
// 加载所有配置(一次请求)
|
||||
const configStore = useConfigStore()
|
||||
configStore.loadAppConfig()
|
||||
|
||||
// 初始化全局 SignalR 连接
|
||||
initGlobalSignalR()
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
// 应用从后台切回前台时,重新连接 SignalR
|
||||
initGlobalSignalR()
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
|
|
|
|||
|
|
@ -79,24 +79,24 @@
|
|||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 服务号关注弹窗 -->
|
||||
<!-- 资料审核中弹窗 -->
|
||||
<template v-else-if="type === 'auditing'">
|
||||
<view class="popup-title">资料审核中</view>
|
||||
<view class="auditing-info">
|
||||
<text class="auditing-desc">正在加急审核您的相亲资料,请耐心等待</text>
|
||||
</view>
|
||||
<button class="popup-btn auditing-btn" @click="handleClose">确定</button>
|
||||
</template>
|
||||
|
||||
<!-- 服务号关注弹窗 - 样式与每日弹窗一致,只显示图片 -->
|
||||
<template v-else-if="type === 'serviceAccount'">
|
||||
<image
|
||||
v-if="imageUrl"
|
||||
class="popup-image service-account-image"
|
||||
class="popup-image"
|
||||
:src="imageUrl"
|
||||
mode="widthFix"
|
||||
@click="handleImageClick"
|
||||
/>
|
||||
<view class="popup-title">{{ title || '关注服务号' }}</view>
|
||||
<view class="popup-content">{{ content || '关注服务号,及时接收消息通知' }}</view>
|
||||
<view class="service-account-tips">
|
||||
<text>• 有人解锁/收藏您时,第一时间通知</text>
|
||||
<text>• 有人给您发消息时,及时提醒</text>
|
||||
<text>• 每日推荐更新,不错过优质对象</text>
|
||||
</view>
|
||||
<button class="popup-btn" @click="handleButtonClick">
|
||||
{{ buttonText || '去关注' }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<!-- 通用弹窗 -->
|
||||
|
|
@ -132,7 +132,7 @@ export default {
|
|||
type: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
validator: (value) => ['gender', 'daily', 'member', 'unlock', 'profile', 'serviceAccount', 'default'].includes(value)
|
||||
validator: (value) => ['gender', 'daily', 'member', 'unlock', 'profile', 'auditing', 'serviceAccount', 'default'].includes(value)
|
||||
},
|
||||
imageUrl: {
|
||||
type: String,
|
||||
|
|
@ -184,6 +184,10 @@ export default {
|
|||
if (this.linkUrl) {
|
||||
this.navigateToLink()
|
||||
}
|
||||
// 服务号弹窗点击图片后关闭弹窗
|
||||
if (this.type === 'serviceAccount') {
|
||||
this.$emit('confirm')
|
||||
}
|
||||
},
|
||||
handleButtonClick() {
|
||||
// 服务号弹窗由父组件处理跳转逻辑,不在这里处理
|
||||
|
|
@ -208,12 +212,9 @@ export default {
|
|||
if (this.linkUrl.startsWith('/pages/')) {
|
||||
uni.navigateTo({ url: this.linkUrl })
|
||||
} else if (this.linkUrl.startsWith('http')) {
|
||||
// 外部链接使用webview或复制链接
|
||||
uni.setClipboardData({
|
||||
data: this.linkUrl,
|
||||
success: () => {
|
||||
uni.showToast({ title: '链接已复制', icon: 'success' })
|
||||
}
|
||||
// 外部链接使用webview打开
|
||||
uni.navigateTo({
|
||||
url: `/pages/webview/index?url=${encodeURIComponent(this.linkUrl)}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -324,9 +325,10 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
// 每日弹窗/会员广告样式 - 透明背景只显示图片
|
||||
// 每日弹窗/会员广告/服务号弹窗样式 - 透明背景只显示图片
|
||||
.popup-daily,
|
||||
.popup-member {
|
||||
.popup-member,
|
||||
.popup-serviceAccount {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
|
|
@ -443,28 +445,24 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
// 服务号关注弹窗样式
|
||||
.popup-serviceAccount {
|
||||
.service-account-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
display: block;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.service-account-tips {
|
||||
background: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
// 资料审核中弹窗样式
|
||||
.popup-auditing {
|
||||
.auditing-info {
|
||||
text-align: center;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
text {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
.auditing-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.auditing-btn {
|
||||
background: #e0e0e0;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -50,9 +50,10 @@
|
|||
<view class="user-details">
|
||||
<view class="user-name-row">
|
||||
<text class="nickname">{{ targetNickname }}</text>
|
||||
<text class="relationship" v-if="targetRelationship">({{ targetRelationship }})</text>
|
||||
<text class="relationship" v-if="targetRelationship && !targetNickname.includes('(')">({{ targetRelationship }})</text>
|
||||
<view class="user-tags">
|
||||
<text v-if="targetIsMember" class="tag tag-vip">VIP会员</text>
|
||||
<image v-if="targetIsMember && memberIconUrl" class="member-icon" :src="memberIconUrl" mode="heightFix" />
|
||||
<text v-else-if="targetIsMember" class="tag tag-member">会员</text>
|
||||
<text v-if="targetIsRealName" class="tag tag-realname">已实名</text>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -341,6 +342,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { useUserStore } from '@/store/user.js'
|
||||
import { useConfigStore } from '@/store/config.js'
|
||||
import { useChatStore, MessageType, MessageStatus } from '@/store/chat.js'
|
||||
import { getMessages, sendMessage, exchangeWeChat, exchangePhoto, respondExchange, uploadVoice, getOrCreateSession } from '@/api/chat.js'
|
||||
import { getUserDetail } from '@/api/user.js'
|
||||
|
|
@ -348,9 +350,11 @@ import Loading from '@/components/Loading/index.vue'
|
|||
import EmojiPicker from '@/components/EmojiPicker/index.vue'
|
||||
import VoiceRecorder from '@/components/VoiceRecorder/index.vue'
|
||||
import { formatTimestamp } from '@/utils/format.js'
|
||||
import { getFullImageUrl } from '@/utils/image.js'
|
||||
import signalR from '@/utils/signalr.js'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const configStore = useConfigStore()
|
||||
const chatStore = useChatStore()
|
||||
|
||||
// 交换请求状态枚举
|
||||
|
|
@ -370,6 +374,7 @@ const targetNickname = ref('')
|
|||
const targetAvatar = ref('')
|
||||
const targetRelationship = ref('')
|
||||
const targetIsMember = ref(false)
|
||||
const targetMemberLevel = ref(0)
|
||||
const targetIsRealName = ref(false)
|
||||
const targetXiangQinNo = ref('')
|
||||
const targetUserDetail = ref(null)
|
||||
|
|
@ -406,6 +411,13 @@ const innerAudioContext = ref(null)
|
|||
const myAvatar = computed(() => userStore.avatar)
|
||||
const myUserId = computed(() => userStore.userId)
|
||||
|
||||
// 会员图标URL
|
||||
const memberIconUrl = computed(() => {
|
||||
if (!targetIsMember.value || !targetMemberLevel.value) return ''
|
||||
const iconUrl = configStore.getMemberIcon(targetMemberLevel.value)
|
||||
return iconUrl ? getFullImageUrl(iconUrl) : ''
|
||||
})
|
||||
|
||||
// 选项映射
|
||||
const educationMap = {
|
||||
1: '高中',
|
||||
|
|
@ -460,6 +472,7 @@ const loadTargetUserDetail = async () => {
|
|||
targetNickname.value = res.data.nickname || targetNickname.value
|
||||
targetAvatar.value = res.data.avatar || targetAvatar.value
|
||||
targetIsMember.value = res.data.isMember || false
|
||||
targetMemberLevel.value = res.data.memberLevel || 0
|
||||
targetIsRealName.value = res.data.isRealName || false
|
||||
targetXiangQinNo.value = res.data.xiangQinNo || ''
|
||||
targetRelationship.value = relationshipMap[res.data.relationship] || ''
|
||||
|
|
@ -1309,18 +1322,31 @@ const handleExchangeResponse = (message) => {
|
|||
// 更新原始请求消息的状态
|
||||
if (message.extraData) {
|
||||
try {
|
||||
const extraData = JSON.parse(message.extraData)
|
||||
if (extraData.requestMessageId) {
|
||||
const requestMsg = messages.value.find(m => m.id === extraData.requestMessageId)
|
||||
const extraData = typeof message.extraData === 'string' ? JSON.parse(message.extraData) : message.extraData
|
||||
// 兼容大小写
|
||||
const requestMessageId = extraData.RequestMessageId || extraData.requestMessageId
|
||||
const status = extraData.Status ?? extraData.status
|
||||
|
||||
if (requestMessageId) {
|
||||
const requestMsg = messages.value.find(m => m.id === requestMessageId)
|
||||
if (requestMsg) {
|
||||
requestMsg.status = extraData.status
|
||||
if (extraData.status === ExchangeStatus.ACCEPTED) {
|
||||
requestMsg.status = status
|
||||
console.log('[Chat] handleExchangeResponse 更新消息状态:', requestMessageId, status)
|
||||
|
||||
if (status === ExchangeStatus.ACCEPTED) {
|
||||
// 更新交换的数据
|
||||
if (requestMsg.messageType === MessageType.EXCHANGE_WECHAT) {
|
||||
requestMsg.exchangedContent = extraData.senderWeChat || extraData.receiverWeChat
|
||||
// 我是发起方,获取对方(接收者)的微信号
|
||||
requestMsg.exchangedContent = extraData.ReceiverWeChat || extraData.receiverWeChat
|
||||
hasExchangedWeChat.value = true
|
||||
exchangedWeChat.value = requestMsg.exchangedContent
|
||||
} else if (requestMsg.messageType === MessageType.EXCHANGE_PHOTO) {
|
||||
requestMsg.photos = extraData.senderPhotos || extraData.receiverPhotos
|
||||
requestMsg.photoCount = requestMsg.photos?.length || 0
|
||||
// 我是发起方,获取对方(接收者)的照片
|
||||
const photos = extraData.ReceiverPhotos || extraData.receiverPhotos || []
|
||||
requestMsg.photos = photos
|
||||
requestMsg.photoCount = photos.length
|
||||
hasExchangedPhoto.value = true
|
||||
exchangedPhotos.value = photos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1479,21 +1505,33 @@ onUnmounted(() => {
|
|||
|
||||
.user-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.tag {
|
||||
font-size: 20rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 16rpx;
|
||||
.member-icon {
|
||||
width: auto;
|
||||
height: 42rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.tag-vip {
|
||||
.tag {
|
||||
display: inline-block;
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
height: 36rpx;
|
||||
line-height: 24rpx;
|
||||
box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
|
||||
&.tag-member {
|
||||
background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
&.tag-realname {
|
||||
background: #e8f5e9;
|
||||
color: #4caf50;
|
||||
background: #3d4a4a;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,14 +41,18 @@
|
|||
:visible="showServiceAccountPopup"
|
||||
type="serviceAccount"
|
||||
:imageUrl="serviceAccountPopup?.imageUrl"
|
||||
:title="serviceAccountPopup?.title || '关注服务号'"
|
||||
:content="serviceAccountPopup?.content || '关注服务号,及时接收消息通知'"
|
||||
:buttonText="serviceAccountPopup?.buttonText || '去关注'"
|
||||
:linkUrl="serviceAccountPopup?.linkUrl"
|
||||
@close="handleCloseServiceAccountPopup"
|
||||
@confirm="handleServiceAccountPopupConfirm"
|
||||
/>
|
||||
|
||||
<!-- 资料审核中弹窗 -->
|
||||
<Popup
|
||||
:visible="showAuditingPopup"
|
||||
type="auditing"
|
||||
@close="handleCloseAuditingPopup"
|
||||
/>
|
||||
|
||||
<!-- ==================== 固定底部条 ==================== -->
|
||||
|
||||
<!-- 会员广告条 - 固定在底部,优先级最高 -->
|
||||
|
|
@ -682,12 +686,24 @@ export default {
|
|||
return true
|
||||
}
|
||||
|
||||
// ==================== 审核中弹窗状态 ====================
|
||||
|
||||
/** 是否显示审核中弹窗 */
|
||||
const showAuditingPopup = ref(false)
|
||||
|
||||
/**
|
||||
* 检查用户资料完善状态
|
||||
*
|
||||
* @returns {boolean} 资料是否已完善
|
||||
*/
|
||||
const checkProfileStatus = () => {
|
||||
// 资料审核中
|
||||
if (userStore.isProfileAuditing) {
|
||||
showAuditingPopup.value = true
|
||||
return false
|
||||
}
|
||||
|
||||
// 资料未完善
|
||||
if (!userStore.isProfileCompleted) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
|
|
@ -704,6 +720,13 @@ export default {
|
|||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭审核中弹窗
|
||||
*/
|
||||
const handleCloseAuditingPopup = () => {
|
||||
showAuditingPopup.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户解锁状态并处理
|
||||
*
|
||||
|
|
@ -883,6 +906,7 @@ export default {
|
|||
dailyPopup,
|
||||
showUnlockPopup,
|
||||
remainingUnlockQuota,
|
||||
showAuditingPopup,
|
||||
|
||||
// 方法
|
||||
initPage,
|
||||
|
|
@ -905,7 +929,8 @@ export default {
|
|||
handleConfirmUnlock,
|
||||
handleGoMember,
|
||||
handleScrollToLower,
|
||||
handleRefresh
|
||||
handleRefresh,
|
||||
handleCloseAuditingPopup
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -291,6 +291,17 @@ export default {
|
|||
|
||||
// 联系用户
|
||||
const handleContact = (userId) => {
|
||||
// 检查是否资料审核中
|
||||
if (userStore.isProfileAuditing) {
|
||||
uni.showModal({
|
||||
title: '资料审核中',
|
||||
content: '正在加急审核您的相亲资料,请耐心等待',
|
||||
showCancel: false,
|
||||
confirmText: '确定'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否完善资料
|
||||
if (!userStore.isProfileCompleted) {
|
||||
uni.showModal({
|
||||
|
|
|
|||
|
|
@ -189,6 +189,17 @@ export default {
|
|||
|
||||
// 联系用户
|
||||
const handleContact = (userId) => {
|
||||
// 检查是否资料审核中
|
||||
if (userStore.isProfileAuditing) {
|
||||
uni.showModal({
|
||||
title: '资料审核中',
|
||||
content: '正在加急审核您的相亲资料,请耐心等待',
|
||||
showCancel: false,
|
||||
confirmText: '确定'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否完善资料
|
||||
if (!userStore.isProfileCompleted) {
|
||||
uni.showModal({
|
||||
|
|
|
|||
|
|
@ -304,20 +304,27 @@
|
|||
let interactType = ''
|
||||
if (url.includes('viewedMe')) {
|
||||
interactType = 'viewedMe'
|
||||
interactCounts.value.viewedMe = 0
|
||||
} else if (url.includes('favoritedMe')) {
|
||||
interactType = 'favoritedMe'
|
||||
interactCounts.value.favoritedMe = 0
|
||||
} else if (url.includes('unlockedMe')) {
|
||||
interactType = 'unlockedMe'
|
||||
interactCounts.value.unlockedMe = 0
|
||||
}
|
||||
|
||||
// 调用后端标记已读(异步,不阻塞跳转)
|
||||
// 先调用后端标记已读,成功后再清零本地计数
|
||||
if (interactType) {
|
||||
markInteractAsRead(interactType).catch(err => {
|
||||
try {
|
||||
await markInteractAsRead(interactType)
|
||||
// 标记成功后清零本地计数
|
||||
if (interactType === 'viewedMe') {
|
||||
interactCounts.value.viewedMe = 0
|
||||
} else if (interactType === 'favoritedMe') {
|
||||
interactCounts.value.favoritedMe = 0
|
||||
} else if (interactType === 'unlockedMe') {
|
||||
interactCounts.value.unlockedMe = 0
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('标记已读失败:', err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
uni.navigateTo({ url })
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
<view class="header-right">
|
||||
<view class="name-row">
|
||||
<text class="nickname">{{ userDetail.nickname }}</text>
|
||||
<text class="relationship">({{ relationshipText }})</text>
|
||||
<text class="relationship" v-if="!userDetail.nickname?.includes('(')">({{ relationshipText }})</text>
|
||||
<view class="header-tags">
|
||||
<image v-if="userDetail.isMember && memberIconUrl" class="member-icon" :src="memberIconUrl" mode="aspectFit" />
|
||||
<text v-else-if="userDetail.isMember" class="tag tag-member">会员</text>
|
||||
|
|
@ -577,6 +577,14 @@ const handleFavorite = async () => {
|
|||
|
||||
// 联系处理
|
||||
const handleContact = async () => {
|
||||
console.log('[Detail] handleContact - 检查实名状态:', {
|
||||
targetIsRealName: userDetail.value?.isRealName,
|
||||
myIsRealName: userStore.isRealName,
|
||||
isLoggedIn: userStore.isLoggedIn,
|
||||
isProfileCompleted: userStore.isProfileCompleted,
|
||||
isProfileAuditing: userStore.isProfileAuditing
|
||||
})
|
||||
|
||||
// 检查是否登录
|
||||
if (!userStore.isLoggedIn) {
|
||||
uni.showModal({
|
||||
|
|
@ -592,6 +600,17 @@ const handleContact = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
// 检查是否资料审核中
|
||||
if (userStore.isProfileAuditing) {
|
||||
uni.showModal({
|
||||
title: '资料审核中',
|
||||
content: '正在加急审核您的相亲资料,请耐心等待',
|
||||
showCancel: false,
|
||||
confirmText: '确定'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!userStore.isProfileCompleted) {
|
||||
showProfilePopup.value = true
|
||||
return
|
||||
|
|
@ -599,6 +618,7 @@ const handleContact = async () => {
|
|||
|
||||
// 如果对方已实名,检查当前用户是否也已实名
|
||||
if (userDetail.value?.isRealName && !userStore.isRealName) {
|
||||
console.log('[Detail] 对方已实名但我未实名,跳转实名认证页')
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '对方已开启实名相亲,请先完成实名认证才能联系',
|
||||
|
|
|
|||
|
|
@ -762,7 +762,7 @@ const formData = reactive({
|
|||
houseStatus: 5, // 默认选择"租房"
|
||||
carStatus: 2, // 默认选择"无车"
|
||||
marriageStatus: 1, // 默认选择"未婚"
|
||||
expectMarryTime: 0,
|
||||
expectMarryTime: 1, // 默认选择"尽快结婚"
|
||||
introduction: '',
|
||||
weChatNo: '',
|
||||
phone: '', // 验证后的手机号
|
||||
|
|
|
|||
|
|
@ -399,6 +399,17 @@ const handleContact = (userId) => {
|
|||
return
|
||||
}
|
||||
|
||||
// 检查是否资料审核中
|
||||
if (userStore.isProfileAuditing) {
|
||||
uni.showModal({
|
||||
title: '资料审核中',
|
||||
content: '正在加急审核您的相亲资料,请耐心等待',
|
||||
showCancel: false,
|
||||
confirmText: '确定'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否完善资料
|
||||
if (!userStore.isProfileCompleted) {
|
||||
uni.showModal({
|
||||
|
|
|
|||
|
|
@ -232,15 +232,22 @@ export const useConfigStore = defineStore('config', {
|
|||
/**
|
||||
* 检查是否应该显示服务号关注弹窗
|
||||
* 条件:
|
||||
* 1. 用户未关注服务号(从后端获取真实状态)
|
||||
* 2. 弹窗已启用
|
||||
* 3. 弹出后5分钟内不再弹出
|
||||
* 4. 一天最多弹出3次
|
||||
* 1. 用户已登录
|
||||
* 2. 用户未关注服务号(从后端获取真实状态)
|
||||
* 3. 弹窗已启用
|
||||
* 4. 弹出后5分钟内不再弹出
|
||||
* 5. 一天最多弹出3次
|
||||
*/
|
||||
checkServiceAccountPopup() {
|
||||
// 从 userStore 获取真实的关注状态
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 如果未登录,不显示
|
||||
if (!userStore.isLoggedIn) {
|
||||
this.showServiceAccountPopup = false
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已关注服务号,不显示
|
||||
if (userStore.isFollowServiceAccount) {
|
||||
this.showServiceAccountPopup = false
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export const useUserStore = defineStore('user', {
|
|||
avatar: '',
|
||||
xiangQinNo: '',
|
||||
isProfileCompleted: false,
|
||||
auditStatus: 0, // 审核状态:0-未提交资料 1-已通过审核 2-审核中 3-已拒绝
|
||||
isMember: false,
|
||||
memberLevel: 0,
|
||||
isRealName: false,
|
||||
|
|
@ -56,6 +57,11 @@ export const useUserStore = defineStore('user', {
|
|||
*/
|
||||
needCompleteProfile: (state) => !state.isProfileCompleted,
|
||||
|
||||
/**
|
||||
* 是否资料审核中(auditStatus = 2)
|
||||
*/
|
||||
isProfileAuditing: (state) => state.auditStatus === 2,
|
||||
|
||||
/**
|
||||
* 是否需要选择性别偏好
|
||||
*/
|
||||
|
|
@ -96,6 +102,7 @@ export const useUserStore = defineStore('user', {
|
|||
this.avatar = ''
|
||||
this.xiangQinNo = ''
|
||||
this.isProfileCompleted = false
|
||||
this.auditStatus = 0
|
||||
this.isMember = false
|
||||
this.memberLevel = 0
|
||||
this.isRealName = false
|
||||
|
|
@ -115,6 +122,7 @@ export const useUserStore = defineStore('user', {
|
|||
if (userInfo.avatar !== undefined) this.avatar = userInfo.avatar
|
||||
if (userInfo.xiangQinNo !== undefined) this.xiangQinNo = userInfo.xiangQinNo
|
||||
if (userInfo.isProfileCompleted !== undefined) this.isProfileCompleted = userInfo.isProfileCompleted
|
||||
if (userInfo.auditStatus !== undefined) this.auditStatus = userInfo.auditStatus
|
||||
if (userInfo.isMember !== undefined) this.isMember = userInfo.isMember
|
||||
if (userInfo.memberLevel !== undefined) this.memberLevel = userInfo.memberLevel
|
||||
if (userInfo.isRealName !== undefined) this.isRealName = userInfo.isRealName
|
||||
|
|
@ -127,6 +135,7 @@ export const useUserStore = defineStore('user', {
|
|||
avatar: this.avatar,
|
||||
xiangQinNo: this.xiangQinNo,
|
||||
isProfileCompleted: this.isProfileCompleted,
|
||||
auditStatus: this.auditStatus,
|
||||
isMember: this.isMember,
|
||||
memberLevel: this.memberLevel,
|
||||
isRealName: this.isRealName,
|
||||
|
|
@ -161,6 +170,7 @@ export const useUserStore = defineStore('user', {
|
|||
this.avatar = userInfo.avatar || ''
|
||||
this.xiangQinNo = userInfo.xiangQinNo || ''
|
||||
this.isProfileCompleted = userInfo.isProfileCompleted || false
|
||||
this.auditStatus = userInfo.auditStatus !== undefined ? userInfo.auditStatus : 0
|
||||
this.isMember = userInfo.isMember || false
|
||||
this.memberLevel = userInfo.memberLevel || 0
|
||||
this.isRealName = userInfo.isRealName || false
|
||||
|
|
@ -218,6 +228,7 @@ export const useUserStore = defineStore('user', {
|
|||
avatar: data.avatar,
|
||||
xiangQinNo: data.xiangQinNo,
|
||||
isProfileCompleted: data.auditStatus === 1,
|
||||
auditStatus: data.auditStatus,
|
||||
isMember: data.isMember,
|
||||
memberLevel: data.memberLevel,
|
||||
isRealName: data.isRealName,
|
||||
|
|
|
|||
|
|
@ -131,10 +131,14 @@ public class ChatController : ControllerBase
|
|||
IsSelf = false // 接收者收到时不是自己发的
|
||||
};
|
||||
|
||||
// 推送给会话组(双方都能收到)
|
||||
// 推送到会话组(双方都在聊天页面时能收到)
|
||||
await _hubContext.SendMessageToSessionAsync(request.SessionId, messageResponse);
|
||||
_logger.LogInformation("消息已通过SignalR推送到会话组: MessageId={MessageId}, SessionId={SessionId}",
|
||||
result.MessageId, request.SessionId);
|
||||
|
||||
// 同时推送到接收者的用户组(即使不在聊天页面也能收到)
|
||||
await _hubContext.SendNewMessageAsync(request.ReceiverId, messageResponse);
|
||||
|
||||
_logger.LogInformation("消息已通过SignalR推送: MessageId={MessageId}, SessionId={SessionId}, ReceiverId={ReceiverId}",
|
||||
result.MessageId, request.SessionId, request.ReceiverId);
|
||||
|
||||
return ApiResponse<SendMessageResponse>.Success(result);
|
||||
}
|
||||
|
|
@ -182,9 +186,14 @@ public class ChatController : ControllerBase
|
|||
IsSelf = false
|
||||
};
|
||||
|
||||
// 推送到会话组(双方都在聊天页面时能收到)
|
||||
await _hubContext.SendMessageToSessionAsync(request.SessionId, messageResponse);
|
||||
_logger.LogInformation("交换微信请求已通过SignalR推送到会话组: MessageId={MessageId}, SessionId={SessionId}",
|
||||
result.RequestMessageId, request.SessionId);
|
||||
|
||||
// 同时推送到接收者的用户组(即使不在聊天页面也能收到)
|
||||
await _hubContext.SendNewMessageAsync(request.ReceiverId, messageResponse);
|
||||
|
||||
_logger.LogInformation("交换微信请求已通过SignalR推送: MessageId={MessageId}, SessionId={SessionId}, ReceiverId={ReceiverId}",
|
||||
result.RequestMessageId, request.SessionId, request.ReceiverId);
|
||||
|
||||
return ApiResponse<ExchangeRequestResponse>.Success(result);
|
||||
}
|
||||
|
|
@ -232,9 +241,14 @@ public class ChatController : ControllerBase
|
|||
IsSelf = false
|
||||
};
|
||||
|
||||
// 推送到会话组(双方都在聊天页面时能收到)
|
||||
await _hubContext.SendMessageToSessionAsync(request.SessionId, messageResponse);
|
||||
_logger.LogInformation("交换照片请求已通过SignalR推送到会话组: MessageId={MessageId}, SessionId={SessionId}",
|
||||
result.RequestMessageId, request.SessionId);
|
||||
|
||||
// 同时推送到接收者的用户组(即使不在聊天页面也能收到)
|
||||
await _hubContext.SendNewMessageAsync(request.ReceiverId, messageResponse);
|
||||
|
||||
_logger.LogInformation("交换照片请求已通过SignalR推送: MessageId={MessageId}, SessionId={SessionId}, ReceiverId={ReceiverId}",
|
||||
result.RequestMessageId, request.SessionId, request.ReceiverId);
|
||||
|
||||
return ApiResponse<ExchangeRequestResponse>.Success(result);
|
||||
}
|
||||
|
|
@ -284,9 +298,14 @@ public class ChatController : ControllerBase
|
|||
IsSelf = false
|
||||
};
|
||||
|
||||
// 推送到会话组(在聊天页面的用户能收到)
|
||||
await _hubContext.SendMessageToSessionAsync(result.SessionId, messageResponse);
|
||||
_logger.LogInformation("交换响应已通过SignalR推送到会话组: ResultMessageId={ResultMessageId}, SessionId={SessionId}, IsAgreed={IsAgreed}",
|
||||
result.ResultMessageId, result.SessionId, result.IsAgreed);
|
||||
|
||||
// 同时推送到请求发起者的用户组(即使不在聊天页面也能收到)
|
||||
await _hubContext.SendExchangeResponseAsync(result.RequesterId, messageResponse);
|
||||
|
||||
_logger.LogInformation("交换响应已通过SignalR推送: ResultMessageId={ResultMessageId}, SessionId={SessionId}, RequesterId={RequesterId}, IsAgreed={IsAgreed}",
|
||||
result.ResultMessageId, result.SessionId, result.RequesterId, result.IsAgreed);
|
||||
|
||||
return ApiResponse<ExchangeRespondResponse>.Success(result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,8 +87,12 @@ builder.Services.AddSwaggerGen(c =>
|
|||
c.DocInclusionPredicate((docName, api) => true);
|
||||
});
|
||||
|
||||
// Add SignalR
|
||||
builder.Services.AddSignalR();
|
||||
// Add SignalR with camelCase JSON serialization
|
||||
builder.Services.AddSignalR()
|
||||
.AddJsonProtocol(options =>
|
||||
{
|
||||
options.PayloadSerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;
|
||||
});
|
||||
|
||||
// Add Hangfire
|
||||
builder.Services.AddHangfireServices(builder.Configuration);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class AdminProfileAuditQueryRequest
|
|||
public int PageSize { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态:0待审核 1已通过 2已拒绝,不传则查询全部
|
||||
/// 审核状态:0未提交 1已通过 2审核中 3已拒绝,不传则查询全部
|
||||
/// </summary>
|
||||
public int? AuditStatus { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public class AdminUserQueryRequest
|
|||
public bool? IsProfileCompleted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资料审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 资料审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int? AuditStatus { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class AdminPendingProfileDto
|
|||
public string WorkCity { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int AuditStatus { get; set; }
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ public class AdminProfileAuditDetailDto
|
|||
public string WeChatNo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int AuditStatus { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public class AdminUserListDto
|
|||
public string MemberLevelText { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 资料审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 资料审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int? AuditStatus { get; set; }
|
||||
|
||||
|
|
@ -394,7 +394,7 @@ public class AdminUserProfileDto
|
|||
public string WeChatNo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int AuditStatus { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ public class ProfileResponse
|
|||
public string? Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int AuditStatus { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -212,14 +212,26 @@ public class AdminProfileAuditService : IAdminProfileAuditService
|
|||
// Pending (0) -> Rejected (2): 待审核 -> 已拒绝
|
||||
// Rejected (2) -> Approved (1): 已拒绝 -> 已通过 (重新审核通过)
|
||||
// Rejected (2) -> Rejected (2): 已拒绝 -> 已拒绝 (更新拒绝原因)
|
||||
// 状态说明:
|
||||
// NotSubmitted (0): 未提交资料
|
||||
// Approved (1): 已通过审核
|
||||
// Pending (2): 审核中
|
||||
// Rejected (3): 已拒绝
|
||||
//
|
||||
// 有效的状态转换:
|
||||
// Pending (2) -> Approved (1): 审核通过
|
||||
// Pending (2) -> Rejected (3): 审核拒绝
|
||||
// Rejected (3) -> Approved (1): 重新审核通过
|
||||
// Rejected (3) -> Rejected (3): 更新拒绝原因
|
||||
//
|
||||
// Invalid transitions:
|
||||
// Approved (1) -> Pending (0): 已通过不能回到待审核
|
||||
// Approved (1) -> Rejected (2): 已通过不能直接拒绝(需要用户重新提交)
|
||||
// Any -> Pending (0): 不能手动设置为待审核(只有用户提交/更新资料时才会设为待审核)
|
||||
// 无效的状态转换:
|
||||
// Approved (1) -> Pending (2): 已通过不能回到审核中
|
||||
// Approved (1) -> Rejected (3): 已通过不能直接拒绝(需要用户重新提交)
|
||||
// Any -> Pending (2): 不能手动设置为审核中(只有用户提交/更新资料时才会设为审核中)
|
||||
// Any -> NotSubmitted (0): 不能手动设置为未提交
|
||||
|
||||
// Cannot transition to Pending status manually
|
||||
if (targetStatus == (int)AuditStatus.Pending)
|
||||
// Cannot transition to Pending or NotSubmitted status manually
|
||||
if (targetStatus == (int)AuditStatus.Pending || targetStatus == (int)AuditStatus.NotSubmitted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -363,9 +375,10 @@ public class AdminProfileAuditService : IAdminProfileAuditService
|
|||
{
|
||||
return auditStatus switch
|
||||
{
|
||||
0 => "待审核",
|
||||
0 => "未提交",
|
||||
1 => "已通过",
|
||||
2 => "已拒绝",
|
||||
2 => "审核中",
|
||||
3 => "已拒绝",
|
||||
_ => "未知"
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -735,9 +735,10 @@ public class AdminUserService : IAdminUserService
|
|||
{
|
||||
return auditStatus switch
|
||||
{
|
||||
0 => "待审核",
|
||||
0 => "未提交",
|
||||
1 => "已通过",
|
||||
2 => "已拒绝",
|
||||
2 => "审核中",
|
||||
3 => "已拒绝",
|
||||
_ => "未知"
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,10 +557,11 @@ public class ChatService : IChatService
|
|||
extraData.SenderWeChat = senderProfile?.WeChatNo;
|
||||
extraData.ReceiverWeChat = receiverProfile?.WeChatNo;
|
||||
|
||||
// 包含 RequestMessageId 以便前端精确匹配
|
||||
// 包含 RequestMessageId 和 Status 以便前端精确匹配和状态更新
|
||||
exchangedData = JsonSerializer.Serialize(new
|
||||
{
|
||||
RequestMessageId = request.RequestMessageId,
|
||||
Status = 1, // 已同意
|
||||
SenderWeChat = extraData.SenderWeChat,
|
||||
ReceiverWeChat = extraData.ReceiverWeChat
|
||||
});
|
||||
|
|
@ -574,10 +575,11 @@ public class ChatService : IChatService
|
|||
extraData.SenderPhotos = senderPhotos.OrderBy(p => p.Sort).Select(p => p.PhotoUrl).ToList();
|
||||
extraData.ReceiverPhotos = receiverPhotos.OrderBy(p => p.Sort).Select(p => p.PhotoUrl).ToList();
|
||||
|
||||
// 包含 RequestMessageId 以便前端精确匹配
|
||||
// 包含 RequestMessageId 和 Status 以便前端精确匹配和状态更新
|
||||
exchangedData = JsonSerializer.Serialize(new
|
||||
{
|
||||
RequestMessageId = request.RequestMessageId,
|
||||
Status = 1, // 已同意
|
||||
SenderPhotos = extraData.SenderPhotos,
|
||||
ReceiverPhotos = extraData.ReceiverPhotos
|
||||
});
|
||||
|
|
|
|||
|
|
@ -121,6 +121,12 @@ public class InteractService : IInteractService
|
|||
foreach (var item in items)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(item.UserId);
|
||||
// 跳过已删除的用户
|
||||
if (user == null || user.IsDeleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = (await _profileRepository.GetListAsync(p => p.UserId == item.UserId)).FirstOrDefault();
|
||||
var photos = await _photoRepository.GetListAsync(p => p.UserId == item.UserId);
|
||||
var firstPhoto = photos.OrderBy(p => p.Sort).FirstOrDefault();
|
||||
|
|
@ -173,6 +179,12 @@ public class InteractService : IInteractService
|
|||
foreach (var item in items)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(item.TargetUserId);
|
||||
// 跳过已删除的用户
|
||||
if (user == null || user.IsDeleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = (await _profileRepository.GetListAsync(p => p.UserId == item.TargetUserId)).FirstOrDefault();
|
||||
var photos = await _photoRepository.GetListAsync(p => p.UserId == item.TargetUserId);
|
||||
var firstPhoto = photos.OrderBy(p => p.Sort).FirstOrDefault();
|
||||
|
|
@ -320,6 +332,12 @@ public class InteractService : IInteractService
|
|||
foreach (var item in items)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(item.UserId);
|
||||
// 跳过已删除的用户
|
||||
if (user == null || user.IsDeleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = (await _profileRepository.GetListAsync(p => p.UserId == item.UserId)).FirstOrDefault();
|
||||
var photos = await _photoRepository.GetListAsync(p => p.UserId == item.UserId);
|
||||
var firstPhoto = photos.OrderBy(p => p.Sort).FirstOrDefault();
|
||||
|
|
@ -371,6 +389,12 @@ public class InteractService : IInteractService
|
|||
foreach (var item in items)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(item.TargetUserId);
|
||||
// 跳过已删除的用户
|
||||
if (user == null || user.IsDeleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = (await _profileRepository.GetListAsync(p => p.UserId == item.TargetUserId)).FirstOrDefault();
|
||||
var photos = await _photoRepository.GetListAsync(p => p.UserId == item.TargetUserId);
|
||||
var firstPhoto = photos.OrderBy(p => p.Sort).FirstOrDefault();
|
||||
|
|
@ -522,6 +546,12 @@ public class InteractService : IInteractService
|
|||
foreach (var item in items)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(item.UserId);
|
||||
// 跳过已删除的用户
|
||||
if (user == null || user.IsDeleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = (await _profileRepository.GetListAsync(p => p.UserId == item.UserId)).FirstOrDefault();
|
||||
var photos = await _photoRepository.GetListAsync(p => p.UserId == item.UserId);
|
||||
var firstPhoto = photos.OrderBy(p => p.Sort).FirstOrDefault();
|
||||
|
|
@ -573,6 +603,12 @@ public class InteractService : IInteractService
|
|||
foreach (var item in items)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(item.TargetUserId);
|
||||
// 跳过已删除的用户
|
||||
if (user == null || user.IsDeleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = (await _profileRepository.GetListAsync(p => p.UserId == item.TargetUserId)).FirstOrDefault();
|
||||
var photos = await _photoRepository.GetListAsync(p => p.UserId == item.TargetUserId);
|
||||
var firstPhoto = photos.OrderBy(p => p.Sort).FirstOrDefault();
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public class ProfileService : IProfileService
|
|||
ParentHousingStatus = request.ParentHousingStatus,
|
||||
ParentPensionStatus = request.ParentPensionStatus,
|
||||
ParentMedicalStatus = request.ParentMedicalStatus,
|
||||
AuditStatus = (int)AuditStatus.Pending, // 新资料设为待审核
|
||||
AuditStatus = (int)AuditStatus.Pending, // 新资料设为审核中
|
||||
CreateTime = DateTime.Now,
|
||||
UpdateTime = DateTime.Now
|
||||
};
|
||||
|
|
@ -147,7 +147,7 @@ public class ProfileService : IProfileService
|
|||
existingProfile.ParentHousingStatus = request.ParentHousingStatus;
|
||||
existingProfile.ParentPensionStatus = request.ParentPensionStatus;
|
||||
existingProfile.ParentMedicalStatus = request.ParentMedicalStatus;
|
||||
existingProfile.AuditStatus = (int)AuditStatus.Pending; // 更新资料重置为待审核
|
||||
existingProfile.AuditStatus = (int)AuditStatus.Pending; // 更新资料重置为审核中
|
||||
existingProfile.RejectReason = null; // 清除之前的拒绝原因
|
||||
existingProfile.UpdateTime = DateTime.Now;
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ public class UserProfile : BaseEntity
|
|||
public string WeChatNo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 审核状态:0待审核 1已通过 2已拒绝
|
||||
/// 审核状态:0未提交 1已通过 2审核中 3已拒绝
|
||||
/// </summary>
|
||||
public int AuditStatus { get; set; } = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -146,17 +146,22 @@ public enum ExpectMarryTime
|
|||
public enum AuditStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 待审核
|
||||
/// 未提交资料
|
||||
/// </summary>
|
||||
Pending = 0,
|
||||
NotSubmitted = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 已通过
|
||||
/// 已通过审核
|
||||
/// </summary>
|
||||
Approved = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 审核中
|
||||
/// </summary>
|
||||
Pending = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 已拒绝
|
||||
/// </summary>
|
||||
Rejected = 2
|
||||
Rejected = 3
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,22 @@ public class AliyunRealNameProvider : IRealNameProvider
|
|||
{
|
||||
try
|
||||
{
|
||||
// 验证配置
|
||||
if (string.IsNullOrEmpty(_options.AccessKeyId))
|
||||
{
|
||||
_logger.LogError("阿里云实名认证配置错误: AccessKeyId 为空");
|
||||
return RealNameResult.Fail("CONFIG_ERROR", "实名认证服务配置错误,请联系管理员");
|
||||
}
|
||||
if (string.IsNullOrEmpty(_options.AccessKeySecret))
|
||||
{
|
||||
_logger.LogError("阿里云实名认证配置错误: AccessKeySecret 为空");
|
||||
return RealNameResult.Fail("CONFIG_ERROR", "实名认证服务配置错误,请联系管理员");
|
||||
}
|
||||
|
||||
_logger.LogInformation("阿里云实名认证配置: AccessKeyId={AccessKeyId}, SecretLength={SecretLength}",
|
||||
_options.AccessKeyId[..8] + "***",
|
||||
_options.AccessKeySecret?.Length ?? 0);
|
||||
|
||||
var parameters = new SortedDictionary<string, string>
|
||||
{
|
||||
{ "Action", "Id2MetaVerify" },
|
||||
|
|
@ -129,7 +145,9 @@ public class AliyunRealNameProvider : IRealNameProvider
|
|||
|
||||
var stringToSign = $"GET&%2F&{PercentEncode(canonicalizedQueryString)}";
|
||||
|
||||
using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(_options.AccessKeySecret + "&"));
|
||||
// 确保 AccessKeySecret 不为空
|
||||
var secretKey = _options.AccessKeySecret ?? string.Empty;
|
||||
using var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(secretKey + "&"));
|
||||
var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
|
||||
return Convert.ToBase64String(hashBytes);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user