|
@@ -29,145 +29,252 @@ AI日记的辅助AI应用,用户(User)、日记、聊天消息、动态、互
|
|
|
|
|
|
# UML类图
|
|
|
```plantuml
|
|
|
-@startuml
|
|
|
-' 设置主题
|
|
|
-skinparam class {
|
|
|
- BackgroundColor White
|
|
|
- ArrowColor #0078D7
|
|
|
- BorderColor #0078D7
|
|
|
+@startuml
|
|
|
+class _User {
|
|
|
+ .. 系统预留字段 ..
|
|
|
+ + objectId: String
|
|
|
+ + username: String
|
|
|
+ + email: String
|
|
|
+ + emailVerified: bool
|
|
|
+ + authData: Object
|
|
|
+ + password: String
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ .. 自定义字段 ..
|
|
|
+ + nickname: String
|
|
|
+ + avatar: File
|
|
|
+ + bio: String
|
|
|
+ + lastActiveAt: Date
|
|
|
+ + privacySettings: Object
|
|
|
}
|
|
|
|
|
|
-' 用户表(使用Parse预留表)
|
|
|
-class _User {
|
|
|
- + objectId: String [PK]
|
|
|
- + username: String
|
|
|
- + email: String
|
|
|
- + authData: Object
|
|
|
- + emailVerified: bool
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + profilePicture: File
|
|
|
- + lastActiveAt: Date
|
|
|
+class Diary {
|
|
|
+ + objectId: String
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + title: String
|
|
|
+ + content: String
|
|
|
+ + author: Pointer<_User>
|
|
|
+ + mood: String
|
|
|
+ + tags: Array
|
|
|
+ + isPublic: bool
|
|
|
+ + location: GeoPoint
|
|
|
+ + weather: Object
|
|
|
+ + aiAnalysis: Object
|
|
|
+}
|
|
|
+
|
|
|
+class ChatMessage {
|
|
|
+ + objectId: String
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + sender: Pointer<_User>
|
|
|
+ + receiver: Pointer<_User>
|
|
|
+ + content: String
|
|
|
+ + diaryRef: Pointer<Diary>
|
|
|
+ + isRead: bool
|
|
|
+ + messageType: String
|
|
|
+ + attachments: Array<File>
|
|
|
}
|
|
|
|
|
|
-' 动态表
|
|
|
class Dynamic {
|
|
|
- + objectId: String [PK]
|
|
|
- + content: String
|
|
|
- + images: Array<File>
|
|
|
- + location: GeoPoint
|
|
|
- + mood: String
|
|
|
- + tags: Array<String>
|
|
|
- + isPublic: bool
|
|
|
- + likeCount: Number
|
|
|
- + commentCount: Number
|
|
|
- + shareCount: Number
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + author: Pointer<_User>
|
|
|
+ + objectId: String
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + creator: Pointer<_User>
|
|
|
+ + content: String
|
|
|
+ + images: Array<File>
|
|
|
+ + refDiary: Pointer<Diary>
|
|
|
+ + location: GeoPoint
|
|
|
+ + tags: Array
|
|
|
+ + interactionCount: Number
|
|
|
}
|
|
|
|
|
|
-' 互动表(包含点赞、评论、分享)
|
|
|
class Interaction {
|
|
|
- + objectId: String [PK]
|
|
|
- + type: String // 'like'|'comment'|'share'
|
|
|
- + content: String // 评论内容
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + user: Pointer<_User>
|
|
|
- + diary: Pointer<Dynamic>
|
|
|
- + targetUser: Pointer<_User> // 互动目标用户(分享给谁/回复谁)
|
|
|
+ + objectId: String
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + type: String
|
|
|
+ + fromUser: Pointer<_User>
|
|
|
+ + toUser: Pointer<_User>
|
|
|
+ + targetType: String
|
|
|
+ + targetId: Pointer
|
|
|
+ + content: String
|
|
|
+ + status: String
|
|
|
}
|
|
|
|
|
|
-' 关系定义
|
|
|
-_User "1" --> "*" Dynamic : 发布
|
|
|
-_User "1" --> "*" Interaction : 发起
|
|
|
-Dynamic "1" --> "*" Interaction : 拥有
|
|
|
-_User "1" --> "*" Interaction : 接收互动(targetUser)
|
|
|
+class ThanksType {
|
|
|
+ + objectId: String
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + creator: Pointer<_User>
|
|
|
+ + title: String
|
|
|
+ + items: Array<{
|
|
|
+ content: String
|
|
|
+ category: String
|
|
|
+ stars: Number
|
|
|
+ }>
|
|
|
+ + themeColor: String
|
|
|
+ + isShared: bool
|
|
|
+ + weeklyGoal: Number
|
|
|
+}
|
|
|
+
|
|
|
+' 核心关系定义
|
|
|
+_User "1" *-- "many" Diary : 创作
|
|
|
+_User "1" *-- "many" ChatMessage : 发送
|
|
|
+_User "1" *-- "many" Dynamic : 发布
|
|
|
+_User "1" *-- "many" Interaction : 发起
|
|
|
+_User "1" *-- "many" ThanksType : 创建
|
|
|
+
|
|
|
+Diary "1" *-- "many" ChatMessage : 关联
|
|
|
+Diary "1" *-- "many" Dynamic : 引用
|
|
|
+Diary "1" *-- "many" Interaction : 接收
|
|
|
+
|
|
|
+Dynamic "1" *-- "many" Interaction : 接收
|
|
|
+
|
|
|
+ThanksType "1" *-- "0..many" Interaction : 接收互动
|
|
|
+
|
|
|
@enduml
|
|
|
```
|
|
|
+
|
|
|
# SQL语句
|
|
|
|
|
|
### 建表语句
|
|
|
```sql
|
|
|
--- 用户表(基于ParseServer的_User表结构扩展)
|
|
|
+-- 用户表(ParseServer 内置 _User 表结构)
|
|
|
CREATE TABLE "_User" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "username" VARCHAR(50) UNIQUE NOT NULL,
|
|
|
- "email" VARCHAR(255) UNIQUE,
|
|
|
- "authData" JSONB,
|
|
|
- "emailVerified" BOOLEAN DEFAULT false,
|
|
|
- "profilePicture" TEXT, -- Parse.File存储的URL
|
|
|
- "lastActiveAt" TIMESTAMP WITH TIME ZONE,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "username" VARCHAR(255) UNIQUE NOT NULL,
|
|
|
+ "email" VARCHAR(255) UNIQUE,
|
|
|
+ "emailVerified" BOOLEAN DEFAULT false,
|
|
|
+ "authData" JSONB,
|
|
|
+ "password" VARCHAR(255),
|
|
|
+ "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "nickname" VARCHAR(100),
|
|
|
+ "avatar" VARCHAR(255),
|
|
|
+ "bio" TEXT,
|
|
|
+ "lastActiveAt" TIMESTAMPTZ,
|
|
|
+ "privacySettings" JSONB
|
|
|
+);
|
|
|
+
|
|
|
+-- 日记表
|
|
|
+CREATE TABLE "Diary" (
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "title" VARCHAR(200) NOT NULL,
|
|
|
+ "content" TEXT NOT NULL,
|
|
|
+ "author" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "mood" VARCHAR(50),
|
|
|
+ "tags" JSONB DEFAULT '[]'::JSONB,
|
|
|
+ "isPublic" BOOLEAN DEFAULT false,
|
|
|
+ "location" JSONB,
|
|
|
+ "weather" JSONB,
|
|
|
+ "aiAnalysis" JSONB
|
|
|
+);
|
|
|
+
|
|
|
+-- 聊天消息表
|
|
|
+CREATE TABLE "ChatMessage" (
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "sender" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "receiver" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "content" TEXT,
|
|
|
+ "diaryRef" VARCHAR(36) REFERENCES "Diary"("objectId"),
|
|
|
+ "isRead" BOOLEAN DEFAULT false,
|
|
|
+ "messageType" VARCHAR(20) DEFAULT 'text',
|
|
|
+ "attachments" JSONB DEFAULT '[]'::JSONB
|
|
|
);
|
|
|
|
|
|
-- 动态表
|
|
|
CREATE TABLE "Dynamic" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "content" TEXT NOT NULL,
|
|
|
- "images" JSONB, -- 存储File URL数组
|
|
|
- "location" JSONB, -- {latitude: xx, longitude: yy}
|
|
|
- "mood" VARCHAR(20),
|
|
|
- "tags" JSONB, -- 字符串数组
|
|
|
- "isPublic" BOOLEAN DEFAULT true,
|
|
|
- "likeCount" INTEGER DEFAULT 0,
|
|
|
- "commentCount" INTEGER DEFAULT 0,
|
|
|
- "shareCount" INTEGER DEFAULT 0,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "author" VARCHAR(36) NOT NULL REFERENCES "_User"("objectId")
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "creator" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "content" TEXT,
|
|
|
+ "images" JSONB DEFAULT '[]'::JSONB,
|
|
|
+ "refDiary" VARCHAR(36) REFERENCES "Diary"("objectId"),
|
|
|
+ "location" JSONB,
|
|
|
+ "tags" JSONB DEFAULT '[]'::JSONB,
|
|
|
+ "interactionCount" INTEGER DEFAULT 0
|
|
|
);
|
|
|
|
|
|
-- 互动表
|
|
|
CREATE TABLE "Interaction" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "type" VARCHAR(10) CHECK ("type" IN ('like', 'comment', 'share')),
|
|
|
- "content" TEXT,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "user" VARCHAR(36) NOT NULL REFERENCES "_User"("objectId"),
|
|
|
- "diary" VARCHAR(36) NOT NULL REFERENCES "Dynamic"("objectId"),
|
|
|
- "targetUser" VARCHAR(36) REFERENCES "_User"("objectId")
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "type" VARCHAR(20) NOT NULL,
|
|
|
+ "fromUser" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "toUser" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "targetType" VARCHAR(20) NOT NULL,
|
|
|
+ "targetId" VARCHAR(36),
|
|
|
+ "content" TEXT,
|
|
|
+ "status" VARCHAR(20) DEFAULT 'unread'
|
|
|
+);
|
|
|
+
|
|
|
+-- 感恩清单表(新增)
|
|
|
+CREATE TABLE "ThanksType" (
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "createdAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "creator" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
+ "title" VARCHAR(200) NOT NULL,
|
|
|
+ "items" JSONB NOT NULL DEFAULT '[]'::JSONB,
|
|
|
+ "themeColor" VARCHAR(20) DEFAULT '#FFD700',
|
|
|
+ "isShared" BOOLEAN DEFAULT false,
|
|
|
+ "weeklyGoal" INTEGER CHECK ("weeklyGoal" > 0)
|
|
|
);
|
|
|
|
|
|
--- 创建更新时间触发器函数
|
|
|
-CREATE OR REPLACE FUNCTION update_timestamp()
|
|
|
-RETURNS TRIGGER AS $$
|
|
|
-BEGIN
|
|
|
- NEW."updatedAt" = CURRENT_TIMESTAMP;
|
|
|
- RETURN NEW;
|
|
|
-END;
|
|
|
-$$ LANGUAGE plpgsql;
|
|
|
-
|
|
|
--- 为每张表添加更新时间触发器
|
|
|
-CREATE TRIGGER update_user_timestamp
|
|
|
-BEFORE UPDATE ON "_User"
|
|
|
-FOR EACH ROW EXECUTE FUNCTION update_timestamp();
|
|
|
-
|
|
|
-CREATE TRIGGER update_diary_timestamp
|
|
|
-BEFORE UPDATE ON "Diary"
|
|
|
-FOR EACH ROW EXECUTE FUNCTION update_timestamp();
|
|
|
-
|
|
|
-CREATE TRIGGER update_interaction_timestamp
|
|
|
-BEFORE UPDATE ON "Interaction"
|
|
|
-FOR EACH ROW EXECUTE FUNCTION update_timestamp();
|
|
|
-
|
|
|
--- 测试数据插入
|
|
|
-INSERT INTO "_User" ("objectId", "username", "email", "emailVerified", "profilePicture", "lastActiveAt")
|
|
|
-VALUES
|
|
|
- ('usr001', 'testUser1', 'user1@example.com', true, 'https://example.com/pic1.jpg', NOW()),
|
|
|
- ('usr002', 'testUser2', 'user2@example.com', true, 'https://example.com/pic2.jpg', NOW());
|
|
|
-
|
|
|
-INSERT INTO "Dynamic" ("objectId", "content", "images", "location", "mood", "tags", "isPublic", "author")
|
|
|
-VALUES
|
|
|
- ('d001', '今天天气真好!', '["https://example.com/img1.jpg"]', '{"latitude": 39.9042, "longitude": 116.4074}', 'happy', '["天气","户外"]', true, 'usr001'),
|
|
|
- ('d002', '学习PostgreSQL很有趣', '[]', NULL, 'excited', '["学习","数据库"]', true, 'usr002');
|
|
|
-
|
|
|
-INSERT INTO "Interaction" ("objectId", "type", "content", "user", "diary", "targetUser")
|
|
|
-VALUES
|
|
|
- ('i001', 'like', NULL, 'usr002', 'd001', NULL),
|
|
|
- ('i002', 'comment', '我也觉得天气不错!', 'usr002', 'd001', NULL),
|
|
|
- ('i003', 'share', NULL, 'usr001', 'd002', 'usr002');
|
|
|
+-- 创建索引
|
|
|
+CREATE INDEX "idx_diary_author" ON "Diary" ("author");
|
|
|
+CREATE INDEX "idx_message_sender" ON "ChatMessage" ("sender");
|
|
|
+CREATE INDEX "idx_message_receiver" ON "ChatMessage" ("receiver");
|
|
|
+CREATE INDEX "idx_moment_creator" ON "Dynamic" ("creator");
|
|
|
+CREATE INDEX "idx_interaction_target" ON "Interaction" ("targetType", "targetId");
|
|
|
+CREATE INDEX "idx_thanks_creator" ON "ThanksType" ("creator");
|
|
|
+```
|
|
|
+
|
|
|
+```sql
|
|
|
+-- 插入测试用户
|
|
|
+INSERT INTO "_User" ("objectId", "username", "email", "nickname", "createdAt") VALUES
|
|
|
+('usr001', 'alice_wonder', 'alice@example.com', 'Alice', NOW()),
|
|
|
+('usr002', 'bob_builder', 'bob@example.com', 'Bob', NOW()),
|
|
|
+('usr003', 'charlie_dev', 'charlie@example.com', 'Charlie', NOW());
|
|
|
+
|
|
|
+-- 插入日记
|
|
|
+INSERT INTO "Diary" ("objectId", "title", "content", "author", "mood", "tags", "createdAt") VALUES
|
|
|
+('d001', '美好的一天', '今天天气晴朗,心情愉快...', 'usr001', 'happy', '["日常", "好天气"]'::JSONB, NOW()),
|
|
|
+('d002', '项目总结', '完成了数据库设计工作...', 'usr002', 'proud', '["工作", "成就"]'::JSONB, NOW()),
|
|
|
+('d003', '感恩日记', '感谢生命中所有的小确幸...', 'usr003', 'grateful', '["感恩", "生活"]'::JSONB, NOW());
|
|
|
+
|
|
|
+-- 插入感恩清单
|
|
|
+INSERT INTO "ThanksType" ("objectId", "creator", "title", "items", "weeklyGoal", "createdAt") VALUES
|
|
|
+('thanks001', 'usr001', '每日感恩',
|
|
|
+'[{"content": "家人的支持", "category": "家庭", "stars": 5},
|
|
|
+ {"content": "美味的午餐", "category": "生活", "stars": 3}]'::JSONB,
|
|
|
+5, NOW()),
|
|
|
+('thanks002', 'usr002', '工作感恩',
|
|
|
+'[{"content": "同事的帮助", "category": "工作", "stars": 4},
|
|
|
+ {"content": "项目顺利完成", "category": "成就", "stars": 5}]'::JSONB,
|
|
|
+3, NOW());
|
|
|
+
|
|
|
+-- 插入动态
|
|
|
+INSERT INTO "Dynamic" ("objectId", "creator", "content", "refDiary", "images", "createdAt") VALUES
|
|
|
+('m001', 'usr001', '分享今天的快乐时刻', 'd001', '["image1.jpg", "image2.jpg"]'::JSONB, NOW()),
|
|
|
+('m002', 'usr002', '技术分享:数据库设计', 'd002', '["tech1.png"]'::JSONB, NOW());
|
|
|
+
|
|
|
+-- 插入互动
|
|
|
+INSERT INTO "Interaction" ("objectId", "type", "fromUser", "toUser", "targetType", "targetId", "content", "createdAt") VALUES
|
|
|
+('i001', 'like', 'usr002', 'usr001', 'Diary', 'd001', NULL, NOW()),
|
|
|
+('i002', 'comment', 'usr001', 'usr002', 'Dynamic', 'm002', '写得真好!', NOW()),
|
|
|
+('i003', 'like', 'usr003', 'usr001', 'ThanksType', 'thanks001', NULL, NOW());
|
|
|
+
|
|
|
+-- 插入聊天消息
|
|
|
+INSERT INTO "ChatMessage" ("objectId", "sender", "receiver", "content", "diaryRef", "createdAt") VALUES
|
|
|
+('msg001', 'usr001', 'usr002', '你好,看了你的日记', 'd002', NOW()),
|
|
|
+('msg002', 'usr002', 'usr001', '谢谢关注!', 'd002', NOW()),
|
|
|
+('msg003', 'usr003', 'usr001', '你的感恩清单很棒!', NULL, NOW());
|
|
|
```
|