2025-04-03 02:23:49 +00:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"os"
|
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"gorm.io/driver/sqlite"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
|
"goodnews/models"
|
|
|
|
|
|
"goodnews/services"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 全局数据库连接
|
|
|
|
|
|
var db *gorm.DB
|
|
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
|
// 初始化数据库
|
|
|
|
|
|
var err error
|
|
|
|
|
|
db, err = gorm.Open(sqlite.Open("goodnews.db"), &gorm.Config{})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
panic("failed to connect database")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 自动迁移数据库
|
|
|
|
|
|
db.AutoMigrate(&models.GoodNews{})
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化Gin路由
|
|
|
|
|
|
r := gin.Default()
|
|
|
|
|
|
|
|
|
|
|
|
// 设置静态文件服务
|
|
|
|
|
|
r.Static("/uploads", "./uploads")
|
|
|
|
|
|
// 设置页面路由
|
|
|
|
|
|
r.StaticFile("/", "./templates/index.html")
|
|
|
|
|
|
r.StaticFile("/manage", "./templates/manage.html")
|
|
|
|
|
|
|
|
|
|
|
|
// API路由组
|
|
|
|
|
|
api := r.Group("/api")
|
|
|
|
|
|
{
|
|
|
|
|
|
api.GET("/news", getGoodNewsList)
|
|
|
|
|
|
api.PUT("/news/:id", updateGoodNews)
|
|
|
|
|
|
api.DELETE("/news/:id", deleteGoodNews)
|
|
|
|
|
|
api.POST("/upload", handleUploadAndCreate)
|
|
|
|
|
|
api.GET("/offices", getOfficesList)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 启动服务
|
|
|
|
|
|
r.Run(":8080")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取喜报列表
|
|
|
|
|
|
func getGoodNewsList(c *gin.Context) {
|
|
|
|
|
|
var goodNewsList []models.GoodNews
|
2025-04-07 03:18:38 +00:00
|
|
|
|
result := db.Order("created_at desc").Find(&goodNewsList)
|
2025-04-03 02:23:49 +00:00
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理每条记录,添加图片URL并设置Office字段
|
|
|
|
|
|
for i := range goodNewsList {
|
|
|
|
|
|
// 将ImagePath转换为可访问的URL
|
|
|
|
|
|
goodNewsList[i].ImageURL = "/" + goodNewsList[i].ImagePath
|
|
|
|
|
|
// 确保Office字段与Representative字段一致
|
|
|
|
|
|
goodNewsList[i].Office = goodNewsList[i].Representative
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, goodNewsList)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取代表处列表
|
|
|
|
|
|
func getOfficesList(c *gin.Context) {
|
|
|
|
|
|
var offices []string
|
|
|
|
|
|
result := db.Model(&models.GoodNews{}).Distinct().Pluck("representative", &offices)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
c.JSON(http.StatusOK, offices)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理文件上传并创建喜报
|
|
|
|
|
|
func handleUploadAndCreate(c *gin.Context) {
|
|
|
|
|
|
// 获取上传的图片
|
|
|
|
|
|
file, err := c.FormFile("file")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "请选择要上传的图片文件"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件类型
|
|
|
|
|
|
ext := filepath.Ext(file.Filename)
|
|
|
|
|
|
allowedExts := map[string]bool{".jpg": true, ".jpeg": true, ".png": true}
|
|
|
|
|
|
if !allowedExts[strings.ToLower(ext)] {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "只支持jpg、jpeg和png格式的图片"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件大小(限制为10MB)
|
|
|
|
|
|
if file.Size > 10<<20 { // 10 MB
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "图片大小不能超过10MB"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成唯一的文件名
|
|
|
|
|
|
newFileName := uuid.New().String() + ext
|
|
|
|
|
|
uploadDir := filepath.Join(".", "uploads")
|
|
|
|
|
|
filePath := filepath.Join(uploadDir, newFileName)
|
|
|
|
|
|
|
|
|
|
|
|
// 确保上传目录存在
|
|
|
|
|
|
if err := os.MkdirAll(uploadDir, 0755); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建上传目录失败: %v", err)})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存图片
|
|
|
|
|
|
if err := c.SaveUploadedFile(file, filePath); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("图片保存失败: %v", err)})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建OCR服务
|
|
|
|
|
|
ocrService, err := services.NewOCRService()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "OCR服务初始化失败"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer ocrService.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 提取图片信息
|
|
|
|
|
|
projectName, points, representative, err := ocrService.ExtractInfo(filePath)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("图片识别失败: %v", err)})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fmt.Println("OCR识别信息:", projectName, points, representative)
|
|
|
|
|
|
// 创建喜报记录
|
2025-04-07 03:18:38 +00:00
|
|
|
|
var pointValue int
|
|
|
|
|
|
if len(points) > 0 {
|
|
|
|
|
|
pointValue = points[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-03 02:23:49 +00:00
|
|
|
|
goodNews := models.GoodNews{
|
|
|
|
|
|
ProjectName: projectName,
|
2025-04-07 03:18:38 +00:00
|
|
|
|
Points: pointValue,
|
2025-04-03 02:23:49 +00:00
|
|
|
|
Representative: representative,
|
|
|
|
|
|
ImagePath: filePath,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result := db.Create(&goodNews)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取记录以确保包含ID
|
|
|
|
|
|
db.First(&goodNews, goodNews.ID)
|
|
|
|
|
|
goodNews.ImageURL = "/" + goodNews.ImagePath
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, goodNews)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新喜报
|
|
|
|
|
|
func updateGoodNews(c *gin.Context) {
|
|
|
|
|
|
var goodNews models.GoodNews
|
|
|
|
|
|
if err := db.First(&goodNews, c.Param("id")).Error; err != nil {
|
|
|
|
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "记录不存在"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := c.ShouldBindJSON(&goodNews); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
db.Save(&goodNews)
|
|
|
|
|
|
c.JSON(http.StatusOK, goodNews)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除喜报
|
|
|
|
|
|
func deleteGoodNews(c *gin.Context) {
|
|
|
|
|
|
var goodNews models.GoodNews
|
|
|
|
|
|
if err := db.First(&goodNews, c.Param("id")).Error; err != nil {
|
|
|
|
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "记录不存在"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
db.Delete(&goodNews)
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理文件上传
|
|
|
|
|
|
func handleFileUpload(c *gin.Context) {
|
|
|
|
|
|
// 获取上传的文件
|
|
|
|
|
|
file, err := c.FormFile("file")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "请选择要上传的文件"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件类型
|
|
|
|
|
|
ext := filepath.Ext(file.Filename)
|
|
|
|
|
|
allowedExts := map[string]bool{".jpg": true, ".jpeg": true, ".png": true}
|
|
|
|
|
|
if !allowedExts[strings.ToLower(ext)] {
|
|
|
|
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "只支持jpg、jpeg和png格式的图片"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成唯一的文件名
|
|
|
|
|
|
newFileName := uuid.New().String() + ext
|
|
|
|
|
|
uploadDir := filepath.Join(".", "uploads")
|
|
|
|
|
|
filePath := filepath.Join(uploadDir, newFileName)
|
|
|
|
|
|
|
|
|
|
|
|
// 确保上传目录存在
|
|
|
|
|
|
if err := os.MkdirAll(uploadDir, 0755); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建上传目录失败: %v", err)})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存图片
|
|
|
|
|
|
if err := c.SaveUploadedFile(file, filePath); err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("图片保存失败: %v", err)})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建OCR服务
|
|
|
|
|
|
ocrService, err := services.NewOCRService()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "OCR服务初始化失败"})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
defer ocrService.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 提取图片信息
|
|
|
|
|
|
projectName, points, representative, err := ocrService.ExtractInfo(filePath)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("图片识别失败: %v", err)})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建喜报记录
|
2025-04-07 03:18:38 +00:00
|
|
|
|
var pointValue int
|
|
|
|
|
|
if len(points) > 0 {
|
|
|
|
|
|
pointValue = points[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-03 02:23:49 +00:00
|
|
|
|
goodNews := models.GoodNews{
|
|
|
|
|
|
ProjectName: projectName,
|
2025-04-07 03:18:38 +00:00
|
|
|
|
Points: pointValue,
|
2025-04-03 02:23:49 +00:00
|
|
|
|
Representative: representative,
|
|
|
|
|
|
ImagePath: filePath,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result := db.Create(&goodNews)
|
|
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取记录以确保包含ID
|
|
|
|
|
|
db.First(&goodNews, goodNews.ID)
|
|
|
|
|
|
goodNews.ImageURL = "/" + goodNews.ImagePath
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, goodNews)
|
|
|
|
|
|
}
|