zhibo/缘池与许愿树功能开发报告.md

19 KiB
Raw Blame History

缘池与许愿树功能开发详细报告

目录

  1. 项目概述
  2. 缘池移动端功能开发
  3. 许愿树功能修复
  4. 管理端修复
  5. 代码修改详情
  6. 新增文件清单
  7. API对接说明

一、项目概述

本次开发主要完成了以下工作:

  1. 缘池FishPond移动端功能完善包括动态板块加载、图标映射、收起/展开功能
  2. 许愿树管理端路径修复
  3. 管理端API配置和登录页面修复
  4. 远程代码合并与冲突解决

二、缘池移动端功能开发

2.1 FishPondActivity - 缘池主页

功能描述

缘池主页面,展示附近用户轨道、快捷入口、功能板块网格。

主要修改

新增成员变量:

private boolean isCategoryExpanded = true; // 板块是否展开

// 手动查找的视图引用(用于收起/展开功能)
private View categoryContainer;
private View toggleCategoryBtn;
private TextView toggleCategoryText;
private ImageView toggleCategoryIcon;

新增方法 - setupCategoryToggle()

/**
 * 设置板块隐藏/展开功能
 */
private void setupCategoryToggle() {
    // 使用getResources().getIdentifier动态获取ID
    int containerId = getResources().getIdentifier("categoryContainer", "id", getPackageName());
    int btnId = getResources().getIdentifier("toggleCategoryBtn", "id", getPackageName());
    int textId = getResources().getIdentifier("toggleCategoryText", "id", getPackageName());
    int iconId = getResources().getIdentifier("toggleCategoryIcon", "id", getPackageName());
    
    categoryContainer = findViewById(containerId);
    toggleCategoryBtn = findViewById(btnId);
    toggleCategoryText = findViewById(textId);
    toggleCategoryIcon = findViewById(iconId);
    
    if (toggleCategoryBtn != null) {
        toggleCategoryBtn.setOnClickListener(v -> {
            v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
            toggleCategoryVisibility();
        });
    }
}

新增方法 - toggleCategoryVisibility()

/**
 * 切换板块显示/隐藏
 */
private void toggleCategoryVisibility() {
    if (categoryContainer == null) return;
    
    isCategoryExpanded = !isCategoryExpanded;
    
    if (isCategoryExpanded) {
        // 展开动画
        categoryContainer.setVisibility(View.VISIBLE);
        categoryContainer.setAlpha(0f);
        categoryContainer.animate()
                .alpha(1f)
                .setDuration(200)
                .start();
        if (toggleCategoryText != null) {
            toggleCategoryText.setText("收起");
        }
        if (toggleCategoryIcon != null) {
            toggleCategoryIcon.animate()
                    .rotation(0f)
                    .setDuration(200)
                    .start();
        }
    } else {
        // 收起动画
        categoryContainer.animate()
                .alpha(0f)
                .setDuration(200)
                .withEndAction(() -> categoryContainer.setVisibility(View.GONE))
                .start();
        if (toggleCategoryText != null) {
            toggleCategoryText.setText("展开");
        }
        if (toggleCategoryIcon != null) {
            toggleCategoryIcon.animate()
                    .rotation(180f)
                    .setDuration(200)
                    .start();
        }
    }
}

onCreate方法修改

// 新增调用
setupCategoryToggle(); // 设置板块隐藏/展开功能

2.2 CategoryAdapter - 板块适配器

功能描述

动态加载从后端获取的板块列表将管理端Element UI图标映射到Android drawable资源。

完整图标映射表

// ========== Element UI 图标 (管理端使用) ==========
// 用户/社交类 - 粉色用户图标
ICON_MAP.put("el-icon-user", R.drawable.ic_user_24);
ICON_MAP.put("el-icon-user-solid", R.drawable.ic_user_24);
ICON_MAP.put("el-icon-s-custom", R.drawable.ic_user_24);

// 星星/收藏类 - 黄色星星
ICON_MAP.put("el-icon-star-on", R.drawable.ic_star_24);
ICON_MAP.put("el-icon-star-off", R.drawable.ic_star_24);
ICON_MAP.put("el-icon-collection", R.drawable.ic_star_24);

// 手机/移动设备类 - 橙色手机
ICON_MAP.put("el-icon-mobile", R.drawable.ic_smartphone_24);
ICON_MAP.put("el-icon-mobile-phone", R.drawable.ic_smartphone_24);
ICON_MAP.put("el-icon-phone", R.drawable.ic_smartphone_24);

