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] =?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} +
导入数量: