update
This commit is contained in:
@@ -0,0 +1,272 @@
|
|||||||
|
# CyyNote
|
||||||
|
|
||||||
|
CyyNote 是一个前后端分离的在线笔记系统,后端基于 Solon + Wood + SQLite 提供鉴权、笔记树、笔记编辑、回收站和浏览历史接口;前端基于 React + Vite + Semi UI + Lexical 提供笔记管理与富文本编辑体验。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
### 前端
|
||||||
|
|
||||||
|
- React 18
|
||||||
|
- TypeScript 5.8
|
||||||
|
- Vite 6
|
||||||
|
- React Router 7
|
||||||
|
- Zustand 5:客户端状态管理
|
||||||
|
- Axios:统一 HTTP 客户端与鉴权拦截器
|
||||||
|
- Semi UI 2.96:页面组件库
|
||||||
|
- Lexical 0.44:富文本编辑器
|
||||||
|
- Yjs + y-websocket:协作编辑基础能力
|
||||||
|
- pnpm 9:包管理器
|
||||||
|
- ESLint 9 Flat Config
|
||||||
|
|
||||||
|
### 后端
|
||||||
|
|
||||||
|
- JDK 17
|
||||||
|
- Solon 3.0.5
|
||||||
|
- Wood ORM / wood-solon-plugin
|
||||||
|
- SQLite JDBC 3.46
|
||||||
|
- HikariCP
|
||||||
|
- solon-sessionstate-jwt:JWT Session
|
||||||
|
- Fastjson2
|
||||||
|
- Hutool
|
||||||
|
- Maven
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
CyyNote/
|
||||||
|
├── cyynote-backend/ # Solon 后端工程
|
||||||
|
│ ├── pom.xml
|
||||||
|
│ └── src/main/
|
||||||
|
│ ├── java/com/cyynote/
|
||||||
|
│ │ ├── controller/ # Auth / Note / Test 控制器
|
||||||
|
│ │ ├── dso/ # DB 初始化、Wood Mapper
|
||||||
|
│ │ ├── model/ # 数据模型
|
||||||
|
│ │ ├── payload/ # 请求/响应 DTO
|
||||||
|
│ │ └── util/ # 笔记树构建工具
|
||||||
|
│ └── resources/
|
||||||
|
│ ├── app.yml # 通用配置
|
||||||
|
│ ├── app-dev.yml # 开发环境配置
|
||||||
|
│ ├── app-pro.yml # 生产环境配置
|
||||||
|
│ └── db/schema.sql # SQLite 初始化脚本
|
||||||
|
└── cyynote-frontend/ # React 前端工程
|
||||||
|
├── package.json
|
||||||
|
├── vite.config.ts
|
||||||
|
└── src/
|
||||||
|
├── components/ # 页面组件、Lexical 编辑器、弹窗、侧栏
|
||||||
|
├── pages/ # 路由页面
|
||||||
|
├── services/ # API Service
|
||||||
|
├── stores/ # Zustand Store
|
||||||
|
├── lib/axios.ts # Axios 实例与拦截器
|
||||||
|
└── types/ # 前端类型定义
|
||||||
|
```
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
| 项目 | 要求 |
|
||||||
|
| --- | --- |
|
||||||
|
| JDK | 17+ |
|
||||||
|
| Maven | 3.8+ |
|
||||||
|
| Node.js | 20+ |
|
||||||
|
| pnpm | 9+ |
|
||||||
|
|
||||||
|
后端 Maven 编译目标已设置为 Java 17;前端 `package.json` 中声明了 Node 20 与 pnpm 9。
|
||||||
|
|
||||||
|
## 后端配置与运行
|
||||||
|
|
||||||
|
### 数据库配置
|
||||||
|
|
||||||
|
开发环境默认使用当前运行目录下的 SQLite 文件:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
test.db1:
|
||||||
|
jdbcUrl: "jdbc:sqlite:./cyynote.db"
|
||||||
|
driverClassName: "org.sqlite.JDBC"
|
||||||
|
```
|
||||||
|
|
||||||
|
首次启动时,如果数据库中不存在 `appx` 表,后端会执行 `src/main/resources/db/schema.sql` 初始化基础表结构和示例数据。
|
||||||
|
|
||||||
|
默认账号:
|
||||||
|
|
||||||
|
| 用户名 | 密码 | 角色 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| admin | cyy123 | ROLE_ADMIN |
|
||||||
|
| test | test | ROLE_USER |
|
||||||
|
|
||||||
|
### 启动后端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd cyynote-backend
|
||||||
|
mvn clean package
|
||||||
|
java -jar target/cyynote.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
默认服务端口:`8080`。
|
||||||
|
|
||||||
|
### 后端关键接口
|
||||||
|
|
||||||
|
接口统一以 `/api` 为前缀。
|
||||||
|
|
||||||
|
#### 鉴权接口
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| POST | `/api/auth/signin` | 登录,返回 `accessToken`、`tokenType` 和 `user` |
|
||||||
|
| GET | `/api/auth/logout` | 清理服务端 Session |
|
||||||
|
| POST | `/api/auth/signup` | 注册普通用户 |
|
||||||
|
| POST | `/api/auth/updatePassword` | 修改密码 |
|
||||||
|
|
||||||
|
登录成功响应中的 `data` 结构:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"accessToken": "...",
|
||||||
|
"tokenType": "Bearer",
|
||||||
|
"user": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"email": "aaaaaaaaa",
|
||||||
|
"roles": ["ROLE_ADMIN"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 笔记接口
|
||||||
|
|
||||||
|
| 方法 | 路径 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| GET | `/api/note/all` | 获取笔记树 |
|
||||||
|
| GET | `/api/note/home?type=1&search=0` | 首页列表、搜索、回收站列表 |
|
||||||
|
| GET | `/api/note/get?id=1` | 获取笔记详情,同时更新浏览时间 |
|
||||||
|
| GET | `/api/note/add?pid=0` | 新增笔记 |
|
||||||
|
| POST | `/api/note/update` | 更新笔记标题和内容 |
|
||||||
|
| POST | `/api/note/delete` | 软删除笔记 |
|
||||||
|
| GET | `/api/note/deleteBack?id=1` | 从回收站恢复笔记 |
|
||||||
|
| GET | `/api/note/historyQueryOrDelete?flag=0` | 查询或清理历史记录 |
|
||||||
|
|
||||||
|
`/api/note/home` 的 `type` 参数含义:
|
||||||
|
|
||||||
|
| type | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 0 | 搜索 |
|
||||||
|
| 1 | 最近更新 |
|
||||||
|
| 2 | 最新添加 |
|
||||||
|
| 3 | 最近浏览 |
|
||||||
|
| 4 | 回收站 |
|
||||||
|
|
||||||
|
## 前端配置与运行
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
|
||||||
|
复制示例配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd cyynote-frontend
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
常用配置:
|
||||||
|
|
||||||
|
```env
|
||||||
|
VITE_API_BASE_URL=/api
|
||||||
|
VITE_WS_URL=ws://localhost:1234
|
||||||
|
```
|
||||||
|
|
||||||
|
开发模式下,Vite 已配置 `/api` 代理到 `http://localhost:8080`。
|
||||||
|
|
||||||
|
### 安装与启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd cyynote-frontend
|
||||||
|
pnpm install
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建与检查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm typecheck
|
||||||
|
pnpm lint
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 前端架构说明
|
||||||
|
|
||||||
|
### 路由
|
||||||
|
|
||||||
|
前端入口使用 `BrowserRouter`。主要路由:
|
||||||
|
|
||||||
|
| 路径 | 页面 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `/login` | SignIn | 登录页 |
|
||||||
|
| `/register` | Register | 注册页 |
|
||||||
|
| `/home` | NotePage | 笔记主界面 |
|
||||||
|
| `/profile` | Profile | 用户信息 |
|
||||||
|
| `/user` | BoardUser | 用户权限测试页 |
|
||||||
|
| `/mod` | BoardModerator | Moderator 权限测试页 |
|
||||||
|
| `/admin` | BoardAdmin | Admin 权限测试页 |
|
||||||
|
|
||||||
|
除登录和注册外,其他路由由 `ProtectedRoute` 保护;未登录用户会跳转到 `/login`。
|
||||||
|
|
||||||
|
### 状态管理
|
||||||
|
|
||||||
|
Zustand Store 分为三类:
|
||||||
|
|
||||||
|
- `useAuthStore`:用户信息、JWT Token、登录状态持久化到 `sessionStorage`
|
||||||
|
- `useNoteStore`:当前笔记、笔记树、首页列表、最近浏览列表
|
||||||
|
- `useUIStore`:当前视图、侧栏状态、搜索条件、弹窗显隐状态
|
||||||
|
|
||||||
|
### HTTP 客户端
|
||||||
|
|
||||||
|
`src/lib/axios.ts` 创建统一 Axios 实例:
|
||||||
|
|
||||||
|
- `baseURL` 读取 `VITE_API_BASE_URL`,默认 `/api`
|
||||||
|
- 请求拦截器自动添加 `Authorization: Bearer <token>`
|
||||||
|
- 响应拦截器在 HTTP 401 时自动登出并跳转登录页
|
||||||
|
|
||||||
|
### 编辑器
|
||||||
|
|
||||||
|
笔记编辑器基于 Lexical。`NoteEditor` 负责标题输入与编辑器挂载,`LexicalApp` 负责富文本编辑能力。协作相关配置位于 `components/lexical/collaboration.ts`,WebSocket 地址由 `VITE_WS_URL` 控制。
|
||||||
|
|
||||||
|
## 本次升级与修复说明
|
||||||
|
|
||||||
|
本次修复覆盖前端、后端和 JDK 17 运行兼容性:
|
||||||
|
|
||||||
|
- 后端 Maven 编译目标升级为 Java 17
|
||||||
|
- 修复后端登录返回结构,使其与前端 `IAuthResponse` 匹配
|
||||||
|
- 修复登录失败时空指针问题,并返回 HTTP 401
|
||||||
|
- 修复注册接口只返回空对象的问题,改为实际创建普通用户
|
||||||
|
- 修复修改密码接口用户不存在时空指针问题
|
||||||
|
- 修复 JWT 拦截器在 401 后仍继续执行 Controller 的问题
|
||||||
|
- 修复软删除接口把标题更新成 `null` 的问题
|
||||||
|
- 修复历史表缺失 `flag` 字段的问题
|
||||||
|
- 修复开发环境 SQLite 路径在 Linux 下不可用的问题
|
||||||
|
- 修复前端 Profile 页面访问不存在 `accessToken` 字段导致崩溃的问题
|
||||||
|
- 修复首页点击“查看”后未切换到笔记视图的问题
|
||||||
|
- 修复 Board 页面仍使用旧 service 返回结构的问题
|
||||||
|
- 修复回收站和密码弹窗状态字段 `Model` / `Modal` 拼写不一致问题
|
||||||
|
- 修复前端笔记树 `key` 类型与后端返回值不一致的问题
|
||||||
|
- 清理未使用的 `@tanstack/react-query` 依赖声明
|
||||||
|
|
||||||
|
## 验证建议
|
||||||
|
|
||||||
|
网络正常后建议执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd cyynote-backend
|
||||||
|
mvn clean package
|
||||||
|
|
||||||
|
cd ../cyynote-frontend
|
||||||
|
pnpm install
|
||||||
|
pnpm typecheck
|
||||||
|
pnpm lint
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
|
如果 CI 使用 `pnpm install --frozen-lockfile`,需要提交 `pnpm-lock.yaml`。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 当前密码仍为明文存储,生产环境应改为 BCrypt/Argon2 等不可逆哈希。
|
||||||
|
- Lexical 从旧版本升级到 0.44 跨度较大,建议重点回归测试自定义 Node、Plugin、序列化/反序列化和保存逻辑。
|
||||||
|
- y-websocket 3.x 与旧版存在差异,协作编辑功能需要单独联调。
|
||||||
|
- SQLite 适合单机和轻量部署;多人协作、高并发或云部署建议迁移到 MySQL/PostgreSQL。
|
||||||
|
|||||||
+13
-9
@@ -20,7 +20,11 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>11</java.version>
|
<java.version>17</java.version>
|
||||||
|
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||||
|
<maven.compiler.release>${java.version}</maven.compiler.release>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -75,14 +79,6 @@
|
|||||||
<version>3.46.1.3</version>
|
<version>3.46.1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.noear</groupId>
|
<groupId>org.noear</groupId>
|
||||||
<artifactId>solon-test</artifactId>
|
<artifactId>solon-test</artifactId>
|
||||||
@@ -96,6 +92,14 @@
|
|||||||
<finalName>${project.artifactId}</finalName>
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<release>${java.version}</release>
|
||||||
|
<encoding>${project.build.sourceEncoding}</encoding>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.noear</groupId>
|
<groupId>org.noear</groupId>
|
||||||
<artifactId>solon-maven-plugin</artifactId>
|
<artifactId>solon-maven-plugin</artifactId>
|
||||||
|
|||||||
@@ -1,103 +1,148 @@
|
|||||||
package com.cyynote.controller;
|
package com.cyynote.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.cyynote.model.UserModel;
|
||||||
import com.cyynote.controller.BaseController;
|
import com.cyynote.payload.request.LoginRequest;
|
||||||
import com.cyynote.model.NoteModel;
|
import com.cyynote.payload.request.SignupRequest;
|
||||||
import com.cyynote.model.UserModel;
|
import com.cyynote.payload.request.UpdatePasswordRequest;
|
||||||
import com.cyynote.payload.request.LoginRequest;
|
import java.sql.SQLException;
|
||||||
import com.cyynote.payload.request.SignupRequest;
|
import java.util.Arrays;
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
import java.util.List;
|
import java.util.logging.Logger;
|
||||||
import java.util.logging.Logger;
|
import org.noear.solon.annotation.Body;
|
||||||
|
import org.noear.solon.annotation.Controller;
|
||||||
import com.cyynote.payload.request.UpdatePasswordRequest;
|
import org.noear.solon.annotation.Mapping;
|
||||||
import org.noear.solon.annotation.Body;
|
import org.noear.solon.annotation.Post;
|
||||||
import org.noear.solon.annotation.Controller;
|
import org.noear.solon.core.handle.Context;
|
||||||
import org.noear.solon.annotation.Mapping;
|
import org.noear.solon.core.handle.Result;
|
||||||
import org.noear.solon.annotation.Post;
|
import org.noear.wood.DbContext;
|
||||||
import org.noear.solon.core.handle.Context;
|
import org.noear.wood.DbTableQuery;
|
||||||
import org.noear.solon.core.handle.Result;
|
import org.noear.wood.annotation.Db;
|
||||||
import org.noear.wood.DbContext;
|
|
||||||
import org.noear.wood.DbTableQuery;
|
@Mapping("/api/auth")
|
||||||
import org.noear.wood.annotation.Db;
|
@Controller
|
||||||
|
public class AuthController extends BaseController {
|
||||||
@Mapping("/api/auth")
|
private static final Logger log = Logger.getLogger(AuthController.class.getName());
|
||||||
@Controller
|
|
||||||
public class AuthController extends BaseController {
|
@Db
|
||||||
private static final Logger log = Logger.getLogger(com.cyynote.controller.AuthController.class.getName());
|
DbContext db;
|
||||||
|
|
||||||
@Db
|
@Mapping("/logout")
|
||||||
DbContext db;
|
public void logout(Context ctx) {
|
||||||
|
ctx.sessionClear();
|
||||||
@Mapping("/logout")
|
}
|
||||||
public void logout(Context ctx) {
|
|
||||||
ctx.sessionClear();
|
@Post
|
||||||
}
|
@Mapping("/signin")
|
||||||
|
public Result signin(Context ctx, @Body LoginRequest loginRequest) throws SQLException {
|
||||||
@Post
|
if (loginRequest == null || loginRequest.getUsername() == null || loginRequest.getPassword() == null) {
|
||||||
@Mapping("/signin")
|
ctx.status(400);
|
||||||
public Result signin(Context ctx, @Body LoginRequest loginRequest) throws SQLException {
|
return Result.failure(400, "用户名和密码不能为空");
|
||||||
log.info("name:" + loginRequest.getUsername());
|
}
|
||||||
log.info("password:" + loginRequest.getPassword());
|
|
||||||
|
log.info("signin username:" + loginRequest.getUsername());
|
||||||
long count = db.table("user").selectCount();
|
UserModel model = (UserModel) ((DbTableQuery) ((DbTableQuery) this.db.table("user")
|
||||||
log.info("countUser:" + count);
|
.whereEq("username", loginRequest.getUsername()))
|
||||||
List<UserModel> all = ((DbTableQuery)this.db.table("user")).selectList("*", UserModel.class);
|
.andEq("password", loginRequest.getPassword()))
|
||||||
log.info( all.toString());
|
.selectItem("*", UserModel.class);
|
||||||
|
|
||||||
UserModel model = (UserModel)((DbTableQuery)((DbTableQuery)this.db.table("user").whereEq("username", loginRequest.getUsername())).andEq("password", loginRequest.getPassword())).selectItem("*", UserModel.class);
|
if (model == null) {
|
||||||
if ("admin".equals(model.getUsername())) {
|
ctx.status(401);
|
||||||
ctx.sessionSet("user_name", loginRequest.getUsername());
|
return Result.failure(401, "用户名或密码错误");
|
||||||
ctx.sessionSet("user_id", model.getId());
|
}
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
String token = ctx.sessionState().sessionToken();
|
ctx.sessionSet("user_name", model.getUsername());
|
||||||
obj.put("accessToken", token);
|
ctx.sessionSet("user_id", model.getId());
|
||||||
obj.put("id", Integer.valueOf(1));
|
String token = ctx.sessionState().sessionToken();
|
||||||
obj.put("username", loginRequest.getUsername());
|
((DbTableQuery) this.db.table("user")
|
||||||
obj.put("email", "1");
|
.set("token", token)
|
||||||
obj.put("roles", "1");
|
.set("logintime", DateUtil.now())
|
||||||
int flag = ((DbTableQuery)this.db.table("user").set("token", token).set("logintime", DateUtil.now()).whereEq("id", model.getId())).update();
|
.whereEq("id", model.getId()))
|
||||||
System.out.println(flag);
|
.update();
|
||||||
return Result.succeed(obj);
|
|
||||||
}
|
JSONObject user = new JSONObject();
|
||||||
return Result.failure();
|
user.put("id", model.getId());
|
||||||
}
|
user.put("username", model.getUsername());
|
||||||
|
user.put("email", model.getEmail());
|
||||||
|
user.put("roles", normalizeRoles(model.getRole()));
|
||||||
@Post
|
|
||||||
@Mapping("/updatePassword")
|
JSONObject payload = new JSONObject();
|
||||||
public Result updatePassword(Context ctx, @Body UpdatePasswordRequest loginRequest) throws SQLException {
|
payload.put("accessToken", token);
|
||||||
log.info("name:" + loginRequest.getUsername());
|
payload.put("tokenType", "Bearer");
|
||||||
log.info("old - password:" + loginRequest.getOldpassword());
|
payload.put("user", user);
|
||||||
log.info("new - password:" + loginRequest.getNewpassword());
|
|
||||||
|
return Result.succeed(payload);
|
||||||
|
}
|
||||||
long count = db.table("user").selectCount();
|
|
||||||
log.info("countUser:" + count);
|
@Post
|
||||||
List<UserModel> all = ((DbTableQuery)this.db.table("user")).selectList("*", UserModel.class);
|
@Mapping("/updatePassword")
|
||||||
log.info( all.toString());
|
public Result updatePassword(Context ctx, @Body UpdatePasswordRequest loginRequest) throws SQLException {
|
||||||
|
if (loginRequest == null || loginRequest.getUsername() == null || loginRequest.getOldpassword() == null || loginRequest.getNewpassword() == null) {
|
||||||
|
ctx.status(400);
|
||||||
UserModel model = (UserModel)((DbTableQuery)((DbTableQuery)this.db.table("user").whereEq("username", loginRequest.getUsername())).andEq("password", loginRequest.getOldpassword())).selectItem("*", UserModel.class);
|
return Result.failure(400, "参数不完整");
|
||||||
if ("admin".equals(model.getUsername())) {
|
}
|
||||||
|
|
||||||
int flag = ((DbTableQuery)this.db.table("user").set("password", loginRequest.getNewpassword()).whereEq("id", model.getId())).update();
|
log.info("update password username:" + loginRequest.getUsername());
|
||||||
System.out.println(flag);
|
UserModel model = (UserModel) ((DbTableQuery) ((DbTableQuery) this.db.table("user")
|
||||||
return Result.succeed(flag);
|
.whereEq("username", loginRequest.getUsername()))
|
||||||
}
|
.andEq("password", loginRequest.getOldpassword()))
|
||||||
return Result.failure();
|
.selectItem("*", UserModel.class);
|
||||||
}
|
if (model == null) {
|
||||||
|
ctx.status(400);
|
||||||
|
return Result.failure(400, "用户名或旧密码错误");
|
||||||
|
}
|
||||||
@Post
|
|
||||||
@Mapping("/signup")
|
int flag = ((DbTableQuery) this.db.table("user")
|
||||||
public Result signup(@Body SignupRequest signUpRequest) {
|
.set("password", loginRequest.getNewpassword())
|
||||||
log.info("signUpRequest:" + JSONObject.toJSONString(signUpRequest, new com.alibaba.fastjson2.JSONWriter.Feature[0]));
|
.whereEq("id", model.getId()))
|
||||||
JSONObject obj = new JSONObject();
|
.update();
|
||||||
return Result.succeed(obj);
|
return Result.succeed(flag);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Post
|
||||||
|
@Mapping("/signup")
|
||||||
|
public Result signup(Context ctx, @Body SignupRequest signUpRequest) throws SQLException {
|
||||||
|
log.info("signup username:" + (signUpRequest == null ? null : signUpRequest.getUsername()));
|
||||||
|
if (signUpRequest == null || signUpRequest.getUsername() == null || signUpRequest.getPassword() == null || signUpRequest.getEmail() == null) {
|
||||||
|
ctx.status(400);
|
||||||
|
return Result.failure(400, "用户名、邮箱和密码不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
long exists = ((DbTableQuery) this.db.table("user")
|
||||||
|
.whereEq("username", signUpRequest.getUsername()))
|
||||||
|
.selectCount();
|
||||||
|
if (exists > 0) {
|
||||||
|
ctx.status(409);
|
||||||
|
return Result.failure(409, "用户名已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel user = new UserModel();
|
||||||
|
user.setUsername(signUpRequest.getUsername());
|
||||||
|
user.setEmail(signUpRequest.getEmail());
|
||||||
|
user.setPassword(signUpRequest.getPassword());
|
||||||
|
user.setRole("ROLE_USER");
|
||||||
|
this.db.table("user").setEntityIf(user, (k, v) -> Boolean.valueOf(v != null)).insert();
|
||||||
|
return Result.succeed("注册成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> normalizeRoles(String role) {
|
||||||
|
if (role == null || role.isBlank()) {
|
||||||
|
return List.of("ROLE_USER");
|
||||||
|
}
|
||||||
|
if (role.startsWith("ROLE_")) {
|
||||||
|
return List.of(role);
|
||||||
|
}
|
||||||
|
if ("admin".equalsIgnoreCase(role)) {
|
||||||
|
return List.of("ROLE_ADMIN");
|
||||||
|
}
|
||||||
|
if ("moderator".equalsIgnoreCase(role) || "mod".equalsIgnoreCase(role)) {
|
||||||
|
return List.of("ROLE_MODERATOR");
|
||||||
|
}
|
||||||
|
if (role.contains(",")) {
|
||||||
|
return Arrays.asList(role.split(","));
|
||||||
|
}
|
||||||
|
return List.of("ROLE_USER");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +1,39 @@
|
|||||||
package com.cyynote.controller;
|
package com.cyynote.controller;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Claims;
|
import org.noear.solon.annotation.Component;
|
||||||
import org.noear.solon.annotation.Component;
|
import org.noear.solon.core.handle.Context;
|
||||||
import org.noear.solon.core.handle.Context;
|
import org.noear.solon.core.handle.Handler;
|
||||||
import org.noear.solon.core.handle.Handler;
|
import org.noear.solon.core.handle.Result;
|
||||||
import org.noear.solon.core.handle.Result;
|
import org.noear.solon.core.route.RouterInterceptor;
|
||||||
import org.noear.solon.core.route.RouterInterceptor;
|
import org.noear.solon.core.route.RouterInterceptorChain;
|
||||||
import org.noear.solon.core.route.RouterInterceptorChain;
|
import org.noear.solon.sessionstate.jwt.JwtUtils;
|
||||||
import org.noear.solon.sessionstate.jwt.JwtUtils;
|
|
||||||
|
@Component
|
||||||
@Component
|
public class JwtInterceptor implements RouterInterceptor {
|
||||||
public class JwtInterceptor implements RouterInterceptor {
|
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
|
||||||
public void doIntercept(Context ctx, Handler mainHandler, RouterInterceptorChain chain) throws Throwable {
|
boolean requireAuth = !("/api/auth/signup".equals(ctx.path())
|
||||||
boolean flag = true;
|
|| "/api/auth/signin".equals(ctx.path())
|
||||||
if ("/api/auth/signup".equals(ctx.path()) ||
|
|| "/demo".equals(ctx.path())
|
||||||
"/api/auth/signin".equals(ctx.path()) ||
|
|| "/api/auth/logout".equals(ctx.path())
|
||||||
"/demo".equals(ctx.path()) ||
|
|| "OPTIONS".equalsIgnoreCase(ctx.method()));
|
||||||
"/api/auth/logout".equals(ctx.path())
|
|
||||||
|
if (requireAuth) {
|
||||||
)
|
String token = ctx.header("Authorization");
|
||||||
flag = false;
|
if (token == null || token.isBlank()) {
|
||||||
if (flag)
|
ctx.status(401);
|
||||||
if (null != ctx.header("Authorization")) {
|
ctx.render(Result.failure(401, "未登录或登录已过期"));
|
||||||
String token = ctx.header("Authorization");
|
return;
|
||||||
token = token.replace("Bearer ", "");
|
}
|
||||||
System.out.println("token:" + token);
|
|
||||||
Claims claims = JwtUtils.parseJwt(token);
|
token = token.replace("Bearer ", "");
|
||||||
System.out.println("claims:" + claims);
|
Claims claims = JwtUtils.parseJwt(token);
|
||||||
if (null != claims) {
|
if (claims == null) {
|
||||||
System.out.println("username:" + claims.get("user_name"));
|
ctx.status(401);
|
||||||
System.out.println("exp:" + claims.get("exp"));
|
ctx.render(Result.failure(401, "未登录或登录已过期"));
|
||||||
} else {
|
return;
|
||||||
ctx.status(401);
|
}
|
||||||
ctx.render(Result.failure(401, ""));
|
}
|
||||||
}
|
chain.doIntercept(ctx, mainHandler);
|
||||||
} else {
|
}
|
||||||
ctx.status(401);
|
}
|
||||||
ctx.render(Result.failure(401, ""));
|
|
||||||
}
|
|
||||||
chain.doIntercept(ctx, mainHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,207 +1,219 @@
|
|||||||
package com.cyynote.controller;
|
package com.cyynote.controller;
|
||||||
|
|
||||||
import cn.hutool.*;
|
import cn.hutool.*;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.cyynote.dso.NoteSqlAnnotation;
|
||||||
import com.cyynote.controller.BaseController;
|
import com.cyynote.model.HistoryModel;
|
||||||
import com.cyynote.dso.NoteSqlAnnotation;
|
import com.cyynote.model.NoteModel;
|
||||||
import com.cyynote.model.HistoryModel;
|
import com.cyynote.payload.request.NoteRequest;
|
||||||
import com.cyynote.model.NoteModel;
|
import com.cyynote.util.TreeBuild;
|
||||||
import com.cyynote.payload.request.NoteRequest;
|
import com.cyynote.util.TreeNode;
|
||||||
import com.cyynote.util.TreeBuild;
|
import io.jsonwebtoken.Claims;
|
||||||
import com.cyynote.util.TreeNode;
|
import java.sql.SQLException;
|
||||||
import io.jsonwebtoken.Claims;
|
import java.util.ArrayList;
|
||||||
import java.sql.SQLException;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.logging.Logger;
|
||||||
import java.util.Date;
|
import org.noear.solon.annotation.Body;
|
||||||
import java.util.List;
|
import org.noear.solon.annotation.Controller;
|
||||||
import java.util.logging.Logger;
|
import org.noear.solon.annotation.Get;
|
||||||
import org.noear.solon.annotation.Body;
|
import org.noear.solon.annotation.Mapping;
|
||||||
import org.noear.solon.annotation.Controller;
|
import org.noear.solon.annotation.Path;
|
||||||
import org.noear.solon.annotation.Get;
|
import org.noear.solon.annotation.Post;
|
||||||
import org.noear.solon.annotation.Mapping;
|
import org.noear.solon.annotation.Put;
|
||||||
import org.noear.solon.annotation.Path;
|
import org.noear.solon.core.handle.Context;
|
||||||
import org.noear.solon.annotation.Post;
|
import org.noear.solon.core.handle.Result;
|
||||||
import org.noear.solon.annotation.Put;
|
import org.noear.solon.sessionstate.jwt.JwtUtils;
|
||||||
import org.noear.solon.core.handle.Context;
|
import org.noear.wood.DbContext;
|
||||||
import org.noear.solon.core.handle.Result;
|
import org.noear.wood.DbTableQuery;
|
||||||
import org.noear.solon.sessionstate.jwt.JwtUtils;
|
import org.noear.wood.annotation.Db;
|
||||||
import org.noear.solon.web.cors.annotation.CrossOrigin;
|
|
||||||
import org.noear.wood.DbContext;
|
@Mapping("/api/note")
|
||||||
import org.noear.wood.DbTableQuery;
|
@Controller
|
||||||
import org.noear.wood.annotation.Db;
|
public class NoteController extends BaseController {
|
||||||
|
private static final Logger log = Logger.getLogger(com.cyynote.controller.NoteController.class.getName());
|
||||||
@Mapping("/api/note")
|
|
||||||
@Controller
|
@Db
|
||||||
public class NoteController extends BaseController {
|
NoteSqlAnnotation mapper;
|
||||||
private static final Logger log = Logger.getLogger(com.cyynote.controller.NoteController.class.getName());
|
|
||||||
|
@Db
|
||||||
@Db
|
DbContext db;
|
||||||
NoteSqlAnnotation mapper;
|
|
||||||
|
private static final String QUERY_F = "id,pid,title,createtime,updatetime,viewtime,flag";
|
||||||
@Db
|
|
||||||
DbContext db;
|
@Get
|
||||||
|
@Mapping("get1")
|
||||||
private static final String QUERY_F = "id,pid,title,createtime,updatetime,viewtime,flag";
|
public String test_post_get(Context context, @Path String appname) {
|
||||||
|
|
||||||
@Get
|
return context.path();
|
||||||
@Mapping("get1")
|
}
|
||||||
public String test_post_get(Context context, @Path String appname) {
|
|
||||||
|
@Post
|
||||||
return context.path();
|
@Mapping("post")
|
||||||
}
|
public String test_post(Context context) {
|
||||||
|
return context.param("name");
|
||||||
@Post
|
}
|
||||||
@Mapping("post")
|
|
||||||
public String test_post(Context context) {
|
@Put
|
||||||
return context.param("name");
|
@Mapping("put")
|
||||||
}
|
public String test_put(Context context, String name) {
|
||||||
|
return context.param("name");
|
||||||
@Put
|
}
|
||||||
@Mapping("put")
|
|
||||||
public String test_put(Context context, String name) {
|
@Get
|
||||||
return context.param("name");
|
@Mapping("/all")
|
||||||
}
|
public Result noteAccess(Context ctx) throws Exception {
|
||||||
|
List<NoteModel> all = ((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
@Get
|
List<TreeNode> treeNodeList = new ArrayList<>();
|
||||||
@Mapping("/all")
|
for (NoteModel n : all) {
|
||||||
public Result noteAccess(Context ctx) throws Exception {
|
TreeNode treeNode = new TreeNode(n.getId().intValue(), n.getPid().intValue(), n.getTitle(), String.valueOf(n.getId()), String.valueOf(n.getId()));
|
||||||
List<NoteModel> all = ((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
treeNodeList.add(treeNode);
|
||||||
List<TreeNode> treeNodeList = new ArrayList<>();
|
}
|
||||||
for (NoteModel n : all) {
|
TreeBuild bb = new TreeBuild(treeNodeList);
|
||||||
TreeNode treeNode = new TreeNode(n.getId().intValue(), n.getPid().intValue(), n.getTitle(), String.valueOf(n.getId()), String.valueOf(n.getId()));
|
List<TreeNode> collect = bb.buildTree();
|
||||||
treeNodeList.add(treeNode);
|
return Result.succeed(JSONArray.parseArray(JSONArray.toJSONString(collect)));
|
||||||
}
|
}
|
||||||
TreeBuild bb = new TreeBuild(treeNodeList);
|
|
||||||
List<TreeNode> collect = bb.buildTree();
|
@Get
|
||||||
return Result.succeed(JSONArray.parseArray(JSONArray.toJSONString(collect)));
|
@Mapping("/home")
|
||||||
}
|
public Result noteHome(Context ctx, @Path int type, @Path String search) throws Exception {
|
||||||
|
List<NoteModel> all = new ArrayList<>();
|
||||||
@Get
|
if (type == 0) {
|
||||||
@Mapping("/home")
|
all = ((DbTableQuery)((DbTableQuery)this.db.table("note").whereLk("context", "%" + search + "%")).andLk("title", "%" + search + "%")).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
public Result noteHome(Context ctx, @Path int type, @Path String search) throws Exception {
|
} else if (type == 1) {
|
||||||
System.out.println(type);
|
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).orderByDesc("updatetime")).limit(20)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
System.out.println(search);
|
} else if (type == 2) {
|
||||||
List<NoteModel> all = new ArrayList<>();
|
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).orderByDesc("createtime")).limit(20)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
if (type == 0) {
|
} else if (type == 3) {
|
||||||
all = ((DbTableQuery)((DbTableQuery)this.db.table("note").whereLk("context", "%" + search + "%")).andLk("title", "%" + search + "%")).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).orderByDesc("viewtime")).limit(20)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
} else if (type == 1) {
|
} else if (type == 4) {
|
||||||
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).orderByDesc("updatetime")).limit(20)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(0))).orderByDesc("updatetime")).limit(10000)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
} else if (type == 2) {
|
}
|
||||||
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).orderByDesc("createtime")).limit(20)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
return Result.succeed(JSONArray.parseArray(JSONArray.toJSONString(all)));
|
||||||
} else if (type == 3) {
|
}
|
||||||
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(1))).orderByDesc("viewtime")).limit(20)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
|
||||||
} else if (type == 4) {
|
@Get
|
||||||
all = ((DbTableQuery)((DbTableQuery)((DbTableQuery)this.db.table("note").whereEq("flag", Integer.valueOf(0))).orderByDesc("updatetime")).limit(10000)).selectList("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
@Mapping("/get")
|
||||||
}
|
public Result getNote(Context ctx, @Path int id) throws Exception {
|
||||||
return Result.succeed(JSONArray.parseArray(JSONArray.toJSONString(all)));
|
NoteModel model = (NoteModel)((DbTableQuery)this.db.table("note").whereEq("id", Integer.valueOf(id))).selectItem("*", NoteModel.class);
|
||||||
}
|
if (model == null) {
|
||||||
|
ctx.status(404);
|
||||||
@Get
|
return Result.failure(404, "笔记不存在");
|
||||||
@Mapping("/get")
|
}
|
||||||
public Result getNote(Context ctx, @Path int id) throws Exception {
|
String time = DateUtil.now();
|
||||||
NoteModel model = (NoteModel)((DbTableQuery)this.db.table("note").whereEq("id", Integer.valueOf(id))).selectItem("*", NoteModel.class);
|
((DbTableQuery)this.db.table("note").set("viewtime", time).whereEq("id", Integer.valueOf(id))).update();
|
||||||
String time = DateUtil.now();
|
model.setViewtime(time);
|
||||||
System.out.println(time);
|
log.info(JSONObject.toJSONString(model, new com.alibaba.fastjson2.JSONWriter.Feature[0]));
|
||||||
int flag = ((DbTableQuery)this.db.table("note").set("viewtime", time).whereEq("id", Integer.valueOf(id))).update();
|
return Result.succeed(model);
|
||||||
System.out.println(flag);
|
}
|
||||||
log.info(JSONObject.toJSONString(model, new com.alibaba.fastjson2.JSONWriter.Feature[0]));
|
|
||||||
return Result.succeed(model);
|
@Get
|
||||||
}
|
@Mapping("/add")
|
||||||
|
public Result addNote(Context ctx, @Path int pid) throws Exception {
|
||||||
@Get
|
String userid = getUserInfoId(ctx);
|
||||||
@Mapping("/add")
|
if (null == userid)
|
||||||
public Result addNote(Context ctx, @Path int pid) throws Exception {
|
return Result.failure(401);
|
||||||
String userid = getUserInfoId(ctx);
|
NoteModel note = new NoteModel();
|
||||||
if (null == userid)
|
note.setPid(Integer.valueOf(pid));
|
||||||
return Result.failure(401);
|
note.setTitle("未命名Note");
|
||||||
NoteModel note = new NoteModel();
|
note.setFlag(Integer.valueOf(1));
|
||||||
note.setPid(Integer.valueOf(pid));
|
note.setCreatetime(DateUtil.now());
|
||||||
note.setTitle("未命名Note");
|
note.setUpdatetime(note.getCreatetime());
|
||||||
note.setFlag(Integer.valueOf(1));
|
note.setViewtime(note.getCreatetime());
|
||||||
note.setCreatetime(DateUtil.now());
|
note.setContext("{\"root\":{\"children\":[{\"children\":[{\"detail\":0,\"format\":0,\"mode\":\"normal\",\"style\":\"\",\"text\":\"未命名Note\",\"type\":\"text\",\"version\":1}],\"direction\":\"ltr\",\"format\":\"\",\"indent\":0,\"type\":\"paragraph\",\"version\":1}],\"direction\":\"ltr\",\"format\":\"\",\"indent\":0,\"type\":\"root\",\"version\":1}}");
|
||||||
note.setContext("{\"root\":{\"children\":[{\"children\":[{\"detail\":0,\"format\":0,\"mode\":\"normal\",\"style\":\"\",\"text\":\"未命名Note\",\"type\":\"text\",\"version\":1}],\"direction\":\"ltr\",\"format\":\"\",\"indent\":0,\"type\":\"paragraph\",\"version\":1}],\"direction\":\"ltr\",\"format\":\"\",\"indent\":0,\"type\":\"root\",\"version\":1}}");
|
|
||||||
|
// note.setContext("{\"root\": {\"type\": \"root\", \"format\": \"\", \"indent\": 0, \"version\": 1, \"children\": [{\"type\": \"paragraph\", \"format\": \"\", \"indent\": 0, \"version\": 1, \"children\": [], \"direction\": null}], \"direction\": null}}");
|
||||||
// note.setContext("{\"root\": {\"type\": \"root\", \"format\": \"\", \"indent\": 0, \"version\": 1, \"children\": [{\"type\": \"paragraph\", \"format\": \"\", \"indent\": 0, \"version\": 1, \"children\": [], \"direction\": null}], \"direction\": null}}");
|
this.db.table("note").setEntityIf(note, (k, v) -> Boolean.valueOf((v != null))).insert();
|
||||||
this.db.table("note").setEntityIf(note, (k, v) -> Boolean.valueOf((v != null))).insert();
|
return Result.succeed("ok");
|
||||||
return Result.succeed("ok");
|
}
|
||||||
}
|
|
||||||
|
@Post
|
||||||
@Post
|
@Mapping("/update")
|
||||||
@Mapping("/update")
|
public Result updateNote(Context ctx, @Body NoteRequest noteRequest) throws SQLException {
|
||||||
public Result updateNote(@Body NoteRequest noteRequest) throws SQLException {
|
if (noteRequest == null || noteRequest.getId() == null || noteRequest.getTitle() == null || noteRequest.getContext() == null) {
|
||||||
NoteModel note = (NoteModel)((DbTableQuery)this.db.table("note").whereEq("id", noteRequest.getId())).selectItem("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
ctx.status(400);
|
||||||
note.setTitle(noteRequest.getTitle());
|
return Result.failure(400, "参数不完整");
|
||||||
note.setUpdatetime(DateUtil.now());
|
}
|
||||||
String cc = noteRequest.getContext();
|
NoteModel note = (NoteModel)((DbTableQuery)this.db.table("note").whereEq("id", noteRequest.getId())).selectItem("id,pid,title,createtime,updatetime,viewtime,flag", NoteModel.class);
|
||||||
JSONObject ar = JSONObject.parseObject(cc);
|
if (note == null) {
|
||||||
note.setContext(ar.toJSONString());
|
ctx.status(404);
|
||||||
int flag = ((DbTableQuery)this.db.table("note").set("title", noteRequest.getTitle()).set("updatetime", DateUtil.now()).set("context", ar.toJSONString()).whereEq("id", noteRequest.getId())).update();
|
return Result.failure(404, "笔记不存在");
|
||||||
log.info("updateNote+ flag");
|
}
|
||||||
HistoryModel history = new HistoryModel();
|
note.setTitle(noteRequest.getTitle());
|
||||||
history.setNid(Integer.valueOf(noteRequest.getId().intValue()));
|
note.setUpdatetime(DateUtil.now());
|
||||||
history.setTitle(noteRequest.getTitle());
|
String cc = noteRequest.getContext();
|
||||||
history.setFlag(Integer.valueOf(1));
|
JSONObject ar = JSONObject.parseObject(cc);
|
||||||
history.setCreatetime(DateUtil.now());
|
note.setContext(ar.toJSONString());
|
||||||
history.setContext(ar.toJSONString());
|
int flag = ((DbTableQuery)this.db.table("note").set("title", noteRequest.getTitle()).set("updatetime", DateUtil.now()).set("context", ar.toJSONString()).whereEq("id", noteRequest.getId())).update();
|
||||||
long his = this.db.table("history").setEntityIf(history, (k, v) -> Boolean.valueOf((v != null))).insert();
|
log.info("updateNote+ flag");
|
||||||
log.info("history+ his");
|
HistoryModel history = new HistoryModel();
|
||||||
return Result.succeed("ok");
|
history.setNid(Integer.valueOf(noteRequest.getId().intValue()));
|
||||||
}
|
history.setTitle(noteRequest.getTitle());
|
||||||
|
history.setFlag(Integer.valueOf(1));
|
||||||
@Post
|
history.setCreatetime(DateUtil.now());
|
||||||
@Mapping("/delete")
|
history.setContext(ar.toJSONString());
|
||||||
public Result deleteNote(@Body NoteRequest noteRequest) throws SQLException {
|
long his = this.db.table("history").setEntityIf(history, (k, v) -> Boolean.valueOf((v != null))).insert();
|
||||||
int flag = ((DbTableQuery)this.db.table("note").set("title", noteRequest.getTitle()).set("flag", Integer.valueOf(0)).whereEq("id", noteRequest.getId())).update();
|
log.info("history+ his");
|
||||||
System.out.println(flag);
|
return Result.succeed("ok");
|
||||||
return Result.succeed("ok");
|
}
|
||||||
}
|
|
||||||
|
@Post
|
||||||
@Get
|
@Mapping("/delete")
|
||||||
@Mapping("/deleteBack")
|
public Result deleteNote(Context ctx, @Body NoteRequest noteRequest) throws SQLException {
|
||||||
public Result deleteBack(@Path int id) throws Exception {
|
if (noteRequest == null || noteRequest.getId() == null) {
|
||||||
int flag = ((DbTableQuery)this.db.table("note").set("flag", Integer.valueOf(1)).whereEq("id", Integer.valueOf(id))).update();
|
ctx.status(400);
|
||||||
System.out.println(flag);
|
return Result.failure(400, "笔记ID不能为空");
|
||||||
return Result.succeed("ok");
|
}
|
||||||
}
|
int flag = ((DbTableQuery)this.db.table("note").set("flag", Integer.valueOf(0)).set("updatetime", DateUtil.now()).whereEq("id", noteRequest.getId())).update();
|
||||||
|
if (flag == 0) {
|
||||||
@Get
|
ctx.status(404);
|
||||||
@Mapping("/historyQueryOrDelete")
|
return Result.failure(404, "笔记不存在");
|
||||||
public Result historyQueryOrDelete(@Path int flag) throws Exception {
|
}
|
||||||
|
return Result.succeed("ok");
|
||||||
log.info("history+ flag" + flag);
|
}
|
||||||
|
|
||||||
if(flag==0){
|
@Get
|
||||||
long count = db.table("history").selectCount();
|
@Mapping("/deleteBack")
|
||||||
log.info("count:" + count);
|
public Result deleteBack(Context ctx, @Path int id) throws Exception {
|
||||||
return Result.succeed(count);
|
int flag = ((DbTableQuery)this.db.table("note").set("flag", Integer.valueOf(1)).set("updatetime", DateUtil.now()).whereEq("id", Integer.valueOf(id))).update();
|
||||||
}else if(flag==1){
|
if (flag == 0) {
|
||||||
int flagdb = db.table("history").whereEq("flag",1).delete();
|
ctx.status(404);
|
||||||
log.info("flagdb:" + flagdb);
|
return Result.failure(404, "笔记不存在");
|
||||||
return Result.succeed(0);
|
}
|
||||||
}
|
return Result.succeed("ok");
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
@Get
|
||||||
private String getUserInfoId(Context ctx) {
|
@Mapping("/historyQueryOrDelete")
|
||||||
String userId = "";
|
public Result historyQueryOrDelete(@Path int flag) throws Exception {
|
||||||
if (null != ctx.header("Authorization")) {
|
|
||||||
String token = ctx.header("Authorization");
|
log.info("history+ flag" + flag);
|
||||||
token = token.replace("Bearer ", "");
|
|
||||||
System.out.println("token:" + token);
|
if(flag==0){
|
||||||
Claims claims = JwtUtils.parseJwt(token);
|
long count = db.table("history").selectCount();
|
||||||
System.out.println("claims:" + claims);
|
log.info("count:" + count);
|
||||||
if (null != claims) {
|
return Result.succeed(count);
|
||||||
System.out.println("username:" + claims.get("user_name"));
|
}else if(flag==1){
|
||||||
System.out.println("userid:" + claims.get("user_id"));
|
int flagdb = db.table("history").whereEq("flag",1).delete();
|
||||||
System.out.println("exp:" + claims.get("exp"));
|
log.info("flagdb:" + flagdb);
|
||||||
userId = claims.get("user_id").toString();
|
return Result.succeed(0);
|
||||||
return userId;
|
}
|
||||||
}
|
return Result.failure(400, "不支持的操作类型");
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
return null;
|
private String getUserInfoId(Context ctx) {
|
||||||
}
|
String userId = "";
|
||||||
}
|
if (null != ctx.header("Authorization")) {
|
||||||
|
String token = ctx.header("Authorization");
|
||||||
|
token = token.replace("Bearer ", "");
|
||||||
|
Claims claims = JwtUtils.parseJwt(token);
|
||||||
|
if (null != claims) {
|
||||||
|
userId = claims.get("user_id").toString();
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
test.db1:
|
test.db1:
|
||||||
jdbcUrl: "jdbc:sqlite:D:/cyynote.db"
|
jdbcUrl: "jdbc:sqlite:./cyynote.db"
|
||||||
driverClassName: "org.sqlite.JDBC"
|
driverClassName: "org.sqlite.JDBC"
|
||||||
@@ -1,53 +1,54 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE `user` (
|
CREATE TABLE `user` (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
email TEXT,
|
email TEXT,
|
||||||
password TEXT,
|
password TEXT,
|
||||||
username TEXT,
|
username TEXT,
|
||||||
role TEXT,
|
role TEXT,
|
||||||
token TEXT,
|
token TEXT,
|
||||||
logintime TEXT
|
logintime TEXT
|
||||||
);
|
);
|
||||||
CREATE TABLE `note` (
|
CREATE TABLE `note` (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
pid INTEGER,
|
pid INTEGER,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
context TEXT,
|
context TEXT,
|
||||||
conjson TEXT,
|
conjson TEXT,
|
||||||
createtime TEXT,
|
createtime TEXT,
|
||||||
updatetime TEXT,
|
updatetime TEXT,
|
||||||
viewtime TEXT,
|
viewtime TEXT,
|
||||||
userid INTEGER,
|
userid INTEGER,
|
||||||
username TEXT,
|
username TEXT,
|
||||||
flag INTEGER DEFAULT 1
|
flag INTEGER DEFAULT 1
|
||||||
);
|
);
|
||||||
CREATE TABLE `history` (
|
CREATE TABLE `history` (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
nid INTEGER,
|
nid INTEGER,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
context TEXT,
|
context TEXT,
|
||||||
conjson TEXT,
|
conjson TEXT,
|
||||||
createtime TEXT,
|
createtime TEXT,
|
||||||
userid INTEGER,
|
userid INTEGER,
|
||||||
username TEXT
|
username TEXT,
|
||||||
);
|
flag INTEGER DEFAULT 1
|
||||||
CREATE TABLE appx (
|
);
|
||||||
app_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
CREATE TABLE appx (
|
||||||
app_key TEXT,
|
app_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
akey TEXT,
|
app_key TEXT,
|
||||||
ugroup_id INTEGER DEFAULT 0,
|
akey TEXT,
|
||||||
agroup_id INTEGER,
|
ugroup_id INTEGER DEFAULT 0,
|
||||||
name TEXT,
|
agroup_id INTEGER,
|
||||||
note TEXT,
|
name TEXT,
|
||||||
ar_is_setting INTEGER NOT NULL DEFAULT 0,
|
note TEXT,
|
||||||
ar_is_examine INTEGER NOT NULL DEFAULT 0,
|
ar_is_setting INTEGER NOT NULL DEFAULT 0,
|
||||||
ar_examine_ver INTEGER NOT NULL DEFAULT 0,
|
ar_is_examine INTEGER NOT NULL DEFAULT 0,
|
||||||
log_fulltime TEXT
|
ar_examine_ver INTEGER NOT NULL DEFAULT 0,
|
||||||
);
|
log_fulltime TEXT
|
||||||
|
);
|
||||||
INSERT INTO `user` VALUES ('1', 'aaaaaaaaa', 'cyy123', 'admin', 'admin','','');
|
|
||||||
INSERT INTO `user` VALUES ('2', 'aaaaaaaaa', 'test', 'test', 'test','','');
|
INSERT INTO `user` VALUES ('1', 'aaaaaaaaa', 'cyy123', 'admin', 'admin','','');
|
||||||
|
INSERT INTO `user` VALUES ('2', 'aaaaaaaaa', 'test', 'test', 'test','','');
|
||||||
INSERT INTO `note` VALUES ('1', '0', 'test', 'test', 'test','','','','1','1','1');
|
INSERT INTO `note` VALUES ('1', '0', 'test', 'test', 'test','','','','1','1','1');
|
||||||
@@ -38,7 +38,6 @@
|
|||||||
"@lexical/table": "0.44.0",
|
"@lexical/table": "0.44.0",
|
||||||
"@lexical/utils": "0.44.0",
|
"@lexical/utils": "0.44.0",
|
||||||
"@lexical/yjs": "0.44.0",
|
"@lexical/yjs": "0.44.0",
|
||||||
"@tanstack/react-query": "^5.74.0",
|
|
||||||
"axios": "^1.8.0",
|
"axios": "^1.8.0",
|
||||||
"html-react-parser": "^5.2.0",
|
"html-react-parser": "^5.2.0",
|
||||||
"katex": "^0.16.21",
|
"katex": "^0.16.21",
|
||||||
|
|||||||
@@ -1,54 +1,23 @@
|
|||||||
import { Component } from "react";
|
import { useEffect, useState } from 'react';
|
||||||
|
import userService from '../services/user.service';
|
||||||
|
|
||||||
import UserService from "../services/user.service";
|
export default function BoardAdmin() {
|
||||||
import EventBus from "../common/EventBus";
|
const [content, setContent] = useState('');
|
||||||
|
|
||||||
type Props = {};
|
useEffect(() => {
|
||||||
|
userService.getAdminBoard().then(
|
||||||
type State = {
|
(res) => setContent(String(res.data ?? '')),
|
||||||
content: string;
|
(error: unknown) => {
|
||||||
}
|
setContent(error instanceof Error ? error.message : String(error));
|
||||||
|
|
||||||
export default class BoardAdmin extends Component<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
content: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
UserService.getAdminBoard().then(
|
|
||||||
response => {
|
|
||||||
this.setState({
|
|
||||||
content: response.data
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
error => {
|
|
||||||
this.setState({
|
|
||||||
content:
|
|
||||||
(error.response &&
|
|
||||||
error.response.data &&
|
|
||||||
error.response.data.message) ||
|
|
||||||
error.message ||
|
|
||||||
error.toString()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error.response && error.response.status === 401) {
|
|
||||||
EventBus.dispatch("logout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
return (
|
<div className="container">
|
||||||
<div className="container">
|
<header className="jumbotron">
|
||||||
<header className="jumbotron">
|
<h3>{content}</h3>
|
||||||
<h3>{this.state.content}</h3>
|
</header>
|
||||||
</header>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,23 @@
|
|||||||
import { Component } from "react";
|
import { useEffect, useState } from 'react';
|
||||||
|
import userService from '../services/user.service';
|
||||||
|
|
||||||
import UserService from "../services/user.service";
|
export default function BoardModerator() {
|
||||||
import EventBus from "../common/EventBus";
|
const [content, setContent] = useState('');
|
||||||
|
|
||||||
type Props = {};
|
useEffect(() => {
|
||||||
|
userService.getModeratorBoard().then(
|
||||||
type State = {
|
(res) => setContent(String(res.data ?? '')),
|
||||||
content: string;
|
(error: unknown) => {
|
||||||
}
|
setContent(error instanceof Error ? error.message : String(error));
|
||||||
|
|
||||||
export default class BoardAdmin extends Component<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
content: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
UserService.getModeratorBoard().then(
|
|
||||||
response => {
|
|
||||||
this.setState({
|
|
||||||
content: response.data
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
error => {
|
|
||||||
this.setState({
|
|
||||||
content:
|
|
||||||
(error.response &&
|
|
||||||
error.response.data &&
|
|
||||||
error.response.data.message) ||
|
|
||||||
error.message ||
|
|
||||||
error.toString()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error.response && error.response.status === 401) {
|
|
||||||
EventBus.dispatch("logout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
return (
|
<div className="container">
|
||||||
<div className="container">
|
<header className="jumbotron">
|
||||||
<header className="jumbotron">
|
<h3>{content}</h3>
|
||||||
<h3>{this.state.content}</h3>
|
</header>
|
||||||
</header>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,23 @@
|
|||||||
import { Component } from "react";
|
import { useEffect, useState } from 'react';
|
||||||
|
import userService from '../services/user.service';
|
||||||
|
|
||||||
import UserService from "../services/user.service";
|
export default function BoardUser() {
|
||||||
import EventBus from "../common/EventBus";
|
const [content, setContent] = useState('');
|
||||||
|
|
||||||
type Props = {};
|
useEffect(() => {
|
||||||
|
userService.getUserBoard().then(
|
||||||
type State = {
|
(res) => setContent(String(res.data ?? '')),
|
||||||
content: string;
|
(error: unknown) => {
|
||||||
}
|
setContent(error instanceof Error ? error.message : String(error));
|
||||||
|
|
||||||
export default class BoardUser extends Component<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
content: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
UserService.getUserBoard().then(
|
|
||||||
response => {
|
|
||||||
this.setState({
|
|
||||||
content: response.data
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
error => {
|
|
||||||
this.setState({
|
|
||||||
content:
|
|
||||||
(error.response &&
|
|
||||||
error.response.data &&
|
|
||||||
error.response.data.message) ||
|
|
||||||
error.message ||
|
|
||||||
error.toString()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error.response && error.response.status === 401) {
|
|
||||||
EventBus.dispatch("logout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
return (
|
<div className="container">
|
||||||
<div className="container">
|
<header className="jumbotron">
|
||||||
<header className="jumbotron">
|
<h3>{content}</h3>
|
||||||
<h3>{this.state.content}</h3>
|
</header>
|
||||||
</header>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useUIStore } from '../../stores/useUIStore';
|
|||||||
import authService from '../../services/auth.service';
|
import authService from '../../services/auth.service';
|
||||||
|
|
||||||
export default function PasswordModal() {
|
export default function PasswordModal() {
|
||||||
const { updatePasswordModelVisible, setUpdatePasswordModelVisible } = useUIStore();
|
const { updatePasswordModalVisible, setUpdatePasswordModalVisible } = useUIStore();
|
||||||
const user = useAuthStore((s) => s.user);
|
const user = useAuthStore((s) => s.user);
|
||||||
|
|
||||||
const handleSubmit = (values: {
|
const handleSubmit = (values: {
|
||||||
@@ -17,7 +17,7 @@ export default function PasswordModal() {
|
|||||||
.then(
|
.then(
|
||||||
() => {
|
() => {
|
||||||
Toast.success('密码修改成功');
|
Toast.success('密码修改成功');
|
||||||
setUpdatePasswordModelVisible(false);
|
setUpdatePasswordModalVisible(false);
|
||||||
},
|
},
|
||||||
(error: unknown) => {
|
(error: unknown) => {
|
||||||
const msg =
|
const msg =
|
||||||
@@ -30,10 +30,10 @@ export default function PasswordModal() {
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="修改密码"
|
title="修改密码"
|
||||||
visible={updatePasswordModelVisible}
|
visible={updatePasswordModalVisible}
|
||||||
size="large"
|
size="large"
|
||||||
footer={null}
|
footer={null}
|
||||||
onCancel={() => setUpdatePasswordModelVisible(false)}
|
onCancel={() => setUpdatePasswordModalVisible(false)}
|
||||||
closeOnEsc
|
closeOnEsc
|
||||||
>
|
>
|
||||||
<div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
|
<div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ interface TrashListModalProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function TrashListModal({ trashList, onRestored }: TrashListModalProps) {
|
export default function TrashListModal({ trashList, onRestored }: TrashListModalProps) {
|
||||||
const { deleteModelVisible, setDeleteModelVisible } = useUIStore();
|
const { deleteModalVisible, setDeleteModalVisible } = useUIStore();
|
||||||
|
|
||||||
const handleRestore = (id: number) => {
|
const handleRestore = (id: number) => {
|
||||||
noteService.restoreFromTrash(id).then(
|
noteService.restoreFromTrash(id).then(
|
||||||
() => {
|
() => {
|
||||||
Toast.success('已从回收站恢复');
|
Toast.success('已从回收站恢复');
|
||||||
setDeleteModelVisible(false);
|
setDeleteModalVisible(false);
|
||||||
onRestored();
|
onRestored();
|
||||||
},
|
},
|
||||||
() => Toast.error('恢复失败,请重试'),
|
() => Toast.error('恢复失败,请重试'),
|
||||||
@@ -26,10 +26,10 @@ export default function TrashListModal({ trashList, onRestored }: TrashListModal
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="回收站"
|
title="回收站"
|
||||||
visible={deleteModelVisible}
|
visible={deleteModalVisible}
|
||||||
size="large"
|
size="large"
|
||||||
footer={null}
|
footer={null}
|
||||||
onCancel={() => setDeleteModelVisible(false)}
|
onCancel={() => setDeleteModalVisible(false)}
|
||||||
closeOnEsc
|
closeOnEsc
|
||||||
>
|
>
|
||||||
<div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
|
<div style={{ padding: 12, border: '1px solid var(--semi-color-border)', margin: 12 }}>
|
||||||
|
|||||||
@@ -1,69 +1,37 @@
|
|||||||
import { Component } from "react";
|
|
||||||
import { Navigate } from 'react-router';
|
import { Navigate } from 'react-router';
|
||||||
import AuthService from "../services/auth.service";
|
import { useAuthStore } from '../stores/useAuthStore';
|
||||||
import type { IUser } from '../types';
|
|
||||||
|
|
||||||
type Props = {};
|
export default function Profile() {
|
||||||
|
const user = useAuthStore((s) => s.user);
|
||||||
|
const token = useAuthStore((s) => s.token);
|
||||||
|
|
||||||
type State = {
|
if (!user) return <Navigate to="/login" replace />;
|
||||||
redirect: string | null,
|
|
||||||
userReady: boolean,
|
|
||||||
currentUser: IUser & { accessToken: string }
|
|
||||||
}
|
|
||||||
export default class Profile extends Component<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
return (
|
||||||
redirect: null,
|
<div className="container">
|
||||||
userReady: false,
|
<div>
|
||||||
currentUser: { accessToken: "" }
|
<header className="jumbotron">
|
||||||
};
|
<h3>
|
||||||
}
|
<strong>{user.username}</strong> Profile
|
||||||
|
</h3>
|
||||||
componentDidMount() {
|
</header>
|
||||||
const currentUser = AuthService.getCurrentUser();
|
<p>
|
||||||
|
<strong>Token:</strong>{' '}
|
||||||
if (!currentUser) this.setState({ redirect: "/home" });
|
{token ? `${token.substring(0, 20)} ... ${token.substring(token.length - 20)}` : 'N/A'}
|
||||||
this.setState({ currentUser: currentUser, userReady: true })
|
</p>
|
||||||
}
|
<p>
|
||||||
|
<strong>Id:</strong> {user.id}
|
||||||
render() {
|
</p>
|
||||||
if (this.state.redirect) {
|
<p>
|
||||||
return <Navigate to={this.state.redirect} />
|
<strong>Email:</strong> {user.email}
|
||||||
}
|
</p>
|
||||||
|
<strong>Authorities:</strong>
|
||||||
const { currentUser } = this.state;
|
<ul>
|
||||||
|
{user.roles.map((role, index) => (
|
||||||
return (
|
<li key={index}>{role}</li>
|
||||||
<div className="container">
|
))}
|
||||||
{(this.state.userReady) ?
|
</ul>
|
||||||
<div>
|
|
||||||
<header className="jumbotron">
|
|
||||||
<h3>
|
|
||||||
<strong>{currentUser.username}</strong> Profile
|
|
||||||
</h3>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
<strong>Token:</strong>{" "}
|
|
||||||
{currentUser.accessToken.substring(0, 20)} ...{" "}
|
|
||||||
{currentUser.accessToken.substr(currentUser.accessToken.length - 20)}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Id:</strong>{" "}
|
|
||||||
{currentUser.id}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Email:</strong>{" "}
|
|
||||||
{currentUser.email}
|
|
||||||
</p>
|
|
||||||
<strong>Authorities:</strong>
|
|
||||||
<ul>
|
|
||||||
{currentUser.roles &&
|
|
||||||
currentUser.roles.map((role, index) => <li key={index}>{role}</li>)}
|
|
||||||
</ul>
|
|
||||||
</div> : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ export default function NoteTree({ onRefreshTree, onNavItemClick, onSearch }: No
|
|||||||
const { treeData, viewData, currentNoteId, setCurrentNote } = useNoteStore();
|
const { treeData, viewData, currentNoteId, setCurrentNote } = useNoteStore();
|
||||||
const { openDeleteConfirm, setSearchQuery, searchQuery, setActiveView } = useUIStore();
|
const { openDeleteConfirm, setSearchQuery, searchQuery, setActiveView } = useUIStore();
|
||||||
|
|
||||||
|
const toNoteId = (id: string | number) => Number(id);
|
||||||
|
|
||||||
const loadNote = useCallback(
|
const loadNote = useCallback(
|
||||||
(id: number) => {
|
(id: number) => {
|
||||||
noteService.get(id).then(
|
noteService.get(id).then(
|
||||||
@@ -81,7 +83,7 @@ export default function NoteTree({ onRefreshTree, onNavItemClick, onSearch }: No
|
|||||||
size="small"
|
size="small"
|
||||||
icon={<IconCopyAdd />}
|
icon={<IconCopyAdd />}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
addNote(item.key);
|
addNote(toNoteId(item.key));
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -90,7 +92,7 @@ export default function NoteTree({ onRefreshTree, onNavItemClick, onSearch }: No
|
|||||||
type="warning"
|
type="warning"
|
||||||
icon={<IconDelete />}
|
icon={<IconDelete />}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
openDeleteConfirm(item.key, String(label));
|
openDeleteConfirm(toNoteId(item.key), String(label));
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -188,11 +190,11 @@ export default function NoteTree({ onRefreshTree, onNavItemClick, onSearch }: No
|
|||||||
showFilteredOnly
|
showFilteredOnly
|
||||||
directory
|
directory
|
||||||
virtualize
|
virtualize
|
||||||
value={currentNoteId}
|
value={currentNoteId === null ? undefined : String(currentNoteId)}
|
||||||
treeData={treeData as unknown as Parameters<typeof Tree>[0]['treeData']}
|
treeData={treeData as unknown as Parameters<typeof Tree>[0]['treeData']}
|
||||||
renderLabel={renderLabel as Parameters<typeof Tree>[0]['renderLabel']}
|
renderLabel={renderLabel as Parameters<typeof Tree>[0]['renderLabel']}
|
||||||
style={treeStyle}
|
style={treeStyle}
|
||||||
onSelect={(id) => loadNote(id as unknown as number)}
|
onSelect={(id) => loadNote(toNoteId(id as string | number))}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,17 +9,20 @@ import {
|
|||||||
Toast,
|
Toast,
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import { useNoteStore } from '../../stores/useNoteStore';
|
import { useNoteStore } from '../../stores/useNoteStore';
|
||||||
|
import { useUIStore } from '../../stores/useUIStore';
|
||||||
import noteService from '../../services/note.service';
|
import noteService from '../../services/note.service';
|
||||||
import type { INote } from '../../types';
|
import type { INote } from '../../types';
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const { homeData, setHomeData, setCurrentNote } = useNoteStore();
|
const { homeData, setHomeData, setCurrentNote } = useNoteStore();
|
||||||
|
const setActiveView = useUIStore((s) => s.setActiveView);
|
||||||
|
|
||||||
const loadNote = (id: number) => {
|
const loadNote = (id: number) => {
|
||||||
noteService.get(id).then(
|
noteService.get(id).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
const note = res.data;
|
const note = res.data;
|
||||||
setCurrentNote(note.id, note.title, note.context);
|
setCurrentNote(note.id, note.title, note.context);
|
||||||
|
setActiveView('note');
|
||||||
},
|
},
|
||||||
() => Toast.error('加载笔记失败'),
|
() => Toast.error('加载笔记失败'),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ export default function NotePage() {
|
|||||||
setActiveView,
|
setActiveView,
|
||||||
setSiderFlag,
|
setSiderFlag,
|
||||||
setSideVisible,
|
setSideVisible,
|
||||||
setDeleteModelVisible,
|
setDeleteModalVisible,
|
||||||
setUpdatePasswordModelVisible,
|
setUpdatePasswordModalVisible,
|
||||||
} = useUIStore();
|
} = useUIStore();
|
||||||
|
|
||||||
const [trashList, setTrashList] = useState<INote[]>([]);
|
const [trashList, setTrashList] = useState<INote[]>([]);
|
||||||
@@ -102,13 +102,13 @@ export default function NotePage() {
|
|||||||
noteService.getHomeData('4', '0').then(
|
noteService.getHomeData('4', '0').then(
|
||||||
(res) => {
|
(res) => {
|
||||||
setTrashList(res.data);
|
setTrashList(res.data);
|
||||||
setDeleteModelVisible(true);
|
setDeleteModalVisible(true);
|
||||||
},
|
},
|
||||||
() => Toast.error('加载回收站失败'),
|
() => Toast.error('加载回收站失败'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setActiveView, setDeleteModelVisible],
|
[setActiveView, setDeleteModalVisible],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSearch = useCallback(() => {
|
const handleSearch = useCallback(() => {
|
||||||
@@ -244,7 +244,7 @@ export default function NotePage() {
|
|||||||
theme="solid"
|
theme="solid"
|
||||||
type="secondary"
|
type="secondary"
|
||||||
style={{ marginRight: 8 }}
|
style={{ marginRight: 8 }}
|
||||||
onClick={() => setUpdatePasswordModelVisible(true)}
|
onClick={() => setUpdatePasswordModalVisible(true)}
|
||||||
>
|
>
|
||||||
修改密码
|
修改密码
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ interface UIState {
|
|||||||
deleteVisible: boolean;
|
deleteVisible: boolean;
|
||||||
deleteId: number | null;
|
deleteId: number | null;
|
||||||
deleteNoteName: string;
|
deleteNoteName: string;
|
||||||
deleteModelVisible: boolean;
|
deleteModalVisible: boolean;
|
||||||
updatePasswordModelVisible: boolean;
|
updatePasswordModalVisible: boolean;
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
setActiveView: (view: ActiveView) => void;
|
setActiveView: (view: ActiveView) => void;
|
||||||
setSideVisible: (visible: boolean) => void;
|
setSideVisible: (visible: boolean) => void;
|
||||||
@@ -19,8 +19,8 @@ interface UIState {
|
|||||||
setNoteLoading: (loading: boolean) => void;
|
setNoteLoading: (loading: boolean) => void;
|
||||||
openDeleteConfirm: (id: number, name: string) => void;
|
openDeleteConfirm: (id: number, name: string) => void;
|
||||||
closeDeleteConfirm: () => void;
|
closeDeleteConfirm: () => void;
|
||||||
setDeleteModelVisible: (visible: boolean) => void;
|
setDeleteModalVisible: (visible: boolean) => void;
|
||||||
setUpdatePasswordModelVisible: (visible: boolean) => void;
|
setUpdatePasswordModalVisible: (visible: boolean) => void;
|
||||||
setSearchQuery: (query: string) => void;
|
setSearchQuery: (query: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ export const useUIStore = create<UIState>()((set) => ({
|
|||||||
deleteVisible: false,
|
deleteVisible: false,
|
||||||
deleteId: null,
|
deleteId: null,
|
||||||
deleteNoteName: '',
|
deleteNoteName: '',
|
||||||
deleteModelVisible: false,
|
deleteModalVisible: false,
|
||||||
updatePasswordModelVisible: false,
|
updatePasswordModalVisible: false,
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
setActiveView: (activeView) => set({ activeView }),
|
setActiveView: (activeView) => set({ activeView }),
|
||||||
setSideVisible: (sideVisible) => set({ sideVisible }),
|
setSideVisible: (sideVisible) => set({ sideVisible }),
|
||||||
@@ -43,8 +43,8 @@ export const useUIStore = create<UIState>()((set) => ({
|
|||||||
set({ deleteVisible: true, deleteId, deleteNoteName }),
|
set({ deleteVisible: true, deleteId, deleteNoteName }),
|
||||||
closeDeleteConfirm: () =>
|
closeDeleteConfirm: () =>
|
||||||
set({ deleteVisible: false, deleteId: null, deleteNoteName: '' }),
|
set({ deleteVisible: false, deleteId: null, deleteNoteName: '' }),
|
||||||
setDeleteModelVisible: (deleteModelVisible) => set({ deleteModelVisible }),
|
setDeleteModalVisible: (deleteModalVisible) => set({ deleteModalVisible }),
|
||||||
setUpdatePasswordModelVisible: (updatePasswordModelVisible) =>
|
setUpdatePasswordModalVisible: (updatePasswordModalVisible) =>
|
||||||
set({ updatePasswordModelVisible }),
|
set({ updatePasswordModalVisible }),
|
||||||
setSearchQuery: (searchQuery) => set({ searchQuery }),
|
setSearchQuery: (searchQuery) => set({ searchQuery }),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ export interface INote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ITreeNode {
|
export interface ITreeNode {
|
||||||
key: number;
|
id?: number;
|
||||||
|
pid?: number;
|
||||||
|
key: string;
|
||||||
|
value?: string;
|
||||||
label: string;
|
label: string;
|
||||||
children?: ITreeNode[];
|
children?: ITreeNode[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,12 @@
|
|||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": false,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
/* Path aliases */
|
/* Path aliases */
|
||||||
|
"ignoreDeprecations": "6.0",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
@@ -23,8 +24,8 @@
|
|||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": false,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
|
|||||||
Reference in New Issue
Block a user