You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

564 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="report-container">
<!-- ========== 被投诉人信息 ========== -->
<view class="target-info">
<view class="target-avatar">
<image :src="targetAvatar || '/static/default-avatar.png'" mode="aspectFill"></image>
<view v-if="isGroup" class="group-badge">群</view>
</view>
<view class="target-detail">
<text class="target-type">{{ targetName }}</text>
</view>
</view>
<!-- ========== 聊天记录展示(只读) ========== -->
<view class="selected-messages">
<view class="selected-header">
<text class="selected-title">投诉的聊天记录</text>
</view>
<view v-if="allMessages.length === 0" class="empty-selected">
暂无聊天记录可投诉
</view>
<view v-else class="message-list">
<view v-for="msg in allMessages" :key="msg.id" class="message-item">
<view class="msg-content-wrapper">
<view class="msg-header">
<image :src="getSenderAvatar(msg)" mode="aspectFill"></image>
<text class="sender-name">{{ getSenderName(msg) }}</text>
<text class="msg-time">{{ formatTime(msg.sendTime) }}</text>
</view>
<view class="msg-body">
<text>{{ getFullMessageContent(msg) }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- ========== 投诉原因 ========== -->
<view class="reason-section">
<view class="section-title">投诉原因 <text class="required">*</text></view>
<radio-group @change="onReasonChange">
<label class="reason-item" v-for="item in reasonList" :key="item.value">
<radio :value="String(item.value)" :checked="selectedReason === item.value" color="#00a89b" />
<text class="reason-text">{{ item.label }}</text>
</label>
</radio-group>
</view>
<!-- ========== 补充描述 ========== -->
<view class="desc-section">
<view class="section-title">补充描述 <text class="optional">(选填)</text></view>
<textarea
class="desc-input"
v-model="description"
placeholder="请详细描述您遇到的问题,以便我们更快处理..."
maxlength="200"
auto-height
/>
<view class="char-count">{{ description.length }}/200</view>
</view>
<!-- ========== 提交按钮 ========== -->
<view class="btn-wrapper">
<button class="submit-btn" @click="submitReport" >
提交投诉
</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
// ===== 页面参数 =====
sendType: '1',
senderId: '',
// ===== 被投诉人 =====
targetName: '',
targetAvatar: '',
isGroup: false,
// ===== 群成员(仅用于展示发送者昵称/头像) =====
groupMembers: [],
// ===== 聊天记录 =====
allMessages: [],
// ===== 投诉原因 =====
reasonList: [
{ label: '色情低俗', value: 1 },
{ label: '暴力恐怖', value: 2 },
{ label: '政治敏感', value: 3 },
{ label: '骚扰谩骂', value: 4 },
{ label: '虚假诈骗', value: 5 },
{ label: '违规宣传', value: 6 },
{ label: '其他', value: 7 }
],
selectedReason: null,
description: '',
// ===== 当前用户 =====
currentUser: {}
};
},
computed: {
},
onLoad(options) {
this.sendType = options.sendType || '1';
this.senderId = options.senderId || '';
this.isGroup = this.sendType === '2';
this.currentUser = uni.getStorageSync('user') || {};
// ===== 从聊天页跳转fromChat=true读取完整聊天记录缓存 =====
if (options.fromChat === 'true') {
this.initFromChatCache();
return;
}
// ===== 无传递数据:走原逻辑 =====
if (!this.senderId) {
uni.showToast({ title: '参数错误', icon: 'none' });
setTimeout(() => uni.navigateBack(), 1500);
return;
}
this.initPage();
},
methods: {
// ==================== 初始化 ====================
async initPage() {
uni.showLoading({ title: '加载中...' });
try {
if (this.isGroup) {
await this.loadGroupInfo();
} else {
await this.loadUserInfo();
}
} catch (e) {
console.error('加载失败', e);
uni.showToast({ title: '加载失败,请重试', icon: 'none' });
} finally {
uni.hideLoading();
}
},
// ==================== 从聊天页读取缓存数据fromChat 场景) ====================
initFromChatCache() {
const cachedRecords = uni.getStorageSync('report_selected_messages') || [];
const cachedSenderId = uni.getStorageSync('report_sender_id');
const cachedSendType = uni.getStorageSync('report_send_type');
const cachedSenderName = uni.getStorageSync('report_sender_name');
const cachedSenderAvatar = uni.getStorageSync('report_sender_avatar');
// 缓存异常(无完整记录)时退回原逻辑
if (!cachedRecords || cachedRecords.length === 0) {
uni.showToast({ title: '未获取到聊天记录', icon: 'none' });
if (this.senderId) {
this.initPage();
} else {
setTimeout(() => uni.navigateBack(), 1500);
}
return;
}
// 完整聊天记录作为展示数据源
this.allMessages = cachedRecords;
// 被投诉人信息
this.senderId = cachedSenderId || this.senderId;
if (cachedSendType) {
this.sendType = String(cachedSendType);
this.isGroup = this.sendType === '2';
}
this.targetName = cachedSenderName || this.targetName;
this.targetAvatar = cachedSenderAvatar || this.targetAvatar;
// 群聊:加载群成员,用于展示发送者昵称/头像
if (this.isGroup && this.senderId) {
this.loadGroupMembersOnly();
}
// 使用完清除缓存,避免下次进入残留
this.clearReportCache();
},
// 仅加载群成员fromChat 场景使用)
async loadGroupMembersOnly() {
try {
const memberRes = await uni.$http.get(`/api/group/members/${this.senderId}`);
this.groupMembers = memberRes.data.data || [];
} catch (e) {
console.error('加载群成员失败', e);
}
},
// 清除聊天页写入的缓存
clearReportCache() {
uni.removeStorageSync('report_selected_messages');
uni.removeStorageSync('report_selected_records');
uni.removeStorageSync('report_sender_id');
uni.removeStorageSync('report_send_type');
uni.removeStorageSync('report_sender_name');
uni.removeStorageSync('report_sender_avatar');
},
// ==================== 加载数据 ====================
async loadGroupInfo() {
const res = await uni.$http.get(`/api/group/find/${this.senderId}`);
const group = res.data.data;
this.targetName = group.groupName;
this.targetAvatar = group.headImage || '';
const memberRes = await uni.$http.get(`/api/group/members/${this.senderId}`);
this.groupMembers = memberRes.data.data || [];
},
async loadUserInfo() {
const res = await uni.$http.get(`/api/friend/find/${this.senderId}`);
const user = res.data.data;
this.targetName = user.nickName || user.showNickName || '未知用户';
this.targetAvatar = user.headImage || '';
},
// ==================== 获取发送者信息 ====================
getSenderAvatar(msg) {
if (msg.selfSend) {
return this.currentUser.avatar || '';
}
if (this.isGroup && msg.sendId) {
const member = this.groupMembers.find(m => m.userId === msg.sendId);
return member ? member.headImage : '';
}
return this.targetAvatar;
},
getSenderName(msg) {
if (msg.selfSend) {
return this.currentUser.nickName || '我';
}
if (this.isGroup && msg.sendId) {
const member = this.groupMembers.find(m => m.userId === msg.sendId);
return member ? (member.showNickName || member.nickName) : '未知';
}
return this.targetName;
},
// ==================== 获取消息完整内容 ====================
getFullMessageContent(msg) {
try {
const type = msg.type;
// 文本消息 - 显示完整原文
if (type === "0" || type === 'TEXT') {
return msg.content || '';
}
// 图片消息
if (type === "1" || type === 'IMAGE') {
return '📷 [图片]';
}
// 语音消息
if (type === "2" || type === 'AUDIO') {
return '🎤 [语音]';
}
// 视频消息
if (type === "3" || type === 'VIDEO') {
return '🎬 [视频]';
}
// 文件消息
if (type === "4" || type === 'FILE') {
try {
const data = JSON.parse(msg.content);
return `📄 [文件] ${data.name || ''}`;
} catch (e) {
return '📄 [文件]';
}
}
// 其他类型
return '[其他消息]';
} catch (e) {
return '[消息]';
}
},
// ==================== 格式化时间 ====================
formatTime(timestamp) {
if (!timestamp) return '';
const date = new Date(timestamp);
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${month}/${day} ${hours}:${minutes}`;
},
// ==================== 投诉原因 ====================
onReasonChange(e) {
this.selectedReason = Number(e.detail.value);
},
// ==================== 提交投诉 ====================
async submitReport() {
let tip = '';
if (!this.selectedReason) {
tip = '请选择投诉原因';
uni.showToast({ title: tip || '请完善投诉信息', icon: 'none' });
return;
}
if (this.allMessages.length === 0) {
tip = '请至少选择一条聊天记录';
uni.showToast({ title: tip || '请完善投诉信息', icon: 'none' });
return;
}
uni.showLoading({ title: '提交中...' });
try {
// 展示的全部聊天记录即本次投诉的完整记录
const messageIds = this.allMessages.map(m => m.id);
const res = await uni.$http.post('/api/report/submit', {
targetUserId: this.senderId,
targetType: this.isGroup ? 2 : 1,
targetGroupId: this.isGroup ? this.senderId : null,
messageIds,
messageDetails: this.allMessages, // 完整聊天记录(含 content/type/sendId/sendTime 等)
reason: this.selectedReason,
description: this.description.trim()
});
if (res.data.success ) {
uni.hideLoading();
uni.showToast({ title: '投诉已提交,我们会尽快处理', icon: 'success' });
setTimeout(() => uni.navigateBack(), 1500);
} else {
uni.hideLoading();
uni.showToast({ title: res.data.msg || '提交失败', icon: 'none' });
}
} catch (e) {
uni.hideLoading();
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
console.error('举报提交失败', e);
}
}
}
};
</script>
<style lang="scss" scoped>
.report-container {
min-height: 100vh;
background-color: #f5f7fa;
padding: 30rpx;
box-sizing: border-box;
}
/* ========== 被投诉人信息 ========== */
.target-info {
background: #ffffff;
border-radius: 20rpx;
padding: 30rpx;
display: flex;
align-items: center;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
.target-avatar {
position: relative;
width: 100rpx;
height: 100rpx;
image {
width: 100%;
height: 100%;
border-radius: 50%;
background: #eee;
}
.group-badge {
position: absolute;
bottom: -4rpx;
right: -4rpx;
background: $im-color-primary;
color: #fff;
font-size: 20rpx;
padding: 2rpx 12rpx;
border-radius: 20rpx;
}
}
.target-detail {
flex: 1;
margin-left: 24rpx;
.target-type {
font-size: 34rpx;
font-weight: 600;
color: #333;
display: block;
}
}
}
/* ========== 聊天记录展示 ========== */
.selected-messages {
background: #ffffff;
border-radius: 20rpx;
padding: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
.selected-header {
display: flex;
justify-content: space-between;
align-items: center;
.selected-title {
font-size: 30rpx;
font-weight: 600;
color: #333;
}
}
.empty-selected {
margin-top: 16rpx;
padding: 30rpx 0;
text-align: center;
color: #ccc;
font-size: 26rpx;
border: 2rpx dashed #eee;
border-radius: 12rpx;
}
.message-list {
margin-top: 16rpx;
}
}
/* ========== 聊天记录条目(只读展示) ========== */
.message-item {
display: flex;
align-items: flex-start;
padding: 16rpx 10rpx;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.msg-content-wrapper {
flex: 1;
min-width: 0;
.msg-header {
display: flex;
align-items: center;
gap: 12rpx;
image {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background: #eee;
flex-shrink: 0;
}
.sender-name {
font-size: 24rpx;
color: #333;
font-weight: 500;
}
.msg-time {
font-size: 20rpx;
color: #bbb;
margin-left: auto;
flex-shrink: 0;
}
}
.msg-body {
font-size: 28rpx;
color: #555;
margin-top: 4rpx;
word-break: break-all;
line-height: 1.6;
white-space: pre-wrap;
}
}
}
/* ========== 投诉原因 & 描述 ========== */
.reason-section, .desc-section {
background: #ffffff;
border-radius: 20rpx;
padding: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
}
.section-title {
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 16rpx;
.required {
color: #e64340;
}
.optional {
font-weight: 400;
color: #999;
font-size: 24rpx;
}
}
.reason-item {
display: flex;
align-items: center;
padding: 14rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
radio {
transform: scale(0.8);
margin-right: 16rpx;
}
.reason-text {
font-size: 28rpx;
color: #333;
}
}
.desc-input {
width: 100%;
min-height: 140rpx;
padding: 16rpx;
background: #f8fafc;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
border: none;
box-sizing: border-box;
}
.char-count {
text-align: right;
font-size: 24rpx;
color: #bbb;
margin-top: 8rpx;
}
/* ========== 提交按钮 ========== */
.btn-wrapper {
padding: 20rpx 0 40rpx;
.submit-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: $im-color-primary;
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
border: none;
box-shadow: 0 4rpx 12rpx $im-color-primary;
&:disabled {
background: #ccc;
box-shadow: none;
}
}
}
</style>