feat: 初始化云笔记项目

功能特性:
- Markdown 编辑与实时预览
- 代码语法高亮
- 目录树形结构管理
- 图片粘贴上传
- Markdown 文件导入导出
- 笔记密码保护
- 前后端分离架构

技术栈:
- Go + Gin + GORM + SQLite
- 原生 HTML/CSS/JavaScript
- Highlight.js
此提交包含在:
Note Manager
2026-05-08 15:07:22 +08:00
當前提交 c8f03dd932
共有 19 個檔案被更改,包括 4333 行新增0 行删除
+89
查看文件
@@ -0,0 +1,89 @@
package handler
import (
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/gin-gonic/gin"
)
// ImageHandler 图片上传处理器
type ImageHandler struct {
uploadDir string
}
// NewImageHandler 创建图片处理器
func NewImageHandler(uploadDir string) *ImageHandler {
return &ImageHandler{uploadDir: uploadDir}
}
// Init 初始化上传目录
func (h *ImageHandler) Init() error {
return os.MkdirAll(h.uploadDir, 0755)
}
// Upload 上传图片
func (h *ImageHandler) Upload(c *gin.Context) {
file, err := c.FormFile("image")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "请选择图片文件"})
return
}
// 验证文件类型
ext := strings.ToLower(filepath.Ext(file.Filename))
allowedExts := map[string]bool{
".jpg": true,
".jpeg": true,
".png": true,
".gif": true,
".webp": true,
".bmp": true,
}
if !allowedExts[ext] {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "不支持的图片格式,仅支持 jpg、png、gif、webp"})
return
}
// 验证文件大小 (最大 5MB)
if file.Size > 5*1024*1024 {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "图片大小不能超过 5MB"})
return
}
// 生成唯一文件名
filename := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomString(8), ext)
filepath := filepath.Join(h.uploadDir, filename)
// 保存文件
if err := c.SaveUploadedFile(file, filepath); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "保存图片失败"})
return
}
// 返回访问 URL
url := "/uploads/" + filename
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "上传成功",
"data": gin.H{
"url": url,
},
})
}
// randomString 生成随机字符串
func randomString(length int) string {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
result := make([]byte, length)
for i := range result {
result[i] = chars[time.Now().UnixNano()%int64(len(chars))]
time.Sleep(time.Nanosecond)
}
return string(result)
}