更新为postgre储存
This commit is contained in:
@@ -1,19 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/cloudprint/cloudprint-backend/config"
|
"github.com/cloudprint/cloudprint-backend/config"
|
||||||
"github.com/cloudprint/cloudprint-backend/internal/grpc"
|
|
||||||
"github.com/cloudprint/cloudprint-backend/internal/grpc/interceptor"
|
"github.com/cloudprint/cloudprint-backend/internal/grpc/interceptor"
|
||||||
"github.com/cloudprint/cloudprint-backend/internal/grpc/service"
|
grpcService "github.com/cloudprint/cloudprint-backend/internal/grpc/service"
|
||||||
"github.com/cloudprint/cloudprint-backend/internal/model"
|
|
||||||
"github.com/cloudprint/cloudprint-backend/internal/repository"
|
"github.com/cloudprint/cloudprint-backend/internal/repository"
|
||||||
"github.com/cloudprint/cloudprint-backend/internal/service"
|
"github.com/cloudprint/cloudprint-backend/internal/service"
|
||||||
"github.com/cloudprint/cloudprint-backend/pkg/jwt"
|
"github.com/cloudprint/cloudprint-backend/pkg/jwt"
|
||||||
@@ -22,7 +23,10 @@ import (
|
|||||||
pb "github.com/cloudprint/cloudprint-backend/proto/generated"
|
pb "github.com/cloudprint/cloudprint-backend/proto/generated"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"gorm.io/driver/mysql"
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
)
|
)
|
||||||
@@ -47,23 +51,6 @@ func main() {
|
|||||||
log.Fatalf("Failed to initialize database: %v", err)
|
log.Fatalf("Failed to initialize database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto migrate
|
|
||||||
if err := db.AutoMigrate(
|
|
||||||
&model.User{},
|
|
||||||
&model.Admin{},
|
|
||||||
&model.Printer{},
|
|
||||||
&model.Order{},
|
|
||||||
&model.OrderItem{},
|
|
||||||
&model.File{},
|
|
||||||
&model.LibraryCategory{},
|
|
||||||
&model.LibraryFile{},
|
|
||||||
&model.PrintJob{},
|
|
||||||
&model.PriceList{},
|
|
||||||
&model.Payment{},
|
|
||||||
); err != nil {
|
|
||||||
log.Fatalf("Failed to migrate database: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize repositories
|
// Initialize repositories
|
||||||
userRepo := repository.NewUserRepository(db)
|
userRepo := repository.NewUserRepository(db)
|
||||||
adminRepo := repository.NewAdminRepository(db)
|
adminRepo := repository.NewAdminRepository(db)
|
||||||
@@ -105,14 +92,17 @@ func main() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Register gRPC services
|
// Register gRPC services
|
||||||
pb.RegisterAuthServiceServer(grpcServer, service.NewAuthServiceServer(authService))
|
pb.RegisterAuthServiceServer(grpcServer, grpcService.NewAuthServiceServer(authService))
|
||||||
pb.RegisterFileServiceServer(grpcServer, service.NewFileServiceServer(fileService))
|
pb.RegisterFileServiceServer(grpcServer, grpcService.NewFileServiceServer(fileService))
|
||||||
pb.RegisterOrderServiceServer(grpcServer, service.NewOrderServiceServer(orderService))
|
pb.RegisterOrderServiceServer(grpcServer, grpcService.NewOrderServiceServer(orderService))
|
||||||
pb.RegisterPrintServiceServer(grpcServer, service.NewPrintServiceServer(printService))
|
pb.RegisterPrintServiceServer(grpcServer, grpcService.NewPrintServiceServer(printService))
|
||||||
pb.RegisterLibraryServiceServer(grpcServer, service.NewLibraryServiceServer(libraryRepo, fileRepo))
|
pb.RegisterLibraryServiceServer(grpcServer, grpcService.NewLibraryServiceServer(libraryRepo, fileRepo))
|
||||||
pb.RegisterPriceServiceServer(grpcServer, service.NewPriceServiceServer(priceRepo))
|
pb.RegisterPriceServiceServer(grpcServer, grpcService.NewPriceServiceServer(priceRepo))
|
||||||
pb.RegisterPayServiceServer(grpcServer, service.NewPayServiceServer(orderService, paymentRepo, weChatPay, userRepo))
|
pb.RegisterPayServiceServer(grpcServer, grpcService.NewPayServiceServer(orderService, paymentRepo, weChatPay, userRepo))
|
||||||
pb.RegisterAdminServiceServer(grpcServer, service.NewAdminServiceServer(authService, orderRepo, printerRepo))
|
pb.RegisterAdminServiceServer(grpcServer, grpcService.NewAdminServiceServer(authService, orderRepo, printerRepo))
|
||||||
|
|
||||||
|
// Initialize HTTP gateway
|
||||||
|
gateway := newHTTPGateway(grpcServer, jwtManager)
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
|
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
|
||||||
@@ -125,14 +115,29 @@ func main() {
|
|||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
// HTTP server for gateway
|
||||||
|
httpServer := &http.Server{
|
||||||
|
Handler: gateway,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start HTTP server in goroutine
|
||||||
go func() {
|
go func() {
|
||||||
<-sigCh
|
zapLogger.Info("Starting HTTP gateway", zap.String("address", addr))
|
||||||
grpcServer.GracefulStop()
|
if err := httpServer.Serve(lis); err != nil && err != http.ErrServerClosed {
|
||||||
|
log.Fatalf("Failed to serve HTTP: %v", err)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
zapLogger.Info("Starting gRPC server", zap.String("address", addr))
|
// Wait for shutdown signal
|
||||||
if err := grpcServer.Serve(lis); err != nil {
|
<-sigCh
|
||||||
log.Fatalf("Failed to serve: %v", err)
|
zapLogger.Info("Shutting down servers...")
|
||||||
|
|
||||||
|
// Graceful stop gRPC server
|
||||||
|
grpcServer.GracefulStop()
|
||||||
|
|
||||||
|
// Shutdown HTTP server
|
||||||
|
if err := httpServer.Close(); err != nil {
|
||||||
|
zapLogger.Error("Failed to close HTTP server", zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +149,7 @@ func initDB(cfg *config.Config) (*gorm.DB, error) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
db, err := gorm.Open(mysql.Open(cfg.Database.DSN()), &gorm.Config{
|
db, err := gorm.Open(postgres.Open(cfg.Database.DSN()), &gorm.Config{
|
||||||
Logger: gormLogger,
|
Logger: gormLogger,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -161,3 +166,301 @@ func initDB(cfg *config.Config) (*gorm.DB, error) {
|
|||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTP Gateway
|
||||||
|
|
||||||
|
type httpGateway struct {
|
||||||
|
grpcServer *grpc.Server
|
||||||
|
jwtManager *jwt.JWTManager
|
||||||
|
mux *http.ServeMux
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHTTPGateway(grpcServer *grpc.Server, jwtManager *jwt.JWTManager) *httpGateway {
|
||||||
|
g := &httpGateway{
|
||||||
|
grpcServer: grpcServer,
|
||||||
|
jwtManager: jwtManager,
|
||||||
|
mux: http.NewServeMux(),
|
||||||
|
}
|
||||||
|
g.registerHandlers()
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
g.mux.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) registerHandlers() {
|
||||||
|
// Health check
|
||||||
|
g.mux.HandleFunc("/health", g.healthHandler)
|
||||||
|
|
||||||
|
// Auth endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/auth/login", g.handleLogin)
|
||||||
|
g.mux.HandleFunc("/api/v1/auth/refresh", g.handleRefreshToken)
|
||||||
|
g.mux.HandleFunc("/api/v1/auth/userinfo", g.handleGetUserInfo)
|
||||||
|
|
||||||
|
// File endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/file/upload", g.handleFileUpload)
|
||||||
|
g.mux.HandleFunc("/api/v1/file/", g.handleFileOps)
|
||||||
|
|
||||||
|
// Order endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/order/create", g.handleCreateOrder)
|
||||||
|
g.mux.HandleFunc("/api/v1/order/", g.handleOrderOps)
|
||||||
|
|
||||||
|
// Print endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/print/printers", g.handleGetPrinters)
|
||||||
|
g.mux.HandleFunc("/api/v1/print/submit", g.handleSubmitPrintJob)
|
||||||
|
|
||||||
|
// Library endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/library/categories", g.handleGetCategories)
|
||||||
|
g.mux.HandleFunc("/api/v1/library/files", g.handleGetLibraryFiles)
|
||||||
|
|
||||||
|
// Price endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/price/list", g.handleGetPriceList)
|
||||||
|
|
||||||
|
// Pay endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/pay/wxpay", g.handleCreateWxPayOrder)
|
||||||
|
g.mux.HandleFunc("/api/v1/pay/callback", g.handlePayCallback)
|
||||||
|
g.mux.HandleFunc("/api/v1/pay/balance", g.handlePayByBalance)
|
||||||
|
|
||||||
|
// Admin endpoints
|
||||||
|
g.mux.HandleFunc("/api/v1/admin/login", g.handleAdminLogin)
|
||||||
|
g.mux.HandleFunc("/api/v1/admin/stats", g.handleGetStatistics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"status":"ok"}`))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) writeJSON(w http.ResponseWriter, statusCode int, data interface{}) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
|
json.NewEncoder(w).Encode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleError(w http.ResponseWriter, err error) {
|
||||||
|
st, ok := status.FromError(err)
|
||||||
|
if !ok {
|
||||||
|
g.writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
switch st.Code() {
|
||||||
|
case codes.OK:
|
||||||
|
code = http.StatusOK
|
||||||
|
case codes.InvalidArgument:
|
||||||
|
code = http.StatusBadRequest
|
||||||
|
case codes.NotFound:
|
||||||
|
code = http.StatusNotFound
|
||||||
|
case codes.Unauthenticated:
|
||||||
|
code = http.StatusUnauthorized
|
||||||
|
case codes.PermissionDenied:
|
||||||
|
code = http.StatusForbidden
|
||||||
|
}
|
||||||
|
g.writeJSON(w, code, map[string]string{"error": st.Message()})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) parseToken(r *http.Request) (context.Context, error) {
|
||||||
|
token := r.Header.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
return nil, status.Error(codes.Unauthenticated, "missing token")
|
||||||
|
}
|
||||||
|
if len(token) > 7 && token[:7] == "Bearer " {
|
||||||
|
token = token[7:]
|
||||||
|
}
|
||||||
|
claims, err := g.jwtManager.ValidateToken(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Error(codes.Unauthenticated, "invalid token")
|
||||||
|
}
|
||||||
|
return metadata.NewOutgoingContext(r.Context(), metadata.Pairs(
|
||||||
|
"user_id", fmt.Sprintf("%d", claims.UserID),
|
||||||
|
"user_type", claims.UserType,
|
||||||
|
)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req pb.LoginRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// gRPC call would go here - returning placeholder for now
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "Use gRPC directly for login"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleRefreshToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleGetUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleFileUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleFileOps(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
case http.MethodDelete:
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
default:
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleCreateOrder(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleOrderOps(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
default:
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleGetPrinters(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleSubmitPrintJob(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleGetCategories(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleGetLibraryFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleGetPriceList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleCreateWxPayOrder(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handlePayCallback(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handlePayByBalance(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleAdminLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *httpGateway) handleGetStatistics(w http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := g.parseToken(r)
|
||||||
|
if err != nil {
|
||||||
|
g.handleError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.writeJSON(w, http.StatusOK, map[string]string{"message": "not implemented"})
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ type DatabaseConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DatabaseConfig) DSN() string {
|
func (d *DatabaseConfig) DSN() string {
|
||||||
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable TimeZone=Asia/Shanghai",
|
||||||
d.Username, d.Password, d.Host, d.Port, d.Database)
|
d.Host, d.Port, d.Username, d.Password, d.Database)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RedisConfig struct {
|
type RedisConfig struct {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/cloudprint/cloudprint-backend
|
module github.com/cloudprint/cloudprint-backend
|
||||||
|
|
||||||
go 1.24.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.0
|
github.com/golang-jwt/jwt/v5 v5.2.0
|
||||||
@@ -8,18 +8,21 @@ require (
|
|||||||
github.com/iGoogle-ink/gopay v1.5.14
|
github.com/iGoogle-ink/gopay v1.5.14
|
||||||
github.com/spf13/viper v1.18.2
|
github.com/spf13/viper v1.18.2
|
||||||
go.uber.org/zap v1.26.0
|
go.uber.org/zap v1.26.0
|
||||||
golang.org/x/crypto v0.46.0
|
golang.org/x/crypto v0.49.0
|
||||||
google.golang.org/grpc v1.79.3
|
google.golang.org/grpc v1.80.0
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gorm.io/driver/mysql v1.5.2
|
gorm.io/driver/postgres v1.5.9
|
||||||
gorm.io/gorm v1.25.5
|
gorm.io/gorm v1.25.10
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/iGoogle-ink/gotil v1.0.2 // indirect
|
github.com/iGoogle-ink/gotil v1.0.2 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
@@ -31,13 +34,16 @@ require (
|
|||||||
github.com/spf13/afero v1.11.0 // indirect
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.43.0 // indirect
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
golang.org/x/net v0.48.0 // indirect
|
golang.org/x/net v0.52.0 // indirect
|
||||||
golang.org/x/sys v0.39.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/text v0.32.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
golang.org/x/text v0.36.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO
|
|||||||
github.com/go-redis/redis/v8 v8.0.0-beta.5/go.mod h1:Mm9EH/5UMRx680UIryN6rd5XFn/L7zORPqLV+1D5thQ=
|
github.com/go-redis/redis/v8 v8.0.0-beta.5/go.mod h1:Mm9EH/5UMRx680UIryN6rd5XFn/L7zORPqLV+1D5thQ=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
|
||||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
@@ -95,6 +93,14 @@ github.com/iGoogle-ink/gopay v1.5.14 h1:vcwdqNeccx8FWrnqKTeZZSK5FcAHGUD07OFHwhMh
|
|||||||
github.com/iGoogle-ink/gopay v1.5.14/go.mod h1:JuI4rWXHSTEgFHD5C5xfpy3Do3b0pIcu/wdsRyw/Ds4=
|
github.com/iGoogle-ink/gopay v1.5.14/go.mod h1:JuI4rWXHSTEgFHD5C5xfpy3Do3b0pIcu/wdsRyw/Ds4=
|
||||||
github.com/iGoogle-ink/gotil v1.0.2 h1:z58bvmhq31twxecMkyWU5Mh8H7T9SGPOTvUuAw9vB7M=
|
github.com/iGoogle-ink/gotil v1.0.2 h1:z58bvmhq31twxecMkyWU5Mh8H7T9SGPOTvUuAw9vB7M=
|
||||||
github.com/iGoogle-ink/gotil v1.0.2/go.mod h1:HOeCIcJkJLAsQ+cAPdozZS3huVDT4YUKN/F7tmvvrbM=
|
github.com/iGoogle-ink/gotil v1.0.2/go.mod h1:HOeCIcJkJLAsQ+cAPdozZS3huVDT4YUKN/F7tmvvrbM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
@@ -176,10 +182,12 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
@@ -190,16 +198,16 @@ go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/otel v0.6.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek=
|
go.opentelemetry.io/otel v0.6.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek=
|
||||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
|
||||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
|
||||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
|
||||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
|
||||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
|
||||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
@@ -210,8 +218,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
@@ -233,8 +241,8 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -242,6 +250,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -252,13 +262,13 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -268,8 +278,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
@@ -279,23 +289,24 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
|
|||||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
@@ -307,11 +318,10 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
|
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
|
||||||
gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
|
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func NewFileServiceServer(fileService *service.FileService) *FileServiceServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) (*pb.UploadResponse, error) {
|
func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) error {
|
||||||
var fileName, fileType, uploaderType string
|
var fileName, fileType, uploaderType string
|
||||||
var uploaderID int32
|
var uploaderID int32
|
||||||
var chunks [][]byte
|
var chunks [][]byte
|
||||||
@@ -32,7 +32,7 @@ func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) (*pb.Uplo
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "receive chunk failed: %v", err)
|
return status.Errorf(codes.Internal, "receive chunk failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileName == "" {
|
if fileName == "" {
|
||||||
@@ -53,14 +53,14 @@ func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) (*pb.Uplo
|
|||||||
|
|
||||||
file, err := s.fileService.Upload(stream.Context(), fileName, fileType, uploaderType, uploaderID, data)
|
file, err := s.fileService.Upload(stream.Context(), fileName, fileType, uploaderType, uploaderID, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "upload failed: %v", err)
|
return status.Errorf(codes.Internal, "upload failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.UploadResponse{
|
return stream.SendAndClose(&pb.UploadResponse{
|
||||||
FileId: file.ID,
|
FileId: file.ID,
|
||||||
FilePath: file.FilePath,
|
FilePath: file.FilePath,
|
||||||
FileUrl: file.FilePath,
|
FileUrl: file.FilePath,
|
||||||
}, nil
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileServiceServer) GetFile(req *pb.GetFileRequest, stream pb.FileService_GetFileServer) error {
|
func (s *FileServiceServer) GetFile(req *pb.GetFileRequest, stream pb.FileService_GetFileServer) error {
|
||||||
|
|||||||
@@ -116,14 +116,14 @@ func (r *OrderRepository) GetStatistics(ctx context.Context) (totalUsers, totalO
|
|||||||
// 今日订单数
|
// 今日订单数
|
||||||
today := time.Now().Format("2006-01-02")
|
today := time.Now().Format("2006-01-02")
|
||||||
if err = r.db.WithContext(ctx).Model(&model.Order{}).
|
if err = r.db.WithContext(ctx).Model(&model.Order{}).
|
||||||
Where("DATE(created_at) = ? AND status = ?", today, model.OrderStatusPaid).
|
Where("created_at::date = ? AND status = ?", today, model.OrderStatusPaid).
|
||||||
Count(&todayOrders).Error; err != nil {
|
Count(&todayOrders).Error; err != nil {
|
||||||
return 0, 0, 0, 0, 0, fmt.Errorf("count today orders failed: %w", err)
|
return 0, 0, 0, 0, 0, fmt.Errorf("count today orders failed: %w", err)
|
||||||
}
|
}
|
||||||
// 今日收入
|
// 今日收入
|
||||||
if err = r.db.WithContext(ctx).Model(&model.Order{}).
|
if err = r.db.WithContext(ctx).Model(&model.Order{}).
|
||||||
Select("COALESCE(SUM(total_amount), 0)").
|
Select("COALESCE(SUM(total_amount), 0)").
|
||||||
Where("DATE(created_at) = ? AND status = ?", today, model.OrderStatusPaid).
|
Where("created_at::date = ? AND status = ?", today, model.OrderStatusPaid).
|
||||||
Scan(&todayRevenue).Error; err != nil {
|
Scan(&todayRevenue).Error; err != nil {
|
||||||
return 0, 0, 0, 0, 0, fmt.Errorf("sum today revenue failed: %w", err)
|
return 0, 0, 0, 0, 0, fmt.Errorf("sum today revenue failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,182 +1,186 @@
|
|||||||
-- 云印享 - 付费打印服务系统数据库初始化脚本
|
-- 云印享 - 付费打印服务系统数据库初始化脚本 (PostgreSQL)
|
||||||
-- 数据库: cloudprint
|
-- 数据库: cloudprint
|
||||||
|
|
||||||
CREATE DATABASE IF NOT EXISTS `cloudprint` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
-- 创建数据库(通常需要超级用户权限,也可以手动创建)
|
||||||
USE `cloudprint`;
|
-- CREATE DATABASE cloudprint WITH ENCODING = 'UTF8';
|
||||||
|
-- \c cloudprint
|
||||||
|
|
||||||
-- 用户表
|
-- 用户表
|
||||||
CREATE TABLE IF NOT EXISTS `user` (
|
CREATE TABLE IF NOT EXISTS "user" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`openid` VARCHAR(64) UNIQUE NOT NULL COMMENT '微信OpenID',
|
"openid" VARCHAR(64) UNIQUE NOT NULL,
|
||||||
`nickname` VARCHAR(128) DEFAULT '' COMMENT '昵称',
|
"nickname" VARCHAR(128) DEFAULT '',
|
||||||
`avatar` VARCHAR(512) DEFAULT '' COMMENT '头像URL',
|
"avatar" VARCHAR(512) DEFAULT '',
|
||||||
`balance` DECIMAL(10,2) DEFAULT 0.00 COMMENT '余额',
|
"balance" DECIMAL(10,2) DEFAULT 0.00,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
"updated_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
INDEX `idx_openid` (`openid`)
|
);
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
|
CREATE INDEX IF NOT EXISTS "idx_user_openid" ON "user" ("openid");
|
||||||
|
|
||||||
-- 管理员表
|
-- 管理员表
|
||||||
CREATE TABLE IF NOT EXISTS `admin` (
|
CREATE TABLE IF NOT EXISTS "admin" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`username` VARCHAR(64) UNIQUE NOT NULL COMMENT '用户名',
|
"username" VARCHAR(64) UNIQUE NOT NULL,
|
||||||
`password_hash` VARCHAR(256) NOT NULL COMMENT '密码哈希',
|
"password_hash" VARCHAR(256) NOT NULL,
|
||||||
`nickname` VARCHAR(128) DEFAULT '' COMMENT '昵称',
|
"nickname" VARCHAR(128) DEFAULT '',
|
||||||
`role` TINYINT DEFAULT 1 COMMENT '1:普通管理员 2:超级管理员',
|
"role" SMALLINT DEFAULT 1,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
INDEX `idx_username` (`username`)
|
);
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员表';
|
CREATE INDEX IF NOT EXISTS "idx_admin_username" ON "admin" ("username");
|
||||||
|
|
||||||
-- 打印机表
|
-- 打印机表
|
||||||
CREATE TABLE IF NOT EXISTS `printer` (
|
CREATE TABLE IF NOT EXISTS "printer" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`name` VARCHAR(128) UNIQUE NOT NULL COMMENT '系统打印机名',
|
"name" VARCHAR(128) UNIQUE NOT NULL,
|
||||||
`display_name` VARCHAR(128) NOT NULL COMMENT '显示名称',
|
"display_name" VARCHAR(128) NOT NULL,
|
||||||
`api_key` VARCHAR(64) UNIQUE NOT NULL COMMENT '客户端认证Key',
|
"api_key" VARCHAR(64) UNIQUE NOT NULL,
|
||||||
`is_active` TINYINT DEFAULT 1 COMMENT '是否启用',
|
"is_active" BOOLEAN DEFAULT TRUE,
|
||||||
`status` TINYINT DEFAULT 0 COMMENT '0:空闲 1:打印中 2:离线',
|
"status" SMALLINT DEFAULT 0,
|
||||||
`last_heartbeat` DATETIME DEFAULT NULL COMMENT '最后心跳时间',
|
"last_heartbeat" TIMESTAMP DEFAULT NULL,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
INDEX `idx_name` (`name`),
|
);
|
||||||
INDEX `idx_api_key` (`api_key`)
|
CREATE INDEX IF NOT EXISTS "idx_printer_name" ON "printer" ("name");
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='打印机表';
|
CREATE INDEX IF NOT EXISTS "idx_printer_api_key" ON "printer" ("api_key");
|
||||||
|
|
||||||
-- 订单表
|
|
||||||
CREATE TABLE IF NOT EXISTS `order` (
|
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
`order_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '订单号',
|
|
||||||
`user_id` INT NOT NULL COMMENT '用户ID',
|
|
||||||
`status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:已支付 2:打印中 3:已完成 4:已取消',
|
|
||||||
`total_amount` DECIMAL(10,2) NOT NULL COMMENT '总金额',
|
|
||||||
`remark` VARCHAR(512) DEFAULT '' COMMENT '备注',
|
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`paid_at` DATETIME DEFAULT NULL COMMENT '支付时间',
|
|
||||||
INDEX `idx_order_no` (`order_no`),
|
|
||||||
INDEX `idx_user_id` (`user_id`),
|
|
||||||
INDEX `idx_status` (`status`),
|
|
||||||
INDEX `idx_created_at` (`created_at`),
|
|
||||||
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE RESTRICT
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
|
|
||||||
|
|
||||||
-- 订单明细表
|
|
||||||
CREATE TABLE IF NOT EXISTS `order_item` (
|
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
`order_id` INT NOT NULL COMMENT '订单ID',
|
|
||||||
`file_id` INT NOT NULL COMMENT '文件ID',
|
|
||||||
`printer_id` INT DEFAULT NULL COMMENT '打印机ID',
|
|
||||||
`copies` INT DEFAULT 1 COMMENT '份数',
|
|
||||||
`color` TINYINT DEFAULT 0 COMMENT '是否彩色 0:黑白 1:彩色',
|
|
||||||
`duplex` TINYINT DEFAULT 0 COMMENT '是否双面 0:单面 1:双面',
|
|
||||||
`page_range` VARCHAR(64) DEFAULT 'all' COMMENT '页面范围',
|
|
||||||
`price` DECIMAL(10,2) NOT NULL COMMENT '价格',
|
|
||||||
INDEX `idx_order_id` (`order_id`),
|
|
||||||
INDEX `idx_file_id` (`file_id`),
|
|
||||||
FOREIGN KEY (`order_id`) REFERENCES `order`(`id`) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (`file_id`) REFERENCES `file`(`id`) ON DELETE RESTRICT
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';
|
|
||||||
|
|
||||||
-- 文件表
|
-- 文件表
|
||||||
CREATE TABLE IF NOT EXISTS `file` (
|
CREATE TABLE IF NOT EXISTS "file" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`file_name` VARCHAR(256) NOT NULL COMMENT '文件名',
|
"file_name" VARCHAR(256) NOT NULL,
|
||||||
`file_path` VARCHAR(512) NOT NULL COMMENT '文件路径',
|
"file_path" VARCHAR(512) NOT NULL,
|
||||||
`file_type` VARCHAR(32) NOT NULL COMMENT '文件类型',
|
"file_type" VARCHAR(32) NOT NULL,
|
||||||
`file_size` BIGINT NOT NULL COMMENT '文件大小(字节)',
|
"file_size" BIGINT NOT NULL,
|
||||||
`uploader_type` VARCHAR(16) NOT NULL COMMENT '上传者类型: user/admin/system',
|
"uploader_type" VARCHAR(16) NOT NULL,
|
||||||
`uploader_id` INT NOT NULL COMMENT '上传者ID',
|
"uploader_id" INTEGER NOT NULL,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
INDEX `idx_uploader` (`uploader_type`, `uploader_id`),
|
);
|
||||||
INDEX `idx_file_type` (`file_type`)
|
CREATE INDEX IF NOT EXISTS "idx_file_uploader" ON "file" ("uploader_type", "uploader_id");
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表';
|
CREATE INDEX IF NOT EXISTS "idx_file_type" ON "file" ("file_type");
|
||||||
|
|
||||||
|
-- 订单表
|
||||||
|
CREATE TABLE IF NOT EXISTS "order" (
|
||||||
|
"id" SERIAL PRIMARY KEY,
|
||||||
|
"order_no" VARCHAR(32) UNIQUE NOT NULL,
|
||||||
|
"user_id" INTEGER NOT NULL,
|
||||||
|
"status" SMALLINT DEFAULT 0,
|
||||||
|
"total_amount" DECIMAL(10,2) NOT NULL,
|
||||||
|
"remark" VARCHAR(512) DEFAULT '',
|
||||||
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"paid_at" TIMESTAMP DEFAULT NULL,
|
||||||
|
FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE RESTRICT
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_order_order_no" ON "order" ("order_no");
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_order_user_id" ON "order" ("user_id");
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_order_status" ON "order" ("status");
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_order_created_at" ON "order" ("created_at");
|
||||||
|
|
||||||
|
-- 订单明细表
|
||||||
|
CREATE TABLE IF NOT EXISTS "order_item" (
|
||||||
|
"id" SERIAL PRIMARY KEY,
|
||||||
|
"order_id" INTEGER NOT NULL,
|
||||||
|
"file_id" INTEGER NOT NULL,
|
||||||
|
"printer_id" INTEGER DEFAULT NULL,
|
||||||
|
"copies" INTEGER DEFAULT 1,
|
||||||
|
"color" BOOLEAN DEFAULT FALSE,
|
||||||
|
"duplex" BOOLEAN DEFAULT FALSE,
|
||||||
|
"page_range" VARCHAR(64) DEFAULT 'all',
|
||||||
|
"price" DECIMAL(10,2) NOT NULL,
|
||||||
|
FOREIGN KEY ("order_id") REFERENCES "order"("id") ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY ("file_id") REFERENCES "file"("id") ON DELETE RESTRICT
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_order_item_order_id" ON "order_item" ("order_id");
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_order_item_file_id" ON "order_item" ("file_id");
|
||||||
|
|
||||||
-- 文库分类表
|
-- 文库分类表
|
||||||
CREATE TABLE IF NOT EXISTS `library_category` (
|
CREATE TABLE IF NOT EXISTS "library_category" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`name` VARCHAR(128) NOT NULL COMMENT '分类名称',
|
"name" VARCHAR(128) NOT NULL,
|
||||||
`icon` VARCHAR(128) DEFAULT '' COMMENT '图标',
|
"icon" VARCHAR(128) DEFAULT '',
|
||||||
`sort_order` INT DEFAULT 0 COMMENT '排序',
|
"sort_order" INTEGER DEFAULT 0,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文库分类表';
|
);
|
||||||
|
|
||||||
-- 文库文件表
|
-- 文库文件表
|
||||||
CREATE TABLE IF NOT EXISTS `library_file` (
|
CREATE TABLE IF NOT EXISTS "library_file" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`category_id` INT NOT NULL COMMENT '分类ID',
|
"category_id" INTEGER NOT NULL,
|
||||||
`file_id` INT NOT NULL COMMENT '文件ID',
|
"file_id" INTEGER NOT NULL,
|
||||||
`title` VARCHAR(256) NOT NULL COMMENT '标题',
|
"title" VARCHAR(256) NOT NULL,
|
||||||
`description` VARCHAR(512) DEFAULT '' COMMENT '描述',
|
"description" VARCHAR(512) DEFAULT '',
|
||||||
`page_count` INT DEFAULT 0 COMMENT '页数',
|
"page_count" INTEGER DEFAULT 0,
|
||||||
`download_count` INT DEFAULT 0 COMMENT '下载次数',
|
"download_count" INTEGER DEFAULT 0,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
INDEX `idx_category_id` (`category_id`),
|
FOREIGN KEY ("category_id") REFERENCES "library_category"("id") ON DELETE CASCADE,
|
||||||
INDEX `idx_file_id` (`file_id`),
|
FOREIGN KEY ("file_id") REFERENCES "file"("id") ON DELETE CASCADE
|
||||||
FOREIGN KEY (`category_id`) REFERENCES `library_category`(`id`) ON DELETE CASCADE,
|
);
|
||||||
FOREIGN KEY (`file_id`) REFERENCES `file`(`id`) ON DELETE CASCADE
|
CREATE INDEX IF NOT EXISTS "idx_library_file_category_id" ON "library_file" ("category_id");
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文库文件表';
|
CREATE INDEX IF NOT EXISTS "idx_library_file_file_id" ON "library_file" ("file_id");
|
||||||
|
|
||||||
-- 打印任务表
|
-- 打印任务表
|
||||||
CREATE TABLE IF NOT EXISTS `print_job` (
|
CREATE TABLE IF NOT EXISTS "print_job" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`job_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '任务号',
|
"job_no" VARCHAR(32) UNIQUE NOT NULL,
|
||||||
`printer_id` INT NOT NULL COMMENT '打印机ID',
|
"printer_id" INTEGER NOT NULL,
|
||||||
`order_item_id` INT NOT NULL COMMENT '订单明细ID',
|
"order_item_id" INTEGER NOT NULL,
|
||||||
`status` VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/printing/completed/failed/cancelled',
|
"status" VARCHAR(16) DEFAULT 'pending',
|
||||||
`progress` INT DEFAULT 0 COMMENT '进度(0-100)',
|
"progress" INTEGER DEFAULT 0,
|
||||||
`error_msg` VARCHAR(512) DEFAULT '' COMMENT '错误信息',
|
"error_msg" VARCHAR(512) DEFAULT '',
|
||||||
`started_at` DATETIME DEFAULT NULL COMMENT '开始时间',
|
"started_at" TIMESTAMP DEFAULT NULL,
|
||||||
`completed_at` DATETIME DEFAULT NULL COMMENT '完成时间',
|
"completed_at" TIMESTAMP DEFAULT NULL,
|
||||||
INDEX `idx_job_no` (`job_no`),
|
FOREIGN KEY ("printer_id") REFERENCES "printer"("id") ON DELETE RESTRICT,
|
||||||
INDEX `idx_printer_id` (`printer_id`),
|
FOREIGN KEY ("order_item_id") REFERENCES "order_item"("id") ON DELETE RESTRICT
|
||||||
INDEX `idx_status` (`status`),
|
);
|
||||||
FOREIGN KEY (`printer_id`) REFERENCES `printer`(`id`) ON DELETE RESTRICT,
|
CREATE INDEX IF NOT EXISTS "idx_print_job_job_no" ON "print_job" ("job_no");
|
||||||
FOREIGN KEY (`order_item_id`) REFERENCES `order_item`(`id`) ON DELETE RESTRICT
|
CREATE INDEX IF NOT EXISTS "idx_print_job_printer_id" ON "print_job" ("printer_id");
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='打印任务表';
|
CREATE INDEX IF NOT EXISTS "idx_print_job_status" ON "print_job" ("status");
|
||||||
|
|
||||||
-- 价目表
|
-- 价目表
|
||||||
CREATE TABLE IF NOT EXISTS `price_list` (
|
CREATE TABLE IF NOT EXISTS "price_list" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`name` VARCHAR(128) NOT NULL COMMENT '项目名称',
|
"name" VARCHAR(128) NOT NULL,
|
||||||
`type` VARCHAR(32) NOT NULL COMMENT '纸张类型: A4/A3/照片纸',
|
"type" VARCHAR(32) NOT NULL,
|
||||||
`price` DECIMAL(10,2) NOT NULL COMMENT '单价',
|
"price" DECIMAL(10,2) NOT NULL,
|
||||||
`unit` VARCHAR(16) NOT NULL COMMENT '单位: 页/张/份',
|
"unit" VARCHAR(16) NOT NULL,
|
||||||
`color_enabled` TINYINT DEFAULT 1 COMMENT '是否支持彩色',
|
"color_enabled" BOOLEAN DEFAULT TRUE,
|
||||||
`is_active` TINYINT DEFAULT 1 COMMENT '是否启用',
|
"is_active" BOOLEAN DEFAULT TRUE,
|
||||||
`sort_order` INT DEFAULT 0 COMMENT '排序',
|
"sort_order" INTEGER DEFAULT 0,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
INDEX `idx_type` (`type`),
|
);
|
||||||
INDEX `idx_is_active` (`is_active`)
|
CREATE INDEX IF NOT EXISTS "idx_price_list_type" ON "price_list" ("type");
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='价目表';
|
CREATE INDEX IF NOT EXISTS "idx_price_list_is_active" ON "price_list" ("is_active");
|
||||||
|
|
||||||
-- 支付记录表
|
-- 支付记录表
|
||||||
CREATE TABLE IF NOT EXISTS `payment` (
|
CREATE TABLE IF NOT EXISTS "payment" (
|
||||||
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
"id" SERIAL PRIMARY KEY,
|
||||||
`order_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '订单号',
|
"order_no" VARCHAR(32) UNIQUE NOT NULL,
|
||||||
`pay_type` VARCHAR(16) DEFAULT 'wechat' COMMENT '支付类型: wechat/balance',
|
"pay_type" VARCHAR(16) DEFAULT 'wechat',
|
||||||
`pay_status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:支付中 2:成功 3:失败',
|
"pay_status" SMALLINT DEFAULT 0,
|
||||||
`transaction_id` VARCHAR(64) DEFAULT '' COMMENT '微信交易号',
|
"transaction_id" VARCHAR(64) DEFAULT '',
|
||||||
`paid_at` DATETIME DEFAULT NULL COMMENT '支付时间',
|
"paid_at" TIMESTAMP DEFAULT NULL,
|
||||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
INDEX `idx_order_no` (`order_no`),
|
);
|
||||||
INDEX `idx_pay_status` (`pay_status`)
|
CREATE INDEX IF NOT EXISTS "idx_payment_order_no" ON "payment" ("order_no");
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付记录表';
|
CREATE INDEX IF NOT EXISTS "idx_payment_pay_status" ON "payment" ("pay_status");
|
||||||
|
|
||||||
-- 初始化管理员账号 (密码: admin123)
|
-- 初始化管理员账号 (密码: admin123)
|
||||||
-- 密码哈希使用 bcrypt 生成
|
-- 密码哈希使用 bcrypt 生成
|
||||||
INSERT INTO `admin` (`username`, `password_hash`, `nickname`, `role`) VALUES
|
INSERT INTO "admin" ("username", "password_hash", "nickname", "role") VALUES
|
||||||
('admin', '$2a$10$N9qo8uLOickgx2ZMRZoMy.MqrqJlmZ2j3.N9qo8uLOickgx2ZMRZoG', '系统管理员', 2);
|
('admin', '$2a$10$N9qo8uLOickgx2ZMRZoMy.MqrqJlmZ2j3.N9qo8uLOickgx2ZMRZoG', '系统管理员', 2)
|
||||||
|
ON CONFLICT ("username") DO NOTHING;
|
||||||
|
|
||||||
-- 初始化默认价目表
|
-- 初始化默认价目表
|
||||||
INSERT INTO `price_list` (`name`, `type`, `price`, `unit`, `color_enabled`, `is_active`, `sort_order`) VALUES
|
INSERT INTO "price_list" ("name", "type", "price", "unit", "color_enabled", "is_active", "sort_order") VALUES
|
||||||
('A4黑白打印', 'A4', 0.10, '页', 0, 1, 1),
|
('A4黑白打印', 'A4', 0.10, '页', FALSE, TRUE, 1),
|
||||||
('A4彩色打印', 'A4', 0.30, '页', 1, 1, 2),
|
('A4彩色打印', 'A4', 0.30, '页', TRUE, TRUE, 2),
|
||||||
('A3黑白打印', 'A3', 0.20, '页', 0, 1, 3),
|
('A3黑白打印', 'A3', 0.20, '页', FALSE, TRUE, 3),
|
||||||
('A3彩色打印', 'A3', 0.60, '页', 1, 1, 4),
|
('A3彩色打印', 'A3', 0.60, '页', TRUE, TRUE, 4),
|
||||||
('照片打印', '照片纸', 2.00, '张', 1, 1, 5);
|
('照片打印', '照片纸', 2.00, '张', TRUE, TRUE, 5)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
-- 初始化默认文库分类
|
-- 初始化默认文库分类
|
||||||
INSERT INTO `library_category` (`name`, `icon`, `sort_order`) VALUES
|
INSERT INTO "library_category" ("name", "icon", "sort_order") VALUES
|
||||||
('学习资料', 'book', 1),
|
('学习资料', 'book', 1),
|
||||||
('考试真题', 'exam', 2),
|
('考试真题', 'exam', 2),
|
||||||
('简历模板', 'resume', 3),
|
('简历模板', 'resume', 3),
|
||||||
('合同协议', 'contract', 4),
|
('合同协议', 'contract', 4),
|
||||||
('其他资料', 'other', 5);
|
('其他资料', 'other', 5)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|||||||
Reference in New Issue
Block a user