feat: 初始提交云印享付费打印服务后端

This commit is contained in:
WuYuuuub
2026-03-29 11:50:43 +08:00
parent 5047380dd0
commit 7491635a75
36 changed files with 13323 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
package repository
import (
"context"
"errors"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type AdminRepository struct {
db *gorm.DB
}
func NewAdminRepository(db *gorm.DB) *AdminRepository {
return &AdminRepository{db: db}
}
func (r *AdminRepository) Create(ctx context.Context, admin *model.Admin) error {
return r.db.WithContext(ctx).Create(admin).Error
}
func (r *AdminRepository) GetByID(ctx context.Context, id int32) (*model.Admin, error) {
var admin model.Admin
err := r.db.WithContext(ctx).First(&admin, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &admin, nil
}
func (r *AdminRepository) GetByUsername(ctx context.Context, username string) (*model.Admin, error) {
var admin model.Admin
err := r.db.WithContext(ctx).Where("username = ?", username).First(&admin).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &admin, nil
}
func (r *AdminRepository) Update(ctx context.Context, admin *model.Admin) error {
return r.db.WithContext(ctx).Save(admin).Error
}

View File

@@ -0,0 +1,67 @@
package repository
import (
"context"
"errors"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type FileRepository struct {
db *gorm.DB
}
func NewFileRepository(db *gorm.DB) *FileRepository {
return &FileRepository{db: db}
}
func (r *FileRepository) Create(ctx context.Context, file *model.File) error {
return r.db.WithContext(ctx).Create(file).Error
}
func (r *FileRepository) GetByID(ctx context.Context, id int32) (*model.File, error) {
var file model.File
err := r.db.WithContext(ctx).First(&file, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &file, nil
}
func (r *FileRepository) Delete(ctx context.Context, id int32) error {
return r.db.WithContext(ctx).Delete(&model.File{}, id).Error
}
func (r *FileRepository) GetListByUploader(ctx context.Context, uploaderType string, uploaderID int32, page, pageSize int) ([]*model.File, int64, error) {
var files []*model.File
var total int64
query := r.db.WithContext(ctx).Model(&model.File{})
if uploaderType != "" {
query = query.Where("uploader_type = ?", uploaderType)
}
if uploaderID > 0 {
query = query.Where("uploader_id = ?", uploaderID)
}
err := query.Count(&total).Error
if err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
err = query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&files).Error
if err != nil {
return nil, 0, err
}
return files, total, nil
}
func (r *FileRepository) Update(ctx context.Context, file *model.File) error {
return r.db.WithContext(ctx).Save(file).Error
}

View File

@@ -0,0 +1,108 @@
package repository
import (
"context"
"errors"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type LibraryRepository struct {
db *gorm.DB
}
func NewLibraryRepository(db *gorm.DB) *LibraryRepository {
return &LibraryRepository{db: db}
}
// Category operations
func (r *LibraryRepository) CreateCategory(ctx context.Context, category *model.LibraryCategory) error {
return r.db.WithContext(ctx).Create(category).Error
}
func (r *LibraryRepository) GetCategoryByID(ctx context.Context, id int32) (*model.LibraryCategory, error) {
var category model.LibraryCategory
err := r.db.WithContext(ctx).First(&category, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &category, nil
}
func (r *LibraryRepository) GetAllCategories(ctx context.Context) ([]*model.LibraryCategory, error) {
var categories []*model.LibraryCategory
err := r.db.WithContext(ctx).Order("sort_order ASC, id ASC").Find(&categories).Error
return categories, err
}
func (r *LibraryRepository) UpdateCategory(ctx context.Context, category *model.LibraryCategory) error {
return r.db.WithContext(ctx).Save(category).Error
}
func (r *LibraryRepository) DeleteCategory(ctx context.Context, id int32) error {
return r.db.WithContext(ctx).Delete(&model.LibraryCategory{}, id).Error
}
// LibraryFile operations
func (r *LibraryRepository) CreateFile(ctx context.Context, file *model.LibraryFile) error {
return r.db.WithContext(ctx).Create(file).Error
}
func (r *LibraryRepository) GetFileByID(ctx context.Context, id int32) (*model.LibraryFile, error) {
var file model.LibraryFile
err := r.db.WithContext(ctx).Preload("File").First(&file, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &file, nil
}
func (r *LibraryRepository) GetFilesByCategory(ctx context.Context, categoryID int32, page, pageSize int) ([]*model.LibraryFile, int64, error) {
var files []*model.LibraryFile
var total int64
query := r.db.WithContext(ctx).Model(&model.LibraryFile{}).Where("category_id = ?", categoryID)
err := query.Count(&total).Error
if err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
err = query.Preload("File").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&files).Error
if err != nil {
return nil, 0, err
}
return files, total, nil
}
func (r *LibraryRepository) DeleteFile(ctx context.Context, id int32) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
// Get file to delete underlying file record
var libFile model.LibraryFile
if err := tx.First(&libFile, id).Error; err != nil {
return err
}
// Delete library file
if err := tx.Delete(&libFile).Error; err != nil {
return err
}
// Delete underlying file
if err := tx.Delete(&model.File{}, libFile.FileID).Error; err != nil {
return err
}
return nil
})
}
func (r *LibraryRepository) IncrementDownloadCount(ctx context.Context, id int32) error {
return r.db.WithContext(ctx).Model(&model.LibraryFile{}).Where("id = ?", id).
Update("download_count", gorm.Expr("download_count + 1")).Error
}

View File

@@ -0,0 +1,162 @@
package repository
import (
"context"
"errors"
"fmt"
"time"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type OrderRepository struct {
db *gorm.DB
}
func NewOrderRepository(db *gorm.DB) *OrderRepository {
return &OrderRepository{db: db}
}
func (r *OrderRepository) Create(ctx context.Context, order *model.Order) error {
return r.db.WithContext(ctx).Create(order).Error
}
func (r *OrderRepository) CreateWithItems(ctx context.Context, order *model.Order, items []*model.OrderItem) error {
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Create(order).Error; err != nil {
return err
}
for _, item := range items {
item.OrderID = order.ID
if err := tx.Create(item).Error; err != nil {
return err
}
}
return nil
})
}
func (r *OrderRepository) GetByID(ctx context.Context, id int32) (*model.Order, error) {
var order model.Order
err := r.db.WithContext(ctx).Preload("Items").Preload("Items.File").Preload("Payment").
First(&order, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &order, nil
}
func (r *OrderRepository) GetByOrderNo(ctx context.Context, orderNo string) (*model.Order, error) {
var order model.Order
err := r.db.WithContext(ctx).Preload("Items").Preload("Items.File").Preload("Items.Printer").Preload("Payment").
Where("order_no = ?", orderNo).First(&order).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &order, nil
}
func (r *OrderRepository) GetListByUserID(ctx context.Context, userID int32, status int8, page, pageSize int) ([]*model.Order, int64, error) {
var orders []*model.Order
var total int64
query := r.db.WithContext(ctx).Model(&model.Order{}).Where("user_id = ?", userID)
if status >= 0 {
query = query.Where("status = ?", status)
}
err := query.Count(&total).Error
if err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
err = query.Preload("Items").Preload("Items.File").
Offset(offset).Limit(pageSize).Order("created_at DESC").
Find(&orders).Error
if err != nil {
return nil, 0, err
}
return orders, total, nil
}
func (r *OrderRepository) UpdateStatus(ctx context.Context, orderNo string, status int8) error {
updates := map[string]interface{}{
"status": status,
}
if status == model.OrderStatusPaid {
now := time.Now()
updates["paid_at"] = &now
}
return r.db.WithContext(ctx).Model(&model.Order{}).
Where("order_no = ?", orderNo).Updates(updates).Error
}
func (r *OrderRepository) GetStatistics(ctx context.Context) (totalUsers, totalOrders, todayOrders int32, todayRevenue float64, pendingOrders int32, err error) {
// 总用户数
if err = r.db.WithContext(ctx).Model(&model.User{}).Count(&totalUsers).Error; err != nil {
return 0, 0, 0, 0, 0, fmt.Errorf("count users failed: %w", err)
}
// 总订单数
if err = r.db.WithContext(ctx).Model(&model.Order{}).Count(&totalOrders).Error; err != nil {
return 0, 0, 0, 0, 0, fmt.Errorf("count orders failed: %w", err)
}
// 待处理订单数
if err = r.db.WithContext(ctx).Model(&model.Order{}).Where("status IN ?", []int8{0, 1, 2}).Count(&pendingOrders).Error; err != nil {
return 0, 0, 0, 0, 0, fmt.Errorf("count pending orders failed: %w", err)
}
// 今日订单数
today := time.Now().Format("2006-01-02")
if err = r.db.WithContext(ctx).Model(&model.Order{}).
Where("DATE(created_at) = ? AND status = ?", today, model.OrderStatusPaid).
Count(&todayOrders).Error; err != nil {
return 0, 0, 0, 0, 0, fmt.Errorf("count today orders failed: %w", err)
}
// 今日收入
if err = r.db.WithContext(ctx).Model(&model.Order{}).
Select("COALESCE(SUM(total_amount), 0)").
Where("DATE(created_at) = ? AND status = ?", today, model.OrderStatusPaid).
Scan(&todayRevenue).Error; err != nil {
return 0, 0, 0, 0, 0, fmt.Errorf("sum today revenue failed: %w", err)
}
return
}
type OrderItemRepository struct {
db *gorm.DB
}
func NewOrderItemRepository(db *gorm.DB) *OrderItemRepository {
return &OrderItemRepository{db: db}
}
func (r *OrderItemRepository) GetByID(ctx context.Context, id int32) (*model.OrderItem, error) {
var item model.OrderItem
err := r.db.WithContext(ctx).Preload("File").First(&item, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &item, nil
}
func (r *OrderItemRepository) Create(ctx context.Context, item *model.OrderItem) error {
return r.db.WithContext(ctx).Create(item).Error
}
func (r *OrderItemRepository) GetByOrderID(ctx context.Context, orderID int32) ([]*model.OrderItem, error) {
var items []*model.OrderItem
err := r.db.WithContext(ctx).Where("order_id = ?", orderID).Find(&items).Error
return items, err
}

View File

@@ -0,0 +1,80 @@
package repository
import (
"context"
"errors"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type PriceRepository struct {
db *gorm.DB
}
func NewPriceRepository(db *gorm.DB) *PriceRepository {
return &PriceRepository{db: db}
}
func (r *PriceRepository) Create(ctx context.Context, item *model.PriceList) error {
return r.db.WithContext(ctx).Create(item).Error
}
func (r *PriceRepository) GetByID(ctx context.Context, id int32) (*model.PriceList, error) {
var item model.PriceList
err := r.db.WithContext(ctx).First(&item, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &item, nil
}
func (r *PriceRepository) GetAllActive(ctx context.Context) ([]*model.PriceList, error) {
var items []*model.PriceList
err := r.db.WithContext(ctx).Where("is_active = ?", true).Order("sort_order ASC, id ASC").Find(&items).Error
return items, err
}
func (r *PriceRepository) Update(ctx context.Context, item *model.PriceList) error {
return r.db.WithContext(ctx).Save(item).Error
}
func (r *PriceRepository) Delete(ctx context.Context, id int32) error {
return r.db.WithContext(ctx).Delete(&model.PriceList{}, id).Error
}
type PaymentRepository struct {
db *gorm.DB
}
func NewPaymentRepository(db *gorm.DB) *PaymentRepository {
return &PaymentRepository{db: db}
}
func (r *PaymentRepository) Create(ctx context.Context, payment *model.Payment) error {
return r.db.WithContext(ctx).Create(payment).Error
}
func (r *PaymentRepository) GetByOrderNo(ctx context.Context, orderNo string) (*model.Payment, error) {
var payment model.Payment
err := r.db.WithContext(ctx).Where("order_no = ?", orderNo).First(&payment).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &payment, nil
}
func (r *PaymentRepository) UpdateStatus(ctx context.Context, orderNo string, status int8, transactionID string) error {
updates := map[string]interface{}{
"pay_status": status,
"transaction_id": transactionID,
}
return r.db.WithContext(ctx).Model(&model.Payment{}).
Where("order_no = ?", orderNo).Updates(updates).Error
}

View File

@@ -0,0 +1,150 @@
package repository
import (
"context"
"errors"
"time"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type PrinterRepository struct {
db *gorm.DB
}
func NewPrinterRepository(db *gorm.DB) *PrinterRepository {
return &PrinterRepository{db: db}
}
func (r *PrinterRepository) Create(ctx context.Context, printer *model.Printer) error {
return r.db.WithContext(ctx).Create(printer).Error
}
func (r *PrinterRepository) GetByID(ctx context.Context, id int32) (*model.Printer, error) {
var printer model.Printer
err := r.db.WithContext(ctx).First(&printer, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &printer, nil
}
func (r *PrinterRepository) GetByName(ctx context.Context, name string) (*model.Printer, error) {
var printer model.Printer
err := r.db.WithContext(ctx).Where("name = ?", name).First(&printer).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &printer, nil
}
func (r *PrinterRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.Printer, error) {
var printer model.Printer
err := r.db.WithContext(ctx).Where("api_key = ?", apiKey).First(&printer).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &printer, nil
}
func (r *PrinterRepository) GetAllActive(ctx context.Context) ([]*model.Printer, error) {
var printers []*model.Printer
err := r.db.WithContext(ctx).Where("is_active = ?", true).Find(&printers).Error
return printers, err
}
func (r *PrinterRepository) UpdateStatus(ctx context.Context, id int32, status int8) error {
return r.db.WithContext(ctx).Model(&model.Printer{}).Where("id = ?", id).Update("status", status).Error
}
func (r *PrinterRepository) UpdateHeartbeat(ctx context.Context, id int32) error {
now := time.Now()
return r.db.WithContext(ctx).Model(&model.Printer{}).Where("id = ?", id).Update("last_heartbeat", &now).Error
}
func (r *PrinterRepository) CountActive(ctx context.Context) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&model.Printer{}).Where("is_active = ? AND status != ?", true, model.PrinterStatusOffline).Count(&count).Error
return count, err
}
type PrintJobRepository struct {
db *gorm.DB
}
func NewPrintJobRepository(db *gorm.DB) *PrintJobRepository {
return &PrintJobRepository{db: db}
}
func (r *PrintJobRepository) Create(ctx context.Context, job *model.PrintJob) error {
return r.db.WithContext(ctx).Create(job).Error
}
func (r *PrintJobRepository) GetByID(ctx context.Context, id int32) (*model.PrintJob, error) {
var job model.PrintJob
err := r.db.WithContext(ctx).First(&job, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &job, nil
}
func (r *PrintJobRepository) GetByJobNo(ctx context.Context, jobNo string) (*model.PrintJob, error) {
var job model.PrintJob
err := r.db.WithContext(ctx).Where("job_no = ?", jobNo).First(&job).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &job, nil
}
func (r *PrintJobRepository) GetPendingJobs(ctx context.Context, printerID int32) ([]*model.PrintJob, error) {
var jobs []*model.PrintJob
err := r.db.WithContext(ctx).
Where("printer_id = ? AND status = ?", printerID, model.PrintJobStatusPending).
Preload("OrderItem").
Preload("OrderItem.File").
Find(&jobs).Error
return jobs, err
}
func (r *PrintJobRepository) UpdateStatus(ctx context.Context, jobNo string, status string, progress int, errorMsg string) error {
updates := map[string]interface{}{
"status": status,
"progress": progress,
"error_msg": errorMsg,
}
if status == model.PrintJobStatusPrinting {
now := time.Now()
updates["started_at"] = &now
} else if status == model.PrintJobStatusCompleted || status == model.PrintJobStatusFailed {
now := time.Now()
updates["completed_at"] = &now
}
return r.db.WithContext(ctx).Model(&model.PrintJob{}).
Where("job_no = ?", jobNo).Updates(updates).Error
}
func (r *PrintJobRepository) GetQueueCount(ctx context.Context, printerID int32) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&model.PrintJob{}).
Where("printer_id = ? AND status IN ?", printerID, []string{model.PrintJobStatusPending, model.PrintJobStatusPrinting}).
Count(&count).Error
return count, err
}

View File

@@ -0,0 +1,64 @@
package repository
import (
"context"
"errors"
"github.com/cloudprint/cloudprint-backend/internal/model"
"gorm.io/gorm"
)
type UserRepository struct {
db *gorm.DB
}
func NewUserRepository(db *gorm.DB) *UserRepository {
return &UserRepository{db: db}
}
func (r *UserRepository) Create(ctx context.Context, user *model.User) error {
return r.db.WithContext(ctx).Create(user).Error
}
func (r *UserRepository) GetByID(ctx context.Context, id int32) (*model.User, error) {
var user model.User
err := r.db.WithContext(ctx).First(&user, id).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &user, nil
}
func (r *UserRepository) GetByOpenid(ctx context.Context, openid string) (*model.User, error) {
var user model.User
err := r.db.WithContext(ctx).Where("openid = ?", openid).First(&user).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &user, nil
}
func (r *UserRepository) Update(ctx context.Context, user *model.User) error {
return r.db.WithContext(ctx).Save(user).Error
}
func (r *UserRepository) UpdateBalance(ctx context.Context, userID int32, balance float64) error {
return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", userID).Update("balance", balance).Error
}
func (r *UserRepository) DeductBalance(ctx context.Context, userID int32, amount float64) error {
return r.db.WithContext(ctx).Model(&model.User{}).
Where("id = ? AND balance >= ?", userID, amount).
Update("balance", gorm.Expr("balance - ?", amount)).Error
}
func (r *UserRepository) AddBalance(ctx context.Context, userID int32, amount float64) error {
return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", userID).
Update("balance", gorm.Expr("balance + ?", amount)).Error
}