Files
im_manager/web/src/views/cultivate/reports/index.vue
T

215 lines
7.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<div class="n-layout-page-header"
><n-card :bordered="false" title="举报处理"
>查看物友动态、评论及用户举报并记录处理结果。</n-card
></div
>
<n-card :bordered="false" class="proCard">
<BasicForm
ref="searchFormRef"
@register="register"
@submit="reloadTable"
@reset="reloadTable"
/>
<BasicTable
ref="actionRef"
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
:actionColumn="actionColumn"
:scroll-x="1650"
/>
</n-card>
<n-modal
v-model:show="showHandle"
preset="dialog"
title="处理举报"
positive-text="确认"
negative-text="取消"
@positive-click="submitHandle"
>
<n-space vertical>
<n-select v-model:value="handleForm.action" :options="handleOptions" />
<n-select
v-model:value="handleForm.contentAction"
:options="contentActionOptions"
:disabled="handleForm.action !== 'resolve'"
placeholder="内容联动处置"
/>
<n-select
v-model:value="handleForm.userAction"
:options="userActionOptions"
:disabled="handleForm.action !== 'resolve'"
placeholder="用户联动处置"
/>
<n-input
v-model:value="handleForm.reason"
type="textarea"
placeholder="联动处置时必须填写原因"
/>
<n-input
v-model:value="handleForm.handleResult"
type="textarea"
placeholder="办结或驳回时必须填写处理结果"
/>
</n-space>
</n-modal>
<n-modal v-model:show="showDetail" preset="card" title="举报详情" class="detail-modal">
<n-spin :show="detailLoading">
<n-descriptions v-if="detail" bordered :column="2">
<n-descriptions-item label="举报人"
>{{ detail.reporterNickname || '-' }}({{ detail.reporterId }})</n-descriptions-item
>
<n-descriptions-item label="被举报人"
>{{ detail.reportedUserNickname || '-' }}({{
detail.reportedUserId
}})</n-descriptions-item
>
<n-descriptions-item label="对象"
>{{ detail.objectType }} / {{ detail.objectId }}</n-descriptions-item
>
<n-descriptions-item label="原因">{{ detail.reasonCode }}</n-descriptions-item>
<n-descriptions-item label="说明" :span="2">{{
detail.description || '-'
}}</n-descriptions-item>
<n-descriptions-item label="证据文件" :span="2">{{
formatEvidence(detail.evidenceFileIds)
}}</n-descriptions-item>
<n-descriptions-item v-if="detail.targetContent" label="目标内容" :span="2">{{
detail.targetContent.contentText || '-'
}}</n-descriptions-item>
</n-descriptions>
<n-divider title-placement="left">该用户近期举报记录</n-divider>
<n-data-table :columns="historyColumns" :data="detail?.history || []" :pagination="false" />
</n-spin>
</n-modal>
</div>
</template>
<script lang="ts" setup>
import { h, onMounted, reactive, ref, watch } from 'vue';
import { useMessage } from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';
import { BasicForm, useForm } from '@/components/Form';
import { ReportHandle, ReportList, ReportView } from '@/api/cultivate/content';
import { columns, loadOptions, ReportState, schemas } from './model';
const actionRef = ref();
const searchFormRef = ref<any>({});
const showHandle = ref(false);
const showDetail = ref(false);
const detailLoading = ref(false);
const detail = ref<any>();
const selected = ref<ReportState>();
const message = useMessage();
const handleForm = reactive({
action: 'processing',
handleResult: '',
contentAction: 'none',
userAction: 'none',
reason: '',
});
const handleOptions = [
{ label: '标记处理中', value: 'processing' },
{ label: '确认处理', value: 'resolve' },
{ label: '驳回举报', value: 'reject' },
];
const contentActionOptions = [
{ label: '不处置内容', value: 'none' },
{ label: '下架被举报内容', value: 'take_down' },
];
const userActionOptions = [
{ label: '不处置用户', value: 'none' },
{ label: '冻结用户', value: 'freeze' },
{ label: '封禁用户', value: 'ban' },
];
const historyColumns = [
{ title: '举报ID', key: 'id' },
{ title: '对象类型', key: 'objectType' },
{ title: '原因', key: 'reasonCode' },
{ title: '状态', key: 'status' },
{ title: '提交时间', key: 'createdAt' },
];
watch(
() => handleForm.action,
(action) => {
if (action !== 'resolve') {
handleForm.contentAction = 'none';
handleForm.userAction = 'none';
handleForm.reason = '';
}
}
);
const [register] = useForm({ gridProps: { cols: '1 s:1 m:2 l:4' }, labelWidth: 90, schemas });
const loadDataTable = (res) => ReportList({ ...searchFormRef.value?.formModel, ...res });
const reloadTable = () => actionRef.value?.reload();
function openHandle(row: ReportState) {
selected.value = row;
Object.assign(handleForm, {
action: row.status === 'submitted' ? 'processing' : 'resolve',
handleResult: '',
contentAction: 'none',
userAction: 'none',
reason: '',
});
showHandle.value = true;
}
async function openDetail(row: ReportState) {
showDetail.value = true;
detailLoading.value = true;
try {
detail.value = await ReportView({ id: row.id });
} finally {
detailLoading.value = false;
}
}
function formatEvidence(value: any) {
if (!value) return '-';
if (Array.isArray(value)) return value.join('、');
return typeof value === 'string' ? value : JSON.stringify(value);
}
async function submitHandle() {
if (!selected.value) return false;
if (handleForm.action !== 'processing' && !handleForm.handleResult.trim()) {
message.warning('请填写处理结果');
return false;
}
if (
(handleForm.contentAction !== 'none' || handleForm.userAction !== 'none') &&
!handleForm.reason.trim()
) {
message.warning('请填写联动处置原因');
return false;
}
await ReportHandle({ id: selected.value.id, ...handleForm });
message.success('处理成功');
reloadTable();
return true;
}
const actionColumn = reactive({
width: 160,
title: '操作',
key: 'action',
fixed: 'right',
render(row: ReportState) {
return h(TableAction as any, {
style: 'button',
actions: [
{ label: '详情', onClick: () => openDetail(row), auth: ['/cultivate/reports/view'] },
{
label: '处理',
onClick: () => openHandle(row),
auth: ['/cultivate/reports/handle'],
disabled: row.status === 'resolved' || row.status === 'rejected',
},
],
});
},
});
onMounted(loadOptions);
</script>
<style scoped>
.detail-modal {
width: min(1000px, 92vw);
}
</style>