更新 index.html 和 manifest.json 中的資源引用版本,並在新計劃頁面中調整海報模板的屬性名稱,將 preview 改為 url,以統一資料結構。
This commit is contained in:
2
Cunkebao/dist/.vite/manifest.json
vendored
2
Cunkebao/dist/.vite/manifest.json
vendored
@@ -32,7 +32,7 @@
|
||||
"name": "vendor"
|
||||
},
|
||||
"index.html": {
|
||||
"file": "assets/index-CeSKt0aC.js",
|
||||
"file": "assets/index-PKCtfAad.js",
|
||||
"name": "index",
|
||||
"src": "index.html",
|
||||
"isEntry": true,
|
||||
|
||||
2
Cunkebao/dist/index.html
vendored
2
Cunkebao/dist/index.html
vendored
@@ -11,7 +11,7 @@
|
||||
</style>
|
||||
<!-- 引入 uni-app web-view SDK(必须) -->
|
||||
<script type="text/javascript" src="./websdk.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CeSKt0aC.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-PKCtfAad.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-2vc8h_ct.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ui-DE3rfvO3.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/utils-BEiZ4iZ8.js">
|
||||
|
||||
@@ -137,12 +137,47 @@ const MainImgUpload: React.FC<MainImgUploadProps> = ({
|
||||
|
||||
// 预览图片
|
||||
const handlePreview = (url: string) => {
|
||||
const img = new Image();
|
||||
// 使用自定义全屏预览,确保不受父级容器限制
|
||||
const modal = document.createElement("div");
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const img = document.createElement("img");
|
||||
img.src = url;
|
||||
const newWindow = window.open();
|
||||
if (newWindow) {
|
||||
newWindow.document.write(img.outerHTML);
|
||||
}
|
||||
img.style.cssText = `
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
`;
|
||||
|
||||
const closeModal = () => {
|
||||
document.body.removeChild(modal);
|
||||
};
|
||||
|
||||
modal.addEventListener("click", closeModal);
|
||||
modal.appendChild(img);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// 添加键盘事件监听
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
closeModal();
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
|
||||
// 格式化文件大小
|
||||
@@ -244,7 +279,20 @@ const MainImgUpload: React.FC<MainImgUploadProps> = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={style.mainImgPreview}>
|
||||
<div
|
||||
className={style.mainImgPreview}
|
||||
onClick={e => {
|
||||
// 阻止事件冒泡,防止触发删除操作
|
||||
e.stopPropagation();
|
||||
// 点击图片预览区域时,触发文件选择
|
||||
const uploadInput = document.querySelector(
|
||||
'input[type="file"]',
|
||||
) as HTMLInputElement;
|
||||
if (uploadInput) {
|
||||
uploadInput.click();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={file.url}
|
||||
alt={file.name}
|
||||
@@ -257,7 +305,10 @@ const MainImgUpload: React.FC<MainImgUploadProps> = ({
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<EyeOutlined />}
|
||||
onClick={() => handlePreview(file.url || "")}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handlePreview(file.url || "");
|
||||
}}
|
||||
className={style.previewBtn}
|
||||
/>
|
||||
)}
|
||||
@@ -265,7 +316,10 @@ const MainImgUpload: React.FC<MainImgUploadProps> = ({
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleRemove()}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handleRemove();
|
||||
}}
|
||||
className={style.deleteBtn}
|
||||
/>
|
||||
</div>
|
||||
|
||||
54
Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts
Normal file
54
Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// 步骤定义 - 只保留三个步骤
|
||||
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
|
||||
import { GroupSelectionItem } from "@/components/GroupSelection/data";
|
||||
export const steps = [
|
||||
{ id: 1, title: "步骤一", subtitle: "基础设置" },
|
||||
{ id: 2, title: "步骤二", subtitle: "好友申请设置" },
|
||||
{ id: 3, title: "步骤三", subtitle: "消息设置" },
|
||||
];
|
||||
|
||||
// 类型定义
|
||||
export interface FormData {
|
||||
name: string;
|
||||
scenario: number;
|
||||
status: number;
|
||||
sceneId: string | number;
|
||||
remarkType: string;
|
||||
greeting: string;
|
||||
addInterval: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
enabled: boolean;
|
||||
remarkFormat: string;
|
||||
addFriendInterval: number;
|
||||
posters: any[]; // 后续可替换为具体Poster类型
|
||||
device: string[];
|
||||
customTags: string[];
|
||||
deveiceGroups: string[];
|
||||
deveiceGroupsOptions: DeviceSelectionItem[];
|
||||
wechatGroups: string[];
|
||||
wechatGroupsOptions: GroupSelectionItem[];
|
||||
messagePlans: any[];
|
||||
}
|
||||
export const defFormData: FormData = {
|
||||
name: "",
|
||||
scenario: 1,
|
||||
status: 0,
|
||||
sceneId: "",
|
||||
remarkType: "phone",
|
||||
greeting: "你好,请通过",
|
||||
addInterval: 1,
|
||||
startTime: "09:00",
|
||||
endTime: "18:00",
|
||||
enabled: true,
|
||||
remarkFormat: "",
|
||||
addFriendInterval: 1,
|
||||
posters: [],
|
||||
device: [],
|
||||
customTags: [],
|
||||
messagePlans: [],
|
||||
deveiceGroups: [],
|
||||
deveiceGroupsOptions: [],
|
||||
wechatGroups: [],
|
||||
wechatGroupsOptions: [],
|
||||
};
|
||||
@@ -8,62 +8,19 @@ import FriendRequestSettings from "./steps/FriendRequestSettings";
|
||||
import MessageSettings from "./steps/MessageSettings";
|
||||
import Layout from "@/components/Layout/Layout";
|
||||
import StepIndicator from "@/components/StepIndicator";
|
||||
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
|
||||
|
||||
import {
|
||||
getScenarioTypes,
|
||||
createPlan,
|
||||
getPlanDetail,
|
||||
updatePlan,
|
||||
} from "./index.api";
|
||||
|
||||
// 步骤定义 - 只保留三个步骤
|
||||
const steps = [
|
||||
{ id: 1, title: "步骤一", subtitle: "基础设置" },
|
||||
{ id: 2, title: "步骤二", subtitle: "好友申请设置" },
|
||||
{ id: 3, title: "步骤三", subtitle: "消息设置" },
|
||||
];
|
||||
|
||||
// 类型定义
|
||||
interface FormData {
|
||||
name: string;
|
||||
scenario: number;
|
||||
posters: any[]; // 后续可替换为具体Poster类型
|
||||
device: string[];
|
||||
customTags: string[];
|
||||
remarkType: string;
|
||||
greeting: string;
|
||||
addInterval: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
enabled: boolean;
|
||||
sceneId: string | number;
|
||||
remarkFormat: string;
|
||||
addFriendInterval: number;
|
||||
deveiceGroups: string[];
|
||||
deveiceGroupsOptions: DeviceSelectionItem[];
|
||||
}
|
||||
import { FormData, defFormData, steps } from "./index.data";
|
||||
|
||||
export default function NewPlan() {
|
||||
const router = useNavigate();
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
name: "",
|
||||
scenario: 1,
|
||||
posters: [],
|
||||
device: [],
|
||||
customTags: [],
|
||||
remarkType: "phone",
|
||||
greeting: "你好,请通过",
|
||||
addInterval: 1,
|
||||
startTime: "09:00",
|
||||
endTime: "18:00",
|
||||
enabled: true,
|
||||
sceneId: "",
|
||||
remarkFormat: "",
|
||||
addFriendInterval: 1,
|
||||
deveiceGroups: [],
|
||||
deveiceGroupsOptions: [],
|
||||
});
|
||||
const [formData, setFormData] = useState<FormData>(defFormData);
|
||||
|
||||
const [sceneList, setSceneList] = useState<any[]>([]);
|
||||
const [sceneLoading, setSceneLoading] = useState(true);
|
||||
@@ -110,6 +67,10 @@ export default function NewPlan() {
|
||||
tips: detail.tips ?? "",
|
||||
deveiceGroups: detail.deveiceGroups ?? [],
|
||||
deveiceGroupsOptions: detail.deveiceGroupsOptions ?? [],
|
||||
wechatGroups: detail.wechatGroups ?? [],
|
||||
wechatGroupsOptions: detail.wechatGroupsOptions ?? [],
|
||||
status: detail.status ?? 0,
|
||||
messagePlans: detail.messagePlans ?? [],
|
||||
}));
|
||||
} else {
|
||||
if (scenarioId) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import styles from "./base.module.scss";
|
||||
import { posterTemplates } from "./base.data";
|
||||
import GroupSelection from "@/components/GroupSelection";
|
||||
import FileUpload from "@/components/Upload/FileUpload";
|
||||
import { GroupSelectionItem } from "@/components/GroupSelection/data";
|
||||
|
||||
interface BasicSettingsProps {
|
||||
isEdit: boolean;
|
||||
@@ -66,14 +67,6 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
|
||||
questionExtraction: formData.phoneSettings?.questionExtraction ?? true,
|
||||
});
|
||||
|
||||
// 群设置相关状态
|
||||
const [weixinqunName, setWeixinqunName] = useState(
|
||||
formData.weixinqunName || "",
|
||||
);
|
||||
const [weixinqunNotice, setWeixinqunNotice] = useState(
|
||||
formData.weixinqunNotice || "",
|
||||
);
|
||||
|
||||
// 新增:自定义海报相关状态
|
||||
const [customPosters, setCustomPosters] = useState<Material[]>([]);
|
||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
||||
@@ -187,6 +180,13 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
|
||||
const openPoster =
|
||||
formData.scenario !== 1 ? { display: "none" } : { display: "block" };
|
||||
|
||||
const handleWechatGroupSelect = (groups: GroupSelectionItem[]) => {
|
||||
onChange({
|
||||
...formData,
|
||||
wechatGroups: groups.map(v => v.id),
|
||||
wechatGroupsOptions: groups,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className={styles["basic-container"]}>
|
||||
{/* 场景选择区块 */}
|
||||
@@ -420,10 +420,8 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
|
||||
<div className={styles["basic-group-selection"]}>
|
||||
<div className={styles["basic-label"]}>选择群聊</div>
|
||||
<GroupSelection
|
||||
selectedOptions={formData.groupSelected || []}
|
||||
onSelect={groups =>
|
||||
onChange({ ...formData, groupSelected: groups })
|
||||
}
|
||||
selectedOptions={formData.wechatGroupsOptions || []}
|
||||
onSelect={handleWechatGroupSelect}
|
||||
placeholder="请选择微信群"
|
||||
className={styles["basic-group-selector"]}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
import React from "react";
|
||||
import { Input, Button } from "antd";
|
||||
import { CloseOutlined, ClockCircleOutlined } from "@ant-design/icons";
|
||||
import styles from "./messages.module.scss";
|
||||
// 导入Upload组件
|
||||
import ImageUpload from "@/components/Upload/ImageUpload/ImageUpload";
|
||||
import VideoUpload from "@/components/Upload/VideoUpload";
|
||||
import FileUpload from "@/components/Upload/FileUpload";
|
||||
import MainImgUpload from "@/components/Upload/MainImgUpload";
|
||||
// 导入GroupSelection组件
|
||||
import GroupSelection from "@/components/GroupSelection";
|
||||
import { GroupSelectionItem } from "@/components/GroupSelection/data";
|
||||
import { MessageContentItem, messageTypes } from "./base.data";
|
||||
|
||||
interface MessageCardProps {
|
||||
message: MessageContentItem;
|
||||
dayIndex: number;
|
||||
messageIndex: number;
|
||||
planDay: number;
|
||||
onUpdateMessage: (
|
||||
dayIndex: number,
|
||||
messageIndex: number,
|
||||
updates: Partial<MessageContentItem>,
|
||||
) => void;
|
||||
onRemoveMessage: (dayIndex: number, messageIndex: number) => void;
|
||||
onToggleIntervalUnit: (dayIndex: number, messageIndex: number) => void;
|
||||
}
|
||||
|
||||
const MessageCard: React.FC<MessageCardProps> = ({
|
||||
message,
|
||||
dayIndex,
|
||||
messageIndex,
|
||||
planDay,
|
||||
onUpdateMessage,
|
||||
onRemoveMessage,
|
||||
onToggleIntervalUnit,
|
||||
}) => {
|
||||
return (
|
||||
<div className={styles["messages-message-card"]}>
|
||||
<div className={styles["messages-message-header"]}>
|
||||
{/* 时间/间隔设置 */}
|
||||
<div className={styles["messages-message-header-content"]}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||
{planDay === 0 ? (
|
||||
<>
|
||||
<span style={{ minWidth: 36 }}>间隔</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={String(message.sendInterval || 5)}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
sendInterval: Number(e.target.value),
|
||||
})
|
||||
}
|
||||
style={{ width: 60 }}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => onToggleIntervalUnit(dayIndex, messageIndex)}
|
||||
>
|
||||
<ClockCircleOutlined />
|
||||
{message.intervalUnit === "minutes" ? "分钟" : "秒"}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span style={{ minWidth: 60 }}>发送时间</span>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
max={23}
|
||||
value={String(message.scheduledTime?.hour || 9)}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
scheduledTime: {
|
||||
...(message.scheduledTime || {
|
||||
hour: 9,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}),
|
||||
hour: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
<span>:</span>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
max={59}
|
||||
value={String(message.scheduledTime?.minute || 0)}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
scheduledTime: {
|
||||
...(message.scheduledTime || {
|
||||
hour: 9,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}),
|
||||
minute: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
<span>:</span>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
max={59}
|
||||
value={String(message.scheduledTime?.second || 0)}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
scheduledTime: {
|
||||
...(message.scheduledTime || {
|
||||
hour: 9,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}),
|
||||
second: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className={styles["messages-message-remove-btn"]}
|
||||
onClick={() => onRemoveMessage(dayIndex, messageIndex)}
|
||||
title="删除"
|
||||
>
|
||||
<CloseOutlined />
|
||||
</button>
|
||||
</div>
|
||||
{/* 类型切换按钮 */}
|
||||
<div className={styles["messages-message-type-btns"]}>
|
||||
{messageTypes.map(type => (
|
||||
<Button
|
||||
key={type.id}
|
||||
type={message.type === type.id ? "primary" : "default"}
|
||||
onClick={() =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
type: type.id as any,
|
||||
})
|
||||
}
|
||||
className={styles["messages-message-type-btn"]}
|
||||
>
|
||||
<type.icon />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["messages-message-content"]}>
|
||||
{/* 文本消息 */}
|
||||
{message.type === "text" && (
|
||||
<Input.TextArea
|
||||
value={message.content}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
content: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入消息内容"
|
||||
autoSize={{ minRows: 3, maxRows: 6 }}
|
||||
/>
|
||||
)}
|
||||
{/* 小程序消息 */}
|
||||
{message.type === "miniprogram" && (
|
||||
<>
|
||||
<Input
|
||||
value={message.title}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
title: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入小程序标题"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.description}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
description: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入小程序描述"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.address}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
address: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入小程序路径"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<MainImgUpload
|
||||
value={message.content || ""}
|
||||
onChange={url =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
content: url,
|
||||
})
|
||||
}
|
||||
maxSize={5}
|
||||
showPreview={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* 链接消息 */}
|
||||
{message.type === "link" && (
|
||||
<>
|
||||
<Input
|
||||
value={message.title}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
title: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入链接标题"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.description}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
description: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入链接描述"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.linkUrl}
|
||||
onChange={e =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
linkUrl: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入链接地址"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<MainImgUpload
|
||||
value={message.coverImage || ""}
|
||||
onChange={url =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
coverImage: url,
|
||||
})
|
||||
}
|
||||
maxSize={5}
|
||||
showPreview={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* 群邀请消息 */}
|
||||
{message.type === "group" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<GroupSelection
|
||||
selectedOptions={message.groupOptions || []}
|
||||
onSelect={(groups: GroupSelectionItem[]) => {
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
groupIds: groups.map(v => v.id),
|
||||
groupOptions: groups,
|
||||
});
|
||||
}}
|
||||
placeholder="选择邀请入的群"
|
||||
showSelectedList={true}
|
||||
selectedListMaxHeight={200}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 图片消息 */}
|
||||
{message.type === "image" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<ImageUpload
|
||||
value={message.content ? [message.content] : []}
|
||||
onChange={urls =>
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
content: urls[0] || "",
|
||||
})
|
||||
}
|
||||
count={1}
|
||||
accept="image/*"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 视频消息 */}
|
||||
{message.type === "video" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<VideoUpload
|
||||
value={message.content || ""}
|
||||
onChange={url => {
|
||||
const videoUrl = Array.isArray(url) ? url[0] || "" : url;
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
content: videoUrl,
|
||||
});
|
||||
}}
|
||||
maxSize={50}
|
||||
maxCount={5}
|
||||
showPreview={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 文件消息 */}
|
||||
{message.type === "file" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<FileUpload
|
||||
value={message.content || ""}
|
||||
onChange={url => {
|
||||
const fileUrl = Array.isArray(url) ? url[0] || "" : url;
|
||||
onUpdateMessage(dayIndex, messageIndex, {
|
||||
content: fileUrl,
|
||||
});
|
||||
}}
|
||||
maxSize={10}
|
||||
maxCount={10}
|
||||
showPreview={true}
|
||||
acceptTypes={["excel", "word", "ppt"]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageCard;
|
||||
@@ -1,96 +1,52 @@
|
||||
import React, { useState } from "react";
|
||||
import { Input, Button, Tabs, Modal, message } from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
CloseOutlined,
|
||||
ClockCircleOutlined,
|
||||
MessageOutlined,
|
||||
PictureOutlined,
|
||||
VideoCameraOutlined,
|
||||
FileOutlined,
|
||||
AppstoreOutlined,
|
||||
LinkOutlined,
|
||||
TeamOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Button, Tabs, Modal, message } from "antd";
|
||||
import { PlusOutlined, CloseOutlined } from "@ant-design/icons";
|
||||
import styles from "./messages.module.scss";
|
||||
// 导入Upload组件
|
||||
import ImageUpload from "@/components/Upload/ImageUpload/ImageUpload";
|
||||
import VideoUpload from "@/components/Upload/VideoUpload";
|
||||
import FileUpload from "@/components/Upload/FileUpload";
|
||||
import MainImgUpload from "@/components/Upload/MainImgUpload";
|
||||
// 导入GroupSelection组件
|
||||
import GroupSelection from "@/components/GroupSelection";
|
||||
|
||||
interface MessageContent {
|
||||
id: string;
|
||||
type: "text" | "image" | "video" | "file" | "miniprogram" | "link" | "group";
|
||||
content: string;
|
||||
sendInterval?: number;
|
||||
intervalUnit?: "seconds" | "minutes";
|
||||
scheduledTime?: {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
};
|
||||
title?: string;
|
||||
description?: string;
|
||||
address?: string;
|
||||
coverImage?: string;
|
||||
groupIds?: string[]; // 改为数组以支持GroupSelection组件
|
||||
linkUrl?: string;
|
||||
}
|
||||
|
||||
interface DayPlan {
|
||||
day: number;
|
||||
messages: MessageContent[];
|
||||
}
|
||||
|
||||
interface MessageSettingsProps {
|
||||
formData: any;
|
||||
onChange: (data: any) => void;
|
||||
}
|
||||
|
||||
// 消息类型配置
|
||||
const messageTypes = [
|
||||
{ id: "text", icon: MessageOutlined, label: "文本" },
|
||||
{ id: "image", icon: PictureOutlined, label: "图片" },
|
||||
{ id: "video", icon: VideoCameraOutlined, label: "视频" },
|
||||
{ id: "file", icon: FileOutlined, label: "文件" },
|
||||
{ id: "miniprogram", icon: AppstoreOutlined, label: "小程序" },
|
||||
{ id: "link", icon: LinkOutlined, label: "链接" },
|
||||
{ id: "group", icon: TeamOutlined, label: "邀请入群" },
|
||||
];
|
||||
import {
|
||||
MessageContentItem,
|
||||
MessageContentGroup,
|
||||
MessageSettingsProps,
|
||||
} from "./base.data";
|
||||
import MessageCard from "./MessageCard";
|
||||
|
||||
const MessageSettings: React.FC<MessageSettingsProps> = ({
|
||||
formData,
|
||||
onChange,
|
||||
}) => {
|
||||
const [dayPlans, setDayPlans] = useState<DayPlan[]>([
|
||||
{
|
||||
day: 0,
|
||||
messages: [
|
||||
{
|
||||
id: "1",
|
||||
type: "text",
|
||||
content: "",
|
||||
sendInterval: 5,
|
||||
intervalUnit: "seconds",
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
const [isAddDayPlanOpen, setIsAddDayPlanOpen] = useState(false);
|
||||
|
||||
// 获取当前的消息计划,如果没有则使用默认值
|
||||
const getCurrentMessagePlans = (): MessageContentGroup[] => {
|
||||
if (formData.messagePlans && formData.messagePlans.length > 0) {
|
||||
return formData.messagePlans;
|
||||
}
|
||||
return [
|
||||
{
|
||||
day: 0,
|
||||
messages: [
|
||||
{
|
||||
id: "1",
|
||||
type: "text",
|
||||
content: "",
|
||||
sendInterval: 5,
|
||||
intervalUnit: "seconds",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// 添加新消息
|
||||
const handleAddMessage = (dayIndex: number, type = "text") => {
|
||||
const updatedPlans = [...dayPlans];
|
||||
const newMessage: MessageContent = {
|
||||
const currentPlans = getCurrentMessagePlans();
|
||||
const updatedPlans = [...currentPlans];
|
||||
const newMessage: MessageContentItem = {
|
||||
id: Date.now().toString(),
|
||||
type: type as MessageContent["type"],
|
||||
type: type as MessageContentItem["type"],
|
||||
content: "",
|
||||
};
|
||||
|
||||
if (dayPlans[dayIndex].day === 0) {
|
||||
if (currentPlans[dayIndex].day === 0) {
|
||||
newMessage.sendInterval = 5;
|
||||
newMessage.intervalUnit = "seconds";
|
||||
} else {
|
||||
@@ -102,7 +58,6 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
|
||||
}
|
||||
|
||||
updatedPlans[dayIndex].messages.push(newMessage);
|
||||
setDayPlans(updatedPlans);
|
||||
onChange({ ...formData, messagePlans: updatedPlans });
|
||||
};
|
||||
|
||||
@@ -110,37 +65,39 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
|
||||
const handleUpdateMessage = (
|
||||
dayIndex: number,
|
||||
messageIndex: number,
|
||||
updates: Partial<MessageContent>,
|
||||
updates: Partial<MessageContentItem>,
|
||||
) => {
|
||||
const updatedPlans = [...dayPlans];
|
||||
const currentPlans = getCurrentMessagePlans();
|
||||
const updatedPlans = [...currentPlans];
|
||||
updatedPlans[dayIndex].messages[messageIndex] = {
|
||||
...updatedPlans[dayIndex].messages[messageIndex],
|
||||
...updates,
|
||||
};
|
||||
setDayPlans(updatedPlans);
|
||||
onChange({ ...formData, messagePlans: updatedPlans });
|
||||
};
|
||||
|
||||
// 删除消息
|
||||
const handleRemoveMessage = (dayIndex: number, messageIndex: number) => {
|
||||
const updatedPlans = [...dayPlans];
|
||||
const currentPlans = getCurrentMessagePlans();
|
||||
const updatedPlans = [...currentPlans];
|
||||
updatedPlans[dayIndex].messages.splice(messageIndex, 1);
|
||||
setDayPlans(updatedPlans);
|
||||
onChange({ ...formData, messagePlans: updatedPlans });
|
||||
};
|
||||
|
||||
// 切换时间单位
|
||||
const toggleIntervalUnit = (dayIndex: number, messageIndex: number) => {
|
||||
const message = dayPlans[dayIndex].messages[messageIndex];
|
||||
const currentPlans = getCurrentMessagePlans();
|
||||
const message = currentPlans[dayIndex].messages[messageIndex];
|
||||
const newUnit = message.intervalUnit === "minutes" ? "seconds" : "minutes";
|
||||
handleUpdateMessage(dayIndex, messageIndex, { intervalUnit: newUnit });
|
||||
};
|
||||
|
||||
// 添加新的天数计划
|
||||
const handleAddDayPlan = () => {
|
||||
const newDay = dayPlans.length;
|
||||
setDayPlans([
|
||||
...dayPlans,
|
||||
const currentPlans = getCurrentMessagePlans();
|
||||
const newDay = currentPlans.length;
|
||||
const updatedPlans = [
|
||||
...currentPlans,
|
||||
{
|
||||
day: newDay,
|
||||
messages: [
|
||||
@@ -156,7 +113,8 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
];
|
||||
onChange({ ...formData, messagePlans: updatedPlans });
|
||||
setIsAddDayPlanOpen(false);
|
||||
message.success(`已添加第${newDay}天的消息计划`);
|
||||
};
|
||||
@@ -168,363 +126,82 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPlans = getCurrentMessagePlans();
|
||||
Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: `确定要删除第${dayPlans[dayIndex].day}天的消息计划吗?`,
|
||||
content: `确定要删除第${currentPlans[dayIndex].day}天的消息计划吗?`,
|
||||
onOk: () => {
|
||||
const updatedPlans = dayPlans.filter((_, index) => index !== dayIndex);
|
||||
const updatedPlans = currentPlans.filter(
|
||||
(_, index) => index !== dayIndex,
|
||||
);
|
||||
// 重新计算天数
|
||||
const recalculatedPlans = updatedPlans.map((plan, index) => ({
|
||||
...plan,
|
||||
day: index,
|
||||
}));
|
||||
setDayPlans(recalculatedPlans);
|
||||
onChange({ ...formData, messagePlans: recalculatedPlans });
|
||||
message.success(`已删除第${dayPlans[dayIndex].day}天的消息计划`);
|
||||
message.success(`已删除第${currentPlans[dayIndex].day}天的消息计划`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const items = dayPlans.map((plan, dayIndex) => ({
|
||||
key: plan.day.toString(),
|
||||
label: (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "2px",
|
||||
}}
|
||||
>
|
||||
<span>{plan.day === 0 ? "即时消息" : `第${plan.day}天`}</span>
|
||||
{dayIndex > 0 && (
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<CloseOutlined />}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handleRemoveDayPlan(dayIndex);
|
||||
}}
|
||||
style={{
|
||||
padding: "0 4px",
|
||||
minWidth: "auto",
|
||||
color: "#ff4d4f",
|
||||
fontSize: "12px",
|
||||
}}
|
||||
title="删除此天计划"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<div className={styles["messages-day-panel"]}>
|
||||
{plan.messages.map((message, messageIndex) => (
|
||||
<div key={message.id} className={styles["messages-message-card"]}>
|
||||
<div className={styles["messages-message-header"]}>
|
||||
{/* 时间/间隔设置 */}
|
||||
<div className={styles["messages-message-header-content"]}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
|
||||
{plan.day === 0 ? (
|
||||
<>
|
||||
<span style={{ minWidth: 36 }}>间隔</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={String(message.sendInterval || 5)}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
sendInterval: Number(e.target.value),
|
||||
})
|
||||
}
|
||||
style={{ width: 60 }}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() =>
|
||||
toggleIntervalUnit(dayIndex, messageIndex)
|
||||
}
|
||||
>
|
||||
<ClockCircleOutlined />
|
||||
{message.intervalUnit === "minutes" ? "分钟" : "秒"}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span style={{ minWidth: 60 }}>发送时间</span>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
max={23}
|
||||
value={String(message.scheduledTime?.hour || 9)}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
scheduledTime: {
|
||||
...(message.scheduledTime || {
|
||||
hour: 9,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}),
|
||||
hour: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
<span>:</span>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
max={59}
|
||||
value={String(message.scheduledTime?.minute || 0)}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
scheduledTime: {
|
||||
...(message.scheduledTime || {
|
||||
hour: 9,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}),
|
||||
minute: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
<span>:</span>
|
||||
<Input
|
||||
type="number"
|
||||
min={0}
|
||||
max={59}
|
||||
value={String(message.scheduledTime?.second || 0)}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
scheduledTime: {
|
||||
...(message.scheduledTime || {
|
||||
hour: 9,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
}),
|
||||
second: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className={styles["messages-message-remove-btn"]}
|
||||
onClick={() => handleRemoveMessage(dayIndex, messageIndex)}
|
||||
title="删除"
|
||||
>
|
||||
<CloseOutlined />
|
||||
</button>
|
||||
</div>
|
||||
{/* 类型切换按钮 */}
|
||||
<div className={styles["messages-message-type-btns"]}>
|
||||
{messageTypes.map(type => (
|
||||
<Button
|
||||
key={type.id}
|
||||
type={message.type === type.id ? "primary" : "default"}
|
||||
onClick={() =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
type: type.id as any,
|
||||
})
|
||||
}
|
||||
className={styles["messages-message-type-btn"]}
|
||||
>
|
||||
<type.icon />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["messages-message-content"]}>
|
||||
{/* 文本消息 */}
|
||||
{message.type === "text" && (
|
||||
<Input.TextArea
|
||||
value={message.content}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
content: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入消息内容"
|
||||
autoSize={{ minRows: 3, maxRows: 6 }}
|
||||
/>
|
||||
)}
|
||||
{/* 小程序消息 */}
|
||||
{message.type === "miniprogram" && (
|
||||
<>
|
||||
<Input
|
||||
value={message.title}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
title: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入小程序标题"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.description}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
description: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入小程序描述"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.address}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
address: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入小程序路径"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<MainImgUpload
|
||||
value={message.coverImage || ""}
|
||||
onChange={url =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
coverImage: url,
|
||||
})
|
||||
}
|
||||
maxSize={5}
|
||||
showPreview={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* 链接消息 */}
|
||||
{message.type === "link" && (
|
||||
<>
|
||||
<Input
|
||||
value={message.title}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
title: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入链接标题"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.description}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
description: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入链接描述"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<Input
|
||||
value={message.linkUrl}
|
||||
onChange={e =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
linkUrl: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="请输入链接地址"
|
||||
style={{ marginBottom: 8 }}
|
||||
/>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<MainImgUpload
|
||||
value={message.coverImage || ""}
|
||||
onChange={url =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
coverImage: url,
|
||||
})
|
||||
}
|
||||
maxSize={5}
|
||||
showPreview={true}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* 群邀请消息 */}
|
||||
{message.type === "group" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<GroupSelection
|
||||
selectedOptions={message.groupIds || []}
|
||||
onSelect={groupIds =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
groupIds: groupIds,
|
||||
})
|
||||
}
|
||||
placeholder="选择邀请入的群"
|
||||
showSelectedList={true}
|
||||
selectedListMaxHeight={200}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 图片消息 */}
|
||||
{message.type === "image" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<ImageUpload
|
||||
value={message.content ? [message.content] : []}
|
||||
onChange={urls =>
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
content: urls[0] || "",
|
||||
})
|
||||
}
|
||||
count={10}
|
||||
accept="image/*"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 视频消息 */}
|
||||
{message.type === "video" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<VideoUpload
|
||||
value={message.content || ""}
|
||||
onChange={url => {
|
||||
const videoUrl = Array.isArray(url) ? url[0] || "" : url;
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
content: videoUrl,
|
||||
});
|
||||
}}
|
||||
maxSize={50}
|
||||
maxCount={5}
|
||||
showPreview={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 文件消息 */}
|
||||
{message.type === "file" && (
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<FileUpload
|
||||
value={message.content || ""}
|
||||
onChange={url => {
|
||||
const fileUrl = Array.isArray(url) ? url[0] || "" : url;
|
||||
handleUpdateMessage(dayIndex, messageIndex, {
|
||||
content: fileUrl,
|
||||
});
|
||||
}}
|
||||
maxSize={10}
|
||||
maxCount={10}
|
||||
showPreview={true}
|
||||
acceptTypes={["excel", "word", "ppt"]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Button
|
||||
onClick={() => handleAddMessage(dayIndex)}
|
||||
className={styles["messages-add-message-btn"]}
|
||||
const items = getCurrentMessagePlans().map(
|
||||
(plan: MessageContentGroup, dayIndex: number) => ({
|
||||
key: plan.day.toString(),
|
||||
label: (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "2px",
|
||||
}}
|
||||
>
|
||||
<PlusOutlined className="w-4 h-4 mr-2" />
|
||||
添加消息
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
<span>{plan.day === 0 ? "即时消息" : `第${plan.day}天`}</span>
|
||||
{dayIndex > 0 && (
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<CloseOutlined />}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handleRemoveDayPlan(dayIndex);
|
||||
}}
|
||||
style={{
|
||||
padding: "0 4px",
|
||||
minWidth: "auto",
|
||||
color: "#ff4d4f",
|
||||
fontSize: "12px",
|
||||
}}
|
||||
title="删除此天计划"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
children: (
|
||||
<div className={styles["messages-day-panel"]}>
|
||||
{plan.messages.map((message, messageIndex) => (
|
||||
<MessageCard
|
||||
key={message.id}
|
||||
message={message}
|
||||
dayIndex={dayIndex}
|
||||
messageIndex={messageIndex}
|
||||
planDay={plan.day}
|
||||
onUpdateMessage={handleUpdateMessage}
|
||||
onRemoveMessage={handleRemoveMessage}
|
||||
onToggleIntervalUnit={toggleIntervalUnit}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
onClick={() => handleAddMessage(dayIndex)}
|
||||
className={styles["messages-add-message-btn"]}
|
||||
>
|
||||
<PlusOutlined className="w-4 h-4 mr-2" />
|
||||
添加消息
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles["messages-container"]}>
|
||||
@@ -555,7 +232,7 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
|
||||
onClick={handleAddDayPlan}
|
||||
className={styles["messages-modal-btn"]}
|
||||
>
|
||||
添加第 {dayPlans.length} 天计划
|
||||
添加第 {getCurrentMessagePlans().length} 天计划
|
||||
</Button>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
@@ -30,3 +30,53 @@ export const posterTemplates = [
|
||||
url: "https://hebbkx1anhila5yf.public.blob.vercel-storage.com/%E7%82%B9%E5%87%BB%E6%8A%A5%E5%90%8D-Mj0nnva0BiASeDAIhNNaRRAbjPgjEj.gif",
|
||||
},
|
||||
];
|
||||
// ========================================
|
||||
import {
|
||||
MessageOutlined,
|
||||
PictureOutlined,
|
||||
VideoCameraOutlined,
|
||||
FileOutlined,
|
||||
AppstoreOutlined,
|
||||
LinkOutlined,
|
||||
TeamOutlined,
|
||||
} from "@ant-design/icons";
|
||||
|
||||
export interface MessageContentItem {
|
||||
id: string;
|
||||
type: "text" | "image" | "video" | "file" | "miniprogram" | "link" | "group";
|
||||
content: string;
|
||||
sendInterval?: number;
|
||||
intervalUnit?: "seconds" | "minutes";
|
||||
scheduledTime?: {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
};
|
||||
title?: string;
|
||||
description?: string;
|
||||
address?: string;
|
||||
groupIds?: string[]; // 改为数组以支持GroupSelection组件
|
||||
groupOptions?: any[]; // 添加群选项数组
|
||||
linkUrl?: string;
|
||||
}
|
||||
|
||||
export interface MessageContentGroup {
|
||||
day: number;
|
||||
messages: MessageContentItem[];
|
||||
}
|
||||
|
||||
export interface MessageSettingsProps {
|
||||
formData: any;
|
||||
onChange: (data: any) => void;
|
||||
}
|
||||
|
||||
// 消息类型配置
|
||||
export const messageTypes = [
|
||||
{ id: "text", icon: MessageOutlined, label: "文本" },
|
||||
{ id: "image", icon: PictureOutlined, label: "图片" },
|
||||
{ id: "video", icon: VideoCameraOutlined, label: "视频" },
|
||||
{ id: "file", icon: FileOutlined, label: "文件" },
|
||||
{ id: "miniprogram", icon: AppstoreOutlined, label: "小程序" },
|
||||
{ id: "link", icon: LinkOutlined, label: "链接" },
|
||||
{ id: "group", icon: TeamOutlined, label: "邀请入群" },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user