重构关键词管理模块:更新关键词和敏感词的请求参数类型为数字,增强类型安全性;优化关键词管理界面,改进状态切换和删除功能,增加确认删除的弹窗,提升用户体验。
This commit is contained in:
@@ -132,9 +132,9 @@ export interface KeywordAddRequest {
|
||||
title: string;
|
||||
keywords: string;
|
||||
content: string;
|
||||
matchType: string; // 匹配类型:模糊匹配、精确匹配
|
||||
priority: string; // 优先级
|
||||
replyType: string; // 回复类型:文本回复、模板回复
|
||||
type: number; // 匹配类型:模糊匹配、精确匹配
|
||||
level: number; // 优先级
|
||||
replyType: number; // 回复类型:文本回复、模板回复
|
||||
status: string;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ export interface KeywordUpdateRequest extends KeywordAddRequest {
|
||||
}
|
||||
|
||||
export interface KeywordSetStatusRequest {
|
||||
id: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
// 关键词回复-列表
|
||||
@@ -157,12 +157,12 @@ export function addKeyword(data: KeywordAddRequest) {
|
||||
}
|
||||
|
||||
// 关键词回复-详情
|
||||
export function getKeywordDetails(id: string) {
|
||||
export function getKeywordDetails(id: number) {
|
||||
return request("/v1/kefu/content/keywords/details", { id }, "GET");
|
||||
}
|
||||
|
||||
// 关键词回复-删除
|
||||
export function deleteKeyword(id: string) {
|
||||
export function deleteKeyword(id: number) {
|
||||
return request("/v1/kefu/content/keywords/del", { id }, "DELETE");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import React, {
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { Button, Input, Tag, Switch, message } from "antd";
|
||||
import { Button, Input, Tag, Switch, message, Popconfirm } from "antd";
|
||||
import {
|
||||
SearchOutlined,
|
||||
FilterOutlined,
|
||||
FormOutlined,
|
||||
DeleteOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import styles from "../../index.module.scss";
|
||||
import styles from "./index.module.scss";
|
||||
import {
|
||||
getKeywordList,
|
||||
deleteKeyword,
|
||||
@@ -23,15 +23,15 @@ import KeywordModal from "../modals/KeywordModal";
|
||||
const { Search } = Input;
|
||||
|
||||
interface KeywordItem {
|
||||
id: string;
|
||||
id?: number;
|
||||
type: number;
|
||||
replyType: number;
|
||||
title: string;
|
||||
keywords: string;
|
||||
status: number;
|
||||
content: string;
|
||||
matchType: string;
|
||||
priority: string;
|
||||
replyType: string;
|
||||
status: string;
|
||||
enabled: boolean;
|
||||
materialId: string;
|
||||
level: number;
|
||||
}
|
||||
|
||||
const KeywordManagement = forwardRef<any, Record<string, never>>(
|
||||
@@ -40,31 +40,52 @@ const KeywordManagement = forwardRef<any, Record<string, never>>(
|
||||
const [keywordsList, setKeywordsList] = useState<KeywordItem[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [editModalVisible, setEditModalVisible] = useState<boolean>(false);
|
||||
const [editingKeywordId, setEditingKeywordId] = useState<string | null>(
|
||||
const [editingKeywordId, setEditingKeywordId] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
//匹配类型
|
||||
const getMatchTypeText = (type: number) => {
|
||||
switch (type) {
|
||||
case 0:
|
||||
return "模糊匹配";
|
||||
case 1:
|
||||
return "精确匹配";
|
||||
}
|
||||
};
|
||||
|
||||
//匹配优先级
|
||||
const getPriorityText = (level: number) => {
|
||||
switch (level) {
|
||||
case 0:
|
||||
return "低优先级";
|
||||
case 1:
|
||||
return "中优先级";
|
||||
case 2:
|
||||
return "高优先级";
|
||||
}
|
||||
};
|
||||
// 回复类型映射
|
||||
const getReplyTypeText = (replyType: string) => {
|
||||
const getReplyTypeText = (replyType: number) => {
|
||||
switch (replyType) {
|
||||
case "text":
|
||||
return "文本回复";
|
||||
case "template":
|
||||
return "模板回复";
|
||||
case 0:
|
||||
return "素材回复";
|
||||
case 1:
|
||||
return "自定义";
|
||||
default:
|
||||
return "未知类型";
|
||||
}
|
||||
};
|
||||
|
||||
// 回复类型颜色
|
||||
const getReplyTypeColor = (replyType: string) => {
|
||||
const getReplyTypeColor = (replyType: number) => {
|
||||
switch (replyType) {
|
||||
case "text":
|
||||
return "#1890ff";
|
||||
case "template":
|
||||
return "#722ed1";
|
||||
case 0:
|
||||
return "blue";
|
||||
case 1:
|
||||
return "purple";
|
||||
default:
|
||||
return "#8c8c8c";
|
||||
return "gray";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,26 +115,24 @@ const KeywordManagement = forwardRef<any, Record<string, never>>(
|
||||
}));
|
||||
|
||||
// 关键词管理相关函数
|
||||
const handleToggleKeyword = async (id: string) => {
|
||||
const handleToggleKeyword = async (id: number) => {
|
||||
try {
|
||||
const response = await setKeywordStatus({ id });
|
||||
if (response) {
|
||||
setKeywordsList(prev =>
|
||||
prev.map(item =>
|
||||
item.id === id ? { ...item, enabled: !item.enabled } : item,
|
||||
),
|
||||
);
|
||||
message.success("状态更新成功");
|
||||
} else {
|
||||
message.error(response?.message || "状态更新失败");
|
||||
}
|
||||
await setKeywordStatus({ id });
|
||||
setKeywordsList(prev =>
|
||||
prev.map(item =>
|
||||
item.id === id
|
||||
? { ...item, status: item.status === 1 ? 0 : 1 }
|
||||
: item,
|
||||
),
|
||||
);
|
||||
message.success("状态更新成功");
|
||||
} catch (error) {
|
||||
console.error("状态更新失败:", error);
|
||||
message.error("状态更新失败");
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditKeyword = (id: string) => {
|
||||
const handleEditKeyword = (id: number) => {
|
||||
setEditingKeywordId(id);
|
||||
setEditModalVisible(true);
|
||||
};
|
||||
@@ -123,15 +142,11 @@ const KeywordManagement = forwardRef<any, Record<string, never>>(
|
||||
fetchKeywords(); // 重新获取数据
|
||||
};
|
||||
|
||||
const handleDeleteKeyword = async (id: string) => {
|
||||
const handleDeleteKeyword = async (id: number) => {
|
||||
try {
|
||||
const response = await deleteKeyword(id);
|
||||
if (response) {
|
||||
setKeywordsList(prev => prev.filter(item => item.id !== id));
|
||||
message.success("删除成功");
|
||||
} else {
|
||||
message.error(response?.message || "删除失败");
|
||||
}
|
||||
await deleteKeyword(id);
|
||||
setKeywordsList(prev => prev.filter(item => item.id !== id));
|
||||
message.success("删除成功");
|
||||
} catch (error) {
|
||||
console.error("删除失败:", error);
|
||||
message.error("删除失败");
|
||||
@@ -169,7 +184,7 @@ const KeywordManagement = forwardRef<any, Record<string, never>>(
|
||||
style={{ width: 300 }}
|
||||
prefix={<SearchOutlined />}
|
||||
/>
|
||||
<Button icon={<FilterOutlined />}>筛选</Button>
|
||||
{/* <Button icon={<FilterOutlined />}>筛选</Button> */}
|
||||
</div>
|
||||
|
||||
<div className={styles.keywordList}>
|
||||
@@ -181,41 +196,48 @@ const KeywordManagement = forwardRef<any, Record<string, never>>(
|
||||
filteredKeywords.map(item => (
|
||||
<div key={item.id} className={styles.keywordItem}>
|
||||
<div className={styles.itemContent}>
|
||||
<div className={styles.title}>{item.title}</div>
|
||||
<div className={styles.tags}>
|
||||
<Tag className={styles.matchTag}>{item.matchType}</Tag>
|
||||
<Tag className={styles.priorityTag}>
|
||||
优先级{item.priority}
|
||||
</Tag>
|
||||
<div className={styles.leftSection}>
|
||||
<div className={styles.titleRow}>
|
||||
<div className={styles.title}>{item.title}</div>
|
||||
<Tag color="default">{getMatchTypeText(item.type)}</Tag>
|
||||
<Tag color="default">{getPriorityText(item.level)}</Tag>
|
||||
</div>
|
||||
<div className={styles.description}>{item.content}</div>
|
||||
<div className={styles.footer}>
|
||||
<Tag color={getReplyTypeColor(item.replyType)}>
|
||||
{getReplyTypeText(item.replyType)}
|
||||
</Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.rightSection}>
|
||||
<Switch
|
||||
checked={item.status === 1}
|
||||
onChange={() => handleToggleKeyword(item.id)}
|
||||
className={styles.toggleSwitch}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<FormOutlined className={styles.editIcon} />}
|
||||
onClick={() => handleEditKeyword(item.id)}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
<Popconfirm
|
||||
title="确认删除"
|
||||
description="确定要删除这个关键词吗?删除后无法恢复。"
|
||||
onConfirm={() => handleDeleteKeyword(item.id)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okType="danger"
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteOutlined className={styles.deleteIcon} />}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
<div className={styles.description}>{item.content}</div>
|
||||
<Tag
|
||||
color={getReplyTypeColor(item.replyType)}
|
||||
className={styles.replyTypeTag}
|
||||
>
|
||||
{getReplyTypeText(item.replyType)}
|
||||
</Tag>
|
||||
</div>
|
||||
<div className={styles.itemActions}>
|
||||
<Switch
|
||||
checked={item.enabled}
|
||||
onChange={() => handleToggleKeyword(item.id)}
|
||||
className={styles.toggleSwitch}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<FormOutlined className={styles.editIcon} />}
|
||||
onClick={() => handleEditKeyword(item.id)}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteOutlined className={styles.deleteIcon} />}
|
||||
onClick={() => handleDeleteKeyword(item.id)}
|
||||
className={styles.actionBtn}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
|
||||
@@ -27,7 +27,7 @@ interface SensitiveWordItem {
|
||||
title: string;
|
||||
keywords: string;
|
||||
content: string;
|
||||
operation: string;
|
||||
operation: number;
|
||||
status: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
@@ -185,12 +185,6 @@ const SensitiveWordManagement = forwardRef<any, Record<string, never>>(
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
// 关键词管理样式
|
||||
.keywordContent {
|
||||
.searchSection {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
:global(.ant-btn) {
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.keywordList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.keywordItem {
|
||||
padding: 16px 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #d9d9d9;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.itemContent {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
|
||||
.leftSection {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.titleRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.matchTag,
|
||||
.priorityTag {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
background: #f0f0f0;
|
||||
color: #666;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.replyTypeTag {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 20px;
|
||||
background: #fff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.rightSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.toggleSwitch {
|
||||
:global(.ant-switch) {
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
|
||||
:global(.ant-switch-checked) {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.actionBtn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.editIcon {
|
||||
font-size: 14px;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.deleteIcon {
|
||||
font-size: 14px;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.headerActions {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-btn) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
|
||||
.tab {
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
border-radius: 0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.materialContent {
|
||||
.searchSection {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.materialGrid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.sensitiveContent {
|
||||
.searchSection {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.sensitiveItem {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
|
||||
.itemContent {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
|
||||
.categoryName {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.itemActions {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.keywordContent {
|
||||
.searchSection {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.keywordItem {
|
||||
.itemContent {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
.leftSection {
|
||||
.titleRow {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
|
||||
.tags {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rightSection {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ const { Option } = Select;
|
||||
interface KeywordModalProps {
|
||||
visible: boolean;
|
||||
mode: "add" | "edit";
|
||||
keywordId?: string | null;
|
||||
keywordId?: number | null;
|
||||
onCancel: () => void;
|
||||
onSuccess: () => void;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
|
||||
// 获取关键词详情
|
||||
const fetchKeywordDetails = useCallback(
|
||||
async (id: string) => {
|
||||
async (id: number) => {
|
||||
try {
|
||||
const response = await getKeywordDetails(id);
|
||||
if (response) {
|
||||
@@ -40,8 +40,8 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
title: keyword.title,
|
||||
keywords: keyword.keywords,
|
||||
content: keyword.content,
|
||||
matchType: keyword.matchType,
|
||||
priority: keyword.priority,
|
||||
type: keyword.type,
|
||||
level: keyword.level,
|
||||
replyType: keyword.replyType,
|
||||
status: keyword.status,
|
||||
});
|
||||
@@ -76,8 +76,8 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
title: values.title,
|
||||
keywords: values.keywords,
|
||||
content: values.content,
|
||||
matchType: values.matchType,
|
||||
priority: values.priority,
|
||||
type: values.type,
|
||||
level: values.level,
|
||||
replyType: values.replyType,
|
||||
status: values.status || "1",
|
||||
};
|
||||
@@ -97,8 +97,8 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
title: values.title,
|
||||
keywords: values.keywords,
|
||||
content: values.content,
|
||||
matchType: values.matchType,
|
||||
priority: values.priority,
|
||||
type: values.type,
|
||||
level: values.level,
|
||||
replyType: values.replyType,
|
||||
status: values.status,
|
||||
};
|
||||
@@ -141,10 +141,10 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
initialValues={{
|
||||
status: "1",
|
||||
matchType: "模糊匹配",
|
||||
priority: "1",
|
||||
replyType: "text",
|
||||
status: 1,
|
||||
type: "模糊匹配",
|
||||
level: 1,
|
||||
replyType: 0,
|
||||
}}
|
||||
>
|
||||
<Form.Item
|
||||
@@ -172,27 +172,25 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="matchType"
|
||||
name="type"
|
||||
label="匹配类型"
|
||||
rules={[{ required: true, message: "请选择匹配类型" }]}
|
||||
>
|
||||
<Select placeholder="请选择匹配类型">
|
||||
<Option value="模糊匹配">模糊匹配</Option>
|
||||
<Option value="精确匹配">精确匹配</Option>
|
||||
<Option value={0}>模糊匹配</Option>
|
||||
<Option value={1}>精确匹配</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="priority"
|
||||
name="level"
|
||||
label="优先级"
|
||||
rules={[{ required: true, message: "请选择优先级" }]}
|
||||
>
|
||||
<Select placeholder="请选择优先级">
|
||||
<Option value="1">优先级1</Option>
|
||||
<Option value="2">优先级2</Option>
|
||||
<Option value="3">优先级3</Option>
|
||||
<Option value="4">优先级4</Option>
|
||||
<Option value="5">优先级5</Option>
|
||||
<Option value={0}>低优先级</Option>
|
||||
<Option value={1}>中优先级</Option>
|
||||
<Option value={2}>高优先级</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
@@ -202,8 +200,8 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
rules={[{ required: true, message: "请选择回复类型" }]}
|
||||
>
|
||||
<Select placeholder="请选择回复类型">
|
||||
<Option value="text">文本回复</Option>
|
||||
<Option value="template">模板回复</Option>
|
||||
<Option value={0}>素材回复</Option>
|
||||
<Option value={1}>自定义</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
@@ -213,8 +211,8 @@ const KeywordModal: React.FC<KeywordModalProps> = ({
|
||||
rules={[{ required: true, message: "请选择状态" }]}
|
||||
>
|
||||
<Select placeholder="请选择状态">
|
||||
<Option value="1">启用</Option>
|
||||
<Option value="0">禁用</Option>
|
||||
<Option value={1}>启用</Option>
|
||||
<Option value={0}>禁用</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
@@ -166,11 +166,11 @@ const SensitiveWordModal: React.FC<SensitiveWordModalProps> = ({
|
||||
rules={[{ required: true, message: "请选择操作类型" }]}
|
||||
>
|
||||
<Select placeholder="请选择操作类型">
|
||||
<Option value="0">不操作</Option>
|
||||
<Option value="1">替换</Option>
|
||||
<Option value="2">删除</Option>
|
||||
<Option value="3">警告</Option>
|
||||
<Option value="4">禁止发送</Option>
|
||||
<Option value={0}>不操作</Option>
|
||||
<Option value={1}>替换</Option>
|
||||
<Option value={2}>删除</Option>
|
||||
<Option value={3}>警告</Option>
|
||||
<Option value={4}>禁止发送</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
@@ -180,8 +180,8 @@ const SensitiveWordModal: React.FC<SensitiveWordModalProps> = ({
|
||||
rules={[{ required: true, message: "请选择状态" }]}
|
||||
>
|
||||
<Select placeholder="请选择状态">
|
||||
<Option value="1">启用</Option>
|
||||
<Option value="0">禁用</Option>
|
||||
<Option value={1}>启用</Option>
|
||||
<Option value={0}>禁用</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
@@ -291,133 +291,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 关键词管理样式
|
||||
.keywordContent {
|
||||
.searchSection {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
:global(.ant-btn) {
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.keywordList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.keywordItem {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: 16px 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #d9d9d9;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.itemContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.matchTag,
|
||||
.priorityTag {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
background: #f0f0f0;
|
||||
color: #666;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.replyTypeTag {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.itemActions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-left: 16px;
|
||||
|
||||
.toggleSwitch {
|
||||
:global(.ant-switch) {
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
|
||||
:global(.ant-switch-checked) {
|
||||
background-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.actionBtn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.editIcon {
|
||||
font-size: 14px;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.deleteIcon {
|
||||
font-size: 14px;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 弹窗中的图片上传组件样式
|
||||
:global(.material-cover-upload) {
|
||||
.uploadContainer {
|
||||
@@ -525,82 +398,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.materialContent {
|
||||
.searchSection {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.materialGrid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.sensitiveContent {
|
||||
.searchSection {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.sensitiveItem {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
|
||||
.itemContent {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
|
||||
.categoryName {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.itemActions {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.keywordContent {
|
||||
.searchSection {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
|
||||
:global(.ant-input-search) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.keywordItem {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
|
||||
.itemContent {
|
||||
.tags {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.itemActions {
|
||||
justify-content: flex-end;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user