feat(users): enforce real bans from report processing and fix appeal lifting
- apply_report_action now writes aksrt_user_restriction via Restriction::restrict
and lifts via new lift_user_restriction(), replacing the display-only
aksrt_user_ban_state meta dual-track
- ban type restrictions destroy the target user's sessions on apply
- appeal approval lifts active ban/suspend/mute restrictions instead of
updating a nonexistent status column
- UsersBan.vue posts to /users/{id}/restrict with valid types (warn/mute/
suspend/ban), scope and expires_at
- add comment report entry to the comment actions dropdown
- add duplicate pending report guard on submit
- remove dead ReportCenter ajax handlers, option migration, REST alias
routes and write-only restriction meta
- fix report admin mail link to the real aksrt_user_ban page
- add report-ban contract tests
This commit is contained in:
@@ -52,6 +52,9 @@
|
||||
<n-form-item label="限制类型">
|
||||
<n-select v-model:value="addForm.type" :options="restrictionTypes" style="width:200px;" />
|
||||
</n-form-item>
|
||||
<n-form-item label="限制范围">
|
||||
<n-select v-model:value="addForm.scope" :options="scopeOptions" style="width:200px;" />
|
||||
</n-form-item>
|
||||
<n-form-item label="原因">
|
||||
<n-input v-model:value="addForm.reason" type="textarea" :rows="2" placeholder="限制原因(必填)" />
|
||||
</n-form-item>
|
||||
@@ -84,15 +87,22 @@ const stats = reactive({ total: 0, active: 0, banned: 0 })
|
||||
|
||||
const addForm = reactive({
|
||||
user_id: null,
|
||||
type: 'muted',
|
||||
type: 'mute',
|
||||
scope: 'global',
|
||||
reason: '',
|
||||
duration: '7d',
|
||||
})
|
||||
|
||||
const restrictionTypes = [
|
||||
{ label: '禁言', value: 'muted' },
|
||||
{ label: '限制', value: 'restricted' },
|
||||
{ label: '封禁', value: 'banned' },
|
||||
{ label: '警告', value: 'warn' },
|
||||
{ label: '禁言', value: 'mute' },
|
||||
{ label: '停权', value: 'suspend' },
|
||||
{ label: '封禁', value: 'ban' },
|
||||
]
|
||||
|
||||
const scopeOptions = [
|
||||
{ label: '全局', value: 'global' },
|
||||
{ label: '仅评论', value: 'comment' },
|
||||
]
|
||||
|
||||
const durationOptions = [
|
||||
@@ -126,15 +136,22 @@ const columns = [
|
||||
]
|
||||
|
||||
function getTypeTag(type) {
|
||||
const map = { muted: 'warning', restricted: 'error', banned: 'error' }
|
||||
const map = { warn: 'info', mute: 'warning', suspend: 'warning', ban: 'error' }
|
||||
return map[type] || 'default'
|
||||
}
|
||||
|
||||
function getTypeLabel(type) {
|
||||
const map = { muted: '禁言', restricted: '限制', banned: '封禁' }
|
||||
const map = { warn: '警告', mute: '禁言', suspend: '停权', ban: '封禁' }
|
||||
return map[type] || type
|
||||
}
|
||||
|
||||
function durationToExpiresAt(duration) {
|
||||
if (!duration || duration === 'permanent') return ''
|
||||
const days = parseInt(duration, 10)
|
||||
if (!Number.isFinite(days) || days <= 0) return ''
|
||||
return new Date(Date.now() + days * 86400000).toISOString()
|
||||
}
|
||||
|
||||
async function loadStats() {
|
||||
try {
|
||||
const res = await api.request('/users/restrictions/stats')
|
||||
@@ -174,12 +191,13 @@ async function addRestriction() {
|
||||
}
|
||||
adding.value = true
|
||||
try {
|
||||
await api.request(`/users/${addForm.user_id}/restrictions`, {
|
||||
await api.request(`/users/${addForm.user_id}/restrict`, {
|
||||
method: 'POST',
|
||||
data: {
|
||||
type: addForm.type,
|
||||
scope: addForm.scope,
|
||||
reason: addForm.reason,
|
||||
duration: addForm.duration,
|
||||
expires_at: durationToExpiresAt(addForm.duration),
|
||||
},
|
||||
})
|
||||
message.success('限制已添加')
|
||||
|
||||
Reference in New Issue
Block a user