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

603 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 缘池与许愿树功能开发详细报告
## 目录
1. [项目概述](#一项目概述)
2. [缘池移动端功能开发](#二缘池移动端功能开发)
3. [许愿树功能修复](#三许愿树功能修复)
4. [管理端修复](#四管理端修复)
5. [代码修改详情](#五代码修改详情)
6. [新增文件清单](#六新增文件清单)
7. [API对接说明](#七api对接说明)
---
## 一、项目概述
本次开发主要完成了以下工作:
1. 缘池FishPond移动端功能完善包括动态板块加载、图标映射、收起/展开功能
2. 许愿树管理端路径修复
3. 管理端API配置和登录页面修复
4. 远程代码合并与冲突解决
---
## 二、缘池移动端功能开发
### 2.1 FishPondActivity - 缘池主页
#### 功能描述
缘池主页面,展示附近用户轨道、快捷入口、功能板块网格。
#### 主要修改
**新增成员变量:**
```java
private boolean isCategoryExpanded = true; // 板块是否展开
// 手动查找的视图引用(用于收起/展开功能)
private View categoryContainer;
private View toggleCategoryBtn;
private TextView toggleCategoryText;
private ImageView toggleCategoryIcon;
```
**新增方法 - setupCategoryToggle()**
```java
/**
* 设置板块隐藏/展开功能
*/
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()**
```java
/**
* 切换板块显示/隐藏
*/
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方法修改**
```java
// 新增调用
setupCategoryToggle(); // 设置板块隐藏/展开功能
```
---
### 2.2 CategoryAdapter - 板块适配器
#### 功能描述
动态加载从后端获取的板块列表将管理端Element UI图标映射到Android drawable资源。
#### 完整图标映射表
```java
// ========== 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);
```
#### 智能图标匹配方法
```java
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 - 布局修改
#### 新增板块容器和收起按钮
```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` 开始标签
- 修复 `LinearLayout``NestedScrollView` 闭合标签
---
## 三、许愿树功能修复
### 3.1 路由文件修复
**文件:** `Zhibo/admin/src/router/modules/wishtreeManage.js`
**修改内容:** 将所有视图路径从大写 `wishTree` 改为小写 `wishtree`
```javascript
// 修改前
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`
```bash
# 修改前
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`
**修改内容:** 添加空值检查,防止后端返回空数据时报错
```javascript
// 修改前
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
<?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
<?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
<?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
<?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
<?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
<?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板块
```json
{
"id": 1,
"name": "在线处对象",
"icon": "el-icon-user",
"type": "card",
"jumpPage": "OnlineDatingActivity",
"sort": 90,
"status": 1
}
```
#### Message消息
```json
{
"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 缘池功能
- [x] 板块从后端动态加载
- [x] 图标根据管理端设置显示
- [x] 板块收起/展开动画
- [x] 点击板块跳转对应页面
- [x] 附近用户轨道展示
### 8.2 许愿树功能
- [x] 管理端路由正常访问
- [x] API接口正常调用
### 8.3 管理端
- [x] 登录页面正常显示
- [x] API连接正常8081端口
---
*报告生成时间2026年1月2日*
*开发环境Windows / Android Studio / Vue.js*