diff --git a/.gitignore b/.gitignore
index 5d8e194..5fd955a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@ build
electron
.local.env
+
+.vs/
diff --git a/database/graphql/homework_reply.graphql b/database/graphql/homework_reply.graphql
new file mode 100644
index 0000000..8ebe315
--- /dev/null
+++ b/database/graphql/homework_reply.graphql
@@ -0,0 +1,74 @@
+# 作业三:聊天室消息的单层回复
+
+# 1. 发一条回复消息:reply_to 指向被回复的消息
+mutation replyMessage(
+ $user_uuid: uuid!,
+ $room_uuid: uuid!,
+ $content: String!,
+ $reply_to: uuid!
+) {
+ insert_message_one(object: {
+ user_uuid: $user_uuid,
+ room_uuid: $room_uuid,
+ content: $content,
+ reply_to: $reply_to
+ }) {
+ uuid
+ content
+ # 自引用外键的对象关系名:Hasura 中为目标表名 message
+ message {
+ uuid
+ content
+ }
+ }
+}
+
+# 2. 查询某个会议的消息,并带出每条消息回复的目标(单层)
+query messagesWithReply($room_uuid: uuid!) {
+ message(
+ where: { room_uuid: { _eq: $room_uuid } },
+ order_by: { created_at: asc }
+ ) {
+ uuid
+ content
+ created_at
+ user {
+ username
+ }
+ # 回复目标(通过 message.reply_to 外键的对象关系)
+ message {
+ uuid
+ content
+ user {
+ username
+ }
+ }
+ }
+}
+
+# 3. 查询某条消息收到了哪些回复
+query messageReplies($uuid: uuid!) {
+ message(where: { reply_to: { _eq: $uuid } }) {
+ uuid
+ content
+ user {
+ username
+ }
+ message {
+ uuid
+ content
+ }
+ }
+}
+
+# 4. 订阅某个会议的新消息(含回复关系),方便聊天室实时更新
+subscription messagesByRoomWithReply($room_uuid: uuid!) {
+ message(where: { room_uuid: { _eq: $room_uuid } }) {
+ uuid
+ content
+ message {
+ uuid
+ content
+ }
+ }
+}
diff --git a/database/sql/homework_reply.sql b/database/sql/homework_reply.sql
new file mode 100644
index 0000000..c94ee8d
--- /dev/null
+++ b/database/sql/homework_reply.sql
@@ -0,0 +1,14 @@
+-- 作业三:聊天室消息支持回复之前的某条消息(单层回复)
+-- 设计:给 message 增加可空的 reply_to 列,自引用 message.uuid。
+-- 被回复的消息删除时 reply_to 置空,避免出现悬空引用。
+
+alter table public.message
+ add column if not exists reply_to uuid;
+
+alter table public.message
+ drop constraint if exists message_reply_to_fkey;
+
+alter table public.message
+ add constraint message_reply_to_fkey
+ foreign key (reply_to) references public.message (uuid)
+ on delete set null;
diff --git a/database/sql/message.sql b/database/sql/message.sql
index 51c8108..2639f9b 100644
--- a/database/sql/message.sql
+++ b/database/sql/message.sql
@@ -42,3 +42,4 @@ insert into public.message (user_uuid, room_uuid, content) values
('00000000-0000-0000-0000-000000000004', '00000000-0000-0000-0000-100000000003', '好了,今天就到这里吧');
update public.message set created_at = '2021-01-01 00:00:00' where room_uuid = '00000000-0000-0000-0000-100000000002';
+-- 信息由AI生成
\ No newline at end of file
diff --git a/frontend/public/about-me.html b/frontend/public/about-me.html
new file mode 100644
index 0000000..ffe9c6c
--- /dev/null
+++ b/frontend/public/about-me.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ 关于我
+
+
+
+
+
+
+
+
+
+
基本信息
+
+
+ | 姓名 |
+ 赵奕然 |
+
+
+ | 班级 |
+ 无56 |
+
+
+
+
+
+
我的爱好
+
+
+
+
+
+
+
+
GitHub
+
+
![GitHub 头像]()
+
+
+
+
+
+
+
diff --git a/frontend/public/about-me.js b/frontend/public/about-me.js
new file mode 100644
index 0000000..cffeae6
--- /dev/null
+++ b/frontend/public/about-me.js
@@ -0,0 +1,46 @@
+const themeToggle = document.getElementById("theme-toggle");
+
+// ===== 功能 1:亮色 / 暗色模式 =====
+const applyTheme = (dark) => {
+ document.body.classList.toggle("dark", dark);
+ themeToggle.textContent = dark ? "切换到亮色模式" : "切换到暗色模式";
+};
+
+const savedTheme = localStorage.getItem("about-me-theme");
+applyTheme(savedTheme === "dark");
+
+themeToggle.addEventListener("click", () => {
+ const dark = !document.body.classList.contains("dark");
+ applyTheme(dark);
+ localStorage.setItem("about-me-theme", dark ? "dark" : "light");
+});
+
+// ===== 功能 2:拉取 GitHub 公开资料(网络资源) =====
+const githubAvatar = document.getElementById("github-avatar");
+const githubName = document.getElementById("github-name");
+const githubRepos = document.getElementById("github-repos");
+const githubError = document.getElementById("github-error");
+
+const loadGithubProfile = async () => {
+ try {
+ const response = await fetch("https://api.github.com/users/Victor-692");
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}`);
+ }
+ const user = await response.json();
+
+ githubAvatar.src = user.avatar_url;
+ githubAvatar.hidden = false;
+ githubName.textContent = user.name || user.login;
+ githubRepos.textContent = `公开仓库数:${user.public_repos}`;
+ githubError.hidden = true;
+ } catch (err) {
+ console.error(err);
+ githubName.textContent = "GitHub 资料加载失败";
+ githubRepos.textContent = "";
+ githubError.hidden = false;
+ githubError.textContent = "请检查网络后刷新页面。";
+ }
+};
+
+loadGithubProfile();
diff --git a/frontend/public/index.css b/frontend/public/index.css
index 1cb6bf9..bdc1881 100644
--- a/frontend/public/index.css
+++ b/frontend/public/index.css
@@ -63,17 +63,140 @@
line-height: 2em;
}
-#clock {
- position: absolute;
- bottom: 0;
- left: 12px;
- width: 40vw;
+/* ===== 关于我页面 ===== */
+#about-me-frame {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+ padding: 32px 16px;
+ box-sizing: border-box;
+ background: linear-gradient(135deg, #fbc2eb 0%, #a6c1ee 100%);
}
-#motto {
+.about-me-card {
+ background-color: rgba(255, 255, 255, 0.35);
+}
+
+#about-me-header {
+ width: min(640px, 92vw);
+ text-align: center;
+}
+
+#about-me-avatar {
+ width: 88px;
+ height: 88px;
+ margin: 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ font-size: 40px;
+ color: #ffffff;
+ background: linear-gradient(135deg, #6a82fb 0%, #fc5c7d 100%);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
+}
+
+.about-me-subtitle {
+ color: rgba(0, 0, 0, 0.65);
+}
+
+#about-me-grid {
+ width: min(920px, 94vw);
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 16px;
+}
+
+.about-me-col {
+ flex: 1 1 320px;
+ max-width: 460px;
+}
+
+.about-me-quote {
+ margin: 12px 0;
+ padding: 8px 16px;
+ border-left: 4px solid #6a82fb;
+ border-radius: 4px;
+ background-color: rgba(255, 255, 255, 0.35);
+ color: rgba(0, 0, 0, 0.75);
+}
+
+#about-me-header {
+ position: relative;
+}
+
+.theme-toggle {
position: absolute;
- bottom: 0;
+ top: 12px;
right: 12px;
- text-align: right;
- width: 40vw;
+ padding: 6px 12px;
+ border: none;
+ border-radius: 16px;
+ cursor: pointer;
+ color: #ffffff;
+ background: linear-gradient(135deg, #6a82fb 0%, #fc5c7d 100%);
+}
+
+#about-me-github {
+ width: min(450px, 94vw);
+}
+
+#github-profile {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+#github-avatar {
+ width: 72px;
+ height: 72px;
+ border-radius: 50%;
+}
+
+#github-info p {
+ margin: 4px 0;
+}
+
+#github-error {
+ color: #b00020;
+}
+
+/* ===== 暗色模式 ===== */
+body.dark #about-me-frame {
+ background: linear-gradient(135deg, #23272f 0%, #30384a 100%);
+}
+
+body.dark .about-me-card {
+ background-color: rgba(255, 255, 255, 0.08);
+ color: #e8e8e8;
+}
+
+body.dark .about-me-quote {
+ background-color: rgba(255, 255, 255, 0.08);
+ color: #cfd3dc;
+}
+
+body.dark .styled-table th,
+body.dark .styled-table td,
+body.dark #about-me-github a {
+ color: #d7dbe3;
+}
+
+#clock {
+ position: absolute;
+ bottom: 0;
+ left: 12px;
+ width: 40vw;
+}
+
+#motto {
+ position: absolute;
+ bottom: 0;
+ right: 12px;
+ text-align: right;
+ width: 40vw;
}
diff --git a/frontend/public/index.html b/frontend/public/index.html
index fe08636..e2938a1 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -28,6 +28,8 @@ 这是一个趣味会议软件
进入主页
关于这个工程
+
+ 关于我
当前时间加载中... ...
每日一句加载中... ...