feat: add tenant content moderation controls

This commit is contained in:
richjohnrambo
2026-09-16 22:21:42 +08:00
parent 32491e9cdd
commit fec2a43b9c
14 changed files with 1156 additions and 431 deletions
+68 -5
View File
@@ -8,7 +8,11 @@
>
<n-form ref="formRef" :model="formValue" label-placement="left" label-width="90">
<n-form-item label="服务商">
<n-input v-model:value="formValue.provider" placeholder="请输入服务商" />
<n-input
v-model:value="formValue.provider"
:disabled="isModeration"
placeholder="请输入服务商"
/>
</n-form-item>
<n-form-item label="端点">
<n-input v-model:value="formValue.endpoint" placeholder="请输入服务端点" />
@@ -16,7 +20,42 @@
<n-form-item label="启用">
<n-switch v-model:value="enabledValue" />
</n-form-item>
<n-form-item label="普通配置">
<template v-if="isModeration">
<n-form-item label="地域"
><n-input v-model:value="moderationConfig.region_id"
/></n-form-item>
<n-form-item label="昵称服务"
><n-input v-model:value="moderationConfig.nickname_service"
/></n-form-item>
<n-form-item label="消息服务"
><n-input v-model:value="moderationConfig.chat_service"
/></n-form-item>
<n-form-item label="超时毫秒"
><n-input-number v-model:value="moderationConfig.timeout_ms" :min="200" :max="10000"
/></n-form-item>
<n-form-item label="异常策略"
><n-radio-group v-model:value="moderationConfig.failure_mode"
><n-space
><n-radio value="allow">放行</n-radio><n-radio value="block">拦截</n-radio></n-space
></n-radio-group
></n-form-item
>
<n-form-item label="AccessKey ID"
><n-input
v-model:value="moderationSecret.access_key_id"
type="password"
show-password-on="click"
placeholder="留空保持原值"
/></n-form-item>
<n-form-item label="AccessKey Secret"
><n-input
v-model:value="moderationSecret.access_key_secret"
type="password"
show-password-on="click"
placeholder="留空保持原值"
/></n-form-item>
</template>
<n-form-item v-else label="普通配置">
<n-input
v-model:value="formValue.configJson"
type="textarea"
@@ -24,7 +63,7 @@
placeholder="请输入JSON配置"
/>
</n-form-item>
<n-form-item label="敏感配置">
<n-form-item v-if="!isModeration" label="敏感配置">
<n-input
v-model:value="formValue.secretJson"
type="textarea"
@@ -68,6 +107,15 @@
formValue.value.enabled = value ? 1 : 0;
},
});
const isModeration = computed(() => formValue.value.service === 'moderation');
const moderationConfig = ref<any>({
region_id: 'cn-shanghai',
nickname_service: 'nickname_detection_pro',
chat_service: 'chat_detection_pro',
timeout_ms: 1500,
failure_mode: 'allow',
});
const moderationSecret = ref<any>({ access_key_id: '', access_key_secret: '' });
function closeForm() {
showModal.value = false;
@@ -86,8 +134,14 @@
async function handleSubmit() {
submitLoading.value = true;
try {
const configJson = parseJson(formValue.value.configJson || '{}', '普通配置') || {};
const secretJson = parseJson(formValue.value.secretJson, '敏感配置');
const configJson = isModeration.value
? moderationConfig.value
: parseJson(formValue.value.configJson || '{}', '普通配置') || {};
const secretJson = isModeration.value
? moderationSecret.value.access_key_id || moderationSecret.value.access_key_secret
? moderationSecret.value
: null
: parseJson(formValue.value.secretJson, '敏感配置');
await Update({
tenantId: formValue.value.tenantId,
service: formValue.value.service,
@@ -111,6 +165,15 @@
formValue.value = newState(state);
formValue.value.secretJson = '';
if (!formValue.value.configJson) formValue.value.configJson = '{}';
if (formValue.value.service === 'moderation') {
formValue.value.provider = 'aliyun_green';
formValue.value.endpoint ||= 'green-cip.cn-shanghai.aliyuncs.com';
moderationConfig.value = {
...moderationConfig.value,
...(parseJson(formValue.value.configJson, '普通配置') || {}),
};
moderationSecret.value = { access_key_id: '', access_key_secret: '' };
}
showModal.value = true;
}
+18
View File
@@ -82,6 +82,24 @@
/>
</n-form-item>
</n-gi>
<n-gi span="1">
<n-form-item label="阿里云内容审核" path="aliyunModerationEnabled">
<n-switch
v-model:value="formValue.aliyunModerationEnabled"
:checked-value="1"
:unchecked-value="0"
/>
</n-form-item>
</n-gi>
<n-gi span="1">
<n-form-item label="本地内容审核" path="localModerationEnabled">
<n-switch
v-model:value="formValue.localModerationEnabled"
:checked-value="1"
:unchecked-value="0"
/>
</n-form-item>
</n-gi>
<n-gi span="2">
<n-form-item label="商户描述" path="tenantDesc">
<n-input
+28
View File
@@ -19,6 +19,8 @@ export class State {
public maxUsers = 0; // 最大用户数
public maxGroups = 0; // 最大群组数
public maxGroupMembers = 0; // 最大群成员数
public aliyunModerationEnabled = 0; // 是否启用阿里云内容审核
public localModerationEnabled = 0; // 是否启用本地内容审核
public dbDsnConfigured = false; // 是否配置独立连接串
public createdBy = 0; // 创建者
public createdBySumma?: null | MemberSumma = null; // 创建者摘要信息
@@ -208,6 +210,32 @@ export const columns = [
return row.maxGroupMembers > 0 ? row.maxGroupMembers : '不限';
},
},
{
title: '阿里云审核',
key: 'aliyunModerationEnabled',
align: 'left',
width: 120,
render(row: State) {
return h(
NTag,
{ type: row.aliyunModerationEnabled === 1 ? 'success' : 'default', bordered: false },
{ default: () => (row.aliyunModerationEnabled === 1 ? '已启用' : '未启用') }
);
},
},
{
title: '本地审核',
key: 'localModerationEnabled',
align: 'left',
width: 120,
render(row: State) {
return h(
NTag,
{ type: row.localModerationEnabled === 1 ? 'success' : 'default', bordered: false },
{ default: () => (row.localModerationEnabled === 1 ? '已启用' : '未启用') }
);
},
},
{
title: '创建者',
key: 'createdBy',