From 3e9a65af3f08c4ea1f01292db546ced21703a05c Mon Sep 17 00:00:00 2001 From: xiaozhuang <2501719347@qq.com> Date: Tue, 30 Dec 2025 18:53:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=AB=AF=E7=BC=98=E6=B1=A0?= =?UTF-8?q?=EF=BC=8C=E8=AE=B8=E6=84=BF=E6=A0=91=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zhibo/admin/src/api/fatePool.js | 93 +++++ Zhibo/admin/src/api/wishTree.js | 146 ++++++++ Zhibo/admin/src/router/index.js | 6 + Zhibo/admin/src/router/modules/fatePool.js | 39 +++ Zhibo/admin/src/router/modules/wishTree.js | 45 +++ .../admin/src/views/fatePool/topic/index.vue | 196 +++++++++++ Zhibo/admin/src/views/fatePool/topic/post.vue | 179 ++++++++++ .../src/views/fatePool/topicUser/index.vue | 181 ++++++++++ .../src/views/wishTree/message/index.vue | 213 ++++++++++++ Zhibo/admin/src/views/wishTree/node/index.vue | 209 ++++++++++++ .../admin/src/views/wishTree/tree/detail.vue | 199 +++++++++++ Zhibo/admin/src/views/wishTree/tree/index.vue | 226 +++++++++++++ .../controller/FatePoolPostController.java | 130 +++++++ .../controller/FatePoolTopicController.java | 169 +++++++++ .../admin/controller/WishTreeController.java | 224 ++++++++++++ .../controller/WishTreeMessageController.java | 136 ++++++++ .../controller/WishTreeNodeController.java | 181 ++++++++++ .../sql/create_fate_pool_wish_tree_tables.sql | 0 缘池与许愿树管理端功能总结.md | 320 ++++++++++++++++++ 19 files changed, 2892 insertions(+) create mode 100644 Zhibo/admin/src/api/fatePool.js create mode 100644 Zhibo/admin/src/api/wishTree.js create mode 100644 Zhibo/admin/src/router/modules/fatePool.js create mode 100644 Zhibo/admin/src/router/modules/wishTree.js create mode 100644 Zhibo/admin/src/views/fatePool/topic/index.vue create mode 100644 Zhibo/admin/src/views/fatePool/topic/post.vue create mode 100644 Zhibo/admin/src/views/fatePool/topicUser/index.vue create mode 100644 Zhibo/admin/src/views/wishTree/message/index.vue create mode 100644 Zhibo/admin/src/views/wishTree/node/index.vue create mode 100644 Zhibo/admin/src/views/wishTree/tree/detail.vue create mode 100644 Zhibo/admin/src/views/wishTree/tree/index.vue create mode 100644 Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolPostController.java create mode 100644 Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolTopicController.java create mode 100644 Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeController.java create mode 100644 Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeMessageController.java create mode 100644 Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeNodeController.java create mode 100644 Zhibo/zhibo-h/sql/create_fate_pool_wish_tree_tables.sql create mode 100644 缘池与许愿树管理端功能总结.md diff --git a/Zhibo/admin/src/api/fatePool.js b/Zhibo/admin/src/api/fatePool.js new file mode 100644 index 00000000..8eb465d0 --- /dev/null +++ b/Zhibo/admin/src/api/fatePool.js @@ -0,0 +1,93 @@ +import request from '@/utils/request'; + +/** + * 缘池管理 API + */ + +// ========== 话题管理 ========== + +// 话题列表 +export function fatePoolTopicListApi(params) { + return request({ + url: '/admin/fate/pool/topic/list', + method: 'get', + params, + }); +} + +// 话题详情 +export function fatePoolTopicInfoApi(id) { + return request({ + url: `/admin/fate/pool/topic/info/${id}`, + method: 'get', + }); +} + +// 新增话题 +export function fatePoolTopicSaveApi(data) { + return request({ + url: '/admin/fate/pool/topic/save', + method: 'post', + data, + }); +} + +// 更新话题 +export function fatePoolTopicUpdateApi(data) { + return request({ + url: '/admin/fate/pool/topic/update', + method: 'post', + data, + }); +} + +// 删除话题 +export function fatePoolTopicDeleteApi(id) { + return request({ + url: `/admin/fate/pool/topic/delete/${id}`, + method: 'post', + }); +} + +// 修改话题状态 +export function fatePoolTopicStatusApi(id) { + return request({ + url: `/admin/fate/pool/topic/status/${id}`, + method: 'post', + }); +} + +// ========== 话题用户发布信息管理 ========== + +// 发布信息列表 +export function fatePoolPostListApi(params) { + return request({ + url: '/admin/fate/pool/post/list', + method: 'get', + params, + }); +} + +// 发布信息详情 +export function fatePoolPostInfoApi(id) { + return request({ + url: `/admin/fate/pool/post/info/${id}`, + method: 'get', + }); +} + +// 删除发布信息 +export function fatePoolPostDeleteApi(id) { + return request({ + url: `/admin/fate/pool/post/delete/${id}`, + method: 'post', + }); +} + +// 修改发布信息状态 +export function fatePoolPostStatusApi(id) { + return request({ + url: `/admin/fate/pool/post/status/${id}`, + method: 'post', + }); +} diff --git a/Zhibo/admin/src/api/wishTree.js b/Zhibo/admin/src/api/wishTree.js new file mode 100644 index 00000000..09e3349d --- /dev/null +++ b/Zhibo/admin/src/api/wishTree.js @@ -0,0 +1,146 @@ +import request from '@/utils/request'; + +/** + * 许愿树管理 API + */ + +// ========== 许愿树管理 ========== + +// 许愿树列表 +export function wishTreeListApi(params) { + return request({ + url: '/admin/wish/tree/list', + method: 'get', + params, + }); +} + +// 许愿树详情(含节点) +export function wishTreeInfoApi(id) { + return request({ + url: `/admin/wish/tree/info/${id}`, + method: 'get', + }); +} + +// 新增许愿树(含节点) +export function wishTreeSaveApi(data) { + return request({ + url: '/admin/wish/tree/save', + method: 'post', + data, + }); +} + +// 更新许愿树(含节点) +export function wishTreeUpdateApi(data) { + return request({ + url: '/admin/wish/tree/update', + method: 'post', + data, + }); +} + +// 删除许愿树 +export function wishTreeDeleteApi(id) { + return request({ + url: `/admin/wish/tree/delete/${id}`, + method: 'post', + }); +} + +// 启用/停用许愿树 +export function wishTreeActivateApi(id) { + return request({ + url: `/admin/wish/tree/activate/${id}`, + method: 'post', + }); +} + +// ========== 节点管理 ========== + +// 节点列表 +export function wishTreeNodeListApi(params) { + return request({ + url: '/admin/wish/tree/node/list', + method: 'get', + params, + }); +} + +// 节点详情 +export function wishTreeNodeInfoApi(id) { + return request({ + url: `/admin/wish/tree/node/info/${id}`, + method: 'get', + }); +} + +// 新增节点 +export function wishTreeNodeSaveApi(data) { + return request({ + url: '/admin/wish/tree/node/save', + method: 'post', + data, + }); +} + +// 更新节点 +export function wishTreeNodeUpdateApi(data) { + return request({ + url: '/admin/wish/tree/node/update', + method: 'post', + data, + }); +} + +// 删除节点 +export function wishTreeNodeDeleteApi(id) { + return request({ + url: `/admin/wish/tree/node/delete/${id}`, + method: 'post', + }); +} + +// 修改节点状态 +export function wishTreeNodeStatusApi(id) { + return request({ + url: `/admin/wish/tree/node/status/${id}`, + method: 'post', + }); +} + +// ========== 用户留言管理 ========== + +// 留言列表(按许愿树查询) +export function wishTreeMessageListApi(params) { + return request({ + url: '/admin/wish/tree/message/list', + method: 'get', + params, + }); +} + +// 留言详情 +export function wishTreeMessageInfoApi(id) { + return request({ + url: `/admin/wish/tree/message/info/${id}`, + method: 'get', + }); +} + +// 删除留言 +export function wishTreeMessageDeleteApi(id) { + return request({ + url: `/admin/wish/tree/message/delete/${id}`, + method: 'post', + }); +} + +// 修改留言状态 +export function wishTreeMessageStatusApi(id) { + return request({ + url: `/admin/wish/tree/message/status/${id}`, + method: 'post', + }); +} diff --git a/Zhibo/admin/src/router/index.js b/Zhibo/admin/src/router/index.js index 1fc09e81..c6e28436 100644 --- a/Zhibo/admin/src/router/index.js +++ b/Zhibo/admin/src/router/index.js @@ -31,6 +31,8 @@ import contentManageRouter from './modules/contentManage'; // 内容管理 import feedbackManageRouter from './modules/feedbackManage'; // 用户反馈 import agentManageRouter from './modules/agentManage'; // 代理管理 import systemSettingRouter from './modules/systemSetting'; // 系统设置 +import fatePoolRouter from './modules/fatePool'; // 缘池 +import wishTreeRouter from './modules/wishTree'; // 许愿树 /** * Note: sub-menu only appear when route children.length >= 1 @@ -84,6 +86,10 @@ export const constantRoutes = [ liveManageRouter, // 4. 社交互动 socialManageRouter, + // 4.5 缘池 + fatePoolRouter, + // 4.6 许愿树 + wishTreeRouter, // 5. 礼物打赏 giftManageRouter, // 6. 虚拟道具 diff --git a/Zhibo/admin/src/router/modules/fatePool.js b/Zhibo/admin/src/router/modules/fatePool.js new file mode 100644 index 00000000..b9f87965 --- /dev/null +++ b/Zhibo/admin/src/router/modules/fatePool.js @@ -0,0 +1,39 @@ +import Layout from '@/layout'; + +/** + * 缘池路由 + */ +const fatePoolRouter = { + path: '/fatePool', + component: Layout, + redirect: '/fatePool/topic', + name: 'FatePool', + alwaysShow: true, + meta: { + title: '缘池', + icon: 'el-icon-connection', + }, + children: [ + { + path: '/fatePool/topic', + component: () => import('@/views/fatePool/topic/index'), + name: 'FatePoolTopic', + meta: { title: '话题管理', icon: '' }, + }, + { + path: '/fatePool/topicUser', + component: () => import('@/views/fatePool/topicUser/index'), + name: 'FatePoolTopicUser', + meta: { title: '用户发布', icon: '' }, + }, + { + path: '/fatePool/topic/post/:topicId', + component: () => import('@/views/fatePool/topic/post'), + name: 'FatePoolTopicPost', + meta: { title: '用户发布', icon: '' }, + hidden: true, + }, + ], +}; + +export default fatePoolRouter; diff --git a/Zhibo/admin/src/router/modules/wishTree.js b/Zhibo/admin/src/router/modules/wishTree.js new file mode 100644 index 00000000..c9811398 --- /dev/null +++ b/Zhibo/admin/src/router/modules/wishTree.js @@ -0,0 +1,45 @@ +import Layout from '@/layout'; + +/** + * 许愿树路由 + */ +const wishTreeRouter = { + path: '/wishTree', + component: Layout, + redirect: '/wishTree/tree', + name: 'WishTree', + alwaysShow: true, + meta: { + title: '许愿树', + icon: 'el-icon-magic-stick', + }, + children: [ + { + path: '/wishTree/tree', + component: () => import('@/views/wishTree/tree/index'), + name: 'WishTreeList', + meta: { title: '许愿树列表', icon: '' }, + }, + { + path: '/wishTree/node', + component: () => import('@/views/wishTree/node/index'), + name: 'WishTreeNode', + meta: { title: '留言节点', icon: '' }, + }, + { + path: '/wishTree/message', + component: () => import('@/views/wishTree/message/index'), + name: 'WishTreeMessage', + meta: { title: '用户留言', icon: '' }, + }, + { + path: '/wishTree/tree/detail/:treeId', + component: () => import('@/views/wishTree/tree/detail'), + name: 'WishTreeDetail', + meta: { title: '许愿树详情', icon: '' }, + hidden: true, + }, + ], +}; + +export default wishTreeRouter; diff --git a/Zhibo/admin/src/views/fatePool/topic/index.vue b/Zhibo/admin/src/views/fatePool/topic/index.vue new file mode 100644 index 00000000..0142853c --- /dev/null +++ b/Zhibo/admin/src/views/fatePool/topic/index.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/Zhibo/admin/src/views/fatePool/topic/post.vue b/Zhibo/admin/src/views/fatePool/topic/post.vue new file mode 100644 index 00000000..165b7c17 --- /dev/null +++ b/Zhibo/admin/src/views/fatePool/topic/post.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/Zhibo/admin/src/views/fatePool/topicUser/index.vue b/Zhibo/admin/src/views/fatePool/topicUser/index.vue new file mode 100644 index 00000000..9c759bd1 --- /dev/null +++ b/Zhibo/admin/src/views/fatePool/topicUser/index.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/Zhibo/admin/src/views/wishTree/message/index.vue b/Zhibo/admin/src/views/wishTree/message/index.vue new file mode 100644 index 00000000..69a7899a --- /dev/null +++ b/Zhibo/admin/src/views/wishTree/message/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/Zhibo/admin/src/views/wishTree/node/index.vue b/Zhibo/admin/src/views/wishTree/node/index.vue new file mode 100644 index 00000000..ba4111d3 --- /dev/null +++ b/Zhibo/admin/src/views/wishTree/node/index.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/Zhibo/admin/src/views/wishTree/tree/detail.vue b/Zhibo/admin/src/views/wishTree/tree/detail.vue new file mode 100644 index 00000000..0edf243e --- /dev/null +++ b/Zhibo/admin/src/views/wishTree/tree/detail.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/Zhibo/admin/src/views/wishTree/tree/index.vue b/Zhibo/admin/src/views/wishTree/tree/index.vue new file mode 100644 index 00000000..0f907682 --- /dev/null +++ b/Zhibo/admin/src/views/wishTree/tree/index.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolPostController.java b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolPostController.java new file mode 100644 index 00000000..a6292568 --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolPostController.java @@ -0,0 +1,130 @@ +package com.zbkj.admin.controller; + +import com.zbkj.common.page.CommonPage; +import com.zbkj.common.result.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 缘池话题用户发布信息管理 Controller + */ +@Slf4j +@RestController +@RequestMapping("api/admin/fate/pool/post") +@Api(tags = "缘池话题发布信息管理") +@Validated +public class FatePoolPostController { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 发布信息列表 + */ + @ApiOperation(value = "发布信息列表") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult>> getList( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "limit", defaultValue = "10") Integer limit, + @RequestParam(value = "topic_id", required = false) Integer topicId, + @RequestParam(value = "nickname", required = false) String nickname, + @RequestParam(value = "status", required = false) Integer status) { + try { + StringBuilder whereSql = new StringBuilder(" WHERE 1=1"); + List params = new ArrayList<>(); + + if (topicId != null) { + whereSql.append(" AND topic_id = ?"); + params.add(topicId); + } + if (nickname != null && !nickname.isEmpty()) { + whereSql.append(" AND user_nickname LIKE ?"); + params.add("%" + nickname + "%"); + } + if (status != null) { + whereSql.append(" AND status = ?"); + params.add(status); + } + + String countSql = "SELECT COUNT(*) FROM eb_fate_pool_topic_post" + whereSql; + Integer total = jdbcTemplate.queryForObject(countSql, params.toArray(), Integer.class); + + // 关联查询话题标题 + String sql = "SELECT p.*, t.title as topic_title FROM eb_fate_pool_topic_post p " + + "LEFT JOIN eb_fate_pool_topic t ON p.topic_id = t.id" + + whereSql.toString().replace("topic_id", "p.topic_id").replace("user_nickname", "p.user_nickname").replace("status", "p.status") + + " ORDER BY p.id DESC LIMIT ?, ?"; + params.add((page - 1) * limit); + params.add(limit); + List> list = jdbcTemplate.queryForList(sql, params.toArray()); + + CommonPage> result = new CommonPage<>(); + result.setList(list); + result.setTotal(total != null ? total.longValue() : 0L); + result.setPage(page); + result.setLimit(limit); + result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / limit)); + + return CommonResult.success(result); + } catch (Exception e) { + log.error("获取发布信息列表失败", e); + return CommonResult.failed("获取列表失败:" + e.getMessage()); + } + } + + /** + * 发布信息详情 + */ + @ApiOperation(value = "发布信息详情") + @RequestMapping(value = "/info/{id}", method = RequestMethod.GET) + public CommonResult> getInfo(@PathVariable Integer id) { + try { + String sql = "SELECT * FROM eb_fate_pool_topic_post WHERE id = ?"; + Map data = jdbcTemplate.queryForMap(sql, id); + return CommonResult.success(data); + } catch (Exception e) { + log.error("获取发布信息详情失败", e); + return CommonResult.failed("获取详情失败:" + e.getMessage()); + } + } + + /** + * 删除发布信息 + */ + @ApiOperation(value = "删除发布信息") + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + public CommonResult delete(@PathVariable Integer id) { + try { + jdbcTemplate.update("DELETE FROM eb_fate_pool_topic_post WHERE id = ?", id); + return CommonResult.success("删除成功"); + } catch (Exception e) { + log.error("删除发布信息失败", e); + return CommonResult.failed("删除失败:" + e.getMessage()); + } + } + + /** + * 修改发布信息状态 + */ + @ApiOperation(value = "修改发布信息状态") + @RequestMapping(value = "/status/{id}", method = RequestMethod.POST) + public CommonResult updateStatus(@PathVariable Integer id) { + try { + String sql = "UPDATE eb_fate_pool_topic_post SET status = IF(status = 1, 0, 1), update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, id); + return CommonResult.success("状态修改成功"); + } catch (Exception e) { + log.error("修改发布信息状态失败", e); + return CommonResult.failed("状态修改失败:" + e.getMessage()); + } + } +} diff --git a/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolTopicController.java b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolTopicController.java new file mode 100644 index 00000000..8521bea9 --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/FatePoolTopicController.java @@ -0,0 +1,169 @@ +package com.zbkj.admin.controller; + +import com.zbkj.common.page.CommonPage; +import com.zbkj.common.result.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 缘池话题管理 Controller + */ +@Slf4j +@RestController +@RequestMapping("api/admin/fate/pool/topic") +@Api(tags = "缘池话题管理") +@Validated +public class FatePoolTopicController { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 话题列表 + */ + @ApiOperation(value = "话题列表") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult>> getList( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "limit", defaultValue = "10") Integer limit, + @RequestParam(value = "title", required = false) String title, + @RequestParam(value = "status", required = false) Integer status) { + try { + StringBuilder whereSql = new StringBuilder(" WHERE 1=1"); + List params = new ArrayList<>(); + + if (title != null && !title.isEmpty()) { + whereSql.append(" AND title LIKE ?"); + params.add("%" + title + "%"); + } + if (status != null) { + whereSql.append(" AND status = ?"); + params.add(status); + } + + String countSql = "SELECT COUNT(*) FROM eb_fate_pool_topic" + whereSql; + Integer total = jdbcTemplate.queryForObject(countSql, params.toArray(), Integer.class); + + // 查询列表,包含发布数统计 + String sql = "SELECT t.*, (SELECT COUNT(*) FROM eb_fate_pool_topic_post WHERE topic_id = t.id) as post_count " + + "FROM eb_fate_pool_topic t" + whereSql + " ORDER BY t.sort DESC, t.id DESC LIMIT ?, ?"; + params.add((page - 1) * limit); + params.add(limit); + List> list = jdbcTemplate.queryForList(sql, params.toArray()); + + CommonPage> result = new CommonPage<>(); + result.setList(list); + result.setTotal(total != null ? total.longValue() : 0L); + result.setPage(page); + result.setLimit(limit); + result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / limit)); + + return CommonResult.success(result); + } catch (Exception e) { + log.error("获取话题列表失败", e); + return CommonResult.failed("获取列表失败:" + e.getMessage()); + } + } + + /** + * 话题详情 + */ + @ApiOperation(value = "话题详情") + @RequestMapping(value = "/info/{id}", method = RequestMethod.GET) + public CommonResult> getInfo(@PathVariable Integer id) { + try { + String sql = "SELECT * FROM eb_fate_pool_topic WHERE id = ?"; + Map data = jdbcTemplate.queryForMap(sql, id); + return CommonResult.success(data); + } catch (Exception e) { + log.error("获取话题详情失败", e); + return CommonResult.failed("获取详情失败:" + e.getMessage()); + } + } + + /** + * 新增话题 + */ + @ApiOperation(value = "新增话题") + @RequestMapping(value = "/save", method = RequestMethod.POST) + public CommonResult save(@RequestBody Map data) { + try { + String sql = "INSERT INTO eb_fate_pool_topic (title, description, cover_image, sort, status, create_time, update_time) VALUES (?, ?, ?, ?, ?, NOW(), NOW())"; + jdbcTemplate.update(sql, + data.get("title"), + data.get("description"), + data.get("cover_image"), + data.get("sort") != null ? data.get("sort") : 0, + data.get("status") != null ? data.get("status") : 1); + return CommonResult.success("新增成功"); + } catch (Exception e) { + log.error("新增话题失败", e); + return CommonResult.failed("新增失败:" + e.getMessage()); + } + } + + /** + * 更新话题 + */ + @ApiOperation(value = "更新话题") + @RequestMapping(value = "/update", method = RequestMethod.POST) + public CommonResult update(@RequestBody Map data) { + try { + String sql = "UPDATE eb_fate_pool_topic SET title = ?, description = ?, cover_image = ?, sort = ?, status = ?, update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, + data.get("title"), + data.get("description"), + data.get("cover_image"), + data.get("sort"), + data.get("status"), + data.get("id")); + return CommonResult.success("更新成功"); + } catch (Exception e) { + log.error("更新话题失败", e); + return CommonResult.failed("更新失败:" + e.getMessage()); + } + } + + /** + * 删除话题 + */ + @ApiOperation(value = "删除话题") + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + public CommonResult delete(@PathVariable Integer id) { + try { + // 先删除话题下的所有发布信息 + jdbcTemplate.update("DELETE FROM eb_fate_pool_topic_post WHERE topic_id = ?", id); + // 再删除话题 + jdbcTemplate.update("DELETE FROM eb_fate_pool_topic WHERE id = ?", id); + return CommonResult.success("删除成功"); + } catch (Exception e) { + log.error("删除话题失败", e); + return CommonResult.failed("删除失败:" + e.getMessage()); + } + } + + /** + * 修改话题状态 + */ + @ApiOperation(value = "修改话题状态") + @RequestMapping(value = "/status/{id}", method = RequestMethod.POST) + public CommonResult updateStatus(@PathVariable Integer id) { + try { + String sql = "UPDATE eb_fate_pool_topic SET status = IF(status = 1, 0, 1), update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, id); + return CommonResult.success("状态修改成功"); + } catch (Exception e) { + log.error("修改话题状态失败", e); + return CommonResult.failed("状态修改失败:" + e.getMessage()); + } + } +} diff --git a/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeController.java b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeController.java new file mode 100644 index 00000000..757e71b5 --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeController.java @@ -0,0 +1,224 @@ +package com.zbkj.admin.controller; + +import com.zbkj.common.page.CommonPage; +import com.zbkj.common.result.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 许愿树管理 Controller + */ +@Slf4j +@RestController +@RequestMapping("api/admin/wish/tree") +@Api(tags = "许愿树管理") +@Validated +public class WishTreeController { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 许愿树列表 + */ + @ApiOperation(value = "许愿树列表") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult>> getList( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "limit", defaultValue = "10") Integer limit, + @RequestParam(value = "name", required = false) String name) { + try { + StringBuilder whereSql = new StringBuilder(" WHERE 1=1"); + List params = new ArrayList<>(); + + if (name != null && !name.isEmpty()) { + whereSql.append(" AND name LIKE ?"); + params.add("%" + name + "%"); + } + + String countSql = "SELECT COUNT(*) FROM eb_wish_tree" + whereSql; + Integer total = jdbcTemplate.queryForObject(countSql, params.toArray(), Integer.class); + + // 查询列表,包含节点数和留言数统计 + String sql = "SELECT t.*, " + + "(SELECT COUNT(*) FROM eb_wish_tree_node WHERE tree_id = t.id) as node_count, " + + "(SELECT COUNT(*) FROM eb_wish_tree_message WHERE tree_id = t.id) as message_count " + + "FROM eb_wish_tree t" + whereSql + " ORDER BY t.sort DESC, t.id DESC LIMIT ?, ?"; + params.add((page - 1) * limit); + params.add(limit); + List> list = jdbcTemplate.queryForList(sql, params.toArray()); + + CommonPage> result = new CommonPage<>(); + result.setList(list); + result.setTotal(total != null ? total.longValue() : 0L); + result.setPage(page); + result.setLimit(limit); + result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / limit)); + + return CommonResult.success(result); + } catch (Exception e) { + log.error("获取许愿树列表失败", e); + return CommonResult.failed("获取列表失败:" + e.getMessage()); + } + } + + /** + * 许愿树详情(含节点) + */ + @ApiOperation(value = "许愿树详情") + @RequestMapping(value = "/info/{id}", method = RequestMethod.GET) + public CommonResult> getInfo(@PathVariable Integer id) { + try { + String sql = "SELECT * FROM eb_wish_tree WHERE id = ?"; + Map data = jdbcTemplate.queryForMap(sql, id); + + // 查询节点列表 + String nodeSql = "SELECT * FROM eb_wish_tree_node WHERE tree_id = ? ORDER BY sort DESC, id ASC"; + List> nodes = jdbcTemplate.queryForList(nodeSql, id); + data.put("nodes", nodes); + + return CommonResult.success(data); + } catch (Exception e) { + log.error("获取许愿树详情失败", e); + return CommonResult.failed("获取详情失败:" + e.getMessage()); + } + } + + /** + * 新增许愿树(含节点) + */ + @ApiOperation(value = "新增许愿树") + @RequestMapping(value = "/save", method = RequestMethod.POST) + public CommonResult save(@RequestBody Map data) { + try { + // 插入许愿树 + String sql = "INSERT INTO eb_wish_tree (name, description, cover_image, background_image, sort, is_active, create_time, update_time) VALUES (?, ?, ?, ?, ?, 0, NOW(), NOW())"; + jdbcTemplate.update(sql, + data.get("name"), + data.get("description"), + data.get("cover_image"), + data.get("background_image"), + data.get("sort") != null ? data.get("sort") : 0); + + // 获取新插入的ID + Integer treeId = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Integer.class); + + // 插入节点 + @SuppressWarnings("unchecked") + List> nodes = (List>) data.get("nodes"); + if (nodes != null && !nodes.isEmpty()) { + String nodeSql = "INSERT INTO eb_wish_tree_node (tree_id, title, description, icon, open_time, sort, status, create_time, update_time) VALUES (?, ?, ?, ?, ?, ?, 1, NOW(), NOW())"; + for (Map node : nodes) { + jdbcTemplate.update(nodeSql, + treeId, + node.get("title"), + node.get("description"), + node.get("icon"), + node.get("open_time"), + node.get("sort") != null ? node.get("sort") : 0); + } + } + + return CommonResult.success("新增成功"); + } catch (Exception e) { + log.error("新增许愿树失败", e); + return CommonResult.failed("新增失败:" + e.getMessage()); + } + } + + /** + * 更新许愿树(含节点) + */ + @ApiOperation(value = "更新许愿树") + @RequestMapping(value = "/update", method = RequestMethod.POST) + public CommonResult update(@RequestBody Map data) { + try { + Integer treeId = (Integer) data.get("id"); + + // 更新许愿树 + String sql = "UPDATE eb_wish_tree SET name = ?, description = ?, cover_image = ?, background_image = ?, sort = ?, update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, + data.get("name"), + data.get("description"), + data.get("cover_image"), + data.get("background_image"), + data.get("sort"), + treeId); + + // 删除旧节点,重新插入 + jdbcTemplate.update("DELETE FROM eb_wish_tree_node WHERE tree_id = ?", treeId); + + @SuppressWarnings("unchecked") + List> nodes = (List>) data.get("nodes"); + if (nodes != null && !nodes.isEmpty()) { + String nodeSql = "INSERT INTO eb_wish_tree_node (tree_id, title, description, icon, open_time, sort, status, create_time, update_time) VALUES (?, ?, ?, ?, ?, ?, 1, NOW(), NOW())"; + for (Map node : nodes) { + jdbcTemplate.update(nodeSql, + treeId, + node.get("title"), + node.get("description"), + node.get("icon"), + node.get("open_time"), + node.get("sort") != null ? node.get("sort") : 0); + } + } + + return CommonResult.success("更新成功"); + } catch (Exception e) { + log.error("更新许愿树失败", e); + return CommonResult.failed("更新失败:" + e.getMessage()); + } + } + + /** + * 删除许愿树 + */ + @ApiOperation(value = "删除许愿树") + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + public CommonResult delete(@PathVariable Integer id) { + try { + // 删除留言 + jdbcTemplate.update("DELETE FROM eb_wish_tree_message WHERE tree_id = ?", id); + // 删除节点 + jdbcTemplate.update("DELETE FROM eb_wish_tree_node WHERE tree_id = ?", id); + // 删除许愿树 + jdbcTemplate.update("DELETE FROM eb_wish_tree WHERE id = ?", id); + return CommonResult.success("删除成功"); + } catch (Exception e) { + log.error("删除许愿树失败", e); + return CommonResult.failed("删除失败:" + e.getMessage()); + } + } + + /** + * 启用/停用许愿树 + */ + @ApiOperation(value = "启用/停用许愿树") + @RequestMapping(value = "/activate/{id}", method = RequestMethod.POST) + public CommonResult activate(@PathVariable Integer id) { + try { + // 查询当前状态 + Integer currentStatus = jdbcTemplate.queryForObject("SELECT is_active FROM eb_wish_tree WHERE id = ?", Integer.class, id); + if (currentStatus != null && currentStatus == 1) { + // 当前是启用状态,改为停用 + jdbcTemplate.update("UPDATE eb_wish_tree SET is_active = 0, update_time = NOW() WHERE id = ?", id); + } else { + // 当前是停用状态,改为启用 + jdbcTemplate.update("UPDATE eb_wish_tree SET is_active = 1, update_time = NOW() WHERE id = ?", id); + } + return CommonResult.success("操作成功"); + } catch (Exception e) { + log.error("启用/停用许愿树失败", e); + return CommonResult.failed("操作失败:" + e.getMessage()); + } + } +} diff --git a/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeMessageController.java b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeMessageController.java new file mode 100644 index 00000000..dd06b8f5 --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeMessageController.java @@ -0,0 +1,136 @@ +package com.zbkj.admin.controller; + +import com.zbkj.common.page.CommonPage; +import com.zbkj.common.result.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 许愿树用户留言管理 Controller + */ +@Slf4j +@RestController +@RequestMapping("api/admin/wish/tree/message") +@Api(tags = "许愿树用户留言管理") +@Validated +public class WishTreeMessageController { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 留言列表 + */ + @ApiOperation(value = "留言列表") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult>> getList( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "limit", defaultValue = "10") Integer limit, + @RequestParam(value = "tree_id", required = false) Integer treeId, + @RequestParam(value = "node_id", required = false) Integer nodeId, + @RequestParam(value = "nickname", required = false) String nickname, + @RequestParam(value = "status", required = false) Integer status) { + try { + StringBuilder whereSql = new StringBuilder(" WHERE 1=1"); + List params = new ArrayList<>(); + + if (treeId != null) { + whereSql.append(" AND m.tree_id = ?"); + params.add(treeId); + } + if (nodeId != null) { + whereSql.append(" AND m.node_id = ?"); + params.add(nodeId); + } + if (nickname != null && !nickname.isEmpty()) { + whereSql.append(" AND m.user_nickname LIKE ?"); + params.add("%" + nickname + "%"); + } + if (status != null) { + whereSql.append(" AND m.status = ?"); + params.add(status); + } + + String countSql = "SELECT COUNT(*) FROM eb_wish_tree_message m" + whereSql; + Integer total = jdbcTemplate.queryForObject(countSql, params.toArray(), Integer.class); + + // 查询列表,关联节点标题 + String sql = "SELECT m.*, n.title as node_title " + + "FROM eb_wish_tree_message m " + + "LEFT JOIN eb_wish_tree_node n ON m.node_id = n.id" + + whereSql + " ORDER BY m.id DESC LIMIT ?, ?"; + params.add((page - 1) * limit); + params.add(limit); + List> list = jdbcTemplate.queryForList(sql, params.toArray()); + + CommonPage> result = new CommonPage<>(); + result.setList(list); + result.setTotal(total != null ? total.longValue() : 0L); + result.setPage(page); + result.setLimit(limit); + result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / limit)); + + return CommonResult.success(result); + } catch (Exception e) { + log.error("获取留言列表失败", e); + return CommonResult.failed("获取列表失败:" + e.getMessage()); + } + } + + /** + * 留言详情 + */ + @ApiOperation(value = "留言详情") + @RequestMapping(value = "/info/{id}", method = RequestMethod.GET) + public CommonResult> getInfo(@PathVariable Integer id) { + try { + String sql = "SELECT m.*, n.title as node_title FROM eb_wish_tree_message m " + + "LEFT JOIN eb_wish_tree_node n ON m.node_id = n.id WHERE m.id = ?"; + Map data = jdbcTemplate.queryForMap(sql, id); + return CommonResult.success(data); + } catch (Exception e) { + log.error("获取留言详情失败", e); + return CommonResult.failed("获取详情失败:" + e.getMessage()); + } + } + + /** + * 删除留言 + */ + @ApiOperation(value = "删除留言") + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + public CommonResult delete(@PathVariable Integer id) { + try { + jdbcTemplate.update("DELETE FROM eb_wish_tree_message WHERE id = ?", id); + return CommonResult.success("删除成功"); + } catch (Exception e) { + log.error("删除留言失败", e); + return CommonResult.failed("删除失败:" + e.getMessage()); + } + } + + /** + * 修改留言状态 + */ + @ApiOperation(value = "修改留言状态") + @RequestMapping(value = "/status/{id}", method = RequestMethod.POST) + public CommonResult updateStatus(@PathVariable Integer id) { + try { + String sql = "UPDATE eb_wish_tree_message SET status = IF(status = 1, 0, 1), update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, id); + return CommonResult.success("状态修改成功"); + } catch (Exception e) { + log.error("修改留言状态失败", e); + return CommonResult.failed("状态修改失败:" + e.getMessage()); + } + } +} diff --git a/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeNodeController.java b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeNodeController.java new file mode 100644 index 00000000..bba98b06 --- /dev/null +++ b/Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/WishTreeNodeController.java @@ -0,0 +1,181 @@ +package com.zbkj.admin.controller; + +import com.zbkj.common.page.CommonPage; +import com.zbkj.common.result.CommonResult; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 许愿树节点管理 Controller + */ +@Slf4j +@RestController +@RequestMapping("api/admin/wish/tree/node") +@Api(tags = "许愿树节点管理") +@Validated +public class WishTreeNodeController { + + @Autowired + private JdbcTemplate jdbcTemplate; + + /** + * 节点列表 + */ + @ApiOperation(value = "节点列表") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult>> getList( + @RequestParam(value = "page", defaultValue = "1") Integer page, + @RequestParam(value = "limit", defaultValue = "10") Integer limit, + @RequestParam(value = "tree_id", required = false) Integer treeId, + @RequestParam(value = "title", required = false) String title, + @RequestParam(value = "status", required = false) Integer status) { + try { + StringBuilder whereSql = new StringBuilder(" WHERE 1=1"); + List params = new ArrayList<>(); + + if (treeId != null) { + whereSql.append(" AND n.tree_id = ?"); + params.add(treeId); + } + if (title != null && !title.isEmpty()) { + whereSql.append(" AND n.title LIKE ?"); + params.add("%" + title + "%"); + } + if (status != null) { + whereSql.append(" AND n.status = ?"); + params.add(status); + } + + String countSql = "SELECT COUNT(*) FROM eb_wish_tree_node n" + whereSql; + Integer total = jdbcTemplate.queryForObject(countSql, params.toArray(), Integer.class); + + String sql = "SELECT n.*, t.name as tree_name, " + + "(SELECT COUNT(*) FROM eb_wish_tree_message WHERE node_id = n.id) as message_count " + + "FROM eb_wish_tree_node n " + + "LEFT JOIN eb_wish_tree t ON n.tree_id = t.id" + + whereSql + " ORDER BY n.tree_id, n.sort DESC, n.id ASC LIMIT ?, ?"; + params.add((page - 1) * limit); + params.add(limit); + List> list = jdbcTemplate.queryForList(sql, params.toArray()); + + CommonPage> result = new CommonPage<>(); + result.setList(list); + result.setTotal(total != null ? total.longValue() : 0L); + result.setPage(page); + result.setLimit(limit); + result.setTotalPage((int) Math.ceil((double) (total != null ? total : 0) / limit)); + + return CommonResult.success(result); + } catch (Exception e) { + log.error("获取节点列表失败", e); + return CommonResult.failed("获取列表失败:" + e.getMessage()); + } + } + + /** + * 节点详情 + */ + @ApiOperation(value = "节点详情") + @RequestMapping(value = "/info/{id}", method = RequestMethod.GET) + public CommonResult> getInfo(@PathVariable Integer id) { + try { + String sql = "SELECT n.*, t.name as tree_name FROM eb_wish_tree_node n " + + "LEFT JOIN eb_wish_tree t ON n.tree_id = t.id WHERE n.id = ?"; + Map data = jdbcTemplate.queryForMap(sql, id); + return CommonResult.success(data); + } catch (Exception e) { + log.error("获取节点详情失败", e); + return CommonResult.failed("获取详情失败:" + e.getMessage()); + } + } + + /** + * 新增节点 + */ + @ApiOperation(value = "新增节点") + @RequestMapping(value = "/save", method = RequestMethod.POST) + public CommonResult save(@RequestBody Map data) { + try { + String sql = "INSERT INTO eb_wish_tree_node (tree_id, title, description, icon, open_time, sort, status, create_time, update_time) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())"; + jdbcTemplate.update(sql, + data.get("tree_id"), + data.get("title"), + data.get("description"), + data.get("icon"), + data.get("open_time"), + data.get("sort") != null ? data.get("sort") : 0, + data.get("status") != null ? data.get("status") : 1); + return CommonResult.success("新增成功"); + } catch (Exception e) { + log.error("新增节点失败", e); + return CommonResult.failed("新增失败:" + e.getMessage()); + } + } + + /** + * 更新节点 + */ + @ApiOperation(value = "更新节点") + @RequestMapping(value = "/update", method = RequestMethod.POST) + public CommonResult update(@RequestBody Map data) { + try { + String sql = "UPDATE eb_wish_tree_node SET tree_id = ?, title = ?, description = ?, icon = ?, open_time = ?, sort = ?, status = ?, update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, + data.get("tree_id"), + data.get("title"), + data.get("description"), + data.get("icon"), + data.get("open_time"), + data.get("sort"), + data.get("status"), + data.get("id")); + return CommonResult.success("更新成功"); + } catch (Exception e) { + log.error("更新节点失败", e); + return CommonResult.failed("更新失败:" + e.getMessage()); + } + } + + /** + * 删除节点 + */ + @ApiOperation(value = "删除节点") + @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) + public CommonResult delete(@PathVariable Integer id) { + try { + // 先删除节点下的所有留言 + jdbcTemplate.update("DELETE FROM eb_wish_tree_message WHERE node_id = ?", id); + // 再删除节点 + jdbcTemplate.update("DELETE FROM eb_wish_tree_node WHERE id = ?", id); + return CommonResult.success("删除成功"); + } catch (Exception e) { + log.error("删除节点失败", e); + return CommonResult.failed("删除失败:" + e.getMessage()); + } + } + + /** + * 修改节点状态 + */ + @ApiOperation(value = "修改节点状态") + @RequestMapping(value = "/status/{id}", method = RequestMethod.POST) + public CommonResult updateStatus(@PathVariable Integer id) { + try { + String sql = "UPDATE eb_wish_tree_node SET status = IF(status = 1, 0, 1), update_time = NOW() WHERE id = ?"; + jdbcTemplate.update(sql, id); + return CommonResult.success("状态修改成功"); + } catch (Exception e) { + log.error("修改节点状态失败", e); + return CommonResult.failed("状态修改失败:" + e.getMessage()); + } + } +} diff --git a/Zhibo/zhibo-h/sql/create_fate_pool_wish_tree_tables.sql b/Zhibo/zhibo-h/sql/create_fate_pool_wish_tree_tables.sql new file mode 100644 index 00000000..e69de29b diff --git a/缘池与许愿树管理端功能总结.md b/缘池与许愿树管理端功能总结.md new file mode 100644 index 00000000..40170d30 --- /dev/null +++ b/缘池与许愿树管理端功能总结.md @@ -0,0 +1,320 @@ +# 缘池与许愿树管理端功能总结 + +> 更新日期:2025-12-30 + +--- + +## 一、文件结构 + +### 1.1 前端文件 + +``` +Zhibo/admin/src/ +├── api/ +│ ├── fatePool.js # 缘池API +│ └── wishTree.js # 许愿树API +├── router/modules/ +│ ├── fatePool.js # 缘池路由 +│ └── wishTree.js # 许愿树路由 +└── views/ + ├── fatePool/ # 缘池页面 + │ ├── topic/ + │ │ ├── index.vue # 话题管理 + │ │ └── post.vue # 话题发布详情 + │ └── topicUser/ + │ └── index.vue # 用户发布列表 + └── wishTree/ # 许愿树页面 + ├── tree/ + │ ├── index.vue # 许愿树列表 + │ └── detail.vue # 许愿树留言详情 + ├── node/ + │ └── index.vue # 节点管理 + └── message/ + └── index.vue # 用户留言列表 +``` + +### 1.2 后端文件 + +``` +Zhibo/zhibo-h/crmeb-admin/src/main/java/com/zbkj/admin/controller/ +├── FatePoolTopicController.java # 缘池话题管理 +├── FatePoolPostController.java # 缘池用户发布管理 +├── WishTreeController.java # 许愿树管理 +├── WishTreeNodeController.java # 许愿树节点管理 +└── WishTreeMessageController.java # 许愿树留言管理 +``` + +### 1.3 数据库表 + +``` +eb_fate_pool_topic # 缘池话题表 +eb_fate_pool_topic_post # 缘池用户发布表 +eb_wish_tree # 许愿树表 +eb_wish_tree_node # 许愿树节点表 +eb_wish_tree_message # 许愿树留言表 +``` + +--- + +## 二、缘池功能 + +### 2.1 话题管理 + +**页面路径:** `/fatePool/topic` +**页面文件:** `views/fatePool/topic/index.vue` + +| 功能 | 说明 | +|-----|------| +| 话题列表 | 分页展示话题,显示封面、标题、描述、发布数 | +| 搜索 | 按标题模糊搜索、按状态筛选 | +| 新增话题 | 填写标题、描述、封面图URL、排序、状态 | +| 编辑话题 | 修改话题信息 | +| 删除话题 | 删除话题及其下所有发布信息 | +| 状态切换 | 启用/禁用话题 | +| 查看发布 | 跳转到该话题的用户发布列表 | + +**接口列表:** + +| 接口 | 方法 | 路径 | 说明 | +|-----|------|------|------| +| 话题列表 | GET | `/api/admin/fate/pool/topic/list` | 分页查询 | +| 话题详情 | GET | `/api/admin/fate/pool/topic/info/{id}` | 获取单个 | +| 新增话题 | POST | `/api/admin/fate/pool/topic/save` | 创建 | +| 更新话题 | POST | `/api/admin/fate/pool/topic/update` | 修改 | +| 删除话题 | POST | `/api/admin/fate/pool/topic/delete/{id}` | 删除 | +| 修改状态 | POST | `/api/admin/fate/pool/topic/status/{id}` | 切换状态 | + +--- + +### 2.2 用户发布管理 + +**页面路径:** `/fatePool/topicUser` +**页面文件:** `views/fatePool/topicUser/index.vue` + +| 功能 | 说明 | +|-----|------| +| 发布列表 | 分页展示用户发布信息 | +| 搜索 | 按话题筛选、按昵称搜索、按状态筛选 | +| 查看详情 | 弹窗展示完整内容和图片 | +| 删除发布 | 删除用户发布信息 | +| 状态切换 | 显示/隐藏发布信息 | + +**接口列表:** + +| 接口 | 方法 | 路径 | 说明 | +|-----|------|------|------| +| 发布列表 | GET | `/api/admin/fate/pool/post/list` | 分页查询 | +| 发布详情 | GET | `/api/admin/fate/pool/post/info/{id}` | 获取单个 | +| 删除发布 | POST | `/api/admin/fate/pool/post/delete/{id}` | 删除 | +| 修改状态 | POST | `/api/admin/fate/pool/post/status/{id}` | 切换状态 | + +--- + +## 三、许愿树功能 + +### 3.1 许愿树管理 + +**页面路径:** `/wishTree/tree` +**页面文件:** `views/wishTree/tree/index.vue` + +| 功能 | 说明 | +|-----|------| +| 许愿树列表 | 分页展示许愿树,显示封面、名称、节点数、留言数 | +| 搜索 | 按名称模糊搜索 | +| 新增许愿树 | 填写名称、描述、封面图、背景图、排序,可同时添加节点 | +| 编辑许愿树 | 修改许愿树信息和节点 | +| 删除许愿树 | 删除许愿树及其所有节点和留言 | +| 启用/停用 | 设置许愿树启用状态 | +| 查看留言 | 跳转到该许愿树的留言列表 | + +**接口列表:** + +| 接口 | 方法 | 路径 | 说明 | +|-----|------|------|------| +| 许愿树列表 | GET | `/api/admin/wish/tree/list` | 分页查询 | +| 许愿树详情 | GET | `/api/admin/wish/tree/info/{id}` | 获取详情(含节点) | +| 新增许愿树 | POST | `/api/admin/wish/tree/save` | 创建(含节点) | +| 更新许愿树 | POST | `/api/admin/wish/tree/update` | 修改(含节点) | +| 删除许愿树 | POST | `/api/admin/wish/tree/delete/{id}` | 删除 | +| 启用/停用 | POST | `/api/admin/wish/tree/activate/{id}` | 切换启用状态 | + +--- + +### 3.2 节点管理 + +**页面路径:** `/wishTree/node` +**页面文件:** `views/wishTree/node/index.vue` + +| 功能 | 说明 | +|-----|------| +| 节点列表 | 分页展示所有节点,显示所属许愿树、标题、开启时间、留言数 | +| 搜索 | 按许愿树筛选、按标题搜索、按状态筛选 | +| 新增节点 | 选择许愿树、填写标题、描述、图标、开启时间、排序 | +| 编辑节点 | 修改节点信息 | +| 删除节点 | 删除节点及其所有留言 | +| 状态切换 | 启用/禁用节点 | + +**接口列表:** + +| 接口 | 方法 | 路径 | 说明 | +|-----|------|------|------| +| 节点列表 | GET | `/api/admin/wish/tree/node/list` | 分页查询 | +| 节点详情 | GET | `/api/admin/wish/tree/node/info/{id}` | 获取单个 | +| 新增节点 | POST | `/api/admin/wish/tree/node/save` | 创建 | +| 更新节点 | POST | `/api/admin/wish/tree/node/update` | 修改 | +| 删除节点 | POST | `/api/admin/wish/tree/node/delete/{id}` | 删除 | +| 修改状态 | POST | `/api/admin/wish/tree/node/status/{id}` | 切换状态 | + +--- + +### 3.3 用户留言管理 + +**页面路径:** `/wishTree/message` +**页面文件:** `views/wishTree/message/index.vue` + +| 功能 | 说明 | +|-----|------| +| 留言列表 | 分页展示用户留言,显示节点、用户信息、内容、匿名状态 | +| 搜索 | 按许愿树/节点筛选、按昵称搜索、按状态筛选 | +| 查看详情 | 弹窗展示完整内容和图片 | +| 删除留言 | 删除用户留言 | +| 状态切换 | 显示/隐藏留言 | + +**接口列表:** + +| 接口 | 方法 | 路径 | 说明 | +|-----|------|------|------| +| 留言列表 | GET | `/api/admin/wish/tree/message/list` | 分页查询 | +| 留言详情 | GET | `/api/admin/wish/tree/message/info/{id}` | 获取单个 | +| 删除留言 | POST | `/api/admin/wish/tree/message/delete/{id}` | 删除 | +| 修改状态 | POST | `/api/admin/wish/tree/message/status/{id}` | 切换状态 | + +--- + +## 四、接口参数说明 + +### 4.1 通用分页参数 + +| 参数 | 类型 | 必填 | 说明 | +|-----|------|------|------| +| page | Integer | 否 | 页码,默认1 | +| limit | Integer | 否 | 每页数量,默认10 | + +### 4.2 缘池话题接口 + +**列表查询参数:** +```json +{ + "page": 1, + "limit": 10, + "title": "关键词", + "status": 1 +} +``` + +**新增/更新参数:** +```json +{ + "id": 1, + "title": "话题标题", + "description": "话题描述", + "cover_image": "https://xxx.com/cover.jpg", + "sort": 100, + "status": 1 +} +``` + +### 4.3 许愿树接口 + +**新增/更新参数(含节点):** +```json +{ + "id": 1, + "name": "许愿树名称", + "description": "描述", + "cover_image": "https://xxx.com/cover.jpg", + "background_image": "https://xxx.com/bg.jpg", + "sort": 100, + "nodes": [ + { + "title": "节点标题", + "description": "节点描述", + "icon": "https://xxx.com/icon.png", + "open_time": "2026-01-01 00:00:00", + "sort": 0 + } + ] +} +``` + +### 4.4 节点接口 + +**列表查询参数:** +```json +{ + "page": 1, + "limit": 10, + "tree_id": 1, + "title": "关键词", + "status": 1 +} +``` + +**新增/更新参数:** +```json +{ + "id": 1, + "tree_id": 1, + "title": "节点标题", + "description": "节点描述", + "icon": "https://xxx.com/icon.png", + "open_time": "2026-01-01 00:00:00", + "sort": 0, + "status": 1 +} +``` + +### 4.5 留言接口 + +**列表查询参数:** +```json +{ + "page": 1, + "limit": 10, + "tree_id": 1, + "node_id": 1, + "nickname": "昵称", + "status": 1 +} +``` + +--- + +## 五、菜单入口 + +管理后台左侧菜单: + +``` +├── 缘池 +│ ├── 话题管理 /fatePool/topic +│ └── 用户发布 /fatePool/topicUser +└── 许愿树 + ├── 许愿树列表 /wishTree/tree + ├── 留言节点 /wishTree/node + └── 用户留言 /wishTree/message +``` + +--- + +## 六、注意事项 + +1. **响应格式**:后端返回 `{code: 200, message: null, data: ...}`,前端 axios 拦截器会直接返回 `data` 部分 + +2. **图片字段**:`images` 字段存储为 JSON 字符串,前端需要解析 + +3. **开启时间**:节点的 `open_time` 为空表示立即开启 + +4. **级联删除**: + - 删除话题会同时删除该话题下所有发布信息 + - 删除许愿树会同时删除所有节点和留言 + - 删除节点会同时删除该节点下所有留言