refactor: 统一错误处理并优化代码
- 移除重复的错误提示,统一在axios拦截器中处理 - 优化XSS拦截器,添加请求头白名单 - 修复注册码服务的日期处理问题 - 添加403权限错误处理 - 优化分组查询参数处理
This commit is contained in:
@@ -7,6 +7,7 @@ import com.test.bijihoudaun.common.response.ResultCode;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDeniedException;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
@@ -71,6 +72,13 @@ public class GlobalExceptionHandler {
|
|||||||
return R.fail(ResultCode.VALIDATE_FAILED.getCode(), "参数错误");
|
return R.fail(ResultCode.VALIDATE_FAILED.getCode(), "参数错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修复:添加权限拒绝异常处理
|
||||||
|
@ExceptionHandler(AuthorizationDeniedException.class)
|
||||||
|
public R<Void> handleAuthorizationDeniedException(AuthorizationDeniedException e, HttpServletRequest request) {
|
||||||
|
log.warn("Access denied at {}: {}", request.getRequestURI(), e.getMessage());
|
||||||
|
return R.fail(ResultCode.FORBIDDEN.getCode(), "无权操作,需要管理员权限");
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public R<Void> handleException(Exception e, HttpServletRequest request) {
|
public R<Void> handleException(Exception e, HttpServletRequest request) {
|
||||||
log.error("Unexpected error at {} - Error type: {}", request.getRequestURI(), e.getClass().getSimpleName());
|
log.error("Unexpected error at {} - Error type: {}", request.getRequestURI(), e.getClass().getSimpleName());
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
@@ -22,6 +23,7 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@EnableMethodSecurity(prePostEnabled = true)
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XSS 过滤拦截器
|
* XSS 过滤拦截器
|
||||||
@@ -21,6 +25,29 @@ import java.util.Enumeration;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class XSSInterceptor implements HandlerInterceptor {
|
public class XSSInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
// 修复:添加不需要检查的请求头白名单(浏览器标准请求头)
|
||||||
|
private static final Set<String> HEADER_WHITELIST = new HashSet<>(Arrays.asList(
|
||||||
|
"sec-ch-ua",
|
||||||
|
"sec-ch-ua-mobile",
|
||||||
|
"sec-ch-ua-platform",
|
||||||
|
"sec-fetch-dest",
|
||||||
|
"sec-fetch-mode",
|
||||||
|
"sec-fetch-site",
|
||||||
|
"sec-fetch-user",
|
||||||
|
"user-agent",
|
||||||
|
"accept",
|
||||||
|
"accept-encoding",
|
||||||
|
"accept-language",
|
||||||
|
"cache-control",
|
||||||
|
"connection",
|
||||||
|
"host",
|
||||||
|
"referer",
|
||||||
|
"upgrade-insecure-requests",
|
||||||
|
"content-type",
|
||||||
|
"content-length",
|
||||||
|
"origin"
|
||||||
|
));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
// 过滤请求头,发现 XSS 攻击则拒绝请求
|
// 过滤请求头,发现 XSS 攻击则拒绝请求
|
||||||
@@ -46,6 +73,10 @@ public class XSSInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
while (headerNames.hasMoreElements()) {
|
while (headerNames.hasMoreElements()) {
|
||||||
String headerName = headerNames.nextElement();
|
String headerName = headerNames.nextElement();
|
||||||
|
// 修复:跳过白名单中的请求头
|
||||||
|
if (HEADER_WHITELIST.contains(headerName.toLowerCase())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String headerValue = request.getHeader(headerName);
|
String headerValue = request.getHeader(headerName);
|
||||||
if (StrUtil.isNotBlank(headerValue)) {
|
if (StrUtil.isNotBlank(headerValue)) {
|
||||||
String filteredValue = HtmlUtil.filter(headerValue);
|
String filteredValue = HtmlUtil.filter(headerValue);
|
||||||
@@ -84,8 +115,12 @@ public class XSSInterceptor implements HandlerInterceptor {
|
|||||||
response.setContentType("application/json;charset=UTF-8");
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
response.setStatus(400);
|
response.setStatus(400);
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
response.getWriter().write(mapper.writeValueAsString(
|
// 修复:使用 try-with-resources 确保 PrintWriter 关闭
|
||||||
R.fail(ResultCode.FAILED.getCode(), message)
|
try (PrintWriter writer = response.getWriter()) {
|
||||||
));
|
writer.write(mapper.writeValueAsString(
|
||||||
|
R.fail(ResultCode.FAILED.getCode(), message)
|
||||||
|
));
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ import org.apache.ibatis.annotations.Select;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface UserMapper extends BaseMapper<User> {
|
public interface UserMapper extends BaseMapper<User> {
|
||||||
// 自定义查询方法示例
|
// 自定义查询方法示例
|
||||||
@Select("SELECT id, `username`, `password`, `email`, created_at, updated_at, `token`, token_enddata FROM `user` WHERE username = #{username}")
|
@Select("SELECT id, `username`, `password`, `email`, `role`, created_at, updated_at, `token`, token_enddata FROM `user` WHERE username = #{username}")
|
||||||
User findByUsername(String username);
|
User findByUsername(String username);
|
||||||
}
|
}
|
||||||
@@ -18,14 +18,18 @@ import java.util.UUID;
|
|||||||
@Transactional
|
@Transactional
|
||||||
public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMapper, RegistrationCode> implements RegistrationCodeService {
|
public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMapper, RegistrationCode> implements RegistrationCodeService {
|
||||||
|
|
||||||
|
// 修复:定义日期时间格式器
|
||||||
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generateCode(String creator) {
|
public String generateCode(String creator) {
|
||||||
RegistrationCode registrationCode = new RegistrationCode();
|
RegistrationCode registrationCode = new RegistrationCode();
|
||||||
String code = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
|
String code = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
|
||||||
registrationCode.setCode(code);
|
registrationCode.setCode(code);
|
||||||
registrationCode.setCreatedBy(creator);
|
registrationCode.setCreatedBy(creator);
|
||||||
registrationCode.setCreatedAt(LocalDateTime.now().toString());
|
// 修复:使用格式化后的日期字符串
|
||||||
registrationCode.setExpiryTime(LocalDateTime.now().plusDays(1).toString());
|
registrationCode.setCreatedAt(LocalDateTime.now().format(DATE_TIME_FORMATTER));
|
||||||
|
registrationCode.setExpiryTime(LocalDateTime.now().plusDays(1).format(DATE_TIME_FORMATTER));
|
||||||
save(registrationCode);
|
save(registrationCode);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
@@ -41,9 +45,16 @@ public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMap
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDateTime expiryTime = LocalDateTime.parse(registrationCode.getExpiryTime());
|
try {
|
||||||
if (expiryTime.isBefore(LocalDateTime.now())) {
|
// 修复:使用格式器解析日期
|
||||||
remove(queryWrapper); // 注册码过期,删除
|
LocalDateTime expiryTime = LocalDateTime.parse(registrationCode.getExpiryTime(), DATE_TIME_FORMATTER);
|
||||||
|
if (expiryTime.isBefore(LocalDateTime.now())) {
|
||||||
|
remove(queryWrapper); // 注册码过期,删除
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果解析失败(可能是旧数据格式),认为已过期
|
||||||
|
remove(queryWrapper);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +66,7 @@ public class RegistrationCodeServiceImpl extends ServiceImpl<RegistrationCodeMap
|
|||||||
@Override
|
@Override
|
||||||
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
|
@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
|
||||||
public void deleteExpiredCodes() {
|
public void deleteExpiredCodes() {
|
||||||
remove(new QueryWrapper<RegistrationCode>().lt("expiry_time", LocalDateTime.now().toString()));
|
// 修复:使用格式化后的日期字符串进行比较
|
||||||
|
remove(new QueryWrapper<RegistrationCode>().lt("expiry_time", LocalDateTime.now().format(DATE_TIME_FORMATTER)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import axiosApi from '@/utils/axios.js'
|
|||||||
export const groupingId = (data) => axiosApi.get(`/api/markdown/grouping/${encodeURIComponent(data)}`)
|
export const groupingId = (data) => axiosApi.get(`/api/markdown/grouping/${encodeURIComponent(data)}`)
|
||||||
// 获取所有分组
|
// 获取所有分组
|
||||||
export const groupingAll = (data) => {
|
export const groupingAll = (data) => {
|
||||||
const params = new URLSearchParams();
|
if (data) {
|
||||||
if (data) params.append('parentId', data);
|
return axiosApi.get(`/api/groupings?parentId=${encodeURIComponent(data)}`);
|
||||||
return axiosApi.get(`/api/groupings?${params.toString()}`);
|
}
|
||||||
|
return axiosApi.get('/api/groupings');
|
||||||
};
|
};
|
||||||
// 获取所有Markdown文件
|
// 获取所有Markdown文件
|
||||||
export const markdownAll = () => axiosApi.get(`/api/markdown`);
|
export const markdownAll = () => axiosApi.get(`/api/markdown`);
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ const refreshCaptcha = async () => {
|
|||||||
captchaCode.value = '';
|
captchaCode.value = '';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取验证码失败,请重试');
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('获取验证码失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -256,7 +256,8 @@ const resetToHomeView = async () => {
|
|||||||
groupMarkdownFiles.value = await getRecentFiles(100) || [];
|
groupMarkdownFiles.value = await getRecentFiles(100) || [];
|
||||||
updateDisplayedFiles();
|
updateDisplayedFiles();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取最近文件失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('获取最近文件失败:', error);
|
||||||
groupMarkdownFiles.value = [];
|
groupMarkdownFiles.value = [];
|
||||||
displayedFiles.value = [];
|
displayedFiles.value = [];
|
||||||
}
|
}
|
||||||
@@ -298,7 +299,8 @@ const handleSelectFile = async (data) => {
|
|||||||
showEditor.value = false;
|
showEditor.value = false;
|
||||||
activeMenu.value = `group-${data.id}`;
|
activeMenu.value = `group-${data.id}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取笔记列表失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('获取笔记列表失败:', error);
|
||||||
groupMarkdownFiles.value = [];
|
groupMarkdownFiles.value = [];
|
||||||
displayedFiles.value = [];
|
displayedFiles.value = [];
|
||||||
}
|
}
|
||||||
@@ -379,7 +381,8 @@ const previewFile = async (file) => {
|
|||||||
selectedFile.value = { ...file, content, isLoading: false };
|
selectedFile.value = { ...file, content, isLoading: false };
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取笔记内容失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('获取笔记内容失败:', error);
|
||||||
selectedFile.value = null;
|
selectedFile.value = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -401,7 +404,8 @@ const deleteNote = (file) => {
|
|||||||
await fetchGroupings();
|
await fetchGroupings();
|
||||||
await resetToHomeView();
|
await resetToHomeView();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('删除笔记失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('删除笔记失败:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -465,7 +469,8 @@ const handleSearch = async () => {
|
|||||||
showEditor.value = false;
|
showEditor.value = false;
|
||||||
activeMenu.value = 'search';
|
activeMenu.value = 'search';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('搜索失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('搜索失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -528,7 +533,8 @@ const handleExport = async (format) => {
|
|||||||
}
|
}
|
||||||
ElMessage.success(`${format.toUpperCase()} 导出成功`);
|
ElMessage.success(`${format.toUpperCase()} 导出成功`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error(`导出失败: ${error.message}`);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('导出失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ const fetchTrashItems = async () => {
|
|||||||
const response = await getTrash();
|
const response = await getTrash();
|
||||||
trashItems.value = response || [];
|
trashItems.value = response || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取回收站内容失败');
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('获取回收站内容失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,7 +82,8 @@ const handleRestore = async (item) => {
|
|||||||
ElMessage.success('恢复成功');
|
ElMessage.success('恢复成功');
|
||||||
fetchTrashItems();
|
fetchTrashItems();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('恢复失败');
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('恢复失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,7 +128,8 @@ const handleCaptchaConfirm = async ({ captchaId, captchaCode }) => {
|
|||||||
pendingItem.value = null;
|
pendingItem.value = null;
|
||||||
fetchTrashItems();
|
fetchTrashItems();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('操作失败: ' + (error.response?.data?.msg || error.message));
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('操作失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,9 @@ const initVditor = () => {
|
|||||||
const url = res.url;
|
const url = res.url;
|
||||||
const baseUrl = import.meta.env.VITE_API_BASE_URL || '';
|
const baseUrl = import.meta.env.VITE_API_BASE_URL || '';
|
||||||
vditor.value.insertValue(``);
|
vditor.value.insertValue(``);
|
||||||
}).catch(() => {
|
}).catch((error) => {
|
||||||
ElMessage.error('图片上传失败');
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('图片上传失败:', error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -150,7 +151,8 @@ const save = async (value) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
saveStatus.value = '保存失败';
|
saveStatus.value = '保存失败';
|
||||||
ElMessage.error('保存失败: ' + (error.message || '未知错误'));
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('保存失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
isSaving.value = false;
|
isSaving.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,8 @@ const handleDeleteGroup = (group) => {
|
|||||||
ElMessage.success('分类已删除');
|
ElMessage.success('分类已删除');
|
||||||
emit('group-deleted');
|
emit('group-deleted');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('删除分类失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('删除分类失败:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ const handleSubmit = async () => {
|
|||||||
emit('group-created'); // 通知父组件刷新
|
emit('group-created'); // 通知父组件刷新
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('创建分类失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('创建分类失败:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ const handleSubmit = async () => {
|
|||||||
emit('move-success');
|
emit('move-success');
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('移动失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('移动失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ const handleSubmit = async () => {
|
|||||||
emit('privacy-changed', updatedFile);
|
emit('privacy-changed', updatedFile);
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('修改笔记状态失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('修改笔记状态失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ const handleSubmit = async () => {
|
|||||||
// 传递新名称给父组件
|
// 传递新名称给父组件
|
||||||
emit('renamed', newName.value);
|
emit('renamed', newName.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('重命名失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('重命名失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ const handleSubmit = () => {
|
|||||||
emit('import-success');
|
emit('import-success');
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('导入失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('导入失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
reader.readAsText(props.fileToImport);
|
reader.readAsText(props.fileToImport);
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ const fetchRegistrationStatus = async () => {
|
|||||||
try {
|
try {
|
||||||
isRegistrationEnabled.value = await getRegistrationStatus();
|
isRegistrationEnabled.value = await getRegistrationStatus();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
console.error("Failed to fetch registration status:", error);
|
console.error("Failed to fetch registration status:", error);
|
||||||
ElMessage.error('获取注册状态失败');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ const handleToggleRegistration = async (value) => {
|
|||||||
await toggleRegistration(value);
|
await toggleRegistration(value);
|
||||||
ElMessage.success(`注册功能已${value ? '开启' : '关闭'}`);
|
ElMessage.success(`注册功能已${value ? '开启' : '关闭'}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('操作失败');
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
isRegistrationEnabled.value = !value; // Revert on failure
|
isRegistrationEnabled.value = !value; // Revert on failure
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -80,7 +80,8 @@ const handleGenerateCode = async () => {
|
|||||||
generatedCode.value = code;
|
generatedCode.value = code;
|
||||||
ElMessage.success('注册码生成成功');
|
ElMessage.success('注册码生成成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('生成注册码失败: ' + error.message);
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('生成注册码失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ const handleCaptchaConfirm = async ({ captchaId, captchaCode }) => {
|
|||||||
emit('password-updated');
|
emit('password-updated');
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('密码修改失败: ' + (error.response?.data?.msg || error.message));
|
// 错误已在 axios 拦截器中显示,这里不再重复显示
|
||||||
|
console.error('密码修改失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,13 @@ instance.interceptors.response.use(
|
|||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 403 - 权限不足
|
||||||
|
if (status === 403) {
|
||||||
|
const msg = data?.msg || '无权操作';
|
||||||
|
ElMessage.error(msg);
|
||||||
|
return Promise.reject(new Error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
// 429 - 请求过于频繁
|
// 429 - 请求过于频繁
|
||||||
if (status === 429) {
|
if (status === 429) {
|
||||||
const msg = data?.msg || '请求过于频繁,请稍后再试';
|
const msg = data?.msg || '请求过于频繁,请稍后再试';
|
||||||
|
|||||||
Reference in New Issue
Block a user