diff --git a/Cunkebao/api/scenarios.ts b/Cunkebao/api/scenarios.ts index e2f7a708..ed77aeb5 100644 --- a/Cunkebao/api/scenarios.ts +++ b/Cunkebao/api/scenarios.ts @@ -21,12 +21,7 @@ export interface SceneItem { export interface ScenesResponse { code: number; msg: string; - data: { - list: SceneItem[]; - total: number; - page: number; - limit: number; - }; + data: SceneItem[]; } // 前端使用的场景数据类型 @@ -80,12 +75,7 @@ export const fetchScenes = async (params: { return { code: 500, msg: "获取场景列表失败", - data: { - list: [], - total: 0, - page: 1, - limit: 10 - } + data: [] }; } }; diff --git a/Cunkebao/app/plans/new/steps/BasicSettings.tsx b/Cunkebao/app/plans/new/steps/BasicSettings.tsx index 0e38f476..4e583774 100644 --- a/Cunkebao/app/plans/new/steps/BasicSettings.tsx +++ b/Cunkebao/app/plans/new/steps/BasicSettings.tsx @@ -168,8 +168,19 @@ export function BasicSettings({ formData, onChange, onNext }: BasicSettingsProps const response = await fetchScenes({ limit: 30 }) - if (response.code === 200 && response.data?.list) { - setScenes(response.data.list) + if (response.code === 200 && Array.isArray(response.data)) { + const formattedScenes = response.data.map(scene => ({ + id: scene.id.toString(), + name: scene.name, + image: scene.image, + status: scene.status, + sort: scene.sort, + createTime: scene.createTime, + updateTime: scene.updateTime, + deleteTime: scene.deleteTime + })) + setScenes(formattedScenes) + setSceneError(null) // 成功时清空错误 } else { setSceneError(response.msg || "获取场景列表失败") console.error("获取场景列表失败:", response.msg) @@ -191,15 +202,27 @@ export function BasicSettings({ formData, onChange, onNext }: BasicSettingsProps onChange({ ...formData, scenario: "haibao" }) } - if (!formData.planName) { + // 只在初始化时设置默认计划名称 + if (!formData.planName && !formData._initialized) { if (formData.materials?.length > 0) { const today = new Date().toLocaleDateString("zh-CN").replace(/\//g, "") - onChange({ ...formData, planName: `海报${today}` }) + onChange({ ...formData, planName: `海报${today}`, _initialized: true }) } else { - onChange({ ...formData, planName: "场景" }) + onChange({ ...formData, planName: "场景", _initialized: true }) } } - }, [formData, onChange]) + }, []) // 移除 formData 依赖,只在组件挂载时执行一次 + + // 处理本地场景选择 + const handleScenarioSelect = (scenarioId: string) => { + onChange({ ...formData, scenario: scenarioId }) + + // 如果选择了电话获客,自动更新计划名称 + if (scenarioId === "phone") { + const today = new Date().toLocaleDateString("zh-CN").replace(/\//g, "") + onChange({ ...formData, planName: `电话${today}` }) + } + } // 处理从API获取的场景选择 const handleSceneSelect = (scene: SceneItem) => { @@ -220,17 +243,6 @@ export function BasicSettings({ formData, onChange, onNext }: BasicSettingsProps } } - // 处理本地场景选择 - const handleScenarioSelect = (scenarioId: string) => { - onChange({ ...formData, scenario: scenarioId }) - - // 如果选择了电话获客,自动更新计划名称 - if (scenarioId === "phone") { - const today = new Date().toLocaleDateString("zh-CN").replace(/\//g, "") - onChange({ ...formData, planName: `电话${today}` }) - } - } - // 根据场景名称推断本地场景类型 const getLocalScenarioType = (name: string): string => { if (name.includes("海报")) return "haibao"; @@ -366,311 +378,318 @@ export function BasicSettings({ formData, onChange, onNext }: BasicSettingsProps }; return ( -
-
-
- - - {/* 场景按钮阵列 */} -
- {loadingScenes ? ( - // 加载中状态 - Array.from({ length: 6 }).map((_, index) => ( -
- )) - ) : sceneError || scenes.length === 0 ? ( - // 加载失败或无数据时显示本地场景 - displayedScenarios.map((scenario) => ( - - )) - ) : ( - // 从API获取的场景列表 - scenes.map((scene) => ( - - )) - )} -
- - {/* 展开更多按钮 - 仅当显示本地场景且未展开全部时显示 */} - {(!loadingScenes && (sceneError || scenes.length === 0) && !showAllScenarios) && ( - +
+ {/* 错误提示,只在 sceneError 存在且不为 'success' 时显示 */} + {sceneError && sceneError !== "success" && ( +
+
{sceneError}
+ +
+ )} +
+
+ + + {/* 场景按钮阵列 */} +
+ {loadingScenes ? ( + // 加载中状态 + Array.from({ length: 6 }).map((_, index) => ( +
+ )) + ) : sceneError || scenes.length === 0 ? ( + // 加载失败或无数据时显示本地场景 + displayedScenarios.map((scenario) => ( + + )) + ) : ( + // 从API获取的场景列表 + scenes.map((scene) => ( + + )) )}
+ + {/* 展开更多按钮 - 仅当显示本地场景且未展开全部时显示 */} + {(!loadingScenes && (sceneError || scenes.length === 0) && !showAllScenarios) && ( + + )} +
-
- - onChange({ ...formData, planName: e.target.value })} - placeholder="请输入计划名称" - className="mt-2" - /> -
+
+ + onChange({ ...formData, planName: e.target.value })} + placeholder="请输入计划名称" + className="mt-2" + /> +
- {formData.scenario && ( - <> - {scenarios.find((s) => s.id === formData.scenario)?.type === "social" && ( -
- -
- - -
- {selectedAccounts.length > 0 && ( -
- {selectedAccounts.map((account) => ( -
- {account.nickname} - {account.nickname} - -
- ))} -
- )} + {formData.scenario && ( + <> + {scenarios.find((s) => s.id === formData.scenario)?.type === "social" && ( +
+ +
+ +
- )} - - {/* 电话获客特殊设置 */} - {formData.scenario === "phone" && ( - -
- - -
-
-
-
-
- 自动添加客户 -
-
- {phoneSettings.autoAdd ? "已开启" : "已关闭"} -
-
-
-
-
- 语音转文字 -
-
- {phoneSettings.speechToText ? "已开启" : "已关闭"} -
-
-
-
-
- 问题提取 -
-
- {phoneSettings.questionExtraction ? "已开启" : "已关闭"} -
-
-
-

- 提示:电话获客功能将自动记录来电信息,并根据设置执行相应操作 -

-
- )} - - {scenarios.find((s) => s.id === formData.scenario)?.type === "material" && ( -
-
- - -
- - {/* 海报展示区域 */} -
- {materials.map((material) => ( -
m.id === material.id) - ? "ring-2 ring-blue-600" - : "hover:ring-2 hover:ring-blue-600" - }`} - onClick={() => handleMaterialSelect(material)} - > + {selectedAccounts.length > 0 && ( +
+ {selectedAccounts.map((account) => ( +
{material.name} -
- -
-
-
{material.name}
-
+ {account.nickname} +
))}
+ )} +
+ )} - {selectedMaterials.length > 0 && ( -
- -
-
- {selectedMaterials[0].name} handlePreviewImage(selectedMaterials[0].preview)} - /> - -
-
-
- )} + {/* 电话获客特殊设置 */} + {formData.scenario === "phone" && ( + +
+ +
- )} - - {scenarios.find((s) => s.id === formData.scenario)?.id === "order" && ( -
-
- -
- - +
+
+
+
+ 自动添加客户 +
+
+ {phoneSettings.autoAdd ? "已开启" : "已关闭"}
+
+
+
+ 语音转文字 +
+
+ {phoneSettings.speechToText ? "已开启" : "已关闭"} +
+
+
+
+
+ 问题提取 +
+
+ {phoneSettings.questionExtraction ? "已开启" : "已关闭"} +
+
+
+

+ 提示:电话获客功能将自动记录来电信息,并根据设置执行相应操作 +

+ + )} - {importedTags.length > 0 && ( -
-

已导入 {importedTags.length} 条数据

-
- - - - 电话号码 - 来源 - - - - {importedTags.slice(0, 5).map((tag, index) => ( - - {tag.phone} - {tag.source} - - ))} - {importedTags.length > 5 && ( - - - 还有 {importedTags.length - 5} 条数据未显示 - - - )} - -
+ {scenarios.find((s) => s.id === formData.scenario)?.type === "material" && ( +
+
+ + +
+ + {/* 海报展示区域 */} +
+ {materials.map((material) => ( +
m.id === material.id) + ? "ring-2 ring-blue-600" + : "hover:ring-2 hover:ring-blue-600" + }`} + onClick={() => handleMaterialSelect(material)} + > + {material.name} +
+ +
+
+
{material.name}
- )} + ))}
- )} - - )} -
- - onChange({ ...formData, enabled: checked })} - /> -
+ {selectedMaterials.length > 0 && ( +
+ +
+
+ {selectedMaterials[0].name} handlePreviewImage(selectedMaterials[0].preview)} + /> + +
+
+
+ )} +
+ )} - -
-
+ {scenarios.find((s) => s.id === formData.scenario)?.id === "order" && ( +
+
+ +
+ + +
+
+ + {importedTags.length > 0 && ( +
+

已导入 {importedTags.length} 条数据

+
+ + + + 电话号码 + 来源 + + + + {importedTags.slice(0, 5).map((tag, index) => ( + + {tag.phone} + {tag.source} + + ))} + {importedTags.length > 5 && ( + + + 还有 {importedTags.length - 5} 条数据未显示 + + + )} + +
+
+
+ )} +
+ )} + + )} + +
+ + onChange({ ...formData, enabled: checked })} + /> +
+ + +
+
) } diff --git a/Cunkebao/app/plans/new/steps/FriendRequestSettings.tsx b/Cunkebao/app/plans/new/steps/FriendRequestSettings.tsx index e6df1ead..17e19bdf 100644 --- a/Cunkebao/app/plans/new/steps/FriendRequestSettings.tsx +++ b/Cunkebao/app/plans/new/steps/FriendRequestSettings.tsx @@ -140,7 +140,7 @@ export function FriendRequestSettings({ formData, onChange, onNext, onPrev }: Fr } return ( -
+
diff --git a/Cunkebao/app/plans/new/steps/MessageSettings.tsx b/Cunkebao/app/plans/new/steps/MessageSettings.tsx index 01ef26b1..68c88b66 100644 --- a/Cunkebao/app/plans/new/steps/MessageSettings.tsx +++ b/Cunkebao/app/plans/new/steps/MessageSettings.tsx @@ -192,7 +192,7 @@ export function MessageSettings({ formData, onChange, onNext, onPrev }: MessageS } return ( -
+

消息设置

diff --git a/Cunkebao/app/plans/new/steps/TagSettings.tsx b/Cunkebao/app/plans/new/steps/TagSettings.tsx index 395abe77..281672a8 100644 --- a/Cunkebao/app/plans/new/steps/TagSettings.tsx +++ b/Cunkebao/app/plans/new/steps/TagSettings.tsx @@ -107,7 +107,7 @@ export function TagSettings({ formData, onChange, onNext, onPrev }: TagSettingsP } return ( -
+
diff --git a/Cunkebao/app/scenarios/page.tsx b/Cunkebao/app/scenarios/page.tsx index 11ecaea0..d61dd15b 100644 --- a/Cunkebao/app/scenarios/page.tsx +++ b/Cunkebao/app/scenarios/page.tsx @@ -121,9 +121,9 @@ export default function ScenariosPage() { setLoading(true) const response = await fetchScenes({ limit: 50 }) - if (response.code === 200 && response.data?.list) { + if (response.code === 200 && response.data) { // 转换场景数据为前端展示格式 - const transformedScenes = response.data.list.map((scene) => { + const transformedScenes = response.data.map((scene) => { const transformedScene = transformSceneItem(scene) // 添加link属性(用于导航) @@ -216,9 +216,6 @@ export default function ScenariosPage() {
-

场景获客

diff --git a/Server/application/common/model/PlanScene.php b/Server/application/common/model/PlanScene.php new file mode 100644 index 00000000..c3bcdf30 --- /dev/null +++ b/Server/application/common/model/PlanScene.php @@ -0,0 +1,26 @@ +middleware(['jwt']); return []; \ No newline at end of file diff --git a/Server/application/cunkebao/controller/Scene.php b/Server/application/cunkebao/controller/Scene.php deleted file mode 100644 index 16d75fd4..00000000 --- a/Server/application/cunkebao/controller/Scene.php +++ /dev/null @@ -1,67 +0,0 @@ - 200, - 'msg' => '获取成功', - 'data' => $result - ]); - } - - /** - * 获取单个场景详情 - * - * @param int $id 场景ID - * @return \think\response\Json - */ - public function read($id) - { - // 查询场景信息 - $scene = PlanScene::getSceneInfo($id); - - if (!$scene) { - return json([ - 'code' => 404, - 'msg' => '场景不存在' - ]); - } - - return json([ - 'code' => 200, - 'msg' => '获取成功', - 'data' => $scene - ]); - } -} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/TrafficTag.php b/Server/application/cunkebao/controller/TrafficTag.php deleted file mode 100644 index 09ae2dc2..00000000 --- a/Server/application/cunkebao/controller/TrafficTag.php +++ /dev/null @@ -1,64 +0,0 @@ -userInfo; - - // 获取查询条件 - $where = []; - - // 关键词搜索 - $keyword = Request::param('keyword', ''); - if (!empty($keyword)) { - $where[] = ['tagName', 'like', "%{$keyword}%"]; - } - - // 添加公司ID过滤条件 - $where[] = ['companyId', '=', $userInfo['companyId']]; - - // 获取分页参数 - $page = (int)Request::param('page', 1); - $limit = (int)Request::param('limit', 200); // 默认每页显示200条 - - // 获取排序参数 - $sort = Request::param('sort', 'id'); - $order = Request::param('order', 'desc'); - - // 查询列表 - $list = TrafficTagModel::getTagsByCompany($where, "{$sort} {$order}", $page, $limit); - - return json([ - 'code' => 200, - 'msg' => '获取成功', - 'data' => [ - 'total' => $list->total(), - 'list' => $list->items(), - 'page' => $page, - 'limit' => $limit - ] - ]); - } catch (\Exception $e) { - return json([ - 'code' => 500, - 'msg' => '获取失败:' . $e->getMessage() - ]); - } - } -} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/plan/GetPlanSceneListV1Controller.php b/Server/application/cunkebao/controller/plan/GetPlanSceneListV1Controller.php new file mode 100644 index 00000000..566f4373 --- /dev/null +++ b/Server/application/cunkebao/controller/plan/GetPlanSceneListV1Controller.php @@ -0,0 +1,41 @@ + PlansSceneModel::STATUS_ACTIVE + ] + ) + ->order('sort desc') + ->select()->toArray(); + } + + /** + * 获取场景列表 + * + * @return \think\response\Json + */ + public function index() + { + return ResponseHelper::success( + $this->getSceneList() + ); + } +} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/plan/PostCreateAddFriendPlanV1Controller.php b/Server/application/cunkebao/controller/plan/PostCreateAddFriendPlanV1Controller.php new file mode 100644 index 00000000..9ea0e76a --- /dev/null +++ b/Server/application/cunkebao/controller/plan/PostCreateAddFriendPlanV1Controller.php @@ -0,0 +1,69 @@ + Request::post('name', ''), + 'sceneId' => Request::post('sceneId', 0), + 'status' => Request::post('status', 0), + 'reqConf' => Request::post('reqConf', ''), + 'msgConf' => Request::post('msgConf', ''), + 'tagConf' => Request::post('tagConf', ''), + 'createTime' => time(), + 'updateTime' => time() + ]; + + // 验证必填字段 + if (empty($data['name'])) { + return ResponseHelper::error('计划名称不能为空', 400); + } + + if (empty($data['sceneId'])) { + return ResponseHelper::error('场景ID不能为空', 400); + } + + // 验证数据格式 + if (!$this->validateJson($data['reqConf'])) { + return ResponseHelper::error('好友申请设置格式不正确', 400); + } + + if (!$this->validateJson($data['msgConf'])) { + return ResponseHelper::error('消息设置格式不正确', 400); + } + + if (!$this->validateJson($data['tagConf'])) { + return ResponseHelper::error('标签设置格式不正确', 400); + } + + // 插入数据库 + $result = Db::name('friend_plan')->insert($data); + + if ($result) { + return ResponseHelper::success([], '添加计划任务成功'); + } else { + return ResponseHelper::error('添加计划任务失败', 500); + } + } catch (\Exception $e) { + return ResponseHelper::error('系统错误: ' . $e->getMessage(), 500); + } + } +} \ No newline at end of file diff --git a/Server/application/cunkebao/model/PlanScene.php b/Server/application/cunkebao/model/PlanScene.php deleted file mode 100644 index 38541e8b..00000000 --- a/Server/application/cunkebao/model/PlanScene.php +++ /dev/null @@ -1,43 +0,0 @@ -count(); - - // 分页查询数据 - $list = $query->page($page, $limit) - ->order($order) - ->select(); - - return [ - 'list' => $list, - 'total' => $total, - 'page' => $page, - 'limit' => $limit - ]; - } -} \ No newline at end of file