mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-03-20 11:07:31 +08:00
Compare commits
9 Commits
codex/set-
...
feature/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6730b2882 | ||
|
|
21b1c3317a | ||
|
|
72a915af2e | ||
|
|
f000011994 | ||
|
|
d48c9dc27a | ||
|
|
94f955e50f | ||
|
|
bf94707914 | ||
|
|
209f0ef1f8 | ||
|
|
e2d900759a |
@@ -57,6 +57,9 @@ cd OpenIsle
|
|||||||
--profile dev up -d --force-recreate
|
--profile dev up -d --force-recreate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
数据初始化sql会创建几个帐户供大家测试使用
|
||||||
|
> username:admin/user1/user2 password:123456
|
||||||
|
|
||||||
3. 查看服务状态:
|
3. 查看服务状态:
|
||||||
```shell
|
```shell
|
||||||
docker compose -f docker/docker-compose.yaml --env-file .env ps
|
docker compose -f docker/docker-compose.yaml --env-file .env ps
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import com.openisle.model.User;
|
|||||||
import com.openisle.repository.NotificationRepository;
|
import com.openisle.repository.NotificationRepository;
|
||||||
import com.openisle.repository.UserRepository;
|
import com.openisle.repository.UserRepository;
|
||||||
import com.openisle.service.EmailSender;
|
import com.openisle.service.EmailSender;
|
||||||
|
import com.openisle.exception.EmailSendException;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -17,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/admin/users")
|
@RequestMapping("/api/admin/users")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class AdminUserController {
|
public class AdminUserController {
|
||||||
|
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
@@ -35,11 +38,15 @@ public class AdminUserController {
|
|||||||
user.setApproved(true);
|
user.setApproved(true);
|
||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
markRegisterRequestNotificationsRead(user);
|
markRegisterRequestNotificationsRead(user);
|
||||||
emailSender.sendEmail(
|
try {
|
||||||
user.getEmail(),
|
emailSender.sendEmail(
|
||||||
"您的注册已审核通过",
|
user.getEmail(),
|
||||||
"🎉您的注册已经审核通过, 点击以访问网站: " + websiteUrl
|
"您的注册已审核通过",
|
||||||
);
|
"🎉您的注册已经审核通过, 点击以访问网站: " + websiteUrl
|
||||||
|
);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
log.warn("Failed to send approve email to {}: {}", user.getEmail(), e.getMessage());
|
||||||
|
}
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +59,15 @@ public class AdminUserController {
|
|||||||
user.setApproved(false);
|
user.setApproved(false);
|
||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
markRegisterRequestNotificationsRead(user);
|
markRegisterRequestNotificationsRead(user);
|
||||||
emailSender.sendEmail(
|
try {
|
||||||
user.getEmail(),
|
emailSender.sendEmail(
|
||||||
"您的注册已被管理员拒绝",
|
user.getEmail(),
|
||||||
"您的注册被管理员拒绝, 点击链接可以重新填写理由申请: " + websiteUrl
|
"您的注册已被管理员拒绝",
|
||||||
);
|
"您的注册被管理员拒绝, 点击链接可以重新填写理由申请: " + websiteUrl
|
||||||
|
);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
log.warn("Failed to send reject email to {}: {}", user.getEmail(), e.getMessage());
|
||||||
|
}
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.openisle.controller;
|
|||||||
|
|
||||||
import com.openisle.config.CachingConfig;
|
import com.openisle.config.CachingConfig;
|
||||||
import com.openisle.dto.*;
|
import com.openisle.dto.*;
|
||||||
|
import com.openisle.exception.EmailSendException;
|
||||||
import com.openisle.exception.FieldException;
|
import com.openisle.exception.FieldException;
|
||||||
import com.openisle.model.RegisterMode;
|
import com.openisle.model.RegisterMode;
|
||||||
import com.openisle.model.User;
|
import com.openisle.model.User;
|
||||||
@@ -19,6 +20,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@@ -83,6 +85,17 @@ public class AuthController {
|
|||||||
"INVITE_APPROVED"
|
"INVITE_APPROVED"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body(
|
||||||
|
Map.of(
|
||||||
|
"error",
|
||||||
|
"邮件发送失败: " + e.getMessage(),
|
||||||
|
"reason_code",
|
||||||
|
"EMAIL_SEND_FAILED"
|
||||||
|
)
|
||||||
|
);
|
||||||
} catch (FieldException e) {
|
} catch (FieldException e) {
|
||||||
return ResponseEntity.badRequest().body(
|
return ResponseEntity.badRequest().body(
|
||||||
Map.of("field", e.getField(), "error", e.getMessage())
|
Map.of("field", e.getField(), "error", e.getMessage())
|
||||||
@@ -97,7 +110,20 @@ public class AuthController {
|
|||||||
registerModeService.getRegisterMode()
|
registerModeService.getRegisterMode()
|
||||||
);
|
);
|
||||||
// 发送确认邮件
|
// 发送确认邮件
|
||||||
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
try {
|
||||||
|
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body(
|
||||||
|
Map.of(
|
||||||
|
"error",
|
||||||
|
"邮件发送失败: " + e.getMessage(),
|
||||||
|
"reason_code",
|
||||||
|
"EMAIL_SEND_FAILED"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
if (!user.isApproved()) {
|
if (!user.isApproved()) {
|
||||||
notificationService.createRegisterRequestNotifications(user, user.getRegisterReason());
|
notificationService.createRegisterRequestNotifications(user, user.getRegisterReason());
|
||||||
}
|
}
|
||||||
@@ -169,14 +195,28 @@ public class AuthController {
|
|||||||
}
|
}
|
||||||
User user = userOpt.get();
|
User user = userOpt.get();
|
||||||
if (!user.isVerified()) {
|
if (!user.isVerified()) {
|
||||||
user = userService.register(
|
user =
|
||||||
user.getUsername(),
|
userService.register(
|
||||||
user.getEmail(),
|
user.getUsername(),
|
||||||
user.getPassword(),
|
user.getEmail(),
|
||||||
user.getRegisterReason(),
|
user.getPassword(),
|
||||||
registerModeService.getRegisterMode()
|
user.getRegisterReason(),
|
||||||
);
|
registerModeService.getRegisterMode()
|
||||||
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
);
|
||||||
|
try {
|
||||||
|
userService.sendVerifyMail(user, VerifyType.REGISTER);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body(
|
||||||
|
Map.of(
|
||||||
|
"error",
|
||||||
|
"Failed to send verification email: " + e.getMessage(),
|
||||||
|
"reason_code",
|
||||||
|
"EMAIL_SEND_FAILED"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
return ResponseEntity.badRequest().body(
|
return ResponseEntity.badRequest().body(
|
||||||
Map.of(
|
Map.of(
|
||||||
"error",
|
"error",
|
||||||
@@ -663,7 +703,20 @@ public class AuthController {
|
|||||||
if (userOpt.isEmpty()) {
|
if (userOpt.isEmpty()) {
|
||||||
return ResponseEntity.badRequest().body(Map.of("error", "User not found"));
|
return ResponseEntity.badRequest().body(Map.of("error", "User not found"));
|
||||||
}
|
}
|
||||||
userService.sendVerifyMail(userOpt.get(), VerifyType.RESET_PASSWORD);
|
try {
|
||||||
|
userService.sendVerifyMail(userOpt.get(), VerifyType.RESET_PASSWORD);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
.body(
|
||||||
|
Map.of(
|
||||||
|
"error",
|
||||||
|
"邮件发送失败: " + e.getMessage(),
|
||||||
|
"reason_code",
|
||||||
|
"EMAIL_SEND_FAILED"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
return ResponseEntity.ok(Map.of("message", "Verification code sent"));
|
return ResponseEntity.ok(Map.of("message", "Verification code sent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.openisle.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when email sending fails so callers can surface a clear error upstream.
|
||||||
|
*/
|
||||||
|
public class EmailSendException extends RuntimeException {
|
||||||
|
|
||||||
|
public EmailSendException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmailSendException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import com.openisle.repository.NotificationRepository;
|
|||||||
import com.openisle.repository.ReactionRepository;
|
import com.openisle.repository.ReactionRepository;
|
||||||
import com.openisle.repository.UserRepository;
|
import com.openisle.repository.UserRepository;
|
||||||
import com.openisle.service.EmailSender;
|
import com.openisle.service.EmailSender;
|
||||||
|
import com.openisle.exception.EmailSendException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -17,6 +18,7 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -26,6 +28,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||||||
/** Service for creating and retrieving notifications. */
|
/** Service for creating and retrieving notifications. */
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class NotificationService {
|
public class NotificationService {
|
||||||
|
|
||||||
private final NotificationRepository notificationRepository;
|
private final NotificationRepository notificationRepository;
|
||||||
@@ -108,7 +111,11 @@ public class NotificationService {
|
|||||||
post.getId(),
|
post.getId(),
|
||||||
comment.getId()
|
comment.getId()
|
||||||
);
|
);
|
||||||
emailSender.sendEmail(user.getEmail(), "有人回复了你", url);
|
try {
|
||||||
|
emailSender.sendEmail(user.getEmail(), "有人回复了你", url);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
log.warn("Failed to send notification email to {}: {}", user.getEmail(), e.getMessage());
|
||||||
|
}
|
||||||
sendCustomPush(user, "有人回复了你", url);
|
sendCustomPush(user, "有人回复了你", url);
|
||||||
} else if (type == NotificationType.REACTION && comment != null) {
|
} else if (type == NotificationType.REACTION && comment != null) {
|
||||||
// long count = reactionRepository.countReceived(comment.getAuthor().getUsername());
|
// long count = reactionRepository.countReceived(comment.getAuthor().getUsername());
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import com.openisle.repository.TagRepository;
|
|||||||
import com.openisle.repository.UserRepository;
|
import com.openisle.repository.UserRepository;
|
||||||
import com.openisle.search.SearchIndexEventPublisher;
|
import com.openisle.search.SearchIndexEventPublisher;
|
||||||
import com.openisle.service.EmailSender;
|
import com.openisle.service.EmailSender;
|
||||||
|
import com.openisle.exception.EmailSendException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
@@ -663,11 +664,15 @@ public class PostService {
|
|||||||
w.getEmail() != null &&
|
w.getEmail() != null &&
|
||||||
!w.getDisabledEmailNotificationTypes().contains(NotificationType.LOTTERY_WIN)
|
!w.getDisabledEmailNotificationTypes().contains(NotificationType.LOTTERY_WIN)
|
||||||
) {
|
) {
|
||||||
emailSender.sendEmail(
|
try {
|
||||||
w.getEmail(),
|
emailSender.sendEmail(
|
||||||
"你中奖了",
|
w.getEmail(),
|
||||||
"恭喜你在抽奖贴 \"" + lp.getTitle() + "\" 中获奖"
|
"你中奖了",
|
||||||
);
|
"恭喜你在抽奖贴 \"" + lp.getTitle() + "\" 中获奖"
|
||||||
|
);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
log.warn("Failed to send lottery win email to {}: {}", w.getEmail(), e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notificationService.createNotification(
|
notificationService.createNotification(
|
||||||
w,
|
w,
|
||||||
@@ -693,11 +698,19 @@ public class PostService {
|
|||||||
.getDisabledEmailNotificationTypes()
|
.getDisabledEmailNotificationTypes()
|
||||||
.contains(NotificationType.LOTTERY_DRAW)
|
.contains(NotificationType.LOTTERY_DRAW)
|
||||||
) {
|
) {
|
||||||
emailSender.sendEmail(
|
try {
|
||||||
lp.getAuthor().getEmail(),
|
emailSender.sendEmail(
|
||||||
"抽奖已开奖",
|
lp.getAuthor().getEmail(),
|
||||||
"您的抽奖贴 \"" + lp.getTitle() + "\" 已开奖"
|
"抽奖已开奖",
|
||||||
);
|
"您的抽奖贴 \"" + lp.getTitle() + "\" 已开奖"
|
||||||
|
);
|
||||||
|
} catch (EmailSendException e) {
|
||||||
|
log.warn(
|
||||||
|
"Failed to send lottery draw email to {}: {}",
|
||||||
|
lp.getAuthor().getEmail(),
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notificationService.createNotification(
|
notificationService.createNotification(
|
||||||
lp.getAuthor(),
|
lp.getAuthor(),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.openisle.service;
|
package com.openisle.service;
|
||||||
|
|
||||||
|
import com.openisle.exception.EmailSendException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@@ -7,8 +8,9 @@ import org.springframework.http.HttpEntity;
|
|||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestClientException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -23,7 +25,6 @@ public class ResendEmailSender extends EmailSender {
|
|||||||
private final RestTemplate restTemplate = new RestTemplate();
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Async("notificationExecutor")
|
|
||||||
public void sendEmail(String to, String subject, String text) {
|
public void sendEmail(String to, String subject, String text) {
|
||||||
String url = "https://api.resend.com/emails"; // hypothetical endpoint
|
String url = "https://api.resend.com/emails"; // hypothetical endpoint
|
||||||
|
|
||||||
@@ -38,6 +39,20 @@ public class ResendEmailSender extends EmailSender {
|
|||||||
body.put("from", "openisle <" + fromEmail + ">");
|
body.put("from", "openisle <" + fromEmail + ">");
|
||||||
|
|
||||||
HttpEntity<Map<String, String>> entity = new HttpEntity<>(body, headers);
|
HttpEntity<Map<String, String>> entity = new HttpEntity<>(body, headers);
|
||||||
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
try {
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(
|
||||||
|
url,
|
||||||
|
HttpMethod.POST,
|
||||||
|
entity,
|
||||||
|
String.class
|
||||||
|
);
|
||||||
|
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
throw new EmailSendException(
|
||||||
|
"Email service returned status " + response.getStatusCodeValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (RestClientException e) {
|
||||||
|
throw new EmailSendException("Failed to send email: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ public class UserService {
|
|||||||
* @param user
|
* @param user
|
||||||
*/
|
*/
|
||||||
public void sendVerifyMail(User user, VerifyType verifyType) {
|
public void sendVerifyMail(User user, VerifyType verifyType) {
|
||||||
// 缓存验证码
|
|
||||||
String code = genCode();
|
String code = genCode();
|
||||||
String key;
|
String key;
|
||||||
String subject;
|
String subject;
|
||||||
@@ -133,8 +132,9 @@ public class UserService {
|
|||||||
subject = "请填写验证码以重置密码(有效期为5分钟)";
|
subject = "请填写验证码以重置密码(有效期为5分钟)";
|
||||||
}
|
}
|
||||||
|
|
||||||
redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES); // 五分钟后验证码过期
|
|
||||||
emailService.sendEmail(user.getEmail(), subject, content);
|
emailService.sendEmail(user.getEmail(), subject, content);
|
||||||
|
// 邮件发送成功后再缓存验证码,避免发送失败时用户收不到但验证被要求
|
||||||
|
redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES); // 五分钟后验证码过期
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ class DailyNewsBot extends BotFather {
|
|||||||
请立即在 https://www.open-isle.com 使用 create_post 发布一篇名为「OpenIsle 每日新闻速递|${dateLabel}」的帖子,并遵循以下要求:
|
请立即在 https://www.open-isle.com 使用 create_post 发布一篇名为「OpenIsle 每日新闻速递|${dateLabel}」的帖子,并遵循以下要求:
|
||||||
1. 发布类型为 NORMAL,categoryId = ${categoryId},tagIds = ${tagIdsText}。
|
1. 发布类型为 NORMAL,categoryId = ${categoryId},tagIds = ${tagIdsText}。
|
||||||
2. 正文以简洁问候开头, 不用再重复标题
|
2. 正文以简洁问候开头, 不用再重复标题
|
||||||
3. 使用 web_search 工具按以下顺序收集资讯,并在正文中以 Markdown 小节呈现:
|
3. 使用 web_search 工具按以下顺序收集资讯,并在正文中以 Markdown 小节呈现, 需要调用3次web_search:
|
||||||
- 「全球区块链与加密」:汇总 CoinDesk 所有重点新闻, 列出至少5条
|
- 「全球区块链与加密」:汇总 coindesk.com 版面所有重点新闻, 列出至少5条
|
||||||
- 「国际新闻速览」:汇总 Reuters 重点头条,关注宏观经济、市场波动或政策变化。列出至少5条
|
- 「国际新闻速览」:汇总 reuters.com 版面重点头条,关注宏观经济、市场波动或政策变化。列出至少5条
|
||||||
- 「AI 行业快讯」:检索全球 AI 领域的重要发布或事件(例如 OpenAI、Google、Meta、国内大模型厂商等)。列出至少5条
|
- 「AI 行业快讯」:检索今天全球 AI 领域的重要发布或事件(例如 OpenAI、Google、Meta、国内大模型厂商等)。列出至少5条
|
||||||
4. 每条新闻采用项目符号,先写结论再给出关键数字或细节,末尾添加来源超链接,格式示例:「**结论** —— 关键细节。(来源:[Reuters](URL))」
|
4. 每条新闻采用项目符号,先写结论再给出关键数字或细节,末尾添加来源超链接,格式示例:「**结论** —— 关键细节。(来源:[Reuters](URL))」
|
||||||
5. 资讯整理完毕后,调用 weather_mcp_server.get_current_weather,列出北京、上海、广州、深圳今日天气,放置在「城市天气」小节下, 本小节可加emoji。
|
5. 资讯整理完毕后,调用 weather_mcp_server.get_current_weather,列出北京、上海、广州、深圳今日天气,放置在「城市天气」小节下, 本小节可加emoji。
|
||||||
6. 最后一节为「今日提醒」,给出 2-3 条与新闻或天气相关的行动建议。
|
6. 最后一节为「今日提醒」,给出 2-3 条与新闻或天气相关的行动建议。
|
||||||
|
|||||||
@@ -58,12 +58,15 @@ const submitLogin = async () => {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ username: username.value, password: password.value }),
|
body: JSON.stringify({ username: username.value, password: password.value }),
|
||||||
})
|
})
|
||||||
const data = await res.json()
|
const data = await res.json().catch(() => ({}))
|
||||||
if (res.ok && data.token) {
|
if (res.ok && data.token) {
|
||||||
setToken(data.token)
|
setToken(data.token)
|
||||||
toast.success('登录成功')
|
toast.success('登录成功')
|
||||||
registerPush()
|
registerPush()
|
||||||
await navigateTo('/', { replace: true })
|
await navigateTo('/', { replace: true })
|
||||||
|
} else if (data.reason_code === 'EMAIL_SEND_FAILED') {
|
||||||
|
const msg = data.error || data.message || res.statusText || '登录失败'
|
||||||
|
toast.error(`${res.status} ${msg} (${data.reason_code})`)
|
||||||
} else if (data.reason_code === 'NOT_VERIFIED') {
|
} else if (data.reason_code === 'NOT_VERIFIED') {
|
||||||
toast.info('当前邮箱未验证,已经为您重新发送验证码')
|
toast.info('当前邮箱未验证,已经为您重新发送验证码')
|
||||||
await navigateTo(
|
await navigateTo(
|
||||||
@@ -76,10 +79,12 @@ const submitLogin = async () => {
|
|||||||
} else if (data.reason_code === 'NOT_APPROVED') {
|
} else if (data.reason_code === 'NOT_APPROVED') {
|
||||||
await navigateTo({ path: '/signup-reason', query: { token: data.token } }, { replace: true })
|
await navigateTo({ path: '/signup-reason', query: { token: data.token } }, { replace: true })
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.error || '登录失败')
|
const msg = data.error || data.message || res.statusText || '登录失败'
|
||||||
|
const reason = data.reason_code ? ` (${data.reason_code})` : ''
|
||||||
|
toast.error(`${res.status} ${msg}${reason}`)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error('登录失败')
|
toast.error(`登录失败: ${e.message}`)
|
||||||
} finally {
|
} finally {
|
||||||
isWaitingForLogin.value = false
|
isWaitingForLogin.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -533,7 +533,7 @@ const {
|
|||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
server: false,
|
server: true,
|
||||||
lazy: false,
|
lazy: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -1395,10 +1395,6 @@ onMounted(async () => {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reaction-action.copy-link:hover {
|
|
||||||
background-color: #e2e2e2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-editor-wrapper {
|
.comment-editor-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,8 +139,7 @@ const sendVerification = async () => {
|
|||||||
inviteToken: inviteToken.value,
|
inviteToken: inviteToken.value,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
isWaitingForEmailSent.value = false
|
const data = await res.json().catch(() => ({}))
|
||||||
const data = await res.json()
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
emailStep.value = 1
|
emailStep.value = 1
|
||||||
toast.success('验证码已发送,请查看邮箱')
|
toast.success('验证码已发送,请查看邮箱')
|
||||||
@@ -149,10 +148,14 @@ const sendVerification = async () => {
|
|||||||
if (data.field === 'email') emailError.value = data.error
|
if (data.field === 'email') emailError.value = data.error
|
||||||
if (data.field === 'password') passwordError.value = data.error
|
if (data.field === 'password') passwordError.value = data.error
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.error || '发送失败')
|
const msg = data.error || data.message || res.statusText || '发送失败'
|
||||||
|
const reason = data.reason_code ? ` (${data.reason_code})` : ''
|
||||||
|
toast.error(`${res.status} ${msg}${reason}`)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error('发送失败')
|
toast.error(`发送失败: ${e.message}`)
|
||||||
|
} finally {
|
||||||
|
isWaitingForEmailSent.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user