diff --git a/Cunkebao/src/components/GroupSelection/index.tsx b/Cunkebao/src/components/GroupSelection/index.tsx index e698a799..e66bf375 100644 --- a/Cunkebao/src/components/GroupSelection/index.tsx +++ b/Cunkebao/src/components/GroupSelection/index.tsx @@ -89,7 +89,7 @@ export default function GroupSelection({
归属:{group.nickName}
)} {!group.nickName && group.chatroomId && ( -
{group.chatroomId}
+
{group.chatroomId}
)} {!readonly && ( diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/list/data.ts b/Cunkebao/src/pages/mobile/scenarios/plan/list/data.ts index 77e1df19..a1f71794 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/list/data.ts +++ b/Cunkebao/src/pages/mobile/scenarios/plan/list/data.ts @@ -8,6 +8,7 @@ export interface Task { total_customers?: number; today_customers?: number; lastUpdated?: string; + planType?: number; // 0-全局计划, 1-独立计划 stats?: { devices?: number; acquired?: number; diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/list/index.module.scss b/Cunkebao/src/pages/mobile/scenarios/plan/list/index.module.scss index d5fc2004..5935bbe6 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/list/index.module.scss +++ b/Cunkebao/src/pages/mobile/scenarios/plan/list/index.module.scss @@ -2,6 +2,73 @@ padding: 0 16px; } +.info-box { + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 12px; + padding: 14px 16px; + margin-bottom: 20px; + display: flex; + align-items: flex-start; + gap: 12px; +} + +.info-icon { + color: #2563eb; + font-size: 20px; + margin-top: 2px; + flex-shrink: 0; +} + +.info-text { + font-size: 13px; + color: #1e40af; + line-height: 1.5; + margin: 0; + font-weight: 500; +} + +.section { + margin-bottom: 24px; +} + +.section-title { + font-size: 15px; + font-weight: 700; + margin-bottom: 12px; + padding-left: 4px; + display: flex; + align-items: center; + gap: 8px; + color: #1e293b; +} + +.section-dot { + width: 4px; + height: 14px; + background: #2563eb; + border-radius: 2px; + box-shadow: 0 0 8px rgba(37, 99, 235, 0.4); +} + +.section-title-independent { + .section-dot { + background: #fb923c; + box-shadow: 0 0 8px rgba(251, 146, 60, 0.4); + } +} + +.section-dot-independent { + background: #fb923c; + box-shadow: 0 0 8px rgba(251, 146, 60, 0.4); +} + +.plan-list-group { + display: flex; + flex-direction: column; + gap: 12px; +} + .loading { display: flex; flex-direction: column; diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/list/index.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/list/index.tsx index e658e26f..4ecd56e6 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/list/index.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/list/index.tsx @@ -101,17 +101,23 @@ const ScenarioList: React.FC = () => { }); if (response && response.list) { + // 处理 planType 字段 + const processedList = response.list.map((task: any) => ({ + ...task, + planType: task.planType ?? task.config?.planType ?? 1, // 默认独立计划 + })); + if (isLoadMore) { // 加载更多时,追加数据 - setTasks(prev => [...prev, ...response.list]); + setTasks(prev => [...prev, ...processedList]); } else { // 首次加载或刷新时,替换数据 - setTasks(response.list); + setTasks(processedList); } // 更新分页信息 setTotal(response.total || 0); - setHasMore(response.list.length === limit); + setHasMore(processedList.length === limit); setCurrentPage(page); } } catch (error) { @@ -313,6 +319,10 @@ const ScenarioList: React.FC = () => { task.name.toLowerCase().includes(searchTerm.toLowerCase()), ); + // 分隔全局计划和独立计划 + const globalPlans = filteredTasks.filter(task => task.planType === 0); + const independentPlans = filteredTasks.filter(task => task.planType === 1 || !task.planType); + // 生成操作菜单 const getActionMenu = (task: Task) => [ { @@ -409,6 +419,16 @@ const ScenarioList: React.FC = () => { loading={loading} >
+ {/* 全局计划提示 */} + {globalPlans.length > 0 && ( +
+ +

+ 全局获客计划将应用于所有设备,包含新添加的设备,请确保设置合理的规则。 +

+
+ )} + {/* 计划列表 */}
{filteredTasks.length === 0 ? ( @@ -428,7 +448,119 @@ const ScenarioList: React.FC = () => {
) : ( <> - {filteredTasks.map(task => ( + {/* 全局获客计划 */} + {globalPlans.length > 0 && ( +
+

+
+ 全局获客计划 +

+
+ {globalPlans.map(task => ( + + {/* 头部:标题、状态和操作菜单 */} +
+
{task.name}
+
+ + {getStatusText(task.status)} + + +
+
+ + {/* 统计数据网格 */} +
+
{ + e.stopPropagation(); // 阻止事件冒泡,避免触发卡片点击 + handleShowDeviceList(task); + }} + > +
设备数
+
+ {deviceCount(task)} +
+
+
{ + e.stopPropagation(); // 阻止事件冒泡,避免触发卡片点击 + handleShowAccountList(task); + }} + > +
已获客
+
+ {task?.acquiredCount || 0} +
+
+
{ + e.stopPropagation(); // 阻止事件冒泡,避免触发卡片点击 + handleShowOreadyAdd(task); + }} + > +
已添加
+
+ {task.passCount || 0} +
+
+
{ + e.stopPropagation(); // 阻止事件冒泡,避免触发卡片点击 + handleShowPoolList(task); + }} + > +
通过率
+
+ {task.passRate}% +
+
+
+ + {/* 底部:上次执行时间 */} +
+
+ + 上次执行: {task.lastUpdated || "--"} +
+
+ { + setShowActionMenu(null); + handleShowQrCode(task.id); + }} + /> +
+
+
+ ))} +
+
+ )} + + {/* 独立获客计划 */} + {independentPlans.length > 0 && ( +
+

+
+ 独立获客计划 +

+
+ {independentPlans.map(task => ( {/* 头部:标题、状态和操作菜单 */}
@@ -520,6 +652,10 @@ const ScenarioList: React.FC = () => {
))} +
+
+ )} + {/* 上拉加载更多 */} ); case 2: @@ -289,16 +290,6 @@ export default function NewPlan() { ); case 3: - return ( - - ); - case 4: - return ; - case 5: 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 07137f67..8afab054 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx @@ -1,5 +1,5 @@ -import React, { useState, useEffect, useRef } from "react"; -import { Input, Button, Tag, Switch, Spin, message, Modal } from "antd"; +import React, { useState, useEffect, useRef, useCallback } from "react"; +import { Input, Button, Tag, Switch, Spin, message, Modal, Radio } from "antd"; import { PlusOutlined, EyeOutlined, @@ -7,13 +7,25 @@ import { DownloadOutlined, SearchOutlined, DeleteOutlined, + QrcodeOutlined, + CopyOutlined, } from "@ant-design/icons"; +import { Toast, SpinLoading } from "antd-mobile"; +import { Checkbox, Popup } from "antd-mobile"; import { uploadFile } from "@/api/common"; import styles from "./base.module.scss"; import { posterTemplates } from "./base.data"; import GroupSelection from "@/components/GroupSelection"; import FileUpload from "@/components/Upload/FileUpload"; +import FriendSelection from "@/components/FriendSelection"; import { GroupSelectionItem } from "@/components/GroupSelection/data"; +import { FriendSelectionItem } from "@/components/FriendSelection/data"; +import { useUserStore } from "@/store/module/user"; +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 BasicSettingsProps { isEdit: boolean; @@ -21,6 +33,7 @@ interface BasicSettingsProps { onChange: (data: any) => void; sceneList: any[]; sceneLoading: boolean; + planId?: string; // 计划ID,用于生成渠道二维码 } interface Material { @@ -45,13 +58,51 @@ const BasicSettings: React.FC = ({ onChange, sceneList, sceneLoading, + planId, }) => { + const { user } = useUserStore(); + const isAdmin = user?.isAdmin === 1; // 判断是否是管理员 const [isPreviewOpen, setIsPreviewOpen] = useState(false); const [materials] = useState(generatePosterMaterials()); const [selectedMaterials, setSelectedMaterials] = useState( formData.posters?.length > 0 ? formData.posters : [], ); + // 分销相关状态 + 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 [customTagInput, setCustomTagInput] = useState(""); const [customTagsOptions, setCustomTagsOptions] = useState( @@ -240,6 +291,302 @@ const BasicSettings: React.FC = ({ }); }; + // ==================== 渠道设置相关函数 ==================== + // 生成H5链接 + const generateH5Url = (channelId: string | number, channelCode?: string): string => { + if (planId) { + return `https://h5.ckb.quwanzhi.com/#/pages/form/input2?id=${planId}&channelId=${channelId}`; + } else if (channelCode) { + return `https://h5.ckb.quwanzhi.com/#/pages/form/input2?channelCode=${channelCode}`; + } + return ""; + }; + + // 生成渠道二维码 + const generateChannelQRCode = async (channelId: string | number, channelCode?: string) => { + const h5Url = generateH5Url(channelId, channelCode); + + if (qrCodeMap[channelId]) { + if (!qrCodeMap[channelId].url) { + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { ...prev[channelId], url: h5Url }, + })); + } + if (qrCodeMap[channelId].qrCode) { + return; + } + } else { + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { + qrCode: "", + url: h5Url, + loading: true, + }, + })); + } + + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { ...prev[channelId], loading: true }, + })); + + try { + const params: any = {}; + if (planId) { + params.taskId = planId; + params.channelId = channelId; + } else if (channelCode) { + params.channelCode = channelCode; + } + + const response = await request( + `/v1/plan/getWxMinAppCode`, + params, + "GET" + ); + + if (response && typeof response === 'string' && response.startsWith('data:image')) { + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { + qrCode: response, + url: h5Url, + loading: false, + }, + })); + } else { + throw new Error("二维码生成失败"); + } + } catch (error: any) { + Toast.show({ + content: error.message || "生成二维码失败", + position: "top", + }); + setQrCodeMap(prev => ({ + ...prev, + [channelId]: { + ...prev[channelId], + qrCode: "", + url: h5Url, + 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, + ]); + + // 加载分销渠道列表 + 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], + ); + }; + + 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: [], + }); + }; + + // ==================== 拉群设置相关函数 ==================== + const handleToggleGroupInvite = (value: boolean) => { + onChange({ + ...formData, + groupInviteEnabled: value, + }); + }; + + const handleGroupNameChange = (e: React.ChangeEvent) => { + onChange({ + ...formData, + groupName: e.target.value, + }); + }; + + const handleFixedMembersSelect = (friends: FriendSelectionItem[]) => { + onChange({ + ...formData, + fixedGroupMembers: friends, + }); + }; + return (
@@ -289,6 +636,22 @@ const BasicSettings: React.FC = ({
)}
+ {/* 计划类型选择 - 仅管理员可见 */} + {isAdmin && ( + <> +
计划类型
+
+ onChange({ ...formData, planType: e.target.value })} + style={{ display: "flex", gap: 24 }} + > + 全局计划 + 独立计划 + +
+ + )} {/* 计划名称输入区 */}
计划名称
@@ -579,6 +942,278 @@ 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} + /> +
+ + )} +
+ + {/* 拉群设置 */} +
+
+
+
+ 拉群设置 +
+
+ 开启后,可配置群名称和固定群成员,将用户引导到指定微信群 +
+
+ +
+ + {formData.groupInviteEnabled && ( +
+ + {/* 固定成员选择 */} +
+
+ 固定群成员 +
+ +
+
+ )} +
+
是否启用 = ({ />
+ {/* 分销渠道选择弹框 */} + + 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 ? ( + 渠道二维码 + ) : ( +
+ +
二维码生成失败
+ +
+ )} + + {/* H5链接展示 */} + {qrCodeMap[currentQrChannel.id]?.url && ( +
+
+ H5链接 +
+
+ + +
+
+ )} + + )} + + )} +
+
+
+ ); }; diff --git a/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.module.scss b/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.module.scss index d99f4a39..8cfb435e 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.module.scss +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.module.scss @@ -1,5 +1,11 @@ +// 页面容器 +.auto-like-page { + padding: 0 16px 24px; + background: #f8fafc; + min-height: 100vh; +} + .task-list { - padding: 0 16px; display: flex; flex-direction: column; gap: 16px; @@ -252,6 +258,50 @@ color: #999; } +// 计划分组(全局 / 独立) +.info-box { + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 12px; + padding: 12px 14px; + margin-bottom: 16px; + font-size: 13px; + color: #1e40af; +} + +.section { + margin-bottom: 20px; +} + +.section-title { + font-size: 15px; + font-weight: 600; + margin-bottom: 8px; + display: flex; + align-items: center; + gap: 6px; + color: #1e293b; +} + +.section-dot { + width: 4px; + height: 14px; + border-radius: 2px; + background: #2563eb; +} + +.section-title-independent { + .section-dot { + background: #fb923c; + } +} + +.plan-list-group { + display: flex; + flex-direction: column; + gap: 12px; +} + // 移动端适配 @media (max-width: 768px) { .task-info { @@ -272,7 +322,7 @@ padding: 12px 16px; } - .task-list { - padding: 0 12px; + .auto-like-page { + padding: 0 12px 16px; } } diff --git a/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.tsx b/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.tsx index 22ff25dc..f91de552 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/list/index.tsx @@ -118,7 +118,7 @@ const AutoLike: React.FC = () => { const Res: any = await fetchAutoLikeTasks(); // 数据在 data.list 中 const taskList = Res?.data?.list || Res?.list || []; - const mappedTasks = taskList.map((task: any) => { + const mappedTasks: LikeTask[] = taskList.map((task: any) => { const config = task.config || {}; const friends = config.friends || []; const devices = config.devices || []; @@ -142,6 +142,7 @@ const AutoLike: React.FC = () => { updateTime: task.updateTime || "", todayLikeCount: config.todayLikeCount || 0, totalLikeCount: config.totalLikeCount || 0, + planType: config.planType ?? task.planType ?? 1, // 保留原始数据 config: config, devices: devices, @@ -243,73 +244,18 @@ const AutoLike: React.FC = () => { task.name.toLowerCase().includes(searchTerm.toLowerCase()), ); - return ( - - navigate("/workspace")} - right={ - - } - /> + // 按计划类型分组 + const globalTasks = filteredTasks.filter(t => t.planType === 0); + const independentTasks = filteredTasks.filter(t => t.planType !== 0); - {/* 搜索栏 */} -
-
- setSearchTerm(e.target.value)} - prefix={} - allowClear - size="large" - /> -
- -
- - } - > -
- {/* 任务列表 */} -
- {loading ? ( -
- -
加载中...
-
- ) : filteredTasks.length === 0 ? ( -
-
- -
-
暂无自动点赞任务
-
- 点击右上角按钮创建新任务 -
-
- ) : ( - filteredTasks.map(task => ( + const renderTaskCard = (task: LikeTask) => (

{task.name}

{Number(task.status) === 1 ? "进行中" : "已暂停"} @@ -320,9 +266,7 @@ const AutoLike: React.FC = () => { - toggleTaskStatus(task.id, Number(task.status)) - } + onChange={() => toggleTaskStatus(task.id, Number(task.status))} /> @@ -339,15 +283,11 @@ const AutoLike: React.FC = () => {
执行设备: - - {task.deviceCount} 个 - + {task.deviceCount} 个
目标人群: - - {task.targetGroup} - + {task.targetGroup}
@@ -387,10 +327,109 @@ const AutoLike: React.FC = () => {
- )) - )} + ); + + let content: React.ReactNode; + if (loading) { + content = ( +
+
+ +
加载中...
+ ); + } else if (filteredTasks.length === 0) { + content = ( +
+
+
+ +
+
暂无自动点赞任务
+
+ 点击右上角按钮创建新任务 +
+
+
+ ); + } else { + content = ( + <> + {globalTasks.length > 0 && ( +
+ 全局计划将应用于所有设备(包括新添加的设备),请谨慎配置点赞频率和数量,避免账号风险。 +
+ )} + + {globalTasks.length > 0 && ( +
+

+ + 全局自动点赞计划 +

+
+ {globalTasks.map(renderTaskCard)} +
+
+ )} + + {independentTasks.length > 0 && ( +
+

+ + 独立自动点赞计划 +

+
+ {independentTasks.map(renderTaskCard)} +
+
+ )} + + ); + } + + return ( + + navigate("/workspace")} + right={ + + } + /> + + {/* 搜索栏 */} +
+
+ setSearchTerm(e.target.value)} + prefix={} + allowClear + size="large" + /> +
+ +
+ + } + > +
{content}
); }; diff --git a/Cunkebao/src/pages/mobile/workspace/auto-like/new/data.ts b/Cunkebao/src/pages/mobile/workspace/auto-like/new/data.ts index 1b47baee..f8cea3c4 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/new/data.ts +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/new/data.ts @@ -69,6 +69,8 @@ export interface LikeTask { todayLikeCount: number; totalLikeCount: number; updateTime: string; + // 计划类型:0-全局计划,1-独立计划 + planType?: number; } // 创建任务数据 @@ -81,12 +83,15 @@ export interface CreateLikeTaskData { contentTypes: ContentType[]; deviceGroups: number[]; deviceGroupsOptions: DeviceSelectionItem[]; - friendsGroups: number[]; - friendsGroupsOptions: FriendSelectionItem[]; + // 实际使用的好友字段(兼容旧字段) + wechatFriends?: number[]; + wechatFriendsOptions?: FriendSelectionItem[]; friendMaxLikes: number; friendTags?: string; enableFriendTags: boolean; targetTags: string[]; + // 计划类型:0-全局计划,1-独立计划 + planType?: number; [key: string]: any; } diff --git a/Cunkebao/src/pages/mobile/workspace/auto-like/new/index.tsx b/Cunkebao/src/pages/mobile/workspace/auto-like/new/index.tsx index b02e5e61..0a94706c 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/new/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/new/index.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { PlusOutlined, MinusOutlined } from "@ant-design/icons"; -import { Button, Input, Switch, Spin, message } from "antd"; +import { Button, Input, Switch, Spin, message, Radio } from "antd"; import Layout from "@/components/Layout/Layout"; import DeviceSelection from "@/components/DeviceSelection"; import FriendSelection from "@/components/FriendSelection"; @@ -13,6 +13,7 @@ import { fetchAutoLikeTaskDetail, } from "./api"; import { CreateLikeTaskData, ContentType } from "./data"; +import { useUserStore } from "@/store/module/user"; import style from "./new.module.scss"; const contentTypeLabels: Record = { @@ -32,12 +33,15 @@ const NewAutoLike: React.FC = () => { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); const isEditMode = !!id; + const { user } = useUserStore(); + const isAdmin = user?.isAdmin === 1; const [currentStep, setCurrentStep] = useState(1); const [isSubmitting, setIsSubmitting] = useState(false); const [isLoading, setIsLoading] = useState(isEditMode); const [autoEnabled, setAutoEnabled] = useState(false); const [selectAllFriends, setSelectAllFriends] = useState(false); const [formData, setFormData] = useState({ + planType: 1, // 默认独立计划 name: "", interval: 5, maxLikes: 200, @@ -67,6 +71,7 @@ const NewAutoLike: React.FC = () => { if (taskDetail) { const config = (taskDetail as any).config || taskDetail; setFormData({ + planType: config.planType ?? (taskDetail as any).planType ?? 1, name: taskDetail.name || "", interval: config.likeInterval || config.interval || 5, maxLikes: config.maxLikesPerDay || config.maxLikes || 200, @@ -184,7 +189,22 @@ const NewAutoLike: React.FC = () => { // 步骤1:基础设置 const renderBasicSettings = () => ( -
+
+ {/* 计划类型和任务名称 */} +
+ {isAdmin && ( +
+
计划类型
+ handleUpdateFormData({ planType: e.target.value })} + className={style.radioGroup} + > + 全局计划 + 独立计划 + +
+ )}
任务名称
{ className={style.input} />
+
+ + {/* 点赞间隔 */} +
点赞间隔
@@ -231,6 +255,10 @@ const NewAutoLike: React.FC = () => {
设置两次点赞之间的最小时间间隔
+
+ + {/* 每日最大点赞数 */} +
每日最大点赞数
@@ -268,6 +296,10 @@ const NewAutoLike: React.FC = () => {
设置每天最多点赞的次数
+
+ + {/* 点赞时间范围 */} +
点赞时间范围
@@ -287,6 +319,10 @@ const NewAutoLike: React.FC = () => {
设置每天可以点赞的时间段
+
+ + {/* 点赞内容类型 */} +
点赞内容类型
@@ -311,6 +347,10 @@ const NewAutoLike: React.FC = () => {
选择要点赞的内容类型
+
+ + {/* 好友标签和自动开启 */} +
启用好友标签 @@ -323,7 +363,7 @@ const NewAutoLike: React.FC = () => { />
{formData.enableFriendTags && ( -
+
{ />
+
+ @@ -389,15 +434,18 @@ const NewAutoLike: React.FC = () => { className={style.nextBtn} size="large" disabled={formData.deviceGroups.length === 0} + style={{ flex: 1 }} > 下一步 +
); // 步骤3:好友设置 const renderFriendSettings = () => ( -
+
+
选择好友
@@ -433,11 +481,13 @@ const NewAutoLike: React.FC = () => { /> )}
+
+
@@ -451,9 +501,11 @@ const NewAutoLike: React.FC = () => { !selectAllFriends && (!formData.wechatFriends || formData.wechatFriends.length === 0) } + style={{ flex: 1 }} > {isEditMode ? "更新任务" : "创建任务"} +
); diff --git a/Cunkebao/src/pages/mobile/workspace/auto-like/new/new.module.scss b/Cunkebao/src/pages/mobile/workspace/auto-like/new/new.module.scss index 8375cac9..6ae11d80 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/new/new.module.scss +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/new/new.module.scss @@ -1,10 +1,39 @@ .formBg { - background: #f8f6f3; + background: #f8fafc; min-height: 100vh; padding: 0 0 80px 0; position: relative; } +.container { + padding: 16px; + background: #f8fafc; + min-height: 100vh; + padding-bottom: 100px; + box-sizing: border-box; + width: 100%; + overflow-x: hidden; + + @media (max-width: 375px) { + padding: 12px; + } +} + +.card { + background: #fff; + border-radius: 12px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + padding: 16px; + margin-bottom: 16px; + box-sizing: border-box; + width: 100%; + overflow: hidden; + + @media (max-width: 375px) { + padding: 12px; + } +} + .basicSection { background: none; border-radius: 0; @@ -26,10 +55,31 @@ margin-bottom: 10px; } +.radioGroup { + display: flex; + gap: 24px; +} + .input { + width: 100%; height: 44px; + padding: 10px 12px; border-radius: 8px; + border: 1px solid #e2e8f0; + background: #f8fafc; font-size: 15px; + outline: none; + transition: all 0.2s; + box-sizing: border-box; + + &:focus { + border-color: #3b82f6; + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); + } + + &::placeholder { + color: #cbd5e1; + } } .timeRow { diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts b/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts index d9abded4..c310818a 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts @@ -56,7 +56,7 @@ export function fetchImportRecords( keyword?: string, ): Promise> { return request( - "/v1/workbench/import-records", + "/v1/workbench/import-contact", { workbenchId, page, diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.module.scss b/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.module.scss index bdc76bee..461a7f10 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.module.scss +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.module.scss @@ -1,11 +1,58 @@ +.formBg { + background: #f8fafc; + min-height: 100vh; + padding-bottom: 100px; +} + .basicSection { - background: none; - border-radius: 0; - box-shadow: none; - padding: 24px 16px 0 16px; + padding: 16px; + background: #f8fafc; + min-height: 100vh; + padding-bottom: 100px; + box-sizing: border-box; width: 100%; - max-width: 600px; - margin: 0 auto; + overflow-x: hidden; + + @media (max-width: 375px) { + padding: 12px; + } +} + +.card { + background: #fff; + border-radius: 12px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + padding: 16px; + margin-bottom: 16px; + box-sizing: border-box; + width: 100%; + overflow: hidden; + + @media (max-width: 375px) { + padding: 12px; + } + + // 输入框样式 + :global(.ant-input) { + width: 100%; + padding: 10px 12px; + border-radius: 8px; + border: 1px solid #e2e8f0; + background: #f8fafc; + font-size: 14px; + outline: none; + transition: all 0.2s; + box-sizing: border-box; + + &:focus { + border-color: #3b82f6; + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); + } + + &::placeholder { + color: #cbd5e1; + } + } } .formItem { @@ -20,6 +67,12 @@ display: block; } +.radioGroup { + display: flex; + flex-direction: row; + gap: 24px; +} + .input { height: 44px; border-radius: 8px; diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx b/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx index 001ad6ba..5b7bb2e8 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useCallback } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { PlusOutlined, MinusOutlined } from "@ant-design/icons"; -import { Button, Input, message, TimePicker, Select, Switch } from "antd"; +import { Button, Input, message, TimePicker, Select, Switch, Radio, Card } from "antd"; import NavCommon from "@/components/NavCommon"; import Layout from "@/components/Layout/Layout"; import DeviceSelection from "@/components/DeviceSelection"; @@ -16,14 +16,18 @@ import { PoolSelectionItem } from "@/components/PoolSelection/data"; import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; import style from "./index.module.scss"; import dayjs from "dayjs"; +import { useUserStore } from "@/store/module/user"; const ContactImportForm: React.FC = () => { const navigate = useNavigate(); const { id } = useParams<{ id?: string }>(); const isEdit = !!id; + const { user } = useUserStore(); + const isAdmin = user?.isAdmin === 1; const [loading, setLoading] = useState(false); const [formData, setFormData] = useState({ + planType: 1, // 计划类型:0-全局计划,1-独立计划 name: "", // 任务名称 status: 1, // 是否启用,默认启用 type: 6, // 任务类型,固定为6 @@ -89,6 +93,7 @@ const ContactImportForm: React.FC = () => { endTime: config.endTime ? dayjs(config.endTime, "HH:mm") : null, deviceGroupsOptions, poolGroupsOptions, + planType: config.planType ?? (data as any).planType ?? 1, }); } } catch (error) { @@ -146,6 +151,7 @@ const ContactImportForm: React.FC = () => { remark: formData.remark || null, startTime: formData.startTime?.format("HH:mm") || null, endTime: formData.endTime?.format("HH:mm") || null, + planType: (formData as any).planType ?? 1, }; if (isEdit && id) { @@ -220,158 +226,191 @@ const ContactImportForm: React.FC = () => { >
-
-
任务名称
- handleUpdateFormData({ name: e.target.value })} - className={style.input} - /> -
为此导入任务设置一个名称
-
- -
-
设备选择
- -
选择要分配联系人的设备
-
- -
-
流量池选择
- -
选择要导入的流量池
-
- -
-
分配数量
-
-
-
要分配给设备的联系人数量
-
- -
-
清除现有联系人
- - handleUpdateFormData({ clearContact: checked ? 1 : 0 }) - } - /> -
是否清除设备上现有的联系人
-
- -
-
备注类型
- -
选择联系人备注的格式
-
- - {formData.remarkType === 3 && ( + {/* 计划类型和任务名称 */} + + {isAdmin && ( +
+
计划类型
+ + handleUpdateFormData({ planType: e.target.value }) + } + className={style.radioGroup} + > + 全局计划 + 独立计划 + +
+ )}
-
自定义备注
+
任务名称
handleUpdateFormData({ remark: e.target.value })} + placeholder="请输入任务名称" + value={formData.name} + onChange={e => handleUpdateFormData({ name: e.target.value })} className={style.input} /> -
输入自定义的备注内容
+
为此导入任务设置一个名称
- )} +
-
-
开始时间
- - handleUpdateFormData({ - startTime: time, - }) - } - format="HH:mm" - placeholder="请选择开始时间" - className={style.timePicker} - /> -
设置每天开始导入的时间
-
+ {/* 设备选择 */} + +
+
设备选择
+ +
选择要分配联系人的设备
+
+
-
-
结束时间
- - handleUpdateFormData({ - endTime: time, - }) - } - format="HH:mm" - placeholder="请选择结束时间" - className={style.timePicker} - /> -
设置每天结束导入的时间
-
+ {/* 流量池选择 */} + +
+
流量池选择
+ +
选择要导入的流量池
+
+
-
- 是否启用 - - handleUpdateFormData({ status: check ? 1 : 0 }) - } - /> -
+ {/* 分配数量 */} + +
+
分配数量
+
+
+
要分配给设备的联系人数量
+
+
+ + {/* 清除现有联系人和备注类型 */} + +
+
清除现有联系人
+ + handleUpdateFormData({ clearContact: checked ? 1 : 0 }) + } + /> +
是否清除设备上现有的联系人
+
+
+
备注类型
+ +
选择联系人备注的格式
+
+ {formData.remarkType === 3 && ( +
+
自定义备注
+ handleUpdateFormData({ remark: e.target.value })} + className={style.input} + /> +
输入自定义的备注内容
+
+ )} +
+ + {/* 时间设置 */} + +
+
开始时间
+ + handleUpdateFormData({ + startTime: time, + }) + } + format="HH:mm" + placeholder="请选择开始时间" + className={style.timePicker} + /> +
设置每天开始导入的时间
+
+
+
结束时间
+ + handleUpdateFormData({ + endTime: time, + }) + } + format="HH:mm" + placeholder="请选择结束时间" + className={style.timePicker} + /> +
设置每天结束导入的时间
+
+
+ + {/* 是否启用 */} + +
+ 是否启用 + + handleUpdateFormData({ status: check ? 1 : 0 }) + } + /> +
+
diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/list/api.ts b/Cunkebao/src/pages/mobile/workspace/contact-import/list/api.ts index ad8e91a5..88d3c202 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/list/api.ts +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/list/api.ts @@ -62,7 +62,7 @@ export function fetchImportRecords( keyword?: string, ): Promise> { return request( - "/v1/workbench/import-records", + "/v1/workbench/import-contact", { workbenchId, page, diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.module.scss b/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.module.scss index 082d3233..679c9112 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.module.scss +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.module.scss @@ -46,6 +46,49 @@ gap: 12px; } +.infoBox { + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 12px; + padding: 12px 14px; + margin-bottom: 16px; + font-size: 13px; + color: #1e40af; +} + +.section { + margin-bottom: 20px; +} + +.sectionTitle { + font-size: 15px; + font-weight: 600; + margin-bottom: 8px; + display: flex; + align-items: center; + gap: 6px; + color: #1e293b; +} + +.sectionDot { + width: 4px; + height: 14px; + border-radius: 2px; + background: #2563eb; +} + +.sectionTitleIndependent { + .sectionDot { + background: #fb923c; + } +} + +.planListGroup { + display: flex; + flex-direction: column; + gap: 12px; +} + .loading { display: flex; align-items: center; @@ -115,6 +158,16 @@ line-height: 1.4; } +.planTypeTag { + margin-left: 8px; + padding: 0 8px; + font-size: 11px; + border-radius: 999px; + border: 1px solid #bfdbfe; + color: #1d4ed8; + background: #eff6ff; +} + .taskStatus { font-size: 12px; font-weight: 500; diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.tsx b/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.tsx index ef1e6661..683867b5 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.tsx @@ -97,9 +97,13 @@ const ContactImport: React.FC = () => { setLoading(true); try { const response = await fetchContactImportTasks(); - const data = response?.list || []; - setTasks(data); - setFilteredTasks(data); + const data: ContactImportTask[] = response?.list || []; + const normalized = data.map(task => ({ + ...task, + planType: task.config?.planType ?? (task as any).planType ?? 1, + })); + setTasks(normalized); + setFilteredTasks(normalized); } catch (error) { Toast.show({ content: "获取任务列表失败", @@ -211,6 +215,11 @@ const ContactImport: React.FC = () => { loadTasks(); }, []); + const globalTasks = filteredTasks.filter(task => (task as any).planType === 0); + const independentTasks = filteredTasks.filter( + task => (task as any).planType !== 0, + ); + return ( { } > -
- {/* 任务列表 */} -
- {loading ? ( -
- 加载中... -
- ) : filteredTasks.length === 0 ? ( -
- -
- {searchKeyword ? "未找到相关任务" : "暂无通讯录导入任务"} +
+ {/* 任务列表 */} +
+ {loading ? ( +
+ 加载中...
- {!searchKeyword && ( - - )} -
- ) : ( - filteredTasks.map(task => ( - -
-
-
{task.name}
-
- {getStatusText(task.status)} + ) : filteredTasks.length === 0 ? ( +
+ +
+ {searchKeyword ? "未找到相关任务" : "暂无通讯录导入任务"} +
+ {!searchKeyword && ( + + )} +
+ ) : ( + <> + {globalTasks.length > 0 && ( +
+ 全局通讯录导入计划将作用于所有设备,请谨慎配置导入数量与时间。 +
+ )} + + {globalTasks.length > 0 && ( +
+

+ + 全局通讯录导入计划 +

+
+ {globalTasks.map(task => ( + +
+
+
{task.name}
+
+ {getStatusText(task.status)} +
+
+ handleView(task.id)} + onEdit={() => handleEdit(task.id)} + onCopy={() => handleCopy(task.id)} + onDelete={() => handleDelete(task.id)} + /> +
+
+
+ 备注类型: + + {task.config?.remarkType === 1 ? "自定义备注" : "其他"} + +
+
+ 设备数量: + + {task.config?.devices?.length || 0} + +
+
+ 导入数量: + + {task.config?.num || 0} + +
+
+ 创建时间: + {task.createTime} +
+
+
+ + +
+
+ ))}
-
- handleView(task.id)} - onEdit={() => handleEdit(task.id)} - onCopy={() => handleCopy(task.id)} - onDelete={() => handleDelete(task.id)} - /> -
-
-
- 备注类型: - - {task.config?.remarkType === 1 ? "自定义备注" : "其他"} - -
-
- 设备数量: - - {task.config?.devices?.length || 0} - -
-
- 导入数量: - {task.config?.num || 0} -
-
- 创建时间: - {task.createTime} -
-
-
- - -
- - )) - )} + + )} + + {independentTasks.length > 0 && ( +
+

+ + 独立通讯录导入计划 +

+
+ {independentTasks.map(task => ( + +
+
+
{task.name}
+
+ {getStatusText(task.status)} +
+
+ handleView(task.id)} + onEdit={() => handleEdit(task.id)} + onCopy={() => handleCopy(task.id)} + onDelete={() => handleDelete(task.id)} + /> +
+
+
+ 备注类型: + + {task.config?.remarkType === 1 ? "自定义备注" : "其他"} + +
+
+ 设备数量: + + {task.config?.devices?.length || 0} + +
+
+ 导入数量: + + {task.config?.num || 0} + +
+
+ 创建时间: + {task.createTime} +
+
+
+ + +
+
+ ))} +
+
+ )} + + )} +
-
); }; diff --git a/Cunkebao/src/pages/mobile/workspace/group-create/form/components/BasicSettings.tsx b/Cunkebao/src/pages/mobile/workspace/group-create/form/components/BasicSettings.tsx index cb3e3350..dacf339a 100644 --- a/Cunkebao/src/pages/mobile/workspace/group-create/form/components/BasicSettings.tsx +++ b/Cunkebao/src/pages/mobile/workspace/group-create/form/components/BasicSettings.tsx @@ -9,6 +9,7 @@ import { FriendSelectionItem } from "@/components/FriendSelection/data"; import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; import { GroupCreateFormData } from "../types"; import style from "./BasicSettings.module.scss"; +import { useUserStore } from "@/store/module/user"; interface BasicSettingsProps { formData: GroupCreateFormData; @@ -22,6 +23,8 @@ export interface BasicSettingsRef { const BasicSettings = forwardRef( ({ formData, onChange }, ref) => { + const { user } = useUserStore(); + const isAdmin = user?.isAdmin === 1; const [executorSelectionVisible, setExecutorSelectionVisible] = useState(false); const [groupAdminSelectionVisible, setGroupAdminSelectionVisible] = useState(false); const [fixedWechatIdsSelectionVisible, setFixedWechatIdsSelectionVisible] = useState(false); @@ -200,6 +203,8 @@ const BasicSettings = forwardRef(
{/* 计划类型和计划名称 */}
+ {/* 计划类型:去掉 isPlanType 限制,只要当前用户为管理员即可配置 */} + {isAdmin && (
( 独立计划
+ )}