修复问题

This commit is contained in:
xiao12feng8 2025-12-25 19:02:07 +08:00
parent c7e75a912a
commit f4c9a42974
12 changed files with 217 additions and 100 deletions

View File

@ -29,6 +29,16 @@ spring:
url: jdbc:mysql://1.15.149.240:3306/zhibo?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8 url: jdbc:mysql://1.15.149.240:3306/zhibo?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
username: zhibo username: zhibo
password: zCETFpGMwYN3CNeH password: zCETFpGMwYN3CNeH
# JPA 配置 - 只新增字段,不删除已有字段
jpa:
hibernate:
ddl-auto: update # update: 只新增表/字段,不删除
show-sql: false
open-in-view: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
redis: redis:
host: 127.0.0.1 #地址 host: 127.0.0.1 #地址
port: 6379 #端口 port: 6379 #端口

View File

@ -79,6 +79,12 @@
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-boot-starter</artifactId>
</dependency> </dependency>
<!-- JPA 自动建表 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 模板引擎 mybatis code generator时需要使用--> <!-- 模板引擎 mybatis code generator时需要使用-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -9,16 +9,20 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
/** /**
* 私聊会话实体类 * 私聊会话实体类
* 同时支持 MyBatis-Plus JPA
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("eb_conversation") @TableName("eb_conversation")
@Entity
@Table(name = "eb_conversation")
@ApiModel(value = "Conversation对象", description = "私聊会话") @ApiModel(value = "Conversation对象", description = "私聊会话")
public class Conversation implements Serializable { public class Conversation implements Serializable {
@ -26,41 +30,55 @@ public class Conversation implements Serializable {
@ApiModelProperty(value = "会话ID") @ApiModelProperty(value = "会话ID")
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
@ApiModelProperty(value = "用户1的ID") @ApiModelProperty(value = "用户1的ID")
@Column(name = "user1_id", nullable = false)
private Integer user1Id; private Integer user1Id;
@ApiModelProperty(value = "用户2的ID") @ApiModelProperty(value = "用户2的ID")
@Column(name = "user2_id", nullable = false)
private Integer user2Id; private Integer user2Id;
@ApiModelProperty(value = "最后一条消息内容") @ApiModelProperty(value = "最后一条消息内容")
@Column(name = "last_message", length = 500)
private String lastMessage; private String lastMessage;
@ApiModelProperty(value = "最后一条消息时间") @ApiModelProperty(value = "最后一条消息时间")
@Column(name = "last_message_time")
private Date lastMessageTime; private Date lastMessageTime;
@ApiModelProperty(value = "用户1的未读数量") @ApiModelProperty(value = "用户1的未读数量")
@Column(name = "user1_unread_count", columnDefinition = "INT DEFAULT 0")
private Integer user1UnreadCount; private Integer user1UnreadCount;
@ApiModelProperty(value = "用户2的未读数量") @ApiModelProperty(value = "用户2的未读数量")
@Column(name = "user2_unread_count", columnDefinition = "INT DEFAULT 0")
private Integer user2UnreadCount; private Integer user2UnreadCount;
@ApiModelProperty(value = "用户1是否删除会话") @ApiModelProperty(value = "用户1是否删除会话")
@Column(name = "user1_deleted", columnDefinition = "TINYINT(1) DEFAULT 0")
private Boolean user1Deleted; private Boolean user1Deleted;
@ApiModelProperty(value = "用户2是否删除会话") @ApiModelProperty(value = "用户2是否删除会话")
@Column(name = "user2_deleted", columnDefinition = "TINYINT(1) DEFAULT 0")
private Boolean user2Deleted; private Boolean user2Deleted;
@ApiModelProperty(value = "用户1是否静音") @ApiModelProperty(value = "用户1是否静音")
@Column(name = "user1_muted", columnDefinition = "TINYINT(1) DEFAULT 0")
private Boolean user1Muted; private Boolean user1Muted;
@ApiModelProperty(value = "用户2是否静音") @ApiModelProperty(value = "用户2是否静音")
@Column(name = "user2_muted", columnDefinition = "TINYINT(1) DEFAULT 0")
private Boolean user2Muted; private Boolean user2Muted;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
@Column(name = "create_time")
private Date createTime; private Date createTime;
@ApiModelProperty(value = "更新时间") @ApiModelProperty(value = "更新时间")
@Column(name = "update_time")
private Date updateTime; private Date updateTime;
} }

View File

@ -9,16 +9,25 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
/** /**
* 私信消息实体类 * 私信消息实体类
* 同时支持 MyBatis-Plus JPA
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("eb_private_message") @TableName("eb_private_message")
@Entity
@Table(name = "eb_private_message", indexes = {
@Index(name = "idx_conversation_id", columnList = "conversation_id"),
@Index(name = "idx_sender_id", columnList = "sender_id"),
@Index(name = "idx_receiver_id", columnList = "receiver_id"),
@Index(name = "idx_create_time", columnList = "create_time")
})
@ApiModel(value = "PrivateMessage对象", description = "私信消息") @ApiModel(value = "PrivateMessage对象", description = "私信消息")
public class PrivateMessage implements Serializable { public class PrivateMessage implements Serializable {
@ -26,35 +35,47 @@ public class PrivateMessage implements Serializable {
@ApiModelProperty(value = "消息ID") @ApiModelProperty(value = "消息ID")
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
@ApiModelProperty(value = "会话ID") @ApiModelProperty(value = "会话ID")
@Column(name = "conversation_id", nullable = false)
private Long conversationId; private Long conversationId;
@ApiModelProperty(value = "发送者用户ID") @ApiModelProperty(value = "发送者用户ID")
@Column(name = "sender_id", nullable = false)
private Integer senderId; private Integer senderId;
@ApiModelProperty(value = "接收者用户ID") @ApiModelProperty(value = "接收者用户ID")
@Column(name = "receiver_id", nullable = false)
private Integer receiverId; private Integer receiverId;
@ApiModelProperty(value = "消息内容") @ApiModelProperty(value = "消息内容")
@Column(name = "content", columnDefinition = "TEXT")
private String content; private String content;
@ApiModelProperty(value = "消息类型: text, image, file") @ApiModelProperty(value = "消息类型: text, image, file")
@Column(name = "message_type", length = 20, columnDefinition = "VARCHAR(20) DEFAULT 'text'")
private String messageType; private String messageType;
@ApiModelProperty(value = "消息状态: sending, sent, read") @ApiModelProperty(value = "消息状态: sending, sent, read")
@Column(name = "status", length = 20, columnDefinition = "VARCHAR(20) DEFAULT 'sent'")
private String status; private String status;
@ApiModelProperty(value = "是否已删除(发送者)") @ApiModelProperty(value = "是否已删除(发送者)")
@Column(name = "sender_deleted", columnDefinition = "TINYINT(1) DEFAULT 0")
private Boolean senderDeleted; private Boolean senderDeleted;
@ApiModelProperty(value = "是否已删除(接收者)") @ApiModelProperty(value = "是否已删除(接收者)")
@Column(name = "receiver_deleted", columnDefinition = "TINYINT(1) DEFAULT 0")
private Boolean receiverDeleted; private Boolean receiverDeleted;
@ApiModelProperty(value = "创建时间") @ApiModelProperty(value = "创建时间")
@Column(name = "create_time")
private Date createTime; private Date createTime;
@ApiModelProperty(value = "已读时间") @ApiModelProperty(value = "已读时间")
@Column(name = "read_time")
private Date readTime; private Date readTime;
} }

View File

@ -39,6 +39,7 @@ public class StoreCoupon implements Serializable {
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Integer id; private Integer id;
@ApiModelProperty(value = "优惠券名称") @ApiModelProperty(value = "优惠券名称")
private String name; private String name;

View File

@ -4,8 +4,10 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
@ -31,6 +33,8 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) //去掉数据源 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) //去掉数据源
@ComponentScan(basePackages = {"com.zbkj", "com.zbkj.front"}) @ComponentScan(basePackages = {"com.zbkj", "com.zbkj.front"})
@MapperScan(basePackages = {"com.zbkj.**.dao"}) @MapperScan(basePackages = {"com.zbkj.**.dao"})
@EntityScan(basePackages = {"com.zbkj.common.model"}) // JPA实体扫描
@EnableJpaRepositories(basePackages = {"com.zbkj.service.repository"}) // JPA仓库扫描可选
public class CrmebFrontApplication { public class CrmebFrontApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(CrmebFrontApplication.class, args); SpringApplication.run(CrmebFrontApplication.class, args);

View File

@ -51,6 +51,19 @@ spring:
url: jdbc:mysql://1.15.149.240:3306/zhibo?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8 url: jdbc:mysql://1.15.149.240:3306/zhibo?characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
username: zhibo username: zhibo
password: zCETFpGMwYN3CNeH password: zCETFpGMwYN3CNeH
# JPA 配置 - 只新增字段,不删除已有字段
jpa:
hibernate:
ddl-auto: update # update: 只新增表/字段不删除none: 不做任何操作
show-sql: false # 生产环境建议关闭
open-in-view: false # 关闭懒加载视图
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
# 命名策略:将驼峰转为下划线
physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
redis: redis:
host: 127.0.0.1 #地址 host: 127.0.0.1 #地址
port: 6379 #端口 port: 6379 #端口

View File

@ -100,6 +100,13 @@
<version>3.3.1</version> <version>3.3.1</version>
</dependency> </dependency>
<!-- JPA 自动建表 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<!--generator--> <!--generator-->
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>

View File

@ -45,6 +45,7 @@ public class ConversationActivity extends AppCompatActivity {
private static final String EXTRA_CONVERSATION_TITLE = "extra_conversation_title"; private static final String EXTRA_CONVERSATION_TITLE = "extra_conversation_title";
private static final String EXTRA_UNREAD_COUNT = "extra_unread_count"; private static final String EXTRA_UNREAD_COUNT = "extra_unread_count";
private static final int PAGE_SIZE = 20; private static final int PAGE_SIZE = 20;
private static final long POLL_INTERVAL = 3000; // 3秒轮询一次
private ActivityConversationBinding binding; private ActivityConversationBinding binding;
private final OkHttpClient httpClient = new OkHttpClient(); private final OkHttpClient httpClient = new OkHttpClient();
@ -52,6 +53,8 @@ public class ConversationActivity extends AppCompatActivity {
private ConversationMessagesAdapter adapter; private ConversationMessagesAdapter adapter;
private final List<ChatMessage> messages = new ArrayList<>(); private final List<ChatMessage> messages = new ArrayList<>();
private Handler handler; private Handler handler;
private Runnable pollRunnable;
private boolean isPolling = false;
private String conversationId; private String conversationId;
private int currentPage = 1; private int currentPage = 1;
@ -78,7 +81,15 @@ public class ConversationActivity extends AppCompatActivity {
conversationId = getIntent() != null ? getIntent().getStringExtra(EXTRA_CONVERSATION_ID) : null; conversationId = getIntent() != null ? getIntent().getStringExtra(EXTRA_CONVERSATION_ID) : null;
initialUnreadCount = getIntent() != null ? getIntent().getIntExtra(EXTRA_UNREAD_COUNT, 0) : 0; initialUnreadCount = getIntent() != null ? getIntent().getIntExtra(EXTRA_UNREAD_COUNT, 0) : 0;
// 先尝试从 AuthStore 获取 userId
currentUserId = AuthStore.getUserId(this); currentUserId = AuthStore.getUserId(this);
Log.d(TAG, "从AuthStore获取的用户ID: " + currentUserId);
// 如果 userId 为空尝试从用户信息接口获取
if (currentUserId == null || currentUserId.isEmpty()) {
fetchCurrentUserId();
}
binding.backButton.setOnClickListener(new DebounceClickListener() { binding.backButton.setOnClickListener(new DebounceClickListener() {
@Override @Override
@ -99,6 +110,42 @@ public class ConversationActivity extends AppCompatActivity {
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
stopPolling();
}
@Override
protected void onResume() {
super.onResume();
startPolling();
}
/**
* 开始轮询新消息
*/
private void startPolling() {
if (isPolling) return;
isPolling = true;
pollRunnable = new Runnable() {
@Override
public void run() {
if (!isPolling || isFinishing() || isDestroyed()) return;
loadMessagesFromServer();
handler.postDelayed(this, POLL_INTERVAL);
}
};
// 延迟开始轮询避免和初始加载冲突
handler.postDelayed(pollRunnable, POLL_INTERVAL);
}
/**
* 停止轮询
*/
private void stopPolling() {
isPolling = false;
if (pollRunnable != null && handler != null) {
handler.removeCallbacks(pollRunnable);
}
} }
private void setupMessages() { private void setupMessages() {
@ -116,6 +163,58 @@ public class ConversationActivity extends AppCompatActivity {
} }
/**
* 从服务器获取当前用户ID
*/
private void fetchCurrentUserId() {
String token = AuthStore.getToken(this);
if (token == null) {
Log.w(TAG, "未登录无法获取用户ID");
return;
}
String url = ApiConfig.getBaseUrl() + "/api/front/user/info";
Log.d(TAG, "获取用户信息: " + url);
Request request = new Request.Builder()
.url(url)
.addHeader("Authori-zation", token)
.get()
.build();
httpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(TAG, "获取用户信息失败", e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String body = response.body() != null ? response.body().string() : "";
Log.d(TAG, "用户信息响应: " + body);
try {
JSONObject json = new JSONObject(body);
if (json.optInt("code", -1) == 200) {
JSONObject data = json.optJSONObject("data");
if (data != null) {
int uid = data.optInt("uid", 0);
if (uid > 0) {
currentUserId = String.valueOf(uid);
// 保存到 AuthStore
AuthStore.setUserInfo(ConversationActivity.this, currentUserId, data.optString("nickname", ""));
Log.d(TAG, "从服务器获取到用户ID: " + currentUserId);
// 重新加载消息以正确显示
runOnUiThread(() -> loadMessagesFromServer());
}
}
}
} catch (Exception e) {
Log.e(TAG, "解析用户信息失败", e);
}
}
});
}
/** /**
* 从服务器加载消息列表 * 从服务器加载消息列表
*/ */
@ -182,7 +281,7 @@ public class ConversationActivity extends AppCompatActivity {
private ChatMessage parseChatMessage(JSONObject item) { private ChatMessage parseChatMessage(JSONObject item) {
try { try {
String messageId = item.optString("messageId", ""); String messageId = item.optString("messageId", "");
int userId = item.optInt("userId", 0); int senderId = item.optInt("userId", 0); // 后端返回的 userId 实际是 senderId
String username = item.optString("username", "未知用户"); String username = item.optString("username", "未知用户");
String message = item.optString("message", ""); String message = item.optString("message", "");
long timestamp = item.optLong("timestamp", System.currentTimeMillis()); long timestamp = item.optLong("timestamp", System.currentTimeMillis());
@ -191,7 +290,20 @@ public class ConversationActivity extends AppCompatActivity {
boolean isSystem = item.optBoolean("isSystemMessage", false); boolean isSystem = item.optBoolean("isSystemMessage", false);
// 判断是否是自己发送的消息 // 判断是否是自己发送的消息
boolean isMine = currentUserId != null && currentUserId.equals(String.valueOf(userId)); // 每次都重新从 AuthStore 获取最新的 userId确保登录后能正确获取
String myUserId = AuthStore.getUserId(this);
if (myUserId == null || myUserId.isEmpty()) {
myUserId = currentUserId;
} else {
currentUserId = myUserId; // 同步更新
}
boolean isMine = false;
if (myUserId != null && !myUserId.isEmpty() && senderId > 0) {
isMine = myUserId.equals(String.valueOf(senderId));
}
Log.d(TAG, "消息判断: myUserId=" + myUserId + ", senderId=" + senderId + ", isMine=" + isMine);
String displayName = isMine ? "" : username; String displayName = isMine ? "" : username;
ChatMessage.MessageStatus msgStatus; ChatMessage.MessageStatus msgStatus;
@ -457,6 +569,7 @@ public class ConversationActivity extends AppCompatActivity {
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
stopPolling();
handler = null; handler = null;
} }
} }

View File

@ -300,17 +300,17 @@ public class ConversationMessagesAdapter extends ListAdapter<ChatMessage, Recycl
switch (message.getStatus()) { switch (message.getStatus()) {
case SENDING: case SENDING:
statusIcon.setImageResource(R.drawable.ic_clock_24); statusIcon.setImageResource(R.drawable.ic_clock_24);
statusIcon.setColorFilter(itemView.getContext().getColor(android.R.color.darker_gray)); statusIcon.setColorFilter(android.graphics.Color.GRAY, android.graphics.PorterDuff.Mode.SRC_IN);
statusIcon.setVisibility(View.VISIBLE); statusIcon.setVisibility(View.VISIBLE);
break; break;
case SENT: case SENT:
statusIcon.setImageResource(R.drawable.ic_check_24); statusIcon.setImageResource(R.drawable.ic_check_24);
statusIcon.setColorFilter(itemView.getContext().getColor(android.R.color.darker_gray)); statusIcon.setColorFilter(android.graphics.Color.GRAY, android.graphics.PorterDuff.Mode.SRC_IN);
statusIcon.setVisibility(View.VISIBLE); statusIcon.setVisibility(View.VISIBLE);
break; break;
case READ: case READ:
statusIcon.setImageResource(R.drawable.ic_check_double_24); statusIcon.setImageResource(R.drawable.ic_check_double_24);
statusIcon.setColorFilter(0xFF4CAF50); statusIcon.setColorFilter(android.graphics.Color.parseColor("#4CAF50"), android.graphics.PorterDuff.Mode.SRC_IN);
statusIcon.setVisibility(View.VISIBLE); statusIcon.setVisibility(View.VISIBLE);
break; break;
default: default:

View File

@ -100,23 +100,7 @@ public class LoginActivity extends AppCompatActivity {
binding.loginButton.setEnabled(false); binding.loginButton.setEnabled(false);
binding.loadingProgress.setVisibility(View.VISIBLE); binding.loadingProgress.setVisibility(View.VISIBLE);
// ============================================ // 调用后端登录接口
// 测试模式直接使用演示模式登录跳过网络请求
// 当后端接口接入后可以删除此代码恢复下面的网络请求
// ============================================
// 模拟网络请求延迟让用户看到加载状态
binding.getRoot().postDelayed(() -> {
handleDemoModeLogin(account);
}, 500); // 延迟500ms模拟网络请求
// 以下代码在测试模式下被注释接入后端后可以恢复
/*
// TODO: 接入后端接口 - 用户登录
// 接口路径: POST /api/front/loginApiService中已定义
// 请求参数: LoginRequest {account: string, password: string}
// 返回数据格式: ApiResponse<LoginResponse>
// LoginResponse对象应包含: token, userId, nickname, avatarUrl等字段
// 登录成功后保存token到AuthStore并更新用户信息到本地SharedPreferences
ApiClient.getService(getApplicationContext()).login(new LoginRequest(account, password)) ApiClient.getService(getApplicationContext()).login(new LoginRequest(account, password))
.enqueue(new Callback<ApiResponse<LoginResponse>>() { .enqueue(new Callback<ApiResponse<LoginResponse>>() {
@Override @Override
@ -128,15 +112,8 @@ public class LoginActivity extends AppCompatActivity {
ApiResponse<LoginResponse> body = response.body(); ApiResponse<LoginResponse> body = response.body();
LoginResponse loginData = body != null ? body.getData() : null; LoginResponse loginData = body != null ? body.getData() : null;
// 如果响应不成功或数据无效检查是否是后端未接入的情况 // 如果响应不成功或数据无效
if (!response.isSuccessful() || body == null || !body.isOk() || loginData == null) { if (!response.isSuccessful() || body == null || !body.isOk() || loginData == null) {
// 如果是404500等错误可能是后端未接入使用演示模式
if (!response.isSuccessful() && (response.code() == 404 || response.code() == 500 || response.code() == 502 || response.code() == 503)) {
// 后端服务未启动或未接入使用演示模式
handleDemoModeLogin(account);
return;
}
String errorMsg = "登录失败"; String errorMsg = "登录失败";
if (body != null && !TextUtils.isEmpty(body.getMessage())) { if (body != null && !TextUtils.isEmpty(body.getMessage())) {
errorMsg = body.getMessage(); errorMsg = body.getMessage();
@ -158,9 +135,10 @@ public class LoginActivity extends AppCompatActivity {
} }
// 保存用户信息到 AuthStore // 保存用户信息到 AuthStore
AuthStore.setUserInfo(getApplicationContext(), String uid = loginData.getUid();
loginData.getUid(), String nickname = loginData.getNikeName();
loginData.getNikeName()); android.util.Log.d("LoginActivity", "登录返回的 uid: " + uid + ", nickname: " + nickname);
AuthStore.setUserInfo(getApplicationContext(), uid, nickname);
// 保存用户信息到本地 SharedPreferences // 保存用户信息到本地 SharedPreferences
SharedPreferences prefs = getSharedPreferences("profile_prefs", MODE_PRIVATE); SharedPreferences prefs = getSharedPreferences("profile_prefs", MODE_PRIVATE);
@ -171,8 +149,7 @@ public class LoginActivity extends AppCompatActivity {
prefs.edit().putString("profile_phone", loginData.getPhone()).apply(); prefs.edit().putString("profile_phone", loginData.getPhone()).apply();
} }
// 登录成功返回上一页如果是从其他页面跳转过来的 // 登录成功
// 如果是直接打开登录页面则跳转到主页面
Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
// 检查是否有上一个Activity // 检查是否有上一个Activity
@ -194,74 +171,14 @@ public class LoginActivity extends AppCompatActivity {
binding.loginButton.setEnabled(true); binding.loginButton.setEnabled(true);
binding.loadingProgress.setVisibility(View.GONE); binding.loadingProgress.setVisibility(View.GONE);
// 检测是否是网络连接错误后端未启动
boolean isNetworkError = false;
String errorMsg = "网络错误"; String errorMsg = "网络错误";
if (t != null) { if (t != null && t.getMessage() != null) {
String msg = t.getMessage(); errorMsg = "网络错误:" + t.getMessage();
if (msg != null) {
if (msg.contains("Unable to resolve host") ||
msg.contains("timeout") ||
msg.contains("Connection refused") ||
msg.contains("Failed to connect")) {
isNetworkError = true;
errorMsg = "无法连接到服务器,已切换到演示模式";
} else {
errorMsg = "网络错误:" + msg;
} }
}
}
// 如果是网络连接错误后端未接入使用演示模式登录
if (isNetworkError) {
handleDemoModeLogin(account);
} else {
Toast.makeText(LoginActivity.this, errorMsg, Toast.LENGTH_LONG).show(); Toast.makeText(LoginActivity.this, errorMsg, Toast.LENGTH_LONG).show();
} }
}
}); });
*/
} }
/**
* 处理演示模式登录测试模式直接登录成功
*/
private void handleDemoModeLogin(String account) {
// 恢复UI状态
isLoggingIn = false;
binding.loginButton.setEnabled(true);
binding.loadingProgress.setVisibility(View.GONE);
// 测试模式允许任意账号密码登录仅用于开发测试
// 生成一个演示token基于账号
String demoToken = "demo_token_" + account.hashCode();
android.util.Log.d("LoginActivity", "演示模式 - 生成 token: " + demoToken);
AuthStore.setToken(getApplicationContext(), demoToken);
// 保存用户信息到本地
SharedPreferences prefs = getSharedPreferences("profile_prefs", MODE_PRIVATE);
String displayName = account.length() > 0 ? account : "演示用户";
prefs.edit()
.putString("profile_name", displayName)
.putString("user_id", "demo_user_" + account.hashCode())
.apply();
// 登录成功提示
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
// 登录成功返回上一页如果是从其他页面跳转过来的
// 如果是直接打开登录页面则跳转到主页面
// 检查是否有上一个Activity
if (isTaskRoot()) {
// 如果没有上一个Activity跳转到主页面
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
} else {
// 有上一个Activity直接返回
finish();
}
}
} }

View File

@ -51,6 +51,7 @@ public final class AuthStore {
public static void setUserInfo(Context context, @Nullable String userId, @Nullable String nickname) { public static void setUserInfo(Context context, @Nullable String userId, @Nullable String nickname) {
if (context == null) return; if (context == null) return;
Log.d(TAG, "setUserInfo: userId=" + userId + ", nickname=" + nickname);
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE) context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
.edit() .edit()
.putString(KEY_USER_ID, userId) .putString(KEY_USER_ID, userId)
@ -61,8 +62,14 @@ public final class AuthStore {
@Nullable @Nullable
public static String getUserId(Context context) { public static String getUserId(Context context) {
if (context == null) return null; if (context == null) return null;
return context.getSharedPreferences(PREFS, Context.MODE_PRIVATE) String userId = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
.getString(KEY_USER_ID, ""); .getString(KEY_USER_ID, null);
// 确保空字符串也返回 null
if (userId != null && userId.trim().isEmpty()) {
userId = null;
}
Log.d(TAG, "getUserId: " + userId);
return userId;
} }
@Nullable @Nullable