diff --git a/backend/src/main/java/com/danyang/match/platform/chat/config/ChatDisabledFilter.java b/backend/src/main/java/com/danyang/match/platform/chat/config/ChatDisabledFilter.java
new file mode 100644
index 0000000..61fe83c
--- /dev/null
+++ b/backend/src/main/java/com/danyang/match/platform/chat/config/ChatDisabledFilter.java
@@ -0,0 +1,44 @@
+package com.danyang.match.platform.chat.config;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+/**
+ * 产品当前不提供用户之间的即时聊天。
+ *
+ *
在 HTTP 和 WebSocket 握手进入 Controller/Handler 前统一拒绝,
+ * 防止只隐藏小程序入口却留下可调用的通信通道。
+ */
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class ChatDisabledFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+ String path = request.getRequestURI();
+ String context = request.getContextPath();
+ if (context != null && !context.isEmpty() && path.startsWith(context)) {
+ path = path.substring(context.length());
+ }
+ if (path.equals("/conversations") || path.startsWith("/conversations/")
+ || path.equals("/ws/chat") || path.startsWith("/ws/chat/")) {
+ response.setStatus(HttpServletResponse.SC_GONE);
+ response.setContentType("application/json;charset=UTF-8");
+ response.getWriter().write(
+ "{\"success\":false,\"code\":\"CHAT_DISABLED\","
+ + "\"message\":\"平台未提供用户之间的即时聊天功能\",\"data\":null}");
+ return;
+ }
+ filterChain.doFilter(request, response);
+ }
+}
diff --git a/backend/src/main/java/com/danyang/match/platform/match/controller/LikeController.java b/backend/src/main/java/com/danyang/match/platform/match/controller/LikeController.java
index 75189ed..8e02969 100644
--- a/backend/src/main/java/com/danyang/match/platform/match/controller/LikeController.java
+++ b/backend/src/main/java/com/danyang/match/platform/match/controller/LikeController.java
@@ -1,7 +1,5 @@
package com.danyang.match.platform.match.controller;
-import com.danyang.match.platform.chat.entity.Conversation;
-import com.danyang.match.platform.chat.service.ChatService;
import com.danyang.match.platform.match.service.RelationService;
import com.danyang.match.platform.match.service.RelationService.LikeResult;
import com.danyang.match.platform.shared.constant.Constants;
@@ -11,7 +9,6 @@ import com.danyang.match.platform.shared.idempotency.Idempotent;
import com.danyang.match.platform.shared.security.principal.UserPrincipal;
import lombok.Data;
import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
@@ -22,18 +19,16 @@ import org.springframework.web.bind.annotation.*;
* DELETE /api/v1/likes/{targetUserId} — A 取消 Like B
*
* 核心规则:INV-005 未 Mutual 不可聊天
- * 响应契约对齐 miniapp/types/index.d.ts 的 LikeResult:{ relationStatus, mutualMatch, matchedConversationId }
+ * 响应返回关系状态和 Match 结果,不创建用户会话。
*
* 说明:原 /relations/{targetUserId}/like(2026-09-10 版)已被本控制器取代,调用方统一走 /likes。
*/
-@Slf4j
@RestController
@RequestMapping("/likes")
@RequiredArgsConstructor
public class LikeController {
private final RelationService relationService;
- private final ChatService chatService;
@Idempotent
@PostMapping
@@ -44,7 +39,7 @@ public class LikeController {
return ApiResponse.error(ApiResponseCode.BAD_REQUEST, "targetUserId不能为空");
}
LikeResult result = relationService.like(principal.id(), req.targetUserId);
- return ApiResponse.ok(LikeResponse.from(result, ensureConversation(result, principal.id(), req.targetUserId)));
+ return ApiResponse.ok(LikeResponse.from(result));
}
/**
@@ -62,20 +57,8 @@ public class LikeController {
/**
* Mutual 达成时确保会话存在,并返回会话 id —— 前端据此直接跳转聊天页。
*
- * - getOrCreateConversation 幂等,不会重复建会话
- * - 建会话失败不应让 Like 整体失败(Like 已落库),故降级为 null,前端仅提示不跳转
*/
- private String ensureConversation(LikeResult result, String userId, String targetUserId) {
- if (!result.mutual || result.match == null) return null;
- try {
- Conversation conv = chatService.getOrCreateConversation(result.match.getId(), userId, targetUserId);
- return conv.getId();
- } catch (RuntimeException e) {
- log.warn("Mutual 达成但会话创建失败,已降级:user={}, target={}, matchId={}, reason={}",
- userId, targetUserId, result.match.getId(), e.getMessage());
- return null;
- }
- }
+ // 当前产品不提供用户间会话;Match 成功后仅展示结果和公益服务入口。
// ==================== DTO ====================
@@ -89,16 +72,14 @@ public class LikeController {
public static class LikeResponse {
private String relationStatus;
private boolean mutualMatch;
- private String matchedConversationId;
private String matchId;
- public static LikeResponse from(LikeResult r, String matchedConversationId) {
+ public static LikeResponse from(LikeResult r) {
LikeResponse resp = new LikeResponse();
resp.relationStatus = r.mutual
? Constants.RELATION_STATUS_MUTUAL_MATCH
: Constants.RELATION_STATUS_LIKED;
resp.mutualMatch = r.mutual;
- resp.matchedConversationId = matchedConversationId;
resp.matchId = r.match != null ? r.match.getId() : null;
return resp;
}
diff --git a/backend/src/main/java/com/danyang/match/platform/relationship/service/RelationshipService.java b/backend/src/main/java/com/danyang/match/platform/relationship/service/RelationshipService.java
index 0d7ba5d..b2a8f13 100644
--- a/backend/src/main/java/com/danyang/match/platform/relationship/service/RelationshipService.java
+++ b/backend/src/main/java/com/danyang/match/platform/relationship/service/RelationshipService.java
@@ -251,16 +251,7 @@ public class RelationshipService {
matchMapper.insert(match);
}
- // V1.1: 活动互选不自动创建Conversation,需双方确认后由confirmActivityInterest处理
- if (autoCreateConversation) {
- try {
- chatService.getOrCreateConversation(match.getId(), userId, targetUserId);
- log.info("Match后自动创建会话: matchId={}, users={}", match.getId(), userId + "," + targetUserId);
- } catch (Exception e) {
- log.warn("创建会话失败,Match已创建但聊天可能不可用: matchId={}, error={}",
- match.getId(), e.toString(), e);
- }
- }
+ // 当前产品不提供用户间聊天;Match 仅用于结果判定和公益服务引导。
return match;
}
@@ -286,7 +277,6 @@ public class RelationshipService {
result.put("matchReused", true);
result.put("matchId", existingMatch.get().getId());
result.put("status", existingMatch.get().getStatus());
- result.put("conversationAutoCreated", true);
log.info("活动互选复用已有Match: userId={}, partnerId={}, matchId={}", userId, partnerId, existingMatch.get().getId());
return result;
}
@@ -299,20 +289,10 @@ public class RelationshipService {
// 3. 创建新 Match Episode(source=activity_mutual,不自动创建 Conversation)
Match match = createMatch(userId, partnerId, Constants.MATCH_SOURCE_ACTIVITY_MUTUAL, false);
- // V1.1 Phase 16 修复(Gate:互选确认后双方可沟通):双确认后必须开启会话。
- // 此前此处未建会话,仅靠首条消息惰性创建,导致「双方可沟通」的入口不可见。
- // 现显式开启,保证互选成功后聊天入口立即可见。
- try {
- chatService.getOrCreateConversation(match.getId(), match.getUserAId(), match.getUserBId());
- } catch (Exception e) {
- log.warn("活动互选开启会话失败(Match 已创建): matchId={}, error={}", match.getId(), e.toString(), e);
- }
-
Map result = new HashMap<>();
result.put("matchCreated", true);
result.put("matchId", match.getId());
result.put("priorUnmatch", priorUnmatchExists);
- result.put("conversationAutoCreated", true);
log.info("活动互选创建新Match Episode: userId={}, partnerId={}, priorUnmatch={}, matchId={}",
userId, partnerId, priorUnmatchExists, match.getId());
return result;
diff --git a/backend/src/test/java/com/danyang/match/platform/activity_mutual/ActivityMutualConsentServiceTest.java b/backend/src/test/java/com/danyang/match/platform/activity_mutual/ActivityMutualConsentServiceTest.java
index 7c657cd..ffb0eef 100644
--- a/backend/src/test/java/com/danyang/match/platform/activity_mutual/ActivityMutualConsentServiceTest.java
+++ b/backend/src/test/java/com/danyang/match/platform/activity_mutual/ActivityMutualConsentServiceTest.java
@@ -73,7 +73,7 @@ class ActivityMutualConsentServiceTest {
@Test
@DisplayName("Gate: 双确认后形成 Match 并开启 Conversation(此前只打日志,Gate 失败)")
- void doubleConfirmCreatesMatchAndConversation() {
+ void doubleConfirmCreatesMatchWithoutConversation() {
// 第一阶段:建立互选同意记录(二阶段同意)
consentService.createMutualConsent(activityId, userA, userB);
@@ -95,8 +95,8 @@ class ActivityMutualConsentServiceTest {
assertEquals(Constants.MATCH_SOURCE_ACTIVITY_MUTUAL, match.getSource());
// 会话必须已开启(Gate:互选确认后双方可沟通)
- assertTrue(conversationMapper.findByMatchId(match.getId()).isPresent(),
- "双确认后必须已开启 Conversation");
+ assertTrue(conversationMapper.findByMatchId(match.getId()).isEmpty(),
+ "双确认后不得创建用户聊天 Conversation");
// 溯源字段:consent 记录应绑定 match_id
ActivityMutualConsent consent = consentMapper.findByActivityPair(activityId, userA, userB).orElseThrow();
diff --git a/backend/src/test/java/com/danyang/match/platform/chat/ChatPhase09IntegrationTest.java b/backend/src/test/java/com/danyang/match/platform/chat/ChatPhase09IntegrationTest.java
index 8528bc0..cb5ebff 100644
--- a/backend/src/test/java/com/danyang/match/platform/chat/ChatPhase09IntegrationTest.java
+++ b/backend/src/test/java/com/danyang/match/platform/chat/ChatPhase09IntegrationTest.java
@@ -71,6 +71,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureMockMvc
+@Disabled("用户端即时聊天已按产品方案下线")
class ChatPhase09IntegrationTest {
@Autowired private MockMvc mockMvc;
diff --git a/backend/src/test/java/com/danyang/match/platform/invariants/P0FixVerificationTest.java b/backend/src/test/java/com/danyang/match/platform/invariants/P0FixVerificationTest.java
index 8061fcd..50ef95a 100644
--- a/backend/src/test/java/com/danyang/match/platform/invariants/P0FixVerificationTest.java
+++ b/backend/src/test/java/com/danyang/match/platform/invariants/P0FixVerificationTest.java
@@ -94,6 +94,7 @@ class P0FixVerificationTest {
// ==================== P0-1: Block不变量验证 ====================
@Test
+ @Disabled("用户端即时聊天已按产品方案下线")
@DisplayName("INV-003: Block后A不可向B发送消息")
void testBlockPreventsChat() {
relationshipService.like(userA, userB);
@@ -213,7 +214,7 @@ class P0FixVerificationTest {
var convs = conversationMapper.selectList(
new LambdaQueryWrapper()
.eq(com.danyang.match.platform.chat.entity.Conversation::getMatchId, match.getId()));
- assertFalse(convs.isEmpty(), "Match后应自动创建Conversation");
+ assertTrue(convs.isEmpty(), "Match 后不得自动创建 Conversation");
}
// ==================== P1-1: Required全字段过滤验证 ====================
diff --git a/backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerActionGuardTest.java b/backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerActionGuardTest.java
index de5b354..09b5402 100644
--- a/backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerActionGuardTest.java
+++ b/backend/src/test/java/com/danyang/match/platform/matchmaker/MatchmakerActionGuardTest.java
@@ -258,12 +258,12 @@ class MatchmakerActionGuardTest {
// ==================== MM-ACTION-002:会话/关系开启无 operator 触达面 ====================
@Test
- @DisplayName("MM-ACTION-002(负向): operator token 打会话开启端点 → 403(match/conversation 仅用户路径)")
+ @DisplayName("MM-ACTION-002(负向): operator token 打已下线会话端点 → 410")
void operatorCannotOpenConversationFromMatch() throws Exception {
- // 认证层即拒绝(hasRole("USER")),无需真实 match 存在
+ // 用户间会话已全局下线,先于角色鉴权返回 CHAT_DISABLED。
mockMvc.perform(post("/conversations/from-match/{matchId}", "no-such-match")
.header("Authorization", "Bearer " + operatorToken))
- .andExpect(status().isForbidden());
+ .andExpect(status().isGone());
}
// ==================== MM-ACTION-003:must-confirm 语义锁定 ====================
diff --git a/backend/src/test/java/com/danyang/match/platform/relationship/RelationshipProgressPhase12Test.java b/backend/src/test/java/com/danyang/match/platform/relationship/RelationshipProgressPhase12Test.java
index 24e4c35..19b51ae 100644
--- a/backend/src/test/java/com/danyang/match/platform/relationship/RelationshipProgressPhase12Test.java
+++ b/backend/src/test/java/com/danyang/match/platform/relationship/RelationshipProgressPhase12Test.java
@@ -237,7 +237,7 @@ class RelationshipProgressPhase12Test {
// 旧 Match 有会话
Long oldConvCount = conversationMapper.selectCount(
new LambdaQueryWrapper().eq(Conversation::getMatchId, first.getId()));
- assertEquals(1L, oldConvCount, "首个 Match 应有 1 个会话");
+ assertEquals(0L, oldConvCount, "首个 Match 不应有用户聊天会话");
// Unmatch
Match m1 = matchMapper.findById(first.getId()).orElseThrow();
@@ -255,10 +255,10 @@ class RelationshipProgressPhase12Test {
new LambdaQueryWrapper().eq(Conversation::getMatchId, second.getId())),
"新 Match 不应自动继承旧会话(旧聊天权限不恢复)");
- // 且旧会话仍挂在旧 Match 上,不会被新 Match 复用
- assertEquals(1L, conversationMapper.selectCount(
+ // 历史数据为空:本产品不再创建用户聊天会话
+ assertEquals(0L, conversationMapper.selectCount(
new LambdaQueryWrapper().eq(Conversation::getMatchId, first.getId())),
- "旧会话应仍属于旧 Match");
+ "旧 Match 也不应存在用户聊天会话");
}
// ==================== 拒绝 / 恢复 / 退出 ====================
diff --git a/docs/NO-USER-IM-SCOPE-2026-10-15.md b/docs/NO-USER-IM-SCOPE-2026-10-15.md
new file mode 100644
index 0000000..5c54e4d
--- /dev/null
+++ b/docs/NO-USER-IM-SCOPE-2026-10-15.md
@@ -0,0 +1,20 @@
+# 用户端无即时通讯边界(2026-10-15)
+
+## 已确认范围
+
+- 小程序全流程不展示微信群二维码,也不展示或交换手机号、微信号、QQ 等个人联系方式。
+- 小程序不提供用户之间的私信、聊天、会话列表或 WebSocket 双向通讯。
+- 双向意向匹配只产生平台系统通知,并引导用户查看公益活动、公益服务站和公益红娘服务。
+- 活动签到二维码属于活动现场核验,不属于群二维码,继续保留。
+
+## 实施边界
+
+- Like 和活动互选不再创建新 Conversation,不返回 `matchedConversationId`。
+- 后端 `/conversations`、`/conversations/**`、`/ws/chat` 返回 `410 CHAT_DISABLED`;历史聊天数据保留,不再新增或向用户端开放。
+- Nginx `/ws/` 直接返回 `410 CHAT_DISABLED`,避免网关继续代理聊天连接。
+- 小程序不注册消息 Tab、消息页和聊天页;历史源码暂保留用于数据迁移和回归兼容,但不在运行路由中暴露。
+
+## 验收
+
+- `tests/miniapp/no_user_im_contract_test.py`:通过。
+- 仍需在后端容器完成完整 `mvn test -B`,并验证运行中的 REST 聊天接口返回 410。
diff --git a/docs/STATUS.md b/docs/STATUS.md
index 301888d..2d12ae4 100644
--- a/docs/STATUS.md
+++ b/docs/STATUS.md
@@ -899,3 +899,8 @@ docker run --rm --dns 223.5.5.5 --dns 114.114.114.114 `
- 后端镜像已按当前源码重建成功;健康检查通过,未认证通知接口返回 401。
- 活栈 E2E 最新结果:55 passed;剩余 8 errors 为测试容器缺少 Docker CLI,另有活动互选测试依赖容器内 `docker exec`,不能计为完整 E2E 通过。
- 证据:`.mimosa/core-e2e-postgres-test.log`。
+
+## 2026-10-15 无用户 IM 改造
+- 已按确认方案关闭小程序用户私信/聊天入口,不展示微信群二维码。
+- 匹配成功保留平台系统通知,并引导公益活动、服务站、红娘服务。
+- 后端与 Nginx 聊天入口返回 CHAT_DISABLED/410;完整 Maven 回归与运行态验收待本轮完成。
diff --git a/infrastructure/nginx-production.conf b/infrastructure/nginx-production.conf
index dc48f32..6e59896 100644
--- a/infrastructure/nginx-production.conf
+++ b/infrastructure/nginx-production.conf
@@ -147,16 +147,10 @@ http {
proxy_read_timeout 60s;
}
- # WebSocket proxy
+ # 用户间即时聊天已下线,避免网关继续暴露 WebSocket 入口。
location /ws/ {
- limit_req zone=ws burst=20 nodelay;
- proxy_pass http://backend;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_read_timeout 3600s;
+ default_type application/json;
+ return 410 '{"success":false,"code":"CHAT_DISABLED","message":"平台未提供用户之间的即时聊天功能","data":null}';
}
# Auth endpoints (strict rate limiting)
diff --git a/infrastructure/nginx.conf b/infrastructure/nginx.conf
index a9997fb..547141e 100644
--- a/infrastructure/nginx.conf
+++ b/infrastructure/nginx.conf
@@ -68,17 +68,10 @@ http {
add_header Pragma "no-cache";
}
- # WebSocket proxy
+ # 用户间即时聊天已下线,避免网关继续暴露 WebSocket 入口。
location /ws/ {
- proxy_pass $backend_upstream;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_read_timeout 3600s;
+ default_type application/json;
+ return 410 '{"success":false,"code":"CHAT_DISABLED","message":"平台未提供用户之间的即时聊天功能","data":null}';
}
# Auth endpoints - stricter rate limit
diff --git a/miniapp/app.json b/miniapp/app.json
index 257bd57..77f2cff 100644
--- a/miniapp/app.json
+++ b/miniapp/app.json
@@ -5,7 +5,6 @@
"pages": [
"pages/index/index",
"pages/discover/discover",
- "pages/messages/messages",
"pages/activity/activity",
"pages/mine/mine",
"pages/login/login",
@@ -23,7 +22,6 @@
"pages/review-rejected/review-rejected",
"pages/profile-detail/profile-detail",
"pages/fate-center/fate-center",
- "pages/chat/chat",
"pages/activity-detail/activity-detail",
"pages/activity-register/activity-register",
"pages/my-activities/my-activities",
@@ -97,12 +95,6 @@
"iconPath": "assets/tabbar/discover.png",
"selectedIconPath": "assets/tabbar/discover-active.png"
},
- {
- "pagePath": "pages/messages/messages",
- "text": "消息",
- "iconPath": "assets/tabbar/message.png",
- "selectedIconPath": "assets/tabbar/message-active.png"
- },
{
"pagePath": "pages/activity/activity",
"text": "活动",
diff --git a/miniapp/constants/statusEnums.js b/miniapp/constants/statusEnums.js
index 3ffada8..cadc95c 100644
--- a/miniapp/constants/statusEnums.js
+++ b/miniapp/constants/statusEnums.js
@@ -173,7 +173,7 @@ exports.ERROR_USER_MESSAGE = {
[exports.BUSINESS_ERROR_CODE.PROFILE_NOT_APPROVED]: '当前资料尚未通过审核',
[exports.BUSINESS_ERROR_CODE.ACCOUNT_LIMITED]: '账号已被限制,详情请查看账号状态',
[exports.BUSINESS_ERROR_CODE.TARGET_UNAVAILABLE]: '该用户当前不可查看或联系',
- [exports.BUSINESS_ERROR_CODE.MATCH_REQUIRED]: '双方互相喜欢后才能开始聊天',
+ [exports.BUSINESS_ERROR_CODE.MATCH_REQUIRED]: '当前平台未提供用户间即时聊天功能',
[exports.BUSINESS_ERROR_CODE.ACTIVITY_FULL]: '本次活动报名人数已满',
[exports.BUSINESS_ERROR_CODE.ACTIVITY_CLOSED]: '本次活动报名已结束',
[exports.BUSINESS_ERROR_CODE.ALREADY_APPLIED]: '你已经提交过申请',
diff --git a/miniapp/pages.json b/miniapp/pages.json
index 0702f1c..998c630 100644
--- a/miniapp/pages.json
+++ b/miniapp/pages.json
@@ -2,7 +2,6 @@
"pages": [
"pages/index/index",
"pages/discover/discover",
- "pages/messages/messages",
"pages/activity/activity",
"pages/mine/mine",
"pages/login/login",
@@ -20,7 +19,6 @@
"pages/review-rejected/review-rejected",
"pages/profile-detail/profile-detail",
"pages/fate-center/fate-center",
- "pages/chat/chat",
"pages/activity-detail/activity-detail",
"pages/activity-register/activity-register",
"pages/my-activities/my-activities",
@@ -68,12 +66,6 @@
"iconPath": "assets/tabbar/discover.png",
"selectedIconPath": "assets/tabbar/discover-active.png"
},
- {
- "pagePath": "pages/messages/messages",
- "text": "消息",
- "iconPath": "assets/tabbar/message.png",
- "selectedIconPath": "assets/tabbar/message-active.png"
- },
{
"pagePath": "pages/activity/activity",
"text": "活动",
@@ -101,4 +93,4 @@
}
},
"sitemapLocation": "sitemap.json"
-}
\ No newline at end of file
+}
diff --git a/miniapp/pages/activity-matches/activity-matches.js b/miniapp/pages/activity-matches/activity-matches.js
index 99b6764..1bcc573 100644
--- a/miniapp/pages/activity-matches/activity-matches.js
+++ b/miniapp/pages/activity-matches/activity-matches.js
@@ -50,9 +50,4 @@ Page({
});
},
- startChat(userId) {
- wx.navigateTo({
- url: `/pages/chat/chat?userId=${userId}&activityId=${this.data.activityId}`
- });
- }
});
diff --git a/miniapp/pages/activity-matches/activity-matches.wxml b/miniapp/pages/activity-matches/activity-matches.wxml
index 1d98917..7b41379 100644
--- a/miniapp/pages/activity-matches/activity-matches.wxml
+++ b/miniapp/pages/activity-matches/activity-matches.wxml
@@ -24,7 +24,7 @@
{{item.age}}岁 · {{item.locationName || ''}}
-
+ 可查看公益服务
diff --git a/miniapp/pages/activity-mutual-result/activity-mutual-result.ts b/miniapp/pages/activity-mutual-result/activity-mutual-result.ts
index 6f87b72..5f4ef7e 100644
--- a/miniapp/pages/activity-mutual-result/activity-mutual-result.ts
+++ b/miniapp/pages/activity-mutual-result/activity-mutual-result.ts
@@ -18,8 +18,4 @@ Page({
} catch (e) { console.error(e); this.setData({ loading: false }); }
},
- openChat(e: any) {
- const partnerId = e.currentTarget.dataset.partnerid;
- wx.navigateTo({ url: `/pages/chat/chat?partnerId=${partnerId}` });
- }
});
diff --git a/miniapp/pages/activity-mutual-result/activity-mutual-result.wxml b/miniapp/pages/activity-mutual-result/activity-mutual-result.wxml
index 6dbc4a5..e886af2 100644
--- a/miniapp/pages/activity-mutual-result/activity-mutual-result.wxml
+++ b/miniapp/pages/activity-mutual-result/activity-mutual-result.wxml
@@ -27,7 +27,7 @@
-
+ 双方已确认,可查看公益活动和服务站
diff --git a/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.ts b/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.ts
index b2ba634..0175f4f 100644
--- a/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.ts
+++ b/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.ts
@@ -55,10 +55,7 @@ Page({
});
if (res.statusCode === 200 && res.data.success) {
this.setData({ myConfirmed: true, bothConfirmed: res.data.data.bothConfirmed });
- if (res.data.data.bothConfirmed) {
- wx.showToast({ title: '双方已确认!', icon: 'success' });
- setTimeout(() => this.openChat(), 1500);
- }
+ if (res.data.data.bothConfirmed) wx.showToast({ title: '双方已确认,可查看公益服务', icon: 'success' });
}
} catch (e) { wx.showToast({ title: '操作失败', icon: 'none' }); }
},
@@ -76,7 +73,4 @@ Page({
} catch (e) { wx.showToast({ title: '操作失败', icon: 'none' }); }
},
- openChat() {
- wx.navigateTo({ url: `/pages/chat/chat?partnerId=${this.data.partnerId}` });
- }
});
diff --git a/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.wxml b/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.wxml
index 3657a8c..fa28b55 100644
--- a/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.wxml
+++ b/miniapp/pages/activity-mutual-waiting/activity-mutual-waiting.wxml
@@ -7,21 +7,20 @@
✅
双方已确认!
- 你们可以开始聊天了
-
+ 双方意向已确认,可查看公益活动和服务站
⏳
已发送邀请
- 对方确认后你们可以开始聊天
+ 对方确认后将收到平台通知
💬
向对方表达兴趣
- 双方确认后才能开启线上沟通
+ 双方确认后将收到平台通知,并可查看公益服务
diff --git a/miniapp/pages/discover/discover.ts b/miniapp/pages/discover/discover.ts
index 1727f7c..47fa4ed 100644
--- a/miniapp/pages/discover/discover.ts
+++ b/miniapp/pages/discover/discover.ts
@@ -305,10 +305,7 @@ Page({
const result = await matchStore.like(userId);
this.setData({ users: this.data.users.filter((u) => u.userId !== userId) });
if (result?.mutualMatch) {
- appStore.toastSuccess('双向喜欢!可以开始聊天了');
- if (result.matchedConversationId) {
- wx.navigateTo({ url: to.chat(result.matchedConversationId) });
- }
+ appStore.toastSuccess('双向意向匹配成功,可查看公益服务');
} else {
appStore.toastSuccess('已表达喜欢');
}
diff --git a/miniapp/pages/fate-center/fate-center.js b/miniapp/pages/fate-center/fate-center.js
index e3f221b..01276c4 100644
--- a/miniapp/pages/fate-center/fate-center.js
+++ b/miniapp/pages/fate-center/fate-center.js
@@ -141,12 +141,7 @@ Page({
wx.navigateTo({ url: to.detail(userId) });
},
- /** 互相喜欢 → 开始聊天(已 Mutual,符合第 3 条) */
- onStartChat(e) {
- const conversationId = e.currentTarget.dataset.conversationId;
- if (!conversationId) return;
- wx.navigateTo({ url: to.chat(conversationId) });
- },
+ /** 互相喜欢 → 查看资料和公益服务 */
/**
* 喜欢我的人 → 喜欢 TA(like-back)
@@ -163,12 +158,9 @@ Page({
likersList: matchStore.state.likersList.filter((u) => u.userId !== userId),
});
if (result && result.mutualMatch) {
- appStore.toastSuccess('双向喜欢!可以开始聊天了');
+ appStore.toastSuccess('双向意向匹配成功,可查看公益服务');
// 刷新互相喜欢列表
try { await matchStore.fetchMutualList({ pageSize: PAGE_SIZE }); } catch (e2) { /* ignore */ }
- if (result.matchedConversationId) {
- wx.navigateTo({ url: to.chat(result.matchedConversationId) });
- }
} else {
appStore.toastSuccess('已表达喜欢');
}
diff --git a/miniapp/pages/fate-center/fate-center.wxml b/miniapp/pages/fate-center/fate-center.wxml
index a5e78f3..d711966 100644
--- a/miniapp/pages/fate-center/fate-center.wxml
+++ b/miniapp/pages/fate-center/fate-center.wxml
@@ -34,7 +34,7 @@
-
+
@@ -45,7 +45,7 @@
wx:else
illustration="heart"
title="还没有互相喜欢的人"
- description="去「找对象」遇见合适的人,互相喜欢就能聊天啦"
+ description="去「找对象」遇见合适的人,双方匹配后可查看公益服务"
actions="{{[{text:'去「找对象', event:'discover', variant:'primary'}]}}"
bind:action="onEmptyAction"
/>
diff --git a/miniapp/pages/index/index.ts b/miniapp/pages/index/index.ts
index b5f310d..000d05d 100644
--- a/miniapp/pages/index/index.ts
+++ b/miniapp/pages/index/index.ts
@@ -4,7 +4,7 @@
*/
const { authStore, appStore, matchStore } = require('../../stores')
const api = require('../../utils/api')
-// 顶部安全区:实测右上角胶囊按钮矩形,避免品牌栏「消息」入口被胶囊压住(见 utils/nav-metrics.js)
+// 顶部安全区:实测右上角胶囊按钮矩形,避免品牌栏入口被胶囊压住(见 utils/nav-metrics.js)
const { navSafeData } = require('../../utils/nav-metrics')
// 4×2 宫格的视觉映射(tone → index.wxss 的 .tone-* 渐变砖;subtitle → 主标题下的说明行)。
@@ -244,10 +244,7 @@ Page({
const result = await matchStore.like(userId)
this.setData({ recommendations: this.data.recommendations.filter((item) => item.userId !== userId) })
if (result?.mutualMatch) {
- appStore.toastSuccess('双向喜欢!可以开始聊天了')
- if (result.matchedConversationId) {
- wx.navigateTo({ url: `/pages/chat/chat?id=${result.matchedConversationId}` })
- }
+ appStore.toastSuccess('双向意向匹配成功,可查看公益服务')
} else {
appStore.toastSuccess('已表达喜欢')
}
@@ -327,7 +324,7 @@ Page({
wx.navigateTo({ url: '/pages/anti-fraud/anti-fraud' })
},
onArticleTap(e) { wx.navigateTo({ url: `/pages/content-detail/content-detail?id=${e.currentTarget.dataset.id}` }) },
- onMessages() { wx.switchTab({ url: '/pages/messages/messages' }) },
+ onMessages() { wx.navigateTo({ url: '/pages/notifications/notifications' }) },
formatDate(timestamp) {
if (!timestamp) return ''
diff --git a/miniapp/pages/index/index.wxml b/miniapp/pages/index/index.wxml
index ec0d199..cef8b10 100644
--- a/miniapp/pages/index/index.wxml
+++ b/miniapp/pages/index/index.wxml
@@ -9,7 +9,7 @@
- 消息
+ 通知
{{unreadCount}}
diff --git a/miniapp/pages/matchmaker-recommendations/matchmaker-recommendations.js b/miniapp/pages/matchmaker-recommendations/matchmaker-recommendations.js
index d5b32f6..5d86c6f 100644
--- a/miniapp/pages/matchmaker-recommendations/matchmaker-recommendations.js
+++ b/miniapp/pages/matchmaker-recommendations/matchmaker-recommendations.js
@@ -47,8 +47,8 @@ Page({
try {
const result = action === 'like' ? await matchStore.like(userId) : await matchStore.pass(userId);
this.setData({ recommendations: this.data.recommendations.filter((item) => item.userId !== userId) });
- if (action === 'like' && result && result.mutualMatch && result.matchedConversationId) {
- wx.navigateTo({ url: to.chat(result.matchedConversationId) });
+ if (action === 'like' && result && result.mutualMatch) {
+ appStore.toastSuccess('双向意向匹配成功,可查看公益服务');
} else {
appStore.toastSuccess(action === 'like' ? '已表达喜欢' : '已暂不考虑');
}
diff --git a/miniapp/pages/mine/mine.ts b/miniapp/pages/mine/mine.ts
index ee6aaaa..6721fe9 100644
--- a/miniapp/pages/mine/mine.ts
+++ b/miniapp/pages/mine/mine.ts
@@ -119,7 +119,7 @@ Page({
// ============ 匹配 ============
- onGoMessages() { wx.switchTab({ url: ROUTE.TAB.MESSAGES }); },
+ onGoMessages() { wx.navigateTo({ url: ROUTE.SETTINGS.NOTIFICATIONS }); },
onGoLikers() { wx.navigateTo({ url: ROUTE.DETAIL.LIKERS }); },
// ============ 账户与安全 ============
diff --git a/miniapp/pages/profile-detail/profile-detail.js b/miniapp/pages/profile-detail/profile-detail.js
index a93dd2d..70e60a4 100644
--- a/miniapp/pages/profile-detail/profile-detail.js
+++ b/miniapp/pages/profile-detail/profile-detail.js
@@ -163,10 +163,7 @@ Page({
relationStatus: RELATION_STATUS.MUTUAL_MATCH,
actionLoading: false,
});
- appStore.toastSuccess('双向喜欢!可以开始聊天了');
- if (result.matchedConversationId) {
- wx.navigateTo({ url: to.chat(result.matchedConversationId) });
- }
+ appStore.toastSuccess('双向意向匹配成功,可查看公益服务');
} else {
this.setData({
isLiked: true,
@@ -185,19 +182,6 @@ Page({
}
},
- /**
- * 开始聊天(仅 Mutual 后可见,AGENTS 第 3 条)
- */
- onGoChat() {
- const { userId, canChat, profile } = this.data;
- if (!canChat) {
- appStore.toast('双方互相喜欢后才能开始聊天');
- return;
- }
- // matchedConversationId 优先来自最近 like 结果;无则用 userId 占位由 chat 页拉取
- const conversationId = (profile && profile.matchedConversationId) || userId;
- wx.navigateTo({ url: to.chat(conversationId) });
- },
/**
* 举报:跳转 report 页,不在本页处理(AGENTS 第 7 条:举报内容不在此暴露)
diff --git a/miniapp/pages/profile-detail/profile-detail.wxml b/miniapp/pages/profile-detail/profile-detail.wxml
index 9f66a02..cc93ec6 100644
--- a/miniapp/pages/profile-detail/profile-detail.wxml
+++ b/miniapp/pages/profile-detail/profile-detail.wxml
@@ -113,14 +113,6 @@
bind:tap="onReport"
disabled="{{actionLoading}}"
>举报
- 开始聊天
}
*/
diff --git a/miniapp/stores/index.js b/miniapp/stores/index.js
index 714c93e..5d380d9 100644
--- a/miniapp/stores/index.js
+++ b/miniapp/stores/index.js
@@ -15,6 +15,7 @@
const authStore = require('./authStore');
const userStore = require('./userStore');
const matchStore = require('./matchStore');
+// 兼容未注册的历史聊天页面源码;页面与服务端入口均已下线,不在启动流程中初始化。
const messageStore = require('./messageStore');
const activityStore = require('./activityStore');
const matchmakerStore = require('./matchmakerStore');
@@ -128,53 +129,40 @@ function isProfileApproved() {
// ============ 跨 Store 编排 ============
/**
- * 拉黑用户:触发 MatchStore 与 MessageStore 同步副作用
- * - MatchStore:从推荐/Mutual 列表移除该用户
- * - MessageStore:标记对应会话不可发消息(AGENTS 第 4 条)
+ * 拉黑用户:从推荐/Mutual 列表移除该用户。
* @param {string} userId
* @param {string} [reason]
*/
async function blockUser(userId, reason) {
await matchStore.block(userId, reason);
- // 查找对应会话并标记停用
- const conv = messageStore.state.conversations.find(
- (c) => c.targetUserId === userId || c.conversationId === userId,
- );
- if (conv) messageStore.markConversationBlocked(conv.conversationId);
}
/**
- * Like 用户:若返回 mutualMatch=true,自动刷新会话列表
+ * Like 用户:若返回 mutualMatch=true,仅保留匹配结果和公益服务引导。
* @param {string} userId
* @returns {Promise}
*/
async function likeUser(userId) {
const result = await matchStore.like(userId);
- if (result && result.mutualMatch) {
- // Mutual Match 达成,刷新会话列表,让用户能立即开始聊天
- await messageStore.fetchConversations();
- }
return result;
}
/**
- * 解除匹配:触发 MatchStore 与 MessageStore 同步副作用
+ * 解除匹配。
* @param {string} matchId
*/
async function unmatchConversation(matchId) {
await matchStore.unmatch(matchId);
- messageStore.markConversationBlocked(matchId);
}
/**
- * 成功牵手:双确认第二步(仅被请求方调用),成功后刷新 userStore 与会话列表
+ * 成功牵手:双确认第二步(仅被请求方调用),成功后刷新 userStore。
* @param {string} matchId
*/
async function confirmSuccess(matchId) {
const result = await matchStore.confirmSuccess(matchId);
// 成功牵手后关系状态变化,需刷新 userState
try { await userStore.fetchStatus(); } catch (e) { /* 不阻塞主流程 */ }
- try { await messageStore.fetchConversations(); } catch (e) { /* 同上 */ }
return result;
}
@@ -185,14 +173,12 @@ async function confirmSuccess(matchId) {
* 1. appStore.init() — 拉取服务端配置(不阻塞核心)
* 2. authStore.hydrate() — 从本地恢复登录态
* 3. userStore.hydrate() — 从本地恢复用户状态快照
- * 4. messageStore.hydrate() — 从本地恢复未读数(兜底)
* 5. 若已登录,异步刷新 userStore.fetchStatus()(不阻塞启动)
*/
async function bootstrap() {
// 同步阶段:本地状态恢复(避免白屏)
authStore.hydrate();
userStore.hydrate();
- messageStore.hydrate();
// 异步阶段:服务端配置 + 用户状态刷新
// 配置失败不阻塞启动;状态失败由路由守卫处理(跳登录页)
diff --git a/miniapp/stores/matchStore.js b/miniapp/stores/matchStore.js
index f250e20..78dca3d 100644
--- a/miniapp/stores/matchStore.js
+++ b/miniapp/stores/matchStore.js
@@ -163,7 +163,7 @@ class MatchStore extends BaseStore {
/**
* 拉黑用户(Block 优先级最高,AGENTS 第 4 条)
* 拉黑后:本地从推荐/Mutual 列表移除;调用方应跳离当前用户详情页。
- * 跨 Store 副作用由 stores/index.js 编排:通知 messageStore 标记会话不可发消息。
+ * 匹配结果由 stores/index.js 编排,不创建用户间聊天会话。
*/
async block(userId, reason) {
if (this._actionLocks.has(`block:${userId}`)) return;
diff --git a/miniapp/types/index.d.ts b/miniapp/types/index.d.ts
index 69ad0ad..2465432 100644
--- a/miniapp/types/index.d.ts
+++ b/miniapp/types/index.d.ts
@@ -109,7 +109,6 @@ export interface Recommendation extends User {
export interface LikeResult {
relationStatus: RelationStatus;
mutualMatch: boolean;
- matchedConversationId?: string;
}
// ============ Conversation / Message(规范 §35-38, §61-63) ============
diff --git a/miniapp/types/index.ts b/miniapp/types/index.ts
index 03e59fa..e8fa31d 100644
--- a/miniapp/types/index.ts
+++ b/miniapp/types/index.ts
@@ -239,7 +239,6 @@ export interface LikeResult {
mutual: boolean
mutualMatch?: boolean
matchCreated?: boolean
- matchedConversationId?: string
}
// ===== 通知 =====
diff --git a/tests/miniapp/no_user_im_contract_test.py b/tests/miniapp/no_user_im_contract_test.py
new file mode 100644
index 0000000..ebebda5
--- /dev/null
+++ b/tests/miniapp/no_user_im_contract_test.py
@@ -0,0 +1,28 @@
+import json
+from pathlib import Path
+
+
+ROOT = Path(__file__).parents[2]
+
+
+def test_miniapp_has_no_user_chat_pages_or_message_tab():
+ app = json.loads((ROOT / "miniapp" / "app.json").read_text(encoding="utf-8"))
+ assert not any(page in {"pages/messages/messages", "pages/chat/chat"} for page in app["pages"])
+ assert not any(item.get("pagePath") == "pages/messages/messages" for item in app["tabBar"]["list"])
+
+
+def test_match_success_does_not_create_or_return_conversation():
+ like = (ROOT / "backend/src/main/java/com/danyang/match/platform/match/controller/LikeController.java").read_text(encoding="utf-8")
+ relationship = (ROOT / "backend/src/main/java/com/danyang/match/platform/relationship/service/RelationshipService.java").read_text(encoding="utf-8")
+ assert "matchedConversationId" not in like
+ assert "getOrCreateConversation" not in like
+ assert "conversationAutoCreated" not in relationship
+
+
+def test_chat_transport_is_disabled_at_backend_boundary():
+ guard = ROOT / "backend/src/main/java/com/danyang/match/platform/chat/config/ChatDisabledFilter.java"
+ assert guard.exists()
+ source = guard.read_text(encoding="utf-8")
+ assert "/conversations" in source
+ assert "/ws/chat" in source
+ assert "CHAT_DISABLED" in source