更新敏感词管理模块:将敏感词管理组件转换为使用forwardRef,增强与父组件的交互能力;修复敏感词状态更新接口的请求方法;优化删除功能,增加确认删除的弹窗;改进敏感词详情获取逻辑,提升用户体验。
This commit is contained in:
@@ -118,7 +118,7 @@ export function updateSensitiveWord(data: SensitiveWordUpdateRequest) {
|
||||
|
||||
// 违禁词管理-修改状态
|
||||
export function setSensitiveWordStatus(data: SensitiveWordSetStatusRequest) {
|
||||
return request("/v1/kefu/content/sensitiveWord/setStatus", data, "POST");
|
||||
return request("/v1/kefu/content/sensitiveWord/setStatus", data, "GET");
|
||||
}
|
||||
|
||||
// 关键词回复管理相关接口
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, {
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { Button, Input, Card, message, Modal } from "antd";
|
||||
import { Button, Input, Card, message, Popconfirm } from "antd";
|
||||
import {
|
||||
SearchOutlined,
|
||||
FilterOutlined,
|
||||
@@ -91,22 +91,13 @@ const MaterialManagement = forwardRef<any, Record<string, never>>(
|
||||
|
||||
// 素材管理相关函数
|
||||
const handleDeleteMaterial = async (id: number) => {
|
||||
Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: "确定要删除这个素材吗?删除后无法恢复。",
|
||||
okText: "确定",
|
||||
cancelText: "取消",
|
||||
okType: "danger",
|
||||
onOk: async () => {
|
||||
try {
|
||||
await deleteMaterial(id.toString());
|
||||
setMaterialsList(prev => prev.filter(item => item.id !== id));
|
||||
message.success("删除成功");
|
||||
} catch (error) {
|
||||
message.error("删除失败");
|
||||
}
|
||||
},
|
||||
});
|
||||
try {
|
||||
await deleteMaterial(id.toString());
|
||||
setMaterialsList(prev => prev.filter(item => item.id !== id));
|
||||
message.success("删除成功");
|
||||
} catch (error) {
|
||||
message.error("删除失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 编辑素材
|
||||
@@ -167,18 +158,24 @@ const MaterialManagement = forwardRef<any, Record<string, never>>(
|
||||
>
|
||||
编辑
|
||||
</Button>,
|
||||
<Button
|
||||
<Popconfirm
|
||||
key="delete"
|
||||
type="text"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handleDeleteMaterial(item.id);
|
||||
}}
|
||||
title="确认删除"
|
||||
description="确定要删除这个素材吗?删除后无法恢复。"
|
||||
onConfirm={() => handleDeleteMaterial(item.id)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okType="danger"
|
||||
>
|
||||
删除
|
||||
</Button>,
|
||||
<Button
|
||||
type="text"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>,
|
||||
]}
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Input, Tag, Switch, message } from "antd";
|
||||
import React, {
|
||||
useState,
|
||||
useEffect,
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { Button, Input, Tag, Switch, message, Popconfirm } from "antd";
|
||||
import {
|
||||
SearchOutlined,
|
||||
FilterOutlined,
|
||||
@@ -27,206 +32,219 @@ interface SensitiveWordItem {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
const SensitiveWordManagement: React.FC = () => {
|
||||
const [searchValue, setSearchValue] = useState<string>("");
|
||||
const [sensitiveWordsList, setSensitiveWordsList] = useState<
|
||||
SensitiveWordItem[]
|
||||
>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [editModalVisible, setEditModalVisible] = useState<boolean>(false);
|
||||
const [editingSensitiveWordId, setEditingSensitiveWordId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const SensitiveWordManagement = forwardRef<any, Record<string, never>>(
|
||||
(props, ref) => {
|
||||
const [searchValue, setSearchValue] = useState<string>("");
|
||||
const [sensitiveWordsList, setSensitiveWordsList] = useState<
|
||||
SensitiveWordItem[]
|
||||
>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [editModalVisible, setEditModalVisible] = useState<boolean>(false);
|
||||
const [editingSensitiveWordId, setEditingSensitiveWordId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
const getTagColor = (tag: string) => {
|
||||
switch (tag) {
|
||||
case "政治":
|
||||
return "#ff4d4f";
|
||||
case "色情":
|
||||
return "#ff4d4f";
|
||||
case "暴力":
|
||||
return "#ff4d4f";
|
||||
default:
|
||||
return "#ff4d4f";
|
||||
}
|
||||
};
|
||||
const getTagColor = (tag: string) => {
|
||||
switch (tag) {
|
||||
case "政治":
|
||||
return "#ff4d4f";
|
||||
case "色情":
|
||||
return "#ff4d4f";
|
||||
case "暴力":
|
||||
return "#ff4d4f";
|
||||
default:
|
||||
return "#ff4d4f";
|
||||
}
|
||||
};
|
||||
|
||||
// 操作类型映射
|
||||
const getOperationText = (operation: string) => {
|
||||
switch (operation) {
|
||||
case "0":
|
||||
return "不操作";
|
||||
case "1":
|
||||
return "替换";
|
||||
case "2":
|
||||
return "删除";
|
||||
case "3":
|
||||
return "警告";
|
||||
case "4":
|
||||
return "禁止发送";
|
||||
default:
|
||||
return "未知操作";
|
||||
}
|
||||
};
|
||||
// 操作类型映射
|
||||
const getOperationText = (operation: string) => {
|
||||
switch (operation) {
|
||||
case "0":
|
||||
return "不操作";
|
||||
case "1":
|
||||
return "替换";
|
||||
case "2":
|
||||
return "删除";
|
||||
case "3":
|
||||
return "警告";
|
||||
case "4":
|
||||
return "禁止发送";
|
||||
default:
|
||||
return "未知操作";
|
||||
}
|
||||
};
|
||||
|
||||
// 获取敏感词列表
|
||||
const fetchSensitiveWords = async (params?: SensitiveWordListParams) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await getSensitiveWordList(params || {});
|
||||
if (response) {
|
||||
setSensitiveWordsList(response.list || []);
|
||||
} else {
|
||||
// 获取敏感词列表
|
||||
const fetchSensitiveWords = async (params?: SensitiveWordListParams) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await getSensitiveWordList(params || {});
|
||||
if (response) {
|
||||
setSensitiveWordsList(response.list || []);
|
||||
} else {
|
||||
setSensitiveWordsList([]);
|
||||
message.error(response?.message || "获取敏感词列表失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取敏感词列表失败:", error);
|
||||
setSensitiveWordsList([]);
|
||||
message.error(response?.message || "获取敏感词列表失败");
|
||||
message.error("获取敏感词列表失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取敏感词列表失败:", error);
|
||||
setSensitiveWordsList([]);
|
||||
message.error("获取敏感词列表失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 敏感词管理相关函数
|
||||
const handleToggleSensitiveWord = async (id: string) => {
|
||||
try {
|
||||
const response = await setSensitiveWordStatus({ id });
|
||||
if (response) {
|
||||
setSensitiveWordsList(prev =>
|
||||
prev.map(item =>
|
||||
item.id === id ? { ...item, enabled: !item.enabled } : item,
|
||||
),
|
||||
);
|
||||
message.success("状态更新成功");
|
||||
} else {
|
||||
message.error(response?.message || "状态更新失败");
|
||||
// 暴露方法给父组件
|
||||
useImperativeHandle(ref, () => ({
|
||||
fetchSensitiveWords,
|
||||
}));
|
||||
|
||||
// 敏感词管理相关函数
|
||||
const handleToggleSensitiveWord = async (id: string) => {
|
||||
try {
|
||||
const response = await setSensitiveWordStatus({ id });
|
||||
if (response) {
|
||||
setSensitiveWordsList(prev =>
|
||||
prev.map(item =>
|
||||
item.id === id ? { ...item, enabled: !item.enabled } : item,
|
||||
),
|
||||
);
|
||||
message.success("状态更新成功");
|
||||
} else {
|
||||
message.error(response?.message || "状态更新失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("状态更新失败:", error);
|
||||
message.error("状态更新失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("状态更新失败:", error);
|
||||
message.error("状态更新失败");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const handleEditSensitiveWord = (id: string) => {
|
||||
setEditingSensitiveWordId(id);
|
||||
setEditModalVisible(true);
|
||||
};
|
||||
const handleEditSensitiveWord = (id: string) => {
|
||||
setEditingSensitiveWordId(id);
|
||||
setEditModalVisible(true);
|
||||
};
|
||||
|
||||
// 编辑弹窗成功回调
|
||||
const handleEditSuccess = () => {
|
||||
fetchSensitiveWords(); // 重新获取数据
|
||||
};
|
||||
// 编辑弹窗成功回调
|
||||
const handleEditSuccess = () => {
|
||||
fetchSensitiveWords(); // 重新获取数据
|
||||
};
|
||||
|
||||
const handleDeleteSensitiveWord = async (id: string) => {
|
||||
try {
|
||||
const response = await deleteSensitiveWord(id);
|
||||
if (response) {
|
||||
const handleDeleteSensitiveWord = async (id: string) => {
|
||||
try {
|
||||
await deleteSensitiveWord(id);
|
||||
setSensitiveWordsList(prev => prev.filter(item => item.id !== id));
|
||||
message.success("删除成功");
|
||||
} else {
|
||||
message.error(response?.message || "删除失败");
|
||||
} catch (error) {
|
||||
console.error("删除失败:", error);
|
||||
message.error("删除失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除失败:", error);
|
||||
message.error("删除失败");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 搜索和筛选功能
|
||||
const filteredSensitiveWords = sensitiveWordsList.filter(item => {
|
||||
if (!searchValue) return true;
|
||||
return (
|
||||
item.title.toLowerCase().includes(searchValue.toLowerCase()) ||
|
||||
item.keywords.toLowerCase().includes(searchValue.toLowerCase()) ||
|
||||
item.content.toLowerCase().includes(searchValue.toLowerCase())
|
||||
);
|
||||
});
|
||||
|
||||
// 搜索处理函数
|
||||
const handleSearch = (value: string) => {
|
||||
fetchSensitiveWords({ keyword: value });
|
||||
};
|
||||
|
||||
// 组件挂载时获取数据
|
||||
useEffect(() => {
|
||||
fetchSensitiveWords();
|
||||
}, []);
|
||||
|
||||
// 搜索和筛选功能
|
||||
const filteredSensitiveWords = sensitiveWordsList.filter(item => {
|
||||
if (!searchValue) return true;
|
||||
return (
|
||||
item.title.toLowerCase().includes(searchValue.toLowerCase()) ||
|
||||
item.keywords.toLowerCase().includes(searchValue.toLowerCase()) ||
|
||||
item.content.toLowerCase().includes(searchValue.toLowerCase())
|
||||
);
|
||||
});
|
||||
<div className={styles.sensitiveContent}>
|
||||
<div className={styles.searchSection}>
|
||||
<Search
|
||||
placeholder="搜索敏感词..."
|
||||
value={searchValue}
|
||||
onChange={e => setSearchValue(e.target.value)}
|
||||
onSearch={handleSearch}
|
||||
style={{ width: 300 }}
|
||||
prefix={<SearchOutlined />}
|
||||
/>
|
||||
<Button icon={<FilterOutlined />}>筛选</Button>
|
||||
</div>
|
||||
|
||||
// 搜索处理函数
|
||||
const handleSearch = (value: string) => {
|
||||
fetchSensitiveWords({ keyword: value });
|
||||
};
|
||||
|
||||
// 组件挂载时获取数据
|
||||
useEffect(() => {
|
||||
fetchSensitiveWords();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.sensitiveContent}>
|
||||
<div className={styles.searchSection}>
|
||||
<Search
|
||||
placeholder="搜索敏感词..."
|
||||
value={searchValue}
|
||||
onChange={e => setSearchValue(e.target.value)}
|
||||
onSearch={handleSearch}
|
||||
style={{ width: 300 }}
|
||||
prefix={<SearchOutlined />}
|
||||
/>
|
||||
<Button icon={<FilterOutlined />}>筛选</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.sensitiveList}>
|
||||
{loading ? (
|
||||
<div className={styles.loading}>加载中...</div>
|
||||
) : filteredSensitiveWords.length === 0 ? (
|
||||
<div className={styles.empty}>暂无敏感词数据</div>
|
||||
) : (
|
||||
filteredSensitiveWords.map(item => (
|
||||
<div key={item.id} className={styles.sensitiveItem}>
|
||||
<div className={styles.itemContent}>
|
||||
<div className={styles.categoryName}>{item.title}</div>
|
||||
<Tag
|
||||
color={getTagColor(item.keywords)}
|
||||
className={styles.sensitiveTag}
|
||||
>
|
||||
{item.keywords}
|
||||
</Tag>
|
||||
<div className={styles.actionText}>
|
||||
{getOperationText(item.operation)}
|
||||
<div className={styles.sensitiveList}>
|
||||
{loading ? (
|
||||
<div className={styles.loading}>加载中...</div>
|
||||
) : filteredSensitiveWords.length === 0 ? (
|
||||
<div className={styles.empty}>暂无敏感词数据</div>
|
||||
) : (
|
||||
filteredSensitiveWords.map(item => (
|
||||
<div key={item.id} className={styles.sensitiveItem}>
|
||||
<div className={styles.itemContent}>
|
||||
<div className={styles.categoryName}>{item.title}</div>
|
||||
<Tag
|
||||
color={getTagColor(item.keywords)}
|
||||
className={styles.sensitiveTag}
|
||||
>
|
||||
{item.keywords}
|
||||
</Tag>
|
||||
<div className={styles.actionText}>
|
||||
{getOperationText(item.operation)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.itemActions}>
|
||||
<Switch
|
||||
checked={item.enabled}
|
||||
onChange={() => handleToggleSensitiveWord(item.id)}
|
||||
className={styles.toggleSwitch}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<FormOutlined className={styles.editIcon} />}
|
||||
onClick={() => handleEditSensitiveWord(item.id)}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
<Popconfirm
|
||||
title="确认删除"
|
||||
description="确定要删除这个敏感词吗?删除后无法恢复。"
|
||||
onConfirm={() => handleDeleteSensitiveWord(item.id)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okType="danger"
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteOutlined className={styles.deleteIcon} />}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.itemActions}>
|
||||
<Switch
|
||||
checked={item.enabled}
|
||||
onChange={() => handleToggleSensitiveWord(item.id)}
|
||||
className={styles.toggleSwitch}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<FormOutlined className={styles.editIcon} />}
|
||||
onClick={() => handleEditSensitiveWord(item.id)}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteOutlined className={styles.deleteIcon} />}
|
||||
onClick={() => handleDeleteSensitiveWord(item.id)}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 编辑弹窗 */}
|
||||
<SensitiveWordModal
|
||||
visible={editModalVisible}
|
||||
mode="edit"
|
||||
sensitiveWordId={editingSensitiveWordId}
|
||||
onCancel={() => {
|
||||
setEditModalVisible(false);
|
||||
setEditingSensitiveWordId(null);
|
||||
}}
|
||||
onSuccess={handleEditSuccess}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
{/* 编辑弹窗 */}
|
||||
<SensitiveWordModal
|
||||
visible={editModalVisible}
|
||||
mode="edit"
|
||||
sensitiveWordId={editingSensitiveWordId}
|
||||
onCancel={() => {
|
||||
setEditModalVisible(false);
|
||||
setEditingSensitiveWordId(null);
|
||||
}}
|
||||
onSuccess={handleEditSuccess}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SensitiveWordManagement.displayName = "SensitiveWordManagement";
|
||||
|
||||
export default SensitiveWordManagement;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { Modal, Form, Input, Button, message, Select } from "antd";
|
||||
import {
|
||||
addSensitiveWord,
|
||||
@@ -30,34 +30,40 @@ const SensitiveWordModal: React.FC<SensitiveWordModalProps> = ({
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 获取敏感词详情
|
||||
const fetchSensitiveWordDetails = async (id: string) => {
|
||||
try {
|
||||
const response = await getSensitiveWordDetails(id);
|
||||
if (response) {
|
||||
const sensitiveWord = response;
|
||||
form.setFieldsValue({
|
||||
title: sensitiveWord.title,
|
||||
keywords: sensitiveWord.keywords,
|
||||
content: sensitiveWord.content,
|
||||
operation: sensitiveWord.operation,
|
||||
status: sensitiveWord.status,
|
||||
});
|
||||
const fetchSensitiveWordDetails = useCallback(
|
||||
async (id: string) => {
|
||||
try {
|
||||
const response = await getSensitiveWordDetails(id);
|
||||
if (response) {
|
||||
const sensitiveWord = response;
|
||||
form.setFieldsValue({
|
||||
title: sensitiveWord.title,
|
||||
keywords: sensitiveWord.keywords,
|
||||
content: sensitiveWord.content,
|
||||
operation: sensitiveWord.operation,
|
||||
status: sensitiveWord.status,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取敏感词详情失败:", error);
|
||||
message.error("获取敏感词详情失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取敏感词详情失败:", error);
|
||||
message.error("获取敏感词详情失败");
|
||||
}
|
||||
};
|
||||
},
|
||||
[form],
|
||||
);
|
||||
|
||||
// 当弹窗打开且为编辑模式时,获取详情
|
||||
// 当弹窗打开时处理数据
|
||||
useEffect(() => {
|
||||
if (visible && mode === "edit" && sensitiveWordId) {
|
||||
fetchSensitiveWordDetails(sensitiveWordId);
|
||||
} else if (visible && mode === "add") {
|
||||
// 添加模式时重置表单
|
||||
form.resetFields();
|
||||
if (visible) {
|
||||
if (mode === "edit" && sensitiveWordId) {
|
||||
// 编辑模式:获取详情
|
||||
fetchSensitiveWordDetails(sensitiveWordId);
|
||||
} else if (mode === "add") {
|
||||
// 添加模式:重置表单
|
||||
form.resetFields();
|
||||
}
|
||||
}
|
||||
}, [visible, mode, sensitiveWordId]);
|
||||
}, [visible, mode, sensitiveWordId, fetchSensitiveWordDetails, form]);
|
||||
|
||||
const handleSubmit = async (values: any) => {
|
||||
try {
|
||||
|
||||
@@ -22,6 +22,7 @@ const ContentManagement: React.FC = () => {
|
||||
// 引用管理组件
|
||||
const materialManagementRef = useRef<any>(null);
|
||||
const keywordManagementRef = useRef<any>(null);
|
||||
const sensitiveWordManagementRef = useRef<any>(null);
|
||||
|
||||
const tabs = [
|
||||
{ key: "material", label: "素材资源库" },
|
||||
@@ -44,12 +45,20 @@ const ContentManagement: React.FC = () => {
|
||||
|
||||
// 弹窗成功回调
|
||||
const handleModalSuccess = () => {
|
||||
console.log("handleModalSuccess");
|
||||
// 刷新素材列表
|
||||
if (materialManagementRef.current?.fetchMaterials) {
|
||||
console.log("刷新素材列表");
|
||||
materialManagementRef.current.fetchMaterials();
|
||||
}
|
||||
// 刷新敏感词列表
|
||||
if (sensitiveWordManagementRef.current?.fetchSensitiveWords) {
|
||||
console.log("刷新敏感词列表");
|
||||
sensitiveWordManagementRef.current.fetchSensitiveWords();
|
||||
}
|
||||
// 刷新关键词列表
|
||||
if (keywordManagementRef.current?.fetchKeywords) {
|
||||
console.log("刷新关键词列表");
|
||||
keywordManagementRef.current.fetchKeywords();
|
||||
}
|
||||
};
|
||||
@@ -61,7 +70,12 @@ const ContentManagement: React.FC = () => {
|
||||
<MaterialManagement ref={materialManagementRef} {...({} as any)} />
|
||||
);
|
||||
case "sensitive":
|
||||
return <SensitiveWordManagement />;
|
||||
return (
|
||||
<SensitiveWordManagement
|
||||
ref={sensitiveWordManagementRef}
|
||||
{...({} as any)}
|
||||
/>
|
||||
);
|
||||
case "keyword":
|
||||
return (
|
||||
<KeywordManagement ref={keywordManagementRef} {...({} as any)} />
|
||||
@@ -89,12 +103,12 @@ const ContentManagement: React.FC = () => {
|
||||
>
|
||||
添加素材
|
||||
</Button>
|
||||
<Button icon={<PlusOutlined />} onClick={handleAddKeyword}>
|
||||
添加关键词回复
|
||||
</Button>
|
||||
<Button icon={<PlusOutlined />} onClick={handleAddSensitiveWord}>
|
||||
添加敏感词
|
||||
</Button>
|
||||
<Button icon={<PlusOutlined />} onClick={handleAddKeyword}>
|
||||
添加关键词回复
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
@@ -136,6 +150,7 @@ const ContentManagement: React.FC = () => {
|
||||
<KeywordModal
|
||||
visible={keywordModalVisible}
|
||||
mode="add"
|
||||
keywordId={null}
|
||||
onCancel={() => setKeywordModalVisible(false)}
|
||||
onSuccess={handleModalSuccess}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user