diff --git a/client/src/pages/About.vue b/client/src/pages/About.vue index 797bd2b..60357ec 100644 --- a/client/src/pages/About.vue +++ b/client/src/pages/About.vue @@ -70,6 +70,18 @@ {{ tech }} + +
代码重构是在不改变代码外部行为的前提下,优化代码内部结构的过程...
', 0, 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); -INSERT INTO `posts` VALUES ('shader', '着色器魔法:从零开始写一个噪声生成器', '图形渲染', '2025-12-08', '深入了解WebGL着色器,学习如何从零开始实现一个高性能的噪声生成器,为你的3D作品增添独特的视觉效果。', 'WebGL着色器是运行在GPU上的小程序,用于处理图形渲染...
', 0, 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); +INSERT INTO `posts` VALUES ('refactor', '重构的艺术:如何优雅地处理遗留代码', '工程化', '2026-01-12', '在本文中,我们将探讨重构的核心原则和实用技巧,帮助你优雅地处理遗留代码,提高代码质量和可维护性。', '代码重构是在不改变代码外部行为的前提下,优化代码内部结构的过程...
', 1, 1, '2026-01-13 16:10:14', '2026-01-15 15:01:35'); +INSERT INTO `posts` VALUES ('shader', '着色器魔法:从零开始写一个噪声生成器', '图形渲染', '2025-12-08', '深入了解WebGL着色器,学习如何从零开始实现一个高性能的噪声生成器,为你的3D作品增添独特的视觉效果。', 'GLSL (OpenGL Shading Language) 是一门让人生畏但也充满魅力的语言。它运行在 GPU 上,能够并行处理数百万个像素,创造出惊人的视觉效果。
\r\n柏林噪声(Perlin Noise)是一种梯度噪声,它比普通的随机数生成的噪声看起来更自然、更平滑。它常被用来模拟云彩、地形、火焰等自然现象。
\r\n在 Three.js 中,我们可以通过 ShaderMaterial 直接编写 GLSL 代码。
// 简单的顶点着色器\r\nvarying vec2 vUv;\r\nvoid main() {\r\n vUv = uv;\r\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\r\n}\r\n 通过调整噪声的频率和振幅,我们可以得到各种不同的纹理效果。在我的个人网站背景中,就使用了这种技术来生成流动的极光效果。
\r\n ', 1, 1, '2026-01-13 16:10:14', '2026-01-15 15:03:42'); INSERT INTO `posts` VALUES ('ux', '用户体验设计:从认知心理学到交互实践', '设计思维', '2025-11-20', '探索用户体验设计的核心原理,结合认知心理学知识,学习如何设计出真正符合用户需求的交互界面。', '了解用户的认知过程是设计良好用户体验的基础...
', 0, 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); +-- ---------------------------- +-- Table structure for role_permissions +-- ---------------------------- +DROP TABLE IF EXISTS `role_permissions`; +CREATE TABLE `role_permissions` ( + `role_id` bigint UNSIGNED NOT NULL COMMENT '角色ID', + `permission_id` bigint UNSIGNED NOT NULL COMMENT '权限ID', + PRIMARY KEY (`role_id`, `permission_id`) USING BTREE, + INDEX `role_permissions_ibfk_2`(`permission_id` ASC) USING BTREE, + CONSTRAINT `role_permissions_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT, + CONSTRAINT `role_permissions_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色权限关联表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of role_permissions +-- ---------------------------- +INSERT INTO `role_permissions` VALUES (1, 1); +INSERT INTO `role_permissions` VALUES (1, 2); +INSERT INTO `role_permissions` VALUES (3, 2); +INSERT INTO `role_permissions` VALUES (1, 3); +INSERT INTO `role_permissions` VALUES (1, 4); +INSERT INTO `role_permissions` VALUES (1, 5); +INSERT INTO `role_permissions` VALUES (1, 6); +INSERT INTO `role_permissions` VALUES (3, 6); +INSERT INTO `role_permissions` VALUES (1, 7); +INSERT INTO `role_permissions` VALUES (1, 8); +INSERT INTO `role_permissions` VALUES (1, 9); +INSERT INTO `role_permissions` VALUES (2, 9); +INSERT INTO `role_permissions` VALUES (1, 10); +INSERT INTO `role_permissions` VALUES (2, 10); +INSERT INTO `role_permissions` VALUES (3, 10); +INSERT INTO `role_permissions` VALUES (1, 11); +INSERT INTO `role_permissions` VALUES (2, 11); +INSERT INTO `role_permissions` VALUES (1, 12); +INSERT INTO `role_permissions` VALUES (2, 12); +INSERT INTO `role_permissions` VALUES (1, 13); +INSERT INTO `role_permissions` VALUES (1, 14); +INSERT INTO `role_permissions` VALUES (3, 14); +INSERT INTO `role_permissions` VALUES (1, 15); +INSERT INTO `role_permissions` VALUES (1, 16); +INSERT INTO `role_permissions` VALUES (1, 17); +INSERT INTO `role_permissions` VALUES (1, 18); +INSERT INTO `role_permissions` VALUES (3, 18); +INSERT INTO `role_permissions` VALUES (1, 19); +INSERT INTO `role_permissions` VALUES (1, 20); +INSERT INTO `role_permissions` VALUES (1, 21); +INSERT INTO `role_permissions` VALUES (1, 22); +INSERT INTO `role_permissions` VALUES (3, 22); +INSERT INTO `role_permissions` VALUES (1, 23); +INSERT INTO `role_permissions` VALUES (1, 24); +INSERT INTO `role_permissions` VALUES (1, 25); +INSERT INTO `role_permissions` VALUES (1, 26); +INSERT INTO `role_permissions` VALUES (3, 26); +INSERT INTO `role_permissions` VALUES (1, 27); +INSERT INTO `role_permissions` VALUES (1, 28); +INSERT INTO `role_permissions` VALUES (1, 29); +INSERT INTO `role_permissions` VALUES (3, 29); +INSERT INTO `role_permissions` VALUES (1, 30); +INSERT INTO `role_permissions` VALUES (3, 30); + +-- ---------------------------- +-- Table structure for roles +-- ---------------------------- +DROP TABLE IF EXISTS `roles`; +CREATE TABLE `roles` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名称', + `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色描述', + `created_at` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `name`(`name` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of roles +-- ---------------------------- +INSERT INTO `roles` VALUES (1, 'admin', '系统管理员', '2026-01-15 12:54:52', '2026-01-15 12:54:52'); +INSERT INTO `roles` VALUES (2, 'editor', '内容编辑', '2026-01-15 12:54:52', '2026-01-15 12:54:52'); +INSERT INTO `roles` VALUES (3, 'viewer', '普通访客', '2026-01-15 12:54:52', '2026-01-15 12:54:52'); + -- ---------------------------- -- Table structure for settings -- ---------------------------- @@ -102,7 +296,7 @@ CREATE TABLE `settings` ( PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `key_name`(`key_name` ASC) USING BTREE, INDEX `idx_key_name`(`key_name` ASC) USING BTREE COMMENT '按键名查询索引' -) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '网站配置表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '网站配置表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of settings @@ -131,7 +325,7 @@ CREATE TABLE `snippets` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_type`(`type` ASC) USING BTREE COMMENT '按代码类型查询索引', INDEX `idx_view_count`(`view_count` ASC) USING BTREE COMMENT '按查看次数查询索引' -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码片段表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码片段表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of snippets @@ -152,113 +346,12 @@ CREATE TABLE `tags` ( UNIQUE INDEX `name`(`name` ASC) USING BTREE, UNIQUE INDEX `slug`(`slug` ASC) USING BTREE, INDEX `idx_slug`(`slug` ASC) USING BTREE COMMENT '按别名查询索引' -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '标签表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '标签表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of tags -- ---------------------------- --- ---------------------------- --- Table structure for roles --- ---------------------------- -DROP TABLE IF EXISTS `roles`; -CREATE TABLE `roles` ( - `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名称', - `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '角色描述', - `created_at` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`) USING BTREE, - UNIQUE INDEX `name`(`name` ASC) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色表' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of roles --- ---------------------------- -INSERT INTO `roles` (`name`, `description`) VALUES ('admin', '系统管理员'); -INSERT INTO `roles` (`name`, `description`) VALUES ('editor', '内容编辑'); -INSERT INTO `roles` (`name`, `description`) VALUES ('viewer', '普通访客'); - --- ---------------------------- --- Table structure for permissions --- ---------------------------- -DROP TABLE IF EXISTS `permissions`; -CREATE TABLE `permissions` ( - `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '权限名称', - `resource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '资源名称', - `action` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作名称', - `created_at` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`) USING BTREE, - UNIQUE INDEX `unique_resource_action`(`resource`, `action`) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '权限表' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of permissions --- ---------------------------- --- User permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create User', 'users', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read User', 'users', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update User', 'users', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete User', 'users', 'delete'); --- Role permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create Role', 'roles', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Role', 'roles', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update Role', 'roles', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete Role', 'roles', 'delete'); --- Post permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create Post', 'posts', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Post', 'posts', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update Post', 'posts', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete Post', 'posts', 'delete'); --- Work permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create Work', 'works', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Work', 'works', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update Work', 'works', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete Work', 'works', 'delete'); --- Snippet permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create Snippet', 'snippets', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Snippet', 'snippets', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update Snippet', 'snippets', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete Snippet', 'snippets', 'delete'); --- Setting permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create Setting', 'settings', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Setting', 'settings', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update Setting', 'settings', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete Setting', 'settings', 'delete'); --- Tag permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Create Tag', 'tags', 'create'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Tag', 'tags', 'read'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Update Tag', 'tags', 'update'); -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Delete Tag', 'tags', 'delete'); --- Log permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Operation Log', 'operation_logs', 'read'); --- Dashboard permissions -INSERT INTO `permissions` (`name`, `resource`, `action`) VALUES ('Read Dashboard', 'dashboard', 'read'); - --- ---------------------------- --- Table structure for role_permissions --- ---------------------------- -DROP TABLE IF EXISTS `role_permissions`; -CREATE TABLE `role_permissions` ( - `role_id` bigint UNSIGNED NOT NULL COMMENT '角色ID', - `permission_id` bigint UNSIGNED NOT NULL COMMENT '权限ID', - PRIMARY KEY (`role_id`, `permission_id`) USING BTREE, - CONSTRAINT `role_permissions_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT, - CONSTRAINT `role_permissions_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色权限关联表' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Records of role_permissions --- ---------------------------- --- Admin has all permissions (assuming ids 1-12) -INSERT INTO `role_permissions` SELECT 1, id FROM permissions; --- Editor has Post permissions (ids 9-12) -INSERT INTO `role_permissions` SELECT 2, id FROM permissions WHERE resource = 'posts'; --- Viewer has read permissions (assuming read action) -INSERT INTO `role_permissions` SELECT 3, id FROM permissions WHERE action = 'read'; - -- ---------------------------- -- Table structure for users -- ---------------------------- @@ -268,7 +361,7 @@ CREATE TABLE `users` ( `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名', `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮箱地址', `password_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码哈希值', - `role_id` bigint UNSIGNED NULL COMMENT '角色ID', + `role_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '角色ID', `role` enum('admin','editor','viewer') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'viewer' COMMENT '用户角色(兼容旧版)', `is_active` tinyint(1) NULL DEFAULT 1 COMMENT '是否激活(0:禁用,1:激活)', `created_at` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', @@ -279,34 +372,15 @@ CREATE TABLE `users` ( INDEX `idx_username`(`username` ASC) USING BTREE COMMENT '按用户名查询索引', INDEX `idx_email`(`email` ASC) USING BTREE COMMENT '按邮箱查询索引', INDEX `idx_role`(`role` ASC) USING BTREE COMMENT '按角色查询索引', + INDEX `users_ibfk_1`(`role_id` ASC) USING BTREE, CONSTRAINT `users_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE SET NULL ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; - --- ---------------------------- --- Table structure for operation_logs --- ---------------------------- -DROP TABLE IF EXISTS `operation_logs`; -CREATE TABLE `operation_logs` ( - `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `user_id` bigint UNSIGNED NOT NULL COMMENT '操作用户ID', - `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作用户名', - `ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作IP地址', - `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '操作路径', - `method` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'HTTP方法', - `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '请求参数', - `status` int NOT NULL COMMENT '响应状态码', - `duration` int NOT NULL COMMENT '响应时间(毫秒)', - `created_at` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间', - PRIMARY KEY (`id`) USING BTREE, - INDEX `idx_user_id`(`user_id` ASC) USING BTREE, - INDEX `idx_created_at`(`created_at` ASC) USING BTREE -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of users -- ---------------------------- -INSERT INTO `users` (`id`, `username`, `email`, `password_hash`, `role_id`, `role`, `is_active`, `created_at`, `updated_at`) VALUES (1, 'lq', 'liqiworker@gmail.com', '$2a$10$yl.1yCZ2PSTsW14byyDQ3uekuEiqnC4VBr/TzR6OvMqFVRuiiHu5e', 1, 'admin', 1, '2026-01-13 16:10:14', '2026-01-14 12:57:55'); -INSERT INTO `users` (`id`, `username`, `email`, `password_hash`, `role_id`, `role`, `is_active`, `created_at`, `updated_at`) VALUES (2, 'editor', 'editor@example.com', '$2a$10$J9q3NfJ2X8H7Q5z5Q7z5Q7z5Q7z5Q7z5Q7z5Q7z5Q7z5Q7z5Q', 2, 'editor', 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); +INSERT INTO `users` VALUES (1, 'lq', 'liqiworker@gmail.com', '$2a$10$yl.1yCZ2PSTsW14byyDQ3uekuEiqnC4VBr/TzR6OvMqFVRuiiHu5e', 1, 'admin', 1, '2026-01-13 16:10:14', '2026-01-15 13:22:46'); +INSERT INTO `users` VALUES (2, 'editor', 'editor@example.com', '$2a$10$J9q3NfJ2X8H7Q5z5Q7z5Q7z5Q7z5Q7z5Q7z5Q7z5Q7z5Q7z5Q', 2, 'editor', 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); -- ---------------------------- -- Table structure for work_gallery @@ -323,7 +397,7 @@ CREATE TABLE `work_gallery` ( INDEX `idx_work_id`(`work_id` ASC) USING BTREE, INDEX `idx_sort_order`(`sort_order` ASC) USING BTREE, CONSTRAINT `work_gallery_ibfk_1` FOREIGN KEY (`work_id`) REFERENCES `works` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '作品图库表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '作品图库表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of work_gallery @@ -347,7 +421,7 @@ CREATE TABLE `work_tech_stack` ( INDEX `idx_work_id`(`work_id` ASC) USING BTREE, INDEX `idx_category`(`category` ASC) USING BTREE, CONSTRAINT `work_tech_stack_ibfk_1` FOREIGN KEY (`work_id`) REFERENCES `works` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT -) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '作品技术栈表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '作品技术栈表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of work_tech_stack @@ -380,12 +454,12 @@ CREATE TABLE `works` ( INDEX `idx_category`(`category` ASC) USING BTREE COMMENT '按分类查询索引', INDEX `idx_year`(`year` ASC) USING BTREE COMMENT '按年份查询索引', INDEX `idx_is_featured`(`is_featured` ASC) USING BTREE COMMENT '按精选状态查询索引' -) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '作品表' ROW_FORMAT = Dynamic; +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '作品表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of works -- ---------------------------- INSERT INTO `works` VALUES ('archdaily', 'ArchDaily 网站重构', '建筑设计', '2022', 'https://images.unsplash.com/photo-1487958449943-2429e8be8625?q=80&w=2070', 'ArchDaily 是全球最受欢迎的建筑网站之一。这次重构的目标是提升移动端体验。我们使用了 Nuxt 3 进行服务端渲染(SSR)。', 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); -INSERT INTO `works` VALUES ('nova', 'Nova 交易平台', '金融科技', '2023', 'https://images.unsplash.com/photo-1611974765270-ca12586343bb?q=80&w=2070', 'Nova 是一个专为机构交易员设计的高频交易终端。我们面临的最大挑战是如何在处理毫秒级市场数据的同时,保持界面的流畅响应。我们采用 Web Worker 来处理繁重的数据计算,避免阻塞主线程。', 1, '2026-01-13 16:10:14', '2026-01-13 16:10:14'); +INSERT INTO `works` VALUES ('nova', 'Nova 交易平台', '金融科技', '2023', 'https://images.unsplash.com/photo-1487958449943-2429e8be8625?q=80&w=2070', 'Nova 是一个专为机构交易员设计的高频交易终端。我们面临的最大挑战是如何在处理毫秒级市场数据的同时,保持界面的流畅响应。我们采用 Web Worker 来处理繁重的数据计算,避免阻塞主线程。', 1, '2026-01-13 16:10:14', '2026-01-15 15:04:52'); -SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file +SET FOREIGN_KEY_CHECKS = 1; diff --git a/server/repositories/about_repository.go b/server/repositories/about_repository.go new file mode 100644 index 0000000..699f40d --- /dev/null +++ b/server/repositories/about_repository.go @@ -0,0 +1,232 @@ +package repositories + +import ( + "database/sql" + "encoding/json" + "log" + + "github.com/niangaodev/art-code/config" + "github.com/niangaodev/art-code/models" +) + +// GetPrimaryAboutProfile 获取主页个人资料 +func GetPrimaryAboutProfile() (*models.AboutProfile, error) { + query := ` + SELECT id, name, avatar, location, bio, email, wechat, tech_stack, experiences, is_primary, created_at, updated_at + FROM about_profiles + WHERE is_primary = TRUE + LIMIT 1 + ` + row := config.DB.QueryRow(query) + + var profile models.AboutProfile + if err := row.Scan( + &profile.ID, + &profile.Name, + &profile.Avatar, + &profile.Location, + &profile.Bio, + &profile.Email, + &profile.Wechat, + &profile.TechStack, + &profile.ExperiencesStr, + &profile.IsPrimary, + &profile.CreatedAt, + &profile.UpdatedAt, + ); err != nil { + if err == sql.ErrNoRows { + // If no primary profile, try to get the first one + return GetFirstAboutProfile() + } + log.Printf("Error scanning primary about profile: %v", err) + return nil, err + } + + // Unmarshal JSON + if profile.TechStack != "" { + _ = json.Unmarshal([]byte(profile.TechStack), &profile.TechList) + } else { + profile.TechList = []string{} + } + + if profile.ExperiencesStr != "" { + _ = json.Unmarshal([]byte(profile.ExperiencesStr), &profile.ExperienceList) + } else { + profile.ExperienceList = []models.Experience{} + } + + return &profile, nil +} + +// GetFirstAboutProfile 获取第一个个人资料(备用) +func GetFirstAboutProfile() (*models.AboutProfile, error) { + query := ` + SELECT id, name, avatar, location, bio, email, wechat, tech_stack, experiences, is_primary, created_at, updated_at + FROM about_profiles + ORDER BY id ASC + LIMIT 1 + ` + row := config.DB.QueryRow(query) + + var profile models.AboutProfile + if err := row.Scan( + &profile.ID, + &profile.Name, + &profile.Avatar, + &profile.Location, + &profile.Bio, + &profile.Email, + &profile.Wechat, + &profile.TechStack, + &profile.ExperiencesStr, + &profile.IsPrimary, + &profile.CreatedAt, + &profile.UpdatedAt, + ); err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + log.Printf("Error scanning first about profile: %v", err) + return nil, err + } + + if profile.TechStack != "" { + _ = json.Unmarshal([]byte(profile.TechStack), &profile.TechList) + } else { + profile.TechList = []string{} + } + + if profile.ExperiencesStr != "" { + _ = json.Unmarshal([]byte(profile.ExperiencesStr), &profile.ExperienceList) + } else { + profile.ExperienceList = []models.Experience{} + } + + return &profile, nil +} + +// GetAllAboutProfiles 获取所有个人资料(管理用) +func GetAllAboutProfiles() ([]models.AboutProfile, error) { + query := "SELECT id, name, avatar, location, bio, email, wechat, tech_stack, experiences, is_primary, created_at, updated_at FROM about_profiles" + rows, err := config.DB.Query(query) + if err != nil { + log.Printf("Error querying about profiles: %v", err) + return nil, err + } + defer rows.Close() + + var profiles []models.AboutProfile + for rows.Next() { + var p models.AboutProfile + if err := rows.Scan( + &p.ID, + &p.Name, + &p.Avatar, + &p.Location, + &p.Bio, + &p.Email, + &p.Wechat, + &p.TechStack, + &p.ExperiencesStr, + &p.IsPrimary, + &p.CreatedAt, + &p.UpdatedAt, + ); err != nil { + continue + } + if p.TechStack != "" { + _ = json.Unmarshal([]byte(p.TechStack), &p.TechList) + } else { + p.TechList = []string{} + } + if p.ExperiencesStr != "" { + _ = json.Unmarshal([]byte(p.ExperiencesStr), &p.ExperienceList) + } else { + p.ExperienceList = []models.Experience{} + } + profiles = append(profiles, p) + } + return profiles, nil +} + +// CreateAboutProfile 创建个人资料 +func CreateAboutProfile(profile *models.AboutProfile) error { + // Marshal JSON + techBytes, _ := json.Marshal(profile.TechList) + profile.TechStack = string(techBytes) + + expBytes, _ := json.Marshal(profile.ExperienceList) + profile.ExperiencesStr = string(expBytes) + + query := ` + INSERT INTO about_profiles (name, avatar, location, bio, email, wechat, tech_stack, experiences, is_primary, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW()) + ` + result, err := config.DB.Exec( + query, + profile.Name, + profile.Avatar, + profile.Location, + profile.Bio, + profile.Email, + profile.Wechat, + profile.TechStack, + profile.ExperiencesStr, + profile.IsPrimary, + ) + if err != nil { + log.Printf("Error creating about profile: %v", err) + return err + } + + id, err := result.LastInsertId() + if err != nil { + return err + } + profile.ID = uint(id) + return nil +} + +// UpdateAboutProfile 更新个人资料 +func UpdateAboutProfile(profile *models.AboutProfile) error { + techBytes, _ := json.Marshal(profile.TechList) + profile.TechStack = string(techBytes) + + expBytes, _ := json.Marshal(profile.ExperienceList) + profile.ExperiencesStr = string(expBytes) + + query := ` + UPDATE about_profiles + SET name = ?, avatar = ?, location = ?, bio = ?, email = ?, wechat = ?, tech_stack = ?, experiences = ?, is_primary = ?, updated_at = NOW() + WHERE id = ? + ` + _, err := config.DB.Exec( + query, + profile.Name, + profile.Avatar, + profile.Location, + profile.Bio, + profile.Email, + profile.Wechat, + profile.TechStack, + profile.ExperiencesStr, + profile.IsPrimary, + profile.ID, + ) + if err != nil { + log.Printf("Error updating about profile: %v", err) + return err + } + return nil +} + +// DeleteAboutProfile 删除个人资料 +func DeleteAboutProfile(id uint) error { + query := "DELETE FROM about_profiles WHERE id = ?" + _, err := config.DB.Exec(query, id) + if err != nil { + log.Printf("Error deleting about profile: %v", err) + return err + } + return nil +}