重构快捷语管理模块:新增快捷回复和分组管理功能,优化数据展示和交互逻辑,提升用户体验和代码可读性。
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
import request from "@/api/request";
|
||||||
|
// 快捷回复项接口
|
||||||
|
export interface QuickWordsReply {
|
||||||
|
id: number;
|
||||||
|
groupId: number;
|
||||||
|
userId: number;
|
||||||
|
title: string;
|
||||||
|
msgType: number;
|
||||||
|
content: string;
|
||||||
|
createTime: string;
|
||||||
|
lastUpdateTime: string;
|
||||||
|
sortIndex: string;
|
||||||
|
updateTime: string | null;
|
||||||
|
isDel: number;
|
||||||
|
delTime: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快捷回复组接口
|
||||||
|
export interface QuickWordsItem {
|
||||||
|
id: number;
|
||||||
|
groupName: string;
|
||||||
|
sortIndex: string;
|
||||||
|
parentId: number;
|
||||||
|
replyType: string;
|
||||||
|
replys: any | null;
|
||||||
|
companyId: number;
|
||||||
|
userId: number;
|
||||||
|
replies: QuickWordsReply[];
|
||||||
|
children: QuickWordsItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
//好友接待配置
|
||||||
|
export function setFriendInjectConfig(params: any): Promise<QuickWordsItem[]> {
|
||||||
|
return request("/v1/kefu/reply/list", params, "GET");
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddReplyRequest {
|
||||||
|
id?: string;
|
||||||
|
content?: string;
|
||||||
|
groupId?: string;
|
||||||
|
/**
|
||||||
|
* 1文本 3图片 43视频 49链接 等
|
||||||
|
*/
|
||||||
|
msgType?: string[];
|
||||||
|
/**
|
||||||
|
* 默认50
|
||||||
|
*/
|
||||||
|
sortIndex?: string;
|
||||||
|
title?: string;
|
||||||
|
[property: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加快捷回复
|
||||||
|
export function addReply(params: AddReplyRequest): Promise<any> {
|
||||||
|
return request("/v1/kefu/reply/addReply", params, "POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新快捷回复
|
||||||
|
export function updateReply(params: AddReplyRequest): Promise<any> {
|
||||||
|
return request("/v1/kefu/reply/updateReply", params, "POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除快捷回复
|
||||||
|
export function deleteReply(params: { id: string }): Promise<any> {
|
||||||
|
return request("/v1/kefu/reply/deleteReply", params, "DELETE");
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddGroupRequest {
|
||||||
|
id?: string;
|
||||||
|
groupName?: string;
|
||||||
|
parentId?: string;
|
||||||
|
/**
|
||||||
|
* 0 公共 1私有 2部门
|
||||||
|
*/
|
||||||
|
replyType?: string[];
|
||||||
|
/**
|
||||||
|
* 默认50
|
||||||
|
*/
|
||||||
|
sortIndex?: string;
|
||||||
|
[property: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加快捷回复组
|
||||||
|
export function addGroup(params: AddGroupRequest): Promise<any> {
|
||||||
|
return request("/v1/kefu/reply/addGroup", params, "POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新快捷回复组
|
||||||
|
export function updateGroup(params: AddGroupRequest): Promise<any> {
|
||||||
|
return request("/v1/kefu/reply/updateGroup", params, "POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除快捷回复组
|
||||||
|
export function deleteGroup(params: { id: string }): Promise<any> {
|
||||||
|
return request("/v1/kefu/reply/deleteGroup", params, "DELETE");
|
||||||
|
}
|
||||||
@@ -1,135 +1,563 @@
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState, useEffect, useCallback } from "react";
|
||||||
import { Card, Input, Button, Space, List, Tag } from "antd";
|
import {
|
||||||
|
Card,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
Space,
|
||||||
|
Tabs,
|
||||||
|
Tree,
|
||||||
|
Modal,
|
||||||
|
Form,
|
||||||
|
Select,
|
||||||
|
message,
|
||||||
|
Tooltip,
|
||||||
|
Spin,
|
||||||
|
} from "antd";
|
||||||
|
import {
|
||||||
|
PlusOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
FileTextOutlined,
|
||||||
|
PictureOutlined,
|
||||||
|
PlayCircleOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import {
|
||||||
|
QuickWordsItem,
|
||||||
|
QuickWordsReply,
|
||||||
|
setFriendInjectConfig,
|
||||||
|
addReply,
|
||||||
|
updateReply,
|
||||||
|
deleteReply,
|
||||||
|
updateGroup,
|
||||||
|
deleteGroup,
|
||||||
|
AddReplyRequest,
|
||||||
|
AddGroupRequest,
|
||||||
|
} from "./api";
|
||||||
|
|
||||||
export interface QuickWordItem {
|
// 消息类型枚举
|
||||||
id: string | number;
|
export enum MessageType {
|
||||||
text?: string; // 兼容旧结构
|
TEXT = 1,
|
||||||
title?: string;
|
IMAGE = 3,
|
||||||
content?: string;
|
VIDEO = 43,
|
||||||
tag?: string; // 分类/标签
|
LINK = 49,
|
||||||
usageCount?: number;
|
}
|
||||||
|
|
||||||
|
// 快捷语类型枚举
|
||||||
|
export enum QuickWordsType {
|
||||||
|
PERSONAL = 1, // 个人
|
||||||
|
PUBLIC = 0, // 公共
|
||||||
|
DEPARTMENT = 2, // 部门
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QuickWordsProps {
|
export interface QuickWordsProps {
|
||||||
title?: string;
|
onInsert?: (reply: QuickWordsReply) => void;
|
||||||
words: QuickWordItem[];
|
|
||||||
onInsert?: (text: string) => void;
|
|
||||||
onAdd?: (text: string) => void;
|
|
||||||
onRemove?: (id: string | number) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QuickWords: React.FC<QuickWordsProps> = ({
|
const QuickWords: React.FC<QuickWordsProps> = ({ onInsert }) => {
|
||||||
title = "快捷语录",
|
const [activeTab, setActiveTab] = useState<QuickWordsType>(
|
||||||
words,
|
QuickWordsType.PUBLIC,
|
||||||
onInsert,
|
|
||||||
|
|
||||||
onRemove,
|
|
||||||
}) => {
|
|
||||||
const [keyword, setKeyword] = useState("");
|
|
||||||
const sorted = useMemo(
|
|
||||||
() =>
|
|
||||||
[...(words || [])].sort((a, b) =>
|
|
||||||
String(a.id).localeCompare(String(b.id)),
|
|
||||||
),
|
|
||||||
[words],
|
|
||||||
);
|
);
|
||||||
|
const [keyword, setKeyword] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [quickWordsData, setQuickWordsData] = useState<QuickWordsItem[]>([]);
|
||||||
|
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
||||||
|
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
|
||||||
|
|
||||||
|
// 模态框状态
|
||||||
|
const [addModalVisible, setAddModalVisible] = useState(false);
|
||||||
|
const [editModalVisible, setEditModalVisible] = useState(false);
|
||||||
|
const [groupModalVisible, setGroupModalVisible] = useState(false);
|
||||||
|
const [editingItem, setEditingItem] = useState<QuickWordsReply | null>(null);
|
||||||
|
const [editingGroup, setEditingGroup] = useState<QuickWordsItem | null>(null);
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [groupForm] = Form.useForm();
|
||||||
|
|
||||||
|
// 获取快捷语数据
|
||||||
|
const fetchQuickWords = useCallback(async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const data = await setFriendInjectConfig({ replyType: activeTab });
|
||||||
|
setQuickWordsData(data || []);
|
||||||
|
} catch (error) {
|
||||||
|
message.error("获取快捷语数据失败");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [activeTab]);
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
useEffect(() => {
|
||||||
|
fetchQuickWords();
|
||||||
|
}, [fetchQuickWords]);
|
||||||
|
|
||||||
|
// 获取消息类型图标
|
||||||
|
const getMessageTypeIcon = (msgType: number) => {
|
||||||
|
switch (msgType) {
|
||||||
|
case MessageType.TEXT:
|
||||||
|
return <FileTextOutlined style={{ color: "#1890ff" }} />;
|
||||||
|
case MessageType.IMAGE:
|
||||||
|
return <PictureOutlined style={{ color: "#52c41a" }} />;
|
||||||
|
case MessageType.VIDEO:
|
||||||
|
return <PlayCircleOutlined style={{ color: "#fa8c16" }} />;
|
||||||
|
default:
|
||||||
|
return <FileTextOutlined style={{ color: "#8c8c8c" }} />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将数据转换为Tree组件需要的格式
|
||||||
|
const convertToTreeData = (data: QuickWordsItem[]): any[] => {
|
||||||
|
return data.map(item => ({
|
||||||
|
key: `group-${item.id}`,
|
||||||
|
title: (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{item.groupName}</span>
|
||||||
|
<div style={{ display: "flex", gap: 4 }}>
|
||||||
|
<Tooltip title="编辑分组">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleEditGroup(item);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="删除分组">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleDeleteGroup(item.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
...item.replies.map(reply => ({
|
||||||
|
key: `reply-${reply.id}`,
|
||||||
|
title: (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||||
|
{getMessageTypeIcon(reply.msgType)}
|
||||||
|
<span>{reply.title}</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex", gap: 4 }}>
|
||||||
|
<Tooltip title="使用">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onInsert?.(reply);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
使用
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="编辑">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleEditReply(reply);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="删除">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleDeleteReply(reply.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
isLeaf: true,
|
||||||
|
})),
|
||||||
|
...convertToTreeData(item.children || []),
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理添加快捷回复
|
||||||
|
const handleAddReply = async (values: AddReplyRequest) => {
|
||||||
|
try {
|
||||||
|
await addReply({
|
||||||
|
...values,
|
||||||
|
groupId: selectedKeys[0]?.toString().replace("group-", "") || "",
|
||||||
|
replyType: [activeTab.toString()],
|
||||||
|
});
|
||||||
|
message.success("添加快捷回复成功");
|
||||||
|
setAddModalVisible(false);
|
||||||
|
form.resetFields();
|
||||||
|
fetchQuickWords();
|
||||||
|
} catch (error) {
|
||||||
|
message.error("添加快捷回复失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理编辑快捷回复
|
||||||
|
const handleEditReply = (reply: QuickWordsReply) => {
|
||||||
|
setEditingItem(reply);
|
||||||
|
form.setFieldsValue({
|
||||||
|
title: reply.title,
|
||||||
|
content: reply.content,
|
||||||
|
msgType: [reply.msgType.toString()],
|
||||||
|
});
|
||||||
|
setEditModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理更新快捷回复
|
||||||
|
const handleUpdateReply = async (values: AddReplyRequest) => {
|
||||||
|
if (!editingItem) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateReply({
|
||||||
|
...values,
|
||||||
|
id: editingItem.id.toString(),
|
||||||
|
});
|
||||||
|
message.success("更新快捷回复成功");
|
||||||
|
setEditModalVisible(false);
|
||||||
|
setEditingItem(null);
|
||||||
|
form.resetFields();
|
||||||
|
fetchQuickWords();
|
||||||
|
} catch (error) {
|
||||||
|
message.error("更新快捷回复失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理删除快捷回复
|
||||||
|
const handleDeleteReply = async (id: number) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认删除",
|
||||||
|
content: "确定要删除这个快捷回复吗?",
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await deleteReply({ id: id.toString() });
|
||||||
|
message.success("删除成功");
|
||||||
|
fetchQuickWords();
|
||||||
|
} catch (error) {
|
||||||
|
message.error("删除失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理编辑分组
|
||||||
|
const handleEditGroup = (group: QuickWordsItem) => {
|
||||||
|
setEditingGroup(group);
|
||||||
|
groupForm.setFieldsValue({
|
||||||
|
groupName: group.groupName,
|
||||||
|
replyType: [group.replyType],
|
||||||
|
});
|
||||||
|
setGroupModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理更新分组
|
||||||
|
const handleUpdateGroup = async (values: AddGroupRequest) => {
|
||||||
|
if (!editingGroup) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateGroup({
|
||||||
|
...values,
|
||||||
|
id: editingGroup.id.toString(),
|
||||||
|
});
|
||||||
|
message.success("更新分组成功");
|
||||||
|
setGroupModalVisible(false);
|
||||||
|
setEditingGroup(null);
|
||||||
|
groupForm.resetFields();
|
||||||
|
fetchQuickWords();
|
||||||
|
} catch (error) {
|
||||||
|
message.error("更新分组失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理删除分组
|
||||||
|
const handleDeleteGroup = async (id: number) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认删除",
|
||||||
|
content: "确定要删除这个分组吗?删除后该分组下的所有快捷回复也会被删除。",
|
||||||
|
onOk: async () => {
|
||||||
|
try {
|
||||||
|
await deleteGroup({ id: id.toString() });
|
||||||
|
message.success("删除成功");
|
||||||
|
fetchQuickWords();
|
||||||
|
} catch (error) {
|
||||||
|
message.error("删除失败");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 过滤数据
|
||||||
|
const filteredData = useMemo(() => {
|
||||||
|
if (!keyword.trim()) return quickWordsData;
|
||||||
|
|
||||||
|
const filterData = (data: QuickWordsItem[]): QuickWordsItem[] => {
|
||||||
|
return data
|
||||||
|
.map(item => ({
|
||||||
|
...item,
|
||||||
|
replies: item.replies.filter(
|
||||||
|
reply =>
|
||||||
|
reply.title.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||||
|
reply.content.toLowerCase().includes(keyword.toLowerCase()),
|
||||||
|
),
|
||||||
|
children: filterData(item.children || []),
|
||||||
|
}))
|
||||||
|
.filter(
|
||||||
|
item =>
|
||||||
|
item.replies.length > 0 ||
|
||||||
|
item.children.length > 0 ||
|
||||||
|
item.groupName.toLowerCase().includes(keyword.toLowerCase()),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return filterData(quickWordsData);
|
||||||
|
}, [quickWordsData, keyword]);
|
||||||
|
|
||||||
|
const treeData = convertToTreeData(filteredData);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card title={title} style={{ marginTop: 12 }}>
|
<Card style={{ marginTop: 12 }}>
|
||||||
<Space direction="vertical" style={{ width: "100%" }}>
|
<Tabs
|
||||||
<Input.Search
|
activeKey={activeTab.toString()}
|
||||||
placeholder="搜索快捷语录..."
|
onChange={key => setActiveTab(Number(key) as QuickWordsType)}
|
||||||
allowClear
|
items={[
|
||||||
value={keyword}
|
{
|
||||||
onChange={e => setKeyword(e.target.value)}
|
key: QuickWordsType.PERSONAL.toString(),
|
||||||
onSearch={v => setKeyword(v)}
|
label: "个人快捷语",
|
||||||
/>
|
},
|
||||||
|
{
|
||||||
|
key: QuickWordsType.PUBLIC.toString(),
|
||||||
|
label: "公共快捷语",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: QuickWordsType.DEPARTMENT.toString(),
|
||||||
|
label: "部门快捷语",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
<List
|
<Space direction="vertical" style={{ width: "100%", marginTop: 16 }}>
|
||||||
itemLayout="vertical"
|
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
||||||
split={false}
|
<Input.Search
|
||||||
dataSource={sorted.filter(item => {
|
placeholder="输入关键字过滤"
|
||||||
const text = `${item.title || ""}${item.content || ""}${item.text || ""}`;
|
allowClear
|
||||||
return text.toLowerCase().includes(keyword.trim().toLowerCase());
|
value={keyword}
|
||||||
})}
|
onChange={e => setKeyword(e.target.value)}
|
||||||
renderItem={item => {
|
style={{ flex: 1 }}
|
||||||
const displayTitle = item.title || item.text || "未命名";
|
/>
|
||||||
const displayContent = item.content || item.text || "";
|
<Tooltip title="添加快捷回复">
|
||||||
return (
|
<Button
|
||||||
<List.Item
|
type="primary"
|
||||||
style={{
|
icon={<PlusOutlined />}
|
||||||
padding: "12px 8px",
|
onClick={() => setAddModalVisible(true)}
|
||||||
border: "1px solid #f0f0f0",
|
/>
|
||||||
borderRadius: 8,
|
</Tooltip>
|
||||||
marginBottom: 12,
|
<Tooltip title="刷新">
|
||||||
background: "#fff",
|
<Button icon={<ReloadOutlined />} onClick={fetchQuickWords} />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Spin spinning={loading}>
|
||||||
|
<Tree
|
||||||
|
showLine
|
||||||
|
showIcon
|
||||||
|
expandedKeys={expandedKeys}
|
||||||
|
selectedKeys={selectedKeys}
|
||||||
|
onExpand={setExpandedKeys}
|
||||||
|
onSelect={setSelectedKeys}
|
||||||
|
treeData={treeData}
|
||||||
|
style={{ maxHeight: 400, overflow: "auto" }}
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
{/* 添加快捷回复模态框 */}
|
||||||
|
<Modal
|
||||||
|
title="添加快捷回复"
|
||||||
|
open={addModalVisible}
|
||||||
|
onCancel={() => {
|
||||||
|
setAddModalVisible(false);
|
||||||
|
form.resetFields();
|
||||||
|
}}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Form form={form} layout="vertical" onFinish={handleAddReply}>
|
||||||
|
<Form.Item
|
||||||
|
name="title"
|
||||||
|
label="标题"
|
||||||
|
rules={[{ required: true, message: "请输入标题" }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入快捷回复标题" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="content"
|
||||||
|
label="内容"
|
||||||
|
rules={[{ required: true, message: "请输入内容" }]}
|
||||||
|
>
|
||||||
|
<Input.TextArea rows={4} placeholder="请输入快捷回复内容" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="msgType"
|
||||||
|
label="消息类型"
|
||||||
|
rules={[{ required: true, message: "请选择消息类型" }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择消息类型">
|
||||||
|
<Select.Option value="1">文本</Select.Option>
|
||||||
|
<Select.Option value="3">图片</Select.Option>
|
||||||
|
<Select.Option value="43">视频</Select.Option>
|
||||||
|
<Select.Option value="49">链接</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" htmlType="submit">
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setAddModalVisible(false);
|
||||||
|
form.resetFields();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
取消
|
||||||
style={{
|
</Button>
|
||||||
display: "flex",
|
</Space>
|
||||||
justifyContent: "space-between",
|
</Form.Item>
|
||||||
gap: 12,
|
</Form>
|
||||||
}}
|
</Modal>
|
||||||
>
|
|
||||||
<div style={{ flex: 1, minWidth: 0 }}>
|
{/* 编辑快捷回复模态框 */}
|
||||||
<div
|
<Modal
|
||||||
style={{
|
title="编辑快捷回复"
|
||||||
display: "flex",
|
open={editModalVisible}
|
||||||
alignItems: "center",
|
onCancel={() => {
|
||||||
gap: 8,
|
setEditModalVisible(false);
|
||||||
marginBottom: 6,
|
setEditingItem(null);
|
||||||
}}
|
form.resetFields();
|
||||||
>
|
}}
|
||||||
{item.tag && <Tag color="blue">{item.tag}</Tag>}
|
footer={null}
|
||||||
<span style={{ fontWeight: 600, color: "#262626" }}>
|
>
|
||||||
{displayTitle}
|
<Form form={form} layout="vertical" onFinish={handleUpdateReply}>
|
||||||
</span>
|
<Form.Item
|
||||||
</div>
|
name="title"
|
||||||
<div
|
label="标题"
|
||||||
style={{
|
rules={[{ required: true, message: "请输入标题" }]}
|
||||||
color: "#8c8c8c",
|
>
|
||||||
fontSize: 13,
|
<Input placeholder="请输入快捷回复标题" />
|
||||||
lineHeight: 1.6,
|
</Form.Item>
|
||||||
whiteSpace: "pre-wrap",
|
|
||||||
}}
|
<Form.Item
|
||||||
>
|
name="content"
|
||||||
{displayContent}
|
label="内容"
|
||||||
</div>
|
rules={[{ required: true, message: "请输入内容" }]}
|
||||||
{typeof item.usageCount === "number" && (
|
>
|
||||||
<div
|
<Input.TextArea rows={4} placeholder="请输入快捷回复内容" />
|
||||||
style={{ color: "#bfbfbf", fontSize: 12, marginTop: 6 }}
|
</Form.Item>
|
||||||
>
|
|
||||||
使用 {item.usageCount} 次
|
<Form.Item
|
||||||
</div>
|
name="msgType"
|
||||||
)}
|
label="消息类型"
|
||||||
</div>
|
rules={[{ required: true, message: "请选择消息类型" }]}
|
||||||
<div
|
>
|
||||||
style={{ display: "flex", alignItems: "center", gap: 8 }}
|
<Select placeholder="请选择消息类型">
|
||||||
>
|
<Select.Option value="1">文本</Select.Option>
|
||||||
{onRemove && (
|
<Select.Option value="3">图片</Select.Option>
|
||||||
<Button
|
<Select.Option value="43">视频</Select.Option>
|
||||||
size="small"
|
<Select.Option value="49">链接</Select.Option>
|
||||||
danger
|
</Select>
|
||||||
onClick={() => onRemove(item.id)}
|
</Form.Item>
|
||||||
>
|
|
||||||
删除
|
<Form.Item>
|
||||||
</Button>
|
<Space>
|
||||||
)}
|
<Button type="primary" htmlType="submit">
|
||||||
<Button
|
确定
|
||||||
type="primary"
|
</Button>
|
||||||
size="small"
|
<Button
|
||||||
onClick={() => onInsert?.(displayContent || displayTitle)}
|
onClick={() => {
|
||||||
>
|
setEditModalVisible(false);
|
||||||
使用
|
setEditingItem(null);
|
||||||
</Button>
|
form.resetFields();
|
||||||
</div>
|
}}
|
||||||
</div>
|
>
|
||||||
</List.Item>
|
取消
|
||||||
);
|
</Button>
|
||||||
}}
|
</Space>
|
||||||
/>
|
</Form.Item>
|
||||||
</Space>
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{/* 编辑分组模态框 */}
|
||||||
|
<Modal
|
||||||
|
title="编辑分组"
|
||||||
|
open={groupModalVisible}
|
||||||
|
onCancel={() => {
|
||||||
|
setGroupModalVisible(false);
|
||||||
|
setEditingGroup(null);
|
||||||
|
groupForm.resetFields();
|
||||||
|
}}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Form form={groupForm} layout="vertical" onFinish={handleUpdateGroup}>
|
||||||
|
<Form.Item
|
||||||
|
name="groupName"
|
||||||
|
label="分组名称"
|
||||||
|
rules={[{ required: true, message: "请输入分组名称" }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入分组名称" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" htmlType="submit">
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setGroupModalVisible(false);
|
||||||
|
setEditingGroup(null);
|
||||||
|
groupForm.resetFields();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user