// 耳机/KTV类 - 青色耳机
ICON_MAP.put("el-icon-headset", R.drawable.ic_headset_24);
ICON_MAP.put("el-icon-service", R.drawable.ic_headset_24);

// 麦克风/语音类 - 蓝色麦克风
ICON_MAP.put("el-icon-microphone", R.drawable.ic_voice_24);
ICON_MAP.put("el-icon-mic", R.drawable.ic_voice_24);

// 播放/视频类 - 橙红色播放
ICON_MAP.put("el-icon-video-play", R.drawable.ic_play_circle_24);
ICON_MAP.put("el-icon-caret-right", R.drawable.ic_play_circle_24);
ICON_MAP.put("el-icon-video-camera", R.drawable.ic_play_circle_24);

// 瞄准/射击类 - 橙色瞄准镜
ICON_MAP.put("el-icon-aim", R.drawable.ic_target_24);
ICON_MAP.put("el-icon-position", R.drawable.ic_target_24);
ICON_MAP.put("el-icon-place", R.drawable.ic_target_24);
ICON_MAP.put("el-icon-location", R.drawable.ic_target_24);

// 九宫格/桌游类 - 青绿色网格
ICON_MAP.put("el-icon-grid", R.drawable.ic_grid3x3_24);
ICON_MAP.put("el-icon-menu", R.drawable.ic_grid3x3_24);
ICON_MAP.put("el-icon-s-grid", R.drawable.ic_grid3x3_24);
ICON_MAP.put("el-icon-s-operation", R.drawable.ic_grid3x3_24);

// 游戏手柄类
ICON_MAP.put("el-icon-coordinate", R.drawable.ic_game_24);
ICON_MAP.put("el-icon-trophy", R.drawable.ic_game_24);

// 编辑/绘画类
ICON_MAP.put("el-icon-edit", R.drawable.ic_palette_24);
ICON_MAP.put("el-icon-edit-outline", R.drawable.ic_palette_24);
ICON_MAP.put("el-icon-brush", R.drawable.ic_palette_24);

// 爱心类
ICON_MAP.put("el-icon-chat-dot-round", R.drawable.ic_heart_24);
ICON_MAP.put("el-icon-chat-line-round", R.drawable.ic_heart_24);

// ========== Lucide 图标名称 ==========
ICON_MAP.put("Microphone", R.drawable.ic_voice_24);
ICON_MAP.put("Star", R.drawable.ic_star_24);
ICON_MAP.put("User", R.drawable.ic_user_24);
ICON_MAP.put("Users", R.drawable.ic_user_24);
ICON_MAP.put("Heart", R.drawable.ic_heart_24);
ICON_MAP.put("Gamepad2", R.drawable.ic_game_24);
ICON_MAP.put("Gamepad", R.drawable.ic_game_24);
ICON_MAP.put("Smartphone", R.drawable.ic_smartphone_24);
ICON_MAP.put("Music", R.drawable.ic_headset_24);
ICON_MAP.put("Music2", R.drawable.ic_headset_24);
ICON_MAP.put("Headphones", R.drawable.ic_headset_24);
ICON_MAP.put("Pencil", R.drawable.ic_palette_24);
ICON_MAP.put("Palette", R.drawable.ic_palette_24);
ICON_MAP.put("Target", R.drawable.ic_target_24);
ICON_MAP.put("Crosshair", R.drawable.ic_target_24);
ICON_MAP.put("Dices", R.drawable.ic_grid3x3_24);
ICON_MAP.put("Grid3x3", R.drawable.ic_grid3x3_24);
ICON_MAP.put("Grid", R.drawable.ic_grid3x3_24);
ICON_MAP.put("CirclePlay", R.drawable.ic_play_circle_24);
ICON_MAP.put("Play", R.drawable.ic_play_circle_24);

智能图标匹配方法

