From 1cb7903e37f98efc3cefacf6c8edf79c274f78a6 Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Thu, 18 Dec 2025 10:34:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=A0=E9=81=93=E4=BB=A3=E7=A0=81=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mobile/scenarios/plan/new/index.data.ts | 5 +- .../pages/mobile/scenarios/plan/new/index.tsx | 9 + .../plan/new/steps/BasicSettings.tsx | 503 +----------- .../plan/new/steps/DistributionSettings.tsx | 743 ++++++++++++++++++ .../controller/plan/PlanSceneV1Controller.php | 19 +- 5 files changed, 774 insertions(+), 505 deletions(-) create mode 100644 Cunkebao/src/pages/mobile/scenarios/plan/new/steps/DistributionSettings.tsx diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts index a3921add..01fec441 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts @@ -1,10 +1,11 @@ -// 步骤定义 - 只保留三个步骤 +// 步骤定义 - 四个步骤 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: "消息设置" }, + { id: 3, title: "步骤三", subtitle: "渠道设置" }, + { id: 4, title: "步骤四", subtitle: "消息设置" }, ]; // 类型定义 diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx index b9c4a20b..ac63a6b6 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx @@ -4,6 +4,7 @@ import { message, Button, Space } from "antd"; import NavCommon from "@/components/NavCommon"; import BasicSettings from "./steps/BasicSettings"; import FriendRequestSettings from "./steps/FriendRequestSettings"; +import DistributionSettings from "./steps/DistributionSettings"; import MessageSettings from "./steps/MessageSettings"; import Layout from "@/components/Layout/Layout"; import StepIndicator from "@/components/StepIndicator"; @@ -254,6 +255,14 @@ export default function NewPlan() { ); case 3: + return ( + + ); + case 4: return ; default: return null; 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 0573b0d2..f8136303 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef, useCallback } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { Input, Button, Tag, Switch, Spin, message, Modal } from "antd"; import { PlusOutlined, @@ -8,17 +8,12 @@ import { SearchOutlined, DeleteOutlined, } from "@ant-design/icons"; -import { Checkbox, Popup } from "antd-mobile"; import { uploadFile } from "@/api/common"; import styles from "./base.module.scss"; -import { fetchChannelList } from "@/pages/mobile/workspace/distribution-management/api"; import { posterTemplates } from "./base.data"; import GroupSelection from "@/components/GroupSelection"; import FileUpload from "@/components/Upload/FileUpload"; import { GroupSelectionItem } from "@/components/GroupSelection/data"; -import Layout from "@/components/Layout/Layout"; -import PopupHeader from "@/components/PopuLayout/header"; -import PopupFooter from "@/components/PopuLayout/footer"; interface BasicSettingsProps { isEdit: boolean; @@ -75,25 +70,6 @@ const BasicSettings: React.FC = ({ questionExtraction: formData.phoneSettings?.questionExtraction ?? true, }); - // 分销相关状态 - const [distributionEnabled, setDistributionEnabled] = useState( - formData.distributionEnabled ?? false, - ); - const [channelModalVisible, setChannelModalVisible] = useState(false); - const [channelLoading, setChannelLoading] = useState(false); - const [channelList, setChannelList] = useState([]); - const [tempSelectedChannelIds, setTempSelectedChannelIds] = useState< - Array - >(formData.distributionChannelIds || []); - const [channelSearchQuery, setChannelSearchQuery] = useState(""); - const [channelCurrentPage, setChannelCurrentPage] = useState(1); - const [channelTotal, setChannelTotal] = useState(0); - const [customerReward, setCustomerReward] = useState( - formData.distributionCustomerReward - ); - const [addReward, setAddReward] = useState( - formData.distributionAddReward - ); // 新增:自定义海报相关状态 const [customPosters, setCustomPosters] = useState([]); @@ -124,18 +100,6 @@ const BasicSettings: React.FC = ({ setTips(formData.tips || ""); }, [formData.tips]); - // 同步分销相关的外部表单数据到本地状态 - useEffect(() => { - setDistributionEnabled(formData.distributionEnabled ?? false); - setTempSelectedChannelIds(formData.distributionChannelIds || []); - setCustomerReward(formData.distributionCustomerReward); - setAddReward(formData.distributionAddReward); - }, [ - formData.distributionEnabled, - formData.distributionChannelIds, - formData.distributionCustomerReward, - formData.distributionAddReward, - ]); // 选中场景 const handleScenarioSelect = (sceneId: number) => { @@ -266,179 +230,6 @@ const BasicSettings: React.FC = ({ }); }; - const PAGE_SIZE = 20; - - // 加载分销渠道列表,支持keyword和分页,强制只获取启用的渠道 - const loadDistributionChannels = useCallback( - async (keyword: string = "", page: number = 1) => { - setChannelLoading(true); - try { - const res = await fetchChannelList({ - page, - limit: PAGE_SIZE, - keyword: keyword.trim() || undefined, - status: "enabled", // 强制只获取启用的渠道 - }); - setChannelList(res.list || []); - setChannelTotal(res.total || 0); - } catch (error: any) { - - } finally { - setChannelLoading(false); - } - }, - [] - ); - - const handleToggleDistribution = (value: boolean) => { - setDistributionEnabled(value); - // 关闭时清空已选渠道和奖励金额 - if (!value) { - setTempSelectedChannelIds([]); - setCustomerReward(undefined); - setAddReward(undefined); - onChange({ - ...formData, - distributionEnabled: false, - distributionChannelIds: [], - distributionChannelsOptions: [], - distributionCustomerReward: undefined, - distributionAddReward: undefined, - }); - } else { - onChange({ - ...formData, - distributionEnabled: true, - }); - } - }; - - // 打开弹窗时获取第一页 - useEffect(() => { - if (channelModalVisible) { - setChannelSearchQuery(""); - setChannelCurrentPage(1); - // 复制一份已选渠道到临时变量 - setTempSelectedChannelIds(formData.distributionChannelIds || []); - loadDistributionChannels("", 1); - } - }, [channelModalVisible, loadDistributionChannels, formData.distributionChannelIds]); - - // 搜索防抖 - useEffect(() => { - if (!channelModalVisible) return; - const timer = setTimeout(() => { - setChannelCurrentPage(1); - loadDistributionChannels(channelSearchQuery, 1); - }, 500); - return () => clearTimeout(timer); - }, [channelSearchQuery, channelModalVisible, loadDistributionChannels]); - - // 翻页时重新请求 - useEffect(() => { - if (!channelModalVisible) return; - loadDistributionChannels(channelSearchQuery, channelCurrentPage); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [channelCurrentPage]); - - const handleOpenChannelModal = () => { - setChannelModalVisible(true); - }; - - const handleChannelToggle = (channel: any) => { - const id = channel.id; - setTempSelectedChannelIds(prev => - prev.includes(id) ? prev.filter(v => v !== id) : [...prev, id], - ); - }; - - // 直接使用从API返回的渠道列表(API已过滤为只返回启用的) - const filteredChannels = channelList; - - const channelTotalPages = Math.max(1, Math.ceil(channelTotal / PAGE_SIZE)); - - // 全选当前页 - const handleSelectAllCurrentPage = (checked: boolean) => { - if (checked) { - // 全选:添加当前页面所有未选中的渠道 - const currentPageChannels = filteredChannels.filter( - (channel: any) => !tempSelectedChannelIds.includes(channel.id), - ); - setTempSelectedChannelIds(prev => [ - ...prev, - ...currentPageChannels.map((c: any) => c.id), - ]); - } else { - // 取消全选:移除当前页面的所有渠道 - const currentPageChannelIds = filteredChannels.map((c: any) => c.id); - setTempSelectedChannelIds(prev => - prev.filter(id => !currentPageChannelIds.includes(id)), - ); - } - }; - - // 检查当前页是否全选 - const isCurrentPageAllSelected = - filteredChannels.length > 0 && - filteredChannels.every((channel: any) => - tempSelectedChannelIds.includes(channel.id), - ); - - const handleConfirmChannels = () => { - const selectedOptions = - channelList - .filter(c => tempSelectedChannelIds.includes(c.id)) - .map(c => ({ - id: c.id, - name: c.name, - })) || []; - - onChange({ - ...formData, - distributionEnabled: true, - distributionChannelIds: tempSelectedChannelIds, - distributionChannelsOptions: selectedOptions, - }); - setDistributionEnabled(true); - setChannelModalVisible(false); - }; - - const handleCancelChannels = () => { - setChannelModalVisible(false); - // 取消时恢复为表单中的已有值 - setTempSelectedChannelIds(formData.distributionChannelIds || []); - }; - - // 获取显示文本(参考设备选择) - const getChannelDisplayText = () => { - const selectedChannels = formData.distributionChannelsOptions || []; - if (selectedChannels.length === 0) return ""; - return `已选择 ${selectedChannels.length} 个渠道`; - }; - - // 删除已选渠道 - const handleRemoveChannel = (id: string | number) => { - const newChannelIds = (formData.distributionChannelIds || []).filter( - (cid: string | number) => cid !== id - ); - const newChannelOptions = (formData.distributionChannelsOptions || []).filter( - (item: { id: string | number; name: string }) => item.id !== id - ); - onChange({ - ...formData, - distributionChannelIds: newChannelIds, - distributionChannelsOptions: newChannelOptions, - }); - }; - - // 清除所有已选渠道 - const handleClearAllChannels = () => { - onChange({ - ...formData, - distributionChannelIds: [], - distributionChannelsOptions: [], - }); - }; return (
@@ -688,190 +479,6 @@ const BasicSettings: React.FC = ({
)} - {/* 分销设置 */} -
-
-
-
分销设置
-
- 开启后,可将当前场景的获客用户同步到指定分销渠道 -
-
- -
- - {distributionEnabled && ( - <> - {/* 输入框 - 参考设备选择样式 */} -
- } - allowClear - onClear={handleClearAllChannels} - size="large" - readOnly - style={{ cursor: "pointer" }} - /> -
- {/* 已选渠道列表 - 参考设备选择样式 */} - {formData.distributionChannelsOptions && - formData.distributionChannelsOptions.length > 0 ? ( -
- {formData.distributionChannelsOptions.map( - (item: { id: string | number; name: string; code?: string }) => ( -
- {/* 渠道图标 */} -
- - {(item.name || "渠")[0]} - -
- -
-
- {item.name} -
- {item.code && ( -
- 编码: {item.code} -
- )} -
-
- ), - )} -
- ) : null} - {/* 奖励金额设置 */} -
-
获客奖励金额(元)
- { - const value = e.target.value ? Number(e.target.value) : undefined; - setCustomerReward(value); - onChange({ - ...formData, - distributionCustomerReward: value, - }); - }} - min={0} - step={0.01} - style={{ marginBottom: 12 }} - /> -
添加奖励金额(元)
- { - const value = e.target.value ? Number(e.target.value) : undefined; - setAddReward(value); - onChange({ - ...formData, - distributionAddReward: value, - }); - }} - min={0} - step={0.01} - /> -
- - )} -
- {/* 订单导入区块 - 使用FileUpload组件 */}
订单表格上传
@@ -959,114 +566,6 @@ const BasicSettings: React.FC = ({ />
- {/* 分销渠道选择弹框 - 参考设备选择样式 */} - - loadDistributionChannels(channelSearchQuery, channelCurrentPage)} - showTabs={false} - /> - } - footer={ - - } - > -
- {channelLoading && channelList.length === 0 ? ( -
-
加载中...
-
- ) : filteredChannels.length === 0 ? ( -
-
- 暂无分销渠道,请先在「分销管理」中创建渠道 -
-
- ) : ( -
- {filteredChannels.map((channel: any) => ( -
- {/* 顶部行:选择框和编码 */} -
-
- handleChannelToggle(channel)} - className={styles["channelCheckbox"]} - /> -
- - 编码: {channel.code} - -
- - {/* 主要内容区域:渠道信息 */} -
- {/* 渠道信息 */} -
-
- - {channel.name} - -
- {channel.status === "enabled" ? "启用" : "禁用"} -
-
-
- {channel.phone && ( -
- 手机号: - - {channel.phone} - -
- )} - {channel.wechatId && ( -
- 微信号: - - {channel.wechatId} - -
- )} -
-
-
-
- ))} -
- )} -
-
-
); }; diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/DistributionSettings.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/DistributionSettings.tsx new file mode 100644 index 00000000..cccafd88 --- /dev/null +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/DistributionSettings.tsx @@ -0,0 +1,743 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { Input, Button, Switch } from "antd"; +import { Toast, SpinLoading } from "antd-mobile"; +import { + SearchOutlined, + DeleteOutlined, + QrcodeOutlined, +} from "@ant-design/icons"; +import { Checkbox, Popup } from "antd-mobile"; +import styles from "./base.module.scss"; +import { fetchChannelList } from "@/pages/mobile/workspace/distribution-management/api"; +import Layout from "@/components/Layout/Layout"; +import PopupHeader from "@/components/PopuLayout/header"; +import PopupFooter from "@/components/PopuLayout/footer"; +import request from "@/api/request"; + +interface DistributionSettingsProps { + formData: any; + onChange: (data: any) => void; + planId?: string; // 计划ID,用于生成二维码 +} + +const DistributionSettings: React.FC = ({ + formData, + onChange, + planId, +}) => { + // 分销相关状态 + const [distributionEnabled, setDistributionEnabled] = useState( + formData.distributionEnabled ?? false, + ); + const [channelModalVisible, setChannelModalVisible] = useState(false); + const [channelLoading, setChannelLoading] = useState(false); + const [channelList, setChannelList] = useState([]); + const [tempSelectedChannelIds, setTempSelectedChannelIds] = useState< + Array + >(formData.distributionChannelIds || []); + const [channelSearchQuery, setChannelSearchQuery] = useState(""); + const [channelCurrentPage, setChannelCurrentPage] = useState(1); + const [channelTotal, setChannelTotal] = useState(0); + const [customerReward, setCustomerReward] = useState( + formData.distributionCustomerReward + ); + const [addReward, setAddReward] = useState( + formData.distributionAddReward + ); + + // 二维码相关状态 + const [qrCodeMap, setQrCodeMap] = useState>({}); + const [showQrDialog, setShowQrDialog] = useState(false); + const [currentQrChannel, setCurrentQrChannel] = useState<{ + id: string | number; + name: string; + code?: string; + } | null>(null); + + const PAGE_SIZE = 20; + + // 生成渠道二维码 + const generateChannelQRCode = async (channelId: string | number, channelCode?: string) => { + // 如果已经有二维码,直接返回 + if (qrCodeMap[channelId]?.qrCode) { + return; + } + + // 设置加载状态 + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { ...prev[channelId], loading: true }, + })); + + try { + // 参考列表生成的参数,使用计划ID和渠道ID/code生成二维码 + // 如果是在新建状态(没有planId),使用渠道code;如果有planId,使用planId和channelId + const params: any = {}; + if (planId) { + params.taskId = planId; + params.channelId = channelId; + } else if (channelCode) { + params.channelCode = channelCode; + } + + // 调用API生成二维码,参考列表中的实现 + const response = await request( + `/v1/plan/getWxMinAppCode`, + params, + "GET" + ); + + if (response && response.qrCode) { + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { + qrCode: response.qrCode, + url: response.url || "", + loading: false, + }, + })); + } else { + throw new Error("二维码生成失败"); + } + } catch (error: any) { + Toast.show({ + content: error.message || "生成二维码失败", + position: "top", + }); + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { ...prev[channelId], loading: false }, + })); + } + }; + + // 显示二维码弹窗 + const handleShowQRCode = async (channel: { id: string | number; name: string; code?: string }) => { + setCurrentQrChannel(channel); + setShowQrDialog(true); + + // 如果还没有生成二维码,则生成 + if (!qrCodeMap[channel.id]?.qrCode && !qrCodeMap[channel.id]?.loading) { + await generateChannelQRCode(channel.id, channel.code); + } + }; + + // 同步分销相关的外部表单数据到本地状态 + useEffect(() => { + setDistributionEnabled(formData.distributionEnabled ?? false); + setTempSelectedChannelIds(formData.distributionChannelIds || []); + setCustomerReward(formData.distributionCustomerReward); + setAddReward(formData.distributionAddReward); + }, [ + formData.distributionEnabled, + formData.distributionChannelIds, + formData.distributionCustomerReward, + formData.distributionAddReward, + ]); + + // 加载分销渠道列表,支持keyword和分页,强制只获取启用的渠道 + const loadDistributionChannels = useCallback( + async (keyword: string = "", page: number = 1) => { + setChannelLoading(true); + try { + const res = await fetchChannelList({ + page, + limit: PAGE_SIZE, + keyword: keyword.trim() || undefined, + status: "enabled", // 强制只获取启用的渠道 + }); + setChannelList(res.list || []); + setChannelTotal(res.total || 0); + } catch (error: any) { + // 错误处理 + } finally { + setChannelLoading(false); + } + }, + [] + ); + + const handleToggleDistribution = (value: boolean) => { + setDistributionEnabled(value); + // 关闭时清空已选渠道和奖励金额 + if (!value) { + setTempSelectedChannelIds([]); + setCustomerReward(undefined); + setAddReward(undefined); + onChange({ + ...formData, + distributionEnabled: false, + distributionChannelIds: [], + distributionChannelsOptions: [], + distributionCustomerReward: undefined, + distributionAddReward: undefined, + }); + } else { + onChange({ + ...formData, + distributionEnabled: true, + }); + } + }; + + // 打开弹窗时获取第一页 + useEffect(() => { + if (channelModalVisible) { + setChannelSearchQuery(""); + setChannelCurrentPage(1); + // 复制一份已选渠道到临时变量 + setTempSelectedChannelIds(formData.distributionChannelIds || []); + loadDistributionChannels("", 1); + } + }, [channelModalVisible, loadDistributionChannels, formData.distributionChannelIds]); + + // 搜索防抖 + useEffect(() => { + if (!channelModalVisible) return; + const timer = setTimeout(() => { + setChannelCurrentPage(1); + loadDistributionChannels(channelSearchQuery, 1); + }, 500); + return () => clearTimeout(timer); + }, [channelSearchQuery, channelModalVisible, loadDistributionChannels]); + + // 翻页时重新请求 + useEffect(() => { + if (!channelModalVisible) return; + loadDistributionChannels(channelSearchQuery, channelCurrentPage); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [channelCurrentPage]); + + const handleOpenChannelModal = () => { + setChannelModalVisible(true); + }; + + const handleChannelToggle = (channel: any) => { + const id = channel.id; + setTempSelectedChannelIds(prev => + prev.includes(id) ? prev.filter(v => v !== id) : [...prev, id], + ); + }; + + // 直接使用从API返回的渠道列表(API已过滤为只返回启用的) + const filteredChannels = channelList; + + const channelTotalPages = Math.max(1, Math.ceil(channelTotal / PAGE_SIZE)); + + // 全选当前页 + const handleSelectAllCurrentPage = (checked: boolean) => { + if (checked) { + // 全选:添加当前页面所有未选中的渠道 + const currentPageChannels = filteredChannels.filter( + (channel: any) => !tempSelectedChannelIds.includes(channel.id), + ); + setTempSelectedChannelIds(prev => [ + ...prev, + ...currentPageChannels.map((c: any) => c.id), + ]); + } else { + // 取消全选:移除当前页面的所有渠道 + const currentPageChannelIds = filteredChannels.map((c: any) => c.id); + setTempSelectedChannelIds(prev => + prev.filter(id => !currentPageChannelIds.includes(id)), + ); + } + }; + + // 检查当前页是否全选 + const isCurrentPageAllSelected = + filteredChannels.length > 0 && + filteredChannels.every((channel: any) => + tempSelectedChannelIds.includes(channel.id), + ); + + const handleConfirmChannels = () => { + const selectedOptions = + channelList + .filter(c => tempSelectedChannelIds.includes(c.id)) + .map(c => ({ + id: c.id, + name: c.name, + code: c.code, + })) || []; + + onChange({ + ...formData, + distributionEnabled: true, + distributionChannelIds: tempSelectedChannelIds, + distributionChannelsOptions: selectedOptions, + }); + setDistributionEnabled(true); + setChannelModalVisible(false); + }; + + const handleCancelChannels = () => { + setChannelModalVisible(false); + // 取消时恢复为表单中的已有值 + setTempSelectedChannelIds(formData.distributionChannelIds || []); + }; + + // 获取显示文本(参考设备选择) + const getChannelDisplayText = () => { + const selectedChannels = formData.distributionChannelsOptions || []; + if (selectedChannels.length === 0) return ""; + return `已选择 ${selectedChannels.length} 个渠道`; + }; + + // 删除已选渠道 + const handleRemoveChannel = (id: string | number) => { + const newChannelIds = (formData.distributionChannelIds || []).filter( + (cid: string | number) => cid !== id + ); + const newChannelOptions = (formData.distributionChannelsOptions || []).filter( + (item: { id: string | number; name: string }) => item.id !== id + ); + onChange({ + ...formData, + distributionChannelIds: newChannelIds, + distributionChannelsOptions: newChannelOptions, + }); + }; + + // 清除所有已选渠道 + const handleClearAllChannels = () => { + onChange({ + ...formData, + distributionChannelIds: [], + distributionChannelsOptions: [], + }); + }; + + return ( +
+ {/* 分销设置 */} +
+
+
+
分销设置
+
+ 开启后,可将当前场景的获客用户同步到指定分销渠道 +
+
+ +
+ + {distributionEnabled && ( + <> + {/* 输入框 - 参考设备选择样式 */} +
+ } + allowClear + onClear={handleClearAllChannels} + size="large" + readOnly + style={{ cursor: "pointer" }} + /> +
+ {/* 已选渠道列表 - 参考设备选择样式 */} + {formData.distributionChannelsOptions && + formData.distributionChannelsOptions.length > 0 ? ( +
+ {formData.distributionChannelsOptions.map( + (item: { id: string | number; name: string; code?: string }) => ( +
+ {/* 渠道图标 */} +
+ + {(item.name || "渠")[0]} + +
+ +
+
+ {item.name} +
+ {item.code && ( +
+ 编码: {item.code} +
+ )} +
+
+
+
+ ), + )} +
+ ) : null} + {/* 奖励金额设置 */} +
+
获客奖励金额(元)
+ { + const value = e.target.value ? Number(e.target.value) : undefined; + setCustomerReward(value); + onChange({ + ...formData, + distributionCustomerReward: value, + }); + }} + min={0} + step={0.01} + style={{ marginBottom: 12 }} + /> +
添加奖励金额(元)
+ { + const value = e.target.value ? Number(e.target.value) : undefined; + setAddReward(value); + onChange({ + ...formData, + distributionAddReward: value, + }); + }} + min={0} + step={0.01} + /> +
+ + )} +
+ + {/* 分销渠道选择弹框 - 参考设备选择样式 */} + + loadDistributionChannels(channelSearchQuery, channelCurrentPage)} + showTabs={false} + /> + } + footer={ + + } + > +
+ {channelLoading && channelList.length === 0 ? ( +
+
加载中...
+
+ ) : filteredChannels.length === 0 ? ( +
+
+ 暂无分销渠道,请先在「分销管理」中创建渠道 +
+
+ ) : ( +
+ {filteredChannels.map((channel: any) => ( +
+ {/* 顶部行:选择框和编码 */} +
+
+ handleChannelToggle(channel)} + className={styles["channelCheckbox"]} + /> +
+ + 编码: {channel.code} + +
+ + {/* 主要内容区域:渠道信息 */} +
+ {/* 渠道信息 */} +
+
+ + {channel.name} + +
+ {channel.status === "enabled" ? "启用" : "禁用"} +
+
+
+ {channel.phone && ( +
+ 手机号: + + {channel.phone} + +
+ )} + {channel.wechatId && ( +
+ 微信号: + + {channel.wechatId} + +
+ )} +
+
+
+
+ ))} +
+ )} +
+
+
+ + {/* 二维码弹窗 - 参考列表中的实现 */} + setShowQrDialog(false)} + position="bottom" + > +
+
+

