From 32f50d676e4871031bfeaaeaabf96232d73d3839 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: Thu, 11 Sep 2025 11:38:03 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat(contact-import):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=80=9A=E8=AE=AF=E5=BD=95=E5=AF=BC=E5=85=A5=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=B9=B6=E4=BC=98=E5=8C=96=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E9=A1=B5=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor(contact-import): 重构API接口类型定义和数据结构 style(contact-import): 调整列表页和表单页的样式布局 fix(contact-import): 修复列表页数据加载和搜索功能的问题 --- .../workspace/contact-import/form/api.ts | 95 +++ .../workspace/contact-import/form/data.ts | 38 ++ .../contact-import/form/index.module.scss | 335 ++++------ .../workspace/contact-import/form/index.tsx | 575 +++++++++--------- .../workspace/contact-import/list/api.ts | 37 +- .../workspace/contact-import/list/data.ts | 5 +- .../contact-import/list/index.module.scss | 42 +- .../workspace/contact-import/list/index.tsx | 90 +-- 8 files changed, 639 insertions(+), 578 deletions(-) create mode 100644 Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts create mode 100644 Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts b/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts new file mode 100644 index 00000000..3b3217e9 --- /dev/null +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts @@ -0,0 +1,95 @@ +import request from "@/api/request"; +import { + ContactImportTask, + CreateContactImportTaskData, + UpdateContactImportTaskData, + ContactImportRecord, + PaginatedResponse, + ImportStats, +} from "./data"; + +// 获取通讯录导入任务列表 +export function fetchContactImportTasks( + params = { type: 6, page: 1, limit: 10 }, +) { + return request("/v1/workbench/list", params, "GET"); +} + +// 获取单个任务详情 +export function fetchContactImportTaskDetail(id: number) { + return request("/v1/workbench/detail", { id }, "GET"); +} + +// 创建通讯录导入任务 +export function createContactImportTask( + data: CreateContactImportTaskData, +): Promise { + return request("/v1/workbench/create", { ...data, type: 6 }, "POST"); +} + +// 更新通讯录导入任务 +export function updateContactImportTask( + data: UpdateContactImportTaskData, +): Promise { + return request("/v1/workbench/update", { ...data, type: 6 }, "POST"); +} + +// 删除通讯录导入任务 +export function deleteContactImportTask(id: number): Promise { + return request("/v1/workbench/delete", { id }, "DELETE"); +} + +// 切换任务状态 +export function toggleContactImportTask(data: { + id: number; + status: number; +}): Promise { + return request("/v1/workbench/update-status", { ...data }, "POST"); +} + +// 复制通讯录导入任务 +export function copyContactImportTask(id: number): Promise { + return request("/v1/workbench/copy", { id }, "POST"); +} + +// 获取导入记录 +export function fetchImportRecords( + workbenchId: number, + page: number = 1, + limit: number = 20, + keyword?: string, +): Promise> { + return request( + "/v1/workbench/import-records", + { + workbenchId, + page, + limit, + keyword, + }, + "GET", + ); +} + +// 获取统计数据 +export function fetchImportStats(): Promise { + return request("/v1/workbench/import-stats", {}, "GET"); +} + +// 获取设备组列表 +export function fetchDeviceGroups(): Promise { + return request("/v1/device/groups", {}, "GET"); +} + +// 手动触发导入 +export function triggerImport(taskId: number): Promise { + return request("/v1/workbench/trigger-import", { taskId }, "POST"); +} + +// 批量操作任务 +export function batchOperateTasks(data: { + taskIds: number[]; + operation: "start" | "stop" | "delete"; +}): Promise { + return request("/v1/workbench/batch-operate", data, "POST"); +} diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts b/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts new file mode 100644 index 00000000..50724ce3 --- /dev/null +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts @@ -0,0 +1,38 @@ +// 分配接口类型 +export interface Allocation { + /** 主键ID */ + id?: number; + /** 任务名称 */ + name: string; + //是否启用0关闭,1启用 + status: number; + //任务类型,固定为6 + type: number; + /** 工作台ID */ + workbenchId: number; + + /** 设备id */ + deviceGroups: number[]; + + /** 流量池 */ + pools?: JSON | null; + + /** 分配数量 */ + num?: number | null; + + /** 是否清除现有联系人,默认0 */ + clearContact?: number; + + /** 备注类型 0不备注 1年月日 2月日 3自定义,默认0 */ + remarkType: number; + + /** 备注 */ + remark?: string | null; + + /** 开始时间 */ + startTime?: string | null; + + /** 结束时间 */ + endTime?: string | null; + [key: string]: any; +} 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 962aedcc..bdc76bee 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,229 +1,146 @@ -.container { - padding: 12px; - background-color: #f5f5f5; - min-height: 100vh; +.basicSection { + background: none; + border-radius: 0; + box-shadow: none; + padding: 24px 16px 0 16px; + width: 100%; + max-width: 600px; + margin: 0 auto; } -.form { - display: flex; - flex-direction: column; - gap: 16px; +.formItem { + margin-bottom: 24px; } -.section { - background: #fff; +.formLabel { + font-size: 15px; + color: #222; + font-weight: 500; + margin-bottom: 10px; + display: block; +} + +.input { + height: 44px; border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - - :global(.adm-card-body) { - padding: 16px; + font-size: 15px; + width: 100%; +} + +.select { + width: 100%; + height: 44px; + + :global(.ant-select-selector) { + height: 44px !important; + border-radius: 8px !important; + font-size: 15px !important; + } + + :global(.ant-select-selection-item) { + line-height: 42px !important; } } -.sectionTitle { - font-size: 16px; - font-weight: 600; - color: #333; - margin-bottom: 16px; - padding-bottom: 8px; - border-bottom: 1px solid #f0f0f0; -} +.timePicker { + width: 100%; + height: 44px; -.actions { - margin-top: 24px; - padding: 16px; - background: #fff; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); -} - -// Form样式覆盖 -:global { - .adm-form-item { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - } - - .adm-form-item-label { - font-size: 14px; - font-weight: 500; - color: #333; - margin-bottom: 8px; - } - - .adm-input { - border: 1px solid #d9d9d9; - border-radius: 6px; - padding: 10px 12px; - font-size: 14px; - - &:focus { - border-color: #1890ff; - box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); - } - - &::placeholder { - color: #bfbfbf; - } - } - - .adm-selector { - .adm-selector-item { - border: 1px solid #d9d9d9; - border-radius: 6px; - margin: 4px; - padding: 8px 12px; - font-size: 14px; - - &.adm-selector-item-active { - border-color: #1890ff; - background-color: #e6f7ff; - color: #1890ff; - } - } - } - - .adm-stepper { - .adm-stepper-button { - border: 1px solid #d9d9d9; - border-radius: 4px; - width: 32px; - height: 32px; - - &:hover { - border-color: #1890ff; - color: #1890ff; - } - } - - .adm-stepper-input { - border: 1px solid #d9d9d9; - border-radius: 4px; - height: 32px; - margin: 0 4px; - text-align: center; - font-size: 14px; - } - } - - .adm-picker { - .adm-picker-view-column { - font-size: 14px; - } - } - - .adm-button { - border-radius: 6px; - font-size: 16px; - font-weight: 500; - - &.adm-button-primary { - background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); - border: none; - - &:hover { - background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%); - } - } - } -} - -// 表单验证错误样式 -:global(.adm-form-item-feedback-error) { - color: #ff4d4f; - font-size: 12px; - margin-top: 4px; -} - -:global(.adm-form-item-has-error) { - .adm-input { - border-color: #ff4d4f; - - &:focus { - border-color: #ff4d4f; - box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2); - } - } - - .adm-selector-item { - border-color: #ff4d4f; - } - - .adm-stepper-button, - .adm-stepper-input { - border-color: #ff4d4f; - } -} - -// 响应式设计 -@media (max-width: 480px) { - .container { - padding: 8px; - } - - .sectionTitle { + :global(.ant-picker) { + width: 100%; + height: 44px; + border-radius: 8px; font-size: 15px; } - - .actions { - margin-top: 16px; - padding: 12px; - } - - :global { - .adm-form-item-label { - font-size: 13px; - } - - .adm-input { - padding: 8px 10px; - font-size: 13px; - } - - .adm-selector-item { - padding: 6px 10px; - font-size: 13px; - } - - .adm-button { - font-size: 15px; - } - } } -// 加载状态 -.loading { +.counterRow { + display: flex; + align-items: center; + gap: 0; +} + +.stepperContainer { + display: flex; + align-items: center; + gap: 0; +} + +.stepperButton { + width: 40px; + height: 40px; + border-radius: 8px; + background: #fff; + border: 1px solid #e5e7eb; + font-size: 16px; + color: #188eee; display: flex; align-items: center; justify-content: center; - padding: 40px; - color: #666; - font-size: 14px; - gap: 8px; + cursor: pointer; + transition: border 0.2s; + + &:hover { + border: 1px solid #188eee; + } } -// 提示信息 -.tip { - background: #f6ffed; - border: 1px solid #b7eb8f; - border-radius: 6px; - padding: 12px; - margin-bottom: 16px; - font-size: 13px; - color: #52c41a; - line-height: 1.5; +.stepperInput { + width: 80px; + height: 40px; + border-radius: 0; + border: 1px solid #e5e7eb; + border-left: none; + border-right: none; + text-align: center; + font-size: 16px; + font-weight: 600; + color: #222; + padding: 0 8px; } -.warning { - background: #fff7e6; - border: 1px solid #ffd591; - border-radius: 6px; - padding: 12px; - margin-bottom: 16px; - font-size: 13px; - color: #fa8c16; - line-height: 1.5; -} \ No newline at end of file +.counterTip { + font-size: 12px; + color: #aaa; + margin-top: 4px; +} + +.buttonGroup { + display: flex; + gap: 12px; + padding: 14px; + background: #fff; +} + +.submitButton { + height: 44px; + border-radius: 8px; + font-size: 15px; + min-width: 120px; + flex: 1; +} + +.resetButton { + height: 44px; + border-radius: 8px; + font-size: 15px; + min-width: 100px; +} + +.deviceSelection { + width: 100%; + + :global { + .ant-input { + border-radius: 8px; + border: 1px solid #e8e8e8; + padding: 12px 16px; + font-size: 14px; + + &:focus { + border-color: #1890ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); + } + } + } +} 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 cada08db..fc06837e 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx @@ -1,140 +1,155 @@ import React, { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { - Button, - Toast, - Form, - Input, - Selector, - Stepper, - DatePicker, - Card, - Space, -} from "antd-mobile"; +import { PlusOutlined, MinusOutlined } from "@ant-design/icons"; +import { Button, Input, message, TimePicker, Select, Switch } from "antd"; import NavCommon from "@/components/NavCommon"; import Layout from "@/components/Layout/Layout"; +import DeviceSelection from "@/components/DeviceSelection"; import { createContactImportTask, updateContactImportTask, fetchContactImportTaskDetail, - fetchDeviceGroups, -} from "../list/api"; -import { - CreateContactImportTaskData, - UpdateContactImportTaskData, - ContactImportTask, - DeviceGroup, -} from "../list/data"; +} from "./api"; +import { Allocation } from "./data"; + import style from "./index.module.scss"; +import dayjs from "dayjs"; const ContactImportForm: React.FC = () => { const navigate = useNavigate(); const { id } = useParams<{ id?: string }>(); const isEdit = !!id; - - const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); - const [deviceGroups, setDeviceGroups] = useState([]); - const [taskData, setTaskData] = useState(null); - const [showStartTimePicker, setShowStartTimePicker] = useState(false); - const [showEndTimePicker, setShowEndTimePicker] = useState(false); - const [startTime, setStartTime] = useState(null); - const [endTime, setEndTime] = useState(null); + const [formData, setFormData] = useState({ + name: "", // 任务名称 + status: 1, // 是否启用,默认启用 + type: 6, // 任务类型,固定为6 + workbenchId: 1, // 默认工作台ID + deviceGroups: [] as number[], + pools: [] as any[], + num: 50, + clearContact: 0, + remarkType: 0, + remark: "", + startTime: null, + endTime: null, + // 保留原有字段用于UI显示 + deviceGroupsOptions: [] as any[], + }); - // 备注类型选项 - const remarkTypeOptions = [ - { label: "公司名称", value: "公司名称" }, - { label: "职位", value: "职位" }, - { label: "部门", value: "部门" }, - { label: "地区", value: "地区" }, - { label: "行业", value: "行业" }, - { label: "来源", value: "来源" }, - { label: "标签", value: "标签" }, - { label: "自定义", value: "自定义" }, - ]; - - // 获取设备组列表 - const loadDeviceGroups = async () => { - try { - const data = await fetchDeviceGroups(); - setDeviceGroups(data); - } catch (error) { - Toast.show({ - content: "获取设备组失败", - icon: "fail", - }); - } + // 处理设备选择 + const handleDeviceSelect = (selectedDevices: any[]) => { + setFormData(prev => ({ + ...prev, + deviceGroupsOptions: selectedDevices, + deviceGroups: selectedDevices.map(device => device.id), // 提取设备ID存储到deviceGroups数组 + })); }; // 获取任务详情(编辑模式) const loadTaskDetail = async () => { if (!id) return; - + try { - const data = await fetchContactImportTaskDetail(id); + setLoading(true); + const data = await fetchContactImportTaskDetail(Number(id)); if (data) { - setTaskData(data); - form.setFieldsValue({ - name: data.name, - deviceGroups: data.deviceGroups, - num: data.num, - clientId: data.clientId, - remarkType: data.remarkType, - remarkValue: data.remarkValue, - startTime: data.startTime, - endTime: data.endTime, - maxImportsPerDay: data.maxImportsPerDay, - importInterval: data.importInterval, + // 构造设备选择组件需要的数据格式 + // 如果后端返回的是设备ID数组,需要构造完整的设备对象用于显示 + const deviceGroupsOptions = + data.deviceGroups?.map((deviceId: number) => ({ + id: deviceId, + memo: `设备 ${deviceId}`, + imei: ``, + wechatId: ``, + status: "online" as const, + })) || []; + + setFormData({ + name: data.name || "", + status: data.status || 1, + type: data.type || 6, + workbenchId: data.workbenchId || 1, + deviceGroups: data.deviceGroups || [], + pools: data.pools ? JSON.parse(JSON.stringify(data.pools)) : [], + num: data.num || 50, + clearContact: data.clearContact || 0, + remarkType: data.remarkType || 0, + remark: data.remark || "", + startTime: data.startTime ? dayjs(data.startTime, "HH:mm:ss") : null, + endTime: data.endTime ? dayjs(data.endTime, "HH:mm:ss") : null, + deviceGroupsOptions, }); } } catch (error) { - Toast.show({ - content: "获取任务详情失败", - icon: "fail", - }); + console.error("Failed to load task detail:", error); + message.error("获取任务详情失败"); navigate("/workspace/contact-import/list"); + } finally { + setLoading(false); } }; + // 更新表单数据 + const handleUpdateFormData = (data: Partial) => { + setFormData(prev => ({ ...prev, ...data })); + }; + // 提交表单 const handleSubmit = async () => { - try { - const values = await form.validateFields(); - setLoading(true); + // 表单验证 + if (!formData.name.trim()) { + message.error("请输入任务名称"); + return; + } - const taskData: CreateContactImportTaskData | UpdateContactImportTaskData = { - name: values.name, - deviceGroups: values.deviceGroups, - num: values.num, - clientId: values.clientId, - remarkType: values.remarkType, - remarkValue: values.remarkValue, - startTime: values.startTime, - endTime: values.endTime, - maxImportsPerDay: values.maxImportsPerDay, - importInterval: values.importInterval, + if (formData.deviceGroups.length === 0) { + message.error("请选择设备"); + return; + } + + if (!formData.num || formData.num <= 0) { + message.error("请输入有效的分配数量"); + return; + } + + // 验证开始时间不得大于结束时间 + if (formData.startTime && formData.endTime) { + if (formData.startTime.isAfter(formData.endTime)) { + message.error("开始时间不得大于结束时间"); + return; + } + } + + setLoading(true); + try { + const submitData: Partial = { + name: formData.name, + status: formData.status, + type: formData.type, + workbenchId: formData.workbenchId, + deviceGroups: formData.deviceGroups, + pools: JSON.parse(JSON.stringify(formData.pools)), + num: formData.num, + clearContact: formData.clearContact, + remarkType: formData.remarkType, + remark: formData.remark || null, + startTime: formData.startTime?.format("HH:mm:ss") || null, + endTime: formData.endTime?.format("HH:mm:ss") || null, }; if (isEdit && id) { - await updateContactImportTask({ ...taskData, id }); - Toast.show({ - content: "更新成功", - icon: "success", - }); + await updateContactImportTask({ ...submitData, id: Number(id) }); + message.success("更新成功"); } else { - await createContactImportTask(taskData); - Toast.show({ - content: "创建成功", - icon: "success", - }); + await createContactImportTask(submitData); + message.success("创建成功"); } navigate("/workspace/contact-import/list"); } catch (error) { - Toast.show({ - content: isEdit ? "更新失败" : "创建失败", - icon: "fail", - }); + message.error(isEdit ? "更新失败" : "创建失败"); } finally { setLoading(false); } @@ -142,11 +157,24 @@ const ContactImportForm: React.FC = () => { // 重置表单 const handleReset = () => { - form.resetFields(); + setFormData({ + name: "", + status: 1, + type: 6, + workbenchId: 1, + deviceGroups: [], + pools: [], + num: 50, + clearContact: 0, + remarkType: 0, + remark: "", + startTime: null, + endTime: null, + deviceGroupsOptions: [], + }); }; useEffect(() => { - loadDeviceGroups(); if (isEdit) { loadTaskDetail(); } @@ -154,200 +182,175 @@ const ContactImportForm: React.FC = () => { return ( navigate("/workspace/contact-import/list")} - > - 返回 - - } - title={isEdit ? "编辑通讯录导入" : "新建通讯录导入"} - /> + header={} + footer={ +
+ + +
} > -
-
- {/* 基本信息 */} - -
基本信息
- - - - - - - ({ - label: `${group.name} (${group.deviceCount}台设备)`, - value: group.id, - }))} - placeholder="请选择设备组" - /> - -
- - {/* 导入配置 */} - -
导入配置
- - - - - - - - - - - - - - - - -
- - {/* 时间配置 */} - -
时间配置
- - - setShowStartTimePicker(true)} - /> - - - - setShowEndTimePicker(true)} - /> - - - setShowStartTimePicker(false)} - onConfirm={(val) => { - setStartTime(val); - form.setFieldValue('startTime', `${val.getHours().toString().padStart(2, '0')}:${val.getMinutes().toString().padStart(2, '0')}`); - setShowStartTimePicker(false); - }} +
+
+
+
任务名称
+ handleUpdateFormData({ name: e.target.value })} + className={style.input} /> - - setShowEndTimePicker(false)} - onConfirm={(val) => { - setEndTime(val); - form.setFieldValue('endTime', `${val.getHours().toString().padStart(2, '0')}:${val.getMinutes().toString().padStart(2, '0')}`); - setShowEndTimePicker(false); - }} - /> - - - - - - - - - - - {/* 操作按钮 */} -
- - - - +
为此导入任务设置一个名称
- + +
+
设备选择
+ +
选择要分配联系人的设备
+
+ +
+
分配数量
+
+
+
要分配给设备的联系人数量
+
+ +
+
清除现有联系人
+ + 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 }) + } + /> +
+
); }; -export default ContactImportForm; \ No newline at end of file +export default ContactImportForm; 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 6c115d27..ad8e91a5 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/list/api.ts +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/list/api.ts @@ -11,22 +11,28 @@ import { // 获取通讯录导入任务列表 export function fetchContactImportTasks( params = { type: 6, page: 1, limit: 10 }, -): Promise<{ code: number; msg: string; data: { list: ContactImportTask[] } }> { +) { return request("/v1/workbench/list", params, "GET"); } // 获取单个任务详情 -export function fetchContactImportTaskDetail(id: number): Promise { +export function fetchContactImportTaskDetail( + id: number, +): Promise { return request("/v1/workbench/detail", { id }, "GET"); } // 创建通讯录导入任务 -export function createContactImportTask(data: CreateContactImportTaskData): Promise { +export function createContactImportTask( + data: CreateContactImportTaskData, +): Promise { return request("/v1/workbench/create", { ...data, type: 6 }, "POST"); } // 更新通讯录导入任务 -export function updateContactImportTask(data: UpdateContactImportTaskData): Promise { +export function updateContactImportTask( + data: UpdateContactImportTaskData, +): Promise { return request("/v1/workbench/update", { ...data, type: 6 }, "POST"); } @@ -36,7 +42,10 @@ export function deleteContactImportTask(id: number): Promise { } // 切换任务状态 -export function toggleContactImportTask(data: { id: number; status: number }): Promise { +export function toggleContactImportTask(data: { + id: number; + status: number; +}): Promise { return request("/v1/workbench/update-status", { ...data }, "POST"); } @@ -52,12 +61,16 @@ export function fetchImportRecords( limit: number = 20, keyword?: string, ): Promise> { - return request("/v1/workbench/import-records", { - workbenchId, - page, - limit, - keyword, - }, "GET"); + return request( + "/v1/workbench/import-records", + { + workbenchId, + page, + limit, + keyword, + }, + "GET", + ); } // 获取统计数据 @@ -81,4 +94,4 @@ export function batchOperateTasks(data: { operation: "start" | "stop" | "delete"; }): Promise { return request("/v1/workbench/batch-operate", data, "POST"); -} \ No newline at end of file +} diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/list/data.ts b/Cunkebao/src/pages/mobile/workspace/contact-import/list/data.ts index c1154310..33986379 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/list/data.ts +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/list/data.ts @@ -88,7 +88,8 @@ export interface CreateContactImportTaskData { } // 更新通讯录导入任务数据 -export interface UpdateContactImportTaskData extends CreateContactImportTaskData { +export interface UpdateContactImportTaskData + extends CreateContactImportTaskData { id: number; } @@ -127,4 +128,4 @@ export interface ImportStats { todayImports: number; totalImports: number; successRate: number; -} \ No newline at end of file +} 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 4a52cdb6..082d3233 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 @@ -1,7 +1,5 @@ .container { - padding: 12px; - background-color: #f5f5f5; - min-height: 100vh; + padding: 0 14px; } .toolbar { @@ -17,15 +15,15 @@ .searchBox { flex: 1; - + :global(.ant-input-affix-wrapper) { border-radius: 6px; border: 1px solid #d9d9d9; - + &:hover { border-color: #40a9ff; } - + &:focus-within { border-color: #1890ff; box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); @@ -36,7 +34,7 @@ .actions { display: flex; gap: 8px; - + :global(.adm-button) { border-radius: 6px; } @@ -87,12 +85,12 @@ border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); transition: all 0.2s ease; - + &:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } - + :global(.adm-card-body) { padding: 16px; } @@ -133,7 +131,7 @@ .menuButton { padding: 4px 8px; color: #666; - + &:hover { color: #1890ff; background-color: #f0f8ff; @@ -162,14 +160,14 @@ color: #333; cursor: pointer; transition: background-color 0.2s; - + &:hover { background-color: #f5f5f5; } - + &:last-child { color: #ff4d4f; - + &:hover { background-color: #fff2f0; } @@ -185,7 +183,7 @@ align-items: center; margin-bottom: 8px; font-size: 14px; - + &:last-child { margin-bottom: 0; } @@ -209,7 +207,7 @@ gap: 8px; padding-top: 12px; border-top: 1px solid #f0f0f0; - + :global(.adm-button) { flex: 1; border-radius: 6px; @@ -219,29 +217,25 @@ // 响应式设计 @media (max-width: 480px) { - .container { - padding: 8px; - } - .toolbar { flex-direction: column; align-items: stretch; gap: 8px; } - + .actions { justify-content: space-between; } - + .taskName { font-size: 15px; } - + .taskDetail { font-size: 13px; } - + .label { min-width: 60px; } -} \ No newline at end of file +} 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 1551ce2d..ef1e6661 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/list/index.tsx @@ -97,7 +97,7 @@ const ContactImport: React.FC = () => { setLoading(true); try { const response = await fetchContactImportTasks(); - const data = response.list || []; + const data = response?.list || []; setTasks(data); setFilteredTasks(data); } catch (error) { @@ -117,10 +117,12 @@ const ContactImport: React.FC = () => { setFilteredTasks(tasks); } else { const filtered = tasks.filter( - (task) => + task => task.name.toLowerCase().includes(keyword.toLowerCase()) || - (task.config?.remark || '').toLowerCase().includes(keyword.toLowerCase()) || - task.creatorName.toLowerCase().includes(keyword.toLowerCase()) + (task.config?.remark || "") + .toLowerCase() + .includes(keyword.toLowerCase()) || + task.creatorName.toLowerCase().includes(keyword.toLowerCase()), ); setFilteredTasks(filtered); } @@ -212,51 +214,45 @@ const ContactImport: React.FC = () => { return ( navigate("/workspace")} - > - 返回 - - } - title="通讯录导入" - /> - } - > -
- {/* 搜索和操作栏 */} -
-
- } - value={searchKeyword} - onChange={(e) => handleSearch(e.target.value)} - allowClear - /> -
-
+ <> + navigate("/workspace")} + title="通讯录导入" + right={ + + } + /> + {/* 搜索栏 */} +
+
+ setSearchKeyword(e.target.value)} + prefix={} + allowClear + size="large" + /> +
-
-
- + + } + > +
{/* 任务列表 */}
{loading ? ( @@ -280,7 +276,7 @@ const ContactImport: React.FC = () => { )}
) : ( - filteredTasks.map((task) => ( + filteredTasks.map(task => (
@@ -302,11 +298,15 @@ const ContactImport: React.FC = () => {
备注类型: - {task.config?.remarkType === 1 ? '自定义备注' : '其他'} + + {task.config?.remarkType === 1 ? "自定义备注" : "其他"} +
设备数量: - {task.config?.devices?.length || 0} + + {task.config?.devices?.length || 0} +
导入数量: From 8d386d9bdf3140f161268ba89d8ac94005a30058 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: Thu, 11 Sep 2025 11:46:36 +0800 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=BB=84=E7=9B=B8=E5=85=B3=E5=8F=98=E9=87=8F=E5=90=8D=E6=8B=BC?= =?UTF-8?q?=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将多处代码中的变量名`deveiceGroups`和`deveiceGroupsOptions`修正为正确的拼写`deviceGroups`和`deviceGroupsOptions`,保持代码一致性 --- .../plan/list/components/DeviceListModal.tsx | 2 +- .../mobile/scenarios/plan/new/index.data.ts | 8 +++---- .../pages/mobile/scenarios/plan/new/index.tsx | 4 ++-- .../plan/new/steps/FriendRequestSettings.tsx | 8 +++---- .../form/components/DeviceSelector.tsx | 20 ++++++++--------- .../workspace/auto-group/form/index.tsx | 22 +++++++++---------- .../mobile/workspace/auto-group/form/types.ts | 6 ++--- .../mobile/workspace/auto-like/new/data.ts | 4 ++-- .../mobile/workspace/auto-like/new/index.tsx | 20 ++++++++--------- .../workspace/contact-import/form/data.ts | 1 - .../workspace/moments-sync/new/index.tsx | 16 +++++++------- .../list/components/DeviceListModal.tsx | 2 +- 12 files changed, 55 insertions(+), 58 deletions(-) diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/list/components/DeviceListModal.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/list/components/DeviceListModal.tsx index 111483cd..e220e3fc 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/list/components/DeviceListModal.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/list/components/DeviceListModal.tsx @@ -38,7 +38,7 @@ const DeviceListModal: React.FC = ({ setLoading(true); try { const detailRes = await getPlanDetail(ruleId.toString()); - const deviceData = detailRes?.deveiceGroupsOptions || []; + const deviceData = detailRes?.deviceGroupsOptions || []; setDevices(deviceData); } catch (error) { console.error("获取设备详情失败:", error); 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 34489536..3cd21563 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.data.ts @@ -25,8 +25,8 @@ export interface FormData { device: string[]; customTags: string[]; customTagsOptions: string[]; - deveiceGroups: string[]; - deveiceGroupsOptions: DeviceSelectionItem[]; + deviceGroups: string[]; + deviceGroupsOptions: DeviceSelectionItem[]; wechatGroups: string[]; wechatGroupsOptions: GroupSelectionItem[]; messagePlans: any[]; @@ -50,8 +50,8 @@ export const defFormData: FormData = { customTags: [], customTagsOptions: [], messagePlans: [], - deveiceGroups: [], - deveiceGroupsOptions: [], + deviceGroups: [], + deviceGroupsOptions: [], wechatGroups: [], wechatGroupsOptions: [], contentGroups: [], diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx index acce83fa..949574a1 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/index.tsx @@ -67,8 +67,8 @@ export default function NewPlan() { remarkFormat: detail.remarkFormat ?? "", addFriendInterval: detail.addFriendInterval ?? 1, tips: detail.tips ?? "", - deveiceGroups: detail.deveiceGroups ?? [], - deveiceGroupsOptions: detail.deveiceGroupsOptions ?? [], + deviceGroups: detail.deviceGroups ?? [], + deviceGroupsOptions: detail.deviceGroupsOptions ?? [], wechatGroups: detail.wechatGroups ?? [], wechatGroupsOptions: detail.wechatGroupsOptions ?? [], contentGroups: detail.contentGroups ?? [], diff --git a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx index 5aa73aed..db8f3648 100644 --- a/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx +++ b/Cunkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx @@ -76,11 +76,11 @@ const FriendRequestSettings: React.FC = ({ onChange({ ...formData, greeting: template }); setIsTemplateDialogOpen(false); }; - const handleDevicesChange = (deveiceGroupsOptions: DeviceSelectionItem[]) => { + const handleDevicesChange = (deviceGroupsOptions: DeviceSelectionItem[]) => { onChange({ ...formData, - deveiceGroups: deveiceGroupsOptions.map(d => d.id), - deveiceGroupsOptions: deveiceGroupsOptions, + deviceGroups: deviceGroupsOptions.map(d => d.id), + deviceGroupsOptions: deviceGroupsOptions, }); }; @@ -90,7 +90,7 @@ const FriendRequestSettings: React.FC = ({
选择设备
diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/form/components/DeviceSelector.tsx b/Cunkebao/src/pages/mobile/workspace/auto-group/form/components/DeviceSelector.tsx index d3b3bb16..281dbab2 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/form/components/DeviceSelector.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/form/components/DeviceSelector.tsx @@ -6,8 +6,8 @@ import { DeviceSelectionItem } from "@/components/DeviceSelection/data"; interface DeviceSelectorProps { selectedDevices: DeviceSelectionItem[]; onNext: (data: { - deveiceGroups: string[]; - deveiceGroupsOptions: DeviceSelectionItem[]; + deviceGroups: string[]; + deviceGroupsOptions: DeviceSelectionItem[]; }) => void; } @@ -37,15 +37,13 @@ const DeviceSelector = forwardRef( })); // 设备选择 - const handleDeviceSelect = ( - deveiceGroupsOptions: DeviceSelectionItem[], - ) => { - const deveiceGroups = deveiceGroupsOptions.map(item => item.id); - form.setFieldValue("deveiceGroups", deveiceGroups); + const handleDeviceSelect = (deviceGroupsOptions: DeviceSelectionItem[]) => { + const deviceGroups = deviceGroupsOptions.map(item => item.id); + form.setFieldValue("deviceGroups", deviceGroups); // 通知父组件数据变化 onNext({ - deveiceGroups: deveiceGroups.map(id => String(id)), - deveiceGroupsOptions, + deviceGroups: deviceGroups.map(id => String(id)), + deviceGroupsOptions, }); }; @@ -55,7 +53,7 @@ const DeviceSelector = forwardRef( form={form} layout="vertical" initialValues={{ - deveiceGroups: selectedDevices.map(item => item.id), + deviceGroups: selectedDevices.map(item => item.id), }} >
@@ -68,7 +66,7 @@ const DeviceSelector = forwardRef(
{ const updatedForm = { ...defaultForm, name: res.name, - deveiceGroups: res.config.deveiceGroups || [], - deveiceGroupsOptions: res.config.deveiceGroupsOptions || [], + deviceGroups: res.config.deviceGroups || [], + deviceGroupsOptions: res.config.deviceGroupsOptions || [], poolGroups: res.config.poolGroups || [], poolGroupsOptions: res.config.poolGroupsOptions || [], startTime: res.config.startTime, @@ -80,7 +80,7 @@ const AutoGroupForm: React.FC = () => { id: res.id, }; setFormData(updatedForm); - setDeviceGroupsOptions(res.config.deveiceGroupsOptions || []); + setDeviceGroupsOptions(res.config.deviceGroupsOptions || []); setpoolGroupsOptions(res.config.poolGroupsOptions || []); setDataLoaded(true); // 标记数据已加载 }); @@ -92,14 +92,14 @@ const AutoGroupForm: React.FC = () => { // 设备组选择 const handleDevicesChange = (data: { - deveiceGroups: string[]; - deveiceGroupsOptions: DeviceSelectionItem[]; + deviceGroups: string[]; + deviceGroupsOptions: DeviceSelectionItem[]; }) => { setFormData(prev => ({ ...prev, - deveiceGroups: data.deveiceGroups, + deviceGroups: data.deviceGroups, })); - setDeviceGroupsOptions(data.deveiceGroupsOptions); + setDeviceGroupsOptions(data.deviceGroupsOptions); }; // 流量池包选择 @@ -116,7 +116,7 @@ const AutoGroupForm: React.FC = () => { Toast.show({ content: "请输入任务名称" }); return; } - if (formData.deveiceGroups.length === 0) { + if (formData.deviceGroups.length === 0) { Toast.show({ content: "请选择至少一个设备组" }); return; } @@ -129,7 +129,7 @@ const AutoGroupForm: React.FC = () => { try { const submitData = { ...formData, - deveiceGroupsOptions: deviceGroupsOptions, + deviceGroupsOptions: deviceGroupsOptions, poolGroupsOptions: poolGroupsOptions, }; diff --git a/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts b/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts index 83ad789d..ba9cbf8a 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts +++ b/Cunkebao/src/pages/mobile/workspace/auto-group/form/types.ts @@ -6,8 +6,8 @@ export interface AutoGroupFormData { id?: string; // 任务ID type: number; // 任务类型 name: string; // 任务名称 - deveiceGroups: string[]; // 设备组 - deveiceGroupsOptions: DeviceSelectionItem[]; // 设备组选项 + deviceGroups: string[]; // 设备组 + deviceGroupsOptions: DeviceSelectionItem[]; // 设备组选项 poolGroups: string[]; // 流量池 poolGroupsOptions: PoolSelectionItem[]; // 流量池选项 startTime: string; // 开始时间 (YYYY-MM-DD HH:mm:ss) @@ -34,7 +34,7 @@ export const formValidationRules = { { required: true, message: "请输入任务名称" }, { min: 2, max: 50, message: "任务名称长度应在2-50个字符之间" }, ], - deveiceGroups: [ + deviceGroups: [ { required: true, message: "请选择设备组" }, { type: "array", min: 1, message: "至少选择一个设备组" }, ], 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 43f1da6f..1b47baee 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/new/data.ts +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/new/data.ts @@ -79,8 +79,8 @@ export interface CreateLikeTaskData { startTime: string; endTime: string; contentTypes: ContentType[]; - deveiceGroups: number[]; - deveiceGroupsOptions: DeviceSelectionItem[]; + deviceGroups: number[]; + deviceGroupsOptions: DeviceSelectionItem[]; friendsGroups: number[]; friendsGroupsOptions: FriendSelectionItem[]; friendMaxLikes: number; 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 3d0aca8d..779aecea 100644 --- a/Cunkebao/src/pages/mobile/workspace/auto-like/new/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/auto-like/new/index.tsx @@ -43,8 +43,8 @@ const NewAutoLike: React.FC = () => { startTime: "08:00", endTime: "22:00", contentTypes: ["text", "image", "video"], - deveiceGroups: [], - deveiceGroupsOptions: [], + deviceGroups: [], + deviceGroupsOptions: [], friendsGroups: [], friendsGroupsOptions: [], targetTags: [], @@ -72,8 +72,8 @@ const NewAutoLike: React.FC = () => { startTime: config.timeRange?.start || config.startTime || "08:00", endTime: config.timeRange?.end || config.endTime || "22:00", contentTypes: config.contentTypes || ["text", "image", "video"], - deveiceGroups: config.deveiceGroups || [], - deveiceGroupsOptions: config.deveiceGroupsOptions || [], + deviceGroups: config.deviceGroups || [], + deviceGroupsOptions: config.deviceGroupsOptions || [], friendsGroups: config.friendsgroups || [], friendsGroupsOptions: config.friendsGroupsOptions || [], targetTags: config.targetTags || [], @@ -121,7 +121,7 @@ const NewAutoLike: React.FC = () => { message.warning("请输入任务名称"); return; } - if (!formData.deveiceGroups || formData.deveiceGroups.length === 0) { + if (!formData.deviceGroups || formData.deviceGroups.length === 0) { message.warning("请选择执行设备"); return; } @@ -329,11 +329,11 @@ const NewAutoLike: React.FC = () => {
handleUpdateFormData({ - deveiceGroups: devices.map(v => v.id), - deveiceGroupsOptions: devices, + deviceGroups: devices.map(v => v.id), + deviceGroupsOptions: devices, }) } showInput={true} @@ -353,7 +353,7 @@ const NewAutoLike: React.FC = () => { onClick={handleNext} className={style.nextBtn} size="large" - disabled={formData.deveiceGroups.length === 0} + disabled={formData.deviceGroups.length === 0} > 下一步 @@ -372,7 +372,7 @@ const NewAutoLike: React.FC = () => { friendsGroupsOptions: friends, }) } - deviceIds={formData.deveiceGroups} + deviceIds={formData.deviceGroups} />
} + loading={loading} >
From dc60dacb02d8d0947619ca741b1d6ff7b72446b0 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: Thu, 11 Sep 2025 14:36:49 +0800 Subject: [PATCH 4/6] =?UTF-8?q?refactor(contact-import):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E9=80=9A=E8=AE=AF=E5=BD=95=E5=AF=BC=E5=85=A5=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89=E5=92=8C=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将ContactImportTask相关类型统一为Allocation类型 - 优化详情页样式和布局 - 移除冗余样式和代码 --- .../contact-import/detail/index.module.scss | 61 ++++---- .../workspace/contact-import/detail/index.tsx | 95 +++++++------ .../workspace/contact-import/form/api.ts | 10 +- .../workspace/contact-import/form/data.ts | 131 ++++++++++++++++++ .../workspace/contact-import/form/index.tsx | 7 +- 5 files changed, 215 insertions(+), 89 deletions(-) diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.module.scss b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.module.scss index aaf11375..1404f16f 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.module.scss +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.module.scss @@ -1,7 +1,5 @@ .container { padding: 12px; - background-color: #f5f5f5; - min-height: 100vh; } .loading { @@ -25,8 +23,7 @@ background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - margin-bottom: 16px; - + :global(.adm-card-body) { padding: 16px; } @@ -61,8 +58,8 @@ .actions { display: flex; - gap: 8px; - + gap: 20px; + :global(.adm-button) { flex: 1; border-radius: 6px; @@ -75,21 +72,21 @@ border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); overflow: hidden; - + :global(.adm-tabs-header) { background: #fafafa; border-bottom: 1px solid #f0f0f0; } - + :global(.adm-tabs-tab) { font-size: 15px; font-weight: 500; - + &.adm-tabs-tab-active { color: #1890ff; } } - + :global(.adm-tabs-tab-line) { background: #1890ff; } @@ -106,7 +103,7 @@ background: #fff; border-radius: 8px; border: 1px solid #f0f0f0; - + :global(.adm-card-body) { padding: 16px; } @@ -158,11 +155,11 @@ border-radius: 8px; border: 1px solid #f0f0f0; margin-bottom: 12px; - + :global(.adm-list-item-content) { padding: 16px; } - + &:last-child { margin-bottom: 0; } @@ -201,12 +198,12 @@ display: flex; align-items: center; font-size: 13px; - + .label { min-width: 70px; color: #666; } - + .value { color: #333; } @@ -237,19 +234,19 @@ border-radius: 12px; font-size: 12px; padding: 2px 8px; - + &.adm-tag-success { background: #f6ffed; border-color: #b7eb8f; color: #52c41a; } - + &.adm-tag-danger { background: #fff2f0; border-color: #ffccc7; color: #ff4d4f; } - + &.adm-tag-warning { background: #fff7e6; border-color: #ffd591; @@ -267,47 +264,43 @@ // 响应式设计 @media (max-width: 480px) { - .container { - padding: 8px; - } - .taskName { font-size: 16px; } - + .taskStatus { font-size: 13px; padding: 3px 10px; } - + .cardTitle { font-size: 15px; } - + .infoItem { font-size: 13px; } - + .label { min-width: 70px; } - + .recordDevice { font-size: 13px; } - + .recordTime { font-size: 11px; } - + .recordDetail { font-size: 12px; - + .label { min-width: 60px; } } - + .recordError { font-size: 12px; padding: 6px 10px; @@ -317,16 +310,16 @@ // 空状态样式 :global(.adm-empty) { padding: 40px 20px; - + .adm-empty-image { width: 60px; height: 60px; opacity: 0.3; } - + .adm-empty-description { color: #999; font-size: 14px; margin-top: 12px; } -} \ No newline at end of file +} diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx index 06ad0310..e50de7e7 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx @@ -21,10 +21,7 @@ import { triggerImport, toggleContactImportTask, } from "../list/api"; -import { - ContactImportTask, - ContactImportRecord, -} from "../list/data"; +import { ContactImportTask, ContactImportRecord } from "../list/data"; import { PlayCircleOutlined, PauseCircleOutlined, @@ -39,7 +36,7 @@ import style from "./index.module.scss"; const ContactImportDetail: React.FC = () => { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); - + const [task, setTask] = useState(null); const [records, setRecords] = useState([]); const [loading, setLoading] = useState(false); @@ -51,7 +48,7 @@ const ContactImportDetail: React.FC = () => { // 获取任务详情 const loadTaskDetail = async () => { if (!id) return; - + setLoading(true); try { const response = await fetchContactImportTaskDetail(id); @@ -71,7 +68,7 @@ const ContactImportDetail: React.FC = () => { // 获取导入记录 const loadRecords = async (pageNum: number = 1, reset: boolean = false) => { if (!id) return; - + setRecordsLoading(true); try { const response = await fetchImportRecords(id, pageNum, 20); @@ -96,7 +93,7 @@ const ContactImportDetail: React.FC = () => { // 切换任务状态 const handleToggleStatus = async () => { if (!task) return; - + try { await toggleContactImportTask({ id: task.id, @@ -118,7 +115,7 @@ const ContactImportDetail: React.FC = () => { // 手动触发导入 const handleTriggerImport = async () => { if (!task) return; - + try { await triggerImport(task.id); Toast.show({ @@ -250,31 +247,20 @@ const ContactImportDetail: React.FC = () => { return ( navigate("/workspace/contact-import/list")} - > - 返回 - - } - title="任务详情" - right={ - - } - /> - } - > - -
+ <> + + navigate(`/workspace/contact-import/form/${task.id}`) + } + > + 编辑 + + } + /> {/* 任务操作栏 */}
@@ -290,14 +276,17 @@ const ContactImportDetail: React.FC = () => {
- + + } + > + +
{/* 标签页 */} {
设备组数: - {task.deviceGroups?.length || 0} + + {task.deviceGroups?.length || 0} +
导入数量: @@ -363,11 +358,15 @@ const ContactImportDetail: React.FC = () => {
每日最大导入: - {task.maxImportsPerDay} + + {task.maxImportsPerDay} +
导入间隔: - {task.importInterval}分钟 + + {task.importInterval}分钟 +
@@ -378,11 +377,15 @@ const ContactImportDetail: React.FC = () => {
今日导入: - {task.todayImportCount} + + {task.todayImportCount} +
总导入数: - {task.totalImportCount} + + {task.totalImportCount} +
创建时间: @@ -403,7 +406,7 @@ const ContactImportDetail: React.FC = () => { ) : ( - {records.map((record) => ( + {records.map(record => (
@@ -440,7 +443,7 @@ const ContactImportDetail: React.FC = () => { ))} )} - + { ); }; -export default ContactImportDetail; \ No newline at end of file +export default ContactImportDetail; 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 3b3217e9..d9abded4 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/api.ts @@ -1,6 +1,6 @@ import request from "@/api/request"; import { - ContactImportTask, + Allocation, CreateContactImportTaskData, UpdateContactImportTaskData, ContactImportRecord, @@ -21,16 +21,12 @@ export function fetchContactImportTaskDetail(id: number) { } // 创建通讯录导入任务 -export function createContactImportTask( - data: CreateContactImportTaskData, -): Promise { +export function createContactImportTask(data: Allocation): Promise { return request("/v1/workbench/create", { ...data, type: 6 }, "POST"); } // 更新通讯录导入任务 -export function updateContactImportTask( - data: UpdateContactImportTaskData, -): Promise { +export function updateContactImportTask(data: Allocation): Promise { return request("/v1/workbench/update", { ...data, type: 6 }, "POST"); } diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts b/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts index 8031789f..4847665e 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/data.ts @@ -35,3 +35,134 @@ export interface Allocation { endTime?: string | null; [key: string]: any; } +// 通讯录导入任务状态 +export type ContactImportTaskStatus = 1 | 2; // 1: 开启, 2: 关闭 + +// 设备组信息 +export interface DeviceGroup { + id: string; + name: string; + deviceCount: number; + status: "online" | "offline"; + lastActive: string; +} + +// 通讯录导入记录 +export interface ContactImportRecord { + id: string; + workbenchId: string; + wechatAccountId: string; + deviceId: string; + num: number; + clientId: string; + remarkType: string; + remarkValue: string; + startTime: string; + endTime: string; + createTime: string; + operatorName: string; + operatorAvatar: string; + deviceName: string; + importStatus: "success" | "failed" | "pending"; + errorMessage?: string; +} + +// 通讯录导入任务配置 +export interface ContactImportTaskConfig { + id: number; + workbenchId: number; + devices: number[]; + pools: number[]; + num: number; + clearContact: number; + remarkType: number; + remark: string; + startTime: string; + endTime: string; + createTime: string; +} + +// 通讯录导入任务 +export interface ContactImportTask { + id: number; + companyId: number; + name: string; + type: number; + status: ContactImportTaskStatus; + autoStart: number; + userId: number; + createTime: string; + updateTime: string; + config: ContactImportTaskConfig; + creatorName: string; + auto_like: any; + moments_sync: any; + traffic_config: any; + group_push: any; + group_create: any; + // 计算属性,用于向后兼容 + deviceGroups?: string[]; + todayImportCount?: number; + totalImportCount?: number; + maxImportsPerDay?: number; + importInterval?: number; +} + +// 创建通讯录导入任务数据 +export interface CreateContactImportTaskData { + name: string; + type: number; + config: { + devices: number[]; + pools: number[]; + num: number; + clearContact: number; + remarkType: number; + remark: string; + startTime: string; + endTime: string; + }; +} + +// 更新通讯录导入任务数据 +export interface UpdateContactImportTaskData + extends CreateContactImportTaskData { + id: number; +} + +// 任务配置 +export interface TaskConfig { + deviceGroups: string[]; + num: number; + clientId: string; + remarkType: string; + remarkValue: string; + startTime: string; + endTime: string; + maxImportsPerDay: number; + importInterval: number; +} + +// API响应 +export interface ApiResponse { + code: number; + msg: string; + data: T; +} + +// 分页响应 +export interface PaginatedResponse { + list: T[]; + total: number; + page: number; + limit: number; +} + +// 统计数据 +export interface ImportStats { + totalTasks: number; + activeTasks: number; + todayImports: number; + totalImports: number; + successRate: number; +} 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 3364540d..a7606240 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/form/index.tsx @@ -135,10 +135,13 @@ const ContactImportForm: React.FC = () => { }; if (isEdit && id) { - await updateContactImportTask({ ...submitData, id: Number(id) }); + await updateContactImportTask({ + ...submitData, + id: Number(id), + } as Allocation); message.success("更新成功"); } else { - await createContactImportTask(submitData); + await createContactImportTask(submitData as Allocation); message.success("创建成功"); } From ff97490a2b45e10ae573ce96f30484d7ccc1aaa6 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: Thu, 11 Sep 2025 14:41:26 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E8=81=94=E7=B3=BB=E8=AE=B0=E5=BD=95=E7=9A=84?= =?UTF-8?q?=E5=89=AF=E4=BD=9C=E7=94=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/mobile/workspace/contact-import/detail/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx index e50de7e7..8db5096e 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx @@ -187,9 +187,9 @@ const ContactImportDetail: React.FC = () => { }, [id]); useEffect(() => { - if (activeTab === "records" && records.length === 0) { - loadRecords(1, true); - } + // if (activeTab === "records" && records.length === 0) { + // loadRecords(1, true); + // } }, [activeTab]); if (loading) { From 18fbf79fa8784616637885e44118387294876f8e 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: Thu, 11 Sep 2025 14:42:00 +0800 Subject: [PATCH 6/6] =?UTF-8?q?refactor(contact-import):=20=E5=B0=86task?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=B1=BB=E5=9E=8B=E4=BB=8EContactImportTask?= =?UTF-8?q?=E6=94=B9=E4=B8=BAany?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 简化状态类型以兼容更多场景,避免类型限制导致的潜在问题 --- .../src/pages/mobile/workspace/contact-import/detail/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx index 8db5096e..90e1319b 100644 --- a/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx +++ b/Cunkebao/src/pages/mobile/workspace/contact-import/detail/index.tsx @@ -37,7 +37,7 @@ const ContactImportDetail: React.FC = () => { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); - const [task, setTask] = useState(null); + const [task, setTask] = useState(null); const [records, setRecords] = useState([]); const [loading, setLoading] = useState(false); const [recordsLoading, setRecordsLoading] = useState(false);