private int getIconResource(String iconName) {
    if (iconName == null || iconName.isEmpty()) {
        android.util.Log.d("CategoryAdapter", "图标名称为空,使用默认图标");
        return ICON_MAP.get("default");
    }
    
    // 先尝试精确匹配
    Integer res = ICON_MAP.get(iconName);
    if (res != null) {
        return res;
    }
    
    // 尝试去除空格后匹配
    String trimmed = iconName.trim();
    res = ICON_MAP.get(trimmed);
    if (res != null) {
        return res;
    }
    
    // 尝试小写匹配遍历所有key
    String lowerName = trimmed.toLowerCase();
    for (Map.Entry<String, Integer> entry : ICON_MAP.entrySet()) {
        if (entry.getKey().toLowerCase().equals(lowerName)) {
            return entry.getValue();
        }
    }
    
    // 尝试部分匹配(图标名称包含关键词)
    if (lowerName.contains("star") || lowerName.contains("collection")) {
        return R.drawable.ic_star_24;
    }
    if (lowerName.contains("user") || lowerName.contains("custom")) {
        return R.drawable.ic_user_24;
    }
    if (lowerName.contains("heart") || lowerName.contains("chat")) {
        return R.drawable.ic_heart_24;
    }
    if (lowerName.contains("mobile") || lowerName.contains("phone") || lowerName.contains("smartphone")) {
        return R.drawable.ic_smartphone_24;
    }
    if (lowerName.contains("headset") || lowerName.contains("headphone") || lowerName.contains("service")) {
        return R.drawable.ic_headset_24;
    }
    if (lowerName.contains("video") || lowerName.contains("play") || lowerName.contains("caret")) {
        return R.drawable.ic_play_circle_24;
    }
    if (lowerName.contains("game") || lowerName.contains("trophy") || lowerName.contains("coordinate")) {
        return R.drawable.ic_game_24;
    }
    if (lowerName.contains("mic") || lowerName.contains("voice")) {
        return R.drawable.ic_voice_24;
    }
    if (lowerName.contains("edit") || lowerName.contains("pencil") || lowerName.contains("brush") || lowerName.contains("palette")) {
        return R.drawable.ic_palette_24;
    }
    if (lowerName.contains("aim") || lowerName.contains("target") || lowerName.contains("crosshair") || lowerName.contains("position") || lowerName.contains("location")) {
        return R.drawable.ic_target_24;
    }
    if (lowerName.contains("grid") || lowerName.contains("dice") || lowerName.contains("menu")) {
        return R.drawable.ic_grid3x3_24;
    }
    
    return ICON_MAP.get("default");
}

2.3 activity_fish_pond.xml - 布局修改

新增板块容器和收起按钮

<!-- 板块区域容器 -->
<LinearLayout
    android:id="@+id/categoryContainer"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:orientation="vertical"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/actionLeft">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/categoryGrid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:overScrollMode="never" />

</LinearLayout>

<!-- 隐藏/展开按钮 -->
<LinearLayout
    android:id="@+id/toggleCategoryBtn"
    android:layout_width="wrap_content"
    android:layout_height="36dp"
    android:layout_marginTop="12dp"
    android:layout_marginBottom="8dp"
    android:background="@drawable/bg_white_16"
    android:clickable="true"
    android:focusable="true"
    android:gravity="center"
    android:orientation="horizontal"
    android:paddingStart="20dp"
    android:paddingEnd="20dp"
    android:elevation="2dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/categoryContainer">

    <TextView
        android:id="@+id/toggleCategoryText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="收起"
        android:textColor="#9966CC"
        android:textSize="13sp" />

    <ImageView
        android:id="@+id/toggleCategoryIcon"
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_marginStart="4dp"
        android:src="@drawable/ic_expand_less_24"
        android:tint="#9966CC" />

</LinearLayout>

修复布局结构

  • 添加缺失的 orbitContainer 开始标签
  • 修复 LinearLayoutNestedScrollView 闭合标签

三、许愿树功能修复

3.1 路由文件修复

文件: Zhibo/admin/src/router/modules/wishtreeManage.js

修改内容: 将所有视图路径从大写 wishTree 改为小写 wishtree

// 修改前
component: () => import('@/views/wishTree/festival/index')

// 修改后
component: () => import('@/views/wishtree/festival/index')

涉及的路由:

  • /wishtree/festival - 节日管理
  • /wishtree/wish - 心愿管理
  • /wishtree/background - 背景素材
  • /wishtree/statistics - 数据统计
  • /wishtree/tree - 许愿树列表
  • /wishtree/tree/detail/:id - 许愿树详情
  • /wishtree/node - 节点管理
  • /wishtree/message - 留言管理

3.2 API文件重命名

操作:Zhibo/admin/src/api/wishTree.js 重命名为 wishtree.js

原因: 视图文件中引用的是 @/api/wishtree(小写),但实际文件名是 wishTree.js大写T


四、管理端修复

4.1 API地址配置

文件: Zhibo/admin/.env.development

# 修改前
VUE_APP_BASE_API = 'http://192.168.1.244:30001'

