@@ -0,0 +1,36 @@
|
||||
package models
|
||||
|
||||
var Configs map[string]interface{}
|
||||
|
||||
var Wed_configs map[string]interface{}
|
||||
|
||||
var Database_configs map[string]interface{}
|
||||
|
||||
var User_configs map[string]interface{}
|
||||
|
||||
var Allowed_avatar_ext = map[string]bool{
|
||||
".jpg": true,
|
||||
".jpeg": true,
|
||||
".png": true,
|
||||
}
|
||||
|
||||
var Allowed_avatar_mime = map[string]bool{
|
||||
"image/jpeg": true,
|
||||
"image/png": true,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
func All_config_init() {
|
||||
//读取web配置
|
||||
Wed_configs = Configs["web"].(map[string]interface{})
|
||||
|
||||
//初始化数据库
|
||||
Database_init()
|
||||
|
||||
//初始化user config
|
||||
User_configs = Configs["user"].(map[string]interface{})
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package models
|
||||
@@ -0,0 +1,191 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var DB *gorm.DB
|
||||
var err error
|
||||
|
||||
type User struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"` // 自增主键
|
||||
Name string `gorm:"size:100;uniqueIndex"` // 唯一约束索引
|
||||
Email string `gorm:"size:255;index"` // 字符串长度限制100 索引
|
||||
Pass string `gorm:"size:128"` // 建议存储哈希后的密码
|
||||
Date time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 默认当前时间
|
||||
}
|
||||
|
||||
type User_info struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||
UserID uint `gorm:"not null;uniqueIndex"`
|
||||
FirstName string `gorm:"size:50;null"`
|
||||
Username string `gorm:"size:30;null"`
|
||||
Birthdate time.Time `gorm:"type:datetime;null"`
|
||||
Gender string `gorm:"type:char(1);check:gender IN ('M', 'F', 'U');default:'U'"`
|
||||
AvatarPath string `gorm:"size:255"`
|
||||
Region string `gorm:"size:50"`
|
||||
Language string `gorm:"size:10;default:'zh-CN'"`
|
||||
CreatedAt time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP;column:created_at"`
|
||||
}
|
||||
|
||||
// var def_user_info = User_info{
|
||||
// ID:0,
|
||||
// UserID:0,
|
||||
// }
|
||||
|
||||
type Cookie struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||
UserID uint `gorm:"size:16;not null"`
|
||||
Name string `gorm:"size:255;not null;index"`
|
||||
Value string `gorm:"size:255;not null;index"`
|
||||
Domain string `gorm:"size:255;not null"`
|
||||
Path string `gorm:"size:255;not null;default:/"`
|
||||
ExpiresAt time.Time `gorm:"type:datetime;index"`
|
||||
CreatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"`
|
||||
UpdatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"`
|
||||
SecureFlag bool `gorm:"not null;default:false"`
|
||||
HttpOnly bool `gorm:"not null;default:false"`
|
||||
SameSite string `gorm:"size:10;not null;default:'Lax'"`
|
||||
PartitionKey string `gorm:"size:50"`
|
||||
}
|
||||
|
||||
type Warehouse struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||
CreatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"`
|
||||
UpdatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"`
|
||||
Name string `gorm:"type:varchar(255);not null;index"` // 仓库名称
|
||||
CreatorID uint `gorm:"not null;index"` // 创建用户ID(外键)
|
||||
Location string `gorm:"type:varchar(500);not null"` // 仓库位置
|
||||
Capacity int `gorm:"not null;check:capacity >= 0"` // 仓库总容量
|
||||
UsedCapacity int `gorm:"not null;check:used_capacity >= 0"` // 已用容量
|
||||
ImagePath string `gorm:"type:varchar(1000)"` // 仓库图片路径
|
||||
Info string `gorm:"type:text"` // 仓库详细信息
|
||||
|
||||
}
|
||||
|
||||
// 物品状态枚举
|
||||
type ItemStatus string
|
||||
|
||||
const (
|
||||
ItemStatusAvailable ItemStatus = "available"
|
||||
ItemStatusMaintenance ItemStatus = "maintenance"
|
||||
ItemStatusRetired ItemStatus = "retired"
|
||||
)
|
||||
|
||||
// Item 仓库物品表模型
|
||||
type Item struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||
CreatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"`
|
||||
UpdatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"`
|
||||
|
||||
// 基本信息
|
||||
Name string `gorm:"type:varchar(255);not null;comment:物品名称"`
|
||||
Description string `gorm:"type:text;comment:物品描述"`
|
||||
|
||||
// 库存信息
|
||||
WarehouseID uint `gorm:"not null;index;comment:仓库ID"`
|
||||
Quantity uint `gorm:"not null;default:0;comment:库存数量"`
|
||||
Location string `gorm:"type:varchar(100);comment:库内位置"`
|
||||
|
||||
// 状态管理
|
||||
Status ItemStatus `gorm:"type:varchar(20);not null;default:'available';index;comment:物品状态"`
|
||||
|
||||
// 扩展信息
|
||||
BatchNumber string `gorm:"type:varchar(50);comment:批次号"`
|
||||
ExpirationDate time.Time `gorm:"type:date;comment:失效日期"`
|
||||
|
||||
// 关联关系
|
||||
//Warehouse Warehouse `gorm:"foreignKey:WarehouseID;references:ID;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT"`
|
||||
}
|
||||
|
||||
type WarehouseItem struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement"`
|
||||
CreatedByID uint `gorm:"not null;index:idx_created_by;comment:创建用户ID"`
|
||||
WarehouseID uint `gorm:"not null;index:idx_warehouse;comment:仓库ID"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;index:idx_created_at;comment:创建时间"`
|
||||
Name string `gorm:"type:varchar(255);not null;index:idx_name;comment:物品名称"`
|
||||
SerialNumber string `gorm:"type:varchar(100);index;null;comment:序列号"`
|
||||
Description string `gorm:"type:text;null;comment:物品描述"`
|
||||
ShelfLocation string `gorm:"type:varchar(50);null;index:idx_shelf;comment:货架位置"`
|
||||
Quantity int `gorm:"type:int unsigned;null;comment:物品数量"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime;index:idx_updated_at;comment:最后更新时间"`
|
||||
Status string `gorm:"type:varchar(10);default:'正常';index:idx_status;comment:物品状态(正常/损坏/维修/报废)"`
|
||||
Color string `gorm:"type:varchar(16);default:'bg-success';comment:状态颜色"`
|
||||
Destiny string `gorm:"type:varchar(100);index:idx_destiny;null;comment:物品归宿"`
|
||||
ItemValue int `gorm:"type:int;null;comment:物品价值(单位:分)"`
|
||||
}
|
||||
|
||||
// 工单表
|
||||
type Ticket struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"` // 自增ID
|
||||
Title string `gorm:"type:varchar(255);index:idx_title,length:191" json:"title"` // 带索引标题
|
||||
Info string `gorm:"type:text;not null" json:"info"` // 详细信息
|
||||
Type string `gorm:"type:varchar(16);not null;default:'normal'" json:"type"` // 工单类型
|
||||
CreatedAt time.Time `gorm:"autoCreateTime;index;not null;" json:"createdAt"` // 创建日期
|
||||
UpdatedAt time.Time `gorm:"autoCreateTime;index;not null;" json:"updatedAt"` // 最后更新时间
|
||||
UserID uint `gorm:"index;not null" json:"userId"` // 创建用户ID
|
||||
Status string `gorm:"type:varchar(16);index;not null;default:'open'" json:"status"` // 最后状态
|
||||
Color string `gorm:"type:varchar(32);not null;default:'#3498db'" json:"color"` // 状态颜色
|
||||
ItemID uint `gorm:"null" json:"itemId"` // 关联物件ID
|
||||
CommentCount uint `gorm:"not null;default:0" json:"commentCount"` // 评论数量
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
func Database_init() {
|
||||
|
||||
fmt.Println("database_init")
|
||||
//var database_config map[string]interface{}=Configs["database"]
|
||||
Database_configs = Configs["database"].(map[string]interface{})
|
||||
|
||||
if Database_configs["type"].(string) == "sqlite" {
|
||||
//sqlite init
|
||||
fmt.Println("sqlite")
|
||||
DB, err = gorm.Open(sqlite.Open(Database_configs["path"].(string)), &gorm.Config{})
|
||||
} else if Database_configs["type"].(string) == "mysql" {
|
||||
//mysql init
|
||||
fmt.Println("mysql")
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", Database_configs["user"].(string), Database_configs["pass"].(string), Database_configs["host"].(string), Database_configs["port"].(string), Database_configs["name"].(string))
|
||||
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
panic("数据库连接失败")
|
||||
}
|
||||
|
||||
// 检查 users 表是否存在
|
||||
// if !DB.Migrator().HasTable(&User{}) {
|
||||
// // 自动创建表结构
|
||||
// err := DB.AutoMigrate(&User{})
|
||||
// if err != nil {
|
||||
// panic("创建表失败: " + err.Error())
|
||||
// }
|
||||
// fmt.Println("users 表已创建")
|
||||
// } else {
|
||||
// fmt.Println("users 表已存在")
|
||||
// }
|
||||
|
||||
// 自动创建表结构
|
||||
DB.AutoMigrate(&User{})
|
||||
|
||||
DB.AutoMigrate(&User_info{})
|
||||
|
||||
DB.AutoMigrate(&Cookie{})
|
||||
|
||||
DB.AutoMigrate(&Warehouse{})
|
||||
|
||||
DB.AutoMigrate(&Item{})
|
||||
|
||||
DB.AutoMigrate(&WarehouseItem{})
|
||||
|
||||
DB.AutoMigrate(&Ticket{})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Unix_to_str_time(nanos int64) string {
|
||||
t := time.Unix(0, nanos)
|
||||
return (t.Format("2006-01-02 15:04:05.999999999")) // 输出:2021-06-10 09:49:59.123456789
|
||||
}
|
||||
|
||||
// 获取当前时间字符串
|
||||
// 参数格式可选,默认"2006-01-02 15:04:05"
|
||||
func Get_current_time_string(format ...string) string {
|
||||
// 默认格式
|
||||
layout := "2006_01_02-15_04_05.999999999"
|
||||
|
||||
// 如果传入了格式参数则使用自定义格式
|
||||
if len(format) > 0 {
|
||||
layout = format[0]
|
||||
}
|
||||
|
||||
return time.Now().Format(layout)
|
||||
}
|
||||
|
||||
func Time_date_str_to_time(timestr string) time.Time {
|
||||
|
||||
// 定义与字符串匹配的布局(注意必须使用Go的参考时间格式)
|
||||
layout := "2006-01-02"
|
||||
|
||||
// 解析时间
|
||||
t, err := time.Parse(layout, timestr)
|
||||
if err != nil {
|
||||
var notime time.Time
|
||||
|
||||
return notime
|
||||
}
|
||||
|
||||
return t
|
||||
|
||||
}
|
||||
|
||||
// 判断文件是否存在
|
||||
func File_exists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Is_email_valid(email string) bool {
|
||||
// 正则表达式(覆盖 99% 常见邮箱格式)
|
||||
pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
|
||||
regex := regexp.MustCompile(pattern)
|
||||
return regex.MatchString(email)
|
||||
}
|
||||
|
||||
func Valid_str_len(s string, min, max int, checkRune bool) bool {
|
||||
var length int
|
||||
if checkRune {
|
||||
length = len([]rune(s))
|
||||
} else {
|
||||
length = len(s)
|
||||
}
|
||||
|
||||
if min < 0 || max < 0 || (max != 0 && max < min) {
|
||||
return false // 参数非法
|
||||
}
|
||||
|
||||
return length >= min && (max == 0 || length <= max)
|
||||
|
||||
// 示例
|
||||
//valid1 := Valid_str_len("hello", 3, 20, false) // 校验字节数
|
||||
//valid2 := Valid_str_len("你好", 1, 2, true) // 校验字符数
|
||||
}
|
||||
|
||||
func Rand_str_32() string {
|
||||
// 生成 32 字节 (256 位) 随机数据
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 转换为 16 进制字符串 (长度 64)
|
||||
cookie := hex.EncodeToString(b)
|
||||
return cookie
|
||||
}
|
||||
|
||||
func Md5_str(str string) string {
|
||||
hashBytes2 := md5.Sum([]byte(str))
|
||||
hashString2 := hex.EncodeToString(hashBytes2[:]) // 注意数组转切片的[:]
|
||||
return hashString2
|
||||
}
|
||||
|
||||
func Hash_user_pass(str string) string {
|
||||
switch User_configs["pass_hash_type"].(string) {
|
||||
case "text":
|
||||
return str
|
||||
case "md5":
|
||||
return Md5_str(str)
|
||||
}
|
||||
|
||||
return Get_current_time_string() + Rand_str_32() //如果转换失败返回当前时间,避免撞库
|
||||
}
|
||||
|
||||
func Page_range(start_page int64, end_page int64, now_page int64, href_heard string) []map[string]string {
|
||||
var a []map[string]string
|
||||
|
||||
for i := start_page; i <= end_page; i++ {
|
||||
var active = ""
|
||||
if i == now_page {
|
||||
active = "active"
|
||||
} else {
|
||||
active = ""
|
||||
}
|
||||
a = append(a, map[string]string{
|
||||
"page_href": fmt.Sprintf("%s%d", href_heard, i),
|
||||
"active": active,
|
||||
"page": fmt.Sprintf("%d", i),
|
||||
})
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package models
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package models
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package models
|
||||
|
||||
func Warehouse_get_total_pages() int64 {
|
||||
var all_page int64 = 0
|
||||
|
||||
DB.Model(&Warehouse{}).Count(&all_page)
|
||||
var repos_per_page = int64(Configs["warehouses"].(map[string]interface{})["repos_per_page"].(int))
|
||||
return (all_page / repos_per_page) + 1
|
||||
|
||||
}
|
||||
|
||||
func Warehouse_get_warehouses(page int64) []Warehouse {
|
||||
|
||||
if page == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var pageSize = int(Configs["warehouses"].(map[string]interface{})["repos_per_page"].(int))
|
||||
var Warehouses []Warehouse
|
||||
offset := int((int(page) - 1) * pageSize)
|
||||
DB.Model(Warehouse{}).
|
||||
Order("id DESC"). // 必须排序保证分页稳定
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&Warehouses)
|
||||
|
||||
return Warehouses
|
||||
}
|
||||
|
||||
func Warehouse_get_items_from_whid(wh_id uint) []WarehouseItem {
|
||||
var seachf []WarehouseItem
|
||||
var seach WarehouseItem
|
||||
seach.WarehouseID = wh_id
|
||||
DB.Where(&seach).Order("id DESC").Find(&seachf)
|
||||
return seachf
|
||||
}
|
||||
Reference in New Issue
Block a user