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

<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>