# 修改后
VUE_APP_BASE_API = 'http://192.168.1.244:8081'

4.2 登录页面修复

文件: Zhibo/admin/src/views/login/index.vue

修改内容: 添加空值检查,防止后端返回空数据时报错

// 修改前
getInfo() {
  getLoginPicApi().then((res) => {
    this.swiperList = res.banner;
    this.loginLogo = res.loginLogo;
    this.backgroundImages = res.backgroundImage;
    localStorage.setItem('singleAdminSiteName', res.siteName);
  });
},

// 修改后
getInfo() {
  getLoginPicApi().then((res) => {
    if (res) {
      this.swiperList = res.banner || [];
      this.loginLogo = res.loginLogo || '';
      this.backgroundImages = res.backgroundImage || '';
      localStorage.setItem('singleAdminSiteName', res.siteName || '');
    }
  }).catch(() => {
    // 忽略获取登录图片的错误
  });
},

五、代码修改详情

5.1 修改文件列表

文件路径 修改类型 说明
android-app/.../FishPondActivity.java 修改 添加板块收起/展开功能
android-app/.../CategoryAdapter.java 修改 完善图标映射和智能匹配
android-app/.../activity_fish_pond.xml 修改 添加收起按钮布局
Zhibo/admin/.../wishtreeManage.js 修改 修复路由路径
Zhibo/admin/.../login/index.vue 修改 添加空值检查
Zhibo/admin/.env.development 修改 修复API端口
Zhibo/admin/src/api/wishtree.js 重命名 从wishTree.js重命名

六、新增文件清单

6.1 图标资源文件

ic_user_24.xml - 用户图标(粉色)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#FF6B9D"
        android:pathData="M12,12a4,4 0,1 0,-4 -4a4,4 0,0 0,4 4zm0,2c-4.42,0 -8,2.24 -8,5v1h16v-1c0,-2.76 -3.58,-5 -8,-5z" />
</vector>

ic_smartphone_24.xml - 手机图标(橙色)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#FF7043"
        android:pathData="M17,1H7C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1 17,1zM17,19H7V5h10V19zM12,17.5c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1s-1,0.45 -1,1S11.45,17.5 12,17.5z" />
</vector>

ic_headset_24.xml - 耳机图标(青色)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#26C6DA"
        android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03,-9 -9,-9z" />
</vector>

ic_play_circle_24.xml - 播放图标(橙红色)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#FF7043"
        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM10,16.5v-9l6,4.5L10,16.5z" />
</vector>

ic_target_24.xml - 瞄准图标(橙色)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#FF7043"
        android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4s4,-1.79 4,-4S14.21,8 12,8zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8c1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12C20,16.42 16.42,20 12,20z" />
</vector>

ic_grid3x3_24.xml - 九宫格图标(青绿色)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#26A69A"
        android:pathData="M4,4h4v4H4V4zM10,4h4v4h-4V4zM16,4h4v4h-4V4zM4,10h4v4H4v-4zM10,10h4v4h-4v-4zM16,10h4v4h-4v-4zM4,16h4v4H4v-4zM10,16h4v4h-4v-4zM16,16h4v4h-4v-4z" />
</vector>

七、API对接说明

7.1 缘池相关API

API 方法 说明
/api/front/community/categories GET 获取板块列表
/api/front/community/messages GET 获取消息列表支持categoryId筛选
/api/front/community/messages POST 发布消息
/api/front/community/nearby-users GET 获取附近用户

7.2 数据结构

Category板块

{
  "id": 1,
  "name": "在线处对象",
  "icon": "el-icon-user",
  "type": "card",
  "jumpPage": "OnlineDatingActivity",
  "sort": 90,
  "status": 1
}

Message消息

{
  "id": 1,
  "uid": 100,
  "nickname": "用户昵称",
  "avatar": "头像URL",
  "categoryId": 1,
  "categoryName": "在线处对象",
  "content": "消息内容",
  "images": "图片URL1,图片URL2",
  "status": 1,
  "createTime": "2026-01-02 12:00:00"
}

八、功能验证清单

8.1 缘池功能

  • 板块从后端动态加载
  • 图标根据管理端设置显示
  • 板块收起/展开动画
  • 点击板块跳转对应页面
  • 附近用户轨道展示

8.2 许愿树功能

  • 管理端路由正常访问
  • API接口正常调用

8.3 管理端

  • 登录页面正常显示
  • API连接正常8081端口

报告生成时间2026年1月2日 开发环境Windows / Android Studio / Vue.js