chore: 同步本地 v9 整改与运营能力
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Organization 组织/养殖场/合作社,用于对象级数据授权。
|
||||
type Organization struct {
|
||||
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
||||
Name string `gorm:"size:128" json:"name"`
|
||||
Code string `gorm:"size:64;uniqueIndex" json:"code"`
|
||||
Description *string `gorm:"type:text" json:"description,omitempty"`
|
||||
Status string `gorm:"size:16;default:active" json:"status"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Organization) TableName() string { return "organizations" }
|
||||
|
||||
// OrganizationMember 用户与组织归属关系。
|
||||
type OrganizationMember struct {
|
||||
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
||||
OrganizationID string `gorm:"column:organization_id;type:uuid;uniqueIndex:idx_org_members_org_user,priority:1" json:"organizationId"`
|
||||
UserID string `gorm:"column:user_id;type:uuid;uniqueIndex:idx_org_members_org_user,priority:2" json:"userId"`
|
||||
Role string `gorm:"size:16;default:member" json:"role"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
}
|
||||
|
||||
func (OrganizationMember) TableName() string { return "organization_members" }
|
||||
|
||||
// DeviceMaintenanceRecord 设备校准/故障/维护/固件记录。
|
||||
type DeviceMaintenanceRecord struct {
|
||||
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
||||
DeviceID string `gorm:"column:device_id;type:uuid;index" json:"deviceId"`
|
||||
Kind string `gorm:"size:16;index" json:"kind"` // calibration/fault/maintenance/firmware
|
||||
Title string `gorm:"size:128" json:"title"`
|
||||
ScheduledAt *time.Time `gorm:"column:scheduled_at;type:timestamptz" json:"scheduledAt,omitempty"`
|
||||
PerformedAt *time.Time `gorm:"column:performed_at;type:timestamptz" json:"performedAt,omitempty"`
|
||||
PerformerID *string `gorm:"column:performer_id;type:uuid" json:"performerId,omitempty"`
|
||||
Result *string `gorm:"type:text" json:"result,omitempty"`
|
||||
FirmwareFrom *string `gorm:"column:firmware_from;size:64" json:"firmwareFrom,omitempty"`
|
||||
FirmwareTo *string `gorm:"column:firmware_to;size:64" json:"firmwareTo,omitempty"`
|
||||
CostAmount *float64 `gorm:"column:cost_amount;type:float" json:"costAmount,omitempty"`
|
||||
CostUnit *string `gorm:"column:cost_unit;size:16" json:"costUnit,omitempty"`
|
||||
Note *string `gorm:"type:text" json:"note,omitempty"`
|
||||
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (DeviceMaintenanceRecord) TableName() string { return "device_maintenance_records" }
|
||||
|
||||
// ValidMaintenanceKind 设备维护记录类型。
|
||||
func ValidMaintenanceKind(kind string) bool {
|
||||
switch kind {
|
||||
case "calibration", "fault", "maintenance", "firmware":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateDeviceMaintenanceRecord 设备维护必填项。
|
||||
func ValidateDeviceMaintenanceRecord(record DeviceMaintenanceRecord) error {
|
||||
if !ValidMaintenanceKind(record.Kind) {
|
||||
return errors.New("kind 仅支持 calibration/fault/maintenance/firmware")
|
||||
}
|
||||
if strings.TrimSpace(record.Title) == "" {
|
||||
return errors.New("维护标题不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProductionLossRecord 产量、死亡、淘汰、损失和防控成本记录。
|
||||
type ProductionLossRecord struct {
|
||||
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
||||
RoomID *string `gorm:"column:room_id;type:uuid;index" json:"roomId,omitempty"`
|
||||
BatchID *string `gorm:"column:batch_id;type:uuid;index" json:"batchId,omitempty"`
|
||||
RecordDate time.Time `gorm:"column:record_date;type:timestamptz;index" json:"recordDate"`
|
||||
DeathCount *int `gorm:"column:death_count;type:int" json:"deathCount,omitempty"`
|
||||
CulledCount *int `gorm:"column:culled_count;type:int" json:"culledCount,omitempty"`
|
||||
YieldKg *float64 `gorm:"column:yield_kg;type:float" json:"yieldKg,omitempty"`
|
||||
LossKg *float64 `gorm:"column:loss_kg;type:float" json:"lossKg,omitempty"`
|
||||
CostType *string `gorm:"column:cost_type;size:32" json:"costType,omitempty"` // medicine/disinfection/detection/labor/other
|
||||
CostAmount *float64 `gorm:"column:cost_amount;type:float" json:"costAmount,omitempty"`
|
||||
Note *string `gorm:"type:text" json:"note,omitempty"`
|
||||
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (ProductionLossRecord) TableName() string { return "production_loss_records" }
|
||||
|
||||
// ValidateProductionLossRecord 产量损失记录必须至少有一个业务数值。
|
||||
func ValidateProductionLossRecord(record ProductionLossRecord) error {
|
||||
if record.RoomID == nil && record.BatchID == nil {
|
||||
return errors.New("roomId/batchId 至少填一个")
|
||||
}
|
||||
if record.RecordDate.IsZero() {
|
||||
return errors.New("记录日期不能为空")
|
||||
}
|
||||
hasValue := record.DeathCount != nil || record.CulledCount != nil ||
|
||||
record.YieldKg != nil || record.LossKg != nil || record.CostAmount != nil
|
||||
if !hasValue {
|
||||
return errors.New("死亡/淘汰/产量/损失/成本至少填写一项")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CaseStudy 已脱敏病例沉淀,必须经审核后发布。
|
||||
type CaseStudy struct {
|
||||
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
||||
Title string `gorm:"size:128" json:"title"`
|
||||
Disease string `gorm:"size:64;index" json:"disease"`
|
||||
SourceConsultationID *string `gorm:"column:source_consultation_id;type:uuid;index" json:"sourceConsultationId,omitempty"`
|
||||
SourceDiseaseEventID *string `gorm:"column:source_disease_event_id;type:uuid;index" json:"sourceDiseaseEventId,omitempty"`
|
||||
SourceRoomID *string `gorm:"column:source_room_id;type:uuid;index" json:"sourceRoomId,omitempty"`
|
||||
Region *string `gorm:"size:64" json:"region,omitempty"`
|
||||
CaseDate *time.Time `gorm:"column:case_date;type:timestamptz" json:"caseDate,omitempty"`
|
||||
Summary *string `gorm:"type:text" json:"summary,omitempty"`
|
||||
DesensitizedPayload json.RawMessage `gorm:"column:desensitized_payload;type:jsonb" json:"desensitizedPayload,omitempty"`
|
||||
Status string `gorm:"size:16;default:draft;index" json:"status"` // draft/pending_review/published/rejected
|
||||
ReviewNote *string `gorm:"column:review_note;type:text" json:"reviewNote,omitempty"`
|
||||
ReviewerID *string `gorm:"column:reviewer_id;type:uuid" json:"reviewerId,omitempty"`
|
||||
ReviewedAt *time.Time `gorm:"column:reviewed_at;type:timestamptz" json:"reviewedAt,omitempty"`
|
||||
PublishedAt *time.Time `gorm:"column:published_at;type:timestamptz" json:"publishedAt,omitempty"`
|
||||
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (CaseStudy) TableName() string { return "case_studies" }
|
||||
|
||||
// ValidCaseStudyTransition 案例审核状态流转。
|
||||
func ValidCaseStudyTransition(from, to string) bool {
|
||||
switch from {
|
||||
case "draft":
|
||||
return to == "pending_review" || to == "rejected"
|
||||
case "pending_review":
|
||||
return to == "published" || to == "rejected"
|
||||
case "published":
|
||||
return to == "rejected" || to == "pending_review"
|
||||
case "rejected":
|
||||
return to == "draft" || to == "pending_review"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// LaboratoryResult 实验室结构化结果,关联三级溯源、发病事件和样本。
|
||||
type LaboratoryResult struct {
|
||||
ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" json:"id"`
|
||||
TraceRecordID *string `gorm:"column:trace_record_id;type:uuid;index" json:"traceRecordId,omitempty"`
|
||||
DiseaseEventID *string `gorm:"column:disease_event_id;type:uuid;index" json:"diseaseEventId,omitempty"`
|
||||
SampleID *string `gorm:"column:sample_id;type:uuid;index" json:"sampleId,omitempty"`
|
||||
RoomID *string `gorm:"column:room_id;type:uuid;index" json:"roomId,omitempty"`
|
||||
BatchID *string `gorm:"column:batch_id;type:uuid;index" json:"batchId,omitempty"`
|
||||
LabName string `gorm:"column:lab_name;size:128" json:"labName"`
|
||||
ReportNo string `gorm:"column:report_no;size:64" json:"reportNo"`
|
||||
TestType string `gorm:"column:test_type;size:32" json:"testType"` // molecular_typing/pathogen/environment_sample/other
|
||||
ResultType string `gorm:"column:result_type;size:16" json:"resultType"`
|
||||
Pathogen *string `gorm:"size:128" json:"pathogen,omitempty"`
|
||||
Genotype *string `gorm:"size:128" json:"genotype,omitempty"`
|
||||
Method *string `gorm:"size:128" json:"method,omitempty"`
|
||||
SampleNo *string `gorm:"column:sample_no;size:64" json:"sampleNo,omitempty"`
|
||||
SampleType *string `gorm:"column:sample_type;size:32" json:"sampleType,omitempty"`
|
||||
Findings *string `gorm:"type:text" json:"findings,omitempty"`
|
||||
ReportURL *string `gorm:"column:report_url;size:512" json:"reportUrl,omitempty"`
|
||||
TestedAt *time.Time `gorm:"column:tested_at;type:timestamptz" json:"testedAt,omitempty"`
|
||||
ConcludedAt *time.Time `gorm:"column:concluded_at;type:timestamptz" json:"concludedAt,omitempty"`
|
||||
CreatedBy *string `gorm:"column:created_by;type:uuid" json:"createdBy,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (LaboratoryResult) TableName() string { return "laboratory_results" }
|
||||
|
||||
// ValidateLaboratoryResult 实验室结果必填项。
|
||||
func ValidateLaboratoryResult(result LaboratoryResult) error {
|
||||
if strings.TrimSpace(result.LabName) == "" {
|
||||
return errors.New("实验室名称不能为空")
|
||||
}
|
||||
if strings.TrimSpace(result.ReportNo) == "" {
|
||||
return errors.New("报告编号不能为空")
|
||||
}
|
||||
if !ValidLaboratoryTestType(result.TestType) {
|
||||
return errors.New("testType 仅支持 molecular_typing/pathogen/environment_sample/other")
|
||||
}
|
||||
if !ValidLaboratoryResultType(result.ResultType) {
|
||||
return errors.New("resultType 仅支持 positive/negative/indeterminate/invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidLaboratoryTestType 实验室检测类型。
|
||||
func ValidLaboratoryTestType(testType string) bool {
|
||||
switch testType {
|
||||
case "molecular_typing", "pathogen", "environment_sample", "other":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ValidLaboratoryResultType 实验室结果类型。
|
||||
func ValidLaboratoryResultType(resultType string) bool {
|
||||
switch resultType {
|
||||
case "positive", "negative", "indeterminate", "invalid":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestValidMaintenanceKind(t *testing.T) {
|
||||
for _, kind := range []string{"calibration", "fault", "maintenance", "firmware"} {
|
||||
if !ValidMaintenanceKind(kind) {
|
||||
t.Errorf("%s should be valid", kind)
|
||||
}
|
||||
}
|
||||
if ValidMaintenanceKind("inspection") {
|
||||
t.Error("inspection is not a maintenance kind")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDeviceMaintenanceRecord(t *testing.T) {
|
||||
record := DeviceMaintenanceRecord{Kind: "calibration", Title: "温度传感器校准"}
|
||||
if err := ValidateDeviceMaintenanceRecord(record); err != nil {
|
||||
t.Fatalf("valid record should pass: %v", err)
|
||||
}
|
||||
record.Title = ""
|
||||
if err := ValidateDeviceMaintenanceRecord(record); err == nil {
|
||||
t.Fatal("missing title should fail")
|
||||
}
|
||||
record.Title = "校准"
|
||||
record.Kind = "unknown"
|
||||
if err := ValidateDeviceMaintenanceRecord(record); err == nil {
|
||||
t.Fatal("invalid kind should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateProductionLossRecord(t *testing.T) {
|
||||
roomID := "room-1"
|
||||
yield := 3.2
|
||||
record := ProductionLossRecord{RoomID: &roomID, RecordDate: time.Now(), YieldKg: &yield}
|
||||
if err := ValidateProductionLossRecord(record); err != nil {
|
||||
t.Fatalf("valid record should pass: %v", err)
|
||||
}
|
||||
record.YieldKg = nil
|
||||
if err := ValidateProductionLossRecord(record); err == nil {
|
||||
t.Fatal("record without business value should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidCaseStudyTransition(t *testing.T) {
|
||||
ok := [][2]string{
|
||||
{"draft", "pending_review"},
|
||||
{"pending_review", "published"},
|
||||
{"pending_review", "rejected"},
|
||||
{"published", "rejected"},
|
||||
}
|
||||
for _, tr := range ok {
|
||||
if !ValidCaseStudyTransition(tr[0], tr[1]) {
|
||||
t.Errorf("expected %s -> %s", tr[0], tr[1])
|
||||
}
|
||||
}
|
||||
if ValidCaseStudyTransition("draft", "published") {
|
||||
t.Error("draft cannot jump to published")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateLaboratoryResult(t *testing.T) {
|
||||
result := LaboratoryResult{
|
||||
LabName: "省蚕科所", ReportNo: "LAB-001",
|
||||
TestType: "molecular_typing", ResultType: "positive",
|
||||
}
|
||||
if err := ValidateLaboratoryResult(result); err != nil {
|
||||
t.Fatalf("valid result should pass: %v", err)
|
||||
}
|
||||
result.ResultType = "unknown"
|
||||
if err := ValidateLaboratoryResult(result); err == nil {
|
||||
t.Fatal("invalid result type should fail")
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ type Room struct {
|
||||
Capacity *int `gorm:"type:int" json:"capacity,omitempty"`
|
||||
Stage *string `gorm:"size:32" json:"stage,omitempty"`
|
||||
Region *string `gorm:"size:64" json:"region,omitempty"`
|
||||
OrgID *string `gorm:"column:org_id;type:uuid;index" json:"orgId,omitempty"`
|
||||
Status string `gorm:"default:active" json:"status"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
@@ -109,38 +110,38 @@ func (Alarm) TableName() string { return "alarms" }
|
||||
|
||||
// Camera 摄像头表
|
||||
type Camera struct {
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
RoomID *string `gorm:"column:room_id;index" json:"roomId,omitempty"`
|
||||
Code string `gorm:"size:64" json:"code"`
|
||||
Name string `gorm:"size:128" json:"name"`
|
||||
RtspURL *string `gorm:"column:rtsp_url;size:512" json:"rtspUrl,omitempty"`
|
||||
HTTPURL *string `gorm:"column:http_url;size:512" json:"httpUrl,omitempty"`
|
||||
Username *string `gorm:"size:64" json:"username,omitempty"`
|
||||
PasswordEnc *string `gorm:"column:password_enc;size:255" json:"-"`
|
||||
Position *string `gorm:"size:255" json:"position,omitempty"`
|
||||
Resolution *string `gorm:"size:32" json:"resolution,omitempty"`
|
||||
FPS *int `gorm:"type:int" json:"fps,omitempty"`
|
||||
IsOnline bool `gorm:"column:is_online;default:true" json:"isOnline"`
|
||||
GbDeviceID *string `gorm:"column:gb_device_id;size:20" json:"gbDeviceId,omitempty"`
|
||||
GbChannelID *string `gorm:"column:gb_channel_id;size:20" json:"gbChannelId,omitempty"`
|
||||
GbAuthID *string `gorm:"column:gb_auth_id;size:20" json:"gbAuthId,omitempty"`
|
||||
GbAuthPassword *string `gorm:"column:gb_auth_password;size:255" json:"-"`
|
||||
GbStreamType *string `gorm:"column:gb_stream_type;size:10" json:"gbStreamType,omitempty"`
|
||||
GbTransport *string `gorm:"column:gb_transport;size:10" json:"gbTransport,omitempty"`
|
||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
RoomID *string `gorm:"column:room_id;index" json:"roomId,omitempty"`
|
||||
Code string `gorm:"size:64" json:"code"`
|
||||
Name string `gorm:"size:128" json:"name"`
|
||||
RtspURL *string `gorm:"column:rtsp_url;size:512" json:"rtspUrl,omitempty"`
|
||||
HTTPURL *string `gorm:"column:http_url;size:512" json:"httpUrl,omitempty"`
|
||||
Username *string `gorm:"size:64" json:"username,omitempty"`
|
||||
PasswordEnc *string `gorm:"column:password_enc;size:255" json:"-"`
|
||||
Position *string `gorm:"size:255" json:"position,omitempty"`
|
||||
Resolution *string `gorm:"size:32" json:"resolution,omitempty"`
|
||||
FPS *int `gorm:"type:int" json:"fps,omitempty"`
|
||||
IsOnline bool `gorm:"column:is_online;default:true" json:"isOnline"`
|
||||
GbDeviceID *string `gorm:"column:gb_device_id;size:20" json:"gbDeviceId,omitempty"`
|
||||
GbChannelID *string `gorm:"column:gb_channel_id;size:20" json:"gbChannelId,omitempty"`
|
||||
GbAuthID *string `gorm:"column:gb_auth_id;size:20" json:"gbAuthId,omitempty"`
|
||||
GbAuthPassword *string `gorm:"column:gb_auth_password;size:255" json:"-"`
|
||||
GbStreamType *string `gorm:"column:gb_stream_type;size:10" json:"gbStreamType,omitempty"`
|
||||
GbTransport *string `gorm:"column:gb_transport;size:10" json:"gbTransport,omitempty"`
|
||||
GbAlarmChannelID *string `gorm:"column:gb_alarm_channel_id;size:20" json:"gbAlarmChannelId,omitempty"`
|
||||
GbVoiceChannelID *string `gorm:"column:gb_voice_channel_id;size:20" json:"gbVoiceChannelId,omitempty"`
|
||||
GbManufacturer *string `gorm:"column:gb_manufacturer;size:64" json:"gbManufacturer,omitempty"`
|
||||
ManufacturerID *string `gorm:"column:manufacturer_id;size:64" json:"manufacturerId,omitempty"`
|
||||
GbManufacturer *string `gorm:"column:gb_manufacturer;size:64" json:"gbManufacturer,omitempty"`
|
||||
ManufacturerID *string `gorm:"column:manufacturer_id;size:64" json:"manufacturerId,omitempty"`
|
||||
// 以下字段不在数据库中,运行时通过 WVP API 填充
|
||||
StreamURL *string `gorm:"-" json:"streamUrl,omitempty"`
|
||||
HlsURL *string `gorm:"-" json:"hlsUrl,omitempty"`
|
||||
FlvURL *string `gorm:"-" json:"flvUrl,omitempty"`
|
||||
WebrtcURL *string `gorm:"-" json:"webrtcUrl,omitempty"`
|
||||
SnapshotURL *string `gorm:"-" json:"snapshotUrl,omitempty"`
|
||||
Online bool `gorm:"-" json:"online"`
|
||||
Enabled bool `gorm:"default:true" json:"enabled"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
StreamURL *string `gorm:"-" json:"streamUrl,omitempty"`
|
||||
HlsURL *string `gorm:"-" json:"hlsUrl,omitempty"`
|
||||
FlvURL *string `gorm:"-" json:"flvUrl,omitempty"`
|
||||
WebrtcURL *string `gorm:"-" json:"webrtcUrl,omitempty"`
|
||||
SnapshotURL *string `gorm:"-" json:"snapshotUrl,omitempty"`
|
||||
Online bool `gorm:"-" json:"online"`
|
||||
Enabled bool `gorm:"default:true" json:"enabled"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (Camera) TableName() string { return "cameras" }
|
||||
@@ -167,8 +168,8 @@ type VideoClip struct {
|
||||
AlarmID *string `gorm:"column:alarm_id;index" json:"alarmId,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
S3Bucket *string `gorm:"column:s3_bucket" json:"s3Bucket,omitempty"`
|
||||
S3Key *string `gorm:"column:s3_key" json:"s3Key,omitempty"`
|
||||
S3Bucket *string `gorm:"column:s3_bucket" json:"s3Bucket,omitempty"`
|
||||
S3Key *string `gorm:"column:s3_key" json:"s3Key,omitempty"`
|
||||
// 以下字段不在数据库中,运行时填充
|
||||
PlaybackURL *string `gorm:"-" json:"playbackUrl,omitempty"`
|
||||
Format string `gorm:"-" json:"format"`
|
||||
|
||||
@@ -47,6 +47,14 @@ var AllPermissions = []PermissionDef{
|
||||
{"biosecurity:write", "生物安全管理", "维护种源、消毒记录并签发二维码"},
|
||||
{"user:manage", "用户管理", "管理用户、角色和权限"},
|
||||
{"audit:read", "审计查看", "查看审计日志"},
|
||||
{"organization:manage", "组织管理", "维护组织及成员数据范围"},
|
||||
{"device:write", "设备管理", "维护设备资产、校准和固件信息"},
|
||||
{"farm:read", "产量损失查看", "查看产量、死亡、淘汰和成本记录"},
|
||||
{"farm:write", "产量损失管理", "新增、编辑产量和损失记录"},
|
||||
{"case:read", "案例查看", "查看已脱敏案例库"},
|
||||
{"case:write", "案例管理", "创建、审核和发布脱敏案例"},
|
||||
{"lab:read", "实验室结果查看", "查看实验室结构化结果"},
|
||||
{"lab:write", "实验室结果管理", "录入实验室结果和分子分型"},
|
||||
}
|
||||
|
||||
// RolePermissionMap 角色-权限码映射(种子数据)
|
||||
@@ -66,6 +74,8 @@ var RolePermissionMap = map[string][]string{
|
||||
"trace:read", "trace:write",
|
||||
"biosecurity:read", "biosecurity:write",
|
||||
"user:manage", "audit:read",
|
||||
"organization:manage", "device:write",
|
||||
"farm:read", "farm:write", "case:read", "case:write", "lab:read", "lab:write",
|
||||
},
|
||||
RoleOperator: {
|
||||
"dashboard:view", "room:read", "room:write", "device:read", "device:control",
|
||||
@@ -81,6 +91,7 @@ var RolePermissionMap = map[string][]string{
|
||||
"consultation:read", "consultation:write",
|
||||
"trace:read", "trace:write",
|
||||
"biosecurity:read", "biosecurity:write",
|
||||
"device:write", "farm:read", "farm:write", "case:read", "case:write", "lab:read", "lab:write",
|
||||
},
|
||||
RoleViewer: {
|
||||
"dashboard:view", "room:read", "device:read",
|
||||
@@ -95,6 +106,7 @@ var RolePermissionMap = map[string][]string{
|
||||
"consultation:read",
|
||||
"trace:read",
|
||||
"biosecurity:read",
|
||||
"farm:read", "case:read", "lab:read",
|
||||
},
|
||||
RoleFarmer: {
|
||||
"dashboard:view", "room:read", "device:read", "device:control",
|
||||
@@ -109,5 +121,6 @@ var RolePermissionMap = map[string][]string{
|
||||
"consultation:read",
|
||||
"trace:read",
|
||||
"biosecurity:read", "biosecurity:write",
|
||||
"farm:read", "farm:write", "case:read", "lab:read",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ type RearingRecord struct {
|
||||
Instar *int `gorm:"type:int" json:"instar,omitempty"`
|
||||
MulberrySource *string `gorm:"column:mulberry_source;size:128" json:"mulberrySource,omitempty"` // 桑叶来源
|
||||
Density *string `gorm:"size:64" json:"density,omitempty"` // 饲养密度
|
||||
DeathCount *int `gorm:"column:death_count;type:int" json:"deathCount,omitempty"`
|
||||
CulledCount *int `gorm:"column:culled_count;type:int" json:"culledCount,omitempty"`
|
||||
Note *string `gorm:"type:text" json:"note,omitempty"`
|
||||
CreatedAt time.Time `gorm:"type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"type:timestamptz" json:"updatedAt"`
|
||||
|
||||
Reference in New Issue
Block a user