fix: 修复表单数据处理和API端点问题
修复RawDataCards和CustomerDetail组件中表单数据的默认值和类型定义 更新getTodayCall API端点路径为current_camp_call 调整sale.vue中表单数据处理逻辑以适应新API响应格式 优化PerformanceComparison组件的数据处理逻辑 修改开发环境API基础路径为本地测试地址
This commit is contained in:
@@ -7,7 +7,7 @@ export const getProblemDistribution = (params) => {
|
|||||||
|
|
||||||
// 今日通话 /api/v1/more_level_screening/today_call
|
// 今日通话 /api/v1/more_level_screening/today_call
|
||||||
export const getTodayCall = (params) => {
|
export const getTodayCall = (params) => {
|
||||||
return https.post('/api/v1/sales/today_call', params)
|
return https.post('/api/v1/sales/current_camp_call', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表格填写率 /api/v1/more_level_screening/table_filling_rate
|
// 表格填写率 /api/v1/more_level_screening/table_filling_rate
|
||||||
|
|||||||
@@ -74,7 +74,10 @@ export const getAbnormalResponseRate = (params) => {
|
|||||||
export const getHistoryCamps = (params) => {
|
export const getHistoryCamps = (params) => {
|
||||||
return https.post('/api/v1/level_three/overview/get_history_camps', params)
|
return https.post('/api/v1/level_three/overview/get_history_camps', params)
|
||||||
}
|
}
|
||||||
|
// 数据对比 /api/v1/level_three/overview/get_team_many_target
|
||||||
|
export const getTeamManyTarget = (params) => {
|
||||||
|
return https.post('/api/v1/level_three/overview/get_team_many_target', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { useUserStore } from '@/stores/user'
|
|||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: 'https://mldash.nycjy.cn/' || '', // API基础路径,支持完整URL
|
// baseURL: 'https://mldash.nycjy.cn/' || '', // API基础路径,支持完整URL
|
||||||
// baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
|
baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
|
||||||
timeout: 100000, // 请求超时时间
|
timeout: 100000, // 请求超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json;charset=UTF-8'
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ const props = defineProps({
|
|||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
formInfo: {
|
formInfo: {
|
||||||
type: Object,
|
type: Array,
|
||||||
default: () => ({})
|
default: () => []
|
||||||
},
|
},
|
||||||
chatRecords: {
|
chatRecords: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -193,89 +193,34 @@ const startBasicAnalysis = async () => {
|
|||||||
basicAnalysisResult.value = '';
|
basicAnalysisResult.value = '';
|
||||||
|
|
||||||
// 构建表单信息
|
// 构建表单信息
|
||||||
const formData = props.formInfo || {};
|
const formData = props.formInfo || [];
|
||||||
let formInfoText = '暂无表单信息';
|
let formInfoText = '暂无表单信息';
|
||||||
|
|
||||||
if (Object.keys(formData).length > 0) {
|
// ** 适配新的 formInfo 数组格式 **
|
||||||
|
if (Array.isArray(formData) && formData.length > 0) {
|
||||||
const allInfo = [];
|
const allInfo = [];
|
||||||
|
|
||||||
// 处理第一种格式:基础信息和additional_info
|
// 遍历新格式: [{ question_label: "...", answer: "..." }, ...]
|
||||||
if (formData.name || formData.mobile || formData.additional_info) {
|
formData.forEach(item => {
|
||||||
const basicInfo = [];
|
// 检查字段是否存在且答案有效
|
||||||
const additionalInfo = [];
|
if (
|
||||||
|
item.question_label &&
|
||||||
const basicFields = {
|
item.answer &&
|
||||||
name: '姓名',
|
item.answer !== '暂无' &&
|
||||||
mobile: '手机号',
|
item.answer !== ''
|
||||||
occupation: '职业',
|
) {
|
||||||
territory: '地区',
|
// 格式化为 "问题标签: 答案"
|
||||||
child_name: '孩子姓名',
|
allInfo.push(`${item.question_label.trim()}: ${item.answer.trim()}`);
|
||||||
child_gender: '孩子性别',
|
|
||||||
child_education: '孩子教育阶段',
|
|
||||||
child_relation: '与孩子关系'
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.entries(basicFields).forEach(([key, label]) => {
|
|
||||||
if (formData[key] && formData[key] !== '暂无' && formData[key] !== '') {
|
|
||||||
basicInfo.push(`${label}: ${formData[key]}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (formData.additional_info && Array.isArray(formData.additional_info)) {
|
|
||||||
formData.additional_info.forEach(item => {
|
|
||||||
if (item.topic && item.answer) {
|
|
||||||
additionalInfo.push(`${item.topic}\n答案: ${item.answer}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (basicInfo.length > 0) {
|
// 格式化表单信息文本
|
||||||
allInfo.push('=== 基础信息 ===');
|
formInfoText = allInfo.length > 0
|
||||||
allInfo.push(...basicInfo);
|
? `=== 问卷/表单信息 ===\n${allInfo.join('\n')}`
|
||||||
}
|
: '暂无有效问卷/表单信息';
|
||||||
|
|
||||||
if (additionalInfo.length > 0) {
|
|
||||||
allInfo.push('\n=== 问卷信息 ===');
|
|
||||||
allInfo.push(...additionalInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理第二种格式:customerExpandFieldMap
|
|
||||||
if (formData.customerExpandFieldMap) {
|
|
||||||
const expandInfo = [];
|
|
||||||
const map = formData.customerExpandFieldMap;
|
|
||||||
|
|
||||||
Object.entries(map).forEach(([key, value]) => {
|
|
||||||
if (!map.hasOwnProperty(key)) return;
|
|
||||||
|
|
||||||
if (value && typeof value === 'object' && value.key) {
|
|
||||||
const question = value.key;
|
|
||||||
let answer = '';
|
|
||||||
|
|
||||||
if (value.typeCode === 'SINGLE_SELECT' || value.typeCode === 'MULTIPLE_SELECT') {
|
|
||||||
if (value.expandValueList && value.expandValueList.length > 0) {
|
|
||||||
answer = value.expandValueList.map(item => item.itemName).join('、');
|
|
||||||
}
|
|
||||||
} else if (value.typeCode === 'TEXT' || value.typeCode === 'TEXTAREA' || value.typeCode === 'NUMBER') {
|
|
||||||
answer = formData[key] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (answer && answer !== '暂无' && answer !== '') {
|
|
||||||
expandInfo.push(`${question}\n答案: ${answer}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (expandInfo.length > 0) {
|
|
||||||
if (allInfo.length > 0) allInfo.push('\n');
|
|
||||||
allInfo.push('=== 问卷详细信息 ===');
|
|
||||||
allInfo.push(...expandInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formInfoText = allInfo.length > 0 ? allInfo.join('\n') : '暂无表单信息';
|
|
||||||
}
|
}
|
||||||
|
// ** 适配结束 **
|
||||||
|
|
||||||
// 构建聊天记录信息
|
// 构建聊天记录信息
|
||||||
const chatData = props.chatRecords || [];
|
const chatData = props.chatRecords || [];
|
||||||
const chatInfoText = chatData.messages && chatData.messages.length > 0 ?
|
const chatInfoText = chatData.messages && chatData.messages.length > 0 ?
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
formInfo: {
|
formInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => []
|
||||||
},
|
},
|
||||||
chatInfo: {
|
chatInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ async function getCoreKpi() {
|
|||||||
// 今日通话数据
|
// 今日通话数据
|
||||||
const res = await getTodayCall(hasParams ? params : undefined)
|
const res = await getTodayCall(hasParams ? params : undefined)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
kpiDataState.totalCalls = res.data.today_call
|
kpiDataState.totalCalls = res.data.call_count
|
||||||
}
|
}
|
||||||
// 转化率、分配数据量、加微率
|
// 转化率、分配数据量、加微率
|
||||||
const conversionRes = await getConversionRateAndAllocatedData(hasParams ? params : undefined)
|
const conversionRes = await getConversionRateAndAllocatedData(hasParams ? params : undefined)
|
||||||
@@ -582,8 +582,9 @@ async function getCustomerForm() {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await getCustomerFormInfo(params)
|
const res = await getCustomerFormInfo(params)
|
||||||
|
console.log('获取客户表单数据:', res)
|
||||||
if(res.code === 200) {
|
if(res.code === 200) {
|
||||||
formInfo.value = res.data
|
formInfo.value = res.data[0].answer || []
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 静默处理错误
|
// 静默处理错误
|
||||||
|
|||||||
@@ -60,42 +60,41 @@ import { ref, computed, onMounted, watch } from 'vue';
|
|||||||
// 假设你有一个API服务来获取对比数据
|
// 假设你有一个API服务来获取对比数据
|
||||||
// import { getPerformanceComparisonData } from '@/api/senorManger.js';
|
// import { getPerformanceComparisonData } from '@/api/senorManger.js';
|
||||||
|
|
||||||
// 模拟API调用
|
// **MODIFIED**: 更新模拟API以返回新的数据结构
|
||||||
const getPerformanceComparisonData = async (params) => {
|
const getPerformanceComparisonData = async (params) => {
|
||||||
console.log('模拟API请求:', params);
|
console.log('模拟API请求 (新数据结构):', params);
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 模拟不同周期返回不同数据
|
|
||||||
let mockData;
|
let mockData;
|
||||||
if (params.period === 'last_week') {
|
if (params.period === 'last_week') {
|
||||||
mockData = {
|
mockData = {
|
||||||
assignedLeads: 480,
|
"allocated_data_volume": 650,
|
||||||
wechatAdds: 390,
|
"wechat_added_volume": 410,
|
||||||
calls: 1450,
|
"call_volume_after_classification": { "加微通话": 10, "20分钟通话": 50, "未分类": 150, "无效通话": 100, "促到课": 40 },
|
||||||
callDuration: 11500,
|
"call_avg_duration_after_classification": { "加微通话": 4.5, "20分钟通话": 15.0, "未分类": 1.5, "无效通话": 1.0, "促到课": 2.0 },
|
||||||
deposits: 38,
|
"deposit_volume": 40,
|
||||||
deals: 50,
|
"transaction_volume": 52,
|
||||||
conversionRate: 10.4,
|
"conversion_rate": "8.00%"
|
||||||
};
|
};
|
||||||
} else if (params.period === 'last_month') {
|
} else if (params.period === 'last_month') {
|
||||||
mockData = {
|
mockData = {
|
||||||
assignedLeads: 2000,
|
"allocated_data_volume": 2800,
|
||||||
wechatAdds: 1500,
|
"wechat_added_volume": 1800,
|
||||||
calls: 5800,
|
"call_volume_after_classification": { "加微通话": 40, "20分钟通话": 220, "未分类": 600, "视频通话": 50, "无效通话": 450, "促到课": 180 },
|
||||||
callDuration: 48000,
|
"call_avg_duration_after_classification": { "加微通话": 5.0, "20分钟通话": 16.0, "未分类": 1.8, "视频通话": 6.0, "无效通话": 1.1, "促到课": 1.5 },
|
||||||
deposits: 150,
|
"deposit_volume": 180,
|
||||||
deals: 210,
|
"transaction_volume": 230,
|
||||||
conversionRate: 10.5,
|
"conversion_rate": "8.21%"
|
||||||
};
|
};
|
||||||
} else {
|
} else { // last_quarter
|
||||||
mockData = {
|
mockData = {
|
||||||
assignedLeads: 6500,
|
"allocated_data_volume": 8500,
|
||||||
wechatAdds: 5200,
|
"wechat_added_volume": 5500,
|
||||||
calls: 18000,
|
"call_volume_after_classification": { "加微通话": 120, "20分钟通话": 650, "未分类": 1800, "视频通话": 150, "无效通话": 1200, "促到课": 500 },
|
||||||
callDuration: 150000,
|
"call_avg_duration_after_classification": { "加微通话": 4.8, "20分钟通话": 16.5, "未分类": 1.7, "视频通话": 5.5, "无效通话": 1.0, "促到课": 1.8 },
|
||||||
deposits: 450,
|
"deposit_volume": 550,
|
||||||
deals: 600,
|
"transaction_volume": 700,
|
||||||
conversionRate: 9.2,
|
"conversion_rate": "8.24%"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
resolve({ code: 200, data: mockData });
|
resolve({ code: 200, data: mockData });
|
||||||
@@ -125,12 +124,11 @@ const selectedPeriodLabel = computed(() => periodLabels[selectedPeriod.value]);
|
|||||||
const fetchComparisonData = async () => {
|
const fetchComparisonData = async () => {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// 真实场景中,这里应该调用API
|
|
||||||
const res = await getPerformanceComparisonData({ period: selectedPeriod.value });
|
const res = await getPerformanceComparisonData({ period: selectedPeriod.value });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
previousPeriodData.value = res.data;
|
previousPeriodData.value = res.data;
|
||||||
} else {
|
} else {
|
||||||
previousPeriodData.value = null; // API出错或无数据
|
previousPeriodData.value = null;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取对比数据失败:', error);
|
console.error('获取对比数据失败:', error);
|
||||||
@@ -144,14 +142,54 @@ onMounted(() => {
|
|||||||
fetchComparisonData();
|
fetchComparisonData();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 如果本期数据可能变化,可以监听props来刷新
|
|
||||||
watch(() => props.currentPeriodData, () => {
|
watch(() => props.currentPeriodData, () => {
|
||||||
fetchComparisonData();
|
fetchComparisonData();
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
|
|
||||||
|
// **NEW**: 新增一个工具函数,用于处理API返回的复杂数据结构
|
||||||
|
// 并将其转换为表格渲染所需的扁平化结构
|
||||||
|
const processRawData = (rawData) => {
|
||||||
|
if (!rawData) return null;
|
||||||
|
|
||||||
|
// 1. 计算通话总量
|
||||||
|
const totalCalls = Object.values(rawData.call_volume_after_classification || {})
|
||||||
|
.reduce((sum, count) => sum + count, 0);
|
||||||
|
|
||||||
|
// 2. 计算通话总时长 (分钟)
|
||||||
|
// 逻辑: (分类通话数 * 分类平均时长) 的总和
|
||||||
|
const callVolumes = rawData.call_volume_after_classification || {};
|
||||||
|
const avgDurations = rawData.call_avg_duration_after_classification || {};
|
||||||
|
const totalDurationInMinutes = Object.keys(callVolumes).reduce((sum, key) => {
|
||||||
|
const volume = callVolumes[key] || 0;
|
||||||
|
const avgDuration = avgDurations[key] || 0;
|
||||||
|
return sum + (volume * avgDuration);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// 3. 将转化率字符串 "7.98%" 转为数字 7.98
|
||||||
|
const conversionRateValue = parseFloat(rawData.conversion_rate) || 0;
|
||||||
|
|
||||||
|
// 4. 返回一个与旧版组件兼容的对象结构
|
||||||
|
return {
|
||||||
|
assignedLeads: rawData.allocated_data_volume,
|
||||||
|
wechatAdds: rawData.wechat_added_volume,
|
||||||
|
calls: totalCalls,
|
||||||
|
// 组件内部格式化时会除以60,因此这里需要乘以60,将分钟转为秒
|
||||||
|
callDuration: totalDurationInMinutes * 60,
|
||||||
|
deposits: rawData.deposit_volume,
|
||||||
|
deals: rawData.transaction_volume,
|
||||||
|
conversionRate: conversionRateValue,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const comparedMetrics = computed(() => {
|
const comparedMetrics = computed(() => {
|
||||||
if (!props.currentPeriodData || !previousPeriodData.value) return [];
|
// **MODIFIED**: 在计算前,先使用 processRawData 对数据进行处理
|
||||||
|
const processedCurrentData = processRawData(props.currentPeriodData);
|
||||||
|
const processedPreviousData = processRawData(previousPeriodData.value);
|
||||||
|
|
||||||
|
if (!processedCurrentData || !processedPreviousData) return [];
|
||||||
|
|
||||||
|
// 指标配置保持不变,因为数据已经被处理成它期望的格式
|
||||||
const metricsConfig = [
|
const metricsConfig = [
|
||||||
{ key: 'assignedLeads', label: '分配数据量', unit: '个' },
|
{ key: 'assignedLeads', label: '分配数据量', unit: '个' },
|
||||||
{ key: 'wechatAdds', label: '加微量', unit: '个' },
|
{ key: 'wechatAdds', label: '加微量', unit: '个' },
|
||||||
@@ -163,8 +201,8 @@ const comparedMetrics = computed(() => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return metricsConfig.map(metric => {
|
return metricsConfig.map(metric => {
|
||||||
const current = props.currentPeriodData[metric.key];
|
const current = processedCurrentData[metric.key];
|
||||||
const previous = previousPeriodData.value[metric.key];
|
const previous = processedPreviousData[metric.key];
|
||||||
return {
|
return {
|
||||||
...metric,
|
...metric,
|
||||||
current,
|
current,
|
||||||
@@ -198,6 +236,7 @@ const calculateChange = (current, previous) => {
|
|||||||
const formatValue = (value, unit) => {
|
const formatValue = (value, unit) => {
|
||||||
if (value === null || value === undefined) return '-';
|
if (value === null || value === undefined) return '-';
|
||||||
if (unit === '分钟') {
|
if (unit === '分钟') {
|
||||||
|
// 假设传入的value是秒,转换为分钟显示
|
||||||
return `${Math.round(value / 60)} 分钟`;
|
return `${Math.round(value / 60)} 分钟`;
|
||||||
}
|
}
|
||||||
if (unit === '%') {
|
if (unit === '%') {
|
||||||
@@ -212,6 +251,7 @@ const formatChange = (diff, unit) => {
|
|||||||
const absDiff = Math.abs(diff);
|
const absDiff = Math.abs(diff);
|
||||||
|
|
||||||
if (unit === '分钟') {
|
if (unit === '分钟') {
|
||||||
|
// 假设diff是秒,转换为分钟显示
|
||||||
return `${prefix}${Math.round(absDiff / 60)} 分钟`;
|
return `${prefix}${Math.round(absDiff / 60)} 分钟`;
|
||||||
}
|
}
|
||||||
if (unit === '%') {
|
if (unit === '%') {
|
||||||
@@ -229,12 +269,12 @@ const getChangeClass = (trend) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
/* 样式部分无需改动,因此省略以保持简洁 */
|
||||||
.performance-comparison {
|
.performance-comparison {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
margin-top: 1.5rem;
|
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +282,6 @@ const getChangeClass = (trend) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 2rem;
|
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
border-bottom: 1px solid #f1f5f9;
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,10 @@
|
|||||||
:severeTimeoutRate="statisticalIndicators.severeTimeoutRate"
|
:severeTimeoutRate="statisticalIndicators.severeTimeoutRate"
|
||||||
:formCompletionRate="statisticalIndicators.formCompletionRate"
|
:formCompletionRate="statisticalIndicators.formCompletionRate"
|
||||||
/>
|
/>
|
||||||
|
<!-- 新增:业绩周期对比组件 -->
|
||||||
|
<div v-if="cardVisibility.performanceComparison" class="performance-comparison-section">
|
||||||
|
<PerformanceComparison :current-period-data="currentPeriodMetrics" />
|
||||||
|
</div>
|
||||||
<!-- Bottom Section -->
|
<!-- Bottom Section -->
|
||||||
<div class="bottom-section">
|
<div class="bottom-section">
|
||||||
<!-- Left Section - Group Performance Ranking -->
|
<!-- Left Section - Group Performance Ranking -->
|
||||||
@@ -90,10 +94,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新增:业绩周期对比组件 -->
|
|
||||||
<div v-if="cardVisibility.performanceComparison" class="performance-comparison-section">
|
|
||||||
<PerformanceComparison :current-period-data="currentPeriodMetrics" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Team Members Detail Section -->
|
<!-- Team Members Detail Section -->
|
||||||
<div class="team-detail-section" v-if="selectedGroup && cardVisibility.teamDetail">
|
<div class="team-detail-section" v-if="selectedGroup && cardVisibility.teamDetail">
|
||||||
@@ -996,10 +997,6 @@ const hideTooltip = () => {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 新增 */
|
|
||||||
.performance-comparison-section {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-items-compact {
|
.action-items-compact {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
Reference in New Issue
Block a user