215 lines
7.1 KiB
Vue
215 lines
7.1 KiB
Vue
<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>
|