+
+
+ {visibleGroups.map((group, gIndex) => {
+ // 获取该组的运行模式
+ const groupMode = rotationStatus?.instanceModes.find(
+ i => i.group === group.name
+ )?.mode
+ const isGroupActive = rotationStatus?.enabled && rotationStatus?.currentActiveGroup === group.name
+ // 检查该组是否有账号在运行
+ const hasRunningAccounts = rotationStatus?.instanceModes.some(i => i.group === group.name)
+
+ return (
+
+
+
+ {
+ setConfig(prev => ({
+ ...prev,
+ accountGroups: prev.accountGroups.map((g, i) =>
+ i === gIndex ? { ...g, name: e.target.value || `第${gIndex + 1}组` } : g
+ )
+ }))
+ }}
+ placeholder={`第${gIndex + 1}组`}
+ className="w-24 px-2 py-1 text-sm text-gray-900 font-medium border border-gray-300 rounded bg-white hover:border-blue-400 focus:border-blue-500 focus:outline-none"
+ />
+ {isRunning && currentGroupIndex === gIndex && (
+
+ 运行中
+
+ )}
+ {/* 运行模式标签 */}
+ {groupMode && (
+
+ {groupMode === 'active' ? '全功能' : '仅回复'}
+
+ )}
+ {/* 活跃组标记 + 运行时间 */}
+ {isGroupActive && (
+
+ 活跃
+ {elapsedTime}
+
+ )}
+
+
+
+
+ {group.accounts.map((acc, aIndex) => {
+ // 计算该账号对应的 viewId
+ const viewId = gIndex * 3 + aIndex + 1
+ const accountStatus = rotationStatus?.instanceModes.find(i => i.viewId === viewId)
+
+ return (
+
+ updateAccount(gIndex, aIndex, 'email', e.target.value)}
+ className="flex-1 px-3 py-2 text-sm text-gray-900 rounded-lg border border-gray-300 focus:border-blue-500 focus:outline-none"
+ />
+ updateAccount(gIndex, aIndex, 'pwd', e.target.value)}
+ className="flex-1 px-3 py-2 text-sm text-gray-900 rounded-lg border border-gray-300 focus:border-blue-500 focus:outline-none"
+ />
+ {/* 账号运行状态 */}
+ {accountStatus && (
+
+ 视图{viewId}
+
+ )}
+
+
+ )
+ })}
+
每组最多 3 个账号,将按组轮换运行
+
+ )
+ })}
+
+
+
+
+
关闭时只跑当前组不切换
+
+
+ {config.rotateEnabled && (
+ <>
+
+
+
+ {[2, 3].map(num => (
+
+ ))}
+
+
+
+
+ {
+ const val = e.target.value
+ // 允许完全清空输入框
+ if (val === '') {
+ updateConfig('switchMinutes', 0) // 0 表示编辑中的临时空状态
+ } else {
+ const num = parseInt(val)
+ if (!isNaN(num)) {
+ updateConfig('switchMinutes', num)
+ }
+ }
+ }}
+ onBlur={(e) => {
+ // 失焦时如果值无效,恢复为默认值 1
+ if (!e.target.value || parseInt(e.target.value) < 1) {
+ updateConfig('switchMinutes', 1)
+ }
+ }}
+ className="w-20 px-3 py-2 text-sm text-gray-900 rounded-lg border border-gray-300 focus:border-blue-500 focus:outline-none"
+ />
+ 每隔 N 分钟切换到下一组
+
+ >
+ )}
+
+ {/* AI 回复 */}
+
+
+
+
开启后由 AI 自动根据对话内容生成回复
+
+
+ {/* 第一条消息 */}
+
+
+
+ {[
+ { value: false, label: '打招呼' },
+ { value: true, label: '发送邀请链接' },
+ ].map(option => (
+
+ ))}
+
+
+
+ {/* 睡眠时间 */}
+
+
+ {
+ const val = e.target.value
+ if (val === '') {
+ updateConfig('sleepTime', -1) // -1 表示未填写
+ } else {
+ updateConfig('sleepTime', parseInt(val) || 0)
+ }
+ }}
+ onBlur={() => {
+ // 失焦时不自动回填,保持未填写状态以便验证
+ }}
+ placeholder="0"
+ className="w-20 px-3 py-2 text-sm text-gray-900 rounded-lg border border-gray-300 focus:border-blue-500 focus:outline-none"
+ />
+
+
+ {/* 邀请阈值 */}
+ {!config.sendInviteFirst && (
+
+
+ {
+ const val = e.target.value
+ // 允许完全清空输入框
+ if (val === '') {
+ updateConfig('inviteThreshold', 0) // 0 表示编辑中的临时空状态
+ } else {
+ const num = parseInt(val)
+ if (!isNaN(num)) {
+ updateConfig('inviteThreshold', num)
+ }
+ }
+ }}
+ onBlur={(e) => {
+ // 失焦时如果值无效,恢复为默认值 1
+ if (!e.target.value || parseInt(e.target.value) < 1) {
+ updateConfig('inviteThreshold', 1)
+ }
+ }}
+ className="w-20 px-3 py-2 text-sm text-gray-900 rounded-lg border border-gray-300 focus:border-blue-500 focus:outline-none"
+ />
+ 打招呼后回复 N 句再发送邀请链接
+
+ )}
+