- {/* 功能内容待开发 */}
-
-
自动打招呼功能正在开发中...
+ {/* 头部区域 */}
+
+
+
}
+ onClick={() => navigate(-1)}
+ className={styles.backButton}
+ >
+ 返回功能中心
+
+
+
自动问候
+
设置智能问候规则,提升客户体验
+
+
+
+ 活跃规则: {activeRulesCount}/{rules.length}
+
+
}>
+ + 新建规则
+
+
+
+
+ {/* 子导航栏 */}
+
+
+
+
+ {/* 主要内容区域 */}
+
+ {activeTab === "rules" && (
+
+ {/* 左侧创建规则表单 */}
+
+
+ {/* 右侧规则列表 */}
+
+
+
+ {rules.length}条规则
+
+
+ {rules.map(rule => (
+
+
+
+
{rule.name}
+
+ {rule.tags.map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+
+
+
toggleRuleStatus(rule.id)}
+ size="small"
+ />
+ }
+ onClick={() => editRule(rule)}
+ />
+ deleteRule(rule.id)}
+ okText="确定"
+ cancelText="取消"
+ >
+ }
+ danger
+ />
+
+
+
+
+
+ {rule.triggerCondition}
+
+
{rule.content}
+
+ 使用次数:{rule.usageCount}
+ 创建时间:{rule.createTime}
+
+
+
+ ))}
+
+
+
+
+ )}
+
+ {activeTab === "templates" && (
+
+ )}
+
+ {activeTab === "statistics" && (
+
+ )}
);
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.module.scss b/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.module.scss
index bf1ac1e6..c9a9cb8c 100644
--- a/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.module.scss
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.module.scss
@@ -5,39 +5,289 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
-.header {
- margin-bottom: 24px;
-
- h1 {
- font-size: 24px;
- font-weight: 600;
- color: #262626;
- margin: 0 0 8px 0;
- }
-
- p {
- font-size: 14px;
- color: #8c8c8c;
- margin: 0;
- }
+// 导出按钮样式
+.exportButton {
+ height: 36px;
+ border-radius: 6px;
+ font-size: 14px;
+ font-weight: 500;
}
.content {
min-height: 400px;
}
-.placeholder {
+// 顶部搜索和筛选区域
+.headerSection {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24px;
+ padding: 16px 0;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.searchBar {
+ flex: 1;
+ max-width: 400px;
+}
+
+.filterButtons {
+ display: flex;
+ gap: 12px;
+
+ .ant-btn {
+ height: 36px;
+ border-radius: 6px;
+ font-size: 14px;
+ }
+}
+
+// 导航栏样式
+.navigationTabs {
+ margin-bottom: 24px;
+
+ .tabs {
+ .ant-tabs-nav {
+ margin-bottom: 0;
+ }
+
+ .ant-tabs-tab {
+ padding: 12px 24px;
+ font-size: 14px;
+ font-weight: 500;
+
+ .anticon {
+ margin-right: 8px;
+ }
+ }
+
+ .ant-tabs-tab-active {
+ color: #1890ff;
+
+ .ant-tabs-tab-btn {
+ color: #1890ff;
+ }
+ }
+
+ .ant-tabs-ink-bar {
+ background: #1890ff;
+ }
+ }
+}
+
+// 记录列表样式
+.recordsList {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.recordCard {
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+ border: 1px solid #f0f0f0;
+ transition: all 0.3s ease;
+
+ &:hover {
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ border-color: #d9d9d9;
+ }
+
+ .ant-card-body {
+ padding: 16px 20px;
+ }
+}
+
+.cardContent {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+}
+
+.cardLeft {
+ display: flex;
+ gap: 12px;
+ flex: 1;
+}
+
+.avatar {
+ width: 40px;
+ height: 40px;
+ background: #1890ff;
+ color: #fff;
+ font-size: 16px;
+ font-weight: 600;
+ flex-shrink: 0;
+}
+
+.recordInfo {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.nameAndType {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ .name {
+ font-size: 15px;
+ font-weight: 600;
+ color: #262626;
+ }
+
+ .type {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 13px;
+ color: #8c8c8c;
+
+ .anticon {
+ font-size: 13px;
+ }
+ }
+}
+
+.statusAndTime {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ .dateTime {
+ font-size: 13px;
+ color: #8c8c8c;
+ }
+
+ .duration {
+ font-size: 13px;
+ color: #8c8c8c;
+ }
+}
+
+.directionAndSubject {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ .subject {
+ font-size: 13px;
+ color: #262626;
+ font-weight: 500;
+ }
+}
+
+.content {
+ font-size: 13px;
+ color: #595959;
+ line-height: 1.4;
+ margin: 2px 0;
+}
+
+.tags {
+ display: flex;
+ gap: 6px;
+ flex-wrap: wrap;
+
+ .tag {
+ font-size: 11px;
+ background: #f5f5f5;
+ border: 1px solid #d9d9d9;
+ color: #8c8c8c;
+ border-radius: 3px;
+ padding: 1px 6px;
+ margin: 0;
+ }
+}
+
+.attachments {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ margin-top: 6px;
+
+ .attachmentsLabel {
+ font-size: 12px;
+ color: #8c8c8c;
+ font-weight: 500;
+ }
+
+ .attachment {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 10px;
+ background: #fafafa;
+ border-radius: 4px;
+ border: 1px solid #f0f0f0;
+
+ .attachmentIcon {
+ font-size: 14px;
+ }
+
+ .attachmentName {
+ font-size: 12px;
+ color: #262626;
+ flex: 1;
+ }
+
+ .downloadIcon {
+ color: #8c8c8c;
+ cursor: pointer;
+ transition: color 0.3s ease;
+ font-size: 12px;
+
+ &:hover {
+ color: #1890ff;
+ }
+ }
+ }
+}
+
+.cardRight {
display: flex;
align-items: center;
justify-content: center;
- height: 300px;
- background: #fafafa;
- border: 1px dashed #d9d9d9;
- border-radius: 6px;
-
- p {
- font-size: 16px;
+ width: 28px;
+ height: 28px;
+
+ .viewIcon {
+ font-size: 14px;
color: #8c8c8c;
- margin: 0;
+ cursor: pointer;
+ transition: color 0.3s ease;
+
+ &:hover {
+ color: #1890ff;
+ }
}
-}
\ No newline at end of file
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+ .headerSection {
+ flex-direction: column;
+ gap: 16px;
+ align-items: stretch;
+ }
+
+ .searchBar {
+ max-width: none;
+ }
+
+ .filterButtons {
+ justify-content: center;
+ }
+
+ .cardContent {
+ flex-direction: column;
+ gap: 16px;
+ }
+
+ .cardRight {
+ align-self: flex-end;
+ }
+}
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.tsx
index f13c4347..8432cafd 100644
--- a/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.tsx
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/communication-record/index.tsx
@@ -1,20 +1,323 @@
-import React from "react";
+import React, { useState } from "react";
+import { Input, Button, Tabs, Tag, Avatar, Card } from "antd";
+import {
+ SearchOutlined,
+ FilterOutlined,
+ CalendarOutlined,
+ MessageOutlined,
+ PhoneOutlined,
+ VideoCameraOutlined,
+ MailOutlined,
+ EyeOutlined,
+ DownloadOutlined,
+} from "@ant-design/icons";
import PowerNavigation from "@/components/PowerNavtion";
import styles from "./index.module.scss";
+const { Search } = Input;
+
+interface CommunicationRecord {
+ id: string;
+ avatar: string;
+ name: string;
+ type: "chat" | "call" | "video" | "email";
+ status: "completed" | "pending" | "cancelled";
+ dateTime: string;
+ duration?: string;
+ direction: "incoming" | "outgoing";
+ subject?: string;
+ content: string;
+ tags: string[];
+ attachments?: Array<{
+ name: string;
+ type: "pdf" | "xlsx" | "doc" | "other";
+ }>;
+}
+
const CommunicationRecord: React.FC = () => {
+ const [activeTab, setActiveTab] = useState("chat");
+ const [searchValue, setSearchValue] = useState("");
+
+ // 模拟数据
+ const mockData: CommunicationRecord[] = [
+ {
+ id: "1",
+ avatar: "李",
+ name: "李先生",
+ type: "chat",
+ status: "completed",
+ dateTime: "2024/3/5 14:30:00",
+ direction: "incoming",
+ content: "咨询AI营销产品的详细功能和价格",
+ tags: ["产品咨询", "价格询问"],
+ },
+ {
+ id: "2",
+ avatar: "张",
+ name: "张总",
+ type: "call",
+ status: "completed",
+ dateTime: "2024/3/5 10:15:00",
+ duration: "25分钟",
+ direction: "outgoing",
+ subject: "产品演示预约",
+ content: "与客户确认产品演示时间,讨论具体需求",
+ tags: ["产品演示", "需求确认"],
+ },
+ {
+ id: "3",
+ avatar: "王",
+ name: "王女士",
+ type: "video",
+ status: "completed",
+ dateTime: "2024/3/4 16:45:00",
+ duration: "45分钟",
+ direction: "incoming",
+ subject: "产品功能演示",
+ content: "详细演示AI客服功能,客户表示很满意",
+ tags: ["产品演示", "功能介绍"],
+ attachments: [
+ { name: "产品介绍.pdf", type: "pdf" },
+ { name: "报价单.xlsx", type: "xlsx" },
+ ],
+ },
+ ];
+
+ const getTypeIcon = (type: string) => {
+ switch (type) {
+ case "chat":
+ return
;
+ case "call":
+ return
;
+ case "video":
+ return
;
+ case "email":
+ return
;
+ default:
+ return
;
+ }
+ };
+
+ const getStatusColor = (status: string) => {
+ switch (status) {
+ case "completed":
+ return "success";
+ case "pending":
+ return "processing";
+ case "cancelled":
+ return "error";
+ default:
+ return "default";
+ }
+ };
+
+ const getDirectionColor = (direction: string) => {
+ return direction === "incoming" ? "green" : "blue";
+ };
+
+ const getDirectionText = (direction: string) => {
+ return direction === "incoming" ? "来电/来信" : "去电/去信";
+ };
+
+ const getStatusText = (status: string) => {
+ switch (status) {
+ case "completed":
+ return "已完成";
+ case "pending":
+ return "进行中";
+ case "cancelled":
+ return "已取消";
+ default:
+ return "未知";
+ }
+ };
+
+ const getAttachmentIcon = (type: string) => {
+ switch (type) {
+ case "pdf":
+ return "📄";
+ case "xlsx":
+ return "📊";
+ case "doc":
+ return "📝";
+ default:
+ return "📎";
+ }
+ };
+
+ const filteredData = mockData.filter(
+ record =>
+ record.type === activeTab &&
+ (searchValue === "" ||
+ record.name.includes(searchValue) ||
+ record.content.includes(searchValue) ||
+ record.tags.some(tag => tag.includes(searchValue))),
+ );
+
+ const tabItems = [
+ {
+ key: "chat",
+ label: (
+
+
+ 聊天(1)
+
+ ),
+ },
+ {
+ key: "call",
+ label: (
+
+
+ 通话(2)
+
+ ),
+ },
+ {
+ key: "video",
+ label: (
+
+
+ 视频(1)
+
+ ),
+ },
+ {
+ key: "email",
+ label: (
+
+
+ 邮件(1)
+
+ ),
+ },
+ ];
+
+ // 导出记录处理函数
+ const handleExportRecords = () => {
+ console.log("导出记录功能");
+ // TODO: 实现导出功能
+ };
+
return (
}
+ onClick={handleExportRecords}
+ className={styles.exportButton}
+ >
+ 导出记录
+
+ }
/>
+
- {/* 功能内容待开发 */}
-
-
沟通记录功能正在开发中...
+ {/* 顶部搜索和筛选区域 */}
+
+
+ setSearchValue(e.target.value)}
+ style={{ width: 300 }}
+ prefix={}
+ />
+
+
+ }>筛选
+ }>日期范围
+
+
+
+ {/* 通信类型导航栏 */}
+
+
+
+
+ {/* 通信记录列表 */}
+
+ {filteredData.map(record => (
+
+
+
+
{record.avatar}
+
+
+ {record.name}
+
+ {getTypeIcon(record.type)}
+ {record.type === "chat"
+ ? "聊天"
+ : record.type === "call"
+ ? "通话"
+ : record.type === "video"
+ ? "视频"
+ : "邮件"}
+
+
+
+
+ {getStatusText(record.status)}
+
+ {record.dateTime}
+ {record.duration && (
+
+ 时长:{record.duration}
+
+ )}
+
+
+
+ {getDirectionText(record.direction)}
+
+ {record.subject && (
+ {record.subject}
+ )}
+
+
{record.content}
+
+ {record.tags.map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+ {record.attachments && record.attachments.length > 0 && (
+
+
附件:
+ {record.attachments.map((attachment, index) => (
+
+
+ {getAttachmentIcon(attachment.type)}
+
+
+ {attachment.name}
+
+
+
+ ))}
+
+ )}
+
+
+
+
+
+
+
+ ))}
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/api.ts b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/api.ts
new file mode 100644
index 00000000..62d156ce
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/api.ts
@@ -0,0 +1,182 @@
+import request from "@/api/request";
+
+// 素材管理相关接口
+export interface MaterialListParams {
+ keyword?: string;
+ limit?: string;
+ page?: string;
+}
+
+// 内容项类型定义
+export interface ContentItem {
+ type: "text" | "image" | "video" | "file" | "audio" | "link";
+ data: string | LinkData;
+}
+
+// 链接数据类型
+export interface LinkData {
+ title: string;
+ url: string;
+ cover: string;
+}
+
+export interface MaterialAddRequest {
+ title: string;
+ cover?: string;
+ status: number;
+ content: ContentItem[];
+}
+
+export interface MaterialUpdateRequest extends MaterialAddRequest {
+ id?: string;
+}
+
+export interface MaterialSetStatusRequest {
+ id: string;
+}
+
+// 素材管理-列表
+export function getMaterialList(params: MaterialListParams) {
+ return request("/v1/kefu/content/material/list", params, "GET");
+}
+
+// 素材管理-添加
+export function addMaterial(data: MaterialAddRequest) {
+ return request("/v1/kefu/content/material/add", data, "POST");
+}
+
+// 素材管理-详情
+export function getMaterialDetails(id: string) {
+ return request("/v1/kefu/content/material/details", { id }, "GET");
+}
+
+// 素材管理-删除
+export function deleteMaterial(id: string) {
+ return request("/v1/kefu/content/material/del", { id }, "DELETE");
+}
+
+// 素材管理-更新
+export function updateMaterial(data: MaterialUpdateRequest) {
+ return request("/v1/kefu/content/material/update", data, "POST");
+}
+
+// 素材管理-修改状态
+export function setMaterialStatus(data: MaterialSetStatusRequest) {
+ return request("/v1/kefu/content/material/setStatus", data, "POST");
+}
+
+// 违禁词管理相关接口
+export interface SensitiveWordListParams {
+ keyword?: string;
+ limit?: string;
+ page?: string;
+}
+
+export interface SensitiveWordAddRequest {
+ content: string;
+ keywords: string;
+ /**
+ * 操作 0不操作 1替换 2删除 3警告 4禁止发送
+ */
+ operation: string;
+ status: string;
+ title: string;
+}
+
+export interface SensitiveWordUpdateRequest extends SensitiveWordAddRequest {
+ id?: string;
+}
+
+export interface SensitiveWordSetStatusRequest {
+ id: string;
+}
+
+// 违禁词管理-列表
+export function getSensitiveWordList(params: SensitiveWordListParams) {
+ return request("/v1/kefu/content/sensitiveWord/list", params, "GET");
+}
+
+// 违禁词管理-添加
+export function addSensitiveWord(data: SensitiveWordAddRequest) {
+ return request("/v1/kefu/content/sensitiveWord/add", data, "POST");
+}
+
+// 违禁词管理-详情
+export function getSensitiveWordDetails(id: string) {
+ return request("/v1/kefu/content/sensitiveWord/details", { id }, "GET");
+}
+
+// 违禁词管理-删除
+export function deleteSensitiveWord(id: string) {
+ return request("/v1/kefu/content/sensitiveWord/del", { id }, "DELETE");
+}
+
+// 违禁词管理-更新
+export function updateSensitiveWord(data: SensitiveWordUpdateRequest) {
+ return request("/v1/kefu/content/sensitiveWord/update", data, "POST");
+}
+
+// 违禁词管理-修改状态
+export function setSensitiveWordStatus(data: SensitiveWordSetStatusRequest) {
+ return request("/v1/kefu/content/sensitiveWord/setStatus", data, "POST");
+}
+
+// 关键词回复管理相关接口
+export interface KeywordListParams {
+ keyword?: string;
+ limit?: string;
+ page?: string;
+}
+
+export interface KeywordAddRequest {
+ title: string;
+ keywords: string;
+ content: string;
+ matchType: string; // 匹配类型:模糊匹配、精确匹配
+ priority: string; // 优先级
+ replyType: string; // 回复类型:文本回复、模板回复
+ status: string;
+}
+
+export interface KeywordUpdateRequest extends KeywordAddRequest {
+ id?: string;
+}
+
+export interface KeywordSetStatusRequest {
+ id: string;
+}
+
+// 关键词回复-列表
+export function getKeywordList(params: KeywordListParams) {
+ return request("/v1/kefu/content/keywords/list", params, "GET");
+}
+
+// 关键词回复-添加
+export function addKeyword(data: KeywordAddRequest) {
+ return request("/v1/kefu/content/keywords/add", data, "POST");
+}
+
+// 关键词回复-详情
+export function getKeywordDetails(id: string) {
+ return request("/v1/kefu/content/keywords/details", { id }, "GET");
+}
+
+// 关键词回复-删除
+export function deleteKeyword(id: string) {
+ return request("/v1/kefu/content/keywords/del", { id }, "DELETE");
+}
+
+// 关键词回复-更新
+export function updateKeyword(data: KeywordUpdateRequest) {
+ return request("/v1/kefu/content/keywords/update", data, "POST");
+}
+
+// 关键词回复-修改状态
+export function setKeywordStatus(data: KeywordSetStatusRequest) {
+ return request("/v1/kefu/content/keywords/setStatus", data, "POST");
+}
+
+//获取好友接待配置
+export function getFriendInjectConfig(params) {
+ return request("/v1/kefu/ai/friend/get", params, "GET");
+}
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/index.ts b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/index.ts
new file mode 100644
index 00000000..8acd8cb1
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/index.ts
@@ -0,0 +1,9 @@
+// 管理组件导出
+export { default as MaterialManagement } from "./management/MaterialManagement";
+export { default as SensitiveWordManagement } from "./management/SensitiveWordManagement";
+export { default as KeywordManagement } from "./management/KeywordManagement";
+
+// 模态框组件导出
+export { default as MaterialModal } from "./modals/MaterialModal";
+export { default as SensitiveWordModal } from "./modals/SensitiveWordModal";
+export { default as KeywordModal } from "./modals/KeywordModal";
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/KeywordManagement.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/KeywordManagement.tsx
new file mode 100644
index 00000000..99be1aaa
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/KeywordManagement.tsx
@@ -0,0 +1,243 @@
+import React, {
+ useState,
+ useEffect,
+ forwardRef,
+ useImperativeHandle,
+} from "react";
+import { Button, Input, Tag, Switch, message } from "antd";
+import {
+ SearchOutlined,
+ FilterOutlined,
+ FormOutlined,
+ DeleteOutlined,
+} from "@ant-design/icons";
+import styles from "../../index.module.scss";
+import {
+ getKeywordList,
+ deleteKeyword,
+ setKeywordStatus,
+ type KeywordListParams,
+} from "../../api";
+import KeywordModal from "../modals/KeywordModal";
+
+const { Search } = Input;
+
+interface KeywordItem {
+ id: string;
+ title: string;
+ keywords: string;
+ content: string;
+ matchType: string;
+ priority: string;
+ replyType: string;
+ status: string;
+ enabled: boolean;
+}
+
+const KeywordManagement = forwardRef
>(
+ (props, ref) => {
+ const [searchValue, setSearchValue] = useState("");
+ const [keywordsList, setKeywordsList] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [editModalVisible, setEditModalVisible] = useState(false);
+ const [editingKeywordId, setEditingKeywordId] = useState(
+ null,
+ );
+
+ // 回复类型映射
+ const getReplyTypeText = (replyType: string) => {
+ switch (replyType) {
+ case "text":
+ return "文本回复";
+ case "template":
+ return "模板回复";
+ default:
+ return "未知类型";
+ }
+ };
+
+ // 回复类型颜色
+ const getReplyTypeColor = (replyType: string) => {
+ switch (replyType) {
+ case "text":
+ return "#1890ff";
+ case "template":
+ return "#722ed1";
+ default:
+ return "#8c8c8c";
+ }
+ };
+
+ // 获取关键词列表
+ const fetchKeywords = async (params?: KeywordListParams) => {
+ try {
+ setLoading(true);
+ const response = await getKeywordList(params || {});
+ if (response) {
+ setKeywordsList(response.list || []);
+ } else {
+ setKeywordsList([]);
+ message.error(response?.message || "获取关键词列表失败");
+ }
+ } catch (error) {
+ console.error("获取关键词列表失败:", error);
+ setKeywordsList([]);
+ message.error("获取关键词列表失败");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // 暴露方法给父组件
+ useImperativeHandle(ref, () => ({
+ fetchKeywords,
+ }));
+
+ // 关键词管理相关函数
+ const handleToggleKeyword = async (id: string) => {
+ 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 || "状态更新失败");
+ }
+ } catch (error) {
+ console.error("状态更新失败:", error);
+ message.error("状态更新失败");
+ }
+ };
+
+ const handleEditKeyword = (id: string) => {
+ setEditingKeywordId(id);
+ setEditModalVisible(true);
+ };
+
+ // 编辑弹窗成功回调
+ const handleEditSuccess = () => {
+ fetchKeywords(); // 重新获取数据
+ };
+
+ const handleDeleteKeyword = async (id: string) => {
+ try {
+ const response = await deleteKeyword(id);
+ if (response) {
+ setKeywordsList(prev => prev.filter(item => item.id !== id));
+ message.success("删除成功");
+ } else {
+ message.error(response?.message || "删除失败");
+ }
+ } catch (error) {
+ console.error("删除失败:", error);
+ message.error("删除失败");
+ }
+ };
+
+ // 搜索和筛选功能
+ const filteredKeywords = keywordsList.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) => {
+ fetchKeywords({ keyword: value });
+ };
+
+ // 组件挂载时获取数据
+ useEffect(() => {
+ fetchKeywords();
+ }, []);
+
+ return (
+
+
+ setSearchValue(e.target.value)}
+ onSearch={handleSearch}
+ style={{ width: 300 }}
+ prefix={}
+ />
+ }>筛选
+
+
+
+ {loading ? (
+
加载中...
+ ) : filteredKeywords.length === 0 ? (
+
暂无关键词数据
+ ) : (
+ filteredKeywords.map(item => (
+
+
+
{item.title}
+
+ {item.matchType}
+
+ 优先级{item.priority}
+
+
+
{item.content}
+
+ {getReplyTypeText(item.replyType)}
+
+
+
+ handleToggleKeyword(item.id)}
+ className={styles.toggleSwitch}
+ />
+ }
+ onClick={() => handleEditKeyword(item.id)}
+ className={styles.actionBtn}
+ />
+ }
+ onClick={() => handleDeleteKeyword(item.id)}
+ className={styles.actionBtn}
+ />
+
+
+ ))
+ )}
+
+
+ {/* 编辑弹窗 */}
+
{
+ setEditModalVisible(false);
+ setEditingKeywordId(null);
+ }}
+ onSuccess={handleEditSuccess}
+ />
+
+ );
+ },
+);
+
+KeywordManagement.displayName = "KeywordManagement";
+
+export default KeywordManagement;
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/MaterialManagement.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/MaterialManagement.tsx
new file mode 100644
index 00000000..5680d28f
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/MaterialManagement.tsx
@@ -0,0 +1,273 @@
+import React, {
+ useState,
+ useEffect,
+ forwardRef,
+ useImperativeHandle,
+} from "react";
+import { Button, Input, Card, message, Modal } from "antd";
+import {
+ SearchOutlined,
+ FilterOutlined,
+ FormOutlined,
+ FileTextOutlined,
+ FileImageOutlined,
+ PlayCircleOutlined,
+ DeleteOutlined,
+} from "@ant-design/icons";
+import styles from "../../index.module.scss";
+import {
+ getMaterialList,
+ deleteMaterial,
+ type MaterialListParams,
+} from "../../api";
+import MaterialModal from "../modals/MaterialModal";
+
+const { Search } = Input;
+
+interface MaterialItem {
+ id: number;
+ companyId: number;
+ userId: number;
+ title: string;
+ content: string;
+ cover: string;
+ status: number;
+ type: string; // 素材类型:文本、图片、视频
+ createTime: string;
+ updateTime: string;
+ isDel: number;
+ delTime: string | null;
+ userName: string;
+}
+
+const MaterialManagement = forwardRef>(
+ (props, ref) => {
+ const [searchValue, setSearchValue] = useState("");
+ const [materialsList, setMaterialsList] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [editModalVisible, setEditModalVisible] = useState(false);
+ const [editingMaterialId, setEditingMaterialId] = useState(
+ null,
+ );
+
+ // 获取类型图标
+ const getTypeIcon = (type: string) => {
+ switch (type) {
+ case "文本":
+ return ;
+ case "图片":
+ return ;
+ case "视频":
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ // 获取素材列表
+ const fetchMaterials = async (params?: MaterialListParams) => {
+ try {
+ setLoading(true);
+ const response = await getMaterialList(params || {});
+ if (response) {
+ setMaterialsList(response.list || []);
+ } else {
+ setMaterialsList([]);
+ message.error(response?.message || "获取素材列表失败");
+ }
+ } catch (error) {
+ console.error("获取素材列表失败:", error);
+ setMaterialsList([]);
+ message.error("获取素材列表失败");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // 暴露方法给父组件
+ useImperativeHandle(ref, () => ({
+ fetchMaterials,
+ }));
+
+ // 素材管理相关函数
+ 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("删除失败");
+ }
+ },
+ });
+ };
+
+ // 编辑素材
+ const handleEditMaterial = (id: number) => {
+ setEditingMaterialId(id);
+ setEditModalVisible(true);
+ };
+
+ // 编辑弹窗成功回调
+ const handleEditSuccess = () => {
+ fetchMaterials(); // 重新获取数据
+ };
+
+ // 搜索处理函数
+ const handleSearch = (value: string) => {
+ fetchMaterials({ keyword: value });
+ };
+
+ // 组件挂载时获取数据
+ useEffect(() => {
+ fetchMaterials();
+ }, []);
+
+ return (
+
+
+ setSearchValue(e.target.value)}
+ onSearch={handleSearch}
+ style={{ width: 300 }}
+ prefix={}
+ />
+ }>筛选
+
+
+
+ {loading ? (
+
加载中...
+ ) : materialsList.length === 0 ? (
+
暂无素材数据
+ ) : (
+ materialsList.map(item => (
+
}
+ onClick={e => {
+ e.stopPropagation();
+ handleEditMaterial(item.id);
+ }}
+ >
+ 编辑
+ ,
+
}
+ onClick={e => {
+ e.stopPropagation();
+ handleDeleteMaterial(item.id);
+ }}
+ >
+ 删除
+ ,
+ ]}
+ >
+
handleEditMaterial(item.id)}
+ style={{ cursor: "pointer" }}
+ >
+ {item.cover ? (
+
+

+
+ {item.type}
+
+
+ ) : (
+
+ {getTypeIcon(item.type)}
+
+ {item.type}
+
+
+ )}
+
+
+
+
{item.title}
+
+
创建人: {item.userName}
+
{item.createTime}
+
+
+
+ ))
+ )}
+
+
+ {/* 编辑弹窗 */}
+
{
+ setEditModalVisible(false);
+ setEditingMaterialId(null);
+ }}
+ onSuccess={handleEditSuccess}
+ />
+
+ );
+ },
+);
+
+MaterialManagement.displayName = "MaterialManagement";
+
+export default MaterialManagement;
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/SensitiveWordManagement.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/SensitiveWordManagement.tsx
new file mode 100644
index 00000000..a51c3953
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/SensitiveWordManagement.tsx
@@ -0,0 +1,232 @@
+import React, { useState, useEffect } from "react";
+import { Button, Input, Tag, Switch, message } from "antd";
+import {
+ SearchOutlined,
+ FilterOutlined,
+ FormOutlined,
+ DeleteOutlined,
+} from "@ant-design/icons";
+import styles from "../../index.module.scss";
+import {
+ getSensitiveWordList,
+ deleteSensitiveWord,
+ setSensitiveWordStatus,
+ type SensitiveWordListParams,
+} from "../../api";
+import SensitiveWordModal from "../modals/SensitiveWordModal";
+
+const { Search } = Input;
+
+interface SensitiveWordItem {
+ id: string;
+ title: string;
+ keywords: string;
+ content: string;
+ operation: string;
+ status: string;
+ enabled: boolean;
+}
+
+const SensitiveWordManagement: React.FC = () => {
+ const [searchValue, setSearchValue] = useState("");
+ const [sensitiveWordsList, setSensitiveWordsList] = useState<
+ SensitiveWordItem[]
+ >([]);
+ const [loading, setLoading] = useState(false);
+ const [editModalVisible, setEditModalVisible] = useState(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 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 {
+ setSensitiveWordsList([]);
+ message.error(response?.message || "获取敏感词列表失败");
+ }
+ } 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 || "状态更新失败");
+ }
+ } catch (error) {
+ console.error("状态更新失败:", error);
+ message.error("状态更新失败");
+ }
+ };
+
+ const handleEditSensitiveWord = (id: string) => {
+ setEditingSensitiveWordId(id);
+ setEditModalVisible(true);
+ };
+
+ // 编辑弹窗成功回调
+ const handleEditSuccess = () => {
+ fetchSensitiveWords(); // 重新获取数据
+ };
+
+ const handleDeleteSensitiveWord = async (id: string) => {
+ try {
+ const response = await deleteSensitiveWord(id);
+ if (response) {
+ setSensitiveWordsList(prev => prev.filter(item => item.id !== id));
+ message.success("删除成功");
+ } else {
+ message.error(response?.message || "删除失败");
+ }
+ } 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();
+ }, []);
+
+ return (
+
+
+ setSearchValue(e.target.value)}
+ onSearch={handleSearch}
+ style={{ width: 300 }}
+ prefix={}
+ />
+ }>筛选
+
+
+
+ {loading ? (
+
加载中...
+ ) : filteredSensitiveWords.length === 0 ? (
+
暂无敏感词数据
+ ) : (
+ filteredSensitiveWords.map(item => (
+
+
+
{item.title}
+
+ {item.keywords}
+
+
+ {getOperationText(item.operation)}
+
+
+
+ handleToggleSensitiveWord(item.id)}
+ className={styles.toggleSwitch}
+ />
+ }
+ onClick={() => handleEditSensitiveWord(item.id)}
+ className={styles.actionBtn}
+ />
+ }
+ onClick={() => handleDeleteSensitiveWord(item.id)}
+ className={styles.actionBtn}
+ />
+
+
+ ))
+ )}
+
+
+ {/* 编辑弹窗 */}
+
{
+ setEditModalVisible(false);
+ setEditingSensitiveWordId(null);
+ }}
+ onSuccess={handleEditSuccess}
+ />
+
+ );
+};
+
+export default SensitiveWordManagement;
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/index.ts b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/index.ts
new file mode 100644
index 00000000..deff774a
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/management/index.ts
@@ -0,0 +1,4 @@
+// 管理组件统一导出
+export { default as MaterialManagement } from "./MaterialManagement";
+export { default as SensitiveWordManagement } from "./SensitiveWordManagement";
+export { default as KeywordManagement } from "./KeywordManagement";
diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/modals/ContentManager.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/modals/ContentManager.tsx
new file mode 100644
index 00000000..915f2de6
--- /dev/null
+++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/content-management/components/modals/ContentManager.tsx
@@ -0,0 +1,276 @@
+import React, { useState, useEffect } from "react";
+import { Button, Input, Select } from "antd";
+import {
+ PlusOutlined,
+ DeleteOutlined,
+ FileTextOutlined,
+ FileImageOutlined,
+ PlayCircleOutlined,
+ FileOutlined,
+ SoundOutlined,
+ LinkOutlined,
+} from "@ant-design/icons";
+import ImageUpload from "@/components/Upload/ImageUpload/ImageUpload";
+import VideoUpload from "@/components/Upload/VideoUpload";
+import FileUpload from "@/components/Upload/FileUpload";
+import AudioUpload from "@/components/Upload/AudioUpload";
+import type { ContentItem, LinkData } from "../../api";
+
+const { TextArea } = Input;
+const { Option } = Select;
+
+interface ContentManagerProps {
+ value?: ContentItem[];
+ onChange?: (content: ContentItem[]) => void;
+}
+
+const ContentManager: React.FC = ({
+ value = [],
+ onChange,
+}) => {
+ const [contentItems, setContentItems] = useState(value);
+
+ // 内容类型配置
+ const contentTypes = [
+ { value: "text", label: "文本", icon: },
+ { value: "image", label: "图片", icon: },
+ { value: "video", label: "视频", icon: },
+ { value: "file", label: "文件", icon: },
+ { value: "audio", label: "音频", icon: },
+ { value: "link", label: "链接", icon: },
+ ];
+
+ // 同步外部value到内部state
+ useEffect(() => {
+ setContentItems(value);
+ }, [value]);
+
+ // 初始化时添加默认文本内容项
+ useEffect(() => {
+ if (contentItems.length === 0) {
+ const defaultTextItem: ContentItem = {
+ type: "text",
+ data: "",
+ };
+ setContentItems([defaultTextItem]);
+ onChange?.([defaultTextItem]);
+ }
+ }, [contentItems.length, onChange]);
+
+ // 更新内容项
+ const updateContentItems = (newItems: ContentItem[]) => {
+ setContentItems(newItems);
+ onChange?.(newItems);
+ };
+
+ // 添加新内容项
+ const handleAddItem = () => {
+ const newItem: ContentItem = {
+ type: "text",
+ data: "",
+ };
+
+ const newItems = [...contentItems, newItem];
+ updateContentItems(newItems);
+ };
+
+ // 删除内容项
+ const handleDeleteItem = (index: number) => {
+ const newItems = contentItems.filter((_, i) => i !== index);
+ updateContentItems(newItems);
+ };
+
+ // 更新内容项数据
+ const updateItemData = (index: number, data: any) => {
+ const newItems = [...contentItems];
+ newItems[index] = { ...newItems[index], data };
+ updateContentItems(newItems);
+ };
+
+ // 更新内容项类型
+ const updateItemType = (index: number, newType: string) => {
+ const newItems = [...contentItems];
+
+ // 根据新类型重置数据
+ let newData: any;
+ if (newType === "link") {
+ newData = { title: "", url: "", cover: "" };
+ } else {
+ newData = "";
+ }
+
+ newItems[index] = {
+ type: newType as any,
+ data: newData,
+ };
+ updateContentItems(newItems);
+ };
+
+ // 渲染内容项
+ const renderContentItem = (item: ContentItem, index: number) => {
+ return (
+
+
+
+
+
+ {index !== 0 && (
+
}
+ onClick={() => handleDeleteItem(index)}
+ />
+ )}
+
+
+ {renderContentInput(item, index)}
+
+ );
+ };
+
+ // 渲染内容输入
+ const renderContentInput = (item: ContentItem, index: number) => {
+ switch (item.type) {
+ case "text":
+ return (
+