From 88a007de7cd3864a7e8f9138883fa328ede0e63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Tue, 12 Aug 2025 15:31:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20index.html=20=E5=92=8C=20m?= =?UTF-8?q?anifest.json=20=E4=B8=AD=E7=9A=84=E8=B3=87=E6=BA=90=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E7=89=88=E6=9C=AC=EF=BC=8C=E4=B8=A6=E5=9C=A8=E6=96=B0?= =?UTF-8?q?=E8=A8=88=E5=8A=83=E9=A0=81=E9=9D=A2=E4=B8=AD=E8=AA=BF=E6=95=B4?= =?UTF-8?q?=E6=B5=B7=E5=A0=B1=E6=A8=A1=E6=9D=BF=E7=9A=84=E5=B1=AC=E6=80=A7?= =?UTF-8?q?=E5=90=8D=E7=A8=B1=EF=BC=8C=E5=B0=87=20preview=20=E6=94=B9?= =?UTF-8?q?=E7=82=BA=20url=EF=BC=8C=E4=BB=A5=E7=B5=B1=E4=B8=80=E8=B3=87?= =?UTF-8?q?=E6=96=99=E7=B5=90=E6=A7=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cunkebao/dist/.vite/manifest.json | 2 +- Cunkebao/dist/index.html | 2 +- .../components/Upload/MainImgUpload/index.tsx | 70 ++- .../mobile/scenarios/plan/new/index.data.ts | 54 ++ .../pages/mobile/scenarios/plan/new/index.tsx | 53 +- .../plan/new/steps/BasicSettings.tsx | 22 +- .../scenarios/plan/new/steps/MessageCard.tsx | 336 +++++++++++ .../plan/new/steps/MessageSettings.tsx | 543 ++++-------------- .../scenarios/plan/new/steps/base.data.ts | 50 ++ 9 files changed, 631 insertions(+), 501 deletions(-) create mode 100644 Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts create mode 100644 Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageCard.tsx diff --git a/Cunkebao/dist/.vite/manifest.json b/Cunkebao/dist/.vite/manifest.json index 213d2ca9..1c9f00ac 100644 --- a/Cunkebao/dist/.vite/manifest.json +++ b/Cunkebao/dist/.vite/manifest.json @@ -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, diff --git a/Cunkebao/dist/index.html b/Cunkebao/dist/index.html index e01bbc47..6ce49aa0 100644 --- a/Cunkebao/dist/index.html +++ b/Cunkebao/dist/index.html @@ -11,7 +11,7 @@ - + diff --git a/Cunkebao/src/components/Upload/MainImgUpload/index.tsx b/Cunkebao/src/components/Upload/MainImgUpload/index.tsx index 2d26cd84..7905a844 100644 --- a/Cunkebao/src/components/Upload/MainImgUpload/index.tsx +++ b/Cunkebao/src/components/Upload/MainImgUpload/index.tsx @@ -137,12 +137,47 @@ const MainImgUpload: React.FC = ({ // 预览图片 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 = ({ /> -
+
{ + // 阻止事件冒泡,防止触发删除操作 + e.stopPropagation(); + // 点击图片预览区域时,触发文件选择 + const uploadInput = document.querySelector( + 'input[type="file"]', + ) as HTMLInputElement; + if (uploadInput) { + uploadInput.click(); + } + }} + > {file.name} = ({ type="text" size="small" icon={} - onClick={() => handlePreview(file.url || "")} + onClick={e => { + e.stopPropagation(); + handlePreview(file.url || ""); + }} className={style.previewBtn} /> )} @@ -265,7 +316,10 @@ const MainImgUpload: React.FC = ({ type="text" size="small" icon={} - onClick={() => handleRemove()} + onClick={e => { + e.stopPropagation(); + handleRemove(); + }} className={style.deleteBtn} />
diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts new file mode 100644 index 00000000..5d98f190 --- /dev/null +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts @@ -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: [], +}; diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx index 5e6d2ac5..4777e8d9 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx @@ -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({ - 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(defFormData); const [sceneList, setSceneList] = useState([]); 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) { diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx index da42a65d..030501c0 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx @@ -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 = ({ questionExtraction: formData.phoneSettings?.questionExtraction ?? true, }); - // 群设置相关状态 - const [weixinqunName, setWeixinqunName] = useState( - formData.weixinqunName || "", - ); - const [weixinqunNotice, setWeixinqunNotice] = useState( - formData.weixinqunNotice || "", - ); - // 新增:自定义海报相关状态 const [customPosters, setCustomPosters] = useState([]); const [previewUrl, setPreviewUrl] = useState(null); @@ -187,6 +180,13 @@ const BasicSettings: React.FC = ({ const openPoster = formData.scenario !== 1 ? { display: "none" } : { display: "block" }; + const handleWechatGroupSelect = (groups: GroupSelectionItem[]) => { + onChange({ + ...formData, + wechatGroups: groups.map(v => v.id), + wechatGroupsOptions: groups, + }); + }; return (
{/* 场景选择区块 */} @@ -420,10 +420,8 @@ const BasicSettings: React.FC = ({
选择群聊
- onChange({ ...formData, groupSelected: groups }) - } + selectedOptions={formData.wechatGroupsOptions || []} + onSelect={handleWechatGroupSelect} placeholder="请选择微信群" className={styles["basic-group-selector"]} /> diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageCard.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageCard.tsx new file mode 100644 index 00000000..8eb50515 --- /dev/null +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageCard.tsx @@ -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, + ) => void; + onRemoveMessage: (dayIndex: number, messageIndex: number) => void; + onToggleIntervalUnit: (dayIndex: number, messageIndex: number) => void; +} + +const MessageCard: React.FC = ({ + message, + dayIndex, + messageIndex, + planDay, + onUpdateMessage, + onRemoveMessage, + onToggleIntervalUnit, +}) => { + return ( +
+
+ {/* 时间/间隔设置 */} +
+
+ {planDay === 0 ? ( + <> + 间隔 + + onUpdateMessage(dayIndex, messageIndex, { + sendInterval: Number(e.target.value), + }) + } + style={{ width: 60 }} + /> + + + ) : ( + <> + 发送时间 + + onUpdateMessage(dayIndex, messageIndex, { + scheduledTime: { + ...(message.scheduledTime || { + hour: 9, + minute: 0, + second: 0, + }), + hour: Number(e.target.value), + }, + }) + } + style={{ width: 40 }} + /> + : + + onUpdateMessage(dayIndex, messageIndex, { + scheduledTime: { + ...(message.scheduledTime || { + hour: 9, + minute: 0, + second: 0, + }), + minute: Number(e.target.value), + }, + }) + } + style={{ width: 40 }} + /> + : + + onUpdateMessage(dayIndex, messageIndex, { + scheduledTime: { + ...(message.scheduledTime || { + hour: 9, + minute: 0, + second: 0, + }), + second: Number(e.target.value), + }, + }) + } + style={{ width: 40 }} + /> + + )} +
+ +
+ {/* 类型切换按钮 */} +
+ {messageTypes.map(type => ( + + ))} +
+
+
+ {/* 文本消息 */} + {message.type === "text" && ( + + onUpdateMessage(dayIndex, messageIndex, { + content: e.target.value, + }) + } + placeholder="请输入消息内容" + autoSize={{ minRows: 3, maxRows: 6 }} + /> + )} + {/* 小程序消息 */} + {message.type === "miniprogram" && ( + <> + + onUpdateMessage(dayIndex, messageIndex, { + title: e.target.value, + }) + } + placeholder="请输入小程序标题" + style={{ marginBottom: 8 }} + /> + + onUpdateMessage(dayIndex, messageIndex, { + description: e.target.value, + }) + } + placeholder="请输入小程序描述" + style={{ marginBottom: 8 }} + /> + + onUpdateMessage(dayIndex, messageIndex, { + address: e.target.value, + }) + } + placeholder="请输入小程序路径" + style={{ marginBottom: 8 }} + /> +
+ + onUpdateMessage(dayIndex, messageIndex, { + content: url, + }) + } + maxSize={5} + showPreview={true} + /> +
+ + )} + {/* 链接消息 */} + {message.type === "link" && ( + <> + + onUpdateMessage(dayIndex, messageIndex, { + title: e.target.value, + }) + } + placeholder="请输入链接标题" + style={{ marginBottom: 8 }} + /> + + onUpdateMessage(dayIndex, messageIndex, { + description: e.target.value, + }) + } + placeholder="请输入链接描述" + style={{ marginBottom: 8 }} + /> + + onUpdateMessage(dayIndex, messageIndex, { + linkUrl: e.target.value, + }) + } + placeholder="请输入链接地址" + style={{ marginBottom: 8 }} + /> +
+ + onUpdateMessage(dayIndex, messageIndex, { + coverImage: url, + }) + } + maxSize={5} + showPreview={true} + /> +
+ + )} + {/* 群邀请消息 */} + {message.type === "group" && ( +
+ { + onUpdateMessage(dayIndex, messageIndex, { + groupIds: groups.map(v => v.id), + groupOptions: groups, + }); + }} + placeholder="选择邀请入的群" + showSelectedList={true} + selectedListMaxHeight={200} + /> +
+ )} + {/* 图片消息 */} + {message.type === "image" && ( +
+ + onUpdateMessage(dayIndex, messageIndex, { + content: urls[0] || "", + }) + } + count={1} + accept="image/*" + /> +
+ )} + {/* 视频消息 */} + {message.type === "video" && ( +
+ { + const videoUrl = Array.isArray(url) ? url[0] || "" : url; + onUpdateMessage(dayIndex, messageIndex, { + content: videoUrl, + }); + }} + maxSize={50} + maxCount={5} + showPreview={true} + /> +
+ )} + {/* 文件消息 */} + {message.type === "file" && ( +
+ { + const fileUrl = Array.isArray(url) ? url[0] || "" : url; + onUpdateMessage(dayIndex, messageIndex, { + content: fileUrl, + }); + }} + maxSize={10} + maxCount={10} + showPreview={true} + acceptTypes={["excel", "word", "ppt"]} + /> +
+ )} +
+
+ ); +}; + +export default MessageCard; diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx index e70a9def..23116882 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx @@ -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 = ({ formData, onChange, }) => { - const [dayPlans, setDayPlans] = useState([ - { - 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 = ({ } updatedPlans[dayIndex].messages.push(newMessage); - setDayPlans(updatedPlans); onChange({ ...formData, messagePlans: updatedPlans }); }; @@ -110,37 +65,39 @@ const MessageSettings: React.FC = ({ const handleUpdateMessage = ( dayIndex: number, messageIndex: number, - updates: Partial, + updates: Partial, ) => { - 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 = ({ }, ], }, - ]); + ]; + onChange({ ...formData, messagePlans: updatedPlans }); setIsAddDayPlanOpen(false); message.success(`已添加第${newDay}天的消息计划`); }; @@ -168,363 +126,82 @@ const MessageSettings: React.FC = ({ 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: ( -
- {plan.day === 0 ? "即时消息" : `第${plan.day}天`} - {dayIndex > 0 && ( -
- ), - children: ( -
- {plan.messages.map((message, messageIndex) => ( -
-
- {/* 时间/间隔设置 */} -
-
- {plan.day === 0 ? ( - <> - 间隔 - - handleUpdateMessage(dayIndex, messageIndex, { - sendInterval: Number(e.target.value), - }) - } - style={{ width: 60 }} - /> - - - ) : ( - <> - 发送时间 - - handleUpdateMessage(dayIndex, messageIndex, { - scheduledTime: { - ...(message.scheduledTime || { - hour: 9, - minute: 0, - second: 0, - }), - hour: Number(e.target.value), - }, - }) - } - style={{ width: 40 }} - /> - : - - handleUpdateMessage(dayIndex, messageIndex, { - scheduledTime: { - ...(message.scheduledTime || { - hour: 9, - minute: 0, - second: 0, - }), - minute: Number(e.target.value), - }, - }) - } - style={{ width: 40 }} - /> - : - - handleUpdateMessage(dayIndex, messageIndex, { - scheduledTime: { - ...(message.scheduledTime || { - hour: 9, - minute: 0, - second: 0, - }), - second: Number(e.target.value), - }, - }) - } - style={{ width: 40 }} - /> - - )} -
- -
- {/* 类型切换按钮 */} -
- {messageTypes.map(type => ( - - ))} -
-
-
- {/* 文本消息 */} - {message.type === "text" && ( - - handleUpdateMessage(dayIndex, messageIndex, { - content: e.target.value, - }) - } - placeholder="请输入消息内容" - autoSize={{ minRows: 3, maxRows: 6 }} - /> - )} - {/* 小程序消息 */} - {message.type === "miniprogram" && ( - <> - - handleUpdateMessage(dayIndex, messageIndex, { - title: e.target.value, - }) - } - placeholder="请输入小程序标题" - style={{ marginBottom: 8 }} - /> - - handleUpdateMessage(dayIndex, messageIndex, { - description: e.target.value, - }) - } - placeholder="请输入小程序描述" - style={{ marginBottom: 8 }} - /> - - handleUpdateMessage(dayIndex, messageIndex, { - address: e.target.value, - }) - } - placeholder="请输入小程序路径" - style={{ marginBottom: 8 }} - /> -
- - handleUpdateMessage(dayIndex, messageIndex, { - coverImage: url, - }) - } - maxSize={5} - showPreview={true} - /> -
- - )} - {/* 链接消息 */} - {message.type === "link" && ( - <> - - handleUpdateMessage(dayIndex, messageIndex, { - title: e.target.value, - }) - } - placeholder="请输入链接标题" - style={{ marginBottom: 8 }} - /> - - handleUpdateMessage(dayIndex, messageIndex, { - description: e.target.value, - }) - } - placeholder="请输入链接描述" - style={{ marginBottom: 8 }} - /> - - handleUpdateMessage(dayIndex, messageIndex, { - linkUrl: e.target.value, - }) - } - placeholder="请输入链接地址" - style={{ marginBottom: 8 }} - /> -
- - handleUpdateMessage(dayIndex, messageIndex, { - coverImage: url, - }) - } - maxSize={5} - showPreview={true} - /> -
- - )} - {/* 群邀请消息 */} - {message.type === "group" && ( -
- - handleUpdateMessage(dayIndex, messageIndex, { - groupIds: groupIds, - }) - } - placeholder="选择邀请入的群" - showSelectedList={true} - selectedListMaxHeight={200} - /> -
- )} - {/* 图片消息 */} - {message.type === "image" && ( -
- - handleUpdateMessage(dayIndex, messageIndex, { - content: urls[0] || "", - }) - } - count={10} - accept="image/*" - /> -
- )} - {/* 视频消息 */} - {message.type === "video" && ( -
- { - const videoUrl = Array.isArray(url) ? url[0] || "" : url; - handleUpdateMessage(dayIndex, messageIndex, { - content: videoUrl, - }); - }} - maxSize={50} - maxCount={5} - showPreview={true} - /> -
- )} - {/* 文件消息 */} - {message.type === "file" && ( -
- { - const fileUrl = Array.isArray(url) ? url[0] || "" : url; - handleUpdateMessage(dayIndex, messageIndex, { - content: fileUrl, - }); - }} - maxSize={10} - maxCount={10} - showPreview={true} - acceptTypes={["excel", "word", "ppt"]} - /> -
- )} -
-
- ))} - -
- ), - })); + {plan.day === 0 ? "即时消息" : `第${plan.day}天`} + {dayIndex > 0 && ( +
+ ), + children: ( +
+ {plan.messages.map((message, messageIndex) => ( + + ))} + +
+ ), + }), + ); return (
@@ -555,7 +232,7 @@ const MessageSettings: React.FC = ({ onClick={handleAddDayPlan} className={styles["messages-modal-btn"]} > - 添加第 {dayPlans.length} 天计划 + 添加第 {getCurrentMessagePlans().length} 天计划
diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/base.data.ts b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/base.data.ts index ea7b7034..d702bcb1 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/base.data.ts +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/base.data.ts @@ -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: "邀请入群" }, +];