+ {currentQrChannel?.name || "渠道"}二维码 +

+ +
+
+ {currentQrChannel && ( + <> + {qrCodeMap[currentQrChannel.id]?.loading ? ( +
+ +
生成二维码中...
+
+ ) : qrCodeMap[currentQrChannel.id]?.qrCode ? ( + <> + 渠道二维码 + {qrCodeMap[currentQrChannel.id].url && ( +
+
+ 链接地址 +
+
+ {qrCodeMap[currentQrChannel.id].url} +
+
+ )} + + ) : ( +
+ +
二维码生成失败
+ +
+ )} + + )} +
+
+
+
+ ); +}; + +export default DistributionSettings; diff --git a/Server/application/cunkebao/controller/plan/PlanSceneV1Controller.php b/Server/application/cunkebao/controller/plan/PlanSceneV1Controller.php index 75d1d01e..80d9e3a3 100644 --- a/Server/application/cunkebao/controller/plan/PlanSceneV1Controller.php +++ b/Server/application/cunkebao/controller/plan/PlanSceneV1Controller.php @@ -441,6 +441,7 @@ class PlanSceneV1Controller extends BaseController { $params = $this->request->param(); $taskId = isset($params['taskId']) ? intval($params['taskId']) : 0; + $channelId = isset($params['channelId']) ? intval($params['channelId']) : 0; if($taskId <= 0) { return ResponseHelper::error('任务ID或场景ID不能为空', 400); @@ -451,8 +452,24 @@ class PlanSceneV1Controller extends BaseController return ResponseHelper::error('任务不存在', 400); } + // 如果提供了channelId,验证渠道是否存在且有效 + if ($channelId > 0) { + $channel = Db::name('distribution_channel') + ->where([ + ['id', '=', $channelId], + ['companyId', '=', $task['companyId']], + ['status', '=', 'enabled'], + ['deleteTime', '=', 0] + ]) + ->find(); + + if (!$channel) { + return ResponseHelper::error('分销渠道不存在或已被禁用', 400); + } + } + $posterWeChatMiniProgram = new PosterWeChatMiniProgram(); - $result = $posterWeChatMiniProgram->generateMiniProgramCodeWithScene($taskId); + $result = $posterWeChatMiniProgram->generateMiniProgramCodeWithScene($taskId, $channelId); $result = json_decode($result, true); if ($result['code'] == 200){ return ResponseHelper::success($result['data'], '获取小程序